Add ECS parsing
parent
0543d9adfc
commit
dc10213f75
|
@ -17,4 +17,5 @@ pitch_shift = "1.0.0"
|
|||
linked_hash_set = "0.1.4"
|
||||
linked-hash-map = "0.5.6"
|
||||
convert_case = "0.6.0"
|
||||
roxmltree = "0.18.0"
|
||||
roxmltree = "0.18.0"
|
||||
regex = "1.9.5"
|
|
@ -1,6 +1,6 @@
|
|||
use std::{error::Error, fs::File, io::Write, path::Path};
|
||||
use clap::Parser;
|
||||
use crate::reskit::{tileset, soundtrack::{formats::dmf::DmfModule, engines::echo::engine::{EchoFormat, EchoArtifact}}, utility::{print_good, print_error}, level::converter::get_tiled_tilemap};
|
||||
use crate::reskit::{tileset, soundtrack::{formats::dmf::DmfModule, engines::echo::engine::{EchoFormat, EchoArtifact}}, utility::{print_good, print_error, print_info}, level::converter::get_tiled_tilemap};
|
||||
use super::settings::{Args, Tools, TileOutputFormat, TileOrder};
|
||||
|
||||
pub fn run_command() -> Result<(), Box<dyn Error>> {
|
||||
|
@ -67,7 +67,7 @@ pub fn run_command() -> Result<(), Box<dyn Error>> {
|
|||
}
|
||||
Tools::Level { input_file, output_directory, console, tile_size } => {
|
||||
let tiled_file = get_tiled_tilemap( &input_file )?;
|
||||
|
||||
print_info( &format!( "{:#?}", tiled_file ) );
|
||||
print_good( "file opened without errors" );
|
||||
print_error( "unimplemented" );
|
||||
}
|
||||
|
|
|
@ -1,27 +1,32 @@
|
|||
use std::{error::Error, fs::read_to_string};
|
||||
use image::DynamicImage;
|
||||
use roxmltree::Node;
|
||||
|
||||
use crate::reskit::utility::print_warning;
|
||||
use super::ecs;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TiledTilemap {
|
||||
tileset: TiledTileset,
|
||||
layers: Vec<Layer>,
|
||||
ecs: Vec<ecs::Entity>,
|
||||
width: usize,
|
||||
height: usize,
|
||||
tile_width: usize,
|
||||
tile_height: usize
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TiledTileset {
|
||||
image: DynamicImage
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SystemPlane {
|
||||
MdPlaneA,
|
||||
MdPlaneB
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Layer {
|
||||
Tile {
|
||||
system_plane: SystemPlane,
|
||||
|
@ -165,10 +170,19 @@ pub fn get_tiled_tilemap( path: &str ) -> Result<TiledTilemap, Box<dyn Error>> {
|
|||
print_warning( "tile map has no \"collision\" layer: this probably is not what you want" );
|
||||
}
|
||||
|
||||
// Get the entity-component system
|
||||
let object_group = map.descendants().find( | node | node.tag_name() == "objectgroup".into() );
|
||||
let ecs = if let Some( object_group ) = object_group {
|
||||
ecs::get_ecs( object_group )?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
Ok(
|
||||
TiledTilemap {
|
||||
tileset: TiledTileset { image },
|
||||
layers,
|
||||
ecs,
|
||||
width,
|
||||
height,
|
||||
tile_width,
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
use std::{error::Error, collections::HashMap};
|
||||
use regex::Regex;
|
||||
use roxmltree::Node;
|
||||
use crate::reskit::utility::print_warning;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Entity {
|
||||
pub components: HashMap<String, Component>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Component {
|
||||
pub attributes: HashMap<String, String>
|
||||
}
|
||||
|
||||
pub fn get_ecs( object_group: Node ) -> Result<Vec<Entity>, Box<dyn Error>> {
|
||||
let mut entities: Vec<Entity> = Vec::new();
|
||||
|
||||
let objects: Vec<Node> = object_group.descendants().filter( | node | node.tag_name() == "object".into() ).collect();
|
||||
for object in objects {
|
||||
let object_id = object.attribute( "id" ).ok_or( "invalid file: no id attribute set on object" )?;
|
||||
let object_name = object.attribute( "name" ).unwrap_or( "<no name>" );
|
||||
let object_name = format!( "({}, ID: {})", object_id, object_name );
|
||||
|
||||
let mut entity: Entity = Entity {
|
||||
components: HashMap::new()
|
||||
};
|
||||
|
||||
// Get attributes for implicit `position` component
|
||||
let x = object.attribute( "x" ).ok_or( "invalid file: position property not present on object" )?;
|
||||
let y = object.attribute( "y" ).ok_or( "invalid file: position property not present on object" )?;
|
||||
let width = object.attribute( "width" ).ok_or( "invalid file: position property not present on object" )?;
|
||||
let height = object.attribute( "height" ).ok_or( "invalid file: position property not present on object" )?;
|
||||
|
||||
entity.components.insert(
|
||||
format!( "position" ),
|
||||
Component {
|
||||
attributes: HashMap::from( [
|
||||
( format!( "x" ), x.to_owned() ),
|
||||
( format!( "y" ), y.to_owned() ),
|
||||
( format!( "width" ), width.to_owned() ),
|
||||
( format!( "height" ), height.to_owned() )
|
||||
] )
|
||||
}
|
||||
);
|
||||
|
||||
let properties = object.descendants().find( | node | node.tag_name() == "properties".into() ).ok_or( "invalid file: no properties in object" )?;
|
||||
let properties = properties.descendants().filter( | node | node.tag_name() == "property".into() && node.attribute( "name" ).unwrap_or( "" ).starts_with( "reskit-component" ) );
|
||||
for component_property in properties {
|
||||
let name = component_property.attribute( "name" ).ok_or( "internal error: name attribute expected" )?;
|
||||
let prop_type = component_property.attribute( "type" ).unwrap_or( "string" );
|
||||
let value = component_property.attribute( "value" );
|
||||
|
||||
if let Some( value ) = value {
|
||||
// Set up regex to remove individual parts
|
||||
let regex = Regex::new( r#"reskit-component\[([a-z0-9_]+)\](\.[a-z0-9_]*)?"# )?;
|
||||
if let Some( captures ) = regex.captures( name ) {
|
||||
let component_name = captures.get( 1 ).ok_or( "internal error: regex did not match properly" )?.as_str();
|
||||
let attribute_name = captures.get( 2 );
|
||||
|
||||
if let Some( attribute_name ) = attribute_name {
|
||||
// Setting is a component attribute setting ("value" is the setting)
|
||||
let attribute_name = attribute_name.as_str().replace( ".", "" );
|
||||
if let Some( component ) = entity.components.get_mut( component_name ) {
|
||||
component.attributes.insert( attribute_name, value.to_owned() );
|
||||
} else {
|
||||
return Err( format!( "in object {}: undefined component in reskit-component definition \"{}\"", object_name, name ) )?;
|
||||
}
|
||||
} else {
|
||||
// Setting is a component definition
|
||||
if prop_type != "bool" {
|
||||
print_warning( &format!( "in object {}: non-bool type reskit-component definition \"{}\". ignoring...", object_name, name ) );
|
||||
} else {
|
||||
if value == "true" {
|
||||
if entity.components.contains_key( component_name ) {
|
||||
print_warning( &format!( "in object {}: duplicate reskit-component definition \"{}\". ignoring...", object_name, name ) );
|
||||
} else {
|
||||
entity.components.insert(
|
||||
component_name.to_owned(),
|
||||
Component { attributes: HashMap::new() }
|
||||
);
|
||||
}
|
||||
} else {
|
||||
print_warning( &format!( "in object {}: reskit-component definition \"{}\" is set to false. ignoring...", object_name, name ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print_warning( &format!( "in object {}: invalid format for reskit-component attribute \"{}\". ignoring...", object_name, name ) );
|
||||
}
|
||||
} else {
|
||||
print_warning( &format!( "in object {}: no value for reskit-component attribute \"{}\". ignoring...", object_name, name ) );
|
||||
}
|
||||
}
|
||||
|
||||
entities.push( entity );
|
||||
}
|
||||
|
||||
Ok( entities )
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
pub mod converter;
|
||||
pub mod ecs;
|
Loading…
Reference in New Issue