75 percent done ECS exporter
parent
bd6136903d
commit
0360a875f2
|
@ -1,6 +1,6 @@
|
||||||
use std::{error::Error, fs::File, io::Write, path::Path};
|
use std::{error::Error, fs::File, io::Write, path::Path};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
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, system::{get_tiles, get_code, get_tilemap, get_collision_map}}};
|
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, system::{get_tiles, get_code, get_tilemap, get_collision_map, get_ecs}}};
|
||||||
use super::settings::{Args, Tools, TileOutputFormat, TileOrder};
|
use super::settings::{Args, Tools, TileOutputFormat, TileOrder};
|
||||||
|
|
||||||
pub fn run_command() -> Result<(), Box<dyn Error>> {
|
pub fn run_command() -> Result<(), Box<dyn Error>> {
|
||||||
|
@ -87,6 +87,10 @@ pub fn run_command() -> Result<(), Box<dyn Error>> {
|
||||||
nametables_bin.write_all( &get_collision_map( &tiled_file )? )?;
|
nametables_bin.write_all( &get_collision_map( &tiled_file )? )?;
|
||||||
print_good( "exported collision.lvc" );
|
print_good( "exported collision.lvc" );
|
||||||
|
|
||||||
|
let mut nametables_bin = File::create( format!( "{}objects.ecs", output_directory ) )?;
|
||||||
|
nametables_bin.write_all( &get_ecs( &tiled_file )? )?;
|
||||||
|
print_good( "exported objects.ecs" );
|
||||||
|
|
||||||
let mut code_asm = File::create( format!( "{}level.asm", output_directory ) )?;
|
let mut code_asm = File::create( format!( "{}level.asm", output_directory ) )?;
|
||||||
code_asm.write_all( &get_code( &tiled_file, "testlevel", "levels/" )?.as_bytes() )?;
|
code_asm.write_all( &get_code( &tiled_file, "testlevel", "levels/" )?.as_bytes() )?;
|
||||||
print_good( "exported level.asm" );
|
print_good( "exported level.asm" );
|
||||||
|
|
|
@ -8,7 +8,7 @@ use super::ecs;
|
||||||
pub struct TiledTilemap {
|
pub struct TiledTilemap {
|
||||||
pub tileset: Vec<TiledTileset>,
|
pub tileset: Vec<TiledTileset>,
|
||||||
pub layers: Vec<Layer>,
|
pub layers: Vec<Layer>,
|
||||||
ecs: Vec<ecs::Entity>,
|
pub ecs: Vec<ecs::Entity>,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize
|
pub height: usize
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{error::Error, convert::TryInto};
|
use std::{error::Error, convert::TryInto, cmp::max};
|
||||||
use image::GenericImageView;
|
use image::GenericImageView;
|
||||||
use crate::reskit::{tileset::image_to_tiles, utility::symbol_to_pascal, cli::settings::TileOrder};
|
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};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -215,6 +216,101 @@ pub fn get_collision_map( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Er
|
||||||
Ok( result )
|
Ok( result )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the entity-component system defined. If none is defined return an empty vec.
|
||||||
|
*/
|
||||||
|
pub fn get_ecs( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
if tilemap.ecs.is_empty() {
|
||||||
|
return Ok( vec![] )
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
// Build a complete set of component IDs and types
|
||||||
|
let mut component_ids: LinkedHashSet<String> = LinkedHashSet::new();
|
||||||
|
let mut types: LinkedHashSet<LinkedHashSet<String>> = LinkedHashSet::new();
|
||||||
|
for entity in &tilemap.ecs {
|
||||||
|
// Get the list of components attached to this entity
|
||||||
|
// Sort alphabetically as order matters in LinkedHashSets
|
||||||
|
let mut components: Vec<String> = entity.components.keys().map( | id | id.to_lowercase() ).collect();
|
||||||
|
components.sort();
|
||||||
|
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
|
||||||
|
// by inserting it into `types`
|
||||||
|
types.insert( components );
|
||||||
|
}
|
||||||
|
|
||||||
|
let largest_type_size: u16 = types.iter()
|
||||||
|
.map( | components | components.len() as u16 )
|
||||||
|
.reduce( | prev, current | max( prev, current ) )
|
||||||
|
.ok_or( "internal error: type is empty" )?;
|
||||||
|
|
||||||
|
// Type Table
|
||||||
|
// 2 bytes: Number of Types
|
||||||
|
result.extend( ( types.len() as u16 ).to_be_bytes() );
|
||||||
|
|
||||||
|
// 2 bytes: Type Definition Union Size
|
||||||
|
result.extend( largest_type_size.to_be_bytes() );
|
||||||
|
|
||||||
|
// For (Number of Types):
|
||||||
|
for ecs_type in &types {
|
||||||
|
// (Type Definition Union Size) bytes: List of Component IDs
|
||||||
|
let mut type_component_ids: Vec<u8> = vec![];
|
||||||
|
|
||||||
|
for component in ecs_type {
|
||||||
|
type_component_ids.push(
|
||||||
|
component_ids.iter().position( | value | component == value ).ok_or( "internal error: no component" )? as u8
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the remainder of the union with 0xFF, if needed
|
||||||
|
let remainder = largest_type_size as usize - type_component_ids.len();
|
||||||
|
for _ in 0..remainder {
|
||||||
|
type_component_ids.push( 0xFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
result.extend( type_component_ids );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object Table
|
||||||
|
// 2 bytes: Object Table Size
|
||||||
|
result.extend( ( 512 as u16 ).to_be_bytes() );
|
||||||
|
|
||||||
|
// For (Object Table Size)
|
||||||
|
for entity in &tilemap.ecs {
|
||||||
|
// Do the thing again
|
||||||
|
let mut components: Vec<String> = entity.components.keys().map( | id | id.to_lowercase() ).collect();
|
||||||
|
components.sort();
|
||||||
|
let components: LinkedHashSet<String> = components.into_iter().collect();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Output type id
|
||||||
|
result.push( type_id );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the remainder of the sparse Object Array with 0xFF, if needed
|
||||||
|
let remainder = 512 - tilemap.ecs.len();
|
||||||
|
for _ in 0..remainder {
|
||||||
|
result.push( 0xFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Component Attribute Table
|
||||||
|
|
||||||
|
// 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 ] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok( result )
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a helper .asm or .c file that ties all the level components together
|
* Get a helper .asm or .c file that ties all the level components together
|
||||||
*/
|
*/
|
||||||
|
@ -246,12 +342,16 @@ pub fn get_code( tilemap: &TiledTilemap, level_name: &str, path_prefix: &str ) -
|
||||||
{level_label}Collision:
|
{level_label}Collision:
|
||||||
incbin '{path_prefix}{level_name}/collision.lvc'
|
incbin '{path_prefix}{level_name}/collision.lvc'
|
||||||
|
|
||||||
|
{level_label}Objects:
|
||||||
|
incbin '{path_prefix}{level_name}/objects.ecs'
|
||||||
|
|
||||||
{level_label}:
|
{level_label}:
|
||||||
dc.w {width}, {height}, {num_tiles}
|
dc.w {width}, {height}, {num_tiles}
|
||||||
dc.l {level_label}Tiles
|
dc.l {level_label}Tiles
|
||||||
dc.l {level_label}Palettes
|
dc.l {level_label}Palettes
|
||||||
dc.l {level_label}Nametables
|
dc.l {level_label}Nametables
|
||||||
dc.l {level_label}Collision"# );
|
dc.l {level_label}Collision
|
||||||
|
dc.l {level_label}Objects"# );
|
||||||
|
|
||||||
Ok( file )
|
Ok( file )
|
||||||
}
|
}
|
Loading…
Reference in New Issue