valence/crates/valence_core/src/particle.rs
Ryan Johnson c5557e744d
Move packets out of valence_core. (#335)
## Description

- Move all packets out of `valence_core` and into the places where
they're actually used. This has a few benefits:
- Avoids compiling code for packets that go unused when feature flags
are disabled.
- Code is distributed more uniformly across crates, improving
compilation times.
- Improves local reasoning when everything relevant to a module is
defined in the same place.
  - Easier to share code between the packet consumer and the packet.
- Tweak `Packet` macro syntax.
- Update `syn` to 2.0.
- Reorganize some code in `valence_client` (needs further work).
- Impl `WritePacket` for `Instance`.
- Remove packet enums such as `S2cPlayPacket` and `C2sPlayPacket`.
- Replace `assert_packet_count` and `assert_packet_order` macros with
non-macro methods.
To prevent this PR from getting out of hand, I've disabled the packet
inspector and stresser until they have been rewritten to account for
these changes.
2023-05-29 01:36:11 -07:00

448 lines
14 KiB
Rust

use std::borrow::Cow;
use std::io::Write;
use anyhow::bail;
use glam::{DVec3, Vec3};
use crate::block_pos::BlockPos;
use crate::item::ItemStack;
use crate::protocol::var_int::VarInt;
use crate::protocol::{packet_id, Decode, Encode, Packet};
#[derive(Clone, PartialEq, Debug)]
pub enum Particle {
AmbientEntityEffect,
AngryVillager,
Block(i32), // TODO: use BlockState type.
BlockMarker(i32), // TODO: use BlockState type.
Bubble,
Cloud,
Crit,
DamageIndicator,
DragonBreath,
DrippingLava,
FallingLava,
LandingLava,
DrippingWater,
FallingWater,
Dust {
rgb: Vec3,
scale: f32,
},
DustColorTransition {
from_rgb: Vec3,
scale: f32,
to_rgb: Vec3,
},
Effect,
ElderGuardian,
EnchantedHit,
Enchant,
EndRod,
EntityEffect,
ExplosionEmitter,
Explosion,
SonicBoom,
FallingDust(i32), // TODO: use BlockState type.
Firework,
Fishing,
Flame,
DrippingCherryLeaves,
FallingCherryLeaves,
LandingCherryLeaves,
SculkSoul,
SculkCharge {
roll: f32,
},
SculkChargePop,
SoulFireFlame,
Soul,
Flash,
HappyVillager,
Composter,
Heart,
InstantEffect,
Item(Option<ItemStack>),
/// The 'Block' variant of the 'Vibration' particle
VibrationBlock {
block_pos: BlockPos,
ticks: i32,
},
/// The 'Entity' variant of the 'Vibration' particle
VibrationEntity {
entity_id: i32,
entity_eye_height: f32,
ticks: i32,
},
ItemSlime,
ItemSnowball,
LargeSmoke,
Lava,
Mycelium,
Note,
Poof,
Portal,
Rain,
Smoke,
Sneeze,
Spit,
SquidInk,
SweepAttack,
TotemOfUndying,
Underwater,
Splash,
Witch,
BubblePop,
CurrentDown,
BubbleColumnUp,
Nautilus,
Dolphin,
CampfireCosySmoke,
CampfireSignalSmoke,
DrippingHoney,
FallingHoney,
LandingHoney,
FallingNectar,
FallingSporeBlossom,
Ash,
CrimsonSpore,
WarpedSpore,
SporeBlossomAir,
DrippingObsidianTear,
FallingObsidianTear,
LandingObsidianTear,
ReversePortal,
WhiteAsh,
SmallFlame,
Snowflake,
DrippingDripstoneLava,
FallingDripstoneLava,
DrippingDripstoneWater,
FallingDripstoneWater,
GlowSquidInk,
Glow,
WaxOn,
WaxOff,
ElectricSpark,
Scrape,
Shriek {
delay: i32,
},
}
impl Particle {
pub const fn id(&self) -> i32 {
match self {
Particle::AmbientEntityEffect => 0,
Particle::AngryVillager => 1,
Particle::Block(_) => 2,
Particle::BlockMarker(_) => 3,
Particle::Bubble => 4,
Particle::Cloud => 5,
Particle::Crit => 6,
Particle::DamageIndicator => 7,
Particle::DragonBreath => 8,
Particle::DrippingLava => 9,
Particle::FallingLava => 10,
Particle::LandingLava => 11,
Particle::DrippingWater => 12,
Particle::FallingWater => 13,
Particle::Dust { .. } => 14,
Particle::DustColorTransition { .. } => 15,
Particle::Effect => 16,
Particle::ElderGuardian => 17,
Particle::EnchantedHit => 18,
Particle::Enchant => 19,
Particle::EndRod => 20,
Particle::EntityEffect => 21,
Particle::ExplosionEmitter => 22,
Particle::Explosion => 23,
Particle::SonicBoom => 24,
Particle::FallingDust(_) => 25,
Particle::Firework => 26,
Particle::Fishing => 27,
Particle::Flame => 28,
Particle::DrippingCherryLeaves => 29,
Particle::FallingCherryLeaves => 30,
Particle::LandingCherryLeaves => 31,
Particle::SculkSoul => 32,
Particle::SculkCharge { .. } => 33,
Particle::SculkChargePop => 34,
Particle::SoulFireFlame => 35,
Particle::Soul => 36,
Particle::Flash => 37,
Particle::HappyVillager => 38,
Particle::Composter => 39,
Particle::Heart => 40,
Particle::InstantEffect => 41,
Particle::Item { .. } => 42,
Particle::VibrationBlock { .. } => 43,
Particle::VibrationEntity { .. } => 43,
Particle::ItemSlime => 44,
Particle::ItemSnowball => 45,
Particle::LargeSmoke => 46,
Particle::Lava => 47,
Particle::Mycelium => 48,
Particle::Note => 49,
Particle::Poof => 50,
Particle::Portal => 51,
Particle::Rain => 52,
Particle::Smoke => 53,
Particle::Sneeze => 54,
Particle::Spit => 55,
Particle::SquidInk => 56,
Particle::SweepAttack => 57,
Particle::TotemOfUndying => 58,
Particle::Underwater => 59,
Particle::Splash => 60,
Particle::Witch => 61,
Particle::BubblePop => 62,
Particle::CurrentDown => 63,
Particle::BubbleColumnUp => 64,
Particle::Nautilus => 65,
Particle::Dolphin => 66,
Particle::CampfireCosySmoke => 67,
Particle::CampfireSignalSmoke => 68,
Particle::DrippingHoney => 69,
Particle::FallingHoney => 70,
Particle::LandingHoney => 71,
Particle::FallingNectar => 72,
Particle::FallingSporeBlossom => 73,
Particle::Ash => 74,
Particle::CrimsonSpore => 75,
Particle::WarpedSpore => 76,
Particle::SporeBlossomAir => 77,
Particle::DrippingObsidianTear => 78,
Particle::FallingObsidianTear => 79,
Particle::LandingObsidianTear => 80,
Particle::ReversePortal => 81,
Particle::WhiteAsh => 82,
Particle::SmallFlame => 83,
Particle::Snowflake => 84,
Particle::DrippingDripstoneLava => 85,
Particle::FallingDripstoneLava => 86,
Particle::DrippingDripstoneWater => 87,
Particle::FallingDripstoneWater => 88,
Particle::GlowSquidInk => 89,
Particle::Glow => 90,
Particle::WaxOn => 91,
Particle::WaxOff => 92,
Particle::ElectricSpark => 93,
Particle::Scrape => 94,
Particle::Shriek { .. } => 95,
}
}
/// Decodes the particle assuming the given particle ID.
pub fn decode_with_id(particle_id: i32, r: &mut &[u8]) -> anyhow::Result<Self> {
Ok(match particle_id {
0 => Particle::AmbientEntityEffect,
1 => Particle::AngryVillager,
2 => Particle::Block(VarInt::decode(r)?.0),
3 => Particle::BlockMarker(VarInt::decode(r)?.0),
4 => Particle::Bubble,
5 => Particle::Cloud,
6 => Particle::Crit,
7 => Particle::DamageIndicator,
8 => Particle::DragonBreath,
9 => Particle::DrippingLava,
10 => Particle::FallingLava,
11 => Particle::LandingLava,
12 => Particle::DrippingWater,
13 => Particle::FallingWater,
14 => Particle::Dust {
rgb: Decode::decode(r)?,
scale: Decode::decode(r)?,
},
15 => Particle::DustColorTransition {
from_rgb: Decode::decode(r)?,
scale: Decode::decode(r)?,
to_rgb: Decode::decode(r)?,
},
16 => Particle::Effect,
17 => Particle::ElderGuardian,
18 => Particle::EnchantedHit,
19 => Particle::Enchant,
20 => Particle::EndRod,
21 => Particle::EntityEffect,
22 => Particle::ExplosionEmitter,
23 => Particle::Explosion,
24 => Particle::SonicBoom,
25 => Particle::FallingDust(VarInt::decode(r)?.0),
26 => Particle::Firework,
27 => Particle::Fishing,
28 => Particle::Flame,
29 => Particle::DrippingCherryLeaves,
30 => Particle::FallingCherryLeaves,
31 => Particle::LandingCherryLeaves,
32 => Particle::SculkSoul,
33 => Particle::SculkCharge {
roll: f32::decode(r)?,
},
34 => Particle::SculkChargePop,
35 => Particle::SoulFireFlame,
36 => Particle::Soul,
37 => Particle::Flash,
38 => Particle::HappyVillager,
39 => Particle::Composter,
40 => Particle::Heart,
41 => Particle::InstantEffect,
42 => Particle::Item(Decode::decode(r)?),
43 => match <&str>::decode(r)? {
"block" => Particle::VibrationBlock {
block_pos: BlockPos::decode(r)?,
ticks: VarInt::decode(r)?.0,
},
"entity" => Particle::VibrationEntity {
entity_id: VarInt::decode(r)?.0,
entity_eye_height: f32::decode(r)?,
ticks: VarInt::decode(r)?.0,
},
invalid => bail!("invalid vibration position source of \"{invalid}\""),
},
44 => Particle::ItemSlime,
45 => Particle::ItemSnowball,
46 => Particle::LargeSmoke,
47 => Particle::Lava,
48 => Particle::Mycelium,
49 => Particle::Note,
50 => Particle::Poof,
51 => Particle::Portal,
52 => Particle::Rain,
53 => Particle::Smoke,
54 => Particle::Sneeze,
55 => Particle::Spit,
56 => Particle::SquidInk,
57 => Particle::SweepAttack,
58 => Particle::TotemOfUndying,
59 => Particle::Underwater,
60 => Particle::Splash,
61 => Particle::Witch,
62 => Particle::BubblePop,
63 => Particle::CurrentDown,
64 => Particle::BubbleColumnUp,
65 => Particle::Nautilus,
66 => Particle::Dolphin,
67 => Particle::CampfireCosySmoke,
68 => Particle::CampfireSignalSmoke,
69 => Particle::DrippingHoney,
70 => Particle::FallingHoney,
71 => Particle::LandingHoney,
72 => Particle::FallingNectar,
73 => Particle::FallingSporeBlossom,
74 => Particle::Ash,
75 => Particle::CrimsonSpore,
76 => Particle::WarpedSpore,
77 => Particle::SporeBlossomAir,
78 => Particle::DrippingObsidianTear,
79 => Particle::FallingObsidianTear,
80 => Particle::LandingObsidianTear,
81 => Particle::ReversePortal,
82 => Particle::WhiteAsh,
83 => Particle::SmallFlame,
84 => Particle::Snowflake,
85 => Particle::DrippingDripstoneLava,
86 => Particle::FallingDripstoneLava,
87 => Particle::DrippingDripstoneWater,
88 => Particle::FallingDripstoneWater,
89 => Particle::GlowSquidInk,
90 => Particle::Glow,
91 => Particle::WaxOn,
92 => Particle::WaxOff,
93 => Particle::ElectricSpark,
94 => Particle::Scrape,
95 => Particle::Shriek {
delay: VarInt::decode(r)?.0,
},
id => bail!("invalid particle ID of {id}"),
})
}
}
#[derive(Clone, Debug, Packet)]
#[packet(id = packet_id::PARTICLE_S2C)]
pub struct ParticleS2c<'a> {
pub particle: Cow<'a, Particle>,
pub long_distance: bool,
pub position: DVec3,
pub offset: Vec3,
pub max_speed: f32,
pub count: i32,
}
impl Encode for ParticleS2c<'_> {
fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
VarInt(self.particle.id()).encode(&mut w)?;
self.long_distance.encode(&mut w)?;
self.position.encode(&mut w)?;
self.offset.encode(&mut w)?;
self.max_speed.encode(&mut w)?;
self.count.encode(&mut w)?;
self.particle.as_ref().encode(w)
}
}
impl<'a> Decode<'a> for ParticleS2c<'a> {
fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
let particle_id = VarInt::decode(r)?.0;
let long_distance = bool::decode(r)?;
let position = Decode::decode(r)?;
let offset = Decode::decode(r)?;
let max_speed = f32::decode(r)?;
let particle_count = i32::decode(r)?;
Ok(Self {
particle: Cow::Owned(Particle::decode_with_id(particle_id, r)?),
long_distance,
position,
offset,
max_speed,
count: particle_count,
})
}
}
/// Encodes the particle without an ID.
impl Encode for Particle {
fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
match self {
Particle::Block(block_state) => VarInt(*block_state).encode(w),
Particle::BlockMarker(block_state) => VarInt(*block_state).encode(w),
Particle::Dust { rgb, scale } => {
rgb.encode(&mut w)?;
scale.encode(w)
}
Particle::DustColorTransition {
from_rgb,
scale,
to_rgb,
} => {
from_rgb.encode(&mut w)?;
scale.encode(&mut w)?;
to_rgb.encode(w)
}
Particle::FallingDust(block_state) => VarInt(*block_state).encode(w),
Particle::SculkCharge { roll } => roll.encode(w),
Particle::Item(stack) => stack.encode(w),
Particle::VibrationBlock { block_pos, ticks } => {
"block".encode(&mut w)?;
block_pos.encode(&mut w)?;
VarInt(*ticks).encode(w)
}
Particle::VibrationEntity {
entity_id,
entity_eye_height,
ticks,
} => {
"entity".encode(&mut w)?;
VarInt(*entity_id).encode(&mut w)?;
entity_eye_height.encode(&mut w)?;
VarInt(*ticks).encode(w)
}
Particle::Shriek { delay } => VarInt(*delay).encode(w),
_ => Ok(()),
}
}
}