diff options
author | Joey Sacchini <joey@sacchini.net> | 2020-10-09 18:42:32 -0400 |
---|---|---|
committer | Joey Sacchini <joey@sacchini.net> | 2020-10-09 18:42:32 -0400 |
commit | fafe72ac2d97bd5c94ad55bd55526c2dcba9b8ff (patch) | |
tree | de32700329d34bb811ca47170e4e41aeedeb68c0 /src/v1_15_2.rs | |
parent | bda2a204d8a44d94a76ac94f4dd33682ac1b05d3 (diff) | |
download | mcproto-rs-fafe72ac2d97bd5c94ad55bd55526c2dcba9b8ff.tar.gz mcproto-rs-fafe72ac2d97bd5c94ad55bd55526c2dcba9b8ff.tar.bz2 mcproto-rs-fafe72ac2d97bd5c94ad55bd55526c2dcba9b8ff.zip |
fix broken lighting data and totally rewrite chat engine
Diffstat (limited to 'src/v1_15_2.rs')
-rw-r--r-- | src/v1_15_2.rs | 437 |
1 files changed, 187 insertions, 250 deletions
diff --git a/src/v1_15_2.rs b/src/v1_15_2.rs index eba809d..ffc8490 100644 --- a/src/v1_15_2.rs +++ b/src/v1_15_2.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; #[cfg(test)] use crate::protocol::TestRandom; +use std::cell::Cell; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum PacketDirection { @@ -37,7 +38,7 @@ impl State { Login => "Login", Play => "Play", } - .to_owned() + .to_owned() } } @@ -1403,7 +1404,7 @@ impl Deserialize for UpdateScoreSpec { "invalid update score action {}", other )) - .into(), + .into(), }?; Deserialized::ok( @@ -1457,7 +1458,7 @@ impl Serialize for TitleActionSpec { Hide => 0x04, Reset => 0x05, }) - .mc_serialize(to)?; + .mc_serialize(to)?; match self { SetTitle(body) => to.serialize_other(body), @@ -1916,8 +1917,8 @@ pub struct PlayerInfoAction<A: Clone + PartialEq + Debug> { } impl<A> Serialize for PlayerInfoAction<A> -where - A: Serialize + Clone + PartialEq + Debug, + where + A: Serialize + Clone + PartialEq + Debug, { fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult { to.serialize_other(&self.uuid)?; @@ -1926,8 +1927,8 @@ where } impl<A> Deserialize for PlayerInfoAction<A> -where - A: Deserialize + Clone + PartialEq + Debug, + where + A: Deserialize + Clone + PartialEq + Debug, { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { let Deserialized { value: uuid, data } = UUID4::mc_deserialize(data)?; @@ -1981,7 +1982,7 @@ impl PlayerInfoActionList { UpdateDisplayName(_) => 0x03, Remove(_) => 0x04, } - .into() + .into() } pub fn len(&self) -> usize { @@ -2185,7 +2186,7 @@ impl WorldBorderAction { SetWarningTime(_) => 0x04, SetWarningBlocks(_) => 0x05, } - .into() + .into() } } @@ -2465,7 +2466,7 @@ impl InteractKind { Attack => 0x01, InteractAt(_) => 0x02, } - .into() + .into() } } @@ -2658,7 +2659,7 @@ impl Recipe { CampfireCooking(_) => "minecraft:campfire_cooking", StoneCutting(_) => "minecraft:stonecutting", } - .to_owned() + .to_owned() } fn serialize_body<S: Serializer>(&self, to: &mut S) -> SerializeResult { @@ -2754,10 +2755,10 @@ impl Deserialize for RecipeSpec { other ))), }? - .map(move |recipe_body| RecipeSpec { - id: recipe_id, - recipe: recipe_body, - })) + .map(move |recipe_body| RecipeSpec { + id: recipe_id, + recipe: recipe_body, + })) } } @@ -2917,26 +2918,11 @@ impl Serialize for ChunkData { impl Deserialize for ChunkData { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { - let Deserialized { - value: chunk_x, - data, - } = i32::mc_deserialize(data)?; - let Deserialized { - value: chunk_z, - data, - } = i32::mc_deserialize(data)?; - let Deserialized { - value: is_full_chunk, - data, - } = bool::mc_deserialize(data)?; - let Deserialized { - value: primary_bit_mask, - data, - } = VarInt::mc_deserialize(data)?; - let Deserialized { - value: heightmaps, - mut data, - } = NamedNbtTag::mc_deserialize(data)?; + let Deserialized { value: chunk_x, data } = i32::mc_deserialize(data)?; + let Deserialized { value: chunk_z, data } = i32::mc_deserialize(data)?; + let Deserialized { value: is_full_chunk, data } = bool::mc_deserialize(data)?; + let Deserialized { value: primary_bit_mask, data } = VarInt::mc_deserialize(data)?; + let Deserialized { value: heightmaps, mut data } = NamedNbtTag::mc_deserialize(data)?; let biomes = if is_full_chunk { let mut biomes: [i32; 1024] = [0i32; 1024]; for elem in &mut biomes { @@ -2948,37 +2934,25 @@ impl Deserialize for ChunkData { } else { None }; - let Deserialized { - value: chunk_data, - data, - } = VarIntCountedArray::<u8>::mc_deserialize(data)?; - let Deserialized { - value: n_block_entities_raw, - mut data, - } = VarInt::mc_deserialize(data)?; + let Deserialized { value: chunk_data, data } = VarIntCountedArray::<u8>::mc_deserialize(data)?; + let Deserialized { value: n_block_entities_raw, mut data } = VarInt::mc_deserialize(data)?; let n_block_entities = n_block_entities_raw.0 as usize; let mut block_entities = Vec::with_capacity(n_block_entities); for _ in 0..n_block_entities { - let Deserialized { - value: entity, - data: rest, - } = NamedNbtTag::mc_deserialize(data)?; + let Deserialized { value: entity, data: rest } = NamedNbtTag::mc_deserialize(data)?; data = rest; block_entities.push(entity); } - Deserialized::ok( - ChunkData { - chunk_x, - chunk_z, - primary_bit_mask, - heightmaps, - biomes, - data: chunk_data, - block_entities, - }, - data, - ) + Deserialized::ok(ChunkData { + chunk_x, + chunk_z, + primary_bit_mask, + heightmaps, + biomes, + data: chunk_data, + block_entities, + }, data) } } @@ -2997,204 +2971,88 @@ impl TestRandom for ChunkData { } } -const LIGHT_DATA_LENGTH: usize = 2048; -const LIGHT_DATA_SECTIONS: usize = 18; - -type LightingData = Vec<Option<[u8; LIGHT_DATA_LENGTH]>>; - -#[derive(Clone, PartialEq, Debug)] -pub struct LightingUpdateSpec { - pub skylight_data: LightingData, - pub blocklight_data: LightingData, - - _cached_skylight_update_mask: Option<VarInt>, - _cached_blocklight_update_mask: Option<VarInt>, - _cached_skylight_reset_mask: Option<VarInt>, - _cached_blocklight_reset_mask: Option<VarInt>, -} - -impl Serialize for LightingUpdateSpec { - fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult { - let ( - (skylight_update_mask, skylight_reset_mask), - (blocklight_update_mask, blocklight_reset_mask), - ) = self.get_masks(); - to.serialize_other(&skylight_update_mask)?; - to.serialize_other(&blocklight_update_mask)?; - to.serialize_other(&skylight_reset_mask)?; - to.serialize_other(&blocklight_reset_mask)?; - Self::write_lighting_data(to, &self.skylight_data)?; - Self::write_lighting_data(to, &self.blocklight_data) - } -} - -impl Deserialize for LightingUpdateSpec { - fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { - let Deserialized { - value: skylight_update_mask, - data, - } = VarInt::mc_deserialize(data)?; - let Deserialized { - value: blocklight_update_mask, - data, - } = VarInt::mc_deserialize(data)?; - let Deserialized { - value: skylight_reset_mask, - data, - } = VarInt::mc_deserialize(data)?; - let Deserialized { - value: blocklight_reset_mask, - data, - } = VarInt::mc_deserialize(data)?; - let Deserialized { - value: skylight_data, - data, - } = Self::read_lighting_data_arrays(&skylight_update_mask, data)?; - let Deserialized { - value: blocklight_data, - data, - } = Self::read_lighting_data_arrays(&blocklight_update_mask, data)?; +pub const LIGHT_DATA_LENGTH: usize = 2048; +pub const LIGHT_DATA_SECTIONS: usize = 18; - Deserialized::ok( - Self { - skylight_data, - blocklight_data, +pub struct LightingData { + pub data: Vec<Option<[u8; LIGHT_DATA_LENGTH]>>, - _cached_skylight_update_mask: Some(skylight_update_mask), - _cached_blocklight_update_mask: Some(blocklight_update_mask), - _cached_skylight_reset_mask: Some(skylight_reset_mask), - _cached_blocklight_reset_mask: Some(blocklight_reset_mask), - }, - data, - ) - } + _update_mask: Cell<Option<VarInt>>, + _reset_mask: Cell<Option<VarInt>>, } -impl LightingUpdateSpec { - pub fn compute_masks(&mut self) { - let this = &mut *self; - let skylight_data = &this.skylight_data; - let blocklight_data = &this.blocklight_data; - Self::replace_optionals_if_needed( - ( - &mut this._cached_skylight_update_mask, - &mut this._cached_skylight_reset_mask, - ), - move || Self::compute_masks_for(skylight_data), - ); - Self::replace_optionals_if_needed( - ( - &mut this._cached_blocklight_update_mask, - &mut this._cached_blocklight_reset_mask, - ), - move || Self::compute_masks_for(blocklight_data), - ); - } - - pub fn get_masks(&self) -> ((VarInt, VarInt), (VarInt, VarInt)) { - ( - Self::read_or_compute( - ( - &self._cached_skylight_update_mask, - &self._cached_skylight_reset_mask, - ), - || Self::compute_masks_for(&self.skylight_data), - ), - Self::read_or_compute( - ( - &self._cached_blocklight_update_mask, - &self._cached_blocklight_reset_mask, - ), - || Self::compute_masks_for(&self.skylight_data), - ), - ) - } - - fn read_lighting_data_arrays<'a>( - mask: &VarInt, - mut data: &'a [u8], - ) -> DeserializeResult<'a, LightingData> { - let mut out = vec![None; LIGHT_DATA_SECTIONS]; +impl LightingData { + fn deserialize(update_mask: VarInt, reset_mask: VarInt, mut data: &[u8]) -> DeserializeResult<Self> { + let mut out = Vec::with_capacity(LIGHT_DATA_SECTIONS); for i in 0..LIGHT_DATA_SECTIONS { - if (mask.0 & (1 << i)) != 0 { - let Deserialized { - value: length, - data: rest, - } = VarInt::mc_deserialize(data)?; - if (length.0 as usize) != LIGHT_DATA_LENGTH { - return DeserializeErr::CannotUnderstandValue(format!( - "all lighting update arrays are supposed to be 2048, got length of {}", - length - )) - .into(); + if update_mask.0 & (1 << i) != 0 { + if data.len() < LIGHT_DATA_LENGTH { + return Err(DeserializeErr::Eof); } - if rest.len() < LIGHT_DATA_LENGTH { - return DeserializeErr::Eof.into(); - } - - let mut data_entry = [0u8; LIGHT_DATA_LENGTH]; - let (data_src, rest) = rest.split_at(LIGHT_DATA_LENGTH); - data_entry.copy_from_slice(data_src); - out[i] = Some(data_entry); + let (section, rest) = data.split_at(LIGHT_DATA_LENGTH); + let mut to_vec = [0u8; LIGHT_DATA_LENGTH]; + to_vec.copy_from_slice(section); + out.push(Some(to_vec)); data = rest; + } else { + out.push(None) } } - Deserialized::ok(out, data) + let result = Self { + data: out, + _update_mask: Cell::new(Some(update_mask)), + _reset_mask: Cell::new(Some(reset_mask)), + }; + + Deserialized::ok(result, data) } - fn compute_masks_for(data: &LightingData) -> (VarInt, VarInt) { - let mut update_mask = 0; - let mut reset_mask = 0; - for i in 0..LIGHT_DATA_SECTIONS { - match data[i] { - Some(_) => { - update_mask |= 1 << i; - } + fn update_mask(&self) -> &VarInt { + Self::lazily_get(&self._update_mask, || self.compute_update_mask()) + } + + fn reset_mask(&self) -> &VarInt { + Self::lazily_get(&self._reset_mask, || self.compute_reset_mask()) + } + + fn lazily_get<T, F>(option: &Cell<Option<T>>, provider: F) -> &T where F: FnOnce() -> T { + unsafe { + let ptr = option.as_ptr().as_mut().expect("non-null"); + match ptr { + Some(data) => data, None => { - reset_mask |= 1 << i; + ptr.replace(provider()); + ptr.as_ref().expect("it's there") } } } + } - (VarInt(update_mask), VarInt(reset_mask)) + fn compute_update_mask(&self) -> VarInt { + self.compute_has_mask(true) } - fn replace_optionals_if_needed<T1, T2, F>( - targets: (&mut Option<T1>, &mut Option<T2>), - update: F, - ) where - F: FnOnce() -> (T1, T2), - { - let (a, b) = targets; - if a.is_none() || b.is_none() { - let (v_a, v_b) = update(); - *a = Some(v_a); - *b = Some(v_b); - } + fn compute_reset_mask(&self) -> VarInt { + self.compute_has_mask(false) } - fn read_or_compute<T1, T2, F>(targets: (&Option<T1>, &Option<T2>), update: F) -> (T1, T2) - where - F: FnOnce() -> (T1, T2), - T1: Copy, - T2: Copy, - { - let (a, b) = targets; - if a.is_none() || b.is_none() { - let (v_a, v_b) = update(); - (v_a, v_b) - } else { - (a.unwrap(), b.unwrap()) + fn compute_has_mask(&self, has: bool) -> VarInt { + let mut out: u32 = 0; + for i in 0..LIGHT_DATA_SECTIONS { + if self.data[i].is_some() == has { + out |= 1 << i; + } } + + VarInt(out as i32) } - fn write_lighting_data<S: Serializer>(to: &mut S, data: &LightingData) -> SerializeResult { - for i in 0..LIGHT_DATA_SECTIONS { - if let Some(entry) = &data[i] { - to.serialize_other(&VarInt(LIGHT_DATA_LENGTH as i32))?; - to.serialize_bytes(&entry[..])?; + fn serialize_data<S: Serializer>(&self, to: &mut S) -> SerializeResult { + for item in &self.data { + if let Some(contents) = item { + to.serialize_bytes(&contents[..])?; } } @@ -3202,36 +3060,57 @@ impl LightingUpdateSpec { } } -#[cfg(test)] -impl TestRandom for LightingUpdateSpec { - fn test_gen_random() -> Self { - let (skylight_update_mask, skylight_reset_mask, skylight_data) = - Self::gen_random_lighting_data(); - let (blocklight_update_mask, blocklight_reset_mask, blocklight_data) = - Self::gen_random_lighting_data(); +impl std::fmt::Debug for LightingData { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "LightingData(update={:018b}, reset={:018b}, size={}, bytes={})", + self.update_mask().0, + self.reset_mask().0, + self.data.iter().filter(move |v| v.is_some()).count(), + self.data.iter() + .filter_map(move |v| v. + map(move |arr| arr.len())) + .sum::<usize>()) + } +} - Self { - skylight_data, - blocklight_data, +impl std::fmt::Display for LightingData { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + <dyn std::fmt::Debug>::fmt(self, f) + } +} - _cached_skylight_update_mask: Some(skylight_update_mask), - _cached_blocklight_update_mask: Some(blocklight_update_mask), - _cached_skylight_reset_mask: Some(skylight_reset_mask), - _cached_blocklight_reset_mask: Some(blocklight_reset_mask), +impl Clone for LightingData { + fn clone(&self) -> Self { + Self { + data: self.data.clone(), + _update_mask: Cell::new(Some(self.update_mask().clone())), + _reset_mask: Cell::new(Some(self.reset_mask().clone())), } } } +impl PartialEq for LightingData { + fn eq(&self, other: &Self) -> bool { + self.data.eq(&other.data) && + self.update_mask().eq(other.update_mask()) && + self.reset_mask().eq(other.reset_mask()) + } +} + #[cfg(test)] -impl LightingUpdateSpec { +impl LightingData { fn gen_random_mask() -> i32 { let rand: u32 = rand::random(); (rand & ((1 << 19) - 1)) as i32 } +} - fn gen_random_lighting_data() -> (VarInt, VarInt, LightingData) { +#[cfg(test)] +impl TestRandom for LightingData { + fn test_gen_random() -> Self { let set_mask = Self::gen_random_mask(); - let reset_mask = !set_mask & ((1 << 19) - 1); let mut data = vec![None; LIGHT_DATA_SECTIONS]; for i in 0..LIGHT_DATA_SECTIONS { if (set_mask & (1 << i)) != 0 { @@ -3243,7 +3122,65 @@ impl LightingUpdateSpec { } } - (VarInt(set_mask), VarInt(reset_mask), data) + let cache_masks = rand::random::<bool>(); + + if cache_masks { + Self { + data, + _update_mask: Cell::new(Some(VarInt(set_mask))), + _reset_mask: Cell::new(None), + } + } else { + Self { + data, + _update_mask: Cell::new(None), + _reset_mask: Cell::new(None), + } + } + } +} + +#[derive(Clone, PartialEq, Debug)] +pub struct LightingUpdateSpec { + pub skylight_data: LightingData, + pub blocklight_data: LightingData, +} + +impl Serialize for LightingUpdateSpec { + fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult { + self.skylight_data.update_mask().mc_serialize(to)?; + self.blocklight_data.update_mask().mc_serialize(to)?; + self.skylight_data.reset_mask().mc_serialize(to)?; + self.blocklight_data.reset_mask().mc_serialize(to)?; + self.skylight_data.serialize_data(to)?; + self.blocklight_data.serialize_data(to) + } +} + +impl Deserialize for LightingUpdateSpec { + fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { + let Deserialized { value: skylight_update_mask, data } = VarInt::mc_deserialize(data)?; + let Deserialized { value: blocklight_update_mask, data } = VarInt::mc_deserialize(data)?; + let Deserialized { value: skylight_reset_mask, data } = VarInt::mc_deserialize(data)?; + let Deserialized { value: blocklight_reset_mask, data } = VarInt::mc_deserialize(data)?; + + let Deserialized { value: skylight_data, data } = LightingData::deserialize(skylight_update_mask, skylight_reset_mask, data)?; + let Deserialized { value: blocklight_data, data } = LightingData::deserialize(blocklight_update_mask, blocklight_reset_mask, data)?; + + Deserialized::ok(Self { + skylight_data, + blocklight_data, + }, data) + } +} + +#[cfg(test)] +impl TestRandom for LightingUpdateSpec { + fn test_gen_random() -> Self { + Self { + skylight_data: LightingData::test_gen_random(), + blocklight_data: LightingData::test_gen_random(), + } } } |