diff --git a/Cargo.lock b/Cargo.lock index 760c22712ea6d8a8f41c0063fcdf8db612be11a7..99bbf099a16398a8e6969256d558feab329db94f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2077,7 +2077,7 @@ dependencies = [ [[package]] name = "micro_ldtk" -version = "0.3.0-beta.2" +version = "0.3.0" dependencies = [ "anyhow", "bevy", diff --git a/Cargo.toml b/Cargo.toml index 095db805be3df38d6a4cab2d3ae279d7cdee77d5..5ee7f6b6731ba1257c732a57b564817517411883 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "micro_ldtk" -version = "0.3.0" +version = "0.4.0" edition = "2021" authors = [ @@ -11,7 +11,8 @@ description = "Load data from LDTK, index it and make it accessible through Bevy license = "Apache-2.0" [features] -default = ["ldtk_1_2_5", "autotile"] +default = ["ldtk_1_3_0", "autotile"] +ldtk_1_3_0 = [] ldtk_1_2_5 = [] ldtk_1_2_4 = [] ldtk_1_2_3 = [] diff --git a/README.md b/README.md index 1bcd51e4f7be2498d7324b809a67fcb54e3e09e1..af9c047c1401a502484eb83918be8b8d0236bbb7 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ corresponding version of LDTK and save it again. | Feature Flag | Uses Schema Version | |----------------------------|-------------------------------------------------------------------------------| +| `ldtk_1_3_0` | [v1.2.5](https://github.com/deepnight/ldtk/blob/v1.3.0/docs/JSON_SCHEMA.json) | | `ldtk_1_2_5` | [v1.2.5](https://github.com/deepnight/ldtk/blob/v1.2.5/docs/JSON_SCHEMA.json) | | `ldtk_1_2_4` | [v1.2.4](https://github.com/deepnight/ldtk/blob/v1.2.4/docs/JSON_SCHEMA.json) | | `ldtk_1_2_3`, `ldtk_1_2_2` | [v1.2.2](https://github.com/deepnight/ldtk/blob/v1.2.2/docs/JSON_SCHEMA.json) | diff --git a/src/ldtk/data_1_3_0.rs b/src/ldtk/data_1_3_0.rs new file mode 100644 index 0000000000000000000000000000000000000000..4067b8f29e328b830244318fcab94459680525a1 --- /dev/null +++ b/src/ldtk/data_1_3_0.rs @@ -0,0 +1,1875 @@ +// Example code that deserializes and serializes the model. +// extern crate serde; +// #[macro_use] +// extern crate serde_derive; +// extern crate serde_json; +// +// use generated_module::Project; +// +// fn main() { +// let json = r#"{"answer": 42}"#; +// let model: Project = serde_json::from_str(&json).unwrap(); +// } + +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +/// This file is a JSON schema of files created by LDtk level editor (https://ldtk.io). +/// +/// This is the root of any Project JSON file. It contains: - the project settings, - an +/// array of levels, - a group of definitions (that can probably be safely ignored for most +/// users). +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Project { + /// This object is not actually used by LDtk. It ONLY exists to force explicit references to + /// all types, to make sure QuickType finds them and integrate all of them. Otherwise, + /// Quicktype will drop types that are not explicitely used. + #[serde(rename = "__FORCED_REFS")] + pub forced_refs: Option<ForcedRefs>, + + /// LDtk application build identifier.<br/> This is only used to identify the LDtk version + /// that generated this particular project file, which can be useful for specific bug fixing. + /// Note that the build identifier is just the date of the release, so it's not unique to + /// each user (one single global ID per LDtk public release), and as a result, completely + /// anonymous. + #[serde(rename = "appBuildId")] + pub app_build_id: f64, + + /// Number of backup files to keep, if the `backupOnSave` is TRUE + #[serde(rename = "backupLimit")] + pub backup_limit: i64, + + /// If TRUE, an extra copy of the project will be created in a sub folder, when saving. + #[serde(rename = "backupOnSave")] + pub backup_on_save: bool, + + /// Target relative path to store backup files + #[serde(rename = "backupRelPath")] + pub backup_rel_path: Option<String>, + + /// Project background color + #[serde(rename = "bgColor")] + pub bg_color: String, + + /// An array of command lines that can be ran manually by the user + #[serde(rename = "customCommands")] + pub custom_commands: Vec<LdtkCustomCommand>, + + /// Default grid size for new layers + #[serde(rename = "defaultGridSize")] + pub default_grid_size: i64, + + /// Default background color of levels + #[serde(rename = "defaultLevelBgColor")] + pub default_level_bg_color: String, + + /// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update. + /// It will then be `null`. You can enable the Multi-worlds advanced project option to enable + /// the change immediately.<br/><br/> Default new level height + #[serde(rename = "defaultLevelHeight")] + pub default_level_height: Option<i64>, + + /// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update. + /// It will then be `null`. You can enable the Multi-worlds advanced project option to enable + /// the change immediately.<br/><br/> Default new level width + #[serde(rename = "defaultLevelWidth")] + pub default_level_width: Option<i64>, + + /// Default X pivot (0 to 1) for new entities + #[serde(rename = "defaultPivotX")] + pub default_pivot_x: f64, + + /// Default Y pivot (0 to 1) for new entities + #[serde(rename = "defaultPivotY")] + pub default_pivot_y: f64, + + /// A structure containing all the definitions of this project + #[serde(rename = "defs")] + pub defs: Definitions, + + /// If the project isn't in MultiWorlds mode, this is the IID of the internal "dummy" World. + #[serde(rename = "dummyWorldIid")] + pub dummy_world_iid: String, + + /// If TRUE, the exported PNGs will include the level background (color or image). + #[serde(rename = "exportLevelBg")] + pub export_level_bg: bool, + + /// **WARNING**: this deprecated value is no longer exported since version 0.9.3 Replaced + /// by: `imageExportMode` + #[serde(rename = "exportPng")] + pub export_png: Option<bool>, + + /// If TRUE, a Tiled compatible file will also be generated along with the LDtk JSON file + /// (default is FALSE) + #[serde(rename = "exportTiled")] + pub export_tiled: bool, + + /// If TRUE, one file will be saved for the project (incl. all its definitions) and one file + /// in a sub-folder for each level. + #[serde(rename = "externalLevels")] + pub external_levels: bool, + + /// An array containing various advanced flags (ie. options or other states). Possible + /// values: `DiscardPreCsvIntGrid`, `ExportPreCsvIntGridFormat`, `IgnoreBackupSuggest`, + /// `PrependIndexToLevelFileNames`, `MultiWorlds`, `UseMultilinesType` + #[serde(rename = "flags")] + pub flags: Vec<Flag>, + + /// Naming convention for Identifiers (first-letter uppercase, full uppercase etc.) Possible + /// values: `Capitalize`, `Uppercase`, `Lowercase`, `Free` + #[serde(rename = "identifierStyle")] + pub identifier_style: IdentifierStyle, + + /// Unique project identifier + #[serde(rename = "iid")] + pub iid: String, + + /// "Image export" option when saving project. Possible values: `None`, `OneImagePerLayer`, + /// `OneImagePerLevel`, `LayersAndLevels` + #[serde(rename = "imageExportMode")] + pub image_export_mode: ImageExportMode, + + /// File format version + #[serde(rename = "jsonVersion")] + pub json_version: String, + + /// The default naming convention for level identifiers. + #[serde(rename = "levelNamePattern")] + pub level_name_pattern: String, + + /// All levels. The order of this array is only relevant in `LinearHorizontal` and + /// `linearVertical` world layouts (see `worldLayout` value).<br/> Otherwise, you should + /// refer to the `worldX`,`worldY` coordinates of each Level. + #[serde(rename = "levels")] + pub levels: Vec<Level>, + + /// If TRUE, the Json is partially minified (no indentation, nor line breaks, default is + /// FALSE) + #[serde(rename = "minifyJson")] + pub minify_json: bool, + + /// Next Unique integer ID available + #[serde(rename = "nextUid")] + pub next_uid: i64, + + /// File naming pattern for exported PNGs + #[serde(rename = "pngFilePattern")] + pub png_file_pattern: Option<String>, + + /// If TRUE, a very simplified will be generated on saving, for quicker & easier engine + /// integration. + #[serde(rename = "simplifiedExport")] + pub simplified_export: bool, + + /// All instances of entities that have their `exportToToc` flag enabled are listed in this + /// array. + #[serde(rename = "toc")] + pub toc: Vec<LdtkTableOfContentEntry>, + + /// This optional description is used by LDtk Samples to show up some informations and + /// instructions. + #[serde(rename = "tutorialDesc")] + pub tutorial_desc: Option<String>, + + /// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update. + /// It will then be `null`. You can enable the Multi-worlds advanced project option to enable + /// the change immediately.<br/><br/> Height of the world grid in pixels. + #[serde(rename = "worldGridHeight")] + pub world_grid_height: Option<i64>, + + /// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update. + /// It will then be `null`. You can enable the Multi-worlds advanced project option to enable + /// the change immediately.<br/><br/> Width of the world grid in pixels. + #[serde(rename = "worldGridWidth")] + pub world_grid_width: Option<i64>, + + /// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update. + /// It will then be `null`. You can enable the Multi-worlds advanced project option to enable + /// the change immediately.<br/><br/> An enum that describes how levels are organized in + /// this project (ie. linearly or in a 2D space). Possible values: <`null`>, `Free`, + /// `GridVania`, `LinearHorizontal`, `LinearVertical` + #[serde(rename = "worldLayout")] + pub world_layout: Option<WorldLayout>, + + /// This array will be empty, unless you enable the Multi-Worlds in the project advanced + /// settings.<br/><br/> - in current version, a LDtk project file can only contain a single + /// world with multiple levels in it. In this case, levels and world layout related settings + /// are stored in the root of the JSON.<br/> - with "Multi-worlds" enabled, there will be a + /// `worlds` array in root, each world containing levels and layout settings. Basically, it's + /// pretty much only about moving the `levels` array to the `worlds` array, along with world + /// layout related values (eg. `worldGridWidth` etc).<br/><br/>If you want to start + /// supporting this future update easily, please refer to this documentation: + /// https://github.com/deepnight/ldtk/issues/231 + #[serde(rename = "worlds")] + pub worlds: Vec<World>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LdtkCustomCommand { + #[serde(rename = "command")] + pub command: String, + + /// Possible values: `Manual`, `AfterLoad`, `BeforeSave`, `AfterSave` + #[serde(rename = "when")] + pub when: When, +} + +/// If you're writing your own LDtk importer, you should probably just ignore *most* stuff in +/// the `defs` section, as it contains data that are mostly important to the editor. To keep +/// you away from the `defs` section and avoid some unnecessary JSON parsing, important data +/// from definitions is often duplicated in fields prefixed with a double underscore (eg. +/// `__identifier` or `__type`). The 2 only definition types you might need here are +/// **Tilesets** and **Enums**. +/// +/// A structure containing all the definitions of this project +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Definitions { + /// All entities definitions, including their custom fields + #[serde(rename = "entities")] + pub entities: Vec<EntityDefinition>, + + /// All internal enums + #[serde(rename = "enums")] + pub enums: Vec<EnumDefinition>, + + /// Note: external enums are exactly the same as `enums`, except they have a `relPath` to + /// point to an external source file. + #[serde(rename = "externalEnums")] + pub external_enums: Vec<EnumDefinition>, + + /// All layer definitions + #[serde(rename = "layers")] + pub layers: Vec<LayerDefinition>, + + /// All custom fields available to all levels. + #[serde(rename = "levelFields")] + pub level_fields: Vec<FieldDefinition>, + + /// All tilesets + #[serde(rename = "tilesets")] + pub tilesets: Vec<TilesetDefinition>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EntityDefinition { + /// Base entity color + #[serde(rename = "color")] + pub color: String, + + /// User defined documentation for this element to provide help/tips to level designers. + #[serde(rename = "doc")] + pub doc: Option<String>, + + /// If enabled, all instances of this entity will be listed in the project "Table of content" + /// object. + #[serde(rename = "exportToToc")] + pub export_to_toc: bool, + + /// Array of field definitions + #[serde(rename = "fieldDefs")] + pub field_defs: Vec<FieldDefinition>, + + #[serde(rename = "fillOpacity")] + pub fill_opacity: f64, + + /// Pixel height + #[serde(rename = "height")] + pub height: i64, + + #[serde(rename = "hollow")] + pub hollow: bool, + + /// User defined unique identifier + #[serde(rename = "identifier")] + pub identifier: String, + + /// Only applies to entities resizable on both X/Y. If TRUE, the entity instance width/height + /// will keep the same aspect ratio as the definition. + #[serde(rename = "keepAspectRatio")] + pub keep_aspect_ratio: bool, + + /// Possible values: `DiscardOldOnes`, `PreventAdding`, `MoveLastOne` + #[serde(rename = "limitBehavior")] + pub limit_behavior: LimitBehavior, + + /// If TRUE, the maxCount is a "per world" limit, if FALSE, it's a "per level". Possible + /// values: `PerLayer`, `PerLevel`, `PerWorld` + #[serde(rename = "limitScope")] + pub limit_scope: LimitScope, + + #[serde(rename = "lineOpacity")] + pub line_opacity: f64, + + /// Max instances count + #[serde(rename = "maxCount")] + pub max_count: i64, + + /// An array of 4 dimensions for the up/right/down/left borders (in this order) when using + /// 9-slice mode for `tileRenderMode`.<br/> If the tileRenderMode is not NineSlice, then + /// this array is empty.<br/> See: https://en.wikipedia.org/wiki/9-slice_scaling + #[serde(rename = "nineSliceBorders")] + pub nine_slice_borders: Vec<i64>, + + /// Pivot X coordinate (from 0 to 1.0) + #[serde(rename = "pivotX")] + pub pivot_x: f64, + + /// Pivot Y coordinate (from 0 to 1.0) + #[serde(rename = "pivotY")] + pub pivot_y: f64, + + /// Possible values: `Rectangle`, `Ellipse`, `Tile`, `Cross` + #[serde(rename = "renderMode")] + pub render_mode: RenderMode, + + /// If TRUE, the entity instances will be resizable horizontally + #[serde(rename = "resizableX")] + pub resizable_x: bool, + + /// If TRUE, the entity instances will be resizable vertically + #[serde(rename = "resizableY")] + pub resizable_y: bool, + + /// Display entity name in editor + #[serde(rename = "showName")] + pub show_name: bool, + + /// An array of strings that classifies this entity + #[serde(rename = "tags")] + pub tags: Vec<String>, + + /// **WARNING**: this deprecated value is no longer exported since version 1.2.0 Replaced + /// by: `tileRect` + #[serde(rename = "tileId")] + pub tile_id: Option<i64>, + + #[serde(rename = "tileOpacity")] + pub tile_opacity: f64, + + /// An object representing a rectangle from an existing Tileset + #[serde(rename = "tileRect")] + pub tile_rect: Option<TilesetRectangle>, + + /// An enum describing how the the Entity tile is rendered inside the Entity bounds. Possible + /// values: `Cover`, `FitInside`, `Repeat`, `Stretch`, `FullSizeCropped`, + /// `FullSizeUncropped`, `NineSlice` + #[serde(rename = "tileRenderMode")] + pub tile_render_mode: TileRenderMode, + + /// Tileset ID used for optional tile display + #[serde(rename = "tilesetId")] + pub tileset_id: Option<i64>, + + /// Unique Int identifier + #[serde(rename = "uid")] + pub uid: i64, + + /// Pixel width + #[serde(rename = "width")] + pub width: i64, +} + +/// This section is mostly only intended for the LDtk editor app itself. You can safely +/// ignore it. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FieldDefinition { + /// Human readable value type. Possible values: `Int, Float, String, Bool, Color, + /// ExternEnum.XXX, LocalEnum.XXX, Point, FilePath`.<br/> If the field is an array, this + /// field will look like `Array<...>` (eg. `Array<Int>`, `Array<Point>` etc.)<br/> NOTE: if + /// you enable the advanced option **Use Multilines type**, you will have "*Multilines*" + /// instead of "*String*" when relevant. + #[serde(rename = "__type")] + pub field_definition_type: String, + + /// Optional list of accepted file extensions for FilePath value type. Includes the dot: + /// `.ext` + #[serde(rename = "acceptFileTypes")] + pub accept_file_types: Option<Vec<String>>, + + /// Possible values: `Any`, `OnlySame`, `OnlyTags`, `OnlySpecificEntity` + #[serde(rename = "allowedRefs")] + pub allowed_refs: AllowedRefs, + + #[serde(rename = "allowedRefsEntityUid")] + pub allowed_refs_entity_uid: Option<i64>, + + #[serde(rename = "allowedRefTags")] + pub allowed_ref_tags: Vec<String>, + + #[serde(rename = "allowOutOfLevelRef")] + pub allow_out_of_level_ref: bool, + + /// Array max length + #[serde(rename = "arrayMaxLength")] + pub array_max_length: Option<i64>, + + /// Array min length + #[serde(rename = "arrayMinLength")] + pub array_min_length: Option<i64>, + + #[serde(rename = "autoChainRef")] + pub auto_chain_ref: bool, + + /// TRUE if the value can be null. For arrays, TRUE means it can contain null values + /// (exception: array of Points can't have null values). + #[serde(rename = "canBeNull")] + pub can_be_null: bool, + + /// Default value if selected value is null or invalid. + #[serde(rename = "defaultOverride")] + pub default_override: Option<serde_json::Value>, + + /// User defined documentation for this field to provide help/tips to level designers about + /// accepted values. + #[serde(rename = "doc")] + pub doc: Option<String>, + + #[serde(rename = "editorAlwaysShow")] + pub editor_always_show: bool, + + #[serde(rename = "editorCutLongValues")] + pub editor_cut_long_values: bool, + + /// Possible values: `Hidden`, `ValueOnly`, `NameAndValue`, `EntityTile`, `LevelTile`, + /// `Points`, `PointStar`, `PointPath`, `PointPathLoop`, `RadiusPx`, `RadiusGrid`, + /// `ArrayCountWithLabel`, `ArrayCountNoLabel`, `RefLinkBetweenPivots`, + /// `RefLinkBetweenCenters` + #[serde(rename = "editorDisplayMode")] + pub editor_display_mode: EditorDisplayMode, + + /// Possible values: `Above`, `Center`, `Beneath` + #[serde(rename = "editorDisplayPos")] + pub editor_display_pos: EditorDisplayPos, + + #[serde(rename = "editorDisplayScale")] + pub editor_display_scale: f64, + + /// Possible values: `ZigZag`, `StraightArrow`, `CurvedArrow`, `ArrowsLine`, `DashedLine` + #[serde(rename = "editorLinkStyle")] + pub editor_link_style: EditorLinkStyle, + + #[serde(rename = "editorShowInWorld")] + pub editor_show_in_world: bool, + + #[serde(rename = "editorTextPrefix")] + pub editor_text_prefix: Option<String>, + + #[serde(rename = "editorTextSuffix")] + pub editor_text_suffix: Option<String>, + + /// User defined unique identifier + #[serde(rename = "identifier")] + pub identifier: String, + + /// TRUE if the value is an array of multiple values + #[serde(rename = "isArray")] + pub is_array: bool, + + /// Max limit for value, if applicable + #[serde(rename = "max")] + pub max: Option<f64>, + + /// Min limit for value, if applicable + #[serde(rename = "min")] + pub min: Option<f64>, + + /// Optional regular expression that needs to be matched to accept values. Expected format: + /// `/some_reg_ex/g`, with optional "i" flag. + #[serde(rename = "regex")] + pub regex: Option<String>, + + #[serde(rename = "symmetricalRef")] + pub symmetrical_ref: bool, + + /// Possible values: <`null`>, `LangPython`, `LangRuby`, `LangJS`, `LangLua`, `LangC`, + /// `LangHaxe`, `LangMarkdown`, `LangJson`, `LangXml`, `LangLog` + #[serde(rename = "textLanguageMode")] + pub text_language_mode: Option<TextLanguageMode>, + + /// UID of the tileset used for a Tile + #[serde(rename = "tilesetUid")] + pub tileset_uid: Option<i64>, + + /// Internal enum representing the possible field types. Possible values: F_Int, F_Float, + /// F_String, F_Text, F_Bool, F_Color, F_Enum(...), F_Point, F_Path, F_EntityRef, F_Tile + #[serde(rename = "type")] + pub purple_type: String, + + /// Unique Int identifier + #[serde(rename = "uid")] + pub uid: i64, + + /// If TRUE, the color associated with this field will override the Entity or Level default + /// color in the editor UI. For Enum fields, this would be the color associated to their + /// values. + #[serde(rename = "useForSmartColor")] + pub use_for_smart_color: bool, +} + +/// This object represents a custom sub rectangle in a Tileset image. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TilesetRectangle { + /// Height in pixels + #[serde(rename = "h")] + pub h: i64, + + /// UID of the tileset + #[serde(rename = "tilesetUid")] + pub tileset_uid: i64, + + /// Width in pixels + #[serde(rename = "w")] + pub w: i64, + + /// X pixels coordinate of the top-left corner in the Tileset image + #[serde(rename = "x")] + pub x: i64, + + /// Y pixels coordinate of the top-left corner in the Tileset image + #[serde(rename = "y")] + pub y: i64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EnumDefinition { + #[serde(rename = "externalFileChecksum")] + pub external_file_checksum: Option<String>, + + /// Relative path to the external file providing this Enum + #[serde(rename = "externalRelPath")] + pub external_rel_path: Option<String>, + + /// Tileset UID if provided + #[serde(rename = "iconTilesetUid")] + pub icon_tileset_uid: Option<i64>, + + /// User defined unique identifier + #[serde(rename = "identifier")] + pub identifier: String, + + /// An array of user-defined tags to organize the Enums + #[serde(rename = "tags")] + pub tags: Vec<String>, + + /// Unique Int identifier + #[serde(rename = "uid")] + pub uid: i64, + + /// All possible enum values, with their optional Tile infos. + #[serde(rename = "values")] + pub values: Vec<EnumValueDefinition>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EnumValueDefinition { + /// **WARNING**: this deprecated value will be *removed* completely on version 1.4.0+ + /// Replaced by: `tileRect` + #[serde(rename = "__tileSrcRect")] + pub tile_src_rect: Option<Vec<i64>>, + + /// Optional color + #[serde(rename = "color")] + pub color: i64, + + /// Enum value + #[serde(rename = "id")] + pub id: String, + + /// **WARNING**: this deprecated value will be *removed* completely on version 1.4.0+ + /// Replaced by: `tileRect` + #[serde(rename = "tileId")] + pub tile_id: Option<i64>, + + /// Optional tileset rectangle to represents this value + #[serde(rename = "tileRect")] + pub tile_rect: Option<TilesetRectangle>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LayerDefinition { + /// Type of the layer (*IntGrid, Entities, Tiles or AutoLayer*) + #[serde(rename = "__type")] + pub layer_definition_type: String, + + /// Contains all the auto-layer rule definitions. + #[serde(rename = "autoRuleGroups")] + pub auto_rule_groups: Vec<AutoLayerRuleGroup>, + + #[serde(rename = "autoSourceLayerDefUid")] + pub auto_source_layer_def_uid: Option<i64>, + + /// **WARNING**: this deprecated value is no longer exported since version 1.2.0 Replaced + /// by: `tilesetDefUid` + #[serde(rename = "autoTilesetDefUid")] + pub auto_tileset_def_uid: Option<i64>, + + /// Allow editor selections when the layer is not currently active. + #[serde(rename = "canSelectWhenInactive")] + pub can_select_when_inactive: bool, + + /// Opacity of the layer (0 to 1.0) + #[serde(rename = "displayOpacity")] + pub display_opacity: f64, + + /// User defined documentation for this element to provide help/tips to level designers. + #[serde(rename = "doc")] + pub doc: Option<String>, + + /// An array of tags to forbid some Entities in this layer + #[serde(rename = "excludedTags")] + pub excluded_tags: Vec<String>, + + /// Width and height of the grid in pixels + #[serde(rename = "gridSize")] + pub grid_size: i64, + + /// Height of the optional "guide" grid in pixels + #[serde(rename = "guideGridHei")] + pub guide_grid_hei: i64, + + /// Width of the optional "guide" grid in pixels + #[serde(rename = "guideGridWid")] + pub guide_grid_wid: i64, + + #[serde(rename = "hideFieldsWhenInactive")] + pub hide_fields_when_inactive: bool, + + /// Hide the layer from the list on the side of the editor view. + #[serde(rename = "hideInList")] + pub hide_in_list: bool, + + /// User defined unique identifier + #[serde(rename = "identifier")] + pub identifier: String, + + /// Alpha of this layer when it is not the active one. + #[serde(rename = "inactiveOpacity")] + pub inactive_opacity: f64, + + /// An array that defines extra optional info for each IntGrid value.<br/> WARNING: the + /// array order is not related to actual IntGrid values! As user can re-order IntGrid values + /// freely, you may value "2" before value "1" in this array. + #[serde(rename = "intGridValues")] + pub int_grid_values: Vec<IntGridValueDefinition>, + + /// Parallax horizontal factor (from -1 to 1, defaults to 0) which affects the scrolling + /// speed of this layer, creating a fake 3D (parallax) effect. + #[serde(rename = "parallaxFactorX")] + pub parallax_factor_x: f64, + + /// Parallax vertical factor (from -1 to 1, defaults to 0) which affects the scrolling speed + /// of this layer, creating a fake 3D (parallax) effect. + #[serde(rename = "parallaxFactorY")] + pub parallax_factor_y: f64, + + /// If true (default), a layer with a parallax factor will also be scaled up/down accordingly. + #[serde(rename = "parallaxScaling")] + pub parallax_scaling: bool, + + /// X offset of the layer, in pixels (IMPORTANT: this should be added to the `LayerInstance` + /// optional offset) + #[serde(rename = "pxOffsetX")] + pub px_offset_x: i64, + + /// Y offset of the layer, in pixels (IMPORTANT: this should be added to the `LayerInstance` + /// optional offset) + #[serde(rename = "pxOffsetY")] + pub px_offset_y: i64, + + /// An array of tags to filter Entities that can be added to this layer + #[serde(rename = "requiredTags")] + pub required_tags: Vec<String>, + + /// If the tiles are smaller or larger than the layer grid, the pivot value will be used to + /// position the tile relatively its grid cell. + #[serde(rename = "tilePivotX")] + pub tile_pivot_x: f64, + + /// If the tiles are smaller or larger than the layer grid, the pivot value will be used to + /// position the tile relatively its grid cell. + #[serde(rename = "tilePivotY")] + pub tile_pivot_y: f64, + + /// Reference to the default Tileset UID being used by this layer definition.<br/> + /// **WARNING**: some layer *instances* might use a different tileset. So most of the time, + /// you should probably use the `__tilesetDefUid` value found in layer instances.<br/> Note: + /// since version 1.0.0, the old `autoTilesetDefUid` was removed and merged into this value. + #[serde(rename = "tilesetDefUid")] + pub tileset_def_uid: Option<i64>, + + /// Type of the layer as Haxe Enum Possible values: `IntGrid`, `Entities`, `Tiles`, + /// `AutoLayer` + #[serde(rename = "type")] + pub purple_type: Type, + + /// Unique Int identifier + #[serde(rename = "uid")] + pub uid: i64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AutoLayerRuleGroup { + #[serde(rename = "active")] + pub active: bool, + + /// *This field was removed in 1.0.0 and should no longer be used.* + #[serde(rename = "collapsed")] + pub collapsed: Option<bool>, + + #[serde(rename = "isOptional")] + pub is_optional: bool, + + #[serde(rename = "name")] + pub name: String, + + #[serde(rename = "rules")] + pub rules: Vec<AutoLayerRuleDefinition>, + + #[serde(rename = "uid")] + pub uid: i64, + + #[serde(rename = "usesWizard")] + pub uses_wizard: bool, +} + +/// This complex section isn't meant to be used by game devs at all, as these rules are +/// completely resolved internally by the editor before any saving. You should just ignore +/// this part. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AutoLayerRuleDefinition { + /// If FALSE, the rule effect isn't applied, and no tiles are generated. + #[serde(rename = "active")] + pub active: bool, + + /// When TRUE, the rule will prevent other rules to be applied in the same cell if it matches + /// (TRUE by default). + #[serde(rename = "breakOnMatch")] + pub break_on_match: bool, + + /// Chances for this rule to be applied (0 to 1) + #[serde(rename = "chance")] + pub chance: f64, + + /// Checker mode Possible values: `None`, `Horizontal`, `Vertical` + #[serde(rename = "checker")] + pub checker: Checker, + + /// If TRUE, allow rule to be matched by flipping its pattern horizontally + #[serde(rename = "flipX")] + pub flip_x: bool, + + /// If TRUE, allow rule to be matched by flipping its pattern vertically + #[serde(rename = "flipY")] + pub flip_y: bool, + + /// Default IntGrid value when checking cells outside of level bounds + #[serde(rename = "outOfBoundsValue")] + pub out_of_bounds_value: Option<i64>, + + /// Rule pattern (size x size) + #[serde(rename = "pattern")] + pub pattern: Vec<i64>, + + /// If TRUE, enable Perlin filtering to only apply rule on specific random area + #[serde(rename = "perlinActive")] + pub perlin_active: bool, + + #[serde(rename = "perlinOctaves")] + pub perlin_octaves: f64, + + #[serde(rename = "perlinScale")] + pub perlin_scale: f64, + + #[serde(rename = "perlinSeed")] + pub perlin_seed: f64, + + /// X pivot of a tile stamp (0-1) + #[serde(rename = "pivotX")] + pub pivot_x: f64, + + /// Y pivot of a tile stamp (0-1) + #[serde(rename = "pivotY")] + pub pivot_y: f64, + + /// Pattern width & height. Should only be 1,3,5 or 7. + #[serde(rename = "size")] + pub size: i64, + + /// Array of all the tile IDs. They are used randomly or as stamps, based on `tileMode` value. + #[serde(rename = "tileIds")] + pub tile_ids: Vec<i64>, + + /// Defines how tileIds array is used Possible values: `Single`, `Stamp` + #[serde(rename = "tileMode")] + pub tile_mode: TileMode, + + /// Max random offset for X tile pos + #[serde(rename = "tileRandomXMax")] + pub tile_random_x_max: i64, + + /// Min random offset for X tile pos + #[serde(rename = "tileRandomXMin")] + pub tile_random_x_min: i64, + + /// Max random offset for Y tile pos + #[serde(rename = "tileRandomYMax")] + pub tile_random_y_max: i64, + + /// Min random offset for Y tile pos + #[serde(rename = "tileRandomYMin")] + pub tile_random_y_min: i64, + + /// Tile X offset + #[serde(rename = "tileXOffset")] + pub tile_x_offset: i64, + + /// Tile Y offset + #[serde(rename = "tileYOffset")] + pub tile_y_offset: i64, + + /// Unique Int identifier + #[serde(rename = "uid")] + pub uid: i64, + + /// X cell coord modulo + #[serde(rename = "xModulo")] + pub x_modulo: i64, + + /// X cell start offset + #[serde(rename = "xOffset")] + pub x_offset: i64, + + /// Y cell coord modulo + #[serde(rename = "yModulo")] + pub y_modulo: i64, + + /// Y cell start offset + #[serde(rename = "yOffset")] + pub y_offset: i64, +} + +/// IntGrid value definition +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct IntGridValueDefinition { + #[serde(rename = "color")] + pub color: String, + + /// User defined unique identifier + #[serde(rename = "identifier")] + pub identifier: Option<String>, + + /// The IntGrid value itself + #[serde(rename = "value")] + pub value: i64, +} + +/// The `Tileset` definition is the most important part among project definitions. It +/// contains some extra informations about each integrated tileset. If you only had to parse +/// one definition section, that would be the one. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TilesetDefinition { + /// Grid-based height + #[serde(rename = "__cHei")] + pub c_hei: i64, + + /// Grid-based width + #[serde(rename = "__cWid")] + pub c_wid: i64, + + /// The following data is used internally for various optimizations. It's always synced with + /// source image changes. + #[serde(rename = "cachedPixelData")] + pub cached_pixel_data: Option<HashMap<String, Option<serde_json::Value>>>, + + /// An array of custom tile metadata + #[serde(rename = "customData")] + pub custom_data: Vec<TileCustomMetadata>, + + /// If this value is set, then it means that this atlas uses an internal LDtk atlas image + /// instead of a loaded one. Possible values: <`null`>, `LdtkIcons` + #[serde(rename = "embedAtlas")] + pub embed_atlas: Option<EmbedAtlas>, + + /// Tileset tags using Enum values specified by `tagsSourceEnumId`. This array contains 1 + /// element per Enum value, which contains an array of all Tile IDs that are tagged with it. + #[serde(rename = "enumTags")] + pub enum_tags: Vec<EnumTagValue>, + + /// User defined unique identifier + #[serde(rename = "identifier")] + pub identifier: String, + + /// Distance in pixels from image borders + #[serde(rename = "padding")] + pub padding: i64, + + /// Image height in pixels + #[serde(rename = "pxHei")] + pub px_hei: i64, + + /// Image width in pixels + #[serde(rename = "pxWid")] + pub px_wid: i64, + + /// Path to the source file, relative to the current project JSON file<br/> It can be null + /// if no image was provided, or when using an embed atlas. + #[serde(rename = "relPath")] + pub rel_path: Option<String>, + + /// Array of group of tiles selections, only meant to be used in the editor + #[serde(rename = "savedSelections")] + pub saved_selections: Vec<HashMap<String, Option<serde_json::Value>>>, + + /// Space in pixels between all tiles + #[serde(rename = "spacing")] + pub spacing: i64, + + /// An array of user-defined tags to organize the Tilesets + #[serde(rename = "tags")] + pub tags: Vec<String>, + + /// Optional Enum definition UID used for this tileset meta-data + #[serde(rename = "tagsSourceEnumUid")] + pub tags_source_enum_uid: Option<i64>, + + #[serde(rename = "tileGridSize")] + pub tile_grid_size: i64, + + /// Unique Intidentifier + #[serde(rename = "uid")] + pub uid: i64, +} + +/// In a tileset definition, user defined meta-data of a tile. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TileCustomMetadata { + #[serde(rename = "data")] + pub data: String, + + #[serde(rename = "tileId")] + pub tile_id: i64, +} + +/// In a tileset definition, enum based tag infos +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EnumTagValue { + #[serde(rename = "enumValueId")] + pub enum_value_id: String, + + #[serde(rename = "tileIds")] + pub tile_ids: Vec<i64>, +} + +/// This object is not actually used by LDtk. It ONLY exists to force explicit references to +/// all types, to make sure QuickType finds them and integrate all of them. Otherwise, +/// Quicktype will drop types that are not explicitely used. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ForcedRefs { + #[serde(rename = "AutoLayerRuleGroup")] + pub auto_layer_rule_group: Option<AutoLayerRuleGroup>, + + #[serde(rename = "AutoRuleDef")] + pub auto_rule_def: Option<AutoLayerRuleDefinition>, + + #[serde(rename = "CustomCommand")] + pub custom_command: Option<LdtkCustomCommand>, + + #[serde(rename = "Definitions")] + pub definitions: Option<Definitions>, + + #[serde(rename = "EntityDef")] + pub entity_def: Option<EntityDefinition>, + + #[serde(rename = "EntityInstance")] + pub entity_instance: Option<EntityInstance>, + + #[serde(rename = "EntityReferenceInfos")] + pub entity_reference_infos: Option<ReferenceToAnEntityInstance>, + + #[serde(rename = "EnumDef")] + pub enum_def: Option<EnumDefinition>, + + #[serde(rename = "EnumDefValues")] + pub enum_def_values: Option<EnumValueDefinition>, + + #[serde(rename = "EnumTagValue")] + pub enum_tag_value: Option<EnumTagValue>, + + #[serde(rename = "FieldDef")] + pub field_def: Option<FieldDefinition>, + + #[serde(rename = "FieldInstance")] + pub field_instance: Option<FieldInstance>, + + #[serde(rename = "GridPoint")] + pub grid_point: Option<GridPoint>, + + #[serde(rename = "IntGridValueDef")] + pub int_grid_value_def: Option<IntGridValueDefinition>, + + #[serde(rename = "IntGridValueInstance")] + pub int_grid_value_instance: Option<IntGridValueInstance>, + + #[serde(rename = "LayerDef")] + pub layer_def: Option<LayerDefinition>, + + #[serde(rename = "LayerInstance")] + pub layer_instance: Option<LayerInstance>, + + #[serde(rename = "Level")] + pub level: Option<Level>, + + #[serde(rename = "LevelBgPosInfos")] + pub level_bg_pos_infos: Option<LevelBackgroundPosition>, + + #[serde(rename = "NeighbourLevel")] + pub neighbour_level: Option<NeighbourLevel>, + + #[serde(rename = "TableOfContentEntry")] + pub table_of_content_entry: Option<LdtkTableOfContentEntry>, + + #[serde(rename = "Tile")] + pub tile: Option<TileInstance>, + + #[serde(rename = "TileCustomMetadata")] + pub tile_custom_metadata: Option<TileCustomMetadata>, + + #[serde(rename = "TilesetDef")] + pub tileset_def: Option<TilesetDefinition>, + + #[serde(rename = "TilesetRect")] + pub tileset_rect: Option<TilesetRectangle>, + + #[serde(rename = "World")] + pub world: Option<World>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EntityInstance { + /// Grid-based coordinates (`[x,y]` format) + #[serde(rename = "__grid")] + pub grid: Vec<i64>, + + /// Entity definition identifier + #[serde(rename = "__identifier")] + pub identifier: String, + + /// Pivot coordinates (`[x,y]` format, values are from 0 to 1) of the Entity + #[serde(rename = "__pivot")] + pub pivot: Vec<f64>, + + /// The entity "smart" color, guessed from either Entity definition, or one its field + /// instances. + #[serde(rename = "__smartColor")] + pub smart_color: String, + + /// Array of tags defined in this Entity definition + #[serde(rename = "__tags")] + pub tags: Vec<String>, + + /// Optional TilesetRect used to display this entity (it could either be the default Entity + /// tile, or some tile provided by a field value, like an Enum). + #[serde(rename = "__tile")] + pub tile: Option<TilesetRectangle>, + + /// Reference of the **Entity definition** UID + #[serde(rename = "defUid")] + pub def_uid: i64, + + /// An array of all custom fields and their values. + #[serde(rename = "fieldInstances")] + pub field_instances: Vec<FieldInstance>, + + /// Entity height in pixels. For non-resizable entities, it will be the same as Entity + /// definition. + #[serde(rename = "height")] + pub height: i64, + + /// Unique instance identifier + #[serde(rename = "iid")] + pub iid: String, + + /// Pixel coordinates (`[x,y]` format) in current level coordinate space. Don't forget + /// optional layer offsets, if they exist! + #[serde(rename = "px")] + pub px: Vec<i64>, + + /// Entity width in pixels. For non-resizable entities, it will be the same as Entity + /// definition. + #[serde(rename = "width")] + pub width: i64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FieldInstance { + /// Field definition identifier + #[serde(rename = "__identifier")] + pub identifier: String, + + /// Optional TilesetRect used to display this field (this can be the field own Tile, or some + /// other Tile guessed from the value, like an Enum). + #[serde(rename = "__tile")] + pub tile: Option<TilesetRectangle>, + + /// Type of the field, such as `Int`, `Float`, `String`, `Enum(my_enum_name)`, `Bool`, + /// etc.<br/> NOTE: if you enable the advanced option **Use Multilines type**, you will have + /// "*Multilines*" instead of "*String*" when relevant. + #[serde(rename = "__type")] + pub field_instance_type: String, + + /// Actual value of the field instance. The value type varies, depending on `__type`:<br/> + /// - For **classic types** (ie. Integer, Float, Boolean, String, Text and FilePath), you + /// just get the actual value with the expected type.<br/> - For **Color**, the value is an + /// hexadecimal string using "#rrggbb" format.<br/> - For **Enum**, the value is a String + /// representing the selected enum value.<br/> - For **Point**, the value is a + /// [GridPoint](#ldtk-GridPoint) object.<br/> - For **Tile**, the value is a + /// [TilesetRect](#ldtk-TilesetRect) object.<br/> - For **EntityRef**, the value is an + /// [EntityReferenceInfos](#ldtk-EntityReferenceInfos) object.<br/><br/> If the field is an + /// array, then this `__value` will also be a JSON array. + #[serde(rename = "__value")] + pub value: Option<serde_json::Value>, + + /// Reference of the **Field definition** UID + #[serde(rename = "defUid")] + pub def_uid: i64, + + /// Editor internal raw values + #[serde(rename = "realEditorValues")] + pub real_editor_values: Vec<Option<serde_json::Value>>, +} + +/// This object describes the "location" of an Entity instance in the project worlds. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ReferenceToAnEntityInstance { + /// IID of the refered EntityInstance + #[serde(rename = "entityIid")] + pub entity_iid: String, + + /// IID of the LayerInstance containing the refered EntityInstance + #[serde(rename = "layerIid")] + pub layer_iid: String, + + /// IID of the Level containing the refered EntityInstance + #[serde(rename = "levelIid")] + pub level_iid: String, + + /// IID of the World containing the refered EntityInstance + #[serde(rename = "worldIid")] + pub world_iid: String, +} + +/// This object is just a grid-based coordinate used in Field values. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GridPoint { + /// X grid-based coordinate + #[serde(rename = "cx")] + pub cx: i64, + + /// Y grid-based coordinate + #[serde(rename = "cy")] + pub cy: i64, +} + +/// IntGrid value instance +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct IntGridValueInstance { + /// Coordinate ID in the layer grid + #[serde(rename = "coordId")] + pub coord_id: i64, + + /// IntGrid value + #[serde(rename = "v")] + pub v: i64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LayerInstance { + /// Grid-based height + #[serde(rename = "__cHei")] + pub c_hei: i64, + + /// Grid-based width + #[serde(rename = "__cWid")] + pub c_wid: i64, + + /// Grid size + #[serde(rename = "__gridSize")] + pub grid_size: i64, + + /// Layer definition identifier + #[serde(rename = "__identifier")] + pub identifier: String, + + /// Layer opacity as Float [0-1] + #[serde(rename = "__opacity")] + pub opacity: f64, + + /// Total layer X pixel offset, including both instance and definition offsets. + #[serde(rename = "__pxTotalOffsetX")] + pub px_total_offset_x: i64, + + /// Total layer Y pixel offset, including both instance and definition offsets. + #[serde(rename = "__pxTotalOffsetY")] + pub px_total_offset_y: i64, + + /// The definition UID of corresponding Tileset, if any. + #[serde(rename = "__tilesetDefUid")] + pub tileset_def_uid: Option<i64>, + + /// The relative path to corresponding Tileset, if any. + #[serde(rename = "__tilesetRelPath")] + pub tileset_rel_path: Option<String>, + + /// Layer type (possible values: IntGrid, Entities, Tiles or AutoLayer) + #[serde(rename = "__type")] + pub layer_instance_type: String, + + /// An array containing all tiles generated by Auto-layer rules. The array is already sorted + /// in display order (ie. 1st tile is beneath 2nd, which is beneath 3rd etc.).<br/><br/> + /// Note: if multiple tiles are stacked in the same cell as the result of different rules, + /// all tiles behind opaque ones will be discarded. + #[serde(rename = "autoLayerTiles")] + pub auto_layer_tiles: Vec<TileInstance>, + + #[serde(rename = "entityInstances")] + pub entity_instances: Vec<EntityInstance>, + + #[serde(rename = "gridTiles")] + pub grid_tiles: Vec<TileInstance>, + + /// Unique layer instance identifier + #[serde(rename = "iid")] + pub iid: String, + + /// **WARNING**: this deprecated value is no longer exported since version 1.0.0 Replaced + /// by: `intGridCsv` + #[serde(rename = "intGrid")] + pub int_grid: Option<Vec<IntGridValueInstance>>, + + /// A list of all values in the IntGrid layer, stored in CSV format (Comma Separated + /// Values).<br/> Order is from left to right, and top to bottom (ie. first row from left to + /// right, followed by second row, etc).<br/> `0` means "empty cell" and IntGrid values + /// start at 1.<br/> The array size is `__cWid` x `__cHei` cells. + #[serde(rename = "intGridCsv")] + pub int_grid_csv: Vec<i64>, + + /// Reference the Layer definition UID + #[serde(rename = "layerDefUid")] + pub layer_def_uid: i64, + + /// Reference to the UID of the level containing this layer instance + #[serde(rename = "levelId")] + pub level_id: i64, + + /// An Array containing the UIDs of optional rules that were enabled in this specific layer + /// instance. + #[serde(rename = "optionalRules")] + pub optional_rules: Vec<i64>, + + /// This layer can use another tileset by overriding the tileset UID here. + #[serde(rename = "overrideTilesetUid")] + pub override_tileset_uid: Option<i64>, + + /// X offset in pixels to render this layer, usually 0 (IMPORTANT: this should be added to + /// the `LayerDef` optional offset, so you should probably prefer using `__pxTotalOffsetX` + /// which contains the total offset value) + #[serde(rename = "pxOffsetX")] + pub px_offset_x: i64, + + /// Y offset in pixels to render this layer, usually 0 (IMPORTANT: this should be added to + /// the `LayerDef` optional offset, so you should probably prefer using `__pxTotalOffsetX` + /// which contains the total offset value) + #[serde(rename = "pxOffsetY")] + pub px_offset_y: i64, + + /// Random seed used for Auto-Layers rendering + #[serde(rename = "seed")] + pub seed: i64, + + /// Layer instance visibility + #[serde(rename = "visible")] + pub visible: bool, +} + +/// This structure represents a single tile from a given Tileset. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TileInstance { + /// Internal data used by the editor.<br/> For auto-layer tiles: `[ruleId, coordId]`.<br/> + /// For tile-layer tiles: `[coordId]`. + #[serde(rename = "d")] + pub d: Vec<i64>, + + /// "Flip bits", a 2-bits integer to represent the mirror transformations of the tile.<br/> + /// - Bit 0 = X flip<br/> - Bit 1 = Y flip<br/> Examples: f=0 (no flip), f=1 (X flip + /// only), f=2 (Y flip only), f=3 (both flips) + #[serde(rename = "f")] + pub f: i64, + + /// Pixel coordinates of the tile in the **layer** (`[x,y]` format). Don't forget optional + /// layer offsets, if they exist! + #[serde(rename = "px")] + pub px: Vec<i64>, + + /// Pixel coordinates of the tile in the **tileset** (`[x,y]` format) + #[serde(rename = "src")] + pub src: Vec<i64>, + + /// The *Tile ID* in the corresponding tileset. + #[serde(rename = "t")] + pub t: i64, +} + +/// This section contains all the level data. It can be found in 2 distinct forms, depending +/// on Project current settings: - If "*Separate level files*" is **disabled** (default): +/// full level data is *embedded* inside the main Project JSON file, - If "*Separate level +/// files*" is **enabled**: level data is stored in *separate* standalone `.ldtkl` files (one +/// per level). In this case, the main Project JSON file will still contain most level data, +/// except heavy sections, like the `layerInstances` array (which will be null). The +/// `externalRelPath` string points to the `ldtkl` file. A `ldtkl` file is just a JSON file +/// containing exactly what is described below. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Level { + /// Background color of the level (same as `bgColor`, except the default value is + /// automatically used here if its value is `null`) + #[serde(rename = "__bgColor")] + pub bg_color: String, + + /// Position informations of the background image, if there is one. + #[serde(rename = "__bgPos")] + pub bg_pos: Option<LevelBackgroundPosition>, + + /// An array listing all other levels touching this one on the world map.<br/> Only relevant + /// for world layouts where level spatial positioning is manual (ie. GridVania, Free). For + /// Horizontal and Vertical layouts, this array is always empty. + #[serde(rename = "__neighbours")] + pub neighbours: Vec<NeighbourLevel>, + + /// The "guessed" color for this level in the editor, decided using either the background + /// color or an existing custom field. + #[serde(rename = "__smartColor")] + pub smart_color: String, + + /// Background color of the level. If `null`, the project `defaultLevelBgColor` should be + /// used. + #[serde(rename = "bgColor")] + pub level_bg_color: Option<String>, + + /// Background image X pivot (0-1) + #[serde(rename = "bgPivotX")] + pub bg_pivot_x: f64, + + /// Background image Y pivot (0-1) + #[serde(rename = "bgPivotY")] + pub bg_pivot_y: f64, + + /// An enum defining the way the background image (if any) is positioned on the level. See + /// `__bgPos` for resulting position info. Possible values: <`null`>, `Unscaled`, + /// `Contain`, `Cover`, `CoverDirty`, `Repeat` + #[serde(rename = "bgPos")] + pub level_bg_pos: Option<BgPos>, + + /// The *optional* relative path to the level background image. + #[serde(rename = "bgRelPath")] + pub bg_rel_path: Option<String>, + + /// This value is not null if the project option "*Save levels separately*" is enabled. In + /// this case, this **relative** path points to the level Json file. + #[serde(rename = "externalRelPath")] + pub external_rel_path: Option<String>, + + /// An array containing this level custom field values. + #[serde(rename = "fieldInstances")] + pub field_instances: Vec<FieldInstance>, + + /// User defined unique identifier + #[serde(rename = "identifier")] + pub identifier: String, + + /// Unique instance identifier + #[serde(rename = "iid")] + pub iid: String, + + /// An array containing all Layer instances. **IMPORTANT**: if the project option "*Save + /// levels separately*" is enabled, this field will be `null`.<br/> This array is **sorted + /// in display order**: the 1st layer is the top-most and the last is behind. + #[serde(rename = "layerInstances")] + pub layer_instances: Option<Vec<LayerInstance>>, + + /// Height of the level in pixels + #[serde(rename = "pxHei")] + pub px_hei: i64, + + /// Width of the level in pixels + #[serde(rename = "pxWid")] + pub px_wid: i64, + + /// Unique Int identifier + #[serde(rename = "uid")] + pub uid: i64, + + /// If TRUE, the level identifier will always automatically use the naming pattern as defined + /// in `Project.levelNamePattern`. Becomes FALSE if the identifier is manually modified by + /// user. + #[serde(rename = "useAutoIdentifier")] + pub use_auto_identifier: bool, + + /// Index that represents the "depth" of the level in the world. Default is 0, greater means + /// "above", lower means "below".<br/> This value is mostly used for display only and is + /// intended to make stacking of levels easier to manage. + #[serde(rename = "worldDepth")] + pub world_depth: i64, + + /// World X coordinate in pixels.<br/> Only relevant for world layouts where level spatial + /// positioning is manual (ie. GridVania, Free). For Horizontal and Vertical layouts, the + /// value is always -1 here. + #[serde(rename = "worldX")] + pub world_x: i64, + + /// World Y coordinate in pixels.<br/> Only relevant for world layouts where level spatial + /// positioning is manual (ie. GridVania, Free). For Horizontal and Vertical layouts, the + /// value is always -1 here. + #[serde(rename = "worldY")] + pub world_y: i64, +} + +/// Level background image position info +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LevelBackgroundPosition { + /// An array of 4 float values describing the cropped sub-rectangle of the displayed + /// background image. This cropping happens when original is larger than the level bounds. + /// Array format: `[ cropX, cropY, cropWidth, cropHeight ]` + #[serde(rename = "cropRect")] + pub crop_rect: Vec<f64>, + + /// An array containing the `[scaleX,scaleY]` values of the **cropped** background image, + /// depending on `bgPos` option. + #[serde(rename = "scale")] + pub scale: Vec<f64>, + + /// An array containing the `[x,y]` pixel coordinates of the top-left corner of the + /// **cropped** background image, depending on `bgPos` option. + #[serde(rename = "topLeftPx")] + pub top_left_px: Vec<i64>, +} + +/// Nearby level info +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NeighbourLevel { + /// A single lowercase character tipping on the level location (`n`orth, `s`outh, `w`est, + /// `e`ast). + #[serde(rename = "dir")] + pub dir: String, + + /// Neighbour Instance Identifier + #[serde(rename = "levelIid")] + pub level_iid: String, + + /// **WARNING**: this deprecated value is no longer exported since version 1.2.0 Replaced + /// by: `levelIid` + #[serde(rename = "levelUid")] + pub level_uid: Option<i64>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LdtkTableOfContentEntry { + #[serde(rename = "identifier")] + pub identifier: String, + + #[serde(rename = "instances")] + pub instances: Vec<ReferenceToAnEntityInstance>, +} + +/// **IMPORTANT**: this type is available as a preview. You can rely on it to update your +/// importers, for when it will be officially available. A World contains multiple levels, +/// and it has its own layout settings. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct World { + /// Default new level height + #[serde(rename = "defaultLevelHeight")] + pub default_level_height: i64, + + /// Default new level width + #[serde(rename = "defaultLevelWidth")] + pub default_level_width: i64, + + /// User defined unique identifier + #[serde(rename = "identifier")] + pub identifier: String, + + /// Unique instance identifer + #[serde(rename = "iid")] + pub iid: String, + + /// All levels from this world. The order of this array is only relevant in + /// `LinearHorizontal` and `linearVertical` world layouts (see `worldLayout` value). + /// Otherwise, you should refer to the `worldX`,`worldY` coordinates of each Level. + #[serde(rename = "levels")] + pub levels: Vec<Level>, + + /// Height of the world grid in pixels. + #[serde(rename = "worldGridHeight")] + pub world_grid_height: i64, + + /// Width of the world grid in pixels. + #[serde(rename = "worldGridWidth")] + pub world_grid_width: i64, + + /// An enum that describes how levels are organized in this project (ie. linearly or in a 2D + /// space). Possible values: `Free`, `GridVania`, `LinearHorizontal`, `LinearVertical`, `null` + #[serde(rename = "worldLayout")] + pub world_layout: Option<WorldLayout>, +} + +/// Possible values: `Manual`, `AfterLoad`, `BeforeSave`, `AfterSave` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum When { + #[serde(rename = "AfterLoad")] + AfterLoad, + + #[serde(rename = "AfterSave")] + AfterSave, + + #[serde(rename = "BeforeSave")] + BeforeSave, + + #[serde(rename = "Manual")] + Manual, +} + +/// Possible values: `Any`, `OnlySame`, `OnlyTags`, `OnlySpecificEntity` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum AllowedRefs { + #[serde(rename = "Any")] + Any, + + #[serde(rename = "OnlySame")] + OnlySame, + + #[serde(rename = "OnlySpecificEntity")] + OnlySpecificEntity, + + #[serde(rename = "OnlyTags")] + OnlyTags, +} + +/// Possible values: `Hidden`, `ValueOnly`, `NameAndValue`, `EntityTile`, `LevelTile`, +/// `Points`, `PointStar`, `PointPath`, `PointPathLoop`, `RadiusPx`, `RadiusGrid`, +/// `ArrayCountWithLabel`, `ArrayCountNoLabel`, `RefLinkBetweenPivots`, +/// `RefLinkBetweenCenters` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum EditorDisplayMode { + #[serde(rename = "ArrayCountNoLabel")] + ArrayCountNoLabel, + + #[serde(rename = "ArrayCountWithLabel")] + ArrayCountWithLabel, + + #[serde(rename = "EntityTile")] + EntityTile, + + #[serde(rename = "Hidden")] + Hidden, + + #[serde(rename = "LevelTile")] + LevelTile, + + #[serde(rename = "NameAndValue")] + NameAndValue, + + #[serde(rename = "PointPath")] + PointPath, + + #[serde(rename = "PointPathLoop")] + PointPathLoop, + + #[serde(rename = "PointStar")] + PointStar, + + #[serde(rename = "Points")] + Points, + + #[serde(rename = "RadiusGrid")] + RadiusGrid, + + #[serde(rename = "RadiusPx")] + RadiusPx, + + #[serde(rename = "RefLinkBetweenCenters")] + RefLinkBetweenCenters, + + #[serde(rename = "RefLinkBetweenPivots")] + RefLinkBetweenPivots, + + #[serde(rename = "ValueOnly")] + ValueOnly, +} + +/// Possible values: `Above`, `Center`, `Beneath` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum EditorDisplayPos { + #[serde(rename = "Above")] + Above, + + #[serde(rename = "Beneath")] + Beneath, + + #[serde(rename = "Center")] + Center, +} + +/// Possible values: `ZigZag`, `StraightArrow`, `CurvedArrow`, `ArrowsLine`, `DashedLine` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum EditorLinkStyle { + #[serde(rename = "ArrowsLine")] + ArrowsLine, + + #[serde(rename = "CurvedArrow")] + CurvedArrow, + + #[serde(rename = "DashedLine")] + DashedLine, + + #[serde(rename = "StraightArrow")] + StraightArrow, + + #[serde(rename = "ZigZag")] + ZigZag, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum TextLanguageMode { + #[serde(rename = "LangC")] + LangC, + + #[serde(rename = "LangHaxe")] + LangHaxe, + + #[serde(rename = "LangJS")] + LangJs, + + #[serde(rename = "LangJson")] + LangJson, + + #[serde(rename = "LangLog")] + LangLog, + + #[serde(rename = "LangLua")] + LangLua, + + #[serde(rename = "LangMarkdown")] + LangMarkdown, + + #[serde(rename = "LangPython")] + LangPython, + + #[serde(rename = "LangRuby")] + LangRuby, + + #[serde(rename = "LangXml")] + LangXml, +} + +/// Possible values: `DiscardOldOnes`, `PreventAdding`, `MoveLastOne` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum LimitBehavior { + #[serde(rename = "DiscardOldOnes")] + DiscardOldOnes, + + #[serde(rename = "MoveLastOne")] + MoveLastOne, + + #[serde(rename = "PreventAdding")] + PreventAdding, +} + +/// If TRUE, the maxCount is a "per world" limit, if FALSE, it's a "per level". Possible +/// values: `PerLayer`, `PerLevel`, `PerWorld` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum LimitScope { + #[serde(rename = "PerLayer")] + PerLayer, + + #[serde(rename = "PerLevel")] + PerLevel, + + #[serde(rename = "PerWorld")] + PerWorld, +} + +/// Possible values: `Rectangle`, `Ellipse`, `Tile`, `Cross` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum RenderMode { + #[serde(rename = "Cross")] + Cross, + + #[serde(rename = "Ellipse")] + Ellipse, + + #[serde(rename = "Rectangle")] + Rectangle, + + #[serde(rename = "Tile")] + Tile, +} + +/// An enum describing how the the Entity tile is rendered inside the Entity bounds. Possible +/// values: `Cover`, `FitInside`, `Repeat`, `Stretch`, `FullSizeCropped`, +/// `FullSizeUncropped`, `NineSlice` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum TileRenderMode { + #[serde(rename = "Cover")] + Cover, + + #[serde(rename = "FitInside")] + FitInside, + + #[serde(rename = "FullSizeCropped")] + FullSizeCropped, + + #[serde(rename = "FullSizeUncropped")] + FullSizeUncropped, + + #[serde(rename = "NineSlice")] + NineSlice, + + #[serde(rename = "Repeat")] + Repeat, + + #[serde(rename = "Stretch")] + Stretch, +} + +/// Checker mode Possible values: `None`, `Horizontal`, `Vertical` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Checker { + #[serde(rename = "Horizontal")] + Horizontal, + + #[serde(rename = "None")] + None, + + #[serde(rename = "Vertical")] + Vertical, +} + +/// Defines how tileIds array is used Possible values: `Single`, `Stamp` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum TileMode { + #[serde(rename = "Single")] + Single, + + #[serde(rename = "Stamp")] + Stamp, +} + +/// Type of the layer as Haxe Enum Possible values: `IntGrid`, `Entities`, `Tiles`, +/// `AutoLayer` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Type { + #[serde(rename = "AutoLayer")] + AutoLayer, + + #[serde(rename = "Entities")] + Entities, + + #[serde(rename = "IntGrid")] + IntGrid, + + #[serde(rename = "Tiles")] + Tiles, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum EmbedAtlas { + #[serde(rename = "LdtkIcons")] + LdtkIcons, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Flag { + #[serde(rename = "DiscardPreCsvIntGrid")] + DiscardPreCsvIntGrid, + + #[serde(rename = "ExportPreCsvIntGridFormat")] + ExportPreCsvIntGridFormat, + + #[serde(rename = "IgnoreBackupSuggest")] + IgnoreBackupSuggest, + + #[serde(rename = "MultiWorlds")] + MultiWorlds, + + #[serde(rename = "PrependIndexToLevelFileNames")] + PrependIndexToLevelFileNames, + + #[serde(rename = "UseMultilinesType")] + UseMultilinesType, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum BgPos { + #[serde(rename = "Contain")] + Contain, + + #[serde(rename = "Cover")] + Cover, + + #[serde(rename = "CoverDirty")] + CoverDirty, + + #[serde(rename = "Repeat")] + Repeat, + + #[serde(rename = "Unscaled")] + Unscaled, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum WorldLayout { + #[serde(rename = "Free")] + Free, + + #[serde(rename = "GridVania")] + GridVania, + + #[serde(rename = "LinearHorizontal")] + LinearHorizontal, + + #[serde(rename = "LinearVertical")] + LinearVertical, +} + +/// Naming convention for Identifiers (first-letter uppercase, full uppercase etc.) Possible +/// values: `Capitalize`, `Uppercase`, `Lowercase`, `Free` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum IdentifierStyle { + #[serde(rename = "Capitalize")] + Capitalize, + + #[serde(rename = "Free")] + Free, + + #[serde(rename = "Lowercase")] + Lowercase, + + #[serde(rename = "Uppercase")] + Uppercase, +} + +/// "Image export" option when saving project. Possible values: `None`, `OneImagePerLayer`, +/// `OneImagePerLevel`, `LayersAndLevels` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum ImageExportMode { + #[serde(rename = "LayersAndLevels")] + LayersAndLevels, + + #[serde(rename = "None")] + None, + + #[serde(rename = "OneImagePerLayer")] + OneImagePerLayer, + + #[serde(rename = "OneImagePerLevel")] + OneImagePerLevel, +} diff --git a/src/ldtk/mod.rs b/src/ldtk/mod.rs index c60e66976828f2973cb08cfaf12f16ef6b2a4256..e17b1f626d6327f0203e37cc592e17fd1ab80f74 100644 --- a/src/ldtk/mod.rs +++ b/src/ldtk/mod.rs @@ -12,6 +12,8 @@ mod data_1_2_2; mod data_1_2_4; #[cfg(feature = "ldtk_1_2_5")] mod data_1_2_5; +#[cfg(feature = "ldtk_1_3_0")] +mod data_1_3_0; use bevy::asset::{AssetLoader, BoxedFuture, LoadContext, LoadedAsset}; use bevy::reflect::{TypeUuid, Uuid}; @@ -29,6 +31,8 @@ pub use data_1_2_2::*; pub use data_1_2_4::*; #[cfg(feature = "ldtk_1_2_5")] pub use data_1_2_5::*; +#[cfg(feature = "ldtk_1_3_0")] +pub use data_1_3_0::*; #[derive(thiserror::Error, Debug)] pub enum ParseError { @@ -44,6 +48,44 @@ impl Project { pub fn from_bytes(bytes: &[u8]) -> Result<Self, ParseError> { serde_json::from_slice(bytes).map_err(|e| ParseError::SerdeError(format!("{}", e))) } + + pub fn get_all_levels(&self) -> Vec<&Level> { + if self.worlds.len() > 0 { + self.worlds + .iter() + .flat_map(|world| world.levels.iter()) + .collect() + } else { + self.levels.iter().collect() + } + } + + #[cfg(any( + feature = "ldtk_1_2_5", + feature = "ldtk_1_2_4", + feature = "ldtk_1_2_3", + feature = "ldtk_1_2_2", + feature = "ldtk_1_2_1", + feature = "ldtk_1_2_0", + feature = "ldtk_1_1_3", + feature = "ldtk_1_1_2", + feature = "ldtk_1_1_1", + feature = "ldtk_1_1_0", + feature = "ldtk_1_0_0" + ))] + pub fn get_world_levels(&self, identifier: impl ToString) -> Vec<&Level> { + vec![] + } + + #[cfg(any(feature = "ldtk_1_3_0",))] + pub fn get_world_levels(&self, identifier: impl ToString) -> Vec<&Level> { + let id = identifier.to_string(); + self.worlds + .iter() + .find(|world| world.identifier == id) + .map(|list| list.levels.iter().collect()) + .unwrap_or_else(Vec::new) + } } pub type LdtkProject = Project; @@ -166,7 +208,7 @@ mod autotile_support { mod test { use crate::ldtk::Project; - #[test] + #[cfg_attr(feature = "ldtk_1_2_5", test)] pub fn load_project() { const project_data: &[u8] = include_bytes!("./test_data/ver_1_2_5.ldtk"); diff --git a/src/lib.rs b/src/lib.rs index 369a99eddbfa12071e2067b7077b035675e5c028..f6b170f6535922fdc96f3233fc6b019510e7a810 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,20 @@ mod map_query; mod pregen; mod system; -#[cfg(any(feature = "ldtk_1_2_5", feature = "ldtk_1_2_4"))] +#[cfg(any( + feature = "ldtk_1_3_0", + feature = "ldtk_1_2_5", + feature = "ldtk_1_2_4", + feature = "ldtk_1_2_3", + feature = "ldtk_1_2_2", + feature = "ldtk_1_2_1", + feature = "ldtk_1_2_0", + feature = "ldtk_1_1_3", + feature = "ldtk_1_1_2", + feature = "ldtk_1_1_1", + feature = "ldtk_1_1_0", + feature = "ldtk_1_0_0", +))] pub mod ldtk; pub static mut LDTK_TILE_SCALE: AtomicU32 = AtomicU32::new(32);