1use nbt::{CompoundTag, CompoundTagError};
5use uuid::Uuid;
6
7use crate::pos::{EntityPos, BlockPos};
8
9
10pub trait NbtExt {
11
12 fn get_i8_or<'a>(&'a self, name: &'a str, default: i8) -> i8;
13 fn get_i16_or<'a>(&'a self, name: &'a str, default: i16) -> i16;
14 fn get_i32_or<'a>(&'a self, name: &'a str, default: i32) -> i32;
15 fn get_i64_or<'a>(&'a self, name: &'a str, default: i64) -> i64;
16 fn get_f32_or<'a>(&'a self, name: &'a str, default: f32) -> f32;
17 fn get_f64_or<'a>(&'a self, name: &'a str, default: f64) -> f64;
18 fn get_bool_or<'a>(&'a self, name: &'a str, default: bool) -> bool;
19
20 fn insert_uuid(&mut self, name: impl ToString, value: &Uuid);
21 fn get_uuid<'a>(&'a self, name: &'a str) -> Result<Uuid, CompoundTagError<'a>>;
22
23 fn insert_entity_pos(&mut self, name: impl ToString, value: &EntityPos);
24 fn get_entity_pos<'a>(&'a self, name: &'a str) -> Result<EntityPos, CompoundTagError<'a>>;
25
26 fn insert_block_pos(&mut self, name: impl ToString, value: &BlockPos);
27 fn get_block_pos<'a>(&'a self, name: &'a str) -> Result<BlockPos, CompoundTagError<'a>>;
28
29 fn insert_split_block_pos(&mut self, x_name: impl ToString, y_name: impl ToString, z_name: impl ToString, value: &BlockPos);
30 fn get_split_block_pos<'a>(&'a self, x_name: &'a str, y_name: &'a str, z_name: &'a str) -> Result<BlockPos, CompoundTagError<'a>>;
31
32 fn get_string_vec<'a>(&'a self, name: &'a str) -> Result<Vec<String>, CompoundTagError<'a>>;
33
34}
35
36impl NbtExt for CompoundTag {
37
38 #[inline]
39 fn get_i8_or<'a>(&'a self, name: &'a str, default: i8) -> i8 {
40 self.get_i8(name).unwrap_or(default)
41 }
42
43 #[inline]
44 fn get_i16_or<'a>(&'a self, name: &'a str, default: i16) -> i16 {
45 self.get_i16(name).unwrap_or(default)
46 }
47
48 #[inline]
49 fn get_i32_or<'a>(&'a self, name: &'a str, default: i32) -> i32 {
50 self.get_i32(name).unwrap_or(default)
51 }
52
53 #[inline]
54 fn get_i64_or<'a>(&'a self, name: &'a str, default: i64) -> i64 {
55 self.get_i64(name).unwrap_or(default)
56 }
57
58 #[inline]
59 fn get_f32_or<'a>(&'a self, name: &'a str, default: f32) -> f32 {
60 self.get_f32(name).unwrap_or(default)
61 }
62
63 #[inline]
64 fn get_f64_or<'a>(&'a self, name: &'a str, default: f64) -> f64 {
65 self.get_f64(name).unwrap_or(default)
66 }
67
68 #[inline]
69 fn get_bool_or<'a>(&'a self, name: &'a str, default: bool) -> bool {
70 self.get_bool(name).unwrap_or(default)
71 }
72
73 fn insert_uuid(&mut self, name: impl ToString, value: &Uuid) {
74 let mut uuid_values = Vec::with_capacity(4);
75 let uuid_raw = value.as_u128();
76 uuid_values[0] = ((uuid_raw >> 96) & 0xFFFFFFFF) as i32;
77 uuid_values[1] = ((uuid_raw >> 64) & 0xFFFFFFFF) as i32;
78 uuid_values[2] = ((uuid_raw >> 32) & 0xFFFFFFFF) as i32;
79 uuid_values[3] = (uuid_raw & 0xFFFFFFFF) as i32;
80 self.insert_i32_vec(name, uuid_values);
81 }
82
83 fn get_uuid<'a>(&'a self, name: &'a str) -> Result<Uuid, CompoundTagError<'a>> {
84 let vec = self.get_i32_vec(name)?;
85 if vec.len() == 4 {
86 let mut uuid_raw = 0;
87 uuid_raw |= (vec[0] as u32 as u128) << 96;
88 uuid_raw |= (vec[1] as u32 as u128) << 64;
89 uuid_raw |= (vec[2] as u32 as u128) << 32;
90 uuid_raw |= vec[3] as u32 as u128;
91 Ok(Uuid::from_u128(uuid_raw))
92 } else {
93 Err(CompoundTagError::TagWrongType {
94 name,
95 actual_tag: self.get(name).unwrap()
96 })
97 }
98 }
99
100 fn insert_entity_pos(&mut self, name: impl ToString, value: &EntityPos) {
101 self.insert_f64_vec(name, value.into_array());
102 }
103
104 fn get_entity_pos<'a>(&'a self, name: &'a str) -> Result<EntityPos, CompoundTagError<'a>> {
105 let raw_pos = self.get_f64_vec(name)?;
106 if raw_pos.len() == 3 {
107 Ok(EntityPos::new(raw_pos[0], raw_pos[1], raw_pos[2]))
108 } else {
109 Err(CompoundTagError::TagWrongType {
110 name,
111 actual_tag: self.get(name).unwrap()
112 })
113 }
114 }
115
116 fn insert_block_pos(&mut self, name: impl ToString, value: &BlockPos) {
117 let mut comp = CompoundTag::new();
118 comp.insert_split_block_pos("X", "Y", "Z", value);
119 self.insert_compound_tag(name, comp);
120 }
121
122 fn get_block_pos<'a>(&'a self, name: &'a str) -> Result<BlockPos, CompoundTagError<'a>> {
123 let comp = self.get_compound_tag(name)?;
124 comp.get_split_block_pos("X", "Y", "Z")
125 }
126
127 fn insert_split_block_pos(&mut self, x_name: impl ToString, y_name: impl ToString, z_name: impl ToString, value: &BlockPos) {
128 self.insert_i32(x_name, value.x);
129 self.insert_i32(y_name, value.y);
130 self.insert_i32(z_name, value.z);
131 }
132
133 fn get_split_block_pos<'a>(&'a self, x_name: &'a str, y_name: &'a str, z_name: &'a str) -> Result<BlockPos, CompoundTagError<'a>> {
134 let x = self.get_i32(x_name)?;
135 let y = self.get_i32(y_name)?;
136 let z = self.get_i32(z_name)?;
137 Ok(BlockPos::new(x, y, z))
138 }
139
140 fn get_string_vec<'a>(&'a self, name: &'a str) -> Result<Vec<String>, CompoundTagError<'a>> {
141 self.get_str_vec(name).map(|raw| {
142 raw.into_iter()
143 .map(|s| s.to_string())
144 .collect::<Vec<String>>()
145 })
146 }
147
148}