Skip to main content

nurtex_protocol/types/
heightmap.rs

1use nurtex_codec::Buffer;
2use nurtex_codec::types::variable::VarI32;
3use nurtex_codec::{read_byte, read_bytes};
4
5/// Сырые данные карт высот
6#[derive(Clone, Debug, PartialEq)]
7pub struct HeightmapsRaw {
8  pub bytes: Vec<u8>,
9}
10
11/// Сырые данные NBT
12#[derive(Clone, Debug, PartialEq)]
13pub struct NbtRaw {
14  pub bytes: Vec<u8>,
15}
16
17impl HeightmapsRaw {
18  fn remaining(buffer: &std::io::Cursor<&[u8]>) -> usize {
19    buffer.get_ref().len().saturating_sub(buffer.position() as usize)
20  }
21
22  fn read_nbt_raw(buffer: &mut std::io::Cursor<&[u8]>) -> Option<Vec<u8>> {
23    let start = buffer.position() as usize;
24
25    let tag_id = read_byte(buffer)?;
26    if tag_id != 0x0A {
27      return None;
28    }
29
30    let name_len = u16::read_buf(buffer)? as usize;
31    let _ = read_bytes(buffer, name_len)?;
32
33    loop {
34      let id = read_byte(buffer)?;
35      if id == 0 {
36        break;
37      }
38
39      let name_len = u16::read_buf(buffer)? as usize;
40      let _ = read_bytes(buffer, name_len)?;
41      skip_nbt_payload(buffer, id)?;
42    }
43
44    let end = buffer.position() as usize;
45    Some(buffer.get_ref()[start..end].to_vec())
46  }
47
48  fn read_map_raw(buffer: &mut std::io::Cursor<&[u8]>) -> Option<Vec<u8>> {
49    let start = buffer.position() as usize;
50
51    let map_size = i32::read_var(buffer)? as usize;
52    for _ in 0..map_size {
53      let _key = i32::read_var(buffer)?;
54      let len = i32::read_var(buffer)? as usize;
55      for _ in 0..len {
56        let _ = i64::read_buf(buffer)?;
57      }
58    }
59
60    let end = buffer.position() as usize;
61    Some(buffer.get_ref()[start..end].to_vec())
62  }
63}
64
65impl Buffer for HeightmapsRaw {
66  fn read_buf(buffer: &mut std::io::Cursor<&[u8]>) -> Option<Self> {
67    if Self::remaining(buffer) == 0 {
68      return Some(Self { bytes: vec![] });
69    }
70
71    let pos = buffer.position() as usize;
72    let first = *buffer.get_ref().get(pos)?;
73
74    let bytes = if first == 0x0A { Self::read_nbt_raw(buffer)? } else { Self::read_map_raw(buffer)? };
75
76    Some(Self { bytes })
77  }
78
79  fn write_buf(&self, buffer: &mut impl std::io::Write) -> std::io::Result<()> {
80    buffer.write_all(&self.bytes)
81  }
82}
83
84impl Buffer for NbtRaw {
85  fn read_buf(buffer: &mut std::io::Cursor<&[u8]>) -> Option<Self> {
86    if HeightmapsRaw::remaining(buffer) == 0 {
87      return Some(Self { bytes: vec![] });
88    }
89
90    let start = buffer.position() as usize;
91    let tag_id = read_byte(buffer)?;
92    if tag_id == 0 {
93      let end = buffer.position() as usize;
94      return Some(Self {
95        bytes: buffer.get_ref()[start..end].to_vec(),
96      });
97    }
98
99    let name_len = u16::read_buf(buffer)? as usize;
100    let _ = read_bytes(buffer, name_len)?;
101    skip_nbt_payload(buffer, tag_id)?;
102
103    let end = buffer.position() as usize;
104    Some(Self {
105      bytes: buffer.get_ref()[start..end].to_vec(),
106    })
107  }
108
109  fn write_buf(&self, buffer: &mut impl std::io::Write) -> std::io::Result<()> {
110    buffer.write_all(&self.bytes)
111  }
112}
113
114/// Функция пропуска NBT данных
115fn skip_nbt_payload(buffer: &mut std::io::Cursor<&[u8]>, tag_id: u8) -> Option<()> {
116  match tag_id {
117    1 => {
118      let _ = i8::read_buf(buffer)?;
119    }
120    2 => {
121      let _ = i16::read_buf(buffer)?;
122    }
123    3 => {
124      let _ = i32::read_buf(buffer)?;
125    }
126    4 => {
127      let _ = i64::read_buf(buffer)?;
128    }
129    5 => {
130      let _ = f32::read_buf(buffer)?;
131    }
132    6 => {
133      let _ = f64::read_buf(buffer)?;
134    }
135    7 => {
136      let len = i32::read_buf(buffer)? as usize;
137      let _ = read_bytes(buffer, len)?;
138    }
139    8 => {
140      let len = u16::read_buf(buffer)? as usize;
141      let _ = read_bytes(buffer, len)?;
142    }
143    9 => {
144      let child_id = read_byte(buffer)?;
145      let len = i32::read_buf(buffer)? as usize;
146      for _ in 0..len {
147        skip_nbt_payload(buffer, child_id)?;
148      }
149    }
150    10 => loop {
151      let id = read_byte(buffer)?;
152      if id == 0 {
153        break;
154      }
155      let name_len = u16::read_buf(buffer)? as usize;
156      let _ = read_bytes(buffer, name_len)?;
157      skip_nbt_payload(buffer, id)?;
158    },
159    11 => {
160      let len = i32::read_buf(buffer)? as usize;
161      let _ = read_bytes(buffer, len * 4)?;
162    }
163    12 => {
164      let len = i32::read_buf(buffer)? as usize;
165      let _ = read_bytes(buffer, len * 8)?;
166    }
167    _ => return None,
168  }
169
170  Some(())
171}