1use bytes::{Bytes, BytesMut};
11use bytestring::ByteString;
12use uuid::Uuid;
13
14use crate::codec::EncodeResult;
15use crate::nbt::{Compound, List, NamedTag, RawNbt, Tag, tag};
16use crate::types::BlockPos;
17
18pub trait Generate: Sized {
20 fn generate(g: &mut Gen) -> Self;
22}
23
24#[derive(Debug, Clone)]
26pub struct Gen {
27 state: u64,
28 pub node_compat: bool,
31}
32
33impl Gen {
34 pub fn new(seed: u64) -> Self {
36 Gen {
37 state: seed ^ 0x9e37_79b9_7f4a_7c15,
38 node_compat: false,
39 }
40 }
41
42 pub fn u64(&mut self) -> u64 {
44 self.state = self.state.wrapping_add(0x9e37_79b9_7f4a_7c15);
45 let mut z = self.state;
46 z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
47 z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
48 z ^ (z >> 31)
49 }
50
51 pub fn below(&mut self, n: u64) -> u64 {
53 self.u64() % n
54 }
55
56 pub fn chance(&mut self, percent: u64) -> bool {
58 self.below(100) < percent
59 }
60
61 pub fn bool(&mut self) -> bool {
63 self.u64() & 1 == 1
64 }
65
66 pub fn int_in(&mut self, lo: i64, hi: i64, hints: &[i64]) -> i64 {
68 let ok: Vec<i64> = hints
69 .iter()
70 .copied()
71 .filter(|v| (lo..=hi).contains(v))
72 .collect();
73 if !ok.is_empty() && self.chance(65) {
74 return ok[self.below(ok.len() as u64) as usize];
75 }
76 match self.below(10) {
77 0..=2 => (self.below(20) as i64 - 3).clamp(lo, hi),
78 3 => lo,
79 4 => hi,
80 _ => {
81 let span = (hi as i128 - lo as i128 + 1) as u128;
82 (lo as i128 + (u128::from(self.u64()) % span) as i128) as i64
83 }
84 }
85 }
86
87 pub fn small_count(&mut self) -> u8 {
89 self.below(4) as u8
90 }
91
92 pub fn count(&mut self) -> usize {
94 if self.chance(90) {
95 self.below(4) as usize
96 } else {
97 self.below(13) as usize
98 }
99 }
100
101 pub fn i64(&mut self) -> i64 {
103 self.int_in(i64::MIN, i64::MAX, &[])
104 }
105
106 pub fn varlong(&mut self) -> i64 {
109 if self.node_compat {
110 self.int_in(0, i64::from(i32::MAX), &[])
111 } else {
112 self.i64()
113 }
114 }
115
116 pub fn f32(&mut self) -> f32 {
118 match self.below(4) {
119 0 => [0.0, -0.0, 1.0, -1.5, 0.25, 64.0][self.below(6) as usize],
120 _ => loop {
121 let v = f32::from_bits(self.u64() as u32);
122 if v.is_finite() {
123 break v;
124 }
125 },
126 }
127 }
128
129 pub fn f64(&mut self) -> f64 {
131 match self.below(4) {
132 0 => [0.0, -0.0, 1.0, -1.5, 0.25, 1e300][self.below(6) as usize],
133 _ => loop {
134 let v = f64::from_bits(self.u64());
135 if v.is_finite() {
136 break v;
137 }
138 },
139 }
140 }
141
142 pub fn uuid(&mut self) -> Uuid {
144 Uuid::from_u64_pair(self.u64(), self.u64())
145 }
146
147 fn text(&mut self, bmp_only: bool) -> String {
148 const CHARS: &[char] = &[
149 'a',
150 'b',
151 'z',
152 'A',
153 'Q',
154 '0',
155 '9',
156 ' ',
157 '_',
158 ':',
159 '{',
160 '"',
161 '\u{a7}',
162 '\u{e9}',
163 '\u{131}',
164 '\u{65e5}',
165 '\u{1f600}',
166 ];
167 let n = self.below(12) as usize;
168 (0..n)
169 .map(|_| CHARS[self.below(CHARS.len() as u64 - u64::from(bmp_only)) as usize])
170 .collect()
171 }
172
173 pub fn string(&mut self) -> ByteString {
175 ByteString::from(self.text(false))
176 }
177
178 pub fn string_in(&mut self, hints: &[&str]) -> ByteString {
180 if !hints.is_empty() && self.chance(80) {
181 ByteString::from(hints[self.below(hints.len() as u64) as usize].to_string())
182 } else {
183 self.string()
184 }
185 }
186
187 pub fn bytes(&mut self) -> Bytes {
189 let n = self.below(25) as usize;
190 (0..n).map(|_| self.u64() as u8).collect::<Vec<u8>>().into()
191 }
192
193 pub fn position(&mut self) -> BlockPos {
195 BlockPos::new(
196 self.int_in(-(1 << 25), (1 << 25) - 1, &[0]) as i32,
197 self.int_in(-2048, 2047, &[0, 64]) as i32,
198 self.int_in(-(1 << 25), (1 << 25) - 1, &[0]) as i32,
199 )
200 }
201
202 fn nbt_tag(&mut self, ty: u8, depth: u32) -> Tag {
203 match ty {
204 tag::BYTE => Tag::Byte(self.u64() as i8),
205 tag::SHORT => Tag::Short(self.u64() as i16),
206 tag::INT => Tag::Int(self.u64() as i32),
207 tag::LONG => Tag::Long(self.u64() as i64),
208 tag::FLOAT => Tag::Float(self.f32()),
209 tag::DOUBLE => Tag::Double(self.f64()),
210 tag::BYTE_ARRAY => Tag::ByteArray(self.bytes()),
211 tag::STRING => Tag::String(self.text(true)),
212 tag::LIST => {
213 let elem = if depth >= 3 {
214 1 + self.below(8) as u8
215 } else {
216 1 + self.below(12) as u8
217 };
218 let n = self.count();
219 let items: Vec<Tag> = (0..n).map(|_| self.nbt_tag(elem, depth + 1)).collect();
220 let elem = if items.is_empty() && self.bool() {
221 tag::END
222 } else {
223 elem
224 };
225 Tag::List(List {
226 elem_type: elem,
227 items,
228 })
229 }
230 tag::COMPOUND => {
231 let n = if depth >= 3 { 0 } else { self.count() };
232 Tag::Compound(Compound(
235 (0..n)
236 .map(|i| {
237 let t = 1 + self.below(12) as u8;
238 (
239 format!("k{i}{}", self.text(true)),
240 self.nbt_tag(t, depth + 1),
241 )
242 })
243 .collect(),
244 ))
245 }
246 tag::INT_ARRAY => Tag::IntArray((0..self.count()).map(|_| self.u64() as i32).collect()),
247 _ => Tag::LongArray((0..self.count()).map(|_| self.u64() as i64).collect()),
248 }
249 }
250
251 pub fn nbt(&mut self) -> RawNbt {
253 if !self.node_compat && self.chance(10) {
254 return RawNbt::END;
255 }
256 let t = NamedTag {
257 name: if self.chance(70) {
258 String::new()
259 } else {
260 self.text(true)
261 },
262 tag: self.nbt_tag(tag::COMPOUND, 0),
263 };
264 RawNbt::from_named(&t).expect("generated NBT is encodable")
265 }
266
267 pub fn opt_nbt(&mut self) -> Option<RawNbt> {
269 if self.chance(30) {
270 None
271 } else {
272 let t = NamedTag {
273 name: String::new(),
274 tag: self.nbt_tag(tag::COMPOUND, 0),
275 };
276 Some(RawNbt::from_named(&t).expect("generated NBT is encodable"))
277 }
278 }
279}
280
281pub fn first_byte_ok(
284 f: impl FnOnce(&mut BytesMut) -> EncodeResult,
285 pred: impl Fn(u8) -> bool,
286) -> bool {
287 let mut w = BytesMut::new();
288 f(&mut w).is_ok() && w.first().is_some_and(|&b| pred(b))
289}
290
291impl Generate for crate::types::slot::legacy::Slot {
292 fn generate(g: &mut Gen) -> Self {
293 use crate::types::slot::legacy::{ItemStack, Slot};
294 if g.chance(25) {
295 return Slot(None);
296 }
297 let id = loop {
298 let id = g.int_in(i64::from(i16::MIN), i64::from(i16::MAX), &[1, 276]) as i16;
299 if id != -1 {
300 break id;
301 }
302 };
303 Slot(Some(ItemStack {
304 id,
305 count: g.u64() as i8,
306 damage: g.u64() as i16,
307 nbt: g.opt_nbt(),
308 }))
309 }
310}
311
312impl Generate for crate::types::slot::modern::Slot {
313 fn generate(g: &mut Gen) -> Self {
314 use crate::types::slot::modern::{ItemStack, Slot};
315 if g.chance(25) {
316 return Slot(None);
317 }
318 Slot(Some(ItemStack {
319 id: g.int_in(i64::from(i32::MIN), i64::from(i32::MAX), &[1, 600]) as i32,
320 count: g.u64() as i8,
321 nbt: g.opt_nbt(),
322 }))
323 }
324}