shity basic one shot
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
use crate::builder::*;
|
||||
use crate::graph::*;
|
||||
use rhai::{Array, Engine, EvalAltResult, Position};
|
||||
|
||||
pub(crate) fn err(message: String) -> Box<EvalAltResult> {
|
||||
Box::new(EvalAltResult::ErrorRuntime(message.into(), Position::NONE))
|
||||
}
|
||||
|
||||
fn condition(parameter: &str, mode: CondMode, threshold: f32) -> Condition {
|
||||
Condition {
|
||||
parameter: parameter.to_string(),
|
||||
mode,
|
||||
threshold,
|
||||
}
|
||||
}
|
||||
|
||||
fn grid(value: i64) -> Result<i32, Box<EvalAltResult>> {
|
||||
i32::try_from(value).map_err(|_| err(format!("grid position {value} does not fit in a 32-bit integer")))
|
||||
}
|
||||
|
||||
fn add_state(aac: &Aac, layer: usize, machine: &[usize], name: &str, x: i64, y: i64) -> Result<StateRef, Box<EvalAltResult>> {
|
||||
let position = GridPos::new(grid(x)?, grid(y)?);
|
||||
let state = aac.write(|graph| {
|
||||
let states = &mut machine_mut(graph, layer, machine).states;
|
||||
states.push(State {
|
||||
name: name.to_string(),
|
||||
position,
|
||||
..Default::default()
|
||||
});
|
||||
states.len() - 1
|
||||
});
|
||||
Ok(StateRef {
|
||||
aac: aac.clone(),
|
||||
layer,
|
||||
machine: machine.to_vec(),
|
||||
state,
|
||||
})
|
||||
}
|
||||
|
||||
fn add_sub_machine(
|
||||
aac: &Aac,
|
||||
layer: usize,
|
||||
machine: &[usize],
|
||||
name: &str,
|
||||
x: i64,
|
||||
y: i64,
|
||||
) -> Result<MachineRef, Box<EvalAltResult>> {
|
||||
let position = GridPos::new(grid(x)?, grid(y)?);
|
||||
let index = aac.write(|graph| {
|
||||
let sub_machines = &mut machine_mut(graph, layer, machine).sub_machines;
|
||||
sub_machines.push(StateMachine {
|
||||
name: Some(name.to_string()),
|
||||
position,
|
||||
..Default::default()
|
||||
});
|
||||
sub_machines.len() - 1
|
||||
});
|
||||
let mut path = machine.to_vec();
|
||||
path.push(index);
|
||||
Ok(MachineRef {
|
||||
aac: aac.clone(),
|
||||
layer,
|
||||
machine: path,
|
||||
})
|
||||
}
|
||||
|
||||
fn assert_new_parameter(aac: &Aac, name: &str) -> Result<(), Box<EvalAltResult>> {
|
||||
if name.trim().is_empty() {
|
||||
return Err(err("parameter name is empty".to_string()));
|
||||
}
|
||||
let duplicate = aac.write(|graph| graph.parameters.iter().any(|p| p.name() == name));
|
||||
if duplicate {
|
||||
return Err(err(format!("parameter `{name}` is already declared")));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn engine(aac: Aac) -> Engine {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.register_type_with_name::<Aac>("Aac");
|
||||
engine.register_type_with_name::<FloatParam>("FloatParam");
|
||||
engine.register_type_with_name::<IntParam>("IntParam");
|
||||
engine.register_type_with_name::<BoolParam>("BoolParam");
|
||||
engine.register_type_with_name::<Condition>("Condition");
|
||||
engine.register_type_with_name::<ControllerBuilder>("Controller");
|
||||
engine.register_type_with_name::<LayerBuilder>("Layer");
|
||||
engine.register_type_with_name::<MachineRef>("Machine");
|
||||
engine.register_type_with_name::<StateRef>("State");
|
||||
engine.register_type_with_name::<TransitionRef>("Transition");
|
||||
engine.register_type_with_name::<ClipBuilder>("Clip");
|
||||
engine.register_type_with_name::<BlendTreeBuilder>("BlendTree");
|
||||
|
||||
register_conditions(&mut engine);
|
||||
register_setup(&mut engine, aac);
|
||||
register_navigation(&mut engine);
|
||||
register_transitions(&mut engine);
|
||||
crate::motion_api::register(&mut engine);
|
||||
|
||||
engine
|
||||
}
|
||||
|
||||
/// Leaf conditions come from overloaded comparison operators, because Rhai's `&&`/`||` cannot be
|
||||
/// overloaded. Combine several conditions with `when_all([...])`.
|
||||
fn register_conditions(engine: &mut Engine) {
|
||||
engine.register_fn(">", |p: FloatParam, v: f64| condition(&p.name, CondMode::Greater, v as f32));
|
||||
engine.register_fn("<", |p: FloatParam, v: f64| condition(&p.name, CondMode::Less, v as f32));
|
||||
engine.register_fn("==", |p: FloatParam, v: f64| condition(&p.name, CondMode::Equals, v as f32));
|
||||
engine.register_fn("!=", |p: FloatParam, v: f64| condition(&p.name, CondMode::NotEqual, v as f32));
|
||||
engine.register_fn(">", |p: IntParam, v: i64| condition(&p.name, CondMode::Greater, v as f32));
|
||||
engine.register_fn("<", |p: IntParam, v: i64| condition(&p.name, CondMode::Less, v as f32));
|
||||
engine.register_fn("==", |p: IntParam, v: i64| condition(&p.name, CondMode::Equals, v as f32));
|
||||
engine.register_fn("!=", |p: IntParam, v: i64| condition(&p.name, CondMode::NotEqual, v as f32));
|
||||
engine.register_fn("==", |p: BoolParam, v: bool| {
|
||||
condition(&p.name, if v { CondMode::If } else { CondMode::IfNot }, 0.0)
|
||||
});
|
||||
engine.register_fn("!=", |p: BoolParam, v: bool| {
|
||||
condition(&p.name, if v { CondMode::IfNot } else { CondMode::If }, 0.0)
|
||||
});
|
||||
}
|
||||
|
||||
fn register_setup(engine: &mut Engine, aac: Aac) {
|
||||
engine.register_fn("AnimatorAsCode", move || aac.clone());
|
||||
|
||||
engine.register_fn("system_name", |a: &mut Aac, name: &str| {
|
||||
a.write(|graph| graph.system_name = name.to_string());
|
||||
});
|
||||
engine.register_fn("asset_key", |a: &mut Aac, key: &str| {
|
||||
a.write(|graph| graph.asset_key = key.to_string());
|
||||
});
|
||||
|
||||
engine.register_fn("float_param", |a: &mut Aac, name: &str, default: f64| -> Result<FloatParam, Box<EvalAltResult>> {
|
||||
assert_new_parameter(a, name)?;
|
||||
a.write(|graph| {
|
||||
graph.parameters.push(Parameter::Float {
|
||||
name: name.to_string(),
|
||||
default: default as f32,
|
||||
})
|
||||
});
|
||||
Ok(FloatParam {
|
||||
name: name.to_string(),
|
||||
})
|
||||
});
|
||||
engine.register_fn("int_param", |a: &mut Aac, name: &str, default: i64| -> Result<IntParam, Box<EvalAltResult>> {
|
||||
assert_new_parameter(a, name)?;
|
||||
a.write(|graph| {
|
||||
graph.parameters.push(Parameter::Int {
|
||||
name: name.to_string(),
|
||||
default: default as i32,
|
||||
})
|
||||
});
|
||||
Ok(IntParam {
|
||||
name: name.to_string(),
|
||||
})
|
||||
});
|
||||
engine.register_fn(
|
||||
"bool_param",
|
||||
|a: &mut Aac, name: &str, default: bool| -> Result<BoolParam, Box<EvalAltResult>> {
|
||||
assert_new_parameter(a, name)?;
|
||||
a.write(|graph| {
|
||||
graph.parameters.push(Parameter::Bool {
|
||||
name: name.to_string(),
|
||||
default,
|
||||
})
|
||||
});
|
||||
Ok(BoolParam {
|
||||
name: name.to_string(),
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
engine.register_fn("new_controller", |a: &mut Aac| ControllerBuilder { aac: a.clone() });
|
||||
}
|
||||
|
||||
fn register_navigation(engine: &mut Engine) {
|
||||
// There is exactly one controller, so this is the only place layers are attached.
|
||||
engine.register_fn("layer", |c: ControllerBuilder, name: &str| -> LayerBuilder {
|
||||
let layer = c.aac.write(|graph| {
|
||||
graph.controller.layers.push(Layer {
|
||||
name: name.to_string(),
|
||||
..Default::default()
|
||||
});
|
||||
graph.controller.layers.len() - 1
|
||||
});
|
||||
LayerBuilder {
|
||||
aac: c.aac.clone(),
|
||||
layer,
|
||||
}
|
||||
});
|
||||
|
||||
engine.register_fn("state", |l: LayerBuilder, name: &str, x: i64, y: i64| {
|
||||
add_state(&l.aac, l.layer, &[], name, x, y)
|
||||
});
|
||||
engine.register_fn("state", |m: MachineRef, name: &str, x: i64, y: i64| {
|
||||
add_state(&m.aac, m.layer, &m.machine, name, x, y)
|
||||
});
|
||||
|
||||
engine.register_fn("sub_machine", |l: LayerBuilder, name: &str, x: i64, y: i64| {
|
||||
add_sub_machine(&l.aac, l.layer, &[], name, x, y)
|
||||
});
|
||||
engine.register_fn("sub_machine", |m: MachineRef, name: &str, x: i64, y: i64| {
|
||||
add_sub_machine(&m.aac, m.layer, &m.machine, name, x, y)
|
||||
});
|
||||
|
||||
engine.register_fn("any_state", |l: LayerBuilder| AnyStateRef {
|
||||
aac: l.aac.clone(),
|
||||
layer: l.layer,
|
||||
machine: Vec::new(),
|
||||
});
|
||||
engine.register_fn("any_state", |m: MachineRef| AnyStateRef {
|
||||
aac: m.aac.clone(),
|
||||
layer: m.layer,
|
||||
machine: m.machine.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
fn register_transitions(engine: &mut Engine) {
|
||||
engine.register_fn("transition_to", |from: StateRef, to: StateRef| from.transition_to(&to));
|
||||
engine.register_fn("transition_to", |from: AnyStateRef, to: StateRef| from.transition_to(&to));
|
||||
|
||||
engine.register_fn("when", |t: TransitionRef, c: Condition| {
|
||||
t.add_conditions([c]);
|
||||
t
|
||||
});
|
||||
engine.register_fn(
|
||||
"when_all",
|
||||
|t: TransitionRef, conditions: Array| -> Result<TransitionRef, Box<EvalAltResult>> {
|
||||
let mut collected = Vec::with_capacity(conditions.len());
|
||||
for value in conditions {
|
||||
collected.push(
|
||||
value
|
||||
.try_cast::<Condition>()
|
||||
.ok_or_else(|| err("when_all expects a list of conditions".to_string()))?,
|
||||
);
|
||||
}
|
||||
t.add_conditions(collected);
|
||||
Ok(t)
|
||||
},
|
||||
);
|
||||
|
||||
engine.register_fn("duration", |t: TransitionRef, seconds: f64| {
|
||||
t.update(|transition| transition.duration = seconds as f32);
|
||||
t
|
||||
});
|
||||
engine.register_fn("no_exit_time", |t: TransitionRef| {
|
||||
t.update(|transition| {
|
||||
transition.has_exit_time = false;
|
||||
transition.exit_time = 0.0;
|
||||
});
|
||||
t
|
||||
});
|
||||
engine.register_fn("exit_time", |t: TransitionRef, normalized: f64| {
|
||||
t.update(|transition| {
|
||||
transition.has_exit_time = true;
|
||||
transition.exit_time = normalized as f32;
|
||||
});
|
||||
t
|
||||
});
|
||||
engine.register_fn("ordered_interruption", |t: TransitionRef, value: bool| {
|
||||
t.update(|transition| transition.ordered_interruption = value);
|
||||
t
|
||||
});
|
||||
engine.register_fn("source_interruption", |t: TransitionRef| {
|
||||
t.update(|transition| transition.source_interruption = true);
|
||||
t
|
||||
});
|
||||
engine.register_fn("to_self", |t: TransitionRef| {
|
||||
t.update(|transition| transition.can_transition_to_self = true);
|
||||
t
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user