siglus_scene_vm/runtime/forms/
counter.rs1use anyhow::Result;
2
3use crate::runtime::{CommandContext, Value, globals::Counter};
4
5fn ensure_len(v: &mut Vec<Counter>, idx: usize) {
6 if v.len() <= idx {
7 v.resize(idx + 1, Counter::default());
8 }
9}
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12enum CounterListOp {
13 GetSize,
14 Unknown,
15}
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18enum CounterOp {
19 Set,
20 Get,
21 Reset,
22 Start,
23 StartReal,
24 StartFrame,
25 StartFrameReal,
26 StartFrameLoop,
27 StartFrameLoopReal,
28 Stop,
29 Resume,
30 Wait,
31 WaitKey,
32 CheckValue,
33 CheckActive,
34 Unknown,
35}
36
37fn resolve_counter_list_op(op: i32) -> CounterListOp {
38 if op == crate::runtime::constants::COUNTERLIST_GET_SIZE {
39 CounterListOp::GetSize
40 } else {
41 CounterListOp::Unknown
42 }
43}
44
45fn resolve_counter_op(op: i32) -> CounterOp {
46 match op {
47 crate::runtime::constants::COUNTER_SET => CounterOp::Set,
48 crate::runtime::constants::COUNTER_GET => CounterOp::Get,
49 crate::runtime::constants::COUNTER_RESET => CounterOp::Reset,
50 crate::runtime::constants::COUNTER_START => CounterOp::Start,
51 crate::runtime::constants::COUNTER_START_REAL => CounterOp::StartReal,
52 crate::runtime::constants::COUNTER_START_FRAME => CounterOp::StartFrame,
53 crate::runtime::constants::COUNTER_START_FRAME_REAL => CounterOp::StartFrameReal,
54 crate::runtime::constants::COUNTER_START_FRAME_LOOP => CounterOp::StartFrameLoop,
55 crate::runtime::constants::COUNTER_START_FRAME_LOOP_REAL => CounterOp::StartFrameLoopReal,
56 crate::runtime::constants::COUNTER_STOP => CounterOp::Stop,
57 crate::runtime::constants::COUNTER_RESUME => CounterOp::Resume,
58 crate::runtime::constants::COUNTER_WAIT => CounterOp::Wait,
59 crate::runtime::constants::COUNTER_WAIT_KEY => CounterOp::WaitKey,
60 crate::runtime::constants::COUNTER_CHECK_VALUE => CounterOp::CheckValue,
61 crate::runtime::constants::COUNTER_CHECK_ACTIVE => CounterOp::CheckActive,
62 _ => CounterOp::Unknown,
63 }
64}
65
66fn arg_int(args: &[Value], idx: usize) -> i64 {
67 args.get(idx).and_then(Value::as_i64).unwrap_or(0)
68}
69
70pub fn dispatch(ctx: &mut CommandContext, form_id: u32, args: &[Value]) -> Result<bool> {
71 let Some((chain_pos, chain_ref)) =
72 crate::runtime::forms::prop_access::parse_element_chain_ctx(ctx, form_id, args)
73 else {
74 return Ok(false);
75 };
76 let chain = chain_ref.to_vec();
77
78 if chain.len() >= 2 && chain[1] != ctx.ids.elm_array {
79 match resolve_counter_list_op(chain[1]) {
80 CounterListOp::GetSize => {
81 let size = ctx
82 .globals
83 .counter_lists
84 .get(&form_id)
85 .map(|v| v.len() as i64)
86 .unwrap_or(0);
87 ctx.push(Value::Int(size));
88 return Ok(true);
89 }
90 CounterListOp::Unknown => return Ok(false),
91 }
92 }
93
94 if chain.len() < 3 || chain[1] != ctx.ids.elm_array {
95 return Ok(false);
96 }
97 let idx = chain[2].max(0) as usize;
98 let params = crate::runtime::forms::prop_access::script_args(args, chain_pos);
99
100 {
101 let counters = ctx.globals.counter_lists.entry(form_id).or_default();
102 ensure_len(counters, idx);
103 }
104
105 if chain.len() == 3 {
106 let (al_id, _ret_form, rhs_value) =
107 crate::runtime::forms::prop_access::infer_assign_and_ret_ctx(ctx, chain_pos, args);
108 if al_id == Some(1) {
109 let rhs = rhs_value.as_ref().and_then(Value::as_i64).unwrap_or(0);
110 if let Some(counter) = ctx
111 .globals
112 .counter_lists
113 .get_mut(&form_id)
114 .and_then(|v| v.get_mut(idx))
115 {
116 counter.set_count(rhs);
117 }
118 ctx.push(Value::Int(0));
119 } else {
120 let value = ctx
121 .globals
122 .counter_lists
123 .get(&form_id)
124 .and_then(|v| v.get(idx))
125 .map(|c| c.get_count())
126 .unwrap_or(0);
127 ctx.push(Value::Int(value));
128 }
129 return Ok(true);
130 }
131
132 match resolve_counter_op(chain[3]) {
133 CounterOp::Set => {
134 if let Some(counter) = ctx
135 .globals
136 .counter_lists
137 .get_mut(&form_id)
138 .and_then(|v| v.get_mut(idx))
139 {
140 counter.set_count(arg_int(params, 0));
141 }
142 ctx.push(Value::Int(0));
143 }
144 CounterOp::Get => {
145 let value = ctx
146 .globals
147 .counter_lists
148 .get(&form_id)
149 .and_then(|v| v.get(idx))
150 .map(|c| c.get_count())
151 .unwrap_or(0);
152 ctx.push(Value::Int(value));
153 }
154 CounterOp::Reset => {
155 if let Some(counter) = ctx
156 .globals
157 .counter_lists
158 .get_mut(&form_id)
159 .and_then(|v| v.get_mut(idx))
160 {
161 counter.reset();
162 }
163 ctx.push(Value::Int(0));
164 }
165 CounterOp::Start => {
166 if let Some(counter) = ctx
167 .globals
168 .counter_lists
169 .get_mut(&form_id)
170 .and_then(|v| v.get_mut(idx))
171 {
172 counter.start();
173 }
174 ctx.push(Value::Int(0));
175 }
176 CounterOp::StartReal => {
177 if let Some(counter) = ctx
178 .globals
179 .counter_lists
180 .get_mut(&form_id)
181 .and_then(|v| v.get_mut(idx))
182 {
183 counter.start_real();
184 }
185 ctx.push(Value::Int(0));
186 }
187 CounterOp::StartFrame => {
188 if let Some(counter) = ctx
189 .globals
190 .counter_lists
191 .get_mut(&form_id)
192 .and_then(|v| v.get_mut(idx))
193 {
194 counter.start_frame(arg_int(params, 0), arg_int(params, 1), arg_int(params, 2));
195 }
196 ctx.push(Value::Int(0));
197 }
198 CounterOp::StartFrameReal => {
199 if let Some(counter) = ctx
200 .globals
201 .counter_lists
202 .get_mut(&form_id)
203 .and_then(|v| v.get_mut(idx))
204 {
205 counter.start_frame_real(
206 arg_int(params, 0),
207 arg_int(params, 1),
208 arg_int(params, 2),
209 );
210 }
211 ctx.push(Value::Int(0));
212 }
213 CounterOp::StartFrameLoop => {
214 if let Some(counter) = ctx
215 .globals
216 .counter_lists
217 .get_mut(&form_id)
218 .and_then(|v| v.get_mut(idx))
219 {
220 counter.start_frame_loop(
221 arg_int(params, 0),
222 arg_int(params, 1),
223 arg_int(params, 2),
224 );
225 }
226 ctx.push(Value::Int(0));
227 }
228 CounterOp::StartFrameLoopReal => {
229 if let Some(counter) = ctx
230 .globals
231 .counter_lists
232 .get_mut(&form_id)
233 .and_then(|v| v.get_mut(idx))
234 {
235 counter.start_frame_loop_real(
236 arg_int(params, 0),
237 arg_int(params, 1),
238 arg_int(params, 2),
239 );
240 }
241 ctx.push(Value::Int(0));
242 }
243 CounterOp::Stop => {
244 if let Some(counter) = ctx
245 .globals
246 .counter_lists
247 .get_mut(&form_id)
248 .and_then(|v| v.get_mut(idx))
249 {
250 counter.stop();
251 }
252 ctx.push(Value::Int(0));
253 }
254 CounterOp::Resume => {
255 if let Some(counter) = ctx
256 .globals
257 .counter_lists
258 .get_mut(&form_id)
259 .and_then(|v| v.get_mut(idx))
260 {
261 counter.resume();
262 }
263 ctx.push(Value::Int(0));
264 }
265 CounterOp::Wait => {
266 ctx.wait
267 .wait_counter(form_id, idx, arg_int(params, 0), false, false);
268 }
269 CounterOp::WaitKey => {
270 ctx.wait
271 .wait_counter(form_id, idx, arg_int(params, 0), true, true);
272 }
273 CounterOp::CheckValue => {
274 let target = arg_int(params, 0);
275 let cur = ctx
276 .globals
277 .counter_lists
278 .get(&form_id)
279 .and_then(|v| v.get(idx))
280 .map(|c| c.get_count())
281 .unwrap_or(target);
282 let ok = cur - target >= 0;
283 if env_is_set!("SG_COUNTER_TRACE") {
284 eprintln!(
285 "[SG_DEBUG][COUNTER] CHECK_VALUE form={} idx={} cur={} target={} ok={}",
286 form_id, idx, cur, target, ok
287 );
288 }
289 ctx.push(Value::Int(if ok { 1 } else { 0 }));
290 }
291 CounterOp::CheckActive => {
292 let active = ctx
293 .globals
294 .counter_lists
295 .get(&form_id)
296 .and_then(|v| v.get(idx))
297 .map(|c| c.is_running())
298 .unwrap_or(false);
299 ctx.push(Value::Int(if active { 1 } else { 0 }));
300 }
301 CounterOp::Unknown => return Ok(false),
302 }
303
304 Ok(true)
305}