From 5ca2a63b5eb37033f833dbc9471fefe7acb4f19a Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Sat, 21 Sep 2024 02:30:06 -0400 Subject: [PATCH] Allow Custom Commands --- example-mods/chat-commands/chat-commands.cpp | 18 ++ mods/include/mods/server/server.h | 12 ++ mods/src/server/server.cpp | 212 ++++++++++--------- 3 files changed, 141 insertions(+), 101 deletions(-) diff --git a/example-mods/chat-commands/chat-commands.cpp b/example-mods/chat-commands/chat-commands.cpp index 14aebfaa..de20cfef 100644 --- a/example-mods/chat-commands/chat-commands.cpp +++ b/example-mods/chat-commands/chat-commands.cpp @@ -3,6 +3,7 @@ #include #include #include +#include // The Actual Mod HOOK(chat_handle_packet_send, void, (const Minecraft *minecraft, ChatPacket *packet)) { @@ -23,3 +24,20 @@ HOOK(chat_handle_packet_send, void, (const Minecraft *minecraft, ChatPacket *pac real_chat_handle_packet_send(minecraft, packet); } } + +// Add Server Command +HOOK(server_get_commands, std::vector *, (Minecraft *minecraft, ServerSideNetworkHandler *server_side_network_handler)) { + // Call Original Method + ensure_server_get_commands(); + std::vector *commands = real_server_get_commands(minecraft, server_side_network_handler); + // Add Command + commands->push_back({ + .name = "greet", + .comment = "Example Custom Command", + .callback = [](__attribute__((unused)) const std::string &cmd) { + INFO("Hello World!"); + } + }); + // Return + return commands; +} \ No newline at end of file diff --git a/mods/include/mods/server/server.h b/mods/include/mods/server/server.h index 06d19449..7a6db404 100644 --- a/mods/include/mods/server/server.h +++ b/mods/include/mods/server/server.h @@ -1,7 +1,19 @@ #pragma once +#include + #include "server_properties.h" +struct ServerCommand { + const std::string name; + const std::string comment; + const std::function callback; + [[nodiscard]] bool has_args() const; + [[nodiscard]] std::string get_lhs_help() const; + [[nodiscard]] std::string get_full_help(int max_lhs_length) const; +}; + extern "C" { +std::vector *server_get_commands(Minecraft *minecraft, ServerSideNetworkHandler *server_side_network_handler); ServerProperties &get_server_properties(); } \ No newline at end of file diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index e02ad394..155bf50f 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -271,30 +271,115 @@ static void handle_server_stop(Minecraft *minecraft) { } // Handle Commands -struct Command { - const std::string name; - const std::string comment; - const std::function callback; - [[nodiscard]] bool has_args() const { - return name[name.length() - 1] == ' '; +bool ServerCommand::has_args() const { + return name[name.length() - 1] == ' '; +} +std::string ServerCommand::get_lhs_help() const { + std::string out; + out.append(4, ' '); + out += name; + if (has_args()) { + out += ""; } - [[nodiscard]] std::string get_lhs_help() const { - std::string out; - out.append(4, ' '); - out += name; - if (has_args()) { - out += ""; + return out; +} +std::string ServerCommand::get_full_help(const int max_lhs_length) const { + std::string out = get_lhs_help(); + out.append(max_lhs_length - out.length(), ' '); + out += " - "; + out += comment; + return out; +} +std::vector *server_get_commands(Minecraft *minecraft, ServerSideNetworkHandler *server_side_network_handler) { + std::vector *commands = new std::vector; + // Ban Player + if (!is_whitelist()) { + commands->push_back({ + .name = "ban ", + .comment = "IP-Ban All Players With Specified Username", + .callback = [minecraft](const std::string &cmd) { + find_players(minecraft, cmd, ban_callback, false); + } + }); + } + // Reload White/Blacklist + commands->push_back({ + .name = "reload", + .comment = std::string("Reload The ") + (is_whitelist() ? "Whitelist" : "Blacklist"), + .callback = [](__attribute__((unused)) const std::string &cmd) { + INFO("Reloading %s", is_whitelist() ? "Whitelist" : "Blacklist"); + is_ip_in_blacklist(nullptr); } - return out; - } - [[nodiscard]] std::string get_full_help(const int max_lhs_length) const { - std::string out = get_lhs_help(); - out.append(max_lhs_length - out.length(), ' '); - out += " - "; - out += comment; - return out; - } -}; + }); + // Kill Player + commands->push_back({ + .name = "kill ", + .comment = "Kill All Players With Specified Username", + .callback = [minecraft](const std::string &cmd) { + find_players(minecraft, cmd, kill_callback, false); + } + }); + // Post Message + commands->push_back({ + .name = "say ", + .comment = "Print Specified Message To Chat", + .callback = [server_side_network_handler](const std::string &cmd) { + // Format Message + const std::string message = "[Server] " + cmd; + char *safe_message = to_cp437(message.c_str()); + std::string cpp_string = safe_message; + // Post Message To Chat + server_side_network_handler->displayGameMessage(cpp_string); + // Free + free(safe_message); + } + }); + // List Players + commands->push_back({ + .name = "list", + .comment = "List All Players", + .callback = [minecraft](__attribute__((unused)) const std::string &cmd) { + INFO("All Players:"); + find_players(minecraft, "", list_callback, true); + } + }); + // Ticks-Per-Second + commands->push_back({ + .name = "tps", + .comment = "Print TPS", + .callback = [](__attribute__((unused)) const std::string &cmd) { + INFO("TPS: %f", tps); + } + }); + // Stop + commands->push_back({ + .name = "stop", + .comment = "Stop Server", + .callback = [](__attribute__((unused)) const std::string &cmd) { + compat_request_exit(); + } + }); + // Help Page + commands->push_back({ + .name = "help", + .comment = "Print This Message", + .callback = [commands](__attribute__((unused)) const std::string &cmd) { + INFO("All Commands:"); + int max_lhs_length = 0; + for (ServerCommand command : *commands) { + const int lhs_length = command.get_lhs_help().length(); + if (lhs_length > max_lhs_length) { + max_lhs_length = lhs_length; + } + } + for (ServerCommand command : *commands) { + INFO("%s", command.get_full_help(max_lhs_length).c_str()); + } + } + }); + // Return + return commands; +} static void handle_commands(Minecraft *minecraft) { // Check If Level Is Generated if (minecraft->isLevelGenerated() && stdin_line_ready) { @@ -306,87 +391,10 @@ static void handle_commands(Minecraft *minecraft) { ServerSideNetworkHandler *server_side_network_handler = get_server_side_network_handler(minecraft); if (server_side_network_handler != nullptr) { // Generate Command List - std::vector commands; - if (!is_whitelist()) { - commands.push_back({ - .name = "ban ", - .comment = "IP-Ban All Players With Specified Username", - .callback = [&minecraft](const std::string &cmd) { - find_players(minecraft, cmd, ban_callback, false); - } - }); - } - commands.push_back({ - .name = "reload", - .comment = std::string("Reload The ") + (is_whitelist() ? "Whitelist" : "Blacklist"), - .callback = [](__attribute__((unused)) const std::string &cmd) { - INFO("Reloading %s", is_whitelist() ? "Whitelist" : "Blacklist"); - is_ip_in_blacklist(nullptr); - } - }); - commands.push_back({ - .name = "kill ", - .comment = "Kill All Players With Specified Username", - .callback = [&minecraft](const std::string &cmd) { - find_players(minecraft, cmd, kill_callback, false); - } - }); - commands.push_back({ - .name = "say ", - .comment = "Print Specified Message To Chat", - .callback = [&server_side_network_handler](const std::string &cmd) { - // Format Message - const std::string message = "[Server] " + cmd; - char *safe_message = to_cp437(message.c_str()); - std::string cpp_string = safe_message; - // Post Message To Chat - server_side_network_handler->displayGameMessage(cpp_string); - // Free - free(safe_message); - } - }); - commands.push_back({ - .name = "list", - .comment = "List All Players", - .callback = [&minecraft](__attribute__((unused)) const std::string &cmd) { - INFO("All Players:"); - find_players(minecraft, "", list_callback, true); - } - }); - commands.push_back({ - .name = "tps", - .comment = "Print TPS", - .callback = [](__attribute__((unused)) const std::string &cmd) { - INFO("TPS: %f", tps); - } - }); - commands.push_back({ - .name = "stop", - .comment = "Stop Server", - .callback = [](__attribute__((unused)) const std::string &cmd) { - compat_request_exit(); - } - }); - commands.push_back({ - .name = "help", - .comment = "Print This Message", - .callback = [&commands](__attribute__((unused)) const std::string &cmd) { - INFO("All Commands:"); - int max_lhs_length = 0; - for (Command command : commands) { - const int lhs_length = command.get_lhs_help().length(); - if (lhs_length > max_lhs_length) { - max_lhs_length = lhs_length; - } - } - for (Command command : commands) { - INFO("%s", command.get_full_help(max_lhs_length).c_str()); - } - } - }); + std::vector *commands = server_get_commands(minecraft, server_side_network_handler); // Run bool success = false; - for (Command command : commands) { + for (ServerCommand command : *commands) { const bool valid = command.has_args() ? data.rfind(command.name, 0) == 0 : data == command.name; if (valid) { command.callback(data.substr(command.name.length())); @@ -397,6 +405,8 @@ static void handle_commands(Minecraft *minecraft) { if (!success) { INFO("Invalid Command: %s", data.c_str()); } + // Free + delete commands; } } }