shity basic one shot

This commit is contained in:
2026-09-18 14:01:10 +01:00
parent 5851077659
commit 42a1234e7f
81 changed files with 3484 additions and 76 deletions
+234
View File
@@ -0,0 +1,234 @@
use crate::graph::*;
use std::sync::{Arc, Mutex, MutexGuard};
/// Shared, thread-safe handle to the graph being built. Every builder carries a clone.
#[derive(Clone)]
pub struct Aac {
pub(crate) graph: Arc<Mutex<ControllerGraph>>,
}
impl Default for Aac {
fn default() -> Self {
Self::new()
}
}
impl Aac {
pub fn new() -> Self {
Self {
graph: Arc::new(Mutex::new(ControllerGraph::default())),
}
}
/// A poisoned lock still holds a usable graph; recovering avoids panicking across the FFI boundary.
fn lock(&self) -> MutexGuard<'_, ControllerGraph> {
self.graph.lock().unwrap_or_else(|e| e.into_inner())
}
pub fn write<R>(&self, f: impl FnOnce(&mut ControllerGraph) -> R) -> R {
f(&mut self.lock())
}
}
/// Parameter handles only carry the name; conditions read nothing else from them.
#[derive(Clone)]
pub struct FloatParam {
pub(crate) name: String,
}
#[derive(Clone)]
pub struct IntParam {
pub(crate) name: String,
}
#[derive(Clone)]
pub struct BoolParam {
pub(crate) name: String,
}
#[derive(Clone)]
pub struct ControllerBuilder {
pub(crate) aac: Aac,
}
#[derive(Clone)]
pub struct LayerBuilder {
pub(crate) aac: Aac,
pub(crate) layer: usize,
}
/// A state machine. `machine` is the chain of sub-machine indices from the layer root, so the empty
/// chain is the layer's root machine and indices stay stable because machines are only ever appended.
#[derive(Clone)]
pub struct MachineRef {
pub(crate) aac: Aac,
pub(crate) layer: usize,
pub(crate) machine: Vec<usize>,
}
#[derive(Clone)]
pub struct StateRef {
pub(crate) aac: Aac,
pub(crate) layer: usize,
pub(crate) machine: Vec<usize>,
pub(crate) state: usize,
}
#[derive(Clone)]
pub struct AnyStateRef {
pub(crate) aac: Aac,
pub(crate) layer: usize,
pub(crate) machine: Vec<usize>,
}
#[derive(Clone)]
pub struct ClipBuilder {
pub(crate) aac: Aac,
pub(crate) name: String,
}
#[derive(Clone)]
pub struct BlendTreeBuilder {
pub(crate) aac: Aac,
pub(crate) name: String,
}
/// `source` is the originating state, or `None` for an any-state transition.
#[derive(Clone)]
pub struct TransitionRef {
pub(crate) aac: Aac,
pub(crate) layer: usize,
pub(crate) machine: Vec<usize>,
pub(crate) source: Option<usize>,
pub(crate) index: usize,
}
pub(crate) fn machine_mut<'a>(
graph: &'a mut ControllerGraph,
layer: usize,
path: &[usize],
) -> &'a mut StateMachine {
let mut machine = &mut graph.controller.layers[layer].state_machine;
for &index in path {
machine = &mut machine.sub_machines[index];
}
machine
}
pub(crate) fn clip_mut<'a>(graph: &'a mut ControllerGraph, name: &str) -> Option<&'a mut ClipData> {
graph.clips.iter_mut().find(|clip| clip.name == name)
}
pub(crate) fn blend_tree_mut<'a>(
graph: &'a mut ControllerGraph,
name: &str,
) -> Option<&'a mut BlendTreeData> {
graph.blend_trees.iter_mut().find(|tree| tree.name == name)
}
impl StateRef {
pub fn state_name(&self) -> String {
self.aac
.write(|graph| machine_mut(graph, self.layer, &self.machine).states[self.state].name.clone())
}
pub fn set_motion(&self, motion: MotionRef) {
self.aac.write(|graph| {
machine_mut(graph, self.layer, &self.machine).states[self.state].motion = Some(motion);
});
}
pub fn transition_to(&self, target: &StateRef) -> TransitionRef {
let to = target.state_name();
let index = self.aac.write(|graph| {
let state = &mut machine_mut(graph, self.layer, &self.machine).states[self.state];
state.transitions.push(Transition::new(to));
state.transitions.len() - 1
});
TransitionRef {
aac: self.aac.clone(),
layer: self.layer,
machine: self.machine.clone(),
source: Some(self.state),
index,
}
}
}
impl AnyStateRef {
pub fn transition_to(&self, target: &StateRef) -> TransitionRef {
let to = target.state_name();
let index = self.aac.write(|graph| {
let machine = machine_mut(graph, self.layer, &self.machine);
machine.any_state_transitions.push(Transition::new(to));
machine.any_state_transitions.len() - 1
});
TransitionRef {
aac: self.aac.clone(),
layer: self.layer,
machine: self.machine.clone(),
source: None,
index,
}
}
}
impl TransitionRef {
/// Apply a mutation to the transition this handle points at.
pub fn update(&self, f: impl FnOnce(&mut Transition)) {
self.aac.write(|graph| {
let machine = machine_mut(graph, self.layer, &self.machine);
let transitions = match self.source {
Some(state) => &mut machine.states[state].transitions,
None => &mut machine.any_state_transitions,
};
f(&mut transitions[self.index]);
});
}
pub fn add_conditions(&self, conditions: impl IntoIterator<Item = Condition>) {
self.update(|transition| transition.conditions.extend(conditions));
}
}
impl ClipBuilder {
pub fn data_mut<R>(&self, f: impl FnOnce(&mut ClipData) -> R) -> Option<R> {
let name = self.name.clone();
self.aac.write(|graph| clip_mut(graph, &name).map(f))
}
/// Append one keyframe to the curve for (path, property), creating the curve if needed.
pub fn push_key(&self, path: &str, property: &str, key: Keyframe) -> Result<(), String> {
let target = infer_target(property).ok_or_else(|| {
format!(
"cannot tell which component `{property}` belongs to; \
known properties are `m_IsActive` and `blendShape.*`"
)
})?;
self.data_mut(|clip| {
clip.curve_mut(path, target, property).keys.push(key);
})
.ok_or_else(|| format!("unknown clip `{}`", self.name))
}
}
impl BlendTreeBuilder {
pub fn data_mut<R>(&self, f: impl FnOnce(&mut BlendTreeData) -> R) -> Option<R> {
let name = self.name.clone();
self.aac.write(|graph| blend_tree_mut(graph, &name).map(f))
}
pub fn configure(&self, blend_type: BlendType, param_x: &str, param_y: Option<&str>) -> Result<(), String> {
self.data_mut(|tree| {
tree.blend_type = blend_type;
tree.param_x = param_x.to_string();
tree.param_y = param_y.map(str::to_string);
})
.ok_or_else(|| format!("unknown blend tree `{}`", self.name))
}
pub fn push_child(&self, child: BlendChild) -> Result<(), String> {
self.data_mut(|tree| tree.children.push(child))
.ok_or_else(|| format!("unknown blend tree `{}`", self.name))
}
}