use crate::datafile;
use bitflags::bitflags;
use fixed::types::{I17F15, I22F10, I27F5};
use image::RgbaImage;
use ndarray::Array2;
use serde::{Deserialize, Serialize};
use structview::View;
use thiserror::Error;
use vek::{Disk, Extent2, Rect, Rgba, Uv, Vec2};
use std::io;
mod checks;
pub mod edit;
mod impls;
mod load;
mod map_dir;
mod parse;
mod save;
pub use checks::MapError;
pub use load::{Load, LoadMultiple};
pub use map_dir::MapDirParseError;
pub use parse::MapParseError;
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase", tag = "type")]
pub enum Version {
DDNet06,
Teeworlds07,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TwMap {
pub version: Version,
pub info: Info,
pub images: Vec<Image>,
pub envelopes: Vec<Envelope>,
pub groups: Vec<Group>,
pub sounds: Vec<Sound>,
}
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error("Map - {0}")]
Map(#[from] MapError),
#[error("Map from Datafile - {0}")]
MapParse(#[from] parse::MapParseError),
#[error("Datafile saving - {0}")]
DatafileSave(#[from] datafile::DatafileSaveError),
#[error("Datafile parsing - {0}")]
DatafileParse(#[from] datafile::DatafileParseError),
#[error("IO - {0}")]
Io(#[from] io::Error),
#[error("MapDir - {0}")]
MapDirParse(#[from] map_dir::MapDirParseError),
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub enum LayerKind {
Game,
Tiles,
Quads,
Front,
Tele,
Speedup,
Switch,
Tune,
Sounds,
Invalid(InvalidLayerKind),
}
#[derive(Debug, Eq, PartialOrd, PartialEq, Copy, Clone, Hash)]
pub enum InvalidLayerKind {
Unknown(i32), UnknownTilemap(i32), NoType, NoTypeTilemap, }
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub enum CompressedData<T, U> {
Compressed(Vec<u8>, usize, U),
Loaded(T),
}
#[derive(Debug, Default, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct Info {
pub author: String,
pub version: String,
pub credits: String,
pub license: String,
pub settings: Vec<String>,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Image {
External(ExternalImage),
Embedded(EmbeddedImage),
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct ExternalImage {
#[serde(skip)]
pub name: String,
pub size: Extent2<u32>,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct ImageLoadInfo {
pub size: Extent2<u32>,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct EmbeddedImage {
pub name: String,
pub image: CompressedData<RgbaImage, ImageLoadInfo>, }
const PARALLAX_DIVISOR: Vec2<i32> = Vec2::new(100, 100);
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct Group {
pub name: String,
pub offset: Vec2<I27F5>,
pub parallax: Vec2<i32>,
#[serde(skip)]
pub layers: Vec<Layer>,
pub clipping: bool,
pub clip: Rect<I27F5, I27F5>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct Sound {
pub name: String,
pub data: CompressedData<Vec<u8>, ()>,
}
#[derive(Default, Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct AutomapperConfig {
pub config: Option<u16>,
pub seed: u32,
pub automatic: bool,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct BezierCurve<T> {
pub handle_l: Vec2<T>,
pub handle_r: Vec2<T>,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum CurveKind<T> {
Step,
#[default]
Linear,
Slow,
Fast,
Smooth,
Bezier(BezierCurve<T>),
Unknown(i32),
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
pub struct EnvPoint<T> {
pub time: i32,
pub content: T,
#[serde(flatten)]
pub curve: CurveKind<T>,
}
pub trait BezierDefault: Default {
fn bezier_default() -> Self {
Default::default()
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize, Default)]
pub struct Position {
#[serde(flatten)]
pub offset: Vec2<I17F15>,
pub rotation: I22F10,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
pub struct Volume(pub I22F10);
#[derive(Default, Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct Env<T: Copy> {
pub name: String,
pub synchronized: bool,
pub points: Vec<EnvPoint<T>>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum Envelope {
Position(Env<Position>),
Color(Env<Rgba<I22F10>>),
Sound(Env<Volume>),
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TilesLoadInfo {
pub size: Extent2<u32>,
pub compression: bool,
}
unsafe impl View for TileFlags {} bitflags! {
#[repr(C)]
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, Hash, Eq, PartialEq)]
#[serde(into = "map_dir::DirTileFlags", try_from = "map_dir::DirTileFlags")]
pub struct TileFlags: u8 {
const FLIP_X = 0b0001;
const FLIP_Y = 0b0010;
const OPAQUE = 0b0100;
const ROTATE = 0b1000;
}
}
#[derive(Debug, Copy, Clone, View, Eq, PartialEq, Default, Serialize, Deserialize)]
#[repr(C)]
pub struct Tile {
pub id: u8,
#[serde(flatten)]
pub flags: TileFlags,
#[serde(skip)]
pub(crate) skip: u8, #[serde(skip)]
pub(crate) unused: u8,
}
#[derive(Debug, Copy, Clone, View, Eq, PartialEq, Default, Serialize, Deserialize)]
#[repr(C)]
pub struct GameTile {
pub id: u8,
#[serde(flatten)]
pub flags: TileFlags,
#[serde(skip)]
pub(crate) skip: u8, #[serde(skip)]
pub(crate) unused: u8,
}
#[derive(Debug, Copy, Clone, View, Eq, PartialEq, Default, Serialize, Deserialize)]
#[repr(C)]
pub struct Tele {
pub number: u8,
pub id: u8,
}
#[derive(Debug, Copy, Clone, View, Eq, PartialEq, Default, Serialize, Deserialize)]
#[repr(C)]
#[serde(into = "i16", from = "i16")]
pub struct I16 {
pub(crate) bytes: [u8; 2],
}
#[derive(Debug, Copy, Clone, View, Eq, PartialEq, Default, Serialize, Deserialize)]
#[repr(C)]
pub struct Speedup {
pub force: u8,
pub max_speed: u8,
pub id: u8,
#[serde(skip)]
pub(crate) unused_padding: u8,
pub angle: I16,
}
#[derive(Debug, Copy, Clone, View, Eq, PartialEq, Default, Serialize, Deserialize)]
#[repr(C)]
pub struct Switch {
pub number: u8,
pub id: u8,
#[serde(flatten)]
pub flags: TileFlags,
pub delay: u8,
}
#[derive(Debug, Copy, Clone, View, Eq, PartialEq, Default, Serialize, Deserialize)]
#[repr(C)]
pub struct Tune {
pub number: u8,
pub id: u8,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct GameLayer {
#[serde(flatten, with = "map_dir::tiles_serialization")]
pub tiles: CompressedData<Array2<GameTile>, TilesLoadInfo>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct FrontLayer {
#[serde(flatten, with = "map_dir::tiles_serialization")]
pub tiles: CompressedData<Array2<GameTile>, TilesLoadInfo>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct TeleLayer {
#[serde(flatten, with = "map_dir::tiles_serialization")]
pub tiles: CompressedData<Array2<Tele>, TilesLoadInfo>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct SpeedupLayer {
#[serde(flatten, with = "map_dir::tiles_serialization")]
pub tiles: CompressedData<Array2<Speedup>, TilesLoadInfo>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct SwitchLayer {
#[serde(flatten, with = "map_dir::tiles_serialization")]
pub tiles: CompressedData<Array2<Switch>, TilesLoadInfo>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct TuneLayer {
#[serde(flatten, with = "map_dir::tiles_serialization")]
pub tiles: CompressedData<Array2<Tune>, TilesLoadInfo>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct TilesLayer {
pub name: String,
pub detail: bool,
pub color: Rgba<u8>,
#[serde(with = "map_dir::envelope_index_serialization")]
pub color_env: Option<u16>,
pub color_env_offset: i32,
#[serde(with = "map_dir::image_index_serialization")]
pub image: Option<u16>,
#[serde(flatten, with = "map_dir::tiles_serialization")]
pub tiles: CompressedData<Array2<Tile>, TilesLoadInfo>,
pub automapper_config: AutomapperConfig,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct Quad {
pub corners: [Vec2<I17F15>; 4],
pub position: Vec2<I17F15>,
pub colors: [Rgba<u8>; 4],
pub texture_coords: [Uv<I22F10>; 4], #[serde(with = "map_dir::envelope_index_serialization")]
pub position_env: Option<u16>,
pub position_env_offset: i32,
#[serde(with = "map_dir::envelope_index_serialization")]
pub color_env: Option<u16>,
pub color_env_offset: i32,
}
#[derive(Default, Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct QuadsLayer {
pub name: String,
pub detail: bool,
pub quads: Vec<Quad>,
#[serde(with = "map_dir::image_index_serialization")]
pub image: Option<u16>, }
#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum SoundArea {
Rectangle(Rect<I17F15, I17F15>),
Circle(Disk<I17F15, I27F5>),
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct SoundSource {
pub area: SoundArea,
pub looping: bool,
pub panning: bool,
pub delay: i32,
pub falloff: u8,
#[serde(with = "map_dir::envelope_index_serialization")]
pub position_env: Option<u16>,
pub position_env_offset: i32,
#[serde(with = "map_dir::envelope_index_serialization")]
pub sound_env: Option<u16>,
pub sound_env_offset: i32,
}
#[derive(Default, Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct SoundsLayer {
pub name: String,
pub detail: bool,
pub sources: Vec<SoundSource>,
#[serde(with = "map_dir::sound_index_serialization")]
pub sound: Option<u16>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum Layer {
Game(GameLayer),
Tiles(TilesLayer),
Quads(QuadsLayer),
Front(FrontLayer),
Tele(TeleLayer),
Speedup(SpeedupLayer),
Switch(SwitchLayer),
Tune(TuneLayer),
Sounds(SoundsLayer),
#[serde(skip)]
Invalid(InvalidLayerKind),
}
pub trait TilemapLayer: AnyLayer {
type TileType: AnyTile;
fn tiles(&self) -> &CompressedData<Array2<Self::TileType>, TilesLoadInfo>;
fn tiles_mut(&mut self) -> &mut CompressedData<Array2<Self::TileType>, TilesLoadInfo>;
}
pub trait AnyTile: Default + PartialEq + Copy + Clone + checks::TileChecking + View {
fn id(&self) -> u8;
fn id_mut(&mut self) -> &mut u8;
fn flags(&self) -> Option<TileFlags>;
fn flags_mut(&mut self) -> Option<&mut TileFlags>;
}
pub trait AnyLayer: Sized {
fn kind() -> LayerKind;
fn get(layer: &Layer) -> Option<&Self>;
fn get_mut(layer: &mut Layer) -> Option<&mut Self>;
}
pub trait PhysicsLayer: TilemapLayer {}