Consistent ordering of components and attributes on export

stinkhead7ds
Ashley N. 2023-09-25 21:31:32 -04:00
parent 73b5ba6cc7
commit 07a7ee97b7
1 changed files with 19 additions and 19 deletions

View File

@ -1,8 +1,7 @@
use std::{error::Error, convert::TryInto, cmp::max, num::ParseIntError, collections::HashMap}; use std::{error::Error, convert::TryInto, cmp::max, num::ParseIntError, collections::HashMap};
use image::GenericImageView; 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 crate::reskit::{tileset::image_to_tiles, utility::{symbol_to_pascal, print_info}, cli::settings::TileOrder};
use super::converter::{TiledTilemap, Layer, SystemPlane, TiledTileset}; use super::{converter::{TiledTilemap, Layer, SystemPlane, TiledTileset}, ecs::Component};
/** /**
* Output the .bin and .pal file (using `tileset` tool to build it) containing each of the tiles * Output the .bin and .pal file (using `tileset` tool to build it) containing each of the tiles
@ -227,14 +226,18 @@ pub fn get_ecs( tilemap: &TiledTilemap, component_ids: &HashMap<String, u8>, att
let mut result: Vec<u8> = Vec::new(); let mut result: Vec<u8> = Vec::new();
// Build a complete set of types // Build a complete set of types
let mut types: LinkedHashSet<LinkedHashSet<String>> = LinkedHashSet::new(); let mut types: Vec<Vec<u8>> = Vec::new();
for entity in &tilemap.ecs { for entity in &tilemap.ecs {
// Get the list of components attached to this entity // Get the list of component IDs attached to this entity
let components: LinkedHashSet<String> = entity.components.keys().map( | id | id.to_lowercase() ).collect(); let mut components: Vec<u8> = entity.components.keys()
.map( | id | Ok( *component_ids.get( id ).ok_or( format!( "invalid file: when building type table: undefined component \"{}\"", id ) )? ) )
.collect::<Result<Vec<u8>, Box<dyn Error>>>()?;
components.sort();
// 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` if let None = types.iter().find( | ecs_type | ecs_type == &&components ) {
types.insert_if_absent( components ); types.push( components );
}
} }
let largest_type_size: u16 = types.iter() let largest_type_size: u16 = types.iter()
@ -252,13 +255,7 @@ pub fn get_ecs( tilemap: &TiledTilemap, component_ids: &HashMap<String, u8>, att
// For (Number of Types): // For (Number of Types):
for ecs_type in &types { for ecs_type in &types {
// (Type Definition Union Size) bytes: List of Component IDs // (Type Definition Union Size) bytes: List of Component IDs
let mut type_component_ids: Vec<u8> = vec![]; let mut type_component_ids: Vec<u8> = ecs_type.clone();
for component in ecs_type {
type_component_ids.push(
*component_ids.get( component ).ok_or( format!( "invalid file: when building type table: undefined component \"{}\"", component ) )?
);
}
// Fill the remainder of the union with 0xFF, if needed // Fill the remainder of the union with 0xFF, if needed
let remainder = largest_type_size as usize - type_component_ids.len(); let remainder = largest_type_size as usize - type_component_ids.len();
@ -275,10 +272,10 @@ pub fn get_ecs( tilemap: &TiledTilemap, component_ids: &HashMap<String, u8>, att
// For (Object Table Size) // For (Object Table Size)
for entity in &tilemap.ecs { for entity in &tilemap.ecs {
// Do the thing again let mut components: Vec<u8> = entity.components.keys()
let mut components: Vec<String> = entity.components.keys().map( | id | id.to_lowercase() ).collect(); .map( | id | Ok( *component_ids.get( id ).ok_or( format!( "invalid file: when building type table: undefined component \"{}\"", id ) )? ) )
.collect::<Result<Vec<u8>, Box<dyn Error>>>()?;
components.sort(); components.sort();
let components: LinkedHashSet<String> = components.into_iter().collect();
// What type id is this? // What type id is this?
let type_id: u8 = types.iter().position( | ecs_type | ecs_type == &components ).ok_or( "internal error: no type id" )? as u8; let type_id: u8 = types.iter().position( | ecs_type | ecs_type == &components ).ok_or( "internal error: no type id" )? as u8;
@ -314,7 +311,10 @@ pub fn get_ecs( tilemap: &TiledTilemap, component_ids: &HashMap<String, u8>, att
for entity in &tilemap.ecs { for entity in &tilemap.ecs {
let mut written_attributes = 0; let mut written_attributes = 0;
for ( component_id, component ) in &entity.components { let mut components: Vec<(&String, &Component)> = entity.components.iter().collect();
components.sort_by_key( | ( component_id, _ ) | component_ids[ *component_id ] );
for ( component_id, component ) in components {
let attributes_in_order = attribute_ids.get( component_id ); let attributes_in_order = attribute_ids.get( component_id );
if let Some( attributes_in_order ) = attributes_in_order { if let Some( attributes_in_order ) = attributes_in_order {
for attribute_id in attributes_in_order { for attribute_id in attributes_in_order {