mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
fix(protocol): remap particle IDs for older clients (#2451)
* feat(protocol): generate particle ID remap tables Generate version-specific particle registry mappings from the existing ViaBackwards data for every supported Java protocol version.\n\nExpose the generated remapper through pumpkin-data and enable it for pumpkin-protocol so packet serializers can translate current registry IDs for older clients. * fix(protocol): remap explosion particles for older clients Translate the explosion particle registry ID for each client's negotiated Java version before serializing the explode packet.\n\nWithout this remap, 1.21.11 interpreted the 26.2 explosion-emitter ID as falling dust, consumed the following bytes as particle data, and disconnected with a decoder exception. Add packet-level coverage for both 1.21.11 and 26.2 encodings. * fix(protocol): remap particle IDs for older clients Level-particle packets and particle entity metadata still encoded raw 26.2 registry IDs, causing older clients to decode the wrong particle schema and disconnect. Route every active outbound particle path through the version remapper, preserve metadata payloads, and cover 1.21.11 and 26.2 encodings with regression tests.
This commit is contained in:
@@ -6,6 +6,7 @@ use crate::version::JavaMinecraftVersion;
|
||||
mod block_state;
|
||||
mod entity_id;
|
||||
mod item_id;
|
||||
mod particle_id;
|
||||
mod sound_id;
|
||||
|
||||
/// Returns the list of remap builder functions paired with their output file names.
|
||||
@@ -15,6 +16,7 @@ pub fn build() -> Vec<(fn() -> TokenStream, &'static str)> {
|
||||
(block_state::build, "block_state_remap.rs"),
|
||||
(entity_id::build, "entity_id_remap.rs"),
|
||||
(item_id::build, "item_id_remap.rs"),
|
||||
(particle_id::build, "particle_id_remap.rs"),
|
||||
(sound_id::build, "sound_id_remap.rs"),
|
||||
]
|
||||
}
|
||||
|
||||
125
pumpkin-codegen/src/remap/particle_id.rs
Normal file
125
pumpkin-codegen/src/remap/particle_id.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
use proc_macro2::{Literal, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
use crate::remap::{MappingNode, ParsedMappings, Remapper};
|
||||
use crate::version::JavaMinecraftVersion;
|
||||
|
||||
/// Generates the `TokenStream` for per-version particle ID remap tables and the
|
||||
/// `remap_particle_id_for_version` function.
|
||||
pub fn build() -> TokenStream {
|
||||
let node_1_20_5 = MappingNode {
|
||||
version: JavaMinecraftVersion::V_1_20_5,
|
||||
value: "../assets/viabackwards/data/mappings-1.21to1.20.5.nbt",
|
||||
child: None,
|
||||
};
|
||||
let node_1_21 = MappingNode {
|
||||
version: JavaMinecraftVersion::V_1_21,
|
||||
value: "../assets/viabackwards/data/mappings-1.21.2to1.21.nbt",
|
||||
child: Some(&node_1_20_5),
|
||||
};
|
||||
let node_1_21_2 = MappingNode {
|
||||
version: JavaMinecraftVersion::V_1_21_2,
|
||||
value: "../assets/viabackwards/data/mappings-1.21.4to1.21.2.nbt",
|
||||
child: Some(&node_1_21),
|
||||
};
|
||||
let node_1_21_4 = MappingNode {
|
||||
version: JavaMinecraftVersion::V_1_21_4,
|
||||
value: "../assets/viabackwards/data/mappings-1.21.5to1.21.4.nbt",
|
||||
child: Some(&node_1_21_2),
|
||||
};
|
||||
let node_1_21_5 = MappingNode {
|
||||
version: JavaMinecraftVersion::V_1_21_5,
|
||||
value: "../assets/viabackwards/data/mappings-1.21.6to1.21.5.nbt",
|
||||
child: Some(&node_1_21_4),
|
||||
};
|
||||
let node_1_21_6 = MappingNode {
|
||||
version: JavaMinecraftVersion::V_1_21_6,
|
||||
value: "../assets/viabackwards/data/mappings-1.21.7to1.21.6.nbt",
|
||||
child: Some(&node_1_21_5),
|
||||
};
|
||||
let node_1_21_7 = MappingNode {
|
||||
version: JavaMinecraftVersion::V_1_21_7,
|
||||
value: "../assets/viabackwards/data/mappings-1.21.9to1.21.7.nbt",
|
||||
child: Some(&node_1_21_6),
|
||||
};
|
||||
let node_1_21_9 = MappingNode {
|
||||
version: JavaMinecraftVersion::V_1_21_9,
|
||||
value: "../assets/viabackwards/data/mappings-1.21.11to1.21.9.nbt",
|
||||
child: Some(&node_1_21_7),
|
||||
};
|
||||
let node_1_21_11 = MappingNode {
|
||||
version: JavaMinecraftVersion::V_1_21_11,
|
||||
value: "../assets/viabackwards/data/mappings-26.1to1.21.11.nbt",
|
||||
child: Some(&node_1_21_9),
|
||||
};
|
||||
let node_26_1 = MappingNode {
|
||||
version: JavaMinecraftVersion::V_26_1,
|
||||
value: "../assets/viabackwards/data/mappings-26.2to26.1.nbt",
|
||||
child: Some(&node_1_21_11),
|
||||
};
|
||||
let remapper: Remapper<_, Option<Vec<u16>>> = Remapper {
|
||||
version: JavaMinecraftVersion::V_26_2,
|
||||
remapper: |first, second| match (first, second) {
|
||||
(Some(first), Some(second)) => Some(
|
||||
first
|
||||
.iter()
|
||||
.map(|id| second.get(usize::from(*id)).copied().unwrap_or(0))
|
||||
.collect(),
|
||||
),
|
||||
(None, Some(second)) => Some(
|
||||
(0..second.len())
|
||||
.map(|id| second.get(id).copied().unwrap_or(0))
|
||||
.collect(),
|
||||
),
|
||||
(Some(first), None) => Some(first.clone()),
|
||||
_ => None,
|
||||
},
|
||||
serializer: |&file| {
|
||||
ParsedMappings::parse_mapping_file(file, "particles")
|
||||
.map(|mappings| mappings.to_u16(file))
|
||||
},
|
||||
};
|
||||
|
||||
let all_mappings = remapper.process(&node_26_1);
|
||||
let mut static_values = TokenStream::new();
|
||||
let mut match_arms = TokenStream::new();
|
||||
for (ver, mapping) in &all_mappings {
|
||||
let ident = format_ident!(
|
||||
"{}",
|
||||
format!("PARTICLE_ID_REMAP_{:?}_TO_{:?}", remapper.version, ver).to_uppercase()
|
||||
);
|
||||
let mapping_tokens: Vec<_> = mapping
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.copied()
|
||||
.map(Literal::u16_unsuffixed)
|
||||
.collect();
|
||||
static_values.extend(quote! {
|
||||
const #ident: &[u16] = &[#(#mapping_tokens),*];
|
||||
});
|
||||
match_arms.extend(quote! {
|
||||
#ver => #ident
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id),
|
||||
});
|
||||
}
|
||||
|
||||
quote! {
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
|
||||
#static_values
|
||||
|
||||
#[must_use]
|
||||
pub fn remap_particle_id_for_version(
|
||||
particle_id: u16,
|
||||
version: JavaMinecraftVersion,
|
||||
) -> u16 {
|
||||
match version {
|
||||
#match_arms
|
||||
_ => particle_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,7 @@ block = []
|
||||
item_id_remap = []
|
||||
entity_id_remap = []
|
||||
sound_id_remap = []
|
||||
particle_id_remap = []
|
||||
potion_brewing = []
|
||||
|
||||
[dependencies]
|
||||
|
||||
144
pumpkin-data/src/generated/particle_id_remap.rs
Normal file
144
pumpkin-data/src/generated/particle_id_remap.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
/* This file is generated. Do not edit manually. */
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
const PARTICLE_ID_REMAP_V_26_2_TO_V_1_20_5: &[u16] = &[
|
||||
0, 1, 2, 3, 68, 71, 4, 4, 0, 0, 0, 4, 37, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 33, 41, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 20, 40, 40, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
|
||||
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
|
||||
86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
|
||||
108, 1, 78, 46,
|
||||
];
|
||||
const PARTICLE_ID_REMAP_V_26_2_TO_V_1_21: &[u16] = &[
|
||||
0, 1, 2, 3, 68, 71, 4, 4, 0, 0, 0, 4, 37, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 33, 41, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 20, 40, 40, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
|
||||
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
|
||||
86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
|
||||
108, 1, 78, 46,
|
||||
];
|
||||
const PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_2: &[u16] = &[
|
||||
0, 1, 2, 3, 69, 72, 4, 4, 0, 0, 0, 4, 37, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 33, 41, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 40, 40, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
|
||||
63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
|
||||
87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
|
||||
108, 109, 110, 79, 47,
|
||||
];
|
||||
const PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_4: &[u16] = &[
|
||||
0, 1, 2, 3, 70, 73, 4, 4, 0, 0, 0, 4, 38, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 42, 35, 36, 37, 38, 39, 40, 41,
|
||||
42, 43, 44, 45, 46, 47, 41, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
|
||||
109, 110, 111, 80, 48,
|
||||
];
|
||||
const PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_5: &[u16] = &[
|
||||
0, 1, 2, 3, 71, 74, 4, 4, 0, 0, 0, 4, 39, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
|
||||
43, 44, 45, 46, 47, 48, 42, 42, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
|
||||
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
|
||||
89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
||||
110, 111, 112, 113, 49,
|
||||
];
|
||||
const PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_6: &[u16] = &[
|
||||
0, 1, 2, 3, 71, 74, 4, 4, 0, 0, 0, 4, 39, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
|
||||
43, 44, 45, 46, 47, 48, 42, 42, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
|
||||
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
|
||||
89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
||||
110, 111, 112, 113, 49,
|
||||
];
|
||||
const PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_7: &[u16] = &[
|
||||
0, 1, 2, 3, 71, 74, 4, 4, 0, 0, 0, 4, 39, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
|
||||
43, 44, 45, 46, 47, 48, 42, 42, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
|
||||
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
|
||||
89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
||||
110, 111, 112, 113, 49,
|
||||
];
|
||||
const PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_9: &[u16] = &[
|
||||
0, 1, 2, 3, 72, 75, 4, 4, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 43, 43, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
|
||||
66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
|
||||
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
|
||||
111, 112, 113, 114, 50,
|
||||
];
|
||||
const PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_11: &[u16] = &[
|
||||
0, 1, 2, 3, 72, 75, 4, 4, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 43, 43, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
|
||||
66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
|
||||
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
|
||||
111, 112, 113, 114, 50,
|
||||
];
|
||||
const PARTICLE_ID_REMAP_V_26_2_TO_V_26_1: &[u16] = &[
|
||||
0, 1, 2, 3, 74, 77, 4, 4, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
|
||||
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
|
||||
92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 52,
|
||||
];
|
||||
#[must_use]
|
||||
pub fn remap_particle_id_for_version(particle_id: u16, version: JavaMinecraftVersion) -> u16 {
|
||||
match version {
|
||||
pumpkin_util::version::JavaMinecraftVersion::V_1_20_5 => {
|
||||
PARTICLE_ID_REMAP_V_26_2_TO_V_1_20_5
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id)
|
||||
}
|
||||
pumpkin_util::version::JavaMinecraftVersion::V_1_21 => PARTICLE_ID_REMAP_V_26_2_TO_V_1_21
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id),
|
||||
pumpkin_util::version::JavaMinecraftVersion::V_1_21_2 => {
|
||||
PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_2
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id)
|
||||
}
|
||||
pumpkin_util::version::JavaMinecraftVersion::V_1_21_4 => {
|
||||
PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_4
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id)
|
||||
}
|
||||
pumpkin_util::version::JavaMinecraftVersion::V_1_21_5 => {
|
||||
PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_5
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id)
|
||||
}
|
||||
pumpkin_util::version::JavaMinecraftVersion::V_1_21_6 => {
|
||||
PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_6
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id)
|
||||
}
|
||||
pumpkin_util::version::JavaMinecraftVersion::V_1_21_7 => {
|
||||
PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_7
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id)
|
||||
}
|
||||
pumpkin_util::version::JavaMinecraftVersion::V_1_21_9 => {
|
||||
PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_9
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id)
|
||||
}
|
||||
pumpkin_util::version::JavaMinecraftVersion::V_1_21_11 => {
|
||||
PARTICLE_ID_REMAP_V_26_2_TO_V_1_21_11
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id)
|
||||
}
|
||||
pumpkin_util::version::JavaMinecraftVersion::V_26_1 => PARTICLE_ID_REMAP_V_26_2_TO_V_26_1
|
||||
.get(usize::from(particle_id))
|
||||
.copied()
|
||||
.unwrap_or(particle_id),
|
||||
_ => particle_id,
|
||||
}
|
||||
}
|
||||
@@ -250,6 +250,11 @@ pub mod entity_id_remap;
|
||||
#[path = "generated/sound_id_remap.rs"]
|
||||
pub mod sound_id_remap;
|
||||
|
||||
#[cfg(feature = "particle_id_remap")]
|
||||
#[rustfmt::skip]
|
||||
#[path = "generated/particle_id_remap.rs"]
|
||||
pub mod particle_id_remap;
|
||||
|
||||
#[cfg(feature = "bedrock_creative")]
|
||||
#[rustfmt::skip]
|
||||
#[path = "generated/bedrock_creative.rs"]
|
||||
|
||||
@@ -13,7 +13,7 @@ query = []
|
||||
|
||||
[dependencies]
|
||||
pumpkin-nbt.workspace = true
|
||||
pumpkin-data = { workspace = true, features = ["packet", "item_id_remap", "entity_id_remap", "sound_id_remap", "recipes", "bedrock_creative"] }
|
||||
pumpkin-data = { workspace = true, features = ["packet", "item_id_remap", "entity_id_remap", "sound_id_remap", "particle_id_remap", "recipes", "bedrock_creative"] }
|
||||
pumpkin-macros.workspace = true
|
||||
pumpkin-world.workspace = true
|
||||
pumpkin-util.workspace = true
|
||||
|
||||
@@ -13,6 +13,8 @@ use crate::{
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
|
||||
use super::particle::particle_id_for_version;
|
||||
|
||||
pub trait MetadataSerializer {
|
||||
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError>;
|
||||
}
|
||||
@@ -138,6 +140,22 @@ impl<T> Metadata<T> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.r#type == MetaDataType::PARTICLE {
|
||||
let mut serialized_value = Vec::new();
|
||||
self.value.write_metadata(&mut serialized_value)?;
|
||||
|
||||
let mut cursor = Cursor::new(serialized_value);
|
||||
let particle_id = VarInt::decode(&mut cursor).map_err(|e| {
|
||||
WritingError::Message(format!("Failed to decode particle metadata: {e}"))
|
||||
})?;
|
||||
writer.write_var_int(&particle_id_for_version(particle_id, *version))?;
|
||||
|
||||
let remainder_start = cursor.position() as usize;
|
||||
let inner = cursor.into_inner();
|
||||
writer.write_slice(&inner[remainder_start..])?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.value.write_metadata(&mut writer)?;
|
||||
|
||||
Ok(())
|
||||
@@ -264,3 +282,71 @@ impl MetadataSerializer for crate::codec::optional_int::OptionalInt {
|
||||
writer.write_var_int(&VarInt(val))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::{Cursor, Read};
|
||||
|
||||
use pumpkin_data::{
|
||||
meta_data_type::MetaDataType, particle::Particle, tracked_data::TrackedData,
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
|
||||
use crate::{VarInt, ser::NetworkWriteExt};
|
||||
|
||||
use super::{Metadata, MetadataSerializer};
|
||||
|
||||
struct ParticleMetadata {
|
||||
particle_id: VarInt,
|
||||
data: [u8; 4],
|
||||
}
|
||||
|
||||
impl MetadataSerializer for ParticleMetadata {
|
||||
fn write_metadata(
|
||||
&self,
|
||||
writer: &mut impl std::io::Write,
|
||||
) -> Result<(), crate::WritingError> {
|
||||
writer.write_var_int(&self.particle_id)?;
|
||||
writer.write_slice(&self.data)
|
||||
}
|
||||
}
|
||||
|
||||
fn encoded_particle(version: JavaMinecraftVersion) -> (VarInt, Vec<u8>) {
|
||||
let particle_data = [0x12, 0x34, 0x56, 0x78];
|
||||
let metadata = Metadata::new(
|
||||
TrackedData::PARTICLE,
|
||||
MetaDataType::PARTICLE,
|
||||
ParticleMetadata {
|
||||
particle_id: VarInt(Particle::ExplosionEmitter as i32),
|
||||
data: particle_data,
|
||||
},
|
||||
);
|
||||
let mut bytes = Vec::new();
|
||||
metadata.write(&mut bytes, &version).unwrap();
|
||||
|
||||
assert_eq!(bytes[0], TrackedData::PARTICLE.get(&version));
|
||||
assert_eq!(bytes[1], MetaDataType::PARTICLE.id(version) as u8);
|
||||
|
||||
let mut cursor = Cursor::new(&bytes[2..]);
|
||||
let particle_id = VarInt::decode(&mut cursor).unwrap();
|
||||
let mut remainder = Vec::new();
|
||||
cursor.read_to_end(&mut remainder).unwrap();
|
||||
(particle_id, remainder)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn particle_metadata_id_remaps_for_1_21_11() {
|
||||
let (particle_id, data) = encoded_particle(JavaMinecraftVersion::V_1_21_11);
|
||||
|
||||
assert_eq!(particle_id, VarInt(22));
|
||||
assert_eq!(data, [0x12, 0x34, 0x56, 0x78]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn particle_metadata_id_stays_latest_for_26_2() {
|
||||
let (particle_id, data) = encoded_particle(JavaMinecraftVersion::V_26_2);
|
||||
|
||||
assert_eq!(particle_id, VarInt(29));
|
||||
assert_eq!(data, [0x12, 0x34, 0x56, 0x78]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ use crate::ser::NetworkWriteExt;
|
||||
use crate::{IdOr, SoundEvent, codec::var_int::VarInt};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
|
||||
use super::particle::particle_id_for_version;
|
||||
|
||||
/// Notifies the client that an explosion has occurred.
|
||||
///
|
||||
/// This is a high-level packet that handles the visual, auditory, and physical
|
||||
@@ -60,7 +62,7 @@ impl ClientPacket for CExplosion {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
write.write_f64_be(self.center.x)?;
|
||||
write.write_f64_be(self.center.y)?;
|
||||
@@ -73,7 +75,8 @@ impl ClientPacket for CExplosion {
|
||||
w.write_f64_be(k.z)?;
|
||||
Ok(())
|
||||
})?;
|
||||
write.write_var_int(&self.particle)?;
|
||||
let particle = particle_id_for_version(self.particle, *version);
|
||||
write.write_var_int(&particle)?;
|
||||
match &self.sound {
|
||||
IdOr::Id(id) => write.write_var_int(&VarInt((*id + 1) as i32))?,
|
||||
IdOr::Value(event) => {
|
||||
@@ -86,3 +89,48 @@ impl ClientPacket for CExplosion {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::{Cursor, Seek, SeekFrom};
|
||||
|
||||
use pumpkin_data::particle::Particle;
|
||||
use pumpkin_util::{math::vector3::Vector3, version::JavaMinecraftVersion};
|
||||
|
||||
use crate::{ClientPacket, IdOr, VarInt};
|
||||
|
||||
use super::CExplosion;
|
||||
|
||||
fn encoded_particle_id(version: JavaMinecraftVersion) -> VarInt {
|
||||
let packet = CExplosion::new(
|
||||
Vector3::new(0.0, 0.0, 0.0),
|
||||
4.0,
|
||||
0,
|
||||
None,
|
||||
VarInt(Particle::ExplosionEmitter as i32),
|
||||
IdOr::Id(0),
|
||||
);
|
||||
let mut bytes = Vec::new();
|
||||
packet.write_packet_data(&mut bytes, &version).unwrap();
|
||||
|
||||
let mut cursor = Cursor::new(bytes);
|
||||
cursor.seek(SeekFrom::Start(33)).unwrap();
|
||||
VarInt::decode(&mut cursor).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explosion_particle_id_remaps_for_1_21_11() {
|
||||
assert_eq!(
|
||||
encoded_particle_id(JavaMinecraftVersion::V_1_21_11),
|
||||
VarInt(22)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explosion_particle_id_stays_latest_for_26_2() {
|
||||
assert_eq!(
|
||||
encoded_particle_id(JavaMinecraftVersion::V_26_2),
|
||||
VarInt(29)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::io::Write;
|
||||
|
||||
use pumpkin_data::packet::clientbound::PLAY_LEVEL_PARTICLES;
|
||||
use pumpkin_data::{
|
||||
packet::clientbound::PLAY_LEVEL_PARTICLES, particle_id_remap::remap_particle_id_for_version,
|
||||
};
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::{math::vector3::Vector3, version::JavaMinecraftVersion};
|
||||
|
||||
@@ -64,11 +66,23 @@ impl<'a> CParticle<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn particle_id_for_version(
|
||||
particle_id: VarInt,
|
||||
version: JavaMinecraftVersion,
|
||||
) -> VarInt {
|
||||
u16::try_from(particle_id.0).map_or(particle_id, |particle_id| {
|
||||
VarInt(i32::from(remap_particle_id_for_version(
|
||||
particle_id,
|
||||
version,
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
impl ClientPacket for CParticle<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
write: impl Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
version: &JavaMinecraftVersion,
|
||||
) -> Result<(), WritingError> {
|
||||
let mut write = write;
|
||||
|
||||
@@ -85,8 +99,55 @@ impl ClientPacket for CParticle<'_> {
|
||||
|
||||
write.write_f32_be(self.max_speed)?;
|
||||
write.write_i32_be(self.particle_count)?;
|
||||
write.write_var_int(&self.particle_id)?;
|
||||
write.write_var_int(&particle_id_for_version(self.particle_id, *version))?;
|
||||
|
||||
write.write_all(self.data).map_err(WritingError::IoError)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::{Cursor, Seek, SeekFrom};
|
||||
|
||||
use pumpkin_data::particle::Particle;
|
||||
use pumpkin_util::{math::vector3::Vector3, version::JavaMinecraftVersion};
|
||||
|
||||
use crate::{ClientPacket, VarInt};
|
||||
|
||||
use super::CParticle;
|
||||
|
||||
fn encoded_particle_id(version: JavaMinecraftVersion) -> VarInt {
|
||||
let packet = CParticle::new(
|
||||
false,
|
||||
false,
|
||||
Vector3::new(0.0, 0.0, 0.0),
|
||||
Vector3::new(0.0, 0.0, 0.0),
|
||||
0.0,
|
||||
1,
|
||||
VarInt(Particle::ExplosionEmitter as i32),
|
||||
&[],
|
||||
);
|
||||
let mut bytes = Vec::new();
|
||||
packet.write_packet_data(&mut bytes, &version).unwrap();
|
||||
|
||||
let mut cursor = Cursor::new(bytes);
|
||||
cursor.seek(SeekFrom::Start(46)).unwrap();
|
||||
VarInt::decode(&mut cursor).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn particle_id_remaps_for_1_21_11() {
|
||||
assert_eq!(
|
||||
encoded_particle_id(JavaMinecraftVersion::V_1_21_11),
|
||||
VarInt(22)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn particle_id_stays_latest_for_26_2() {
|
||||
assert_eq!(
|
||||
encoded_particle_id(JavaMinecraftVersion::V_26_2),
|
||||
VarInt(29)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user