gmodx/
open_close.rs

1use std::{collections::HashSet, sync::atomic::AtomicBool};
2
3use crate::lua::{self, ffi};
4
5static GMOD_CLOSED: AtomicBool = AtomicBool::new(true);
6
7#[inline]
8pub fn is_closed() -> bool {
9    GMOD_CLOSED.load(std::sync::atomic::Ordering::Acquire)
10}
11
12#[inline]
13pub fn is_open() -> bool {
14    !is_closed()
15}
16
17pub struct OpenClose {
18    pub priority: i32, // Lower priority loads first
19    pub id: &'static str,
20    pub open: fn(&lua::State),
21    pub close: fn(&lua::State),
22}
23
24pub const fn new(
25    priority: i32,
26    id: &'static str,
27    open: fn(&lua::State),
28    close: fn(&lua::State),
29) -> OpenClose {
30    OpenClose {
31        priority,
32        id,
33        open,
34        close,
35    }
36}
37
38inventory::collect!(OpenClose);
39
40fn get_sorted_modules() -> Vec<&'static OpenClose> {
41    let mut modules: Vec<&OpenClose> = inventory::iter::<OpenClose>().collect();
42
43    let mut seen_ids = HashSet::new();
44    for module in &modules {
45        if !seen_ids.insert(module.id) {
46            panic!("Duplicate OpenClose ID: {}", module.id);
47        }
48    }
49
50    // Sort by priority (lower priority loads first)
51    // For modules with same priority, maintain a stable order
52    modules.sort_by_key(|m| (m.priority, m.id));
53
54    modules
55}
56
57#[allow(unused)]
58pub fn load_all(state: &lua::State) {
59    GMOD_CLOSED.store(false, std::sync::atomic::Ordering::Release);
60
61    let modules = get_sorted_modules();
62    for module in &modules {
63        ffi::lua_settop(state.0, 1); // Clear the stack, on gmod13_open, there is a string at index 1
64        (module.open)(state);
65        #[cfg(debug_assertions)]
66        println!(
67            "[gmodx] Loaded OpenClose '{}' (priority: {})",
68            module.id, module.priority
69        );
70    }
71}
72
73#[allow(unused)]
74pub fn unload_all(state: &lua::State) {
75    GMOD_CLOSED.store(true, std::sync::atomic::Ordering::Release);
76
77    let modules = get_sorted_modules();
78    // Unload in reverse order
79    for module in modules.iter().rev() {
80        ffi::lua_settop(state.0, 0); // Clear the stack
81        (module.close)(state);
82        #[cfg(debug_assertions)]
83        println!(
84            "[gmodx] Unloaded OpenClose '{}' (priority: {})",
85            module.id, module.priority
86        );
87    }
88}