1use std::{
2 f32::consts::PI,
3 fmt::{Debug, Display, Formatter},
4 ops::{Add, AddAssign, Index, Mul, MulAssign, Neg, Sub},
5};
6
7use colored::Colorize;
8use itertools::Itertools;
9use once_cell::sync::Lazy;
10use regex::{Captures, Regex};
11use serde::{Deserialize, Serialize};
12use swarm_bot_packets::{
13 read::{ByteReadable, ByteReader},
14 write::{ByteWritable, ByteWriter},
15 *,
16};
17
18use crate::types::{
19 block_data::{Block, BlockData},
20 Origin::{Abs, Rel},
21};
22
23pub mod block_data;
24
25#[derive(Clone)]
26pub struct PacketData {
27 pub id: u32,
28 pub reader: ByteReader,
29}
30
31impl PacketData {
32 #[inline]
33 pub fn read<T: ByteReadable>(&mut self) -> T {
34 self.reader.read()
35 }
36}
37
38#[derive(Serialize, Deserialize, Debug, Clone)]
39pub struct ChatSection {
40 pub color: Option<String>,
41 pub bold: Option<bool>,
42 pub italic: Option<bool>,
43 pub underlined: Option<bool>,
44 pub strikethrough: Option<bool>,
45 pub text: String,
46}
47
48#[derive(Serialize, Deserialize, Debug, Clone)]
49pub struct Chat {
50 pub extra: Option<Vec<ChatSection>>,
51 pub text: Option<String>,
52}
53
54impl Chat {
55 pub fn colorize(self) -> String {
56 if let Some(extra) = self.extra {
57 extra.into_iter().map(|section| section.colorize()).join("")
58 } else {
59 String::new()
60 }
61 }
62}
63
64impl ChatSection {
65 fn colorize(self) -> String {
66 use colored::Color::*;
67
68 let color = match self.color.unwrap_or_default().as_str() {
69 "dark_blue" | "blue" => Blue,
70 "dark_aqua" | "aqua" => Cyan,
71 "red" | "dark_red" => Red,
72 "purple" | "light_purple" => Magenta,
73 "gold" | "yellow" => Yellow,
74 "gray" => White,
75 "dark_gray" => Black,
76 "green" | "dark_green" => Green,
77 "white" => White,
78 _ => Black,
79 };
80
81 let mut res = self.text.color(color);
82
83 if self.bold.unwrap_or_default() {
84 res = res.bold();
85 }
86
87 if self.italic.unwrap_or_default() {
88 res = res.italic();
89 }
90
91 if self.underlined.unwrap_or_default() {
92 res = res.underline();
93 }
94
95 if self.strikethrough.unwrap_or_default() {
96 res = res.strikethrough();
97 }
98
99 res.to_string()
100 }
101}
102
103#[derive(Debug)]
104pub struct Command {
105 pub player: String,
106 pub command: String,
107 pub args: Vec<String>,
108}
109
110#[derive(Debug)]
111pub struct PlayerMessage {
112 pub player: String,
113 pub message: String,
114}
115
116impl PlayerMessage {
117 pub fn into_cmd(self) -> Option<Command> {
118 static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"#(\S+)\s?(.*)").unwrap());
119 let capture = RE.captures(&self.message)?;
120
121 let command = capture.get(1)?.as_str().to_string();
122 let args = capture.get(2)?.as_str().to_string();
123
124 let args = if args.is_empty() {
125 Vec::new()
126 } else {
127 args.split(' ').map(|x| x.to_string()).collect()
128 };
129
130 Some(Command {
131 player: self.player,
132 command,
133 args,
134 })
135 }
136}
137
138impl Chat {
139 pub fn player_dm(&self) -> Option<PlayerMessage> {
140 static RE: Lazy<Regex> =
141 Lazy::new(|| Regex::new(r"^([A-Za-z_0-9]+) whispers: (.*)").unwrap());
142
143 let text = self.extra.as_ref()?.iter().map(|x| &x.text).join("");
144
145 let captures: Captures = RE.captures(&text)?;
146
147 let player = captures.get(1)?.as_str().to_string();
148 let message = captures.get(2)?.as_str().to_string();
149 Some(PlayerMessage { player, message })
150 }
151 pub fn player_message(&self) -> Option<PlayerMessage> {
152 static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^<([A-Za-z_0-9]+)> (.*)").unwrap());
153
154 let text = self.extra.as_ref()?.iter().map(|x| &x.text).join("");
155
156 let captures: Captures = RE.captures(&text)?;
157
158 let player = captures.get(1)?.as_str().to_string();
159 let message = captures.get(2)?.as_str().to_string();
160
161 Some(PlayerMessage { player, message })
162 }
163}
164
165impl ByteReadable for Chat {
166 fn read_from_bytes(byte_reader: &mut ByteReader) -> Self {
167 let string: String = byte_reader.read();
168 let json: Chat = serde_json::from_str(&string).unwrap();
169 json
170 }
171}
172
173#[derive(Writable, Readable, Debug, Copy, Clone, Default, PartialEq)]
174pub struct LocationFloat {
175 pub x: f32,
176 pub y: f32,
177 pub z: f32,
178}
179
180impl From<LocationFloat> for Location {
181 fn from(loc: LocationFloat) -> Self {
182 Self {
183 x: loc.x as f64,
184 y: loc.y as f64,
185 z: loc.z as f64,
186 }
187 }
188}
189
190impl Add<Displacement> for Location {
191 type Output = Location;
192
193 fn add(self, rhs: Displacement) -> Self::Output {
194 Location {
195 x: self.x + rhs.dx,
196 y: self.y + rhs.dy,
197 z: self.z + rhs.dz,
198 }
199 }
200}
201
202impl Location {
203 pub const fn new(x: f64, y: f64, z: f64) -> Location {
204 Location { x, y, z }
205 }
206}
207
208impl From<Location> for BlockLocation {
209 fn from(location: Location) -> Self {
210 let Location { x, y, z } = location;
211 BlockLocation::from_flts(x, y, z)
212 }
213}
214
215impl Sub<Location> for Location {
216 type Output = Displacement;
217
218 fn sub(self, rhs: Location) -> Self::Output {
219 Displacement {
220 dx: self.x - rhs.x,
221 dy: self.y - rhs.y,
222 dz: self.z - rhs.z,
223 }
224 }
225}
226
227impl Display for Location {
228 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
229 f.write_fmt(format_args!("[{:.2} {:.2} {:.2}]", self.x, self.y, self.z))
230 }
231}
232
233#[derive(Writable, Readable, Debug, Copy, Clone, Default)]
234pub struct Displacement {
235 pub dx: f64,
236 pub dy: f64,
237 pub dz: f64,
238}
239
240#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
241pub struct Enchantment {
242 pub lvl: u16,
243 pub id: u16,
244}
245
246impl Enchantment {
247 pub fn efficiency(self) -> Option<u16> {
248 if self.id == 32 {
249 Some(self.lvl)
250 } else {
251 None
252 }
253 }
254}
255
256pub struct ShortVec<T>(pub Vec<T>);
257
258impl<T: ByteReadable> ByteReadable for ShortVec<T> {
259 fn read_from_bytes(byte_reader: &mut ByteReader) -> Self {
260 let length: u16 = byte_reader.read();
261 let length = length as usize;
262 let mut vec = Vec::with_capacity(length);
263 for _ in 0..length {
264 vec.push(byte_reader.read());
265 }
266 ShortVec(vec)
267 }
268}
269
270pub struct Change {
271 pub dx: i32,
272 pub dy: i16,
273 pub dz: i32,
274}
275
276impl Change {
277 pub fn new(dx: i32, dy: i16, dz: i32) -> Change {
278 Change { dx, dy, dz }
279 }
280}
281
282impl From<Change> for Displacement {
283 fn from(change: Change) -> Self {
284 Self {
285 dx: change.dx as f64,
286 dy: change.dy as f64,
287 dz: change.dz as f64,
288 }
289 }
290}
291
292impl Display for Displacement {
293 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
294 f.write_fmt(format_args!(
295 "[{:.2} {:.2} {:.2}]",
296 self.dx, self.dy, self.dz
297 ))
298 }
299}
300
301impl Neg for Displacement {
302 type Output = Displacement;
303
304 fn neg(self) -> Self::Output {
305 self * (-1.0)
306 }
307}
308
309impl Sub for Displacement {
310 type Output = Displacement;
311
312 fn sub(self, rhs: Self) -> Self::Output {
313 let rhs = rhs * (-1.0);
314 self + rhs
315 }
316}
317
318impl Add for Displacement {
319 type Output = Displacement;
320
321 fn add(self, rhs: Self) -> Self::Output {
322 Self {
323 dx: self.dx + rhs.dx,
324 dy: self.dy + rhs.dy,
325 dz: self.dz + rhs.dz,
326 }
327 }
328}
329
330impl Displacement {
331 pub const EYE_HEIGHT: Displacement = Displacement::new(0., 1.6, 0.);
332 pub const EPSILON_Y: Displacement = Displacement::new(0., 0.01, 0.);
333
334 pub const fn new(dx: f64, dy: f64, dz: f64) -> Displacement {
335 Displacement { dx, dy, dz }
336 }
337
338 pub fn zero_if_reachable(&self) -> Displacement {
339 let dx = if self.dx.abs() < 0.5 { 0. } else { self.dx };
340 let dy = if self.dy.abs() < 0.5 { 0. } else { self.dy };
341 let dz = if self.dz.abs() < 0.5 { 0. } else { self.dz };
342 Self { dx, dy, dz }
343 }
344
345 pub fn make_dy(&self, dy: f64) -> Displacement {
346 Self {
347 dx: self.dx,
348 dy,
349 dz: self.dz,
350 }
351 }
352
353 pub fn mag(&self) -> f64 {
354 self.mag2().sqrt()
355 }
356
357 pub fn dot(&self, other: Displacement) -> f64 {
358 self.dx * other.dx + self.dy * other.dy + self.dz * other.dz
359 }
360
361 pub fn reflect(&self, normal: Displacement) -> Displacement {
362 let rhs = normal * 2.0 * (self.dot(normal));
363 *self - rhs
364 }
365
366 pub fn normalize(self) -> Displacement {
367 let mag = self.mag();
368 if mag == 0. {
369 self
371 } else {
372 let mult = 1.0 / mag;
373 self * mult
374 }
375 }
376
377 pub fn mag2(&self) -> f64 {
378 let Displacement { dx, dy, dz } = *self;
379 dx * dx + dy * dy + dz * dz
380 }
381
382 pub fn cross(&self, other: Displacement) -> Displacement {
383 let dx = self[1] * other[2] - self[2] * other[1];
384 let dy = self[2] * other[0] - self[0] * other[2];
385 let dz = self[0] * other[1] - self[1] * other[0];
386 Displacement::new(dx, dy, dz)
387 }
388 pub fn has_length(&self) -> bool {
389 self.dx != 0.0 || self.dy != 0.0 || self.dz != 0.0
390 }
391}
392
393impl MulAssign<f64> for Displacement {
394 fn mul_assign(&mut self, rhs: f64) {
395 self.dx *= rhs;
396 self.dy *= rhs;
397 self.dz *= rhs;
398 }
399}
400
401impl Mul<f64> for Displacement {
402 type Output = Displacement;
403
404 fn mul(self, rhs: f64) -> Self::Output {
405 Self {
406 dx: self.dx * rhs,
407 dy: self.dy * rhs,
408 dz: self.dz * rhs,
409 }
410 }
411}
412
413impl Index<usize> for Displacement {
414 type Output = f64;
415
416 fn index(&self, index: usize) -> &Self::Output {
417 match index {
418 0 => &self.dx,
419 1 => &self.dy,
420 2 => &self.dz,
421 _ => panic!("invalid index"),
422 }
423 }
424}
425
426impl AddAssign<Location> for Location {
427 fn add_assign(&mut self, rhs: Location) {
428 self.x += rhs.x;
429 self.y += rhs.y;
430 self.z += rhs.z;
431 }
432}
433
434impl Add<Location> for Location {
435 type Output = Location;
436
437 fn add(self, rhs: Location) -> Self::Output {
438 Location {
439 x: self.x + rhs.x,
440 y: self.y + rhs.y,
441 z: self.z + rhs.z,
442 }
443 }
444}
445
446impl From<Location> for LocationOrigin {
459 fn from(loc: Location) -> Self {
460 LocationOrigin {
461 x: Abs(loc.x),
462 y: Abs(loc.y),
463 z: Abs(loc.z),
464 }
465 }
466}
467
468impl Location {
469 pub fn dist2(&self, loc: Location) -> f64 {
470 let dx = loc.x - self.x;
471 let dy = loc.y - self.y;
472 let dz = loc.z - self.z;
473 dx * dx + dy * dy + dz * dz
474 }
475
476 pub fn apply_change(&mut self, loc: LocationOrigin) {
477 loc.x.apply(&mut self.x);
478 loc.y.apply(&mut self.y);
479 loc.z.apply(&mut self.z);
480 }
481}
482
483#[derive(Readable, Writable, Debug)]
484pub struct ShortLoc {
485 dx: i16,
486 dy: i16,
487 dz: i16,
488}
489
490impl From<ShortLoc> for LocationOrigin {
491 fn from(loc: ShortLoc) -> Self {
492 LocationOrigin {
493 x: Rel(loc.dx as f64 / (128.0 * 32.0)),
494 y: Rel(loc.dy as f64 / (128.0 * 32.0)),
495 z: Rel(loc.dz as f64 / (128.0 * 32.0)),
496 }
497 }
498}
499
500impl Add<LocationOrigin> for Location {
501 type Output = Location;
502
503 fn add(mut self, rhs: LocationOrigin) -> Self::Output {
504 rhs.x.apply(&mut self.x);
505 rhs.y.apply(&mut self.y);
506 rhs.z.apply(&mut self.z);
507 self
508 }
509}
510
511#[derive(Debug, Eq, PartialEq)]
512pub enum Origin<T> {
513 Rel(T),
514 Abs(T),
515}
516
517impl<T> Origin<T> {
518 fn from(value: T, relative: bool) -> Origin<T> {
519 if relative {
520 Rel(value)
521 } else {
522 Abs(value)
523 }
524 }
525}
526
527impl Origin<f64> {
528 pub fn apply(&self, other: &mut f64) {
529 match self {
530 Rel(x) => *other += *x,
531 Abs(x) => *other = *x,
532 }
533 }
534}
535
536impl Origin<f32> {
537 pub fn apply(&self, other: &mut f32) {
538 match self {
539 Rel(x) => *other += *x,
540 Abs(x) => *other = *x,
541 }
542 }
543}
544
545#[derive(Debug)]
546pub struct LocationOrigin {
547 pub x: Origin<f64>,
548 pub y: Origin<f64>,
549 pub z: Origin<f64>,
550}
551
552impl LocationOrigin {
553 pub fn from(location: Location, x: bool, y: bool, z: bool) -> LocationOrigin {
554 LocationOrigin {
555 x: Origin::from(location.x, x),
556 y: Origin::from(location.y, y),
557 z: Origin::from(location.z, z),
558 }
559 }
560}
561
562#[derive(Debug)]
563pub struct DirectionOrigin {
564 pub yaw: Origin<f32>,
565 pub pitch: Origin<f32>,
566}
567
568impl DirectionOrigin {
569 pub fn from(dir: Direction, yaw: bool, pitch: bool) -> DirectionOrigin {
570 DirectionOrigin {
571 yaw: Origin::from(dir.yaw, yaw),
572 pitch: Origin::from(dir.pitch, pitch),
573 }
574 }
575}
576
577#[derive(Readable, Writable, Copy, Clone, Default, Debug)]
578pub struct Direction {
579 pub yaw: f32,
587 pub pitch: f32,
588}
589
590impl Direction {
591 pub const DOWN: Direction = Direction {
592 yaw: 90.,
593 pitch: 90.,
594 };
595
596 pub fn unit_vector(&self) -> Displacement {
597 let pitch = self.pitch.to_radians();
598 let yaw = self.yaw.to_radians();
599
600 let x = -(pitch).to_radians().cos() * (yaw).sin();
601 let y = -(pitch).sin();
602 let z = (pitch).cos() * (yaw).cos();
603
604 Displacement::new(x as f64, y as f64, z as f64)
605 }
606
607 pub fn horizontal(&self) -> Direction {
608 let mut res = *self;
609 res.pitch = 0.0;
610 res
611 }
612}
613
614impl From<Displacement> for Direction {
615 fn from(displacement: Displacement) -> Self {
616 let Displacement { dx, dy, dz } = displacement;
617 let (dx, dy, dz) = (dx as f32, dy as f32, dz as f32);
618 let r = (dx * dx + dy * dy + dz * dz).sqrt();
619 let mut yaw = -dx.atan2(dz) / PI * 180.0;
620
621 if yaw < 0.0 {
622 yaw += 360.0
623 }
624
625 const EPSILON: f32 = 0.1;
626
627 if yaw.abs() < EPSILON {
628 yaw = 0.0;
629 }
630 let pitch = -(dy / r).asin() / PI * 180.0;
631 Direction { yaw, pitch }
632 }
633}
634
635#[derive(Debug, Copy, Clone, Eq, PartialEq)]
636pub enum Dimension {
637 Nether,
638 Overworld,
639 End,
640}
641
642impl Display for Dimension {
643 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
644 let to_write = match self {
645 Dimension::Nether => "nether",
646 Dimension::Overworld => "overworld",
647 Dimension::End => "end",
648 };
649 f.write_str(to_write)
650 }
651}
652
653impl ByteReadable for Dimension {
654 fn read_from_bytes(byte_reader: &mut ByteReader) -> Self {
655 use Dimension::*;
656 let val: i32 = byte_reader.read();
657 match val {
658 -1 => Nether,
659 0 => Overworld,
660 1 => End,
661 val => panic!("dimension {val} is not valid"),
662 }
663 }
664}
665
666pub type Position = BlockLocation;
667
668impl ByteReadable for Position {
669 fn read_from_bytes(byte_reader: &mut ByteReader) -> Self {
671 let val: u64 = byte_reader.read();
672
673 let mut x = (val >> 38) as i32;
674 let mut y = ((val >> 26) & 0xFFF) as i16;
675 let mut z = (val << 38 >> 38) as i32;
676
677 const LAT_LON_THRESHOLD: i32 = 1 << 25;
678 const LAT_LON_SUB: i32 = 1 << 26;
679
680 const Y_THRESH: i16 = 1 << 11;
681 const Y_SUB: i16 = 1 << 12;
682
683 if x >= LAT_LON_THRESHOLD {
684 x -= LAT_LON_SUB
685 }
686 if y >= Y_THRESH {
687 y -= Y_SUB
688 }
689 if z >= LAT_LON_THRESHOLD {
690 z -= LAT_LON_SUB
691 }
692
693 Position { x, y, z }
694 }
695}
696
697impl ByteWritable for Position {
698 fn write_to_bytes(self, writer: &mut ByteWriter) {
699 let Position { x, y, z } = self;
700 let write =
701 ((x as u64 & 0x3FFFFFF) << 38) | ((y as u64 & 0xFFF) << 26) | (z as u64 & 0x3FFFFFF);
702 writer.write(write);
703 }
704}
705
706#[derive(Serialize, Deserialize, Debug)]
707pub struct Selection2D {
708 pub from: BlockLocation2D,
709 pub to: BlockLocation2D,
710}
711
712impl Selection2D {
713 pub fn normalize(self) -> Self {
716 let min_x = self.from.x.min(self.to.x);
717 let min_z = self.from.z.min(self.to.z);
718
719 let max_x = self.from.x.max(self.to.x);
720 let max_z = self.from.z.max(self.to.z);
721
722 Selection2D {
723 from: BlockLocation2D::new(min_x, min_z),
724 to: BlockLocation2D::new(max_x, max_z),
725 }
726 }
727}
728
729#[derive(Writable, Readable, Debug, Copy, Clone, Default, PartialEq)]
730pub struct Location {
731 pub x: f64,
732 pub y: f64,
733 pub z: f64,
734}
735
736impl Location {
737 pub fn sub_y(&self, dy: f64) -> Location {
738 Location::new(self.x, self.y - dy, self.z)
739 }
740
741 pub fn round(&self) -> Location {
742 let &Location { x, y, z } = self;
743 Location {
744 x: x.round(),
745 y: y.round(),
746 z: z.round(),
747 }
748 }
749
750 pub fn add_y(&self, dy: f64) -> Location {
751 Location::new(self.x, self.y + dy, self.z)
752 }
753}
754
755impl Sub<Displacement> for Location {
756 type Output = Location;
757
758 fn sub(self, rhs: Displacement) -> Self::Output {
759 let Displacement { dx, dy, dz } = rhs;
760 Self {
761 x: self.x - dx,
762 y: self.y - dy,
763 z: self.z - dz,
764 }
765 }
766}
767
768#[derive(Copy, Clone, Hash, Eq, PartialEq)]
769pub struct ChunkLocation(pub i32, pub i32);
770
771impl From<BlockLocation> for ChunkLocation {
772 fn from(loc: BlockLocation) -> Self {
773 Self(loc.x >> 4, loc.z >> 4)
774 }
775}
776
777impl From<Location> for ChunkLocation {
778 fn from(loc: Location) -> Self {
779 let block_loc = BlockLocation::from(loc);
780 Self::from(block_loc)
781 }
782}
783
784#[derive(
788 Copy, Clone, Debug, Hash, PartialOrd, PartialEq, Ord, Eq, Default, Serialize, Deserialize,
789)]
790pub struct BlockLocation {
791 pub x: i32,
792 pub y: i16,
793 pub z: i32,
794}
795
796impl From<BlockLocation> for BlockLocation2D {
797 fn from(loc: BlockLocation) -> Self {
798 Self { x: loc.x, z: loc.z }
799 }
800}
801
802impl From<BlockLocation2D> for BlockLocation {
803 fn from(loc: BlockLocation2D) -> Self {
804 Self {
805 x: loc.x,
806 y: 0,
807 z: loc.z,
808 }
809 }
810}
811
812#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
813pub struct BlockLocation2D {
814 pub x: i32,
815 pub z: i32,
816}
817
818impl BlockLocation2D {
819 pub fn new(x: i32, z: i32) -> Self {
820 Self { x, z }
821 }
822 pub fn dist2(self, other: BlockLocation2D) -> u64 {
823 let dx = self.x.abs_diff(other.x) as u64;
825 let dz = self.z.abs_diff(other.z) as u64;
826 dx * dx + dz * dz
827 }
828}
829
830impl From<Change> for BlockLocation {
831 fn from(change: Change) -> Self {
832 Self {
833 x: change.dx,
834 y: change.dy,
835 z: change.dz,
836 }
837 }
838}
839
840impl Add for BlockLocation {
841 type Output = BlockLocation;
842
843 fn add(self, rhs: Self) -> Self::Output {
844 let BlockLocation { x, y, z } = self;
845 BlockLocation::new(x + rhs.x, y + rhs.y, z + rhs.z)
846 }
847}
848
849impl BlockLocation {
850 pub fn new(x: i32, y: i16, z: i32) -> BlockLocation {
851 BlockLocation { x, y, z }
852 }
853
854 pub fn faces(self) -> [Location; 6] {
855 const DISPLACEMENTS: [Displacement; 6] = {
856 let a = Displacement::new(0.5, 0.0, 0.5);
857 let b = Displacement::new(0.5, 1.0, 0.5);
858
859 let c = Displacement::new(0.5, 0.5, 0.0);
860 let d = Displacement::new(0.5, 0.5, 1.0);
861
862 let e = Displacement::new(0.0, 0.5, 0.5);
863 let f = Displacement::new(1.0, 0.5, 0.5);
864
865 [a, b, c, d, e, f]
866 };
867
868 let lowest = Location::new(self.x as f64, self.y as f64, self.z as f64);
869 let mut res = [Location::default(); 6];
870 for i in 0..6 {
871 res[i] = lowest + DISPLACEMENTS[i]
872 }
873 res
874 }
875
876 pub fn below(&self) -> BlockLocation {
877 Self {
878 x: self.x,
879 y: self.y - 1,
880 z: self.z,
881 }
882 }
883
884 pub fn above(&self) -> BlockLocation {
885 Self {
886 x: self.x,
887 y: self.y + 1,
888 z: self.z,
889 }
890 }
891
892 pub fn get(&self, idx: usize) -> i32 {
893 match idx {
894 0 => self.x,
895 1 => self.y as i32,
896 2 => self.z,
897 _ => panic!("invalid index for block location"),
898 }
899 }
900
901 pub fn set(&mut self, idx: usize, value: i32) {
902 match idx {
903 0 => self.x = value,
904 1 => self.y = value as i16,
905 2 => self.z = value,
906 _ => panic!("invalid index for block location"),
907 }
908 }
909
910 pub fn from_flts(x: impl num::Float, y: impl num::Float, z: impl num::Float) -> BlockLocation {
911 let x = num::cast(x.floor()).unwrap();
912 let y = num::cast(y.floor()).unwrap_or(-100); let z = num::cast(z.floor()).unwrap();
914 BlockLocation::new(x, y, z)
915 }
916
917 pub fn add_y(&self, dy: i16) -> BlockLocation {
918 let &BlockLocation { x, y, z } = self;
919 Self { x, y: y + dy, z }
920 }
921
922 pub fn center_bottom(&self) -> Location {
923 Location {
924 x: self.x as f64 + 0.5,
925 y: self.y as f64,
926 z: self.z as f64 + 0.5,
927 }
928 }
929
930 pub fn true_center(&self) -> Location {
931 Location {
932 x: self.x as f64 + 0.5,
933 y: self.y as f64 + 0.5,
934 z: self.z as f64 + 0.5,
935 }
936 }
937}
938
939impl BlockLocation {
940 pub fn dist2(&self, other: BlockLocation) -> f64 {
941 let (dx, dy, dz) = self.abs_dif(other);
942 let (dx, dy, dz) = (dx as f64, dy as f64, dz as f64);
943 dx * dx + dy * dy + dz * dz
944 }
945
946 pub fn abs_dif(&self, other: BlockLocation) -> (u32, u16, u32) {
947 let dx = self.x.abs_diff(other.x);
948 let dy = self.y.abs_diff(other.y);
949 let dz = self.z.abs_diff(other.z);
950 (dx, dy, dz)
951 }
952
953 pub fn manhatten(&self, other: BlockLocation) -> u64 {
954 let (dx, dy, dz) = self.abs_dif(other);
955 let (dx, dy, dz) = (dx as u64, dy as u64, dz as u64);
956 dx + dy + dz
957 }
958
959 pub fn dist(&self, other: BlockLocation) -> f64 {
960 self.dist2(other).sqrt()
961 }
962}
963
964impl Display for BlockLocation {
965 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
966 f.write_fmt(format_args!("[{}, {}, {}]", self.x, self.y, self.z))
967 }
968}
969
970#[derive(Copy, Clone, Debug)]
971pub enum BlockApprox {
972 Realized(BlockState),
973 Estimate(SimpleType),
974}
975
976impl BlockApprox {
977 pub const AIR: BlockApprox = BlockApprox::Estimate(SimpleType::WalkThrough);
978
979 pub fn s_type(&self) -> SimpleType {
980 match self {
981 BlockApprox::Realized(x) => x.simple_type(),
982 BlockApprox::Estimate(x) => *x,
983 }
984 }
985
986 pub fn as_real(&self) -> BlockState {
987 match self {
988 BlockApprox::Realized(inner) => *inner,
989 _ => panic!("was not realized"),
990 }
991 }
992
993 pub fn is_solid(&self) -> bool {
994 self.s_type() == SimpleType::Solid
995 }
996
997 pub fn is_walkable(&self) -> bool {
998 self.s_type() == SimpleType::WalkThrough
999 }
1000}
1001
1002#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
1003pub enum SimpleType {
1004 Solid,
1005 Water,
1006 Avoid,
1007 WalkThrough,
1008}
1009
1010impl SimpleType {
1011 pub fn id(&self) -> u8 {
1012 match self {
1013 SimpleType::Solid => 0,
1014 SimpleType::Water => 1,
1015 SimpleType::Avoid => 2,
1016 SimpleType::WalkThrough => 3,
1017 }
1018 }
1019}
1020
1021impl From<u8> for SimpleType {
1022 fn from(id: u8) -> Self {
1023 match id {
1024 0 => SimpleType::Solid,
1025 1 => SimpleType::Water,
1026 2 => SimpleType::Avoid,
1027 3 => SimpleType::WalkThrough,
1028 _ => panic!("invalid id"),
1029 }
1030 }
1031}
1032
1033#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
1034#[repr(transparent)]
1035pub struct BlockKind(pub u32);
1036
1037impl From<u32> for BlockKind {
1038 fn from(id: u32) -> Self {
1039 Self(id)
1040 }
1041}
1042
1043impl BlockKind {
1044 pub const DEFAULT_SLIP: f64 = 0.6;
1045 pub const LADDER: BlockKind = BlockKind(65);
1046 pub const LEAVES: BlockKind = BlockKind(18);
1047 pub const FLOWING_WATER: BlockKind = BlockKind(8);
1048 pub const STONE: BlockKind = BlockKind(1);
1049 pub const DIRT: BlockKind = BlockKind(3);
1050 pub const GLASS: BlockKind = BlockKind(20);
1051
1052 #[inline]
1053 pub fn id(self) -> u32 {
1054 self.0
1055 }
1056
1057 pub fn hardness(&self, blocks: &BlockData) -> Option<f64> {
1058 let block = blocks
1059 .by_id(self.0)
1060 .unwrap_or_else(|| panic!("no block for id {}", self.0));
1061 block.hardness
1062 }
1063
1064 pub fn data<'a>(&self, blocks: &'a BlockData) -> &'a Block {
1065 blocks
1066 .by_id(self.0)
1067 .unwrap_or_else(|| panic!("no block for id {}", self.0))
1068 }
1069
1070 pub fn throw_away_block(self) -> bool {
1071 matches!(self.id(), 4)
1073 }
1074
1075 pub fn mineable(&self, blocks: &BlockData) -> bool {
1076 if self.0 == 0 {
1078 return false;
1079 }
1080
1081 match self.hardness(blocks) {
1082 None => false,
1083 Some(val) => val < 100.0,
1084 }
1085 }
1086
1087 pub fn slip(&self) -> f64 {
1088 match self.0 {
1089 266 => 0.989, 79 | 174 | 212 => 0.98, 37 => 0.8, _ => Self::DEFAULT_SLIP,
1093 }
1094 }
1095}
1096
1097#[derive(Copy, Clone, Eq, PartialEq, Hash, Default)]
1098#[repr(transparent)]
1099pub struct BlockState(pub u32);
1100
1101impl Debug for BlockState {
1102 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1103 f.write_fmt(format_args!("{}:{}", self.0 >> 4, self.0 % 16))
1104 }
1105}
1106
1107impl BlockState {
1108 pub const AIR: BlockState = BlockState(0);
1109 pub const WATER: BlockState = BlockState(9);
1110 pub const STONE: BlockState = BlockState(16);
1111
1112 pub fn from(id: u32, data: u16) -> BlockState {
1113 BlockState((id << 4) + data as u32)
1114 }
1115
1116 pub fn id(&self) -> u32 {
1117 self.0 >> 4
1118 }
1119
1120 pub fn kind(&self) -> BlockKind {
1121 BlockKind(self.id())
1122 }
1123
1124 pub fn simple_type(&self) -> SimpleType {
1125 if self.full_block() {
1126 return SimpleType::Solid;
1127 }
1128
1129 if self.is_water() {
1130 return SimpleType::Water;
1131 }
1132
1133 if self.walk_through() {
1134 return SimpleType::WalkThrough;
1135 }
1136
1137 SimpleType::Avoid
1138 }
1139
1140 pub fn metadata(&self) -> u8 {
1141 (self.0 & 0b1111) as u8
1142 }
1143
1144 pub fn full_block(&self) -> bool {
1145 matches!(self.id(),
1147 1..=5 |7 | 12..=25 | 29 | 33 |35 | 41 ..=43 | 45..=49 | 52 | 56..=58 | 60..=62 | 73 | 74 |
1148 78..=80| 82| 84|86|87|89|91|95|
1151 97| 98..=100|
1153 103|110|112|118|121|123..=125|
1155 129|133|137..=138|155|159|161|162|
1156 165| 166|
1158 168..=170| 172..=174|
1160 179|181|199..=202|
1161 204|206|208..=212|214..=255
1162
1163 )
1164 }
1165
1166 pub fn is_water(&self) -> bool {
1167 matches!(
1168 self.id(),
1169 8 | 9 | 65 )
1171 }
1172
1173 pub fn walk_through(&self) -> bool {
1174 self.is_water() || self.no_motion_effect()
1175 }
1176
1177 pub fn no_motion_effect(&self) -> bool {
1178 matches!(
1179 self.id(),
1180 0| 6|27|28| 31| 38|37|39|40| 50|59|66|68|69|70|72|75|76|77|83|
1189 90| 104|105|106|
1191 115|119|
1192 175..=177
1193 )
1194 }
1195}