diff --git a/src/reskit/level/converter.rs b/src/reskit/level/converter.rs index 0b96a4e..531bc65 100644 --- a/src/reskit/level/converter.rs +++ b/src/reskit/level/converter.rs @@ -1,5 +1,6 @@ -use std::{error::Error, fs::read_to_string, path::Path, borrow::Cow}; +use std::{error::Error, fs::read_to_string, path::Path, borrow::Cow, collections::HashMap}; use image::{DynamicImage, GenericImageView}; +use regex::Regex; use roxmltree::Node; use crate::reskit::{utility::print_warning, cli::settings::TileOrder}; use super::ecs; @@ -9,6 +10,7 @@ pub struct TiledTilemap { pub tileset: Vec, pub layers: Vec, pub ecs: Vec, + pub ecs_component_ids: HashMap, pub width: usize, pub height: usize } @@ -252,8 +254,28 @@ pub fn get_tiled_tilemap( path: &str ) -> Result> { } // Get the entity-component system + let mut ecs_component_ids = HashMap::new(); let object_group = map.descendants().find( | node | node.tag_name() == "objectgroup".into() ); let ecs = if let Some( object_group ) = object_group { + let object_group_properties = object_group.descendants().find( | node | node.tag_name() == "properties".into() ); + if let Some( object_group_properties ) = object_group_properties { + let component_id_properties = object_group_properties.descendants() + .filter( | node | node.attribute( "name" ).unwrap_or( "" ).starts_with( "reskit-component-id" ) ); + for property in component_id_properties { + let name_attribute = property.attribute( "name" ).ok_or( "internal error: no name attribute" )?; + let id: u8 = property.attribute( "value" ).ok_or( "internal error: no property value in object layer" )?.parse()?; + + // Set up regex to remove individual parts + let regex = Regex::new( r#"reskit-component-id\[([a-z0-9_]+)\]"# )?; + let captures = regex.captures( name_attribute ).ok_or( "invalid file: invalid reskit-component-id key in object layer" )?; + let component_name = captures.get( 1 ).ok_or( "internal error: regex did not match properly" )?.as_str(); + ecs_component_ids.insert( component_name.to_owned(), id ); + } + } + + // Add the "position" component by default + ecs_component_ids.insert( "position".to_owned(), ecs_component_ids.len() as u8 ); + ecs::get_ecs( object_group )? } else { Vec::new() @@ -264,6 +286,7 @@ pub fn get_tiled_tilemap( path: &str ) -> Result> { tileset, layers, ecs, + ecs_component_ids, width, height } diff --git a/src/reskit/level/system.rs b/src/reskit/level/system.rs index 70e91bb..5d2e41e 100644 --- a/src/reskit/level/system.rs +++ b/src/reskit/level/system.rs @@ -226,8 +226,7 @@ pub fn get_ecs( tilemap: &TiledTilemap ) -> Result, Box> { let mut result: Vec = Vec::new(); - // Build a complete set of component IDs and types - let mut component_ids: LinkedHashSet = LinkedHashSet::new(); + // Build a complete set of types let mut types: LinkedHashSet> = LinkedHashSet::new(); for entity in &tilemap.ecs { // Get the list of components attached to this entity @@ -236,9 +235,6 @@ pub fn get_ecs( tilemap: &TiledTilemap ) -> Result, Box> { components.sort(); let components: LinkedHashSet = components.into_iter().collect(); - // Assign an index to each unique component id by inserting it into `component_ids` - component_ids.extend( components.clone() ); - // Assign this unique combination of components a type id // by inserting it into `types` types.insert_if_absent( components ); @@ -263,7 +259,7 @@ pub fn get_ecs( tilemap: &TiledTilemap ) -> Result, Box> { for component in ecs_type { type_component_ids.push( - component_ids.iter().position( | value | component == value ).ok_or( "internal error: no component" )? as u8 + *tilemap.ecs_component_ids.get( component ).ok_or( format!( "invalid file: undefined component symbol \"{}\"", component ) )? ); } @@ -387,12 +383,6 @@ pub fn get_ecs( tilemap: &TiledTilemap ) -> Result, Box> { } } - // Output IDs to terminal - let component_ids: Vec = component_ids.into_iter().collect(); - for i in 0..component_ids.len() { - print_info( &format!( "Component ID {}: {}", i, component_ids[ i ] ) ); - } - // Output type structures to terminal let mut visited_types: LinkedHashSet> = LinkedHashSet::new(); for entity in &tilemap.ecs {