1use crate::snap::Error;
2use crate::ReadInt;
3use libtw2_buffer::CapacityError;
4use libtw2_packer::IntUnpacker;
5use libtw2_packer::Packer;
6use libtw2_packer::Unpacker;
7use libtw2_warn::wrap;
8use libtw2_warn::Warn;
9use uuid::Uuid;
10
11#[derive(Clone, Debug, Eq, PartialEq)]
12pub struct DeltaDifferingSizes;
13
14#[derive(Clone, Debug, Eq, PartialEq)]
15pub enum Warning {
16 Packer(libtw2_packer::Warning),
17 NonZeroPadding,
18 DuplicateDelete,
19 DuplicateUpdate,
20 UnknownDelete,
21 DeleteUpdate,
22 NumUpdatedItems,
23 ExcessSnapData,
24 ExcessUuidItemData,
25}
26
27impl From<libtw2_packer::Warning> for Warning {
28 fn from(w: libtw2_packer::Warning) -> Warning {
29 Warning::Packer(w)
30 }
31}
32
33pub use libtw2_gamenet_common::snap_obj::TypeId;
34
35pub const TYPE_ID_EX: u16 = 0;
36pub const OFFSET_EXTENDED_TYPE_ID: u16 = 0x4000;
37
38pub fn key_to_raw_type_id(key: i32) -> u16 {
39 ((key as u32 >> 16) & 0xffff) as u16
40}
41
42pub fn key_to_id(key: i32) -> u16 {
43 ((key as u32) & 0xffff) as u16
44}
45
46pub fn key(raw_type_id: u16, id: u16) -> i32 {
47 (((raw_type_id as u32) << 16) | (id as u32)) as i32
48}
49
50pub fn uuid_to_item_data(uuid: Uuid) -> [i32; 4] {
51 let mut result = [0; 4];
52 for (int, four_bytes) in result.iter_mut().zip(uuid.as_bytes().chunks(4)) {
53 let four_bytes: [u8; 4] = four_bytes.try_into().unwrap();
54 *int = i32::from_be_bytes(four_bytes);
55 }
56 result
57}
58
59pub fn item_data_to_uuid<W: Warn<Warning>>(warn: &mut W, mut data: &[i32]) -> Option<Uuid> {
60 if data.len() > 4 {
61 data = &data[..4];
62 warn.warn(Warning::ExcessUuidItemData);
63 }
64 let data: &[i32; 4] = data.try_into().ok()?;
65
66 let mut result = [0; 16];
67 for (four_bytes, &int) in result.chunks_mut(4).zip(data) {
68 four_bytes.copy_from_slice(&int.to_be_bytes());
69 }
70 Some(Uuid::from_bytes(result))
71}
72
73#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
74pub struct Item<'a> {
75 pub type_id: TypeId,
76 pub id: u16,
77 pub data: &'a [i32],
78}
79
80#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
81pub struct RawItem<'a> {
82 pub raw_type_id: u16,
83 pub id: u16,
84 pub data: &'a [i32],
85}
86
87impl<'a> RawItem<'a> {
88 pub fn from_key(key: i32, data: &'a [i32]) -> RawItem<'a> {
89 RawItem {
90 raw_type_id: key_to_raw_type_id(key),
91 id: key_to_id(key),
92 data: data,
93 }
94 }
95 pub fn key(&self) -> i32 {
96 key(self.raw_type_id, self.id)
97 }
98}
99
100pub struct SnapHeader {
101 pub data_size: i32,
102 pub num_items: i32,
103}
104
105impl SnapHeader {
106 pub fn decode<W: Warn<Warning>>(warn: &mut W, p: &mut Unpacker) -> Result<SnapHeader, Error> {
107 Ok(SnapHeader {
108 data_size: libtw2_packer::positive(p.read_int(wrap(warn))?)?,
109 num_items: libtw2_packer::positive(p.read_int(wrap(warn))?)?,
110 })
111 }
112 pub fn decode_obj(p: &mut IntUnpacker) -> Result<SnapHeader, Error> {
113 Ok(SnapHeader {
114 data_size: libtw2_packer::positive(p.read_int()?)?,
115 num_items: libtw2_packer::positive(p.read_int()?)?,
116 })
117 }
118}
119
120#[derive(Clone, Copy, Debug)]
121pub struct DeltaHeader {
122 pub num_deleted_items: i32,
123 pub num_updated_items: i32,
124}
125
126impl DeltaHeader {
127 pub(crate) fn decode_impl<W: Warn<Warning>, R: ReadInt>(
128 warn: &mut W,
129 reader: &mut R,
130 ) -> Result<DeltaHeader, Error> {
131 let result = DeltaHeader {
132 num_deleted_items: libtw2_packer::positive(reader.read_int(warn)?)?,
133 num_updated_items: libtw2_packer::positive(reader.read_int(warn)?)?,
134 };
135 if reader.read_int(warn)? != 0 {
136 warn.warn(Warning::NonZeroPadding);
137 }
138 Ok(result)
139 }
140 pub fn decode<W: Warn<Warning>>(warn: &mut W, p: &mut Unpacker) -> Result<DeltaHeader, Error> {
141 DeltaHeader::decode_impl(warn, p)
142 }
143 pub fn decode_obj<W: Warn<Warning>>(
144 warn: &mut W,
145 p: &mut IntUnpacker,
146 ) -> Result<DeltaHeader, Error> {
147 DeltaHeader::decode_impl(warn, p)
148 }
149 pub fn encode<'d, 's>(&self, mut p: Packer<'d, 's>) -> Result<&'d [u8], CapacityError> {
150 for int in self.encode_obj() {
151 p.write_int(int)?;
152 }
153 Ok(p.written())
154 }
155 pub fn encode_obj(&self) -> [i32; 3] {
156 [self.num_deleted_items, self.num_updated_items, 0]
157 }
158}
159
160pub fn apply_item_delta(
185 in_: Option<&[i32]>,
186 delta: &[i32],
187 out: &mut [i32],
188) -> Result<(), DeltaDifferingSizes> {
189 assert!(delta.len() == out.len());
190 match in_ {
191 Some(in_) => {
192 if in_.len() != out.len() {
193 return Err(DeltaDifferingSizes);
194 }
195 for i in 0..out.len() {
196 out[i] = in_[i].wrapping_add(delta[i]);
197 }
198 }
199 None => out.copy_from_slice(delta),
200 }
201 Ok(())
202}
203
204pub fn create_item_delta(
229 from: Option<&[i32]>,
230 to: &[i32],
231 out: &mut [i32],
232) -> Result<(), DeltaDifferingSizes> {
233 assert!(to.len() == out.len());
234 match from {
235 Some(from) => {
236 if from.len() != to.len() {
237 return Err(DeltaDifferingSizes);
238 }
239 for i in 0..out.len() {
240 out[i] = to[i].wrapping_sub(from[i]);
241 }
242 }
243 None => out.copy_from_slice(to),
244 }
245 Ok(())
246}