engine/entity_manager/src/entityparser.rs

320 lines
10 KiB
Rust
Raw Normal View History

2024-08-23 11:22:09 +00:00
#![allow(unused)]
use assetpath::AssetPath;
use anyhow::Result;
use engine::prelude::*;
2024-08-25 07:11:52 +00:00
use crate::animation_info::AnimationType;
use super::entity_tags::EntityTags;
2024-08-23 11:22:09 +00:00
use std::collections::HashMap;
use std::{fmt::Display, str::FromStr, time::Duration};
// parse state keys
const META_KEY: &str = "Meta";
const ANIMATION_KEY: &str = "Animation";
const AUDIO_KEY: &str = "Sounds";
// meta information keys
const GLTF_FILE_NAME: &str = "Object";
const ENTITY_TAGS: &str = "Tags";
const HITBOX: &str = "HitBox";
const HITBOX_RADIUS: &str = "HitboxRadius";
const HITBOX_HEIGHT: &str = "HitboxHeight";
// animation information keys
const ANIMATION_DATA_KEY: &str = "Info";
const ANIMATION_MOVE_KEY: &str = "Move";
const ANIMATION_IDLE_KEY: &str = "Idle";
const ANIMATION_CAST_KEY: &str = "Cast";
const ANIMATION_ATTACK_KEY: &str = "Attack";
// sound information keys
pub const SOUND_MOVE_KEY: &str = "Move";
pub const SOUND_CREATE_KEY: &str = ON_ENABLE_SOUND;
pub const SOUND_DESTROY_KEY: &str = ON_DISABLE_SOUND;
// TODO: more
pub fn split_matches(s: &str, c: char) -> (&str, &str) {
match s.find(c) {
Some(pos) => {
let (f, l) = s.split_at(pos);
let l = l.trim_start_matches(c);
(f, l)
}
None => (s, ""),
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct AnimationData {
pub index: u32,
pub name: String,
pub duration: Duration,
}
impl FromStr for AnimationData {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (index, rest) = split_matches(s, ';');
let (name, duration) = split_matches(rest, ';');
Ok(Self {
index: index.parse()?,
name: name.to_string(),
duration: PersistentDuration::from_str(duration)?.into(),
})
}
}
impl Display for AnimationData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{};{};{}",
self.index,
self.name,
PersistentDuration::from(self.duration)
)
}
}
pub struct EntityParser {
pub enable_hitbox: bool,
pub hitbox_radius: f32,
pub hitbox_height: f32,
pub gltf_file_name: String,
pub tags: Vec<EntityTags>,
pub animations: Vec<AnimationData>,
pub animation_map: HashMap<AnimationType, Vec<u32>>,
pub sound_map: HashMap<String, AssetPath>,
}
impl EntityParser {
pub fn parse(file: &AssetPath) -> Result<EntityParser> {
let mut entity_parser = EntityParser::default();
let parsed_entity = ConfigHandler::read_config(&file.full_path())?;
if let Some(info) = parsed_entity.get(META_KEY) {
if let Some(key_value) = info.get(GLTF_FILE_NAME) {
entity_parser.gltf_file_name = key_value.to_value()?;
}
if let Some(key_value) = info.get(HITBOX) {
entity_parser.enable_hitbox = key_value.to_value()?;
}
if let Some(key_value) = info.get(HITBOX_RADIUS) {
entity_parser.hitbox_radius = key_value.to_value()?;
}
if let Some(key_value) = info.get(HITBOX_HEIGHT) {
entity_parser.hitbox_height = key_value.to_value()?;
}
if let Some(key_value) = info.get(ENTITY_TAGS) {
let tag_strings: Vec<String> = key_value.to_array()?;
for tag_string in tag_strings {
match tag_string.as_str() {
"Ability" => {
if !entity_parser.tags.contains(&EntityTags::Ability) {
entity_parser.tags.push(EntityTags::Ability);
}
}
"WorldObject" => {
if !entity_parser.tags.contains(&EntityTags::WorldObject) {
entity_parser.tags.push(EntityTags::WorldObject);
}
}
"Creature" => {
if !entity_parser.tags.contains(&EntityTags::Creature) {
entity_parser.tags.push(EntityTags::Creature);
}
}
_ => (),
}
}
}
}
if let Some(info) = parsed_entity.get(ANIMATION_KEY) {
if let Some(key_value) = info.get(ANIMATION_DATA_KEY) {
entity_parser.animations = key_value.to_array()?;
}
if let Some(key_value) = info.get(ANIMATION_MOVE_KEY) {
Self::insert_animation(
key_value,
&mut entity_parser.animation_map,
AnimationType::Move,
)?;
}
if let Some(key_value) = info.get(ANIMATION_IDLE_KEY) {
Self::insert_animation(
key_value,
&mut entity_parser.animation_map,
AnimationType::Idle,
)?;
}
if let Some(key_value) = info.get(ANIMATION_ATTACK_KEY) {
Self::insert_animation(
key_value,
&mut entity_parser.animation_map,
AnimationType::Attack,
)?;
}
if let Some(key_value) = info.get(ANIMATION_CAST_KEY) {
Self::insert_animation(
key_value,
&mut entity_parser.animation_map,
AnimationType::Cast,
)?;
}
}
if let Some(info) = parsed_entity.get(AUDIO_KEY) {
if let Some(key_value) = info.get(SOUND_MOVE_KEY) {
Self::insert_sound(key_value, &mut entity_parser.sound_map, SOUND_MOVE_KEY)?;
}
if let Some(key_value) = info.get(SOUND_CREATE_KEY) {
Self::insert_sound(key_value, &mut entity_parser.sound_map, SOUND_CREATE_KEY)?;
}
if let Some(key_value) = info.get(SOUND_DESTROY_KEY) {
Self::insert_sound(key_value, &mut entity_parser.sound_map, SOUND_DESTROY_KEY)?;
}
}
Ok(entity_parser)
}
pub fn save(&self, file: &str) -> Result<()> {
let data = vec![
(
META_KEY,
vec![
(GLTF_FILE_NAME, Value::from(&self.gltf_file_name)),
(ENTITY_TAGS, Value::from(self.tags.as_slice())),
(HITBOX, Value::from(&self.enable_hitbox)),
(HITBOX_RADIUS, Value::from(&self.hitbox_radius)),
(HITBOX_HEIGHT, Value::from(&self.hitbox_height)),
],
),
(
ANIMATION_KEY,
vec![
(ANIMATION_DATA_KEY, Value::from(self.animations.as_slice())),
(
ANIMATION_MOVE_KEY,
match self.animation_map.get(&AnimationType::Move) {
Some(indices) => Value::from(indices.as_slice()),
None => Value::empty_array(),
},
),
(
ANIMATION_CAST_KEY,
match self.animation_map.get(&AnimationType::Cast) {
Some(indices) => Value::from(indices.as_slice()),
None => Value::empty_array(),
},
),
(
ANIMATION_IDLE_KEY,
match self.animation_map.get(&AnimationType::Idle) {
Some(indices) => Value::from(indices.as_slice()),
None => Value::empty_array(),
},
),
(
ANIMATION_ATTACK_KEY,
match self.animation_map.get(&AnimationType::Attack) {
Some(indices) => Value::from(indices.as_slice()),
None => Value::empty_array(),
},
),
],
),
(
AUDIO_KEY,
vec![
(
SOUND_MOVE_KEY,
match self.sound_map.get(SOUND_MOVE_KEY) {
Some(file_name) => Value::from(&file_name),
None => Value::empty(),
},
),
(
SOUND_CREATE_KEY,
match self.sound_map.get(SOUND_CREATE_KEY) {
Some(file_name) => Value::from(&file_name),
None => Value::empty(),
},
),
(
SOUND_DESTROY_KEY,
match self.sound_map.get(SOUND_DESTROY_KEY) {
Some(file_name) => Value::from(&file_name),
None => Value::empty(),
},
),
],
),
];
Ok(ConfigHandler::write_config(file, &data)?)
}
fn insert_animation(
key_value: &Value,
animation_map: &mut HashMap<AnimationType, Vec<u32>>,
animation_type: AnimationType,
) -> Result<()> {
animation_map.insert(animation_type, key_value.to_array()?);
Ok(())
}
fn insert_sound(
key_value: &Value,
sound_map: &mut HashMap<String, AssetPath>,
sound_type: &str,
) -> Result<()> {
sound_map.insert(sound_type.to_string(), key_value.to_value()?);
Ok(())
}
}
impl Default for EntityParser {
fn default() -> EntityParser {
EntityParser {
enable_hitbox: false,
hitbox_radius: 0.0,
hitbox_height: 0.0,
gltf_file_name: String::new(),
animations: Vec::new(),
animation_map: HashMap::new(),
sound_map: HashMap::new(),
tags: Vec::new(),
}
}
}