Allow user-specified component ids in ECS

stinkhead7ds
Ashley N. 2023-09-22 10:23:08 -04:00
parent 6e63b9c40f
commit 31832e8882
2 changed files with 26 additions and 13 deletions

View File

@ -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 image::{DynamicImage, GenericImageView};
use regex::Regex;
use roxmltree::Node; use roxmltree::Node;
use crate::reskit::{utility::print_warning, cli::settings::TileOrder}; use crate::reskit::{utility::print_warning, cli::settings::TileOrder};
use super::ecs; use super::ecs;
@ -9,6 +10,7 @@ pub struct TiledTilemap {
pub tileset: Vec<TiledTileset>, pub tileset: Vec<TiledTileset>,
pub layers: Vec<Layer>, pub layers: Vec<Layer>,
pub ecs: Vec<ecs::Entity>, pub ecs: Vec<ecs::Entity>,
pub ecs_component_ids: HashMap<String, u8>,
pub width: usize, pub width: usize,
pub height: usize pub height: usize
} }
@ -252,8 +254,28 @@ pub fn get_tiled_tilemap( path: &str ) -> Result<TiledTilemap, Box<dyn Error>> {
} }
// Get the entity-component system // 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 object_group = map.descendants().find( | node | node.tag_name() == "objectgroup".into() );
let ecs = if let Some( object_group ) = object_group { 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 )? ecs::get_ecs( object_group )?
} else { } else {
Vec::new() Vec::new()
@ -264,6 +286,7 @@ pub fn get_tiled_tilemap( path: &str ) -> Result<TiledTilemap, Box<dyn Error>> {
tileset, tileset,
layers, layers,
ecs, ecs,
ecs_component_ids,
width, width,
height height
} }

View File

@ -226,8 +226,7 @@ pub fn get_ecs( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>> {
let mut result: Vec<u8> = Vec::new(); let mut result: Vec<u8> = Vec::new();
// Build a complete set of component IDs and types // Build a complete set of types
let mut component_ids: LinkedHashSet<String> = LinkedHashSet::new();
let mut types: LinkedHashSet<LinkedHashSet<String>> = LinkedHashSet::new(); let mut types: LinkedHashSet<LinkedHashSet<String>> = LinkedHashSet::new();
for entity in &tilemap.ecs { for entity in &tilemap.ecs {
// Get the list of components attached to this entity // Get the list of components attached to this entity
@ -236,9 +235,6 @@ pub fn get_ecs( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>> {
components.sort(); components.sort();
let components: LinkedHashSet<String> = components.into_iter().collect(); let components: LinkedHashSet<String> = 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 // Assign this unique combination of components a type id
// by inserting it into `types` // by inserting it into `types`
types.insert_if_absent( components ); types.insert_if_absent( components );
@ -263,7 +259,7 @@ pub fn get_ecs( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>> {
for component in ecs_type { for component in ecs_type {
type_component_ids.push( 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<Vec<u8>, Box<dyn Error>> {
} }
} }
// Output IDs to terminal
let component_ids: Vec<String> = 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 // Output type structures to terminal
let mut visited_types: LinkedHashSet<LinkedHashSet<String>> = LinkedHashSet::new(); let mut visited_types: LinkedHashSet<LinkedHashSet<String>> = LinkedHashSet::new();
for entity in &tilemap.ecs { for entity in &tilemap.ecs {