classicube_sys\command/
owned_chat_command.rs1use core::{ffi::CStr, ptr};
2
3use crate::{
4 COMMAND_FLAG_SINGLEPLAYER_ONLY, ChatCommand,
5 bindings::{Commands_Register, cc_string},
6 std_types::{Box, CString, Vec, c_int},
7};
8
9pub struct OwnedChatCommand {
10 pub name: Box<CStr>,
11 pub help: Vec<Box<CStr>>,
12 pub command: Box<ChatCommand>,
13}
14
15impl OwnedChatCommand {
16 pub fn new(
20 name: &str,
21 execute: unsafe extern "C" fn(args: *const cc_string, argsCount: c_int),
22 singleplayer_only: bool,
23 mut help: Vec<&str>,
24 ) -> Self {
25 let name = CString::new(name).unwrap().into_boxed_c_str();
26
27 let help: Vec<Box<CStr>> = help
28 .drain(..)
29 .map(|s| CString::new(s).unwrap().into_boxed_c_str())
30 .collect();
31
32 let help_array = [
33 #[expect(
34 clippy::get_first,
35 reason = "consistent indexing across the 5-slot array"
36 )]
37 help.get(0).map_or(ptr::null(), |cs| cs.as_ptr()),
38 help.get(1).map_or(ptr::null(), |cs| cs.as_ptr()),
39 help.get(2).map_or(ptr::null(), |cs| cs.as_ptr()),
40 help.get(3).map_or(ptr::null(), |cs| cs.as_ptr()),
41 help.get(4).map_or(ptr::null(), |cs| cs.as_ptr()),
42 ];
43
44 #[expect(
45 clippy::cast_possible_truncation,
46 reason = "COMMAND_FLAG_SINGLEPLAYER_ONLY fits in the flags u8"
47 )]
48 let flags = if singleplayer_only {
49 COMMAND_FLAG_SINGLEPLAYER_ONLY as _
50 } else {
51 0
52 };
53
54 let command = Box::new(ChatCommand {
55 name: name.as_ptr(),
56 Execute: Some(execute),
57 flags,
58 help: help_array,
59 next: ptr::null_mut(),
60 });
61
62 Self {
63 name,
64 help,
65 command,
66 }
67 }
68
69 pub fn register(&mut self) {
70 let OwnedChatCommand { command, .. } = self;
71
72 unsafe {
73 Commands_Register(command.as_mut());
74 }
75 }
76}
77
78