Implement attack script baking
This commit is contained in:
+9
-12
@@ -1,12 +1,8 @@
|
|||||||
|
use bevy::reflect::Reflect;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::math::{int::FGi32, vec3::FGVec3};
|
use crate::math::{int::FGi32, vec3::FGVec3};
|
||||||
|
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||||
|
|
||||||
pub struct FighterMoveManifest {
|
|
||||||
script_path: String,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
|
||||||
pub struct FighterDamage(FGi32);
|
pub struct FighterDamage(FGi32);
|
||||||
|
|
||||||
impl FighterDamage {
|
impl FighterDamage {
|
||||||
@@ -15,7 +11,7 @@ impl FighterDamage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum KnockbackType {
|
pub enum KnockbackType {
|
||||||
Normal,
|
Normal,
|
||||||
Fixed
|
Fixed
|
||||||
@@ -31,7 +27,7 @@ impl KnockbackType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||||
pub struct Knockback(FGi32);
|
pub struct Knockback(FGi32);
|
||||||
|
|
||||||
impl Knockback {
|
impl Knockback {
|
||||||
@@ -40,7 +36,7 @@ impl Knockback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum AttackAngle {
|
pub enum AttackAngle {
|
||||||
Normal(FGi32),
|
Normal(FGi32),
|
||||||
Sakurai
|
Sakurai
|
||||||
@@ -63,7 +59,8 @@ impl AttackAngle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Reflect, Serialize, Deserialize)]
|
||||||
|
#[reflect(opaque)]
|
||||||
pub struct AttackHitbox {
|
pub struct AttackHitbox {
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub bone: String,
|
pub bone: String,
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ impl Plugin for GamePlugin {
|
|||||||
input::FighterInputPlugin,
|
input::FighterInputPlugin,
|
||||||
fighter::FighterPlugin,
|
fighter::FighterPlugin,
|
||||||
fighter::baked_animation::BakedAnimationPlugin,
|
fighter::baked_animation::BakedAnimationPlugin,
|
||||||
|
scripting::importer::FighterScriptImportPlugin,
|
||||||
stage::StagePlugin,
|
stage::StagePlugin,
|
||||||
MatchCameraPlugin,
|
MatchCameraPlugin,
|
||||||
bevy_common_assets::ron::RonAssetPlugin::<FighterManifest>::new(&["fighter.ron"]),
|
bevy_common_assets::ron::RonAssetPlugin::<FighterManifest>::new(&["fighter.ron"]),
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use bevy::{asset::{AssetLoader, AssetPath, AsyncReadExt, AsyncWriteExt, LoadContext, io::{Reader, Writer}, processor::LoadTransformAndSave, saver::{AssetSaver, SavedAsset}, transformer::{AssetTransformer, TransformedAsset}}, prelude::*};
|
||||||
|
|
||||||
|
use crate::scripting::{FighterAttackScript, move_compiler};
|
||||||
|
|
||||||
|
#[derive(Default, TypePath)]
|
||||||
|
struct FighterAttackScriptSourceLoader;
|
||||||
|
|
||||||
|
#[derive(Asset, TypePath)]
|
||||||
|
struct FighterAttackScriptContents(String);
|
||||||
|
|
||||||
|
impl AssetLoader for FighterAttackScriptSourceLoader {
|
||||||
|
type Asset = FighterAttackScriptContents;
|
||||||
|
type Settings = ();
|
||||||
|
type Error = io::Error;
|
||||||
|
|
||||||
|
async fn load(
|
||||||
|
&self,
|
||||||
|
reader: &mut dyn Reader,
|
||||||
|
_: &Self::Settings,
|
||||||
|
_: &mut LoadContext<'_>,
|
||||||
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
|
let mut contents = String::default();
|
||||||
|
reader.read_to_string(&mut contents).await?;
|
||||||
|
Ok(FighterAttackScriptContents(contents))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extensions(&self) -> &[&str] {
|
||||||
|
&["attack.rhai"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, TypePath)]
|
||||||
|
struct FighterAttackScriptTransformer;
|
||||||
|
|
||||||
|
impl AssetTransformer for FighterAttackScriptTransformer {
|
||||||
|
type AssetInput = FighterAttackScriptContents;
|
||||||
|
type AssetOutput = FighterAttackScript;
|
||||||
|
type Settings = ();
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
async fn transform<'a>(
|
||||||
|
&'a self,
|
||||||
|
source: TransformedAsset<Self::AssetInput>,
|
||||||
|
_: &'a Self::Settings,
|
||||||
|
) -> Result<TransformedAsset<Self::AssetOutput>, Self::Error> {
|
||||||
|
let output = move_compiler::compile_script(&source.0)?;
|
||||||
|
Ok(source.replace_asset(output))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Default, TypePath)]
|
||||||
|
struct FighterAttackScriptLoader;
|
||||||
|
|
||||||
|
impl AssetLoader for FighterAttackScriptLoader {
|
||||||
|
type Asset = FighterAttackScript;
|
||||||
|
type Settings = ();
|
||||||
|
type Error = io::Error;
|
||||||
|
|
||||||
|
async fn load(
|
||||||
|
&self,
|
||||||
|
reader: &mut dyn Reader,
|
||||||
|
_: &Self::Settings,
|
||||||
|
_: &mut LoadContext<'_>,
|
||||||
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
reader.read_to_end(&mut bytes).await?;
|
||||||
|
bincode::deserialize(&bytes)
|
||||||
|
.map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extensions(&self) -> &[&str] {
|
||||||
|
&["attack.rhai"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, TypePath)]
|
||||||
|
struct FighterAttackScriptSaver;
|
||||||
|
|
||||||
|
impl AssetSaver for FighterAttackScriptSaver {
|
||||||
|
type Asset = FighterAttackScript;
|
||||||
|
type Settings = ();
|
||||||
|
type OutputLoader = FighterAttackScriptLoader;
|
||||||
|
type Error = io::Error;
|
||||||
|
|
||||||
|
async fn save(
|
||||||
|
&self,
|
||||||
|
writer: &mut Writer,
|
||||||
|
asset: SavedAsset<'_, '_, Self::Asset>,
|
||||||
|
_: &Self::Settings,
|
||||||
|
_: AssetPath<'_>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let bytes = bincode::serialize(&*asset)
|
||||||
|
.map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;
|
||||||
|
writer.write_all(&bytes).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FighterAttackScriptProcessor = LoadTransformAndSave<
|
||||||
|
FighterAttackScriptSourceLoader,
|
||||||
|
FighterAttackScriptTransformer,
|
||||||
|
FighterAttackScriptSaver,
|
||||||
|
>;
|
||||||
|
|
||||||
|
pub struct FighterScriptImportPlugin;
|
||||||
|
|
||||||
|
impl Plugin for FighterScriptImportPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.init_asset::<FighterAttackScript>()
|
||||||
|
.register_asset_loader(FighterAttackScriptSourceLoader)
|
||||||
|
.register_asset_loader(FighterAttackScriptLoader)
|
||||||
|
.register_asset_processor(FighterAttackScriptProcessor::new(
|
||||||
|
FighterAttackScriptTransformer,
|
||||||
|
FighterAttackScriptSaver,
|
||||||
|
))
|
||||||
|
.set_default_asset_processor::<FighterAttackScriptProcessor>("attack.rhai");
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-13
@@ -1,23 +1,17 @@
|
|||||||
use bevy::ecs::name::HashedStr;
|
use bevy::{prelude::*};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::math::int::FGi32;
|
use crate::{fighter::attack::AttackHitbox, math::int::FGi32};
|
||||||
|
|
||||||
pub mod move_compiler;
|
pub mod move_compiler;
|
||||||
|
pub mod importer;
|
||||||
|
|
||||||
pub enum MoveAngleKind {
|
pub enum MoveAngleKind {
|
||||||
Normal(FGi32),
|
Normal(FGi32),
|
||||||
Sakurai
|
Sakurai
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MoveEventHurtbox {
|
#[derive(Asset, Reflect, Serialize, Deserialize)]
|
||||||
pub priority: u32,
|
pub struct FighterAttackScript {
|
||||||
pub bone: HashedStr,
|
pub hitboxes: Vec<AttackHitbox>
|
||||||
pub radius: FGi32,
|
|
||||||
pub damage: FGi32,
|
|
||||||
pub knockback_scaling: FGi32,
|
|
||||||
pub angle: MoveAngleKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum MoveEvent {
|
|
||||||
Hurtbox(MoveEventHurtbox)
|
|
||||||
}
|
}
|
||||||
@@ -3,8 +3,7 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
|||||||
use rhai::EvalAltResult;
|
use rhai::EvalAltResult;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
fighter::attack::{self, AttackAngle, FighterDamage, Knockback, KnockbackType},
|
fighter::attack::{self, AttackAngle, FighterDamage, Knockback, KnockbackType}, math::{int::FGi32, vec::FGVec2, vec3::FGVec3}, scripting::FighterAttackScript,
|
||||||
math::{int::FGi32, vec::FGVec2, vec3::FGVec3},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
@@ -59,6 +58,14 @@ impl MoveCompiler {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_attack_script(mut self) -> Result<FighterAttackScript, String> {
|
||||||
|
self.remove_all_hitboxes().map_err(|err| err.to_string())?;
|
||||||
|
let hitboxes = self.hitboxes.into_iter().map(|(_, hitbox)| hitbox).collect();
|
||||||
|
Ok(FighterAttackScript {
|
||||||
|
hitboxes
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// scripting functions
|
// scripting functions
|
||||||
@@ -83,11 +90,12 @@ pub fn register_common_types(engine: &mut rhai::Engine) {
|
|||||||
.register_fn("damage", FighterDamage::lit);
|
.register_fn("damage", FighterDamage::lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_script(text: &str) -> Result<MoveCompiler, String> {
|
pub fn compile_script(text: &str) -> Result<FighterAttackScript, String> {
|
||||||
let mc = Rc::new(RefCell::new(MoveCompiler {
|
let mc = Rc::new(RefCell::new(MoveCompiler {
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}));
|
}));
|
||||||
|
let result = {
|
||||||
let mut engine = rhai::Engine::new();
|
let mut engine = rhai::Engine::new();
|
||||||
|
|
||||||
register_common_types(&mut engine);
|
register_common_types(&mut engine);
|
||||||
@@ -169,9 +177,10 @@ pub fn compile_script(text: &str) -> Result<MoveCompiler, String> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
engine.run(&text)
|
||||||
|
};
|
||||||
|
|
||||||
engine
|
|
||||||
.run(&text)
|
result.map(|_| Rc::into_inner(mc).unwrap().into_inner().into_attack_script())
|
||||||
.map(|_| Rc::into_inner(mc).unwrap().into_inner())
|
.map_err(|err| err.to_string())?
|
||||||
.map_err(|err| err.to_string())
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user