1use std::str::FromStr;
7use std::{
8 fmt,
9 hash::Hash,
10 io::{Cursor, Write},
11 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, Sub},
12};
13
14use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
15
16use crate::direction::Direction;
17use crate::math;
18use crate::resource_location::ResourceLocation;
19
20macro_rules! vec3_impl {
21 ($name:ident, $type:ty) => {
22 impl $name {
23 #[inline]
24 pub const fn new(x: $type, y: $type, z: $type) -> Self {
25 Self { x, y, z }
26 }
27
28 #[inline]
31 pub fn length_squared(&self) -> $type {
32 self.x * self.x + self.y * self.y + self.z * self.z
33 }
34
35 #[inline]
38 pub fn distance_squared_to(&self, other: &Self) -> $type {
39 (self - other).length_squared()
40 }
41
42 #[inline]
43 pub fn horizontal_distance_squared(&self) -> $type {
44 self.x * self.x + self.z * self.z
45 }
46
47 #[inline]
48 pub fn horizontal_distance_squared_to(&self, other: &Self) -> $type {
49 (self - other).horizontal_distance_squared()
50 }
51
52 #[inline]
55 pub fn down(&self, y: $type) -> Self {
56 Self {
57 x: self.x,
58 y: self.y - y,
59 z: self.z,
60 }
61 }
62 #[inline]
65 pub fn up(&self, y: $type) -> Self {
66 Self {
67 x: self.x,
68 y: self.y + y,
69 z: self.z,
70 }
71 }
72
73 #[inline]
76 pub fn north(&self, z: $type) -> Self {
77 Self {
78 x: self.x,
79 y: self.y,
80 z: self.z - z,
81 }
82 }
83 #[inline]
86 pub fn east(&self, x: $type) -> Self {
87 Self {
88 x: self.x + x,
89 y: self.y,
90 z: self.z,
91 }
92 }
93 #[inline]
96 pub fn south(&self, z: $type) -> Self {
97 Self {
98 x: self.x,
99 y: self.y,
100 z: self.z + z,
101 }
102 }
103 #[inline]
106 pub fn west(&self, x: $type) -> Self {
107 Self {
108 x: self.x - x,
109 y: self.y,
110 z: self.z,
111 }
112 }
113
114 #[inline]
115 pub fn dot(&self, other: Self) -> $type {
116 self.x * other.x + self.y * other.y + self.z * other.z
117 }
118
119 #[inline]
121 pub fn xz(&self) -> Self {
122 Self {
123 x: self.x,
124 y: <$type>::default(),
125 z: self.z,
126 }
127 }
128
129 pub fn with_x(&self, x: $type) -> Self {
130 Self { x, ..*self }
131 }
132 pub fn with_y(&self, y: $type) -> Self {
133 Self { y, ..*self }
134 }
135 pub fn with_z(&self, z: $type) -> Self {
136 Self { z, ..*self }
137 }
138 }
139
140 impl Add for &$name {
141 type Output = $name;
142
143 #[inline]
144 fn add(self, rhs: Self) -> Self::Output {
145 $name {
146 x: self.x + rhs.x,
147 y: self.y + rhs.y,
148 z: self.z + rhs.z,
149 }
150 }
151 }
152 impl Add for $name {
153 type Output = $name;
154
155 #[inline]
156 fn add(self, rhs: Self) -> Self::Output {
157 (&self).add(&rhs)
158 }
159 }
160 impl Add<$type> for $name {
161 type Output = Self;
162
163 #[inline]
164 fn add(self, rhs: $type) -> Self::Output {
165 Self {
166 x: self.x + rhs,
167 y: self.y + rhs,
168 z: self.z + rhs,
169 }
170 }
171 }
172
173 impl AddAssign for $name {
174 #[inline]
175 fn add_assign(&mut self, rhs: Self) {
176 self.x += rhs.x;
177 self.y += rhs.y;
178 self.z += rhs.z;
179 }
180 }
181 impl Rem<$type> for $name {
182 type Output = Self;
183
184 #[inline]
185 fn rem(self, rhs: $type) -> Self::Output {
186 Self {
187 x: self.x % rhs,
188 y: self.y % rhs,
189 z: self.z % rhs,
190 }
191 }
192 }
193
194 impl Sub for &$name {
195 type Output = $name;
196
197 #[inline]
199 fn sub(self, other: Self) -> Self::Output {
200 Self::Output {
201 x: self.x - other.x,
202 y: self.y - other.y,
203 z: self.z - other.z,
204 }
205 }
206 }
207 impl Sub for $name {
208 type Output = Self;
209
210 #[inline]
211 fn sub(self, other: Self) -> Self::Output {
212 (&self).sub(&other)
213 }
214 }
215
216 impl Mul<$type> for $name {
217 type Output = Self;
218
219 #[inline]
220 fn mul(self, multiplier: $type) -> Self::Output {
221 Self {
222 x: self.x * multiplier,
223 y: self.y * multiplier,
224 z: self.z * multiplier,
225 }
226 }
227 }
228 impl MulAssign<$type> for $name {
229 #[inline]
230 fn mul_assign(&mut self, multiplier: $type) {
231 self.x *= multiplier;
232 self.y *= multiplier;
233 self.z *= multiplier;
234 }
235 }
236
237 impl Div<$type> for $name {
238 type Output = Self;
239
240 #[inline]
241 fn div(self, divisor: $type) -> Self::Output {
242 Self {
243 x: self.x / divisor,
244 y: self.y / divisor,
245 z: self.z / divisor,
246 }
247 }
248 }
249 impl DivAssign<$type> for $name {
250 #[inline]
251 fn div_assign(&mut self, divisor: $type) {
252 self.x /= divisor;
253 self.y /= divisor;
254 self.z /= divisor;
255 }
256 }
257
258 impl From<($type, $type, $type)> for $name {
259 #[inline]
260 fn from(pos: ($type, $type, $type)) -> Self {
261 Self::new(pos.0, pos.1, pos.2)
262 }
263 }
264 impl From<&($type, $type, $type)> for $name {
265 #[inline]
266 fn from(pos: &($type, $type, $type)) -> Self {
267 Self::new(pos.0, pos.1, pos.2)
268 }
269 }
270 impl From<$name> for ($type, $type, $type) {
271 #[inline]
272 fn from(pos: $name) -> Self {
273 (pos.x, pos.y, pos.z)
274 }
275 }
276 };
277}
278
279#[derive(Clone, Copy, Debug, Default, PartialEq, AzBuf)]
283#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
284pub struct Vec3 {
285 pub x: f64,
286 pub y: f64,
287 pub z: f64,
288}
289vec3_impl!(Vec3, f64);
290
291impl Vec3 {
292 pub const ZERO: Vec3 = Vec3::new(0.0, 0.0, 0.0);
293
294 pub fn length(&self) -> f64 {
297 f64::sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
298 }
299
300 pub fn distance_to(&self, other: &Self) -> f64 {
303 (self - other).length()
304 }
305
306 pub fn x_rot(self, radians: f32) -> Vec3 {
307 let x_delta = math::cos(radians);
308 let y_delta = math::sin(radians);
309 let x = self.x;
310 let y = self.y * (x_delta as f64) + self.z * (y_delta as f64);
311 let z = self.z * (x_delta as f64) - self.y * (y_delta as f64);
312 Vec3 { x, y, z }
313 }
314 pub fn y_rot(self, radians: f32) -> Vec3 {
315 let x_delta = math::cos(radians);
316 let y_delta = math::sin(radians);
317 let x = self.x * (x_delta as f64) + self.z * (y_delta as f64);
318 let y = self.y;
319 let z = self.z * (x_delta as f64) - self.x * (y_delta as f64);
320 Vec3 { x, y, z }
321 }
322
323 pub fn to_block_pos_floor(&self) -> BlockPos {
324 BlockPos {
325 x: self.x.floor() as i32,
326 y: self.y.floor() as i32,
327 z: self.z.floor() as i32,
328 }
329 }
330 pub fn to_block_pos_ceil(&self) -> BlockPos {
331 BlockPos {
332 x: self.x.ceil() as i32,
333 y: self.y.ceil() as i32,
334 z: self.z.ceil() as i32,
335 }
336 }
337}
338
339#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
342#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
343pub struct BlockPos {
344 pub x: i32,
345 pub y: i32,
346 pub z: i32,
347}
348vec3_impl!(BlockPos, i32);
349
350impl BlockPos {
351 pub fn center(&self) -> Vec3 {
354 Vec3 {
355 x: self.x as f64 + 0.5,
356 y: self.y as f64 + 0.5,
357 z: self.z as f64 + 0.5,
358 }
359 }
360
361 pub fn to_vec3_floored(&self) -> Vec3 {
363 Vec3 {
364 x: self.x as f64,
365 y: self.y as f64,
366 z: self.z as f64,
367 }
368 }
369
370 pub fn length_manhattan(&self) -> u32 {
372 (self.x.abs() + self.y.abs() + self.z.abs()) as u32
373 }
374
375 pub fn min(&self, other: &Self) -> Self {
388 Self {
389 x: self.x.min(other.x),
390 y: self.y.min(other.y),
391 z: self.z.min(other.z),
392 }
393 }
394
395 pub fn max(&self, other: &Self) -> Self {
408 Self {
409 x: self.x.max(other.x),
410 y: self.y.max(other.y),
411 z: self.z.max(other.z),
412 }
413 }
414
415 pub fn offset_with_direction(self, direction: Direction) -> Self {
416 self + direction.normal()
417 }
418}
419
420#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, AzBuf)]
423pub struct Vec3i {
424 #[var]
425 pub x: i32,
426 #[var]
427 pub y: i32,
428 #[var]
429 pub z: i32,
430}
431
432#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
435pub struct ChunkPos {
436 pub x: i32,
437 pub z: i32,
438}
439impl ChunkPos {
440 pub fn new(x: i32, z: i32) -> Self {
441 ChunkPos { x, z }
442 }
443}
444impl Add<ChunkPos> for ChunkPos {
445 type Output = Self;
446
447 fn add(self, rhs: Self) -> Self::Output {
448 Self {
449 x: self.x + rhs.x,
450 z: self.z + rhs.z,
451 }
452 }
453}
454
455impl From<ChunkPos> for u64 {
459 #[inline]
460 fn from(pos: ChunkPos) -> Self {
461 (pos.x as u64) | ((pos.z as u64) << 32)
462 }
463}
464impl From<u64> for ChunkPos {
465 #[inline]
466 fn from(pos: u64) -> Self {
467 ChunkPos {
468 x: (pos) as i32,
469 z: (pos >> 32) as i32,
470 }
471 }
472}
473impl AzaleaRead for ChunkPos {
474 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
475 let long = u64::azalea_read(buf)?;
476 Ok(ChunkPos::from(long))
477 }
478}
479impl AzaleaWrite for ChunkPos {
480 fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
481 u64::from(*self).azalea_write(buf)?;
482 Ok(())
483 }
484}
485
486impl Hash for ChunkPos {
487 #[inline]
488 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
489 u64::from(*self).hash(state);
491 }
492}
493impl nohash_hasher::IsEnabled for ChunkPos {}
496
497#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
499pub struct ChunkSectionPos {
500 pub x: i32,
501 pub y: i32,
502 pub z: i32,
503}
504vec3_impl!(ChunkSectionPos, i32);
505
506impl ChunkSectionPos {
507 pub fn block_to_section_coord(block: i32) -> i32 {
508 block >> 4
509 }
510}
511
512#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
514pub struct ChunkBlockPos {
515 pub x: u8,
516 pub y: i32,
517 pub z: u8,
518}
519
520impl ChunkBlockPos {
521 pub fn new(x: u8, y: i32, z: u8) -> Self {
522 ChunkBlockPos { x, y, z }
523 }
524}
525
526impl Hash for ChunkBlockPos {
527 #[inline]
529 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
530 u64::from(*self).hash(state);
531 }
532}
533impl From<ChunkBlockPos> for u64 {
534 #[inline]
535 fn from(pos: ChunkBlockPos) -> Self {
536 let mut val: u64 = 0;
538 val |= pos.y as u64;
540 val |= (pos.z as u64) << 32;
542 val |= (pos.x as u64) << 40;
544 val
545 }
546}
547impl nohash_hasher::IsEnabled for ChunkBlockPos {}
548
549#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
552pub struct ChunkSectionBlockPos {
553 pub x: u8,
554 pub y: u8,
555 pub z: u8,
556}
557vec3_impl!(ChunkSectionBlockPos, u8);
558
559impl Add<ChunkSectionBlockPos> for ChunkSectionPos {
560 type Output = BlockPos;
561
562 fn add(self, rhs: ChunkSectionBlockPos) -> Self::Output {
563 BlockPos::new(
564 self.x * 16 + rhs.x as i32,
565 self.y * 16 + rhs.y as i32,
566 self.z * 16 + rhs.z as i32,
567 )
568 }
569}
570impl Hash for ChunkSectionBlockPos {
571 #[inline]
573 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
574 u16::from(*self).hash(state);
575 }
576}
577
578impl From<ChunkSectionBlockPos> for u16 {
579 #[inline]
580 fn from(pos: ChunkSectionBlockPos) -> Self {
581 ((((pos.y as u16) << 4) | pos.z as u16) << 4) | pos.x as u16
583 }
584}
585impl nohash_hasher::IsEnabled for ChunkSectionBlockPos {}
586
587#[derive(Debug, Clone, PartialEq)]
589pub struct GlobalPos {
590 pub world: ResourceLocation,
592 pub pos: BlockPos,
593}
594
595impl From<&BlockPos> for ChunkPos {
596 #[inline]
597 fn from(pos: &BlockPos) -> Self {
598 ChunkPos {
599 x: pos.x >> 4,
600 z: pos.z >> 4,
601 }
602 }
603}
604impl From<BlockPos> for ChunkPos {
605 #[inline]
606 fn from(pos: BlockPos) -> Self {
607 ChunkPos {
608 x: pos.x >> 4,
609 z: pos.z >> 4,
610 }
611 }
612}
613
614impl From<BlockPos> for ChunkSectionPos {
615 #[inline]
616 fn from(pos: BlockPos) -> Self {
617 ChunkSectionPos {
618 x: pos.x >> 4,
619 y: pos.y >> 4,
620 z: pos.z >> 4,
621 }
622 }
623}
624impl From<&BlockPos> for ChunkSectionPos {
625 #[inline]
626 fn from(pos: &BlockPos) -> Self {
627 ChunkSectionPos {
628 x: pos.x >> 4,
629 y: pos.y >> 4,
630 z: pos.z >> 4,
631 }
632 }
633}
634
635impl From<ChunkSectionPos> for ChunkPos {
636 fn from(pos: ChunkSectionPos) -> Self {
637 ChunkPos { x: pos.x, z: pos.z }
638 }
639}
640impl From<&Vec3> for ChunkSectionPos {
641 fn from(pos: &Vec3) -> Self {
642 ChunkSectionPos::from(&BlockPos::from(pos))
643 }
644}
645impl From<Vec3> for ChunkSectionPos {
646 fn from(pos: Vec3) -> Self {
647 ChunkSectionPos::from(&pos)
648 }
649}
650
651impl From<&BlockPos> for ChunkBlockPos {
652 #[inline]
653 fn from(pos: &BlockPos) -> Self {
654 ChunkBlockPos {
655 x: (pos.x & 0xF) as u8,
656 y: pos.y,
657 z: (pos.z & 0xF) as u8,
658 }
659 }
660}
661impl From<BlockPos> for ChunkBlockPos {
662 #[inline]
663 fn from(pos: BlockPos) -> Self {
664 ChunkBlockPos {
665 x: (pos.x & 0xF) as u8,
666 y: pos.y,
667 z: (pos.z & 0xF) as u8,
668 }
669 }
670}
671
672impl From<BlockPos> for ChunkSectionBlockPos {
673 #[inline]
674 fn from(pos: BlockPos) -> Self {
675 ChunkSectionBlockPos {
676 x: (pos.x & 0xF) as u8,
677 y: (pos.y & 0xF) as u8,
678 z: (pos.z & 0xF) as u8,
679 }
680 }
681}
682
683impl From<&ChunkBlockPos> for ChunkSectionBlockPos {
684 #[inline]
685 fn from(pos: &ChunkBlockPos) -> Self {
686 ChunkSectionBlockPos {
687 x: pos.x,
688 y: (pos.y & 0xF) as u8,
689 z: pos.z,
690 }
691 }
692}
693impl From<&Vec3> for BlockPos {
694 #[inline]
695 fn from(pos: &Vec3) -> Self {
696 BlockPos {
697 x: pos.x.floor() as i32,
698 y: pos.y.floor() as i32,
699 z: pos.z.floor() as i32,
700 }
701 }
702}
703impl From<Vec3> for BlockPos {
704 #[inline]
705 fn from(pos: Vec3) -> Self {
706 BlockPos::from(&pos)
707 }
708}
709
710impl From<&Vec3> for ChunkPos {
711 fn from(pos: &Vec3) -> Self {
712 ChunkPos::from(&BlockPos::from(pos))
713 }
714}
715impl From<Vec3> for ChunkPos {
716 fn from(pos: Vec3) -> Self {
717 ChunkPos::from(&pos)
718 }
719}
720
721impl From<&Vec3> for ChunkBlockPos {
722 fn from(pos: &Vec3) -> Self {
723 ChunkBlockPos::from(&BlockPos::from(pos))
724 }
725}
726impl From<Vec3> for ChunkBlockPos {
727 fn from(pos: Vec3) -> Self {
728 ChunkBlockPos::from(&pos)
729 }
730}
731
732impl fmt::Display for BlockPos {
733 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
735 write!(f, "{} {} {}", self.x, self.y, self.z)
736 }
737}
738impl fmt::Display for Vec3 {
739 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
741 write!(f, "{} {} {}", self.x, self.y, self.z)
742 }
743}
744
745const PACKED_X_LENGTH: u64 = 1 + 25; const PACKED_Z_LENGTH: u64 = PACKED_X_LENGTH;
747const PACKED_Y_LENGTH: u64 = 64 - PACKED_X_LENGTH - PACKED_Z_LENGTH;
748const PACKED_X_MASK: u64 = (1 << PACKED_X_LENGTH) - 1;
749const PACKED_Y_MASK: u64 = (1 << PACKED_Y_LENGTH) - 1;
750const PACKED_Z_MASK: u64 = (1 << PACKED_Z_LENGTH) - 1;
751const Z_OFFSET: u64 = PACKED_Y_LENGTH;
752const X_OFFSET: u64 = PACKED_Y_LENGTH + PACKED_Z_LENGTH;
753
754impl AzaleaRead for BlockPos {
755 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
756 let val = i64::azalea_read(buf)?;
757 let x = (val << (64 - X_OFFSET - PACKED_X_LENGTH) >> (64 - PACKED_X_LENGTH)) as i32;
758 let y = (val << (64 - PACKED_Y_LENGTH) >> (64 - PACKED_Y_LENGTH)) as i32;
759 let z = (val << (64 - Z_OFFSET - PACKED_Z_LENGTH) >> (64 - PACKED_Z_LENGTH)) as i32;
760 Ok(BlockPos { x, y, z })
761 }
762}
763
764impl AzaleaRead for GlobalPos {
765 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
766 Ok(GlobalPos {
767 world: ResourceLocation::azalea_read(buf)?,
768 pos: BlockPos::azalea_read(buf)?,
769 })
770 }
771}
772
773impl AzaleaRead for ChunkSectionPos {
774 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
775 let long = i64::azalea_read(buf)?;
776 Ok(ChunkSectionPos {
777 x: (long >> 42) as i32,
778 y: (long << 44 >> 44) as i32,
779 z: (long << 22 >> 42) as i32,
780 })
781 }
782}
783
784impl AzaleaWrite for BlockPos {
785 fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
786 let mut val: u64 = 0;
787 val |= ((self.x as u64) & PACKED_X_MASK) << X_OFFSET;
788 val |= (self.y as u64) & PACKED_Y_MASK;
789 val |= ((self.z as u64) & PACKED_Z_MASK) << Z_OFFSET;
790 val.azalea_write(buf)
791 }
792}
793
794impl AzaleaWrite for GlobalPos {
795 fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
796 ResourceLocation::azalea_write(&self.world, buf)?;
797 BlockPos::azalea_write(&self.pos, buf)?;
798
799 Ok(())
800 }
801}
802
803impl AzaleaWrite for ChunkSectionPos {
804 fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
805 let long = (((self.x & 0x3FFFFF) as i64) << 42)
806 | (self.y & 0xFFFFF) as i64
807 | (((self.z & 0x3FFFFF) as i64) << 20);
808 long.azalea_write(buf)?;
809 Ok(())
810 }
811}
812
813fn parse_three_values<T>(s: &str) -> Result<[T; 3], &'static str>
814where
815 T: FromStr,
816 <T as FromStr>::Err: fmt::Debug,
817{
818 let parts = s.split_whitespace().collect::<Vec<_>>();
819 if parts.len() != 3 {
820 return Err("Expected three values");
821 }
822
823 let x = parts[0].parse().map_err(|_| "Invalid X value")?;
824 let y = parts[1].parse().map_err(|_| "Invalid Y value")?;
825 let z = parts[2].parse().map_err(|_| "Invalid Z value")?;
826
827 Ok([x, y, z])
828}
829
830impl FromStr for BlockPos {
836 type Err = &'static str;
837
838 fn from_str(s: &str) -> Result<Self, Self::Err> {
839 let [x, y, z] = parse_three_values::<i32>(s)?;
840 Ok(BlockPos { x, y, z })
841 }
842}
843
844impl FromStr for Vec3 {
850 type Err = &'static str;
851
852 fn from_str(s: &str) -> Result<Self, Self::Err> {
853 let [x, y, z] = parse_three_values::<f64>(s)?;
854 Ok(Vec3 { x, y, z })
855 }
856}
857
858#[cfg(test)]
859mod tests {
860 use super::*;
861
862 #[test]
863 fn test_from_block_pos_to_chunk_pos() {
864 let block_pos = BlockPos::new(5, 78, -2);
865 let chunk_pos = ChunkPos::from(&block_pos);
866 assert_eq!(chunk_pos, ChunkPos::new(0, -1));
867 }
868
869 #[test]
870 fn test_from_block_pos_to_chunk_block_pos() {
871 let block_pos = BlockPos::new(5, 78, -2);
872 let chunk_block_pos = ChunkBlockPos::from(&block_pos);
873 assert_eq!(chunk_block_pos, ChunkBlockPos::new(5, 78, 14));
874 }
875
876 #[test]
877 fn test_from_entity_pos_to_block_pos() {
878 let entity_pos = Vec3 {
879 x: 31.5,
880 y: 80.0,
881 z: -16.1,
882 };
883 let block_pos = BlockPos::from(&entity_pos);
884 assert_eq!(block_pos, BlockPos::new(31, 80, -17));
885 }
886
887 #[test]
888 fn test_from_entity_pos_to_chunk_pos() {
889 let entity_pos = Vec3 {
890 x: 31.5,
891 y: 80.0,
892 z: -16.1,
893 };
894 let chunk_pos = ChunkPos::from(&entity_pos);
895 assert_eq!(chunk_pos, ChunkPos::new(1, -2));
896 }
897
898 #[test]
899 fn test_read_blockpos_from() {
900 let mut buf = Vec::new();
901 13743895338965u64.azalea_write(&mut buf).unwrap();
902 let mut buf = Cursor::new(&buf[..]);
903 let block_pos = BlockPos::azalea_read(&mut buf).unwrap();
904 assert_eq!(block_pos, BlockPos::new(49, -43, -3));
905 }
906
907 #[test]
908 fn test_into_chunk_section_block_pos() {
909 let block_pos = BlockPos::new(0, -60, 0);
910 assert_eq!(
911 ChunkSectionBlockPos::from(block_pos),
912 ChunkSectionBlockPos::new(0, 4, 0)
913 );
914 }
915
916 #[test]
917 fn test_read_chunk_pos_from() {
918 let mut buf = Vec::new();
919 ChunkPos::new(2, -1).azalea_write(&mut buf).unwrap();
920 let mut buf = Cursor::new(&buf[..]);
921 let chunk_pos = ChunkPos::from(u64::azalea_read(&mut buf).unwrap());
922 assert_eq!(chunk_pos, ChunkPos::new(2, -1));
923 }
924}