added some imperfect loading of worlds
This commit is contained in:
parent
20d1b0510d
commit
659d023ea5
14 changed files with 577 additions and 107 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
|||
official_server
|
||||
.DS_Store
|
||||
flamegraph.svg
|
||||
/server/world
|
||||
|
|
41
lib/Cargo.lock
generated
41
lib/Cargo.lock
generated
|
@ -2,13 +2,54 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"data",
|
||||
"flate2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
|
|
@ -5,3 +5,4 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
data = {path = "../data", version = "*"}
|
||||
flate2 = "1.1.2"
|
||||
|
|
|
@ -108,15 +108,15 @@ pub fn slot(data: &mut Vec<u8>) -> Result<Slot, Box<dyn Error>> {
|
|||
for _ in 0..number_of_components_to_add {
|
||||
let component_id = varint(data)?;
|
||||
components_to_add.push(match component_id {
|
||||
0 => SlotComponent::CustomData(nbt(data)?),
|
||||
0 => SlotComponent::CustomData(nbt_network(data)?),
|
||||
1 => SlotComponent::MaxStackSize(varint(data)?),
|
||||
2 => SlotComponent::MaxDamage(varint(data)?),
|
||||
3 => SlotComponent::Damage(varint(data)?),
|
||||
4 => SlotComponent::Unbreakable,
|
||||
5 => SlotComponent::CustomName(nbt(data)?),
|
||||
6 => SlotComponent::ItemName(nbt(data)?),
|
||||
5 => SlotComponent::CustomName(nbt_network(data)?),
|
||||
6 => SlotComponent::ItemName(nbt_network(data)?),
|
||||
7 => SlotComponent::ItemModel(string(data)?),
|
||||
8 => SlotComponent::Lore((0..varint(data)?).map(|_| nbt(data).unwrap()).collect()),
|
||||
8 => SlotComponent::Lore((0..varint(data)?).map(|_| nbt_network(data).unwrap()).collect()),
|
||||
9 => SlotComponent::Rarity(data.remove(0)),
|
||||
10 => SlotComponent::Enchantments((0..varint(data)?).map(|_| (varint(data).unwrap(), varint(data).unwrap())).collect()),
|
||||
11 => todo!(), //SlotComponent::CanPlaceOn,
|
||||
|
@ -127,7 +127,7 @@ pub fn slot(data: &mut Vec<u8>) -> Result<Slot, Box<dyn Error>> {
|
|||
16 => SlotComponent::RepairCost(varint(data)?),
|
||||
17 => SlotComponent::CreativeSlotLock,
|
||||
18 => SlotComponent::EnchantmentGlintOverride(boolean(data)?),
|
||||
19 => SlotComponent::IntangibleProjectile(nbt(data)?),
|
||||
19 => SlotComponent::IntangibleProjectile(nbt_network(data)?),
|
||||
20 => SlotComponent::Food(varint(data)?, float(data)?, boolean(data)?),
|
||||
21 => todo!(), //SlotComponent::Consumable,
|
||||
22 => SlotComponent::UseRemainder(slot(data)?),
|
||||
|
@ -146,7 +146,7 @@ pub fn slot(data: &mut Vec<u8>) -> Result<Slot, Box<dyn Error>> {
|
|||
35 => SlotComponent::DyedColor(int(data)?),
|
||||
36 => SlotComponent::MapColor(int(data)?),
|
||||
37 => SlotComponent::MapId(varint(data)?),
|
||||
38 => SlotComponent::MapDecorations(nbt(data)?),
|
||||
38 => SlotComponent::MapDecorations(nbt_network(data)?),
|
||||
39 => SlotComponent::MapPostProcessing(data.remove(0)),
|
||||
40 => SlotComponent::ChargedProjectiles((0..varint(data)?).map(|_| slot(data).unwrap()).collect()),
|
||||
41 => SlotComponent::BundleContents((0..varint(data)?).map(|_| slot(data).unwrap()).collect()),
|
||||
|
@ -156,16 +156,16 @@ pub fn slot(data: &mut Vec<u8>) -> Result<Slot, Box<dyn Error>> {
|
|||
45 => SlotComponent::WritableBookContent((0..varint(data)?).map(|_| (string(data).unwrap(), if boolean(data).unwrap() {Some(string(data).unwrap())} else {None})).collect()),
|
||||
46 => SlotComponent::WrittenBookContent((0..varint(data)?).map(|_| (string(data).unwrap(), if boolean(data).unwrap() {Some(string(data).unwrap())} else {None})).collect()),
|
||||
47 => todo!(), //SlotComponent::Trim,
|
||||
48 => SlotComponent::DebugStickState(nbt(data)?),
|
||||
49 => SlotComponent::EntityData(nbt(data)?),
|
||||
50 => SlotComponent::BucketEntityData(nbt(data)?),
|
||||
51 => SlotComponent::BlockEntityData(nbt(data)?),
|
||||
48 => SlotComponent::DebugStickState(nbt_network(data)?),
|
||||
49 => SlotComponent::EntityData(nbt_network(data)?),
|
||||
50 => SlotComponent::BucketEntityData(nbt_network(data)?),
|
||||
51 => SlotComponent::BlockEntityData(nbt_network(data)?),
|
||||
52 => todo!(), //SlotComponent::Instrument,
|
||||
53 => todo!(), //SlotComponent::ProvidesTrimMaterial,
|
||||
54 => SlotComponent::OminousBottleAmplifier(data.remove(0)),
|
||||
55 => todo!(), //SlotComponent::JukeboxPlayable,
|
||||
56 => SlotComponent::ProvidesBannerPatterns(string(data)?),
|
||||
57 => SlotComponent::Recipes(nbt(data)?),
|
||||
57 => SlotComponent::Recipes(nbt_network(data)?),
|
||||
58 => SlotComponent::LodestoneTracker(boolean(data)?, string(data)?, position(data)?, boolean(data)?),
|
||||
59 => todo!(), //SlotComponent::FireworkExplosion,
|
||||
60 => todo!(), //SlotComponent::Fireworks,
|
||||
|
@ -176,9 +176,9 @@ pub fn slot(data: &mut Vec<u8>) -> Result<Slot, Box<dyn Error>> {
|
|||
65 => SlotComponent::PotDecorations((0..varint(data)?).map(|_| varint(data).unwrap()).collect()),
|
||||
66 => SlotComponent::Container((0..varint(data)?).map(|_| varint(data).unwrap()).collect()),
|
||||
67 => SlotComponent::BlockState((0..varint(data)?).map(|_| (string(data).unwrap(), string(data).unwrap())).collect()),
|
||||
68 => SlotComponent::Bees((0..varint(data)?).map(|_| (nbt(data).unwrap(), varint(data).unwrap(), varint(data).unwrap())).collect()),
|
||||
69 => SlotComponent::Lock(nbt(data)?),
|
||||
70 => SlotComponent::ContainerLoot(nbt(data)?),
|
||||
68 => SlotComponent::Bees((0..varint(data)?).map(|_| (nbt_network(data).unwrap(), varint(data).unwrap(), varint(data).unwrap())).collect()),
|
||||
69 => SlotComponent::Lock(nbt_network(data)?),
|
||||
70 => SlotComponent::ContainerLoot(nbt_network(data)?),
|
||||
71 => todo!(), //SlotComponent::BreakSound,
|
||||
72 => todo!(), //SlotComponent::VillagerVariant,
|
||||
73 => todo!(), //SlotComponent::WolfVariant,
|
||||
|
@ -249,11 +249,15 @@ pub fn varint(data: &mut Vec<u8>) -> Result<i32, Box<dyn Error>> {
|
|||
return Ok(value);
|
||||
}
|
||||
|
||||
pub fn nbt(data: &mut Vec<u8>) -> Result<NbtTag, Box<dyn Error>> {
|
||||
//println!("deserialize nbt:\n\n{data:?}\n\n\n\n");
|
||||
|
||||
pub fn nbt_network(data: &mut Vec<u8>) -> Result<NbtTag, Box<dyn Error>> {
|
||||
return nbt_tag_compound(data, false, true);
|
||||
}
|
||||
|
||||
pub fn nbt_disk(data: &mut Vec<u8>) -> Result<NbtTag, Box<dyn Error>> {
|
||||
return nbt_tag_compound(data, true, true);
|
||||
}
|
||||
|
||||
fn nbt_byte_array_value(data: &mut Vec<u8>) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
let len = int(data)?;
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
|
@ -279,9 +283,8 @@ pub fn nbt_string_value(data: &mut Vec<u8>) -> Result<String, Box<dyn Error>> {
|
|||
}
|
||||
|
||||
fn nbt_list(data: &mut Vec<u8>, has_description: bool, has_id: bool) -> Result<NbtTag, Box<dyn Error>> {
|
||||
data.reverse();
|
||||
if has_id {
|
||||
data.pop();
|
||||
data.remove(0);
|
||||
}
|
||||
|
||||
let description: Option<String> = if has_description {
|
||||
|
@ -290,127 +293,105 @@ fn nbt_list(data: &mut Vec<u8>, has_description: bool, has_id: bool) -> Result<N
|
|||
None
|
||||
};
|
||||
|
||||
let id = data.pop().unwrap();
|
||||
let id = data.remove(0);
|
||||
let len = int(data)?;
|
||||
|
||||
if len == 0 {
|
||||
return Ok(NbtTag::List(description, Vec::new()));
|
||||
}
|
||||
|
||||
let output: NbtTag = match id {
|
||||
0x01 => {
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
for _ in 0..len {
|
||||
list.push(NbtTag::Byte(None, data.pop().unwrap()));
|
||||
list.push(NbtTag::Byte(None, data.remove(0)));
|
||||
}
|
||||
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x02 => {
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
data.reverse();
|
||||
for _ in 0..len {
|
||||
list.push(NbtTag::Short(None, short(data)?));
|
||||
}
|
||||
data.reverse();
|
||||
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x03 => {
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
data.reverse();
|
||||
for _ in 0..len {
|
||||
list.push(NbtTag::Int(None, int(data)?));
|
||||
}
|
||||
data.reverse();
|
||||
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x04 => {
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
data.reverse();
|
||||
for _ in 0..len {
|
||||
list.push(NbtTag::Long(None, long(data)?));
|
||||
}
|
||||
data.reverse();
|
||||
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x05 => {
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
data.reverse();
|
||||
for _ in 0..len {
|
||||
list.push(NbtTag::Float(None, float(data)?));
|
||||
}
|
||||
data.reverse();
|
||||
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x06 => {
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
data.reverse();
|
||||
for _ in 0..len {
|
||||
list.push(NbtTag::Double(None, double(data)?));
|
||||
}
|
||||
data.reverse();
|
||||
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x07 => {
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
data.reverse();
|
||||
for _ in 0..len {
|
||||
list.push(NbtTag::ByteArray(None, nbt_byte_array_value(data)?));
|
||||
}
|
||||
data.reverse();
|
||||
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x08 => {
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
data.reverse();
|
||||
for _ in 0..len {
|
||||
list.push(NbtTag::String(None, nbt_string_value(data)?));
|
||||
}
|
||||
data.reverse();
|
||||
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x09 => {
|
||||
todo!("this isnt implemented yet lol");
|
||||
//let mut list: Vec<NbtTag> = Vec::new();
|
||||
//data.reverse();
|
||||
//for _ in 0..len {
|
||||
// list.push(NbtTag::String(None, nbt_string_value(&mut data)?));
|
||||
//}
|
||||
//data.reverse();
|
||||
|
||||
//NbtTag::List(description, list)
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
for _ in 0..len {
|
||||
list.push(nbt_list(data, false, false).unwrap());
|
||||
}
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x0a => {
|
||||
todo!("this isnt implemented yet lol");
|
||||
//let mut list: Vec<NbtTag> = Vec::new();
|
||||
//data.reverse();
|
||||
//for _ in 0..len {
|
||||
// list.push(NbtTag::String(None, nbt_string_value(&mut data)?));
|
||||
//}
|
||||
//data.reverse();
|
||||
|
||||
//NbtTag::List(description, list)
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
for _ in 0..len {
|
||||
list.push(nbt_tag_compound(data, false, false).unwrap());
|
||||
}
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x0b => {
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
data.reverse();
|
||||
for _ in 0..len {
|
||||
list.push(NbtTag::IntArray(None, nbt_int_array_value(data)?));
|
||||
}
|
||||
data.reverse();
|
||||
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
0x0c => {
|
||||
let mut list: Vec<NbtTag> = Vec::new();
|
||||
data.reverse();
|
||||
for _ in 0..len {
|
||||
list.push(NbtTag::LongArray(None, nbt_long_array_value(data)?));
|
||||
}
|
||||
data.reverse();
|
||||
|
||||
NbtTag::List(description, list)
|
||||
},
|
||||
|
@ -419,13 +400,11 @@ fn nbt_list(data: &mut Vec<u8>, has_description: bool, has_id: bool) -> Result<N
|
|||
}
|
||||
};
|
||||
|
||||
data.reverse();
|
||||
|
||||
return Ok(output);
|
||||
}
|
||||
|
||||
fn nbt_tag_compound(data: &mut Vec<u8>, has_description: bool, has_id: bool) -> Result<NbtTag, Box<dyn Error>> {
|
||||
if has_id {
|
||||
if has_id {
|
||||
data.remove(0);
|
||||
}
|
||||
|
||||
|
@ -439,7 +418,6 @@ fn nbt_tag_compound(data: &mut Vec<u8>, has_description: bool, has_id: bool) ->
|
|||
|
||||
loop {
|
||||
let id = data.remove(0);
|
||||
|
||||
match id {
|
||||
0x00 => break,
|
||||
0x01 => {
|
||||
|
@ -577,6 +555,61 @@ mod test {
|
|||
|
||||
let mut nbt_bytes: Vec<u8> = vec![10,2,0,17,77,97,120,78,101,97,114,98,121,69,110,116,105,116,105,101,115,0,6,2,0,19,82,101,113,117,105,114,101,100,80,108,97,121,101,114,82,97,110,103,101,0,16,2,0,10,83,112,97,119,110,67,111,117,110,116,0,4,10,0,9,83,112,97,119,110,68,97,116,97,10,0,6,101,110,116,105,116,121,8,0,2,105,100,0,16,109,105,110,101,99,114,97,102,116,58,115,112,105,100,101,114,0,0,2,0,13,77,97,120,83,112,97,119,110,68,101,108,97,121,3,32,2,0,10,83,112,97,119,110,82,97,110,103,101,0,4,2,0,5,68,101,108,97,121,0,20,2,0,13,77,105,110,83,112,97,119,110,68,101,108,97,121,0,200,0];
|
||||
|
||||
assert_eq!(nbt(&mut nbt_bytes).unwrap(), nbt_parsed);
|
||||
assert_eq!(nbt_network(&mut nbt_bytes).unwrap(), nbt_parsed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nbt_with_list_of_compounds_network() {
|
||||
let nbt = NbtTag::TagCompound(None, vec![
|
||||
NbtTag::List(Some("this_is_a_list".to_string()), vec![
|
||||
NbtTag::TagCompound(None, vec![
|
||||
NbtTag::String(Some("a".to_string()), "b".to_string()),
|
||||
]),
|
||||
NbtTag::TagCompound(None, vec![
|
||||
NbtTag::String(Some("a".to_string()), "b".to_string()),
|
||||
]),
|
||||
NbtTag::TagCompound(None, vec![
|
||||
NbtTag::String(Some("a".to_string()), "b".to_string()),
|
||||
]),
|
||||
]),
|
||||
]);
|
||||
|
||||
let mut nbt_bytes = crate::serialize::nbt_network(nbt.clone());
|
||||
println!("nbt_bytes\n{nbt_bytes:?}");
|
||||
assert_eq!(nbt_network(&mut nbt_bytes).unwrap(), nbt);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nbt_with_list_of_compounds_disk() {
|
||||
let nbt = NbtTag::TagCompound(Some("".to_string()), vec![
|
||||
NbtTag::List(Some("this_is_a_list".to_string()), vec![
|
||||
NbtTag::TagCompound(None, vec![
|
||||
NbtTag::String(Some("a".to_string()), "b".to_string()),
|
||||
]),
|
||||
NbtTag::TagCompound(None, vec![
|
||||
NbtTag::String(Some("a".to_string()), "b".to_string()),
|
||||
]),
|
||||
NbtTag::TagCompound(None, vec![
|
||||
NbtTag::String(Some("a".to_string()), "b".to_string()),
|
||||
]),
|
||||
]),
|
||||
]);
|
||||
|
||||
let mut nbt_bytes = crate::serialize::nbt_disk(nbt.clone());
|
||||
println!("nbt_bytes\n{nbt_bytes:?}");
|
||||
assert_eq!(nbt_disk(&mut nbt_bytes).unwrap(), nbt);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nbt_with_empty_list_disk() {
|
||||
let nbt = NbtTag::TagCompound(Some("".to_string()), vec![
|
||||
NbtTag::List(Some("this_is_a_list".to_string()), vec![
|
||||
|
||||
]),
|
||||
]);
|
||||
|
||||
let mut nbt_bytes = crate::serialize::nbt_disk(nbt.clone());
|
||||
println!("nbt_bytes\n{nbt_bytes:?}");
|
||||
assert_eq!(nbt_disk(&mut nbt_bytes).unwrap(), nbt);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ impl TryFrom<RegistryData> for Vec<u8> {
|
|||
data.append(&mut crate::serialize::string(&x.entry_id));
|
||||
data.append(&mut crate::serialize::boolean(x.has_data));
|
||||
if x.has_data {
|
||||
data.append(&mut crate::serialize::nbt(x.clone().data.unwrap()));
|
||||
data.append(&mut crate::serialize::nbt_network(x.clone().data.unwrap()));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -103,7 +103,7 @@ impl TryFrom<Vec<u8>> for RegistryData {
|
|||
let entry_id = crate::deserialize::string(&mut value)?;
|
||||
let has_data = crate::deserialize::boolean(&mut value)?;
|
||||
let data: Option<crate::nbt::NbtTag> = if has_data {
|
||||
Some(crate::deserialize::nbt(&mut value)?)
|
||||
Some(crate::deserialize::nbt_network(&mut value)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
@ -451,7 +451,7 @@ impl TryFrom<ChunkDataAndUpdateLight> for Vec<u8> {
|
|||
output.append(&mut crate::serialize::short(x.y));
|
||||
output.append(&mut crate::serialize::varint(x.block_entity_type));
|
||||
if x.data.is_some() {
|
||||
output.append(&mut crate::serialize::nbt(x.data.unwrap()));
|
||||
output.append(&mut crate::serialize::nbt_network(x.data.unwrap()));
|
||||
} else {
|
||||
output.push(0x00);
|
||||
}
|
||||
|
@ -628,7 +628,7 @@ impl TryFrom<Vec<u8>> for ChunkDataAndUpdateLight {
|
|||
let data = if *value.first().unwrap() == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(crate::deserialize::nbt(&mut value)?)
|
||||
Some(crate::deserialize::nbt_network(&mut value)?)
|
||||
};
|
||||
block_entities.push(BlockEntity {
|
||||
packed_xz,
|
||||
|
@ -1161,7 +1161,7 @@ impl TryFrom<PlayerChatMessage> for Vec<u8> {
|
|||
});
|
||||
if value.unsigned_content.is_some() {
|
||||
output.append(&mut crate::serialize::boolean(true));
|
||||
output.append(&mut crate::serialize::nbt(value.unsigned_content.unwrap()));
|
||||
output.append(&mut crate::serialize::nbt_network(value.unsigned_content.unwrap()));
|
||||
} else {
|
||||
output.append(&mut crate::serialize::boolean(false));
|
||||
}
|
||||
|
@ -1170,9 +1170,9 @@ impl TryFrom<PlayerChatMessage> for Vec<u8> {
|
|||
output.append(&mut crate::serialize::bitset(&value.filter_type_bits));
|
||||
}
|
||||
output.append(&mut crate::serialize::varint(value.chat_type));
|
||||
output.append(&mut crate::serialize::nbt(value.sender_name));
|
||||
output.append(&mut crate::serialize::nbt_network(value.sender_name));
|
||||
if value.target_name.is_some() {
|
||||
output.append(&mut crate::serialize::nbt(value.target_name.unwrap()));
|
||||
output.append(&mut crate::serialize::nbt_network(value.target_name.unwrap()));
|
||||
}
|
||||
output.push(0); //not sure why this is needed
|
||||
|
||||
|
@ -1208,7 +1208,7 @@ impl TryFrom<Vec<u8>> for PlayerChatMessage {
|
|||
}).collect();
|
||||
let unsigned_content_present = crate::deserialize::boolean(&mut value)?;
|
||||
let unsigned_content = if unsigned_content_present {
|
||||
Some(crate::deserialize::nbt(&mut value)?)
|
||||
Some(crate::deserialize::nbt_network(&mut value)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -1219,10 +1219,10 @@ impl TryFrom<Vec<u8>> for PlayerChatMessage {
|
|||
Vec::new()
|
||||
};
|
||||
let chat_type = crate::deserialize::varint(&mut value)?;
|
||||
let sender_name = crate::deserialize::nbt(&mut value)?;
|
||||
let sender_name = crate::deserialize::nbt_network(&mut value)?;
|
||||
let target_name_present = crate::deserialize::boolean(&mut value)?;
|
||||
let target_name = if target_name_present {
|
||||
Some(crate::deserialize::nbt(&mut value)?)
|
||||
Some(crate::deserialize::nbt_network(&mut value)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -1365,7 +1365,7 @@ impl TryFrom<PlayerInfoUpdate> for Vec<u8> {
|
|||
PlayerAction::UpdateDisplayName(display_name) => {
|
||||
output.append(&mut crate::serialize::boolean(display_name.is_some()));
|
||||
if let Some(display_name) = display_name {
|
||||
output.append(&mut crate::serialize::nbt(display_name));
|
||||
output.append(&mut crate::serialize::nbt_network(display_name));
|
||||
}
|
||||
},
|
||||
PlayerAction::UpdateListPriority(priority) => output.append(&mut crate::serialize::varint(priority)),
|
||||
|
@ -1441,7 +1441,7 @@ impl TryFrom<Vec<u8>> for PlayerInfoUpdate {
|
|||
|
||||
if actions & 0x20 != 0 {
|
||||
let display_name = if crate::deserialize::boolean(&mut value)? {
|
||||
Some(crate::deserialize::nbt(&mut value)?)
|
||||
Some(crate::deserialize::nbt_network(&mut value)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -1729,12 +1729,12 @@ impl TryFrom<SetEntityMetadata> for Vec<u8> {
|
|||
EntityMetadataValue::Varlong(_) => todo!(),
|
||||
EntityMetadataValue::Float(a) => output.append(&mut crate::serialize::float(a)),
|
||||
EntityMetadataValue::String(a) => output.append(&mut crate::serialize::string(&a)),
|
||||
EntityMetadataValue::TextComponent(a) => output.append(&mut crate::serialize::nbt(a)),
|
||||
EntityMetadataValue::TextComponent(a) => output.append(&mut crate::serialize::nbt_network(a)),
|
||||
EntityMetadataValue::OptionalTextComponent(a) => {
|
||||
match a {
|
||||
Some(a) => {
|
||||
output.push(0x01);
|
||||
output.append(&mut crate::serialize::nbt(a));
|
||||
output.append(&mut crate::serialize::nbt_network(a));
|
||||
},
|
||||
None => {
|
||||
output.push(0x00);
|
||||
|
@ -1769,7 +1769,7 @@ impl TryFrom<SetEntityMetadata> for Vec<u8> {
|
|||
},
|
||||
EntityMetadataValue::BlockState(a) => output.append(&mut crate::serialize::varint(a)),
|
||||
EntityMetadataValue::OptionalBlockState(a) => output.append(&mut crate::serialize::varint(a)),
|
||||
EntityMetadataValue::Nbt(a) => output.append(&mut crate::serialize::nbt(a)),
|
||||
EntityMetadataValue::Nbt(a) => output.append(&mut crate::serialize::nbt_network(a)),
|
||||
EntityMetadataValue::Particle(_) => todo!(),
|
||||
EntityMetadataValue::Particles(_, _) => todo!(),
|
||||
EntityMetadataValue::VillagerData(_, _, _) => todo!(),
|
||||
|
@ -1833,11 +1833,11 @@ impl TryFrom<Vec<u8>> for SetEntityMetadata {
|
|||
2 => todo!(),
|
||||
3 => EntityMetadataValue::Float(crate::deserialize::float(&mut value)?),
|
||||
4 => EntityMetadataValue::String(crate::deserialize::string(&mut value)?),
|
||||
5 => EntityMetadataValue::TextComponent(crate::deserialize::nbt(&mut value)?),
|
||||
5 => EntityMetadataValue::TextComponent(crate::deserialize::nbt_network(&mut value)?),
|
||||
6 => {
|
||||
let nbt_present = crate::deserialize::boolean(&mut value)?;
|
||||
let nbt = if nbt_present {
|
||||
Some(crate::deserialize::nbt(&mut value)?)
|
||||
Some(crate::deserialize::nbt_network(&mut value)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -1860,7 +1860,7 @@ impl TryFrom<Vec<u8>> for SetEntityMetadata {
|
|||
13 => todo!(),
|
||||
14 => EntityMetadataValue::BlockState(crate::deserialize::varint(&mut value)?),
|
||||
15 => EntityMetadataValue::OptionalBlockState(crate::deserialize::varint(&mut value)?),
|
||||
16 => EntityMetadataValue::Nbt(crate::deserialize::nbt(&mut value)?),
|
||||
16 => EntityMetadataValue::Nbt(crate::deserialize::nbt_network(&mut value)?),
|
||||
17 => todo!(),
|
||||
18 => todo!(),
|
||||
19 => EntityMetadataValue::VillagerData(crate::deserialize::varint(&mut value)?, crate::deserialize::varint(&mut value)?, crate::deserialize::varint(&mut value)?),
|
||||
|
@ -1910,7 +1910,7 @@ impl TryFrom<SystemChatMessage> for Vec<u8> {
|
|||
fn try_from(value: SystemChatMessage) -> Result<Self, Box<dyn Error>> {
|
||||
let mut output: Vec<u8> = Vec::new();
|
||||
|
||||
output.append(&mut crate::serialize::nbt(value.content));
|
||||
output.append(&mut crate::serialize::nbt_network(value.content));
|
||||
output.append(&mut crate::serialize::boolean(value.overlay));
|
||||
|
||||
return Ok(output);
|
||||
|
@ -1922,7 +1922,7 @@ impl TryFrom<Vec<u8>> for SystemChatMessage {
|
|||
|
||||
fn try_from(mut value: Vec<u8>) -> Result<Self, Box<dyn Error>> {
|
||||
return Ok(Self {
|
||||
content: crate::deserialize::nbt(&mut value)?,
|
||||
content: crate::deserialize::nbt_network(&mut value)?,
|
||||
overlay: crate::deserialize::boolean(&mut value)?,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -96,15 +96,15 @@ pub fn slot(input: &Slot) -> Vec<u8> {
|
|||
for component_to_add in &input.components_to_add {
|
||||
output.append(&mut varint(component_to_add.into()));
|
||||
output.append(&mut match component_to_add.clone() {
|
||||
SlotComponent::CustomData(a) => nbt(a),
|
||||
SlotComponent::CustomData(a) => nbt_network(a),
|
||||
SlotComponent::MaxStackSize(a) => varint(a),
|
||||
SlotComponent::MaxDamage(a) => varint(a),
|
||||
SlotComponent::Damage(a) => varint(a),
|
||||
SlotComponent::Unbreakable => vec![],
|
||||
SlotComponent::CustomName(a) => nbt(a),
|
||||
SlotComponent::ItemName(a) => nbt(a),
|
||||
SlotComponent::CustomName(a) => nbt_network(a),
|
||||
SlotComponent::ItemName(a) => nbt_network(a),
|
||||
SlotComponent::ItemModel(a) => string(&a),
|
||||
SlotComponent::Lore(a) => a.into_iter().flat_map(nbt).collect(),
|
||||
SlotComponent::Lore(a) => a.into_iter().flat_map(nbt_network).collect(),
|
||||
SlotComponent::Rarity(a) => vec![a],
|
||||
SlotComponent::Enchantments(a) => a.into_iter().flat_map(|(x, y)| vec![varint(x), varint(y)]).flatten().collect(),
|
||||
SlotComponent::CanPlaceOn => todo!(),
|
||||
|
@ -115,7 +115,7 @@ pub fn slot(input: &Slot) -> Vec<u8> {
|
|||
SlotComponent::RepairCost(a) => varint(a),
|
||||
SlotComponent::CreativeSlotLock => vec![],
|
||||
SlotComponent::EnchantmentGlintOverride(a) => boolean(a),
|
||||
SlotComponent::IntangibleProjectile(a) => nbt(a),
|
||||
SlotComponent::IntangibleProjectile(a) => nbt_network(a),
|
||||
SlotComponent::Food(a, b, c) => vec![varint(a), float(b), boolean(c)].into_iter().flatten().collect(),
|
||||
SlotComponent::Consumable => todo!(),
|
||||
SlotComponent::UseRemainder(a) => slot(&a),
|
||||
|
@ -134,7 +134,7 @@ pub fn slot(input: &Slot) -> Vec<u8> {
|
|||
SlotComponent::DyedColor(a) => int(a),
|
||||
SlotComponent::MapColor(a) => int(a),
|
||||
SlotComponent::MapId(a) => varint(a),
|
||||
SlotComponent::MapDecorations(a) => nbt(a),
|
||||
SlotComponent::MapDecorations(a) => nbt_network(a),
|
||||
SlotComponent::MapPostProcessing(a) => vec![a],
|
||||
SlotComponent::ChargedProjectiles(a) => a.into_iter().flat_map(|x| slot(&x)).collect(),
|
||||
SlotComponent::BundleContents(a) => a.into_iter().flat_map(|x| slot(&x)).collect(),
|
||||
|
@ -144,16 +144,16 @@ pub fn slot(input: &Slot) -> Vec<u8> {
|
|||
SlotComponent::WritableBookContent(a) => a.into_iter().flat_map(|(x, y)| vec![string(&x), if y.is_some() {vec![vec![0x01], string(&y.unwrap())].into_iter().flatten().collect()} else {vec![0x00]}]).flatten().collect(),
|
||||
SlotComponent::WrittenBookContent(a) => a.into_iter().flat_map(|(x, y)| vec![string(&x), if y.is_some() {vec![vec![0x01], string(&y.unwrap())].into_iter().flatten().collect()} else {vec![0x00]}]).flatten().collect(),
|
||||
SlotComponent::Trim => todo!(),
|
||||
SlotComponent::DebugStickState(a) => nbt(a),
|
||||
SlotComponent::EntityData(a) => nbt(a),
|
||||
SlotComponent::BucketEntityData(a) => nbt(a),
|
||||
SlotComponent::BlockEntityData(a) => nbt(a),
|
||||
SlotComponent::DebugStickState(a) => nbt_network(a),
|
||||
SlotComponent::EntityData(a) => nbt_network(a),
|
||||
SlotComponent::BucketEntityData(a) => nbt_network(a),
|
||||
SlotComponent::BlockEntityData(a) => nbt_network(a),
|
||||
SlotComponent::Instrument => todo!(),
|
||||
SlotComponent::ProvidesTrimMaterial => todo!(),
|
||||
SlotComponent::OminousBottleAmplifier(a) => vec![a],
|
||||
SlotComponent::JukeboxPlayable => todo!(),
|
||||
SlotComponent::ProvidesBannerPatterns(a) => string(&a),
|
||||
SlotComponent::Recipes(a) => nbt(a),
|
||||
SlotComponent::Recipes(a) => nbt_network(a),
|
||||
SlotComponent::LodestoneTracker(a, b, c, d) => vec![boolean(a), string(&b), position(&c), boolean(d)].into_iter().flatten().collect(),
|
||||
SlotComponent::FireworkExplosion => todo!(),
|
||||
SlotComponent::Fireworks => todo!(),
|
||||
|
@ -164,9 +164,9 @@ pub fn slot(input: &Slot) -> Vec<u8> {
|
|||
SlotComponent::PotDecorations(a) => a.into_iter().flat_map(varint).collect(),
|
||||
SlotComponent::Container(a) => a.into_iter().flat_map(varint).collect(),
|
||||
SlotComponent::BlockState(a) => a.into_iter().flat_map(|(x, y)| vec![string(&x), string(&y)]).flatten().collect(),
|
||||
SlotComponent::Bees(a) => a.into_iter().flat_map(|(x, y, z)| vec![nbt(x), varint(y), varint(z)]).flatten().collect(),
|
||||
SlotComponent::Lock(a) => nbt(a),
|
||||
SlotComponent::ContainerLoot(a) => nbt(a),
|
||||
SlotComponent::Bees(a) => a.into_iter().flat_map(|(x, y, z)| vec![nbt_network(x), varint(y), varint(z)]).flatten().collect(),
|
||||
SlotComponent::Lock(a) => nbt_network(a),
|
||||
SlotComponent::ContainerLoot(a) => nbt_network(a),
|
||||
SlotComponent::BreakSound => todo!(),
|
||||
SlotComponent::VillagerVariant => todo!(),
|
||||
SlotComponent::WolfVariant => todo!(),
|
||||
|
@ -213,10 +213,22 @@ pub fn prefixed_array(mut data: Vec<u8>, len: i32) -> Vec<u8> {
|
|||
return output;
|
||||
}
|
||||
|
||||
pub fn nbt(input: NbtTag) -> Vec<u8> {
|
||||
let mut nbt = nbt_tag_compound(None, vec![input], false);
|
||||
nbt.pop(); //Otherwise we have one 0x00 byte too much at the end
|
||||
return nbt;
|
||||
pub fn nbt_network(input: NbtTag) -> Vec<u8> {
|
||||
match input {
|
||||
NbtTag::TagCompound(_, p) => {
|
||||
return nbt_tag_compound(None, p, true);
|
||||
},
|
||||
_ => panic!("root node must be a tag compound"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nbt_disk(input: NbtTag) -> Vec<u8> {
|
||||
match input {
|
||||
NbtTag::TagCompound(_, p) => {
|
||||
return nbt_tag_compound(Some("".to_string()), p, true);
|
||||
},
|
||||
_ => panic!("root node must be a tag compound"),
|
||||
}
|
||||
}
|
||||
|
||||
fn nbt_byte(description: Option<String>, payload: u8, include_id: bool) -> Vec<u8> {
|
||||
|
@ -362,6 +374,7 @@ fn nbt_list(description: Option<String>, payload: Vec<NbtTag>, include_id: bool)
|
|||
}
|
||||
|
||||
if payload.is_empty() {
|
||||
output.append(&mut vec![0;5]);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,3 +19,128 @@ impl Default for NbtTag {
|
|||
return NbtTag::TagCompound(None, Vec::new());
|
||||
}
|
||||
}
|
||||
|
||||
impl NbtTag {
|
||||
pub fn get_children(&self) -> Vec<NbtTag> {
|
||||
match self {
|
||||
NbtTag::TagCompound(_, p) => return p.clone(),
|
||||
NbtTag::List(_, p) => return p.clone(),
|
||||
_ => return Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_child(&self, description: &str) -> Option<NbtTag> {
|
||||
match self {
|
||||
NbtTag::TagCompound(_, p) => {
|
||||
for tag in p {
|
||||
if tag.get_description().unwrap_or_default().as_str() == description {
|
||||
return Some(tag.clone());
|
||||
}
|
||||
}
|
||||
return None;
|
||||
},
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_description(&self) -> Option<String> {
|
||||
return match self {
|
||||
NbtTag::Byte(d, _) => d.clone(),
|
||||
NbtTag::Short(d, _) => d.clone(),
|
||||
NbtTag::Int(d, _) => d.clone(),
|
||||
NbtTag::Long(d, _) => d.clone(),
|
||||
NbtTag::Float(d, _) => d.clone(),
|
||||
NbtTag::Double(d, _) => d.clone(),
|
||||
NbtTag::ByteArray(d, _) => d.clone(),
|
||||
NbtTag::String(d, _) => d.clone(),
|
||||
NbtTag::List(d, _) => d.clone(),
|
||||
NbtTag::TagCompound(d, _) => d.clone(),
|
||||
NbtTag::IntArray(d, _) => d.clone(),
|
||||
NbtTag::LongArray(d, _) => d.clone(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn as_byte(&self) -> u8 {
|
||||
match self {
|
||||
NbtTag::Byte(_, p) => return *p,
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_short(&self) -> i16 {
|
||||
match self {
|
||||
NbtTag::Short(_, p) => return *p,
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_int(&self) -> i32 {
|
||||
match self {
|
||||
NbtTag::Int(_, p) => return *p,
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_long(&self) -> i64 {
|
||||
match self {
|
||||
NbtTag::Long(_, p) => return *p,
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_float(&self) -> f32 {
|
||||
match self {
|
||||
NbtTag::Float(_, p) => return *p,
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_double(&self) -> f64 {
|
||||
match self {
|
||||
NbtTag::Double(_, p) => return *p,
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_byte_array(&self) -> Vec<u8> {
|
||||
match self {
|
||||
NbtTag::ByteArray(_, p) => return p.clone(),
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_string(&self) -> String {
|
||||
match self {
|
||||
NbtTag::String(_, p) => return p.clone(),
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_list(&self) -> Vec<NbtTag> {
|
||||
match self {
|
||||
NbtTag::List(_, p) => return p.clone(),
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_tag_compound(&self) -> Vec<NbtTag> {
|
||||
match self {
|
||||
NbtTag::TagCompound(_, p) => return p.clone(),
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_int_array(&self) -> Vec<i32> {
|
||||
match self {
|
||||
NbtTag::IntArray(_, p) => return p.clone(),
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_long_array(&self) -> Vec<i64> {
|
||||
match self {
|
||||
NbtTag::LongArray(_, p) => return p.clone(),
|
||||
_ => panic!("wrong type of Tag!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
8
lib/src/types/world/loader/mod.rs
Normal file
8
lib/src/types/world/loader/mod.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
pub mod vanilla;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub trait WorldLoader {
|
||||
fn load_chunk(&self, x: i32, z: i32) -> super::Chunk;
|
||||
fn is_initialized(&self) -> bool;
|
||||
}
|
140
lib/src/types/world/loader/vanilla.rs
Normal file
140
lib/src/types/world/loader/vanilla.rs
Normal file
|
@ -0,0 +1,140 @@
|
|||
use std::{fs, io::prelude::*, path::PathBuf, str::FromStr};
|
||||
use flate2::read::ZlibDecoder;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Loader {
|
||||
pub path: PathBuf
|
||||
}
|
||||
|
||||
impl super::WorldLoader for Loader {
|
||||
fn load_chunk(&self, x: i32, z: i32) -> Chunk {
|
||||
let region = chunk_to_region(x, z);
|
||||
|
||||
let mut region_file_path = self.path.clone();
|
||||
region_file_path.push(PathBuf::from_str("region").unwrap());
|
||||
region_file_path.push(PathBuf::from_str(format!("r.{}.{}.mca", region.0, region.1).as_str()).unwrap());
|
||||
|
||||
if !fs::exists(region_file_path.clone()).unwrap() {
|
||||
return Chunk::new(x, z);
|
||||
}
|
||||
|
||||
//TODO: only read in necessary ranges and not whole file
|
||||
let region_file = fs::read(region_file_path).unwrap();
|
||||
let chunk_pos_in_header = 4 * ((x & 31) + (z & 31) * 32);
|
||||
let chunk_location_bytes = ®ion_file[(chunk_pos_in_header as usize)..=((chunk_pos_in_header+2) as usize)];
|
||||
let chunk_offset = i32::from_be_bytes([0, chunk_location_bytes[0], chunk_location_bytes[1], chunk_location_bytes[2]]) * 4096;
|
||||
let chunk_length_padded = region_file[(chunk_pos_in_header+3) as usize] as i32 * 4096;
|
||||
|
||||
if chunk_offset == 0 && chunk_length_padded == 0 {
|
||||
return Chunk::new(x, z);
|
||||
}
|
||||
|
||||
let actual_chunk_length_bytes = ®ion_file[(chunk_offset as usize)..=(chunk_offset+3) as usize];
|
||||
let actual_chunk_length = i32::from_be_bytes([actual_chunk_length_bytes[0], actual_chunk_length_bytes[1], actual_chunk_length_bytes[2], actual_chunk_length_bytes[3]]);
|
||||
let compression_scheme = region_file[(chunk_offset+4) as usize];
|
||||
let compressed_data: &[u8] = ®ion_file[((chunk_offset+5) as usize)..=(chunk_offset+actual_chunk_length) as usize];
|
||||
let mut uncompressed_data: Vec<u8> = Vec::new();
|
||||
if compression_scheme == 2 {
|
||||
let mut decoder: ZlibDecoder<&[u8]> = ZlibDecoder::new(compressed_data);
|
||||
decoder.read_to_end(&mut uncompressed_data).unwrap();
|
||||
} else {
|
||||
panic!("unknown chunk compression scheme {compression_scheme}");
|
||||
}
|
||||
|
||||
let chunk_nbt = crate::deserialize::nbt_disk(&mut uncompressed_data).unwrap();
|
||||
|
||||
if chunk_nbt.get_child("Status").unwrap().as_string() != "minecraft:full" {
|
||||
return Chunk::new(x, z);
|
||||
}
|
||||
|
||||
let block_states = data::blocks::get_blocks();
|
||||
|
||||
let sections: Vec<super::ChunkSection> = chunk_nbt.get_child("sections").unwrap().as_list().into_iter().map(|x| {
|
||||
let palette = x.get_child("block_states").unwrap().get_child("palette").unwrap().as_list();
|
||||
|
||||
if palette.len() == 1 {
|
||||
return ChunkSection { blocks: vec![block_states.get(&palette[0].get_child("Name").unwrap().as_string()).unwrap().states.iter().find(|x| x.default).unwrap().id; 4096] }
|
||||
}
|
||||
|
||||
let bits_per_entry = match palette.len() {
|
||||
0..=16 => 4,
|
||||
17..=32 => 5,
|
||||
33..=64 => 6,
|
||||
65..=128 => 7,
|
||||
129..=256 => 8,
|
||||
257..=512 => 9,
|
||||
513..=1024 => 10,
|
||||
1025..=2048 => 11,
|
||||
_ => 12,
|
||||
};
|
||||
|
||||
let long_array = x.get_child("block_states").unwrap().get_child("data").unwrap().as_long_array();
|
||||
let mut data_array: Vec<i32> = Vec::new();
|
||||
for value in long_array {
|
||||
let entries_per_long = 64 / bits_per_entry;
|
||||
for i in 0..entries_per_long {
|
||||
if data_array.len() == 4096 {
|
||||
break;
|
||||
}
|
||||
let entry = value as u64 >> (64 - ((i+1) * bits_per_entry));
|
||||
let entry = entry & (u64::MAX >> (64 - bits_per_entry));
|
||||
data_array.push(entry as i32);
|
||||
}
|
||||
}
|
||||
assert_eq!(data_array.len(), 4096);
|
||||
return ChunkSection { blocks: data_array };
|
||||
}).collect();
|
||||
|
||||
return Chunk {
|
||||
x: chunk_nbt.get_child("xPos").unwrap().as_int(),
|
||||
z: chunk_nbt.get_child("zPos").unwrap().as_int(),
|
||||
sections,
|
||||
};
|
||||
}
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
let mut level_dat_path = self.path.clone();
|
||||
level_dat_path.push(PathBuf::from_str("level.dat").unwrap());
|
||||
return std::fs::exists(level_dat_path).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn chunk_to_region(x: i32, z: i32) -> (i32, i32) {
|
||||
return ((x as f32 / 32.0).floor() as i32, (z as f32 / 32.0).floor() as i32)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
mod chunk_to_region {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn works_positive() {
|
||||
assert_eq!(chunk_to_region(6, 5), (0, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_positive_large() {
|
||||
assert_eq!(chunk_to_region(12345, 321), (385, 10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_zero() {
|
||||
assert_eq!(chunk_to_region(0, 0), (0, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_negative() {
|
||||
assert_eq!(chunk_to_region(-10, -20), (-1, -1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_negative_large() {
|
||||
assert_eq!(chunk_to_region(-1000, -2000), (-32, -63));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
pub mod loader;
|
||||
|
||||
use std::{collections::HashMap, error::Error};
|
||||
|
||||
use crate::types::position::Position;
|
||||
|
@ -27,12 +29,18 @@ pub struct ChunkSection {
|
|||
|
||||
impl World {
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new() -> Self {
|
||||
println!("create new world");
|
||||
let mut dimensions: HashMap<String, Dimension> = HashMap::new();
|
||||
dimensions.insert("minecraft:overworld".to_string(), Dimension::new());
|
||||
println!("creation of new world finished");
|
||||
|
||||
pub fn new(loader: impl loader::WorldLoader) -> Self {
|
||||
let mut dimensions: HashMap<String, Dimension> = HashMap::new();
|
||||
if loader.is_initialized() {
|
||||
let now = std::time::Instant::now();
|
||||
println!("loading existing world");
|
||||
dimensions.insert("minecraft:overworld".to_string(), Dimension::new_from_loader(loader));
|
||||
println!("finished loading existing world in {:.2?}", now.elapsed());
|
||||
} else {
|
||||
println!("create new world");
|
||||
dimensions.insert("minecraft:overworld".to_string(), Dimension::new());
|
||||
println!("creation of new world finished");
|
||||
}
|
||||
return Self { dimensions };
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +61,20 @@ impl Dimension {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn new_from_loader(loader: impl loader::WorldLoader) -> Self {
|
||||
let mut chunks: Vec<Chunk> = Vec::new();
|
||||
|
||||
for x in -20..=20 {
|
||||
for z in -20..=20 {
|
||||
chunks.push(loader.load_chunk(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
return Self {
|
||||
chunks,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_chunk_from_position_mut(&mut self, position: Position) -> Option<&mut Chunk> {
|
||||
let chunk_coordinates = position.convert_to_coordinates_of_chunk();
|
||||
|
41
proxy/Cargo.lock
generated
41
proxy/Cargo.lock
generated
|
@ -2,15 +2,56 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"data",
|
||||
"flate2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
41
server/Cargo.lock
generated
41
server/Cargo.lock
generated
|
@ -2,15 +2,56 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"data",
|
||||
"flate2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use std::collections::HashMap;
|
||||
use std::net::{TcpListener, SocketAddr, TcpStream};
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use lib::types::world::World;
|
||||
use types::*;
|
||||
|
||||
mod packet_handlers;
|
||||
|
@ -19,10 +19,14 @@ fn main() {
|
|||
fn initialize_server() {
|
||||
let listener = TcpListener::bind("0.0.0.0:25565").unwrap();
|
||||
|
||||
let world_loader = lib::world::loader::vanilla::Loader {
|
||||
path: Path::new("./world").to_owned(),
|
||||
};
|
||||
|
||||
let connections: Arc<Mutex<HashMap<SocketAddr, Connection>>> = Arc::new(Mutex::new(HashMap::new()));
|
||||
let mut game = Game {
|
||||
players: Vec::new(),
|
||||
world: World::new(),
|
||||
world: World::new(world_loader),
|
||||
last_created_entity_id: 0,
|
||||
chat_message_index: 0,
|
||||
commands: Vec::new(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue