This commit is contained in:
Alexander Medvedev
2026-08-15 16:30:25 +02:00
parent a2b92e6dc5
commit 0fe84c75d8
109 changed files with 84259 additions and 1204 deletions

View File

@@ -7,15 +7,10 @@ use crate::version::JavaMinecraftVersion;
/// Generates the `TokenStream` for per-version block-state remap tables and the
/// `remap_block_state_for_version` function.
pub fn build() -> TokenStream {
let node_1_7_2 = MappingNode {
version: JavaMinecraftVersion::V_1_7_2,
value: "../../assets/viabackwards/data/mappings-1.7.6to1.7.2.nbt",
child: None,
};
let node_1_7_6 = MappingNode {
version: JavaMinecraftVersion::V_1_7_6,
value: "../../assets/viarewind/data/mappings-1.8to1.7.10.nbt",
child: Some(&node_1_7_2),
child: None,
};
let node_1_8 = MappingNode {
version: JavaMinecraftVersion::V_1_8,

View File

@@ -7,15 +7,10 @@ use crate::version::JavaMinecraftVersion;
/// Generates the `TokenStream` for per-version entity ID remap tables and the
/// `remap_entity_id_for_version` function.
pub fn build() -> TokenStream {
let node_1_7_2 = MappingNode {
version: JavaMinecraftVersion::V_1_7_2,
value: "../../assets/viabackwards/data/mappings-1.7.6to1.7.2.nbt",
child: None,
};
let node_1_7_6 = MappingNode {
version: JavaMinecraftVersion::V_1_7_6,
value: "../../assets/viarewind/data/mappings-1.8to1.7.10.nbt",
child: Some(&node_1_7_2),
child: None,
};
let node_1_8 = MappingNode {
version: JavaMinecraftVersion::V_1_8,

View File

@@ -9,15 +9,10 @@ use crate::version::JavaMinecraftVersion;
pub fn build() -> TokenStream {
// ViaBackwards mappings go new → old (26.1 → 1.21.11 → ... → 1.20.5)
// This is the correct direction for a new server sending to old clients.
let node_1_7_2 = MappingNode {
version: JavaMinecraftVersion::V_1_7_2,
value: "../../assets/viabackwards/data/mappings-1.7.6to1.7.2.nbt",
child: None,
};
let node_1_7_6 = MappingNode {
version: JavaMinecraftVersion::V_1_7_6,
value: "../../assets/viarewind/data/mappings-1.8to1.7.10.nbt",
child: Some(&node_1_7_2),
child: None,
};
let node_1_8 = MappingNode {
version: JavaMinecraftVersion::V_1_8,

View File

@@ -111,18 +111,40 @@ impl ParsedMappings {
let forward = match strategy {
// Direct
0 => mappings
.get_int_array("val")
.unwrap_or_else(|| panic!("Missing `{section}.val` for direct mapping in {path}"))
.to_vec(),
0 => {
if let Some(val) = mappings.get_int_array("val") {
val.to_vec()
} else if let Some(val_bytes) = mappings.get_byte_array("val") {
let size = mappings.get_int("size").unwrap_or(mapped_size) as usize;
let bytes: &[u8] = unsafe {
std::slice::from_raw_parts(val_bytes.as_ptr().cast::<u8>(), val_bytes.len())
};
let mut cursor = std::io::Cursor::new(bytes);
let mut values = Vec::with_capacity(size);
let mut prev = 0i32;
for _ in 0..size {
prev += Self::read_zigzag_var_int(&mut cursor).unwrap_or(0);
values.push(prev);
}
values
} else {
panic!("Missing `{section}.val` for direct mapping in {path}");
}
}
// Shifts
1 => {
let shifts_at = mappings.get_int_array("at").unwrap_or_else(|| {
panic!("Missing `{section}.at` for shift mapping in {path}")
});
let shifts_to = mappings.get_int_array("to").unwrap_or_else(|| {
panic!("Missing `{section}.to` for shift mapping in {path}")
});
let (shifts_at, shifts_to) = if let (Some(at), Some(to)) =
(mappings.get_int_array("at"), mappings.get_int_array("to"))
{
(at.to_vec(), to.to_vec())
} else if let Some(val_bytes) = mappings.get_byte_array("val") {
Self::read_at_value_pairs(val_bytes)
} else {
panic!(
"Missing `{section}.at`/`to` or `{section}.val` for shift mapping in {path}"
);
};
let size = mappings.get_int("size").unwrap_or_else(|| {
panic!("Missing `{section}.size` for shift mapping in {path}")
}) as usize;
@@ -156,12 +178,16 @@ impl ParsedMappings {
}
// Changes
2 => {
let changes_at = mappings.get_int_array("at").unwrap_or_else(|| {
panic!("Missing `{section}.at` for change mapping in {path}")
});
let values = mappings.get_int_array("val").unwrap_or_else(|| {
panic!("Missing `{section}.val` for change mapping in {path}")
});
let (changes_at, values) = if let (Some(at), Some(val)) =
(mappings.get_int_array("at"), mappings.get_int_array("val"))
{
(at.to_vec(), val.to_vec())
} else if let Some(val_bytes) = mappings.get_byte_array("val") {
Self::read_at_value_pairs(val_bytes)
} else {
panic!("Missing `{section}.at`/`val` for change mapping in {path}");
};
let size = mappings.get_int("size").unwrap_or_else(|| {
panic!("Missing `{section}.size` for change mapping in {path}")
}) as usize;
@@ -186,6 +212,12 @@ impl ParsedMappings {
result[*changed_id as usize] = values[index];
}
if fill_between {
for id in next_unhandled_id..size as i32 {
result[id as usize] = id;
}
}
result
}
// Identity
@@ -204,6 +236,53 @@ impl ParsedMappings {
}
}
fn read_var_int(cursor: &mut std::io::Cursor<&[u8]>) -> Option<i32> {
use std::io::Read;
let mut num_read = 0;
let mut result = 0i32;
loop {
let mut byte = [0u8; 1];
if cursor.read_exact(&mut byte).is_err() {
return None;
}
let b = byte[0];
let value = (b & 0b0111_1111) as i32;
result |= value << (7 * num_read);
num_read += 1;
if num_read > 5 {
return None;
}
if (b & 0b1000_0000) == 0 {
break;
}
}
Some(result)
}
fn read_zigzag_var_int(cursor: &mut std::io::Cursor<&[u8]>) -> Option<i32> {
let value = Self::read_var_int(cursor)?;
let unsigned = value as u32;
Some(((unsigned >> 1) as i32) ^ (-((unsigned & 1) as i32)))
}
fn read_at_value_pairs(val_bytes: &[i8]) -> (Vec<i32>, Vec<i32>) {
let bytes: &[u8] =
unsafe { std::slice::from_raw_parts(val_bytes.as_ptr().cast::<u8>(), val_bytes.len()) };
let mut cursor = std::io::Cursor::new(bytes);
let mut at = Vec::new();
let mut values = Vec::new();
let mut prev_at = -1i32;
let mut prev_val = 0i32;
while let Some(diff_at) = Self::read_var_int(&mut cursor) {
let diff_val = Self::read_zigzag_var_int(&mut cursor).unwrap_or(0);
prev_at = prev_at + 1 + diff_at;
prev_val += diff_val;
at.push(prev_at);
values.push(prev_val);
}
(at, values)
}
/// Inverts the forward mapping into a reverse lookup table where index is the new ID and value
/// is the corresponding old ID. Unmapped entries default to their own index cast to `u16`.
///
@@ -248,6 +327,10 @@ impl ParsedMappings {
.map(|&id| {
if id < 0 {
0 // unmapped → air
} else if id > 0xFFFF {
// For pre-1.13 mappings where itemId was packed as (id << 16) | data
u16::try_from(id >> 16)
.unwrap_or_else(|_| panic!("{name}: id {id} does not fit in u16"))
} else {
u16::try_from(id)
.unwrap_or_else(|_| panic!("{name}: id {id} does not fit in u16"))

View File

@@ -7,15 +7,10 @@ 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_7_2 = MappingNode {
version: JavaMinecraftVersion::V_1_7_2,
value: "../../assets/viabackwards/data/mappings-1.7.6to1.7.2.nbt",
child: None,
};
let node_1_7_6 = MappingNode {
version: JavaMinecraftVersion::V_1_7_6,
value: "../../assets/viarewind/data/mappings-1.8to1.7.10.nbt",
child: Some(&node_1_7_2),
child: None,
};
let node_1_8 = MappingNode {
version: JavaMinecraftVersion::V_1_8,

View File

@@ -7,15 +7,10 @@ use crate::version::JavaMinecraftVersion;
/// Generates the `TokenStream` for per-version sound ID remap tables and the
/// `remap_sound_id_for_version` function.
pub fn build() -> TokenStream {
let node_1_7_2 = MappingNode {
version: JavaMinecraftVersion::V_1_7_2,
value: "../../assets/viabackwards/data/mappings-1.7.6to1.7.2.nbt",
child: None,
};
let node_1_7_6 = MappingNode {
version: JavaMinecraftVersion::V_1_7_6,
value: "../../assets/viarewind/data/mappings-1.8to1.7.10.nbt",
child: Some(&node_1_7_2),
child: None,
};
let node_1_8 = MappingNode {
version: JavaMinecraftVersion::V_1_8,

View File

@@ -230,14 +230,37 @@ fn convert_value(
let expr = match type_ident {
"String" | "str" => match mode {
MappingMode::Serialize => {
if is_ref {
if is_slice {
let tmp = dst.unwrap_or("slice");
if is_ref {
prep.push_str(&format!(
"{}let vec_{}: Vec<&str> = {}.iter().map(|s| s.as_str()).collect();\n",
prep_prefix, tmp, src
));
format!("&vec_{}", tmp)
} else {
format!("{}.clone()", src)
}
} else if is_ref {
format!("&{}", src)
} else {
format!("{}.clone()", src)
}
}
MappingMode::Deserialize => format!("{}.into()", src),
MappingMode::ToWit => format!("{}.to_string()", src),
MappingMode::Deserialize => {
if is_slice {
format!("{}.iter().map(|s| s.to_string()).collect()", src)
} else {
format!("{}.into()", src)
}
}
MappingMode::ToWit => {
if is_slice {
format!("{}.iter().map(|s| s.to_string()).collect()", src)
} else {
format!("{}.to_string()", src)
}
}
MappingMode::Downcast => String::new(),
},
"Identifier" => match mode {

View File

@@ -6,12 +6,9 @@ rust-version.workspace = true
license.workspace = true
[dependencies]
pumpkin-protocol.workspace = true
pumpkin-util.workspace = true
tokio = { workspace = true, features = ["full"] }
clap = { version = "4", features = ["derive"] }
colored.workspace = true
bytes.workspace = true
rand = "0.9"
[lints.clippy]