Skip to main content

gizmo_scripting/
commands.rs

1//! Script Command Queue — Lua scriptlerden gelen değişiklik isteklerinin biriktirildiği kuyruk
2//!
3//! Lua scriptleri doğrudan World'ü mutate edemez (Rust borrow kuralları).
4//! Bunun yerine komutlar bu kuyrukta birikir ve frame sonunda `flush()` ile uygulanır.
5
6use gizmo_math::{Quat, Vec3};
7use std::sync::Mutex;
8/// Lua'dan gelen tüm değişiklik istekleri
9#[derive(Debug, Clone)]
10#[non_exhaustive]
11pub enum ScriptCommand {
12    // Transform
13    SetPosition(u32, Vec3),
14    SetRotation(u32, Quat),
15    SetScale(u32, Vec3),
16
17    // Velocity
18    SetVelocity(u32, Vec3),
19    SetAngularVelocity(u32, Vec3),
20
21    // Physics
22    ApplyForce(u32, Vec3),
23    ApplyImpulse(u32, Vec3),
24    AddRigidBody {
25        id: u32,
26        mass: f32,
27        use_gravity: bool,
28    },
29    AddBoxCollider {
30        id: u32,
31        hx: f32,
32        hy: f32,
33        hz: f32,
34    },
35    AddSphereCollider {
36        id: u32,
37        radius: f32,
38    },
39
40    // Vehicle
41    SetVehicleEngineForce(u32, f32),
42    SetVehicleSteering(u32, f32),
43    SetVehicleBrake(u32, f32),
44
45    // Entity Lifecycle
46    SpawnEntity {
47        name: String,
48        position: Vec3,
49    },
50    SpawnPrefab {
51        name: String,
52        prefab_type: String,
53        position: Vec3,
54    },
55    DestroyEntity(u32),
56
57    // Audio
58    PlaySound(String),
59    PlaySound3D(String, Vec3),
60    StopSound(String),
61
62    // Scene
63    LoadScene(String),
64    SaveScene(String),
65
66    // Diyalog Sistemi
67    ShowDialogue {
68        speaker: String,
69        text: String,
70        duration: f32,
71    },
72    HideDialogue,
73
74    // Ara Sahne (Cutscene)
75    TriggerCutscene(String), // cutscene adı/id
76    EndCutscene,
77
78    // Yarış Sistemi
79    StartRace,
80    AddCheckpoint {
81        id: u32,
82        position: Vec3,
83        radius: f32,
84    },
85    ActivateCheckpoint(u32),
86    FinishRace {
87        winner_name: String,
88    },
89    ResetRace,
90
91    // Kamera
92    SetCameraTarget(u32), // hangi entity'yi takip etsin
93    SetCameraFov(f32),
94    /// İki dövüşçüyü aynı anda takip eden fighting camera
95    SetFightCamera {
96        p1_id: u32,
97        p2_id: u32,
98        height: f32,     // Kamera yüksekliği (Y offset)
99        distance: f32,   // Minimum uzaklık (Z offset)
100    },
101
102// Component
103    SetEntityName(u32, String),
104PlayAnimation {
105        id: u32,
106        name: String,
107        blend: f32,
108        loop_anim: bool,
109    },
110    SetAnimationSpeed(u32, f32),
111
112
113    // AI
114    AddNavAgent(u32),
115    SetAiTarget(u32, Vec3),
116    ClearAiTarget(u32),
117
118    // Fighter
119    SetFighterMove {
120        id: u32,
121        name: String,
122        startup: u32,
123        active: u32,
124        recovery: u32,
125        damage: f32,
126    },
127    ApplyHitstop(u32, u32),
128    ApplyHitstun(u32, u32),
129}
130
131
132/// Thread-safe queue of pending [`ScriptCommand`]s, accessible from Lua callbacks.
133///
134/// Lua callbacks cannot mutate the `World` directly, so they push commands here;
135/// the engine later drains and applies them at a controlled point in the frame.
136#[derive(Debug, Default)]
137pub struct CommandQueue {
138    /// Pending commands, guarded by a mutex so Lua callbacks can push concurrently.
139    pub commands: Mutex<Vec<ScriptCommand>>,
140}
141
142impl CommandQueue {
143    /// Creates an empty command queue.
144    pub fn new() -> Self {
145        Self {
146            commands: Mutex::new(Vec::new()),
147        }
148    }
149
150    /// Appends a command to the queue.
151    pub fn push(&self, cmd: ScriptCommand) {
152        // Poison-recovery: bir thread lock tutarken panic etse bile kuyruk
153        // kullanılabilir kalır (FFI/Lua callback sınırında panic-free).
154        self.commands
155            .lock()
156            .unwrap_or_else(|e| e.into_inner())
157            .push(cmd);
158    }
159
160    /// Removes and returns all currently queued commands, leaving the queue empty.
161    pub fn drain(&self) -> Vec<ScriptCommand> {
162        // Poison-recovery: zehirlenmiş mutex'i kurtar, panic etme.
163        self.commands
164            .lock()
165            .unwrap_or_else(|e| e.into_inner())
166            .drain(..)
167            .collect()
168    }
169
170    /// Returns `true` if no commands are currently queued.
171    pub fn is_empty(&self) -> bool {
172        // Poison-recovery: zehirlenmiş mutex'i kurtar, panic etme.
173        self.commands
174            .lock()
175            .unwrap_or_else(|e| e.into_inner())
176            .is_empty()
177    }
178
179    /// Returns the number of currently queued commands.
180    pub fn len(&self) -> usize {
181        // Poison-recovery: zehirlenmiş mutex'i kurtar, panic etme.
182        self.commands
183            .lock()
184            .unwrap_or_else(|e| e.into_inner())
185            .len()
186    }
187}