1use std::collections::HashMap;
74use std::ops::CoroutineState::*;
75use std::ops::{Coroutine, Index, IndexMut};
76use std::pin::Pin;
77use thiserror::Error;
78
79use crate::block::content::Type as BlockEnum;
80use crate::block::{Block, Rotation, State};
81use crate::data::dynamic::DynData;
82use crate::data::renderer::*;
83use crate::data::DataRead;
84use crate::fluid::Type as Fluid;
85use crate::item::{storage::Storage, Type as Item};
86use crate::team::Team;
87use crate::unit::Unit;
88#[cfg(doc)]
89use crate::{block::content, data::*, fluid, item, modifier, unit};
90
91use super::{entity_mapping, Serializable};
92use crate::content::Content;
93
94#[derive(Clone)]
96pub struct Tile {
97 pub floor: BlockEnum,
98 pub ore: BlockEnum,
99 build: Option<Build>,
100}
101
102macro_rules! lo {
103 ($v:expr => [$(|)? $($k:literal $(|)?)+], $scale: ident) => { paste::paste! {
104 match $v {
105 $(BlockEnum::[<$k:camel>] => load!(raw $k, $scale),)+
106 n => unreachable!("{n:?}"),
107 }
108 } };
109}
110
111#[inline]
112pub(crate) fn ore(ore: BlockEnum, s: Scale) -> Image<&'static [u8], 4> {
113 lo!(ore => ["ore-copper" | "ore-beryllium" | "ore-lead" | "ore-scrap" | "ore-coal" | "ore-thorium" | "ore-titanium" | "ore-tungsten" | "pebbles" | "tendrils" | "ore-wall-tungsten" | "ore-wall-beryllium" | "ore-wall-thorium" | "spawn" | "ore-crystal-thorium"], s)
114}
115
116#[inline]
117pub(crate) fn floor(tile: BlockEnum, s: Scale) -> Image<&'static [u8], 3> {
118 lo!(tile => [
119 | "darksand"
120 | "sand-floor"
121 | "dacite"
122 | "dirt"
123 | "arkycite-floor"
124 | "basalt"
125 | "moss"
126 | "mud"
127 | "grass"
128 | "ice-snow" | "snow" | "salt" | "ice"
129 | "hotrock" | "char" | "magmarock"
130 | "shale"
131 | "metal-floor" | "metal-floor-2" | "metal-floor-3" | "metal-floor-4" | "metal-floor-5" | "metal-floor-damaged"
132 | "dark-panel-1" | "dark-panel-2" | "dark-panel-3" | "dark-panel-4" | "dark-panel-5" | "dark-panel-6"
133 | "darksand-tainted-water" | "darksand-water" | "deep-tainted-water" | "deep-water" | "sand-water" | "shallow-water" | "tainted-water"
134 | "tar" | "pooled-cryofluid" | "molten-slag"
135 | "space"
136 | "stone"
137 | "bluemat"
138 | "ferric-craters"
139 | "beryllic-stone"
140 | "rhyolite" | "rough-rhyolite" | "rhyolite-crater" | "rhyolite-vent"
141 | "core-zone"
142 | "crater-stone"
143 | "redmat"
144 | "red-ice"
145 | "spore-moss"
146 | "regolith"
147 | "ferric-stone"
148 | "arkyic-stone" | "arkyic-vent"
149 | "yellow-stone" | "yellow-stone-plates" | "yellow-stone-vent"
150 | "red-stone" | "red-stone-vent" | "dense-red-stone"
151 | "carbon-stone" | "carbon-vent"
152 | "crystal-floor" | "crystalline-stone" | "crystalline-vent"
153 | "empty"], s)
154}
155
156impl Tile {
157 #[must_use]
158 pub const fn new(floor: BlockEnum, ore: BlockEnum) -> Self {
159 Self {
160 floor,
161 ore,
162 build: None,
163 }
164 }
165
166 fn set_block(&mut self, block: &'static Block) {
167 self.build = Some(Build {
168 block,
169 state: None,
170 items: Storage::new(),
171 liquids: Storage::new(),
172 rotation: Rotation::Up,
173 team: Team::SHARDED,
174 data: 0,
175 });
176 }
177
178 #[must_use]
179 pub const fn build(&self) -> Option<&Build> {
180 self.build.as_ref()
181 }
182
183 #[must_use]
189 #[inline]
190 pub fn size(&self) -> u8 {
191 self.build.as_ref().map_or(1, |v| v.block.get_size())
192 }
193
194 #[inline]
195 pub(crate) fn floor(&self, s: Scale) -> Image<&'static [u8], 3> {
196 floor(self.floor, s)
197 }
198
199 #[must_use]
200 #[inline]
201 pub(crate) fn ore(&self, s: Scale) -> Image<&'static [u8], 4> {
202 ore(self.ore, s)
203 }
204
205 #[must_use]
206 #[inline]
207 pub fn has_ore(&self) -> bool {
208 self.ore != BlockEnum::Air
209 }
210
211 #[must_use]
213 pub fn floor_image(&self, s: Scale) -> ImageHolder<3> {
214 let mut floor = ImageHolder::from(self.floor(s));
215 if self.has_ore() {
216 unsafe { floor.overlay(&self.ore(s)) };
217 }
218 floor
219 }
220
221 #[must_use]
223 #[inline]
224 pub fn build_image(&self, context: Option<&RenderingContext>, s: Scale) -> ImageHolder<4> {
225 let Some(b) = &self.build else {
227 unreachable!();
228 };
229 b.image(context, s)
230 }
231}
232
233impl std::fmt::Debug for Tile {
234 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
235 write!(
236 f,
237 "Tile@{}{}{}",
238 self.floor.get_name(),
239 if self.ore != BlockEnum::Air {
240 format!("+{}", self.ore.get_name())
241 } else {
242 String::new()
243 },
244 if let Some(build) = &self.build {
245 format!(":{}", build.block.name())
246 } else {
247 String::new()
248 }
249 )
250 }
251}
252
253impl BlockState for Tile {
254 fn get_block(&self) -> Option<&'static Block> {
255 Some(self.build()?.block)
256 }
257}
258
259impl RotationState for Tile {
260 fn get_rotation(&self) -> Option<Rotation> {
261 Some(self.build()?.rotation)
262 }
263}
264
265impl RotationState for Option<Tile> {
266 fn get_rotation(&self) -> Option<Rotation> {
267 self.as_ref().unwrap().get_rotation()
268 }
269}
270
271impl BlockState for Option<Tile> {
272 fn get_block(&self) -> Option<&'static Block> {
273 self.as_ref().unwrap().get_block()
274 }
275}
276
277#[derive(Clone)]
279pub struct Build {
280 pub block: &'static Block,
281 pub items: Storage<Item>,
282 pub liquids: Storage<Fluid>,
283 pub state: Option<State>,
284 pub rotation: Rotation,
286 pub team: Team,
287 pub data: i8,
288}
289
290impl std::fmt::Debug for Build {
291 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292 write!(f, "Build<{block}>", block = self.block.name(),)
293 }
294}
295
296impl Build {
297 #[must_use]
298 pub fn new(block: &'static Block) -> Build {
299 Self {
300 block,
301 items: Storage::default(),
302 liquids: Storage::default(),
303 state: None,
304 rotation: Rotation::Up,
305 team: Team::SHARDED,
306 data: 0,
307 }
308 }
309
310 fn image(&self, context: Option<&RenderingContext>, s: Scale) -> ImageHolder<4> {
311 self.block
312 .image(self.state.as_ref(), context, self.rotation, s)
313 }
314
315 #[must_use]
316 pub const fn name(&self) -> &str {
317 self.block.name()
318 }
319
320 pub fn read(&mut self, buff: &mut DataRead<'_>) -> Result<(), ReadError> {
321 let _ = buff.read_f32()?;
323 let rot = buff.read_i8()? as i16;
324 let _ = buff.read_i8()?;
326 self.rotation = Rotation::try_from((rot & 127) as u8).unwrap_or(Rotation::Up);
327 let mut mask = 0;
328 let mut version = 0;
329 if rot & 128 != 0 {
330 version = buff.read_u8()?;
331 if version < 3 {
332 return Err(ReadError::Version(version));
333 }
334 buff.skip(1)?;
335 mask = buff.read_u8()?;
336 }
337
338 if mask & 1 != 0 {
339 read_items(buff, &mut self.items)?;
340 }
341 if mask & 2 != 0 {
342 read_power(buff)?;
343 }
344 if mask & 4 != 0 {
345 read_liquids(buff, &mut self.liquids)?;
346 }
347 _ = buff.read_u8()? as f64 / 255.;
349 _ = buff.read_u8()? as f64 / 255.;
350
351 if version == 4 {
352 _ = buff.read_u64()?;
354 }
355 self.block.read(self, buff)?;
357
358 Ok(())
359 }
360}
361
362fn read_items(from: &mut DataRead, to: &mut Storage<Item>) -> Result<(), ReadError> {
368 to.clear();
369 let n = from.read_u16()?;
370 to.reserve(n as usize);
371 for _ in 0..n {
372 let item = from.read_u16()?;
373 let amount = from.read_u32()?;
374 if let Ok(item) = Item::try_from(item) {
375 to.set(item, amount);
376 }
377 }
378 Ok(())
379}
380
381fn read_liquids(from: &mut DataRead, to: &mut Storage<Fluid>) -> Result<(), ReadError> {
386 to.clear();
387 let n = from.read_u16()?;
388 to.reserve(n as usize);
389 for _ in 0..n {
390 let fluid = from.read_u16()?;
391 let amount = from.read_f32()?;
392 if let Ok(fluid) = Fluid::try_from(fluid) {
393 to.set(fluid, (amount * 100.0) as u32);
394 }
395 }
396 Ok(())
397}
398
399fn read_power(from: &mut DataRead) -> Result<(), ReadError> {
404 let n = from.read_u16()? as usize;
405 from.skip((n + 1) * 4)?;
406 Ok(())
407}
408
409#[test]
410fn test_read_items() {
411 let mut s = Storage::new();
412 read_items(
413 &mut DataRead::new(&[
414 0, 6, 0, 0, 0, 0, 2, 187, 0, 1, 0, 0, 1, 154, 0, 2, 0, 0, 15, 160, 0, 3, 0, 0, 0, 235,
415 0, 6, 0, 0, 1, 46, 0, 12, 0, 0, 1, 81, 255, 255,
416 ]),
417 &mut s,
418 )
419 .unwrap();
420 assert!(s.get_total() == 5983);
421}
422
423#[test]
424fn test_read_liquids() {
425 let mut s = Storage::new();
426 read_liquids(
427 &mut DataRead::new(&[0, 1, 0, 0, 67, 111, 247, 126, 255, 255]),
428 &mut s,
429 )
430 .unwrap();
431 assert!(s.get(Fluid::Water) == 23996);
432}
433
434#[derive(Debug)]
437pub struct Map {
438 pub width: usize,
439 pub height: usize,
440 pub tags: HashMap<String, String>,
441 pub entities: Vec<Unit>,
442 pub tiles: Vec<Tile>,
449}
450
451macro_rules! cond {
452 ($cond: expr, $do: expr) => {
453 if $cond {
454 None
455 } else {
456 $do
457 }
458 };
459}
460
461impl Crossable for Map {
462 fn cross(&self, j: usize, c: &PositionContext) -> Cross {
463 let get = |i| {
464 let b = &self[i];
465 Some((b.get_block()?, b.get_rotation()?))
466 };
467 [
468 cond![
469 c.position.1 == 0 || c.position.1 >= c.height,
470 get(j + self.height)
471 ],
472 cond![c.position.0 >= (c.height - 1), get(j + 1)],
473 cond![c.position.1 >= (c.height - 1), get(j - self.width)],
474 cond![j < c.height, get(j - 1)],
475 ]
476 }
477}
478
479impl Map {
480 #[must_use]
481 pub fn new(width: usize, height: usize, tags: HashMap<String, String>) -> Self {
482 Self {
483 tiles: Vec::with_capacity(width * height),
484 height,
485 width,
486 tags,
487 entities: vec![],
488 }
489 }
490
491 fn push(&mut self, t: Tile) {
492 self.tiles.push(t);
493 }
494}
495
496impl Index<usize> for Map {
497 type Output = Tile;
498 fn index(&self, index: usize) -> &Self::Output {
499 &self.tiles[index]
500 }
501}
502
503impl IndexMut<usize> for Map {
504 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
505 &mut self.tiles[index]
506 }
507}
508
509const MAP_HEADER: [u8; 4] = [b'M', b'S', b'A', b'V'];
510
511#[derive(Debug, Error)]
513pub enum ReadError {
514 #[error("failed to read from buffer")]
515 Read(#[from] super::ReadError),
516 #[error(transparent)]
517 Decompress(#[from] super::DecompressError),
518 #[error("incorrect header ({0:?})")]
519 Header([u8; 4]),
520 #[error("unsupported version ({0})")]
521 Version(u8),
522 #[error("unknown block {0:?}")]
523 NoSuchBlock(String),
524 #[error("failed to read block data")]
525 ReadState(#[from] super::dynamic::ReadError),
526}
527
528pub struct MapReader {
530 #[allow(dead_code)]
531 backing: Vec<u8>,
532 buff: DataRead<'static>,
534}
535
536#[derive(Debug)]
537pub enum ThinBloc {
538 None(u8),
539 Build(Rotation, &'static Block, Team),
540 Many(&'static Block, u8),
541}
542
543#[derive(Debug)]
544pub enum ThinMapData {
545 Init { width: u16, height: u16 },
546 Bloc(ThinBloc),
547 Tile { floor: BlockEnum, ore: BlockEnum },
548}
549
550#[derive(Debug)]
551pub enum Bloc {
552 None(u8),
553 Build(Build, &'static Block),
554 Data(&'static Block, i8),
555 Many(&'static Block, u8),
556}
557
558#[derive(Debug)]
559pub enum MapData {
560 Init { width: u16, height: u16 },
561 Bloc(Bloc),
562 Tile { floor: BlockEnum, ore: BlockEnum },
563}
564
565#[derive(Debug)]
566pub enum EntityData {
567 Length(u32),
568 Data(Unit),
569}
570
571macro_rules! tiles {
572 ($count:ident, $me:ident, $w: ident) => {
573 let mut i = 0;
574 while i < $count {
575 let floor_id = $me.buff.read_u16()?;
576 let overlay_id = $me.buff.read_u16()?;
577 let floor = BlockEnum::try_from(floor_id).unwrap_or(BlockEnum::Stone);
578 let ore = BlockEnum::try_from(overlay_id).unwrap_or(BlockEnum::Air);
579 yield $w::Tile { floor, ore };
580 let consecutives = $me.buff.read_u8()? as usize;
581 for _ in 0..consecutives {
582 yield $w::Tile { floor, ore };
583 }
584 i += consecutives;
585 i += 1;
586 }
587 };
588}
589
590impl MapReader {
591 pub fn new(buff: &mut DataRead<'_>) -> Result<Self, ReadError> {
592 let backing = buff.deflate()?;
593 Ok(Self {
594 buff: DataRead::new(unsafe {
595 std::mem::transmute::<&'_ [u8], &'static [u8]>(&backing)
596 }),
597 backing,
598 })
599 }
600
601 pub fn header(&mut self) -> Result<[u8; 4], ReadError> {
602 let b = self.buff.readN::<4>()?;
603 (b == MAP_HEADER).then_some(b).ok_or(ReadError::Header(b))
604 }
605
606 pub fn version(&mut self) -> Result<u32, ReadError> {
607 let x = self.buff.read_u32()?;
609 (x == 7)
610 .then_some(x)
611 .ok_or(ReadError::Version(x.try_into().unwrap_or(0)))
612 }
613
614 pub fn tags(&mut self) -> Result<HashMap<&str, &str>, ReadError> {
615 let mut tags = HashMap::new();
616 self.buff.skip(5)?;
617 for _ in 0..self.buff.read_u8()? {
618 let key = self.buff.read_utf()?;
619 let value = self.buff.read_utf()?;
620 tags.insert(key, value);
621 }
622 Ok(tags)
623 }
624
625 pub fn tags_alloc(&mut self) -> Result<HashMap<String, String>, ReadError> {
626 let mut tags = HashMap::new();
627 self.buff
628 .read_chunk(true, |buff| {
629 buff.skip(1)?;
630 for _ in 0..buff.read_u8()? {
631 let key = buff.read_utf()?;
632 let value = buff.read_utf()?;
633 tags.insert(key.to_owned(), value.to_owned());
634 }
635 Ok::<(), ReadError>(())
636 })
637 .map(|_| tags)
638 }
639
640 pub fn skip(&mut self) -> Result<(), ReadError> {
641 let len = self.buff.read_u32()? as usize;
642 self.buff.skip(len)?;
643 Ok(())
644 }
645
646 pub fn thin_map(
647 &mut self,
648 ) -> Result<
649 impl Coroutine<(), Return = Result<(), ReadError>, Yield = ThinMapData> + '_,
650 ReadError,
651 > {
652 let len = self.buff.read_u32()? as usize;
653 let rb4 = self.buff.read;
654 let map = #[coroutine]
655 move || {
656 let w = self.buff.read_u16()?;
657 let h = self.buff.read_u16()?;
658 yield ThinMapData::Init {
659 width: w,
660 height: h,
661 };
662 let w = w as usize;
663 let h = h as usize;
664 let count = w * h;
665 tiles!(count, self, ThinMapData);
666
667 let mut i = 0;
668 while i < count {
669 let block_id = self.buff.read_u16()?;
670 let packed = self.buff.read_u8()?;
671 let entity = (packed & 1) != 0;
672 let data = (packed & 2) != 0;
673 let central = if entity {
674 self.buff.read_bool()?
675 } else {
676 false
677 };
678 let block = BlockEnum::try_from(block_id)
679 .map_err(|_| ReadError::NoSuchBlock(block_id.to_string()))?;
680 let block = block.to_block();
681 let Some(block) = block else {
682 let consecutives = self.buff.read_u8()?;
683 yield ThinMapData::Bloc(ThinBloc::None(consecutives));
684 i += consecutives as usize;
685 i += 1;
686 continue;
687 };
688 yield if entity {
689 if central {
690 let len = self.buff.read_u16()? as usize;
691 let rb4 = self.buff.read;
692
693 #[cfg(debug_assertions)]
694 println!("reading {block:?} ");
695 let _ = self.buff.read_i8()?;
696 let _ = self.buff.read_f32()?;
697 let rot = self.buff.read_i8()?;
698 let rot = Rotation::try_from((rot & 127) as u8).unwrap_or(Rotation::Up);
699 let team = Team::of(self.buff.read_u8()?);
700 let read = self.buff.read - rb4;
701 let n = len - read;
702 self.buff.skip(n)?;
703
704 ThinMapData::Bloc(ThinBloc::Build(rot, block, team))
705 } else {
706 ThinMapData::Bloc(ThinBloc::None(0))
707 }
708 } else if data {
709 _ = self.buff.read_i8()?;
710 ThinMapData::Bloc(ThinBloc::Many(block, 0))
711 } else {
712 let consecutives = self.buff.read_u8()?;
713 i += consecutives as usize;
714 ThinMapData::Bloc(ThinBloc::Many(block, consecutives))
715 };
716
717 i += 1;
718 }
719 let read = self.buff.read - rb4;
720 debug_assert!(len >= read, "overread; supposed to read {len}; read {read}");
721 debug_assert!((len - read) == 0, "supposed to read {len}; read {read}");
722 Ok(())
723 };
724 Ok(map)
725 }
726
727 pub fn collect_map(&mut self, tags: HashMap<String, String>) -> Result<Map, ReadError> {
728 let mut co = self.map()?;
729 let (w, h) = match Pin::new(&mut co).resume(()) {
730 Yielded(MapData::Init { width, height }) => (width as usize, height as usize),
731 Complete(Err(x)) => return Err(x),
732 _ => unreachable!(),
733 };
734 let mut m = Map::new(w, h, tags);
735 for _ in 0..w * h {
736 match Pin::new(&mut co).resume(()) {
737 Yielded(MapData::Tile { floor, ore }) => m.push(Tile::new(floor, ore)),
738 Complete(Err(x)) => return Err(x),
739 _ => unreachable!(),
740 }
741 }
742 let mut i = 0;
743 while i < w * h {
744 match Pin::new(&mut co).resume(()) {
745 Yielded(MapData::Bloc(Bloc::None(n))) => i += n as usize,
746 Yielded(MapData::Bloc(Bloc::Build(x, y))) => {
747 m[i].set_block(y);
748 m[i].build = Some(x);
749 }
750 Yielded(MapData::Bloc(Bloc::Data(x, y))) => {
751 m[i].set_block(x);
752 m[i].build.as_mut().unwrap().data = y;
753 }
754 Yielded(MapData::Bloc(Bloc::Many(bloc, n))) => {
755 for i in i..=i + n as usize {
756 m[i].set_block(bloc);
757 }
758 i += n as usize;
759 }
760 Complete(Err(x)) => return Err(x),
761 _ => unreachable!(),
762 }
763 i += 1;
764 }
765 match Pin::new(&mut co).resume(()) {
766 Complete(Ok(())) => (),
767 _ => unreachable!(),
768 };
769 Ok(m)
770 }
771
772 pub fn map(
773 &mut self,
774 ) -> Result<impl Coroutine<(), Return = Result<(), ReadError>, Yield = MapData> + '_, ReadError>
775 {
776 let len = self.buff.read_u32()? as usize;
777 let rb4 = self.buff.read;
778
779 let c = #[coroutine]
780 move || {
781 let w = self.buff.read_u16()?;
782 let h = self.buff.read_u16()?;
783 yield MapData::Init {
784 width: w,
785 height: h,
786 };
787 let w = w as usize;
788 let h = h as usize;
789 let count = w * h;
790 tiles!(count, self, MapData);
791
792 let mut i = 0;
793 while i < count {
794 let block_id = self.buff.read_u16()?;
795 let packed = self.buff.read_u8()?;
796 let entity = (packed & 1) != 0;
797 let data = (packed & 2) != 0;
798 let central = if entity {
799 self.buff.read_bool()?
800 } else {
801 false
802 };
803 let block = BlockEnum::try_from(block_id)
804 .map_err(|_| ReadError::NoSuchBlock(block_id.to_string()))?;
805 let block = block.to_block();
806 let Some(block) = block else {
807 let consecutives = self.buff.read_u8()?;
808 yield MapData::Bloc(Bloc::None(consecutives));
809 i += consecutives as usize;
810 i += 1;
811 continue;
812 };
813 yield if entity {
814 if central {
815 let len = self.buff.read_u16()? as usize;
816 let rb4 = self.buff.read;
817
818 #[cfg(debug_assertions)]
819 println!("reading {block:?} ");
820 let _ = self.buff.read_i8()?;
821 let mut b = Build::new(block);
822 b.read(&mut self.buff)?;
823 let read = self.buff.read - rb4;
825
826 assert!(len >= read, "overread; supposed to read {len}; read {read}");
828 let n = len - read;
829 if n != 0 {
830 #[cfg(debug_assertions)]
831 println!(
832 "({block:?}) supposed to read {len}; read {read} - skipping excess"
833 );
834 self.buff.skip(n)?;
835 };
836
837 MapData::Bloc(Bloc::Build(b, block))
838 } else {
839 MapData::Bloc(Bloc::None(0))
840 }
841 } else if data {
842 MapData::Bloc(Bloc::Data(block, self.buff.read_i8()?))
843 } else {
844 let consecutives = self.buff.read_u8()?;
845 i += consecutives as usize;
846 MapData::Bloc(Bloc::Many(block, consecutives))
847 };
848
849 i += 1;
850 }
851 let read = self.buff.read - rb4;
852 debug_assert!(len >= read, "overread; supposed to read {len}; read {read}");
853 debug_assert!((len - read) == 0, "supposed to read {len}; read {read}");
854 Ok(())
855 };
856 Ok(c)
857 }
858
859 pub fn entities(
860 &mut self,
861 ) -> Result<
862 impl Coroutine<(), Yield = EntityData, Return = Result<(), ReadError>> + '_,
863 ReadError,
864 > {
865 let len = self.buff.read_u32()? as usize;
866 let rb4 = self.buff.read;
867
868 let c = #[coroutine]
869 move || {
870 for _ in 0..self.buff.read_u16()? {
871 self.buff.skip(2)?;
872 let _ = self.buff.read_utf()?;
873 }
874 for _ in 0..self.buff.read_u32()? {
876 self.buff.skip(4)?;
877 for _ in 0..self.buff.read_u32()? {
878 self.buff.skip(8usize)?;
879 let _ = DynData::deserialize(&mut self.buff)?;
880 }
881 }
882 let n = self.buff.read_u32()?;
884 yield EntityData::Length(n);
885 for _ in 0..n {
886 let len = self.buff.read_u16()? as usize;
887 let id = self.buff.read_u8()? as usize;
888 let Some(&Some(u)) = entity_mapping::ID.get(id) else {
889 self.buff.skip(len - 1)?;
890 continue;
891 };
892 self.buff.skip(4)?;
893 yield EntityData::Data(u.read(&mut self.buff)?);
894 }
895 let read = self.buff.read - rb4;
896 debug_assert!(len >= read, "overread; supposed to read {len}; read {read}");
897 debug_assert!((len - read) == 0, "supposed to read {len}; read {read}");
898 Ok(())
899 };
900 Ok(c)
901 }
902
903 pub fn collect_entities(&mut self) -> Result<Vec<Unit>, ReadError> {
904 let mut co = self.entities()?;
905 let n = match Pin::new(&mut co).resume(()) {
906 Yielded(EntityData::Length(x)) => x,
907 Complete(Err(e)) => return Err(e),
908 _ => unreachable!(),
909 };
910 let mut o = Vec::with_capacity(n as usize);
911 for _ in 0..n {
912 match Pin::new(&mut co).resume(()) {
913 Yielded(EntityData::Data(x)) => o.push(x),
914 Complete(Err(e)) => return Err(e),
915 Complete(Ok(())) => break,
916 _ => unreachable!(),
917 }
918 }
919 Ok(o)
920 }
921}
922
923impl Serializable for Map {
925 type ReadError = ReadError;
926 type WriteError = ();
927 fn deserialize(buff: &mut DataRead<'_>) -> Result<Map, Self::ReadError> {
931 let mut buff = MapReader::new(buff)?;
932 buff.header()?;
933 buff.version()?;
934 let tags = buff.tags_alloc()?;
935 buff.skip()?;
936 let mut m = buff.collect_map(tags)?;
937 m.entities = buff.collect_entities()?;
938
939 buff.skip()?;
941 Ok(m)
942 }
943
944 fn serialize(&self, _: &mut super::DataWrite<'_>) -> Result<(), Self::WriteError> {
947 unimplemented!()
948 }
949}