Skip to main content

engage/
ext.rs

1// The extension traits/iterators here mirror the generated `List_1` / `Dictionary_2` names on
2// purpose, so they carry the same non-camel-case `_1`/`_2`.
3#![allow(non_camel_case_types)]
4
5use unity::{IntPtr, MethodInfo};
6
7fn method_info_intptr(callback_ptr: *mut u8, args: u8) -> IntPtr {
8    let mi = unity::method_info_for_fn(callback_ptr, args);
9    IntPtr(mi as *const MethodInfo as *mut ())
10}
11
12#[cfg(feature = "system-collections-generic-list_1")]
13mod list_1_ext {
14    use crate::system::collections::generic::list_1::{IList_1Methods, List_1};
15
16    pub trait List_1Ext<T: Copy + ::unity::ClassIdentity> {
17        fn with_capacity(capacity: i32) -> Self;
18        fn get(self, index: i32) -> T;
19        fn iter(self) -> List_1Iter<T>;
20        fn count(self) -> i32;
21    }
22
23    impl<T: Copy + ::unity::ClassIdentity> List_1Ext<T> for List_1<T> {
24        fn with_capacity(capacity: i32) -> Self {
25            let list = Self::new();
26            list.ensure_capacity(capacity);
27            list
28        }
29
30        fn get(self, index: i32) -> T {
31            self.get_item(index)
32        }
33
34        fn iter(self) -> List_1Iter<T> {
35            let len = self.get_count();
36            List_1Iter { list: self, index: 0, len }
37        }
38
39        fn count(self) -> i32 {
40            self.get_count()
41        }
42    }
43
44    pub struct List_1Iter<T: Copy + ::unity::ClassIdentity> {
45        list: List_1<T>,
46        index: i32,
47        len: i32,
48    }
49
50    impl<T: Copy + ::unity::ClassIdentity> Iterator for List_1Iter<T> {
51        type Item = T;
52
53        fn next(&mut self) -> Option<T> {
54            if self.index < self.len {
55                let v = self.list.get_item(self.index);
56                self.index += 1;
57                Some(v)
58            } else {
59                None
60            }
61        }
62
63        fn size_hint(&self) -> (usize, Option<usize>) {
64            let r = (self.len - self.index) as usize;
65            (r, Some(r))
66        }
67    }
68
69    impl<T: Copy + ::unity::ClassIdentity> ExactSizeIterator for List_1Iter<T> {}
70}
71#[cfg(feature = "system-collections-generic-list_1")]
72pub use list_1_ext::*;
73
74#[cfg(feature = "system-collections-generic-dictionary_2")]
75mod dictionary_2_ext {
76    use ::unity::Array;
77
78    use crate::system::collections::generic::dictionary_2::{
79        Dictionary_2, IDictionary_2Methods, IDictionary_2_KeyCollectionMethods, IDictionary_2_ValueCollectionMethods,
80    };
81
82    pub trait Dictionary_2Ext<K: Copy + ::unity::ClassIdentity, V: Copy + ::unity::ClassIdentity> {
83        fn iter(self) -> Dictionary_2Iter<K, V>;
84    }
85
86    impl<K: Copy + ::unity::ClassIdentity, V: Copy + ::unity::ClassIdentity> Dictionary_2Ext<K, V> for Dictionary_2<K, V> {
87        fn iter(self) -> Dictionary_2Iter<K, V> {
88            let len = self.get_count();
89            let keys = Array::<K>::of_len(len as usize).expect("Dictionary_2Iter: keys alloc");
90            let values = Array::<V>::of_len(len as usize).expect("Dictionary_2Iter: values alloc");
91            self.get_keys().copy_to(keys, 0);
92            self.get_values().copy_to(values, 0);
93            Dictionary_2Iter { keys, values, index: 0, len }
94        }
95    }
96
97    pub struct Dictionary_2Iter<K: Copy + ::unity::ClassIdentity, V: Copy + ::unity::ClassIdentity> {
98        keys: Array<K>,
99        values: Array<V>,
100        index: i32,
101        len: i32,
102    }
103
104    impl<K: Copy + ::unity::ClassIdentity, V: Copy + ::unity::ClassIdentity> Iterator for Dictionary_2Iter<K, V> {
105        type Item = (K, V);
106
107        fn next(&mut self) -> Option<(K, V)> {
108            if self.index >= self.len {
109                return None;
110            }
111            let i = self.index as usize;
112            let pair = (self.keys.get(i), self.values.get(i));
113            self.index += 1;
114            Some(pair)
115        }
116
117        fn size_hint(&self) -> (usize, Option<usize>) {
118            let r = (self.len - self.index) as usize;
119            (r, Some(r))
120        }
121    }
122
123    impl<K: Copy + ::unity::ClassIdentity, V: Copy + ::unity::ClassIdentity> ExactSizeIterator for Dictionary_2Iter<K, V> {}
124}
125#[cfg(feature = "system-collections-generic-dictionary_2")]
126pub use dictionary_2_ext::*;
127
128#[cfg(all(
129    feature = "app-gameuserdata",
130    feature = "app-gamevariable",
131    feature = "app-singletonclass_1",
132    feature = "system-collections-generic-list_1",
133))]
134mod game_variable_manager {
135    use unity::Il2CppString;
136
137    use crate::{
138        app::{
139            gameuserdata::{GameUserData, IGameUserDataMethods},
140            gamevariable::{GameVariable, IGameVariableMethods},
141            singletonclass_1::ISingletonClass_1Methods,
142        },
143        system::collections::generic::list_1::List_1,
144    };
145
146    pub struct GameVariableManager;
147
148    impl GameVariableManager {
149        #[inline]
150        fn variable() -> GameVariable {
151            GameUserData::get_instance().get_variable()
152        }
153
154        pub fn get_bool(key: impl Into<Il2CppString>) -> bool {
155            Self::variable().get_bool(key.into())
156        }
157
158        pub fn set_bool(key: impl Into<Il2CppString>, value: bool) {
159            Self::variable().set(key.into(), value);
160        }
161
162        pub fn get_number(key: impl Into<Il2CppString>) -> i32 {
163            Self::variable().get_number(key.into())
164        }
165
166        pub fn set_number(key: impl Into<Il2CppString>, value: i32) {
167            Self::variable().set_number(key.into(), value);
168        }
169
170        pub fn get_string(key: impl Into<Il2CppString>) -> Il2CppString {
171            Self::variable().get_string(key.into())
172        }
173
174        pub fn set_string(key: impl Into<Il2CppString>, value: impl Into<Il2CppString>) {
175            Self::variable().set_string(key.into(), value.into());
176        }
177
178        pub fn make_entry(key: impl Into<Il2CppString>, num: i32) -> bool {
179            Self::variable().entry(key.into(), num)
180        }
181
182        pub fn make_entry_norewind(key: impl Into<Il2CppString>, num: i32) -> bool {
183            Self::variable().entry_no_rewind(key.into(), num)
184        }
185
186        pub fn is_exist(key: impl Into<Il2CppString>) -> bool {
187            Self::variable().is_exist(key.into())
188        }
189
190        pub fn is_string(key: impl Into<Il2CppString>) -> bool {
191            Self::variable().is_string(key.into())
192        }
193
194        pub fn remove(key: impl Into<Il2CppString>) -> bool {
195            Self::variable().remove(key.into())
196        }
197
198        pub fn find_starts_with(prefix: impl Into<Il2CppString>) -> List_1<Il2CppString> {
199            Self::variable().find_starts_with(prefix.into())
200        }
201    }
202}
203#[cfg(all(
204    feature = "app-gameuserdata",
205    feature = "app-gamevariable",
206    feature = "app-singletonclass_1",
207    feature = "system-collections-generic-list_1",
208))]
209pub use game_variable_manager::*;
210
211#[cfg(feature = "app-mess")]
212mod mess_ext {
213    use unity::Il2CppString;
214
215    pub struct Mess;
216
217    impl Mess {
218        pub fn get(label: impl Into<Il2CppString>) -> Il2CppString {
219            crate::app::mess::Mess::get(label.into())
220        }
221
222        pub fn load(file_name: impl Into<Il2CppString>) -> bool {
223            crate::app::mess::Mess::load(file_name.into())
224        }
225
226        pub fn try_load(file_name: impl Into<Il2CppString>) -> bool {
227            crate::app::mess::Mess::try_load(file_name.into())
228        }
229
230        pub fn free(file_name: impl Into<Il2CppString>) -> bool {
231            crate::app::mess::Mess::free(file_name.into())
232        }
233
234        pub fn try_free(file_name: impl Into<Il2CppString>) -> bool {
235            crate::app::mess::Mess::try_free(file_name.into())
236        }
237
238        pub fn is_exist(label: impl Into<Il2CppString>) -> bool {
239            crate::app::mess::Mess::is_exist(label.into())
240        }
241
242        pub fn is_load_done(file_name: impl Into<Il2CppString>) -> bool {
243            crate::app::mess::Mess::is_load_done(file_name.into())
244        }
245
246        pub fn is_file_exist(file_name: impl Into<Il2CppString>) -> bool {
247            crate::app::mess::Mess::is_file_exist(file_name.into())
248        }
249
250        pub fn get_language_directory_name() -> Il2CppString {
251            crate::app::mess::Mess::get_language_directory_name()
252        }
253
254        pub fn get_file_path(label: impl Into<Il2CppString>) -> Il2CppString {
255            crate::app::mess::Mess::get_file_path(label.into())
256        }
257    }
258}
259#[cfg(feature = "app-mess")] pub use mess_ext::*;
260
261#[cfg(feature = "app-titlebar")]
262mod title_bar_ext {
263    use unity::Il2CppString;
264
265    pub struct TitleBar;
266
267    impl TitleBar {
268        pub fn open_header(title: impl Into<Il2CppString>, title_help: impl Into<Il2CppString>, key_help_id: impl Into<Il2CppString>) -> bool {
269            use crate::app::titlebar::{ITitleBarMethods, TitleBar as TB};
270            TB::get_instance().open_header(title.into(), title_help.into(), key_help_id.into())
271        }
272
273        pub fn close_header() {
274            use crate::app::titlebar::{ITitleBarMethods, TitleBar as TB};
275            TB::get_instance().close_header();
276        }
277    }
278}
279#[cfg(feature = "app-titlebar")]
280pub use title_bar_ext::*;
281
282#[cfg(all(feature = "app-pad", feature = "app-vibrationmanager"))]
283mod vibrate_ext {
284    pub const FREQ_LOW: f32 = 160.0;
285    pub const FREQ_HIGH: f32 = 300.0;
286
287    pub fn vibrate(time: f32, amplitude_magnitude: f32, amp_low: f32, amp_high: f32, freq_low: f32, freq_high: f32) {
288        use crate::app::{pad::Pad, vibrationmanager::IVibrationManagerMethods};
289        Pad::vibration().one_shot_2(time, amplitude_magnitude, amp_low, amp_high, freq_low, freq_high);
290    }
291}
292#[cfg(all(feature = "app-pad", feature = "app-vibrationmanager"))]
293pub use vibrate_ext::*;
294
295#[cfg(all(feature = "app-procvoidmethod", feature = "system-object"))]
296mod proc_void_method_ext {
297    use unity::{FromIlInstance, IlInstance, IntPtr, MethodInfo, OptionalMethod, SystemObject};
298
299    use crate::{app::procvoidmethod::ProcVoidMethod, system::object::Object};
300
301    pub trait ProcVoidMethodExt: Sized {
302        /// Bind `target` and call `callback` on it. ProcVoidMethod's Invoke() takes no VM argument, so
303        /// the bound target is the only object the callback ever sees, that's why it's required. The
304        /// callback's first parameter is forced to the same type as `target`, so they can't drift.
305        fn from_fn<T: crate::app::procinst::IProcInst>(target: T, callback: extern "C" fn(T, OptionalMethod)) -> Option<Self>;
306        fn from_raw_parts(target: IlInstance, method_info: &'static MethodInfo) -> Option<Self>;
307    }
308
309    impl ProcVoidMethodExt for ProcVoidMethod {
310        fn from_fn<T: crate::app::procinst::IProcInst>(target: T, callback: extern "C" fn(T, OptionalMethod)) -> Option<Self> {
311            let intptr = super::method_info_intptr(callback as *mut u8, 0);
312            Some(ProcVoidMethod::new(
313                <Object as FromIlInstance>::from_il_instance(target.as_instance()),
314                intptr,
315            ))
316        }
317
318        fn from_raw_parts(target: IlInstance, method_info: &'static MethodInfo) -> Option<Self> {
319            let intptr = IntPtr(method_info as *const MethodInfo as *mut ());
320            Some(ProcVoidMethod::new(<Object as FromIlInstance>::from_il_instance(target), intptr))
321        }
322    }
323}
324#[cfg(all(feature = "app-procvoidmethod", feature = "system-object"))]
325pub use proc_void_method_ext::*;
326
327#[cfg(all(feature = "app-procvoidfunction", feature = "app-procinst", feature = "system-object",))]
328mod proc_void_function_ext {
329    use unity::{FromIlInstance, IlInstance, OptionalMethod, SystemObject};
330
331    use crate::{app::procvoidfunction::ProcVoidFunction, system::object::Object};
332
333    pub trait ProcVoidFunctionExt: Sized {
334        /// Wrap a Rust fn as a ProcVoidFunction (for `Proc::call` steps). The proc running the desc is
335        /// handed to the callback by the VM itself, so there's nothing to bind, the callback just
336        /// receives that proc as its argument. Prefer this unless you need a bound object that differs
337        /// from the running proc.
338        fn from_fn<T: crate::app::procinst::IProcInst>(callback: extern "C" fn(T, OptionalMethod)) -> Option<Self>;
339
340        /// Like `from_fn`, but also binds `target`. The callback receives `(target, inst, methodinfo)`
341        /// where `inst` is the proc running the desc. Use this only when the object you want differs
342        /// from the running proc. The target's type is tied to the callback's first parameter.
343        fn from_fn_with_target<T: crate::app::procinst::IProcInst, U: crate::app::procinst::IProcInst>(
344            target: T,
345            callback: extern "C" fn(T, U, OptionalMethod),
346        ) -> Option<Self>;
347    }
348
349    impl ProcVoidFunctionExt for ProcVoidFunction {
350        fn from_fn<T: crate::app::procinst::IProcInst>(callback: extern "C" fn(T, OptionalMethod)) -> Option<Self> {
351            // A null target plus parameters_count = 1 makes the delegate's Invoke(inst) call the
352            // callback as method_ptr(inst, method_info), so its only argument is the executing proc.
353            let intptr = super::method_info_intptr(callback as *mut u8, 1);
354            Some(ProcVoidFunction::new(
355                <Object as FromIlInstance>::from_il_instance(IlInstance::null()),
356                intptr,
357            ))
358        }
359
360        fn from_fn_with_target<T: crate::app::procinst::IProcInst, U: crate::app::procinst::IProcInst>(
361            target: T,
362            callback: extern "C" fn(T, U, OptionalMethod),
363        ) -> Option<Self> {
364            // parameters_count = 2 with a real target makes Invoke(inst) call
365            // method_ptr(target, inst, method_info).
366            let intptr = super::method_info_intptr(callback as *mut u8, 2);
367            Some(ProcVoidFunction::new(
368                <Object as FromIlInstance>::from_il_instance(target.as_instance()),
369                intptr,
370            ))
371        }
372    }
373}
374#[cfg(all(feature = "app-procvoidfunction", feature = "app-procinst", feature = "system-object",))]
375pub use proc_void_function_ext::*;
376
377#[cfg(all(feature = "app-procboolmethod", feature = "system-object"))]
378mod proc_bool_method_ext {
379    use unity::{FromIlInstance, OptionalMethod, SystemObject};
380
381    use crate::{app::procboolmethod::ProcBoolMethod, system::object::Object};
382
383    pub trait ProcBoolMethodExt: Sized {
384        /// Bind `target` and call `callback` on it (returning bool). Like ProcVoidMethod, Invoke() takes
385        /// no VM argument, so the bound target is the only object the callback sees. The callback's first
386        /// parameter is forced to the same type as `target`.
387        fn from_fn<T: crate::app::procinst::IProcInst>(target: T, callback: extern "C" fn(T, OptionalMethod) -> bool) -> Option<Self>;
388    }
389
390    impl ProcBoolMethodExt for ProcBoolMethod {
391        fn from_fn<T: crate::app::procinst::IProcInst>(target: T, callback: extern "C" fn(T, OptionalMethod) -> bool) -> Option<Self> {
392            let intptr = super::method_info_intptr(callback as *mut u8, 0);
393            Some(ProcBoolMethod::new(
394                <Object as FromIlInstance>::from_il_instance(target.as_instance()),
395                intptr,
396            ))
397        }
398    }
399}
400#[cfg(all(feature = "app-procboolmethod", feature = "system-object"))]
401pub use proc_bool_method_ext::*;
402
403#[cfg(all(
404    feature = "app-proc",
405    feature = "app-procvoidmethod",
406    feature = "app-procvoidfunction",
407    feature = "app-procdesc",
408))]
409mod proc_ext {
410    use crate::app::{proc::Proc, procdesc::ProcDesc, procvoidfunction::ProcVoidFunction, procvoidmethod::ProcVoidMethod};
411
412    pub trait ProcExt {
413        fn call_method(method: ProcVoidMethod) -> ProcDesc;
414        fn call_function(function: ProcVoidFunction) -> ProcDesc;
415    }
416
417    impl ProcExt for Proc {
418        fn call_method(method: ProcVoidMethod) -> ProcDesc {
419            Proc::call_2(method)
420        }
421
422        fn call_function(function: ProcVoidFunction) -> ProcDesc {
423            Proc::call(function)
424        }
425    }
426}
427#[cfg(all(
428    feature = "app-proc",
429    feature = "app-procvoidmethod",
430    feature = "app-procvoidfunction",
431    feature = "app-procdesc",
432))]
433pub use proc_ext::*;
434
435#[cfg(feature = "app-procdesc")]
436mod proc_desc_patch {
437    use unity::Array;
438
439    use crate::app::procdesc::ProcDesc;
440    #[cfg(all(feature = "app-proc", feature = "app-procdesclabel"))]
441    use ::unity::Cast;
442    #[cfg(all(feature = "app-proc", feature = "app-procdesclabel"))]
443    use crate::app::proc::Proc;
444    #[cfg(all(feature = "app-proc", feature = "app-procdesclabel"))]
445    use crate::app::procdesclabel::{IProcDescLabel, ProcDescLabel};
446
447    pub struct ProcDescPatch {
448        original: Vec<ProcDesc>,
449        patches: Vec<(usize, Vec<ProcDesc>)>,
450    }
451
452    impl ProcDescPatch {
453        pub fn new(original: Array<ProcDesc>) -> Self {
454            Self {
455                original: original.iter().collect(),
456                patches: Vec::new(),
457            }
458        }
459
460        pub fn insert(mut self, position: usize, descs: impl IntoIterator<Item = ProcDesc>) -> Self {
461            self.patches.push((position, descs.into_iter().collect()));
462            self
463        }
464
465        pub fn finish(mut self) -> Array<ProcDesc> {
466            self.patches.sort_by_key(|patch| std::cmp::Reverse(patch.0));
467            for (pos, descs) in self.patches {
468                self.original.splice(pos..pos, descs);
469            }
470            Array::<ProcDesc>::from_slice(&self.original).expect("ProcDescPatch::finish: ProcDesc array allocation failed")
471        }
472    }
473
474    #[cfg(all(feature = "app-proc", feature = "app-procdesclabel"))]
475    impl ProcDescPatch {
476        fn next_free_label(&self) -> i32 {
477            self.original
478                .iter()
479                .filter_map(|desc| desc.try_cast::<ProcDescLabel>())
480                .map(|label| label.m_label())
481                .max()
482                .map(|highest| highest + 1)
483                .unwrap_or(31)
484        }
485
486        pub fn append_labeled_block(self, body: impl IntoIterator<Item = ProcDesc>) -> (Self, i32) {
487            let label = self.next_free_label();
488            let end = self.original.len();
489            let mut block = std::vec![Proc::label(label)];
490            block.extend(body);
491            (self.insert(end, block), label)
492        }
493    }
494}
495#[cfg(feature = "app-procdesc")]
496pub use proc_desc_patch::*;
497
498#[cfg(feature = "app-basicmenu")]
499mod basic_menu_result {
500    use crate::app::basicmenu::BasicMenu_Result;
501
502    #[repr(transparent)]
503    #[derive(Copy, Clone, PartialEq, Eq)]
504    pub struct BasicMenuResult(pub BasicMenu_Result);
505
506    impl Default for BasicMenuResult {
507        fn default() -> Self {
508            Self::new()
509        }
510    }
511
512    impl BasicMenuResult {
513        const CLOSE_ALL: i32 = 1 << 2;
514        const CLOSE_PARENT: i32 = 1 << 1;
515        const CLOSE_THIS: i32 = 1 << 0;
516        const DELETE_ALL: i32 = 1 << 5;
517        const DELETE_PARENT: i32 = 1 << 4;
518        const DELETE_THIS: i32 = 1 << 3;
519        const DO_NOTHING: i32 = 1 << 13;
520        const SE_CANCEL: i32 = 1 << 9;
521        const SE_CURSOR: i32 = 1 << 12;
522        const SE_DECIDE: i32 = 1 << 7;
523        const SE_DECIDE2: i32 = 1 << 8;
524        const SE_MISS: i32 = 1 << 11;
525
526        #[inline]
527        pub const fn new() -> Self {
528            Self(BasicMenu_Result { value: 0 })
529        }
530
531        #[inline]
532        pub const fn bits(self) -> i32 {
533            self.0.value
534        }
535
536        fn set(mut self, mask: i32, v: bool) -> Self {
537            if v {
538                self.0.value |= mask;
539            } else {
540                self.0.value &= !mask;
541            }
542            self
543        }
544
545        pub const fn close_this(self) -> bool {
546            self.0.value & Self::CLOSE_THIS != 0
547        }
548
549        pub const fn close_parent(self) -> bool {
550            self.0.value & Self::CLOSE_PARENT != 0
551        }
552
553        pub const fn close_all(self) -> bool {
554            self.0.value & Self::CLOSE_ALL != 0
555        }
556
557        pub const fn delete_this(self) -> bool {
558            self.0.value & Self::DELETE_THIS != 0
559        }
560
561        pub const fn delete_parent(self) -> bool {
562            self.0.value & Self::DELETE_PARENT != 0
563        }
564
565        pub const fn delete_all(self) -> bool {
566            self.0.value & Self::DELETE_ALL != 0
567        }
568
569        pub const fn do_nothing(self) -> bool {
570            self.0.value & Self::DO_NOTHING != 0
571        }
572
573        pub fn with_close_this(self, v: bool) -> Self {
574            self.set(Self::CLOSE_THIS, v)
575        }
576
577        pub fn with_close_parent(self, v: bool) -> Self {
578            self.set(Self::CLOSE_PARENT, v)
579        }
580
581        pub fn with_close_all(self, v: bool) -> Self {
582            self.set(Self::CLOSE_ALL, v)
583        }
584
585        pub fn with_delete_this(self, v: bool) -> Self {
586            self.set(Self::DELETE_THIS, v)
587        }
588
589        pub fn with_delete_parent(self, v: bool) -> Self {
590            self.set(Self::DELETE_PARENT, v)
591        }
592
593        pub fn with_delete_all(self, v: bool) -> Self {
594            self.set(Self::DELETE_ALL, v)
595        }
596
597        pub fn with_se_decide(self, v: bool) -> Self {
598            self.set(Self::SE_DECIDE, v)
599        }
600
601        pub fn with_se_decide2(self, v: bool) -> Self {
602            self.set(Self::SE_DECIDE2, v)
603        }
604
605        pub fn with_se_cancel(self, v: bool) -> Self {
606            self.set(Self::SE_CANCEL, v)
607        }
608
609        pub fn with_se_miss(self, v: bool) -> Self {
610            self.set(Self::SE_MISS, v)
611        }
612
613        pub fn with_se_cursor(self, v: bool) -> Self {
614            self.set(Self::SE_CURSOR, v)
615        }
616
617        pub fn with_do_nothing(self, v: bool) -> Self {
618            self.set(Self::DO_NOTHING, v)
619        }
620
621        pub fn se_cursor() -> Self {
622            Self::new().with_se_cursor(true)
623        }
624
625        pub fn se_decide() -> Self {
626            Self::new().with_se_decide(true)
627        }
628
629        pub fn close_decide() -> Self {
630            Self::new().with_close_this(true).with_se_decide(true)
631        }
632
633        pub fn se_miss() -> Self {
634            Self::new().with_se_miss(true)
635        }
636
637        pub fn close_parent_decide() -> Self {
638            Self::new().with_close_parent(true).with_se_decide(true)
639        }
640
641        pub fn delete_decide() -> Self {
642            Self::new().with_delete_this(true).with_se_decide(true)
643        }
644
645        pub fn close_cancel() -> Self {
646            Self::new().with_se_cancel(true).with_close_this(true)
647        }
648    }
649
650    impl ::unity::ClassIdentity for BasicMenuResult {
651        const NAME: &'static str = <BasicMenu_Result as ::unity::ClassIdentity>::NAME;
652        const NAMESPACE: &'static str = <BasicMenu_Result as ::unity::ClassIdentity>::NAMESPACE;
653
654        fn class() -> ::unity::Class {
655            <BasicMenu_Result as ::unity::ClassIdentity>::class()
656        }
657    }
658
659    impl ::unity::IlType for BasicMenuResult {
660        fn il_type() -> &'static ::unity::il2cpp::Il2CppType {
661            <BasicMenu_Result as ::unity::IlType>::il_type()
662        }
663    }
664}
665#[cfg(feature = "app-basicmenu")]
666pub use basic_menu_result::*;
667
668#[cfg(all(feature = "app-basicmenuitem", feature = "app-basicmenu"))]
669mod basic_menu_item_ext {
670    use unity::{Cast, Il2CppString, OptionalMethod};
671
672    use super::BasicMenuResult;
673    pub use crate::app::basicmenuitem::BasicMenuItem_Attribute as BasicMenuItemAttribute;
674    use crate::app::basicmenuitem::{BasicMenuItem, IBasicMenuItemMethods};
675
676    pub trait BasicMenuItemMethods {
677        extern "C" fn get_name(this: BasicMenuItem, method_info: OptionalMethod) -> Il2CppString;
678        extern "C" fn a_call(_this: BasicMenuItem, _method_info: OptionalMethod) -> BasicMenuResult {
679            BasicMenuResult::new()
680        }
681        extern "C" fn b_call(_this: BasicMenuItem, _method_info: OptionalMethod) -> BasicMenuResult {
682            BasicMenuResult::new().with_close_this(true).with_se_cancel(true)
683        }
684        extern "C" fn build_attribute(_this: BasicMenuItem, _method_info: OptionalMethod) -> BasicMenuItemAttribute {
685            BasicMenuItemAttribute::enable()
686        }
687    }
688
689    pub trait BasicMenuItemExt: Sized {
690        fn new_default() -> Self;
691        fn new_impl<M: BasicMenuItemMethods>() -> Self;
692        fn new_impl_from_template<M: BasicMenuItemMethods>(template: BasicMenuItem) -> Self;
693    }
694
695    impl BasicMenuItemExt for BasicMenuItem {
696        fn new_default() -> Self {
697            let item = <Self as ::unity::FromIlInstance>::instantiate().expect("BasicMenuItem::new_default allocation failed");
698            <Self as IBasicMenuItemMethods>::ctor(item);
699            item
700        }
701
702        fn new_impl<M: BasicMenuItemMethods>() -> Self {
703            let item = Self::new_default();
704            let class = item.override_class();
705            class.override_virtual_method("GetName", ::unity::method_info!(M::get_name, 0));
706            class.override_virtual_method("ACall", ::unity::method_info!(M::a_call, 0));
707            class.override_virtual_method("BCall", ::unity::method_info!(M::b_call, 0));
708            class.override_virtual_method("BuildAttribute", ::unity::method_info!(M::build_attribute, 0));
709            item
710        }
711
712        fn new_impl_from_template<M: BasicMenuItemMethods>(template: BasicMenuItem) -> Self {
713            use ::unity::FromIlInstance;
714            let cloned_class = template.get_class().clone_for_override();
715            let item =
716                <Self as FromIlInstance>::instantiate_with_class(cloned_class).expect("BasicMenuItem::new_impl_from_template allocation failed");
717            <Self as IBasicMenuItemMethods>::ctor(item);
718            cloned_class.override_virtual_method("GetName", ::unity::method_info!(M::get_name, 0));
719            cloned_class.override_virtual_method("ACall", ::unity::method_info!(M::a_call, 0));
720            cloned_class.override_virtual_method("BCall", ::unity::method_info!(M::b_call, 0));
721            cloned_class.override_virtual_method("BuildAttribute", ::unity::method_info!(M::build_attribute, 0));
722            item
723        }
724    }
725}
726#[cfg(all(feature = "app-basicmenuitem", feature = "app-basicmenu"))]
727pub use basic_menu_item_ext::*;
728
729#[cfg(all(
730    feature = "app-basicmenu",
731    feature = "app-basicmenucontent",
732    feature = "app-basicmenuitem",
733    feature = "app-procdesc",
734    feature = "system-collections-generic-list_1",
735))]
736mod basic_menu_ext {
737    use unity::Array;
738
739    use crate::{
740        app::{
741            basicmenu::{BasicMenu, IBasicMenu, IBasicMenuMethods},
742            basicmenucontent::BasicMenuContent,
743            basicmenuitem::BasicMenuItem,
744            procdesc::ProcDesc,
745        },
746        system::collections::generic::list_1::{IList_1Methods, List_1},
747    };
748
749    pub trait BasicMenuExt: Sized {
750        fn add_item(self, item: impl Into<BasicMenuItem>);
751        fn close_anime_all(self);
752        fn close_anime(self);
753        fn open_anime_all(self);
754        fn open_anime(self);
755        fn create_default_desc(self) -> Array<ProcDesc>;
756        fn build(menu_item_list: List_1<BasicMenuItem>, menu_content: BasicMenuContent) -> Self;
757    }
758
759    fn basic_menu_virtual_call_0(this: BasicMenu, method_name: &str) {
760        let class = ::unity::object_get_class(this);
761        let entry = class
762            .get_virtual_method(method_name)
763            .unwrap_or_else(|| panic!("BasicMenu vtable missing `{}`", method_name));
764        let f: extern "C" fn(BasicMenu, &'static ::unity::MethodInfo) = unsafe { ::core::mem::transmute(entry.method_ptr) };
765        f(this, entry.method_info)
766    }
767
768    impl BasicMenuExt for BasicMenu {
769        fn add_item(self, item: impl Into<BasicMenuItem>) {
770            self.m_full_menu_item_list().add(item.into());
771        }
772
773        fn close_anime_all(self) {
774            basic_menu_virtual_call_0(self, "CloseAnimeAll");
775        }
776
777        fn close_anime(self) {
778            basic_menu_virtual_call_0(self, "CloseAnime");
779        }
780
781        fn open_anime_all(self) {
782            basic_menu_virtual_call_0(self, "OpenAnimeAll");
783        }
784
785        fn open_anime(self) {
786            basic_menu_virtual_call_0(self, "OpenAnime");
787        }
788
789        fn create_default_desc(self) -> Array<ProcDesc> {
790            let class = ::unity::object_get_class(self);
791            let entry = class
792                .get_virtual_method("CreateDefaultDesc")
793                .expect("BasicMenu vtable missing `CreateDefaultDesc`");
794            let f: extern "C" fn(BasicMenu, &'static ::unity::MethodInfo) -> Array<ProcDesc> = unsafe { ::core::mem::transmute(entry.method_ptr) };
795            f(self, entry.method_info)
796        }
797
798        fn build(menu_item_list: List_1<BasicMenuItem>, menu_content: BasicMenuContent) -> Self {
799            let menu = <Self as ::unity::FromIlInstance>::instantiate().expect("BasicMenu::build allocation failed");
800            <Self as IBasicMenuMethods>::ctor(menu, menu_item_list, menu_content);
801            menu
802        }
803    }
804}
805#[cfg(all(
806    feature = "app-basicmenu",
807    feature = "app-basicmenucontent",
808    feature = "app-basicmenuitem",
809    feature = "app-procdesc",
810    feature = "system-collections-generic-list_1",
811))]
812pub use basic_menu_ext::*;
813
814#[cfg(all(feature = "app-soundmanager", feature = "app-soundsystem", feature = "system-collections-generic-list_1",))]
815mod sound_manager_ext {
816    use unity::{Cast, Il2CppString, MethodInfo};
817
818    use crate::{
819        app::{
820            soundmanager::{ISoundManager, SoundManager},
821            soundsystem::SoundSystem_SoundHandle,
822        },
823        system::collections::generic::list_1::IList_1Methods,
824    };
825
826    pub trait SoundManagerExt: Sized {
827        fn is_event_playing_with_prefix(self, prefix: impl AsRef<str>) -> bool;
828    }
829
830    fn sound_handle_event_name(handle: SoundSystem_SoundHandle) -> Il2CppString {
831        let class = ::unity::object_get_class(handle);
832        let entry = class
833            .get_virtual_method("GetEventName")
834            .expect("SoundSystem.SoundHandle vtable missing `GetEventName`");
835        let f: extern "C" fn(SoundSystem_SoundHandle, &'static MethodInfo) -> Il2CppString = unsafe { ::core::mem::transmute(entry.method_ptr) };
836        f(handle, entry.method_info)
837    }
838
839    impl SoundManagerExt for SoundManager {
840        fn is_event_playing_with_prefix(self, prefix: impl AsRef<str>) -> bool {
841            let prefix = prefix.as_ref();
842            let list = self.m_sound_handle_list();
843            let count = list.get_count();
844            (0..count).any(|i| {
845                let handle = list.get_item(i);
846                !handle.is_null() && sound_handle_event_name(handle).to_string().starts_with(prefix)
847            })
848        }
849    }
850}
851#[cfg(all(feature = "app-soundmanager", feature = "app-soundsystem", feature = "system-collections-generic-list_1",))]
852pub use sound_manager_ext::*;
853
854#[cfg(all(feature = "app-force", feature = "app-unit"))]
855mod force_ext {
856    use unity::Cast;
857
858    use crate::app::{
859        force::{Force, IForceMethods},
860        unit::{IUnitMethods, Unit},
861    };
862
863    pub trait ForceExt: Sized {
864        fn iter(self) -> ForceIter;
865    }
866
867    impl ForceExt for Force {
868        fn iter(self) -> ForceIter {
869            ForceIter { current: self.get_first() }
870        }
871    }
872
873    pub struct ForceIter {
874        current: Unit,
875    }
876
877    impl Iterator for ForceIter {
878        type Item = Unit;
879
880        fn next(&mut self) -> Option<Unit> {
881            if self.current.is_null() {
882                return None;
883            }
884            let unit = self.current;
885            self.current = unit.get_next();
886            Some(unit)
887        }
888    }
889}
890#[cfg(all(feature = "app-force", feature = "app-unit"))]
891pub use force_ext::*;
892
893#[cfg(all(feature = "root-configbasicmenuitem", feature = "app-basicmenuitem", feature = "app-basicmenu",))]
894mod config_basic_menu_item_ext {
895    use unity::{Cast, Il2CppString, OptionalMethod};
896
897    use super::{BasicMenuItemAttribute, BasicMenuResult};
898    use crate::root::configbasicmenuitem::{
899        ConfigBasicMenuItem, ConfigBasicMenuItem_ConfigMethodKind, IConfigBasicMenuItem, IConfigBasicMenuItemMethods,
900    };
901
902    pub trait ConfigBasicMenuItemSwitchMethods {
903        fn init_content(_this: ConfigBasicMenuItem) {}
904        extern "C" fn custom_call(this: ConfigBasicMenuItem, method_info: OptionalMethod) -> BasicMenuResult;
905        extern "C" fn set_command_text(this: ConfigBasicMenuItem, method_info: OptionalMethod);
906        extern "C" fn set_help_text(this: ConfigBasicMenuItem, method_info: OptionalMethod);
907        extern "C" fn a_call(_this: ConfigBasicMenuItem, _method_info: OptionalMethod) -> BasicMenuResult {
908            BasicMenuResult::new()
909        }
910        extern "C" fn build_attribute(_this: ConfigBasicMenuItem, _method_info: OptionalMethod) -> BasicMenuItemAttribute {
911            BasicMenuItemAttribute::enable()
912        }
913    }
914
915    pub trait ConfigBasicMenuItemCommandMethods {
916        fn init_content(_this: ConfigBasicMenuItem) {}
917        extern "C" fn custom_call(this: ConfigBasicMenuItem, method_info: OptionalMethod) -> BasicMenuResult;
918        extern "C" fn set_command_text(this: ConfigBasicMenuItem, method_info: OptionalMethod);
919        extern "C" fn set_help_text(this: ConfigBasicMenuItem, method_info: OptionalMethod);
920        extern "C" fn on_select(this: ConfigBasicMenuItem, _method_info: OptionalMethod) {
921            <ConfigBasicMenuItem as IConfigBasicMenuItemMethods>::on_select(this);
922            this.set_m_is_arrow(false);
923            <ConfigBasicMenuItem as IConfigBasicMenuItemMethods>::on_deselect(this);
924        }
925        extern "C" fn on_deselect(this: ConfigBasicMenuItem, _method_info: OptionalMethod) {
926            <ConfigBasicMenuItem as IConfigBasicMenuItemMethods>::on_select(this);
927            this.set_m_is_arrow(false);
928            <ConfigBasicMenuItem as IConfigBasicMenuItemMethods>::on_deselect(this);
929        }
930        extern "C" fn a_call(_this: ConfigBasicMenuItem, _method_info: OptionalMethod) -> BasicMenuResult {
931            BasicMenuResult::new()
932        }
933        extern "C" fn build_attribute(_this: ConfigBasicMenuItem, _method_info: OptionalMethod) -> BasicMenuItemAttribute {
934            BasicMenuItemAttribute::enable()
935        }
936    }
937
938    pub trait ConfigBasicMenuItemGaugeMethods {
939        fn init_content(_this: ConfigBasicMenuItem) {}
940        extern "C" fn custom_call(this: ConfigBasicMenuItem, method_info: OptionalMethod) -> BasicMenuResult;
941        extern "C" fn set_help_text(this: ConfigBasicMenuItem, method_info: OptionalMethod);
942        extern "C" fn a_call(_this: ConfigBasicMenuItem, _method_info: OptionalMethod) -> BasicMenuResult {
943            BasicMenuResult::new()
944        }
945        extern "C" fn build_attribute(_this: ConfigBasicMenuItem, _method_info: OptionalMethod) -> BasicMenuItemAttribute {
946            BasicMenuItemAttribute::enable()
947        }
948    }
949
950    pub trait ConfigBasicMenuItemExt: Sized {
951        fn new_switch<M: ConfigBasicMenuItemSwitchMethods>(title: impl Into<Il2CppString>) -> Self;
952        fn new_command<M: ConfigBasicMenuItemCommandMethods>(title: impl Into<Il2CppString>) -> Self;
953        fn new_gauge<M: ConfigBasicMenuItemGaugeMethods>(title: impl Into<Il2CppString>) -> Self;
954        fn change_key_value_b(value: bool) -> bool;
955    }
956
957    impl ConfigBasicMenuItemExt for ConfigBasicMenuItem {
958        fn new_switch<M: ConfigBasicMenuItemSwitchMethods>(title: impl Into<Il2CppString>) -> Self {
959            let item = ConfigBasicMenuItem::new();
960            M::init_content(item);
961
962            item.set_m_config_method(ConfigBasicMenuItem_ConfigMethodKind::switch());
963            let class = item.override_class();
964            class.override_virtual_method("CustomCall", ::unity::method_info!(M::custom_call, 0));
965            class.override_virtual_method("ACall", ::unity::method_info!(M::a_call, 0));
966            class.override_virtual_method("BuildAttribute", ::unity::method_info!(M::build_attribute, 0));
967
968            item.set_title_text(title.into());
969            M::set_command_text(item, None);
970            M::set_help_text(item, None);
971
972            item
973        }
974
975        fn new_gauge<M: ConfigBasicMenuItemGaugeMethods>(title: impl Into<Il2CppString>) -> Self {
976            let item = ConfigBasicMenuItem::new();
977            M::init_content(item);
978
979            item.set_m_config_method(ConfigBasicMenuItem_ConfigMethodKind::gauge());
980            let class = item.override_class();
981            class.override_virtual_method("CustomCall", ::unity::method_info!(M::custom_call, 0));
982            class.override_virtual_method("ACall", ::unity::method_info!(M::a_call, 0));
983            class.override_virtual_method("BuildAttribute", ::unity::method_info!(M::build_attribute, 0));
984
985            item.set_title_text(title.into());
986            M::set_help_text(item, None);
987
988            item
989        }
990
991        fn new_command<M: ConfigBasicMenuItemCommandMethods>(title: impl Into<Il2CppString>) -> Self {
992            let item = ConfigBasicMenuItem::new();
993            M::init_content(item);
994
995            item.set_m_config_method(ConfigBasicMenuItem_ConfigMethodKind::switch());
996            item.set_m_is_arrow(false);
997            item.set_m_is_command_icon(true);
998            let class = item.override_class();
999            class.override_virtual_method("CustomCall", ::unity::method_info!(M::custom_call, 0));
1000            class.override_virtual_method("OnSelect", ::unity::method_info!(M::on_select, 0));
1001            class.override_virtual_method("OnDeselect", ::unity::method_info!(M::on_deselect, 0));
1002            class.override_virtual_method("ACall", ::unity::method_info!(M::a_call, 0));
1003            class.override_virtual_method("BuildAttribute", ::unity::method_info!(M::build_attribute, 0));
1004
1005            item.set_title_text(title.into());
1006            M::set_command_text(item, None);
1007            M::set_help_text(item, None);
1008
1009            item
1010        }
1011
1012        fn change_key_value_b(value: bool) -> bool {
1013            ConfigBasicMenuItem::change_key_value(value as i32, 0, 1, 1) == 1
1014        }
1015    }
1016}
1017#[cfg(all(feature = "root-configbasicmenuitem", feature = "app-basicmenuitem", feature = "app-basicmenu",))]
1018pub use config_basic_menu_item_ext::*;
1019
1020#[cfg(feature = "app-procinst")]
1021mod restore_parent_on_dispose_ext {
1022    use unity::{Cast, OptionalMethod};
1023
1024    pub extern "C" fn restore_parent_on_dispose(this: crate::app::procinst::ProcInst, _method_info: OptionalMethod) {
1025        use crate::app::procinst::IProcInstMethods;
1026        let parent = this.get_super();
1027        if parent.is_null() {
1028            return;
1029        }
1030        if let Some(slot) = parent.get_class().raw().get_virtual_method("OpenAnimeAll") {
1031            let f: extern "C" fn(crate::app::procinst::ProcInst, &'static ::unity::MethodInfo) = unsafe { ::core::mem::transmute(slot.method_ptr) };
1032            f(parent, slot.method_info);
1033        }
1034    }
1035}
1036#[cfg(feature = "app-procinst")]
1037pub use restore_parent_on_dispose_ext::*;
1038
1039#[cfg(all(
1040    feature = "app-basicdialog",
1041    feature = "app-yesmenuitem",
1042    feature = "app-basicdialogitem",
1043    feature = "app-basicdialogitemno",
1044    feature = "app-basicmenuitem",
1045    feature = "system-collections-generic-list_1",
1046    feature = "app-procinst",
1047    feature = "system-action",
1048))]
1049mod basic_menu_confirm_ext {
1050    use unity::Il2CppString;
1051
1052    use crate::{
1053        app::{
1054            basicdialog::{BasicDialog, IBasicDialogMethods},
1055            basicdialogitemno::{BasicDialogItemNo, IBasicDialogItemNoMethods},
1056            basicmenuitem::BasicMenuItem,
1057            yesmenuitem::{IYesMenuItemMethods, YesMenuItem},
1058        },
1059        system::{
1060            action::Action,
1061            collections::generic::list_1::{IList_1Methods, List_1},
1062        },
1063    };
1064
1065    pub fn basic_menu_confirm(
1066        proc: impl Into<crate::app::procinst::ProcInst>,
1067        message: impl Into<Il2CppString>,
1068        yes_text: impl Into<Il2CppString>,
1069        no_text: impl Into<Il2CppString>,
1070        handler: Action,
1071    ) -> BasicDialog {
1072        use crate::app::basicdialogitem::IBasicDialogItem;
1073        let yes_item = <YesMenuItem as ::unity::FromIlInstance>::instantiate().expect("YesMenuItem allocation failed");
1074        <YesMenuItem as IYesMenuItemMethods>::ctor(yes_item, handler);
1075        yes_item.set_m_text(yes_text.into());
1076
1077        let no_item = <BasicDialogItemNo as ::unity::FromIlInstance>::instantiate().expect("BasicDialogItemNo allocation failed");
1078        <BasicDialogItemNo as IBasicDialogItemNoMethods>::ctor_2(no_item, no_text.into());
1079
1080        let items = List_1::<BasicMenuItem>::new();
1081        items.add(yes_item.into());
1082        items.add(no_item.into());
1083
1084        let dialog = BasicDialog::create_basic_dialog_bind(proc.into(), items);
1085        dialog.set_text(message.into());
1086        dialog
1087    }
1088}
1089#[cfg(all(
1090    feature = "app-basicdialog",
1091    feature = "app-yesmenuitem",
1092    feature = "app-basicdialogitem",
1093    feature = "app-basicdialogitemno",
1094    feature = "app-basicmenuitem",
1095    feature = "system-collections-generic-list_1",
1096    feature = "app-procinst",
1097    feature = "system-action",
1098))]
1099pub use basic_menu_confirm_ext::*;
1100
1101#[cfg(all(
1102    feature = "app-yesnodialog",
1103    feature = "app-basicdialogitemyes",
1104    feature = "app-basicdialogitemno",
1105    feature = "app-procinst",
1106    feature = "app-basicmenu",
1107))]
1108mod yes_no_dialog_ext {
1109    use unity::{Cast, Il2CppString, OptionalMethod};
1110
1111    use super::BasicMenuResult;
1112    use crate::app::{
1113        basicdialogitemno::{BasicDialogItemNo, IBasicDialogItemNoMethods},
1114        basicdialogitemyes::{BasicDialogItemYes, IBasicDialogItemYesMethods},
1115        yesnodialog::YesNoDialog,
1116    };
1117
1118    pub trait TwoChoiceDialogMethods {
1119        extern "C" fn on_first_choice(_this: BasicDialogItemYes, _method_info: OptionalMethod) -> BasicMenuResult {
1120            BasicMenuResult::new().with_close_this(true)
1121        }
1122        extern "C" fn on_second_choice(_this: BasicDialogItemNo, _method_info: OptionalMethod) -> BasicMenuResult {
1123            BasicMenuResult::new().with_close_this(true)
1124        }
1125        extern "C" fn bcall_first(_this: BasicDialogItemYes, _method_info: OptionalMethod) -> BasicMenuResult {
1126            BasicMenuResult::new().with_close_this(true).with_se_cancel(true)
1127        }
1128        extern "C" fn bcall_second(_this: BasicDialogItemNo, _method_info: OptionalMethod) -> BasicMenuResult {
1129            BasicMenuResult::new().with_close_this(true).with_se_cancel(true)
1130        }
1131    }
1132
1133    pub trait YesNoDialogExt {
1134        fn bind_with<Methods: TwoChoiceDialogMethods>(
1135            proc: impl Into<crate::app::procinst::ProcInst>,
1136            message: impl Into<Il2CppString>,
1137            first_text: impl Into<Il2CppString>,
1138            second_text: impl Into<Il2CppString>,
1139        );
1140    }
1141
1142    impl YesNoDialogExt for YesNoDialog {
1143        fn bind_with<Methods: TwoChoiceDialogMethods>(
1144            proc: impl Into<crate::app::procinst::ProcInst>,
1145            message: impl Into<Il2CppString>,
1146            first_text: impl Into<Il2CppString>,
1147            second_text: impl Into<Il2CppString>,
1148        ) {
1149            let yes = <BasicDialogItemYes as ::unity::FromIlInstance>::instantiate().expect("BasicDialogItemYes allocation failed");
1150            <BasicDialogItemYes as IBasicDialogItemYesMethods>::ctor_2(yes, first_text.into());
1151            let no = <BasicDialogItemNo as ::unity::FromIlInstance>::instantiate().expect("BasicDialogItemNo allocation failed");
1152            <BasicDialogItemNo as IBasicDialogItemNoMethods>::ctor_2(no, second_text.into());
1153
1154            let yes_class = yes.override_class();
1155            let no_class = no.override_class();
1156
1157            let on_first = ::unity::method_info!(Methods::on_first_choice, 0);
1158            let bcall_first = ::unity::method_info!(Methods::bcall_first, 0);
1159            let on_second = ::unity::method_info!(Methods::on_second_choice, 0);
1160            let bcall_second = ::unity::method_info!(Methods::bcall_second, 0);
1161
1162            yes_class.override_virtual_method("ACall", on_first);
1163            yes_class.override_virtual_method("BCall", bcall_first);
1164            no_class.override_virtual_method("ACall", on_second);
1165            no_class.override_virtual_method("BCall", bcall_second);
1166
1167            let _ = YesNoDialog::create_bind(proc.into(), message.into(), yes, no);
1168        }
1169    }
1170}
1171#[cfg(all(
1172    feature = "app-yesnodialog",
1173    feature = "app-basicdialogitemyes",
1174    feature = "app-basicdialogitemno",
1175    feature = "app-procinst",
1176    feature = "app-basicmenu",
1177))]
1178pub use yes_no_dialog_ext::*;
1179
1180#[cfg(feature = "app-filedata")]
1181mod file_handle_ext {
1182    use unity::MethodInfo;
1183
1184    #[::unity::class(namespace = "App", name = "FileHandle`1")]
1185    pub struct FileHandle {
1186        #[rename(name = "m_Data")]
1187        pub m_data: crate::app::filedata::FileData,
1188    }
1189
1190    impl FileHandle {
1191        pub fn unload(self) {
1192            let class = ::unity::object_get_class(self);
1193            let method = class
1194                .get_method_from_name("Unload", 0)
1195                .expect("FileHandle::Unload missing from runtime class");
1196            let unload: extern "C" fn(Self, &MethodInfo) = unsafe { ::core::mem::transmute(method.method_ptr) };
1197            unload(self, method);
1198        }
1199    }
1200}
1201#[cfg(feature = "app-filedata")]
1202pub use file_handle_ext::*;
1203
1204#[cfg(all(
1205    feature = "app-itemdata",
1206    feature = "app-scriptutil",
1207    feature = "moon_sharp-interpreter-dynvalue",
1208    feature = "app-unit",
1209))]
1210mod dyn_value_args_ext {
1211    use unity::{Array, FromIlInstance, Il2CppString, IlInstance};
1212
1213    use crate::{
1214        app::{itemdata::ItemData, scriptutil::ScriptUtil, unit::Unit},
1215        moon_sharp::interpreter::dynvalue::DynValue,
1216    };
1217
1218    pub trait DynValueArgs {
1219        fn try_get_i32(self, index: i32) -> i32;
1220        fn try_get_string(self, index: i32) -> Il2CppString;
1221        fn try_get_unit(self, index: i32) -> Unit;
1222        fn try_get_item(self, index: i32) -> ItemData;
1223    }
1224
1225    impl DynValueArgs for Array<DynValue> {
1226        fn try_get_i32(self, index: i32) -> i32 {
1227            ScriptUtil::try_get_int(self, index, i32::MAX)
1228        }
1229
1230        fn try_get_string(self, index: i32) -> Il2CppString {
1231            ScriptUtil::try_get_string(self, index, Il2CppString::from_il_instance(IlInstance::null()))
1232        }
1233
1234        fn try_get_unit(self, index: i32) -> Unit {
1235            ScriptUtil::try_get_unit(self, index, true)
1236        }
1237
1238        fn try_get_item(self, index: i32) -> ItemData {
1239            ScriptUtil::try_get_item(self, index, true)
1240        }
1241    }
1242}
1243#[cfg(all(
1244    feature = "app-itemdata",
1245    feature = "app-scriptutil",
1246    feature = "moon_sharp-interpreter-dynvalue",
1247    feature = "app-unit",
1248))]
1249pub use dyn_value_args_ext::*;
1250
1251#[cfg(all(feature = "app-eventscript", feature = "moon_sharp-interpreter-dynvalue"))]
1252mod event_script_ext {
1253    use unity::{Array, Class, FromIlInstance, Il2CppString, IlInstance, IntPtr, MethodInfo, OptionalMethod};
1254
1255    use crate::{
1256        app::eventscript::{EventScript, EventScript_ActionArgs, EventScript_FunctionArgs, IEventScriptMethods},
1257        moon_sharp::interpreter::dynvalue::DynValue,
1258    };
1259
1260    #[::unity::class(namespace = "App", name = "EventScript.ActionArgs")]
1261    pub struct EventScriptActionArgsExt {
1262        #[rename(name = "method_ptr")]
1263        pub method_ptr: ::unity::IntPtr,
1264        #[rename(name = "m_target")]
1265        pub m_target: ::unity::IlInstance,
1266        #[rename(name = "method")]
1267        pub method: ::unity::IntPtr,
1268    }
1269
1270    #[::unity::class(namespace = "App", name = "EventScript.FunctionArgs")]
1271    pub struct EventScriptFunctionArgsExt {
1272        #[rename(name = "method_ptr")]
1273        pub method_ptr: ::unity::IntPtr,
1274        #[rename(name = "m_target")]
1275        pub m_target: ::unity::IlInstance,
1276        #[rename(name = "method")]
1277        pub method: ::unity::IntPtr,
1278    }
1279
1280    fn clone_invoke_method_info(method_ptr: *mut u8) -> &'static MethodInfo {
1281        use std::{collections::HashMap, sync::Mutex};
1282
1283        static CACHE: Mutex<Option<HashMap<usize, &'static MethodInfo>>> = Mutex::new(None);
1284
1285        let mut guard = CACHE.lock().unwrap();
1286        let map = guard.get_or_insert_with(HashMap::new);
1287        let key = method_ptr as usize;
1288        if let Some(mi) = map.get(&key) {
1289            return mi;
1290        }
1291        let donor = Class::lookup("App", "ScriptSystem")
1292            .raw()
1293            .get_method_from_name("Log", 1)
1294            .expect("App.ScriptSystem::Log(args) donor missing");
1295        let mut cloned: MethodInfo = *donor;
1296        cloned.method_ptr = method_ptr;
1297        let leaked: &'static MethodInfo = Box::leak(Box::new(cloned));
1298        map.insert(key, leaked);
1299        leaked
1300    }
1301
1302    fn make_action_args(callback: *mut u8) -> EventScript_ActionArgs {
1303        let mi = clone_invoke_method_info(callback);
1304        let instance = <EventScriptActionArgsExt as FromIlInstance>::instantiate().expect("EventScript.ActionArgs allocation failed");
1305        instance.set_method_ptr(IntPtr(callback as *mut ()));
1306        instance.set_m_target(IlInstance::null());
1307        instance.set_method(IntPtr(mi as *const MethodInfo as *mut ()));
1308        EventScript_ActionArgs::from_il_instance(IlInstance::from(instance))
1309    }
1310
1311    fn make_function_args(callback: *mut u8) -> EventScript_FunctionArgs {
1312        let mi = clone_invoke_method_info(callback);
1313        let instance = <EventScriptFunctionArgsExt as FromIlInstance>::instantiate().expect("EventScript.FunctionArgs allocation failed");
1314        instance.set_method_ptr(IntPtr(callback as *mut ()));
1315        instance.set_m_target(IlInstance::null());
1316        instance.set_method(IntPtr(mi as *const MethodInfo as *mut ()));
1317        EventScript_FunctionArgs::from_il_instance(IlInstance::from(instance))
1318    }
1319
1320    pub trait EventScriptExt {
1321        fn register_action(self, name: impl Into<Il2CppString>, callback: extern "C" fn(Array<DynValue>, OptionalMethod));
1322        fn register_function(self, name: impl Into<Il2CppString>, callback: extern "C" fn(Array<DynValue>, OptionalMethod) -> DynValue);
1323    }
1324
1325    impl EventScriptExt for EventScript {
1326        fn register_action(self, name: impl Into<Il2CppString>, callback: extern "C" fn(Array<DynValue>, OptionalMethod)) {
1327            let args = make_action_args(callback as *mut u8);
1328            self.regist_action(args, name.into());
1329        }
1330
1331        fn register_function(self, name: impl Into<Il2CppString>, callback: extern "C" fn(Array<DynValue>, OptionalMethod) -> DynValue) {
1332            let args = make_function_args(callback as *mut u8);
1333            self.regist_function(args, name.into());
1334        }
1335    }
1336}
1337#[cfg(all(feature = "app-eventscript", feature = "moon_sharp-interpreter-dynvalue"))]
1338pub use event_script_ext::*;
1339
1340#[cfg(all(feature = "unity_engine-assetbundle", feature = "unity_engine-assetbundlecreaterequest",))]
1341mod asset_bundle_ext {
1342    use unity::{Array, OptionalMethod};
1343
1344    use crate::unity_engine::{assetbundle::AssetBundle, assetbundlecreaterequest::AssetBundleCreateRequest};
1345
1346    #[skyline::from_offset(0x491ff0)]
1347    unsafe fn engage_method_from_full_name(name: *const u8) -> *const u8;
1348
1349    fn lookup_method_by_signature(full_signature: &str) -> *const u8 {
1350        let c = std::ffi::CString::new(full_signature).unwrap();
1351        unsafe { engage_method_from_full_name(c.as_ptr() as *const u8) }
1352    }
1353
1354    pub trait AssetBundleExt {
1355        fn load_from_memory_async_internal(binary: Array<u8>, crc: u32) -> AssetBundleCreateRequest;
1356    }
1357
1358    impl AssetBundleExt for AssetBundle {
1359        fn load_from_memory_async_internal(binary: Array<u8>, crc: u32) -> AssetBundleCreateRequest {
1360            static METHOD_PTR: ::std::sync::OnceLock<usize> = ::std::sync::OnceLock::new();
1361            let ptr = *METHOD_PTR.get_or_init(|| {
1362                let p = lookup_method_by_signature("UnityEngine.AssetBundle::LoadFromMemoryAsync_Internal(System.Byte[],System.UInt32)");
1363                assert!(
1364                    !p.is_null(),
1365                    "UnityEngine.AssetBundle.LoadFromMemoryAsync_Internal not found via runtime full-signature lookup"
1366                );
1367                p as usize
1368            });
1369
1370            type RawFn = extern "C" fn(Array<u8>, u32, OptionalMethod) -> AssetBundleCreateRequest;
1371            let f: RawFn = unsafe { ::std::mem::transmute(ptr) };
1372            f(binary, crc, None)
1373        }
1374    }
1375}
1376#[cfg(all(feature = "unity_engine-assetbundle", feature = "unity_engine-assetbundlecreaterequest",))]
1377pub use asset_bundle_ext::*;