Write component attribute table to .ecs file

stinkhead7ds
Ashley N. 2023-09-20 23:03:17 -04:00
parent 0360a875f2
commit efa2c24487
1 changed files with 81 additions and 4 deletions

View File

@ -1,8 +1,8 @@
use std::{error::Error, convert::TryInto, cmp::max};
use std::{error::Error, convert::TryInto, cmp::max, num::ParseIntError};
use image::GenericImageView;
use linked_hash_set::LinkedHashSet;
use crate::reskit::{tileset::image_to_tiles, utility::{symbol_to_pascal, print_info}, cli::settings::TileOrder};
use super::converter::{TiledTilemap, Layer, SystemPlane};
use super::{converter::{TiledTilemap, Layer, SystemPlane}, ecs::Component};
/**
* Output the .bin and .pal file (using `tileset` tool to build it) containing each of the tiles
@ -241,7 +241,7 @@ pub fn get_ecs( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>> {
// Assign this unique combination of components a type id
// by inserting it into `types`
types.insert( components );
types.insert_if_absent( components );
}
let largest_type_size: u16 = types.iter()
@ -300,7 +300,84 @@ pub fn get_ecs( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>> {
result.push( 0xFF );
}
// TODO: Component Attribute Table
// Component Attribute Table
// Index all attribute values that do not parse to u16
let mut attribute_value_ids: LinkedHashSet<String> = LinkedHashSet::new();
for entity in &tilemap.ecs {
for ( _, component ) in &entity.components {
for ( _, attribute_value ) in &component.attributes {
// Handling various types from Tiled Editor
// * If it is "true" or "false", leave it alone. It will be articulated as 1 or 0.
// * If it can be parsed as a u16, leave it alone.
// * In all other cases, add to attribute_value_ids to create an index.
if attribute_value != "true" && attribute_value != "false" {
let try_as_u16: Result<u16, ParseIntError> = attribute_value.parse();
if let Err( _ ) = try_as_u16 {
attribute_value_ids.insert_if_absent( attribute_value.clone() );
print_info( &format!( "Attribute Value ID {}: \"{}\"", attribute_value_ids.len() - 1, attribute_value ) );
}
}
}
}
}
// Find the largest size of a combination of attributes (the component attribute union size)
let largest_type_attributes_size = tilemap.ecs.iter()
.map( | entity | {
let mut total_attributes_for_entity = 0;
for ( _, component ) in &entity.components {
total_attributes_for_entity += component.attributes.len()
}
total_attributes_for_entity
} )
.reduce( | prev, current | max( prev, current ) )
.ok_or( "internal error: no largest type attributes size" )? as u16;
// 2 bytes: Component Attribute Union Size
result.extend( largest_type_attributes_size.to_be_bytes() );
// For (Object Table Size):
for entity in &tilemap.ecs {
// (Component Attribute Union Size) bytes: Component attribute settings
// Sort components in this entity alphabetically, ascending
let mut components: Vec<(&String, &Component)> = entity.components.iter().collect();
components.sort_by( | a, b | a.0.partial_cmp( b.0 ).expect( "internal error: unsortable" ) );
let mut written_attributes = 0;
for ( _, component ) in &components {
// Sort attributes in each component alphabetically
let mut attributes: Vec<(&String, &String)> = component.attributes.iter().collect();
attributes.sort_by( | a, b | a.0.partial_cmp( b.0 ).expect( "internal error: unsortable" ) );
for ( _, attribute_value ) in attributes {
written_attributes += 1;
match attribute_value.as_str() {
"true" => result.extend( ( 1 as u16 ).to_be_bytes() ),
"false" => result.extend( ( 0 as u16 ).to_be_bytes() ),
string => {
let try_as_u16: Result<u16, ParseIntError> = string.parse();
if let Ok( numeric ) = try_as_u16 {
result.extend( numeric.to_be_bytes() );
} else {
let id: u16 = attribute_value_ids.iter()
.position( | attribute_value | attribute_value == &string )
.ok_or( "internal error: no type id" )? as u16;
result.extend( id.to_be_bytes() );
}
}
}
}
}
// Fill the remainder of the union with 0xFF, if needed
let remainder = largest_type_attributes_size - written_attributes;
for _ in 0..remainder {
result.extend( ( 0xFFFF as u16 ).to_be_bytes() );
}
}
// Output IDs to terminal
let component_ids: Vec<String> = component_ids.into_iter().collect();