1use crate::{
15 as_tbl, coalition::Side, env::miz::GroupId, wrap_f, wrapped_table, LuaEnv, MizLua, String,
16};
17use anyhow::Result;
18use compact_str::format_compact;
19use mlua::{prelude::*, Value};
20use serde_derive::Serialize;
21use std::ops::Deref;
22
23#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
24struct ItemPath(Vec<String>);
25
26impl<'lua> IntoLua<'lua> for ItemPath {
27 fn into_lua(self, lua: &'lua Lua) -> LuaResult<Value<'lua>> {
28 let tbl = lua.create_table()?;
29 for s in self.0 {
30 tbl.raw_push(s)?
31 }
32 Ok(Value::Table(tbl))
33 }
34}
35
36impl<'lua> FromLua<'lua> for ItemPath {
37 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> LuaResult<Self> {
38 let tbl = LuaTable::from_lua(value, lua)?;
39 let mut res = Vec::new();
40 for v in tbl.sequence_values() {
41 let v = v?;
42 res.push(String::from_lua(v, lua)?);
43 }
44 Ok(Self(res))
45 }
46}
47
48macro_rules! item {
49 ($name:ident) => {
50 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
51 pub struct $name(ItemPath);
52
53 impl<'lua> IntoLua<'lua> for $name {
54 fn into_lua(self, lua: &'lua Lua) -> LuaResult<Value<'lua>> {
55 self.0.into_lua(lua)
56 }
57 }
58
59 impl<'lua> FromLua<'lua> for $name {
60 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> LuaResult<Self> {
61 Ok(Self(ItemPath::from_lua(value, lua)?))
62 }
63 }
64
65 impl From<Vec<String>> for $name {
66 fn from(v: Vec<String>) -> Self {
67 Self(ItemPath(v))
68 }
69 }
70
71 impl Into<Vec<String>> for $name {
72 fn into(self) -> Vec<String> {
73 (self.0).0
74 }
75 }
76 };
77}
78
79item!(SubMenu);
80item!(CoalitionSubMenu);
81item!(GroupSubMenu);
82item!(CommandItem);
83item!(CoalitionCommandItem);
84item!(GroupCommandItem);
85
86wrapped_table!(MissionCommands, None);
87
88impl<'lua> MissionCommands<'lua> {
89 pub fn singleton(lua: MizLua<'lua>) -> Result<Self> {
90 Ok(lua.inner().globals().raw_get("missionCommands")?)
91 }
92
93 pub fn add_submenu(&self, name: String, parent: Option<SubMenu>) -> Result<SubMenu> {
94 Ok(self.call_function("addSubMenu", (name, parent))?)
95 }
96
97 pub fn add_command<F, A>(
98 &self,
99 name: String,
100 parent: Option<SubMenu>,
101 f: F,
102 arg: A,
103 ) -> Result<CommandItem>
104 where
105 F: Fn(MizLua, A) -> Result<()> + 'static,
106 A: IntoLua<'lua> + FromLua<'lua>,
107 {
108 let msg = format_compact!("command {:?},{name}", parent);
109 let f = self.lua.create_function(move |lua, arg: A| {
110 wrap_f(msg.as_str(), MizLua(lua), |lua| f(lua, arg))
111 })?;
112 Ok(self.call_function("addCommand", (name, parent, f, arg))?)
113 }
114
115 pub fn remove_submenu(&self, menu: SubMenu) -> Result<()> {
116 Ok(self.call_function("removeItem", menu)?)
117 }
118
119 pub fn remove_command(&self, item: CommandItem) -> Result<()> {
120 Ok(self.call_function("removeItem", item)?)
121 }
122
123 pub fn add_submenu_for_coalition(
124 &self,
125 side: Side,
126 name: String,
127 parent: Option<CoalitionSubMenu>,
128 ) -> Result<CoalitionSubMenu> {
129 Ok(self.call_function("addSubMenuForCoalition", (side, name, parent))?)
130 }
131
132 pub fn add_command_for_coalition<F, A>(
133 &self,
134 side: Side,
135 name: String,
136 parent: Option<CoalitionSubMenu>,
137 f: F,
138 arg: A,
139 ) -> Result<CoalitionCommandItem>
140 where
141 F: Fn(MizLua, A) -> Result<()> + 'static,
142 A: IntoLua<'lua> + FromLua<'lua>,
143 {
144 let msg = format_compact!("coa cmd {:?},{name}", parent);
145 let f = self.lua.create_function(move |lua, arg: A| {
146 wrap_f(msg.as_str(), MizLua(lua), |lua| f(lua, arg))
147 })?;
148 Ok(self.call_function("addCommandForCoalition", (side, name, parent, f, arg))?)
149 }
150
151 pub fn remove_submenu_for_coalition(&self, side: Side, menu: CoalitionSubMenu) -> Result<()> {
152 Ok(self.call_function("removeItemForCoalition", (side, menu))?)
153 }
154
155 pub fn remove_command_for_coalition(&self, side: Side, item: CoalitionCommandItem) -> Result<()> {
156 Ok(self.call_function("removeItemForCoalition", (side, item))?)
157 }
158
159 pub fn add_submenu_for_group(
160 &self,
161 group: GroupId,
162 name: String,
163 parent: Option<GroupSubMenu>,
164 ) -> Result<GroupSubMenu> {
165 Ok(self.call_function("addSubMenuForGroup", (group, name, parent))?)
166 }
167
168 pub fn add_command_for_group<F, A>(
169 &self,
170 group: GroupId,
171 name: String,
172 parent: Option<GroupSubMenu>,
173 f: F,
174 arg: A,
175 ) -> Result<GroupCommandItem>
176 where
177 F: Fn(MizLua, A) -> Result<()> + 'static,
178 A: IntoLua<'lua> + FromLua<'lua>,
179 {
180 let msg = format_compact!("grp cmd {:?}, {name}", parent);
181 let f = self.lua.create_function(move |lua, arg: A| {
182 wrap_f(msg.as_str(), MizLua(lua), |lua| f(lua, arg))
183 })?;
184 Ok(self.call_function("addCommandForGroup", (group, name, parent, f, arg))?)
185 }
186
187 pub fn remove_submenu_for_group(&self, group: GroupId, menu: GroupSubMenu) -> Result<()> {
188 Ok(self.call_function("removeItemForGroup", (group, menu))?)
189 }
190
191 pub fn remove_command_for_group(&self, group: GroupId, item: GroupCommandItem) -> Result<()> {
192 Ok(self.call_function("removeItemForGroup", (group, item))?)
193 }
194
195 pub fn clear_all_menus(&self) -> Result<()> {
196 Ok(self.call_function("removeItem", ())?)
197 }
198}