diff options
Diffstat (limited to 'client/src/world/map.rs')
-rw-r--r-- | client/src/world/map.rs | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/client/src/world/map.rs b/client/src/world/map.rs new file mode 100644 index 0000000..fb67918 --- /dev/null +++ b/client/src/world/map.rs @@ -0,0 +1,135 @@ +use ::map as mapfile; +use anyhow::Error; +use common::{num::Cast, vec}; +use log::{info, log}; +use ndarray::Array2; +use std::{ + collections::{hash_map, HashMap}, + fs::File, + mem, +}; + +pub use mapfile::format; +pub use mapfile::{ + format::Tile, + reader::{self, Color, LayerTilemapType}, +}; +pub const TILE_NUM: u32 = 16; + +pub struct Layer { + pub color: Color, + pub image: Option<usize>, + pub tiles: Array2<Tile>, + pub kind: LayerTilemapType, +} + +pub struct Map { + pub layers: Vec<Layer>, + pub tilesets: HashMap<Option<usize>, Array2<Color>>, +} + +impl Map { + pub fn empty() -> Self { + Self { + layers: Vec::new(), + tilesets: HashMap::new(), + } + } + + pub fn load(file: File) -> Result<Self, Error> { + info!("loading map"); + let datafile = datafile::Reader::new(file).unwrap(); + let mut map = mapfile::Reader::from_datafile(datafile); + + let mut layers = vec![]; + for group_idx in map.group_indices() { + let group = map.group(group_idx).unwrap(); + + if group.parallax_x != 100 + || group.parallax_y != 100 + || group.offset_x != 0 + || group.offset_y != 0 + || group.clipping.is_some() + { + continue; + } + + for layer_idx in group.layer_indices { + let layer = map.layer(layer_idx).unwrap(); + + let tilemap = if let reader::LayerType::Tilemap(t) = layer.t { + t + } else { + continue; + }; + let normal = if let Some(n) = tilemap.type_.to_normal() { + n + } else { + continue; + }; + let tiles = map.layer_tiles(tilemap.tiles(normal.data)).unwrap(); + layers.push(Layer { + color: normal.color, + image: normal.image, + kind: tilemap.type_, + tiles, + }); + } + } + + let mut tilesets = HashMap::new(); + for layer in &layers { + match tilesets.entry(layer.image) { + hash_map::Entry::Occupied(_) => {} + hash_map::Entry::Vacant(v) => { + let data = match layer.image { + None => Array2::from_elem( + (1, 1), + Color { + alpha: 255, + red: 255, + blue: 255, + green: 0, + }, + ), + Some(image_idx) => { + let image = map.image(image_idx).unwrap(); + let height = image.height.usize(); + let width = image.width.usize(); + match image.data { + Some(d) => { + let data = map.image_data(d).unwrap(); + if data.len() % mem::size_of::<Color>() != 0 { + panic!("image shape invalid"); + } + let data: Vec<Color> = unsafe { vec::transmute(data) }; + Array2::from_shape_vec((height, width), data).unwrap() + } + None => { + continue; + // let image_name = map.image_name(image.name)?; + // // WARN? Unknown external image + // // WARN! Wrong dimensions + // str::from_utf8(&image_name).ok() + // .and_then(sanitize) + // .map(&mut external_tileset_loader) + // .transpose()? + // .unwrap_or(None) + // .unwrap_or_else(|| Array2::from_elem((1, 1), Color::white())) + } + } + } + }; + v.insert(data); + } + } + } + + info!( + "{} layers + {} tilesets loaded", + layers.len(), + tilesets.len() + ); + Ok(Self { tilesets, layers }) + } +} |