diff --git a/minimize-lints.sh b/minimize-lints.sh new file mode 100755 index 0000000..08d0d41 --- /dev/null +++ b/minimize-lints.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +cargo check -p all-is-cubes --message-format=json \ No newline at end of file diff --git a/repro.sh b/repro.sh new file mode 100755 index 0000000..f89acaa --- /dev/null +++ b/repro.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +cp tiles.rs src/tiles.rs +cargo clean -p mantle-diver +cargo build +git apply crash.patch + +OUT=$(cargo build 2>&1) + +cp tiles.rs src/tiles.rs + +if echo $OUT | grep "internal compiler error"; +then + echo "The ICE reproduces" + exit 0 +else + echo "No reproduction" + exit 1 +fi \ No newline at end of file diff --git a/tiles.rs b/tiles.rs new file mode 100644 index 0000000..4b6288e --- /dev/null +++ b/tiles.rs @@ -0,0 +1,317 @@ +pub mod tiledb_edit_ui; + +use std::{fmt::Debug, marker::PhantomData, ops::Index}; + +use egui_inspect::{derive::Inspect, Inspect}; +use serde::{Deserialize, Serialize}; + +use crate::{ + graphics::ScreenVec, + math::{IntRect, TILE_SIZE}, + texture_atlas::RectMap, +}; + +#[derive(Inspect, PartialEq, Eq)] +pub struct TileId(pub u16, PhantomData); + +impl Copy for TileId {} +impl Clone for TileId { + fn clone(&self) -> Self { + Self(self.0, PhantomData) + } +} +impl Debug for TileId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("TileId").field(&self.0).finish() + } +} + +impl TileId { + pub fn empty(&self) -> bool { + self.0 == 0 + } + pub const EMPTY: Self = Self(0, PhantomData); +} + +#[derive(Debug)] +pub enum Bg {} +#[derive(Debug)] +pub enum Mid {} +#[derive(Debug)] +pub enum Fg {} + +impl Bg { + pub fn unknown_def() -> TileDef { + TileDef { + light: Some(ScreenVec { x: 0, y: 0 }), + graphic_name: String::from("tiles/unknown_bg"), + tex_rect: IntRect { + x: 0, + y: 0, + w: 0, + h: 0, + }, + layer: (), + } + } +} + +impl Mid { + pub fn unknown_def() -> TileDef { + TileDef { + light: Some(ScreenVec { x: 0, y: 0 }), + graphic_name: String::from("tiles/unknown_mid"), + tex_rect: IntRect { + x: 0, + y: 0, + w: 0, + h: 0, + }, + layer: MidDef { + platform: true, + bb: Some(TileBb { + x: 0, + y: 0, + w: 32, + h: 32, + }), + }, + } + } +} + +impl Fg { + pub fn unknown_def() -> TileDef { + TileDef { + light: Some(ScreenVec { x: 0, y: 0 }), + graphic_name: String::from("tiles/unknown_fg"), + tex_rect: IntRect { + x: 0, + y: 0, + w: 0, + h: 0, + }, + layer: (), + } + } +} + +pub trait TileLayer { + /// Definitions specific to this layer + type SpecificDef; +} + +impl TileLayer for Bg { + type SpecificDef = (); +} + +impl TileLayer for Mid { + type SpecificDef = MidDef; +} + +impl TileLayer for Fg { + type SpecificDef = (); +} + +pub type BgTileId = TileId; +pub type MidTileId = TileId; +pub type FgTileId = TileId; + +impl BgTileId { + pub const DIRT: Self = Self(1, PhantomData); + pub const STONE: Self = Self(2, PhantomData); +} + +impl MidTileId { + pub const DIRT: Self = Self(1, PhantomData); + pub const STONE: Self = Self(2, PhantomData); + pub const TORCH: Self = Self(3, PhantomData); + pub const PLATFORM: Self = Self(4, PhantomData); + pub const PANZERIUM: Self = Self(5, PhantomData); + pub const UNBREAKANIUM: Self = Self(6, PhantomData); +} + +impl FgTileId { + pub const COAL: Self = Self(1, PhantomData); +} + +#[derive(Serialize, Deserialize, Inspect)] +pub struct TileDef +where + Layer::SpecificDef: Debug + Inspect, +{ + /// Whether the tile emits light, and the light source offset + pub light: Option, + pub graphic_name: String, + pub tex_rect: IntRect, + pub layer: Layer::SpecificDef, +} + +#[derive(Debug, Inspect, Default, Serialize, Deserialize)] +pub struct MidDef { + /// Platform behavior: Horizontally passable, vertically passable upwards + pub platform: bool, + /// Collision bounding box + pub bb: Option, +} + +impl Debug for TileDef +where + Layer::SpecificDef: Debug + Inspect, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TileDef") + .field("light", &self.light) + .field("graphic_name", &self.graphic_name) + .field("tex_rect", &self.tex_rect) + .field("layer", &self.layer) + .finish() + } +} + +impl Default for TileDef +where + Layer::SpecificDef: Default + Debug + Inspect, +{ + fn default() -> Self { + Self { + light: Default::default(), + graphic_name: Default::default(), + tex_rect: Default::default(), + layer: Layer::SpecificDef::default(), + } + } +} + +const DEFAULT_TILE_BB: TileBb = TileBb { + x: 0, + y: 0, + w: TILE_SIZE, + h: TILE_SIZE, +}; + +#[derive(Serialize, Deserialize, Debug, Inspect, Clone, Copy)] +pub struct TileBb { + pub x: u8, + pub y: u8, + pub w: u8, + pub h: u8, +} + +#[derive(Serialize, Deserialize, Debug, Inspect)] +pub struct TileDb { + unknown_bg: TileDef, + unknown_mid: TileDef, + unknown_fg: TileDef, + bg: Vec>, + mid: Vec>, + fg: Vec>, +} + +impl Default for TileDb { + fn default() -> Self { + Self { + unknown_bg: Bg::unknown_def(), + unknown_mid: Mid::unknown_def(), + unknown_fg: Fg::unknown_def(), + bg: vec![], + mid: vec![], + fg: vec![], + } + } +} + +impl Index for TileDb { + type Output = TileDef; + + fn index(&self, index: BgTileId) -> &Self::Output { + self.bg + .get(index.0 as usize - 1) + .unwrap_or(&self.unknown_bg) + } +} + +impl Index for TileDb { + type Output = TileDef; + + fn index(&self, index: MidTileId) -> &Self::Output { + self.mid + .get(index.0 as usize - 1) + .unwrap_or(&self.unknown_mid) + } +} + +impl Index for TileDb { + type Output = TileDef; + + fn index(&self, index: FgTileId) -> &Self::Output { + self.fg + .get(index.0 as usize - 1) + .unwrap_or(&self.unknown_fg) + } +} + +const PATH: &str = "tiles.dat"; + +impl TileDb { + pub fn load_or_default() -> Self { + match std::fs::read(PATH) { + Ok(data) => match rmp_serde::from_slice(&data) { + Ok(db) => db, + Err(e) => { + log::warn!("Failed to load tile database: {e}\nCreating default."); + Default::default() + } + }, + Err(e) => { + log::warn!("Failed to load tile database: {e}\nCreating default."); + Default::default() + } + } + } + pub fn try_save(&self) { + match rmp_serde::to_vec(self) { + Ok(vec) => match std::fs::write(PATH, vec) { + Ok(()) => {} + Err(e) => log::warn!("Failed to save tile db: {e}"), + }, + Err(e) => log::warn!("Failed to save tile db: {e}"), + } + } + + pub(crate) fn update_rects(&mut self, rects: &RectMap) { + update_rect_def(&mut self.unknown_bg, rects); + update_rect_def(&mut self.unknown_mid, rects); + update_rect_def(&mut self.unknown_fg, rects); + update_rect_db(&mut self.bg, rects); + update_rect_db(&mut self.mid, rects); + update_rect_db(&mut self.fg, rects); + } +} + +fn update_rect_db(db: &mut Vec>, rects: &RectMap) +where + Layer::SpecificDef: Debug + Inspect, +{ + for def in db { + update_rect_def(def, rects); + } +} + +fn update_rect_def( + def: &mut TileDef, + rects: &std::collections::HashMap, +) where + Layer::SpecificDef: Debug + Inspect, +{ + if !def.graphic_name.is_empty() { + if let Some(rect) = rects.get(def.graphic_name.as_str()) { + def.tex_rect = *rect; + log::info!("Updated rect for {}: {:?}", def.graphic_name.as_str(), rect); + } else { + log::error!("Missing texture for {:?}", def.graphic_name.as_str()); + } + } else { + log::warn!("Empty graphic name!"); + } +}