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