mc_core/util/
nbt_ext.rs

1//! This module defines some NBT utilities which extends the real NBT crate,
2//! named 'named-binary-tag'.
3
4use 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}