mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-10-30 08:01:01 +00:00
* improve --client flag and domain resolution * stop using the debug flag for dev binds * smaller character width with spaces for the hud font
333 lines
No EOL
13 KiB
C
333 lines
No EOL
13 KiB
C
#include "pc/network/network.h"
|
|
#include "pc/network/socket/socket.h"
|
|
#include "pc/lua/smlua_hooks.h"
|
|
#include "pc/djui/djui_chat_message.h"
|
|
#include "chat_commands.h"
|
|
#include "pc/network/ban_list.h"
|
|
#include "pc/network/moderator_list.h"
|
|
#include "pc/debuglog.h"
|
|
#include "pc/lua/utils/smlua_level_utils.h"
|
|
#include "level_table.h"
|
|
|
|
|
|
extern bool gIsModerator;
|
|
static enum ChatConfirmCommand sConfirming = CCC_NONE;
|
|
static u8 sConfirmPlayerIndex = 0;
|
|
|
|
static struct NetworkPlayer* chat_get_network_player(char* name) {
|
|
// check for id
|
|
for (s32 i = 0; i < MAX_PLAYERS; i++) {
|
|
if (!gNetworkPlayers[i].connected) { continue; }
|
|
char id[16] = { 0 };
|
|
if (snprintf(id, 16, "%d", i) < 0) {
|
|
// do nothing
|
|
}
|
|
if (strcmp(id, name) == 0) {
|
|
return &gNetworkPlayers[i];
|
|
}
|
|
}
|
|
|
|
// check for name
|
|
for (s32 i = 0; i < MAX_PLAYERS; i++) {
|
|
if (!gNetworkPlayers[i].connected) { continue; }
|
|
if (strcmp(gNetworkPlayers[i].name, name) == 0) {
|
|
return &gNetworkPlayers[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static bool str_starts_with(const char* pre, char* str) {
|
|
return strncmp(pre, str, strlen(pre)) == 0;
|
|
}
|
|
|
|
bool exec_chat_command(char* command) {
|
|
enum ChatConfirmCommand ccc = sConfirming;
|
|
sConfirming = CCC_NONE;
|
|
|
|
if (ccc != CCC_NONE && strcmp("/confirm", command) == 0) {
|
|
if (gNetworkType == NT_SERVER || gIsModerator) {
|
|
if (ccc == CCC_KICK) {
|
|
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
|
|
if (!np->connected) { return true; }
|
|
char message[256] = { 0 };
|
|
snprintf(message, 256, "\\#fff982\\Kicking '%s%s\\#fff982\\'!", network_get_player_text_color_string(np->localIndex), np->name);
|
|
djui_chat_message_create(message);
|
|
if (gNetworkType == NT_SERVER) {
|
|
network_send_kick(np->localIndex, EKT_KICKED);
|
|
network_player_disconnected(np->localIndex);
|
|
} else {
|
|
network_send_chat_command(np->globalIndex, CCC_KICK);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
if (gNetworkType == NT_SERVER || gIsModerator) {
|
|
if (ccc == CCC_BAN) {
|
|
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
|
|
if (!np->connected) { return true; }
|
|
char message[256] = { 0 };
|
|
snprintf(message, 256, "\\#fff982\\Banning '%s%s\\#fff982\\'!", network_get_player_text_color_string(np->localIndex), np->name);
|
|
djui_chat_message_create(message);
|
|
if (gNetworkType == NT_SERVER) {
|
|
network_send_kick(np->localIndex, EKT_BANNED);
|
|
ban_list_add(gNetworkSystem->get_id_str(np->localIndex), false);
|
|
network_player_disconnected(np->localIndex);
|
|
} else {
|
|
network_send_chat_command(np->globalIndex, CCC_BAN);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
if (gNetworkType == NT_SERVER && ccc == CCC_PERMBAN) {
|
|
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
|
|
if (!np->connected) { return true; }
|
|
char message[256] = { 0 };
|
|
snprintf(message, 256, "\\#fff982\\Permanently banning '%s%s\\#fff982\\'!", network_get_player_text_color_string(np->localIndex), np->name);
|
|
djui_chat_message_create(message);
|
|
network_send_kick(np->localIndex, EKT_BANNED);
|
|
ban_list_add(gNetworkSystem->get_id_str(np->localIndex), true);
|
|
network_player_disconnected(np->localIndex);
|
|
return true;
|
|
}
|
|
if (gNetworkType == NT_SERVER && ccc == CCC_MODERATOR) {
|
|
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
|
|
if (!np->connected) { return true; }
|
|
char message[256] = { 0 };
|
|
snprintf(message, 256, "\\#fff982\\Adding '%s%s\\#fff982\\' as a Moderator!", network_get_player_text_color_string(np->localIndex), np->name);
|
|
djui_chat_message_create(message);
|
|
network_send_moderator(np->localIndex);
|
|
moderator_list_add(gNetworkSystem->get_id_str(np->localIndex), true);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (strcmp("/players", command) == 0) {
|
|
char line[128] = { 0 };
|
|
strncat(line, "\\#fff982\\Players:\n", 127);
|
|
djui_chat_message_create(line);
|
|
for (s32 i = 0; i < MAX_PLAYERS; i++) {
|
|
struct NetworkPlayer* np = &gNetworkPlayers[i];
|
|
if (!np->connected) { continue; }
|
|
if (gNetworkSystem == &gNetworkSystemSocket) {
|
|
snprintf(line, 127, "\\#82f9ff\\%u\\#fff982\\ - %s%s\n", np->globalIndex, network_get_player_text_color_string(np->localIndex), np->name);
|
|
} else {
|
|
snprintf(line, 127, "\\#82f9ff\\%u\\#fff982\\ - \\#82f9ff\\%s\\#fff982\\ - %s%s\n", np->globalIndex, gNetworkSystem->get_id_str(np->localIndex), network_get_player_text_color_string(np->localIndex), np->name);
|
|
}
|
|
djui_chat_message_create(line);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (str_starts_with("/kick ", command)) {
|
|
if (gNetworkType != NT_SERVER && !gIsModerator) {
|
|
djui_chat_message_create("You do not have permission to use this command.");
|
|
return true;
|
|
}
|
|
|
|
struct NetworkPlayer* np = chat_get_network_player(&command[6]);
|
|
if (np == NULL) {
|
|
djui_chat_message_create("Could not find player.");
|
|
return true;
|
|
}
|
|
|
|
if (np->localIndex == 0) {
|
|
djui_chat_message_create("Can not kick yourself.");
|
|
return true;
|
|
}
|
|
|
|
char message[256] = { 0 };
|
|
snprintf(message, 256, "\\#fff982\\Are you sure you want to kick '%s%s\\#fff982\\'?\nType '\\#a0ffa0\\/confirm\\#fff982\\' to kick.", network_get_player_text_color_string(np->localIndex), np->name);
|
|
djui_chat_message_create(message);
|
|
|
|
sConfirming = CCC_KICK;
|
|
sConfirmPlayerIndex = np->localIndex;
|
|
|
|
return true;
|
|
}
|
|
|
|
if (str_starts_with("/ban ", command)) {
|
|
if (gNetworkType != NT_SERVER && !gIsModerator) {
|
|
djui_chat_message_create("You do not have permission to use this command.");
|
|
return true;
|
|
}
|
|
|
|
struct NetworkPlayer* np = chat_get_network_player(&command[5]);
|
|
if (np == NULL) {
|
|
djui_chat_message_create("Could not find player.");
|
|
return true;
|
|
}
|
|
|
|
if (np->localIndex == 0) {
|
|
djui_chat_message_create("Can not ban yourself.");
|
|
return true;
|
|
}
|
|
|
|
char message[256] = { 0 };
|
|
snprintf(message, 256, "\\#fff982\\Are you sure you want to ban '%s%s\\#fff982\\'?\nType '\\#a0ffa0\\/confirm\\#fff982\\' to ban.", network_get_player_text_color_string(np->localIndex), np->name);
|
|
djui_chat_message_create(message);
|
|
|
|
sConfirming = CCC_BAN;
|
|
sConfirmPlayerIndex = np->localIndex;
|
|
|
|
return true;
|
|
}
|
|
|
|
if (str_starts_with("/permban ", command)) {
|
|
if (gNetworkType != NT_SERVER && !gIsModerator) {
|
|
djui_chat_message_create("You do not have permission to use this command.");
|
|
return true;
|
|
}
|
|
|
|
struct NetworkPlayer* np = chat_get_network_player(&command[9]);
|
|
if (np == NULL) {
|
|
djui_chat_message_create("Could not find player.");
|
|
return true;
|
|
}
|
|
|
|
if (np->localIndex == 0) {
|
|
djui_chat_message_create("Can not permanently ban yourself.");
|
|
return true;
|
|
}
|
|
|
|
char message[256] = { 0 };
|
|
snprintf(message, 256, "\\#fff982\\Are you sure you want to permanently ban '%s%s\\#fff982\\'?\nType '\\#a0ffa0\\/confirm\\#fff982\\' to permanently ban.", network_get_player_text_color_string(np->localIndex), np->name);
|
|
djui_chat_message_create(message);
|
|
|
|
sConfirming = CCC_PERMBAN;
|
|
sConfirmPlayerIndex = np->localIndex;
|
|
|
|
return true;
|
|
}
|
|
|
|
if (str_starts_with("/moderator ", command)) {
|
|
if (gNetworkType != NT_SERVER) {
|
|
djui_chat_message_create("Only the server can use this command.");
|
|
return true;
|
|
}
|
|
|
|
struct NetworkPlayer* np = chat_get_network_player(&command[11]);
|
|
if (np == NULL) {
|
|
djui_chat_message_create("Could not find player.");
|
|
return true;
|
|
}
|
|
|
|
if (np->localIndex == 0) {
|
|
djui_chat_message_create("Can not make yourself a moderator.");
|
|
return true;
|
|
}
|
|
|
|
char message[256] = { 0 };
|
|
snprintf(message, 256, "\\#fff982\\Are you sure you want to make '%s%s\\#fff982\\' a moderator?\nType '\\#a0ffa0\\/confirm\\#fff982\\' to moderate.", network_get_player_text_color_string(np->localIndex), np->name);
|
|
djui_chat_message_create(message);
|
|
|
|
sConfirming = CCC_MODERATOR;
|
|
sConfirmPlayerIndex = np->localIndex;
|
|
|
|
return true;
|
|
}
|
|
#if defined(DEVELOPMENT)
|
|
if (gNetworkSystem == &gNetworkSystemSocket && str_starts_with("/warp ", command)) {
|
|
static const struct { const char *name; s32 num; } sLevelNumByName[] = {
|
|
#undef STUB_LEVEL
|
|
#undef DEFINE_LEVEL
|
|
#define STUB_LEVEL(...)
|
|
#define DEFINE_LEVEL(_0, levelnum, _2, levelname, ...) { #levelname, levelnum },
|
|
#include "levels/level_defines.h"
|
|
#undef STUB_LEVEL
|
|
#undef DEFINE_LEVEL
|
|
};
|
|
|
|
// Params
|
|
char *paramLevel = command + 6;
|
|
if (*paramLevel == 0 || *paramLevel == ' ') {
|
|
djui_chat_message_create("Missing parameters: [LEVEL] [AREA] [ACT]");
|
|
return true;
|
|
}
|
|
char *paramArea = strchr(paramLevel, ' ');
|
|
if (paramArea++ == NULL || *paramArea == 0 || *paramArea == ' ') {
|
|
djui_chat_message_create("Missing parameters: [AREA] [ACT]");
|
|
return true;
|
|
}
|
|
char *paramAct = strchr(paramArea, ' ');
|
|
if (paramAct++ == NULL || *paramAct == 0 || *paramAct == ' ') {
|
|
djui_chat_message_create("Missing parameters: [ACT]");
|
|
return true;
|
|
}
|
|
*(paramArea - 1) = 0;
|
|
*(paramAct - 1) = 0;
|
|
|
|
// Level
|
|
s32 level = -1;
|
|
if (sscanf(paramLevel, "%d", &level) <= 0) {
|
|
for (s32 i = 0; i != (s32) (sizeof(sLevelNumByName) / sizeof(sLevelNumByName[0])); ++i) {
|
|
if (strstr(paramLevel, sLevelNumByName[i].name) == paramLevel) {
|
|
level = sLevelNumByName[i].num;
|
|
break;
|
|
}
|
|
}
|
|
if (level == -1) {
|
|
struct CustomLevelInfo* info = smlua_level_util_get_info_from_short_name(paramLevel);
|
|
if (info != NULL) {
|
|
level = info->levelNum;
|
|
}
|
|
}
|
|
if (level == -1) {
|
|
char message[256];
|
|
snprintf(message, 256, "Invalid [LEVEL] parameter: %s", paramLevel);
|
|
djui_chat_message_create(message);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Area
|
|
s32 area = -1;
|
|
if (sscanf(paramArea, "%d", &area) <= 0) {
|
|
char message[256];
|
|
snprintf(message, 256, "Invalid [AREA] parameter: %s", paramArea);
|
|
djui_chat_message_create(message);
|
|
return true;
|
|
}
|
|
|
|
// Act
|
|
s32 act = -1;
|
|
if (sscanf(paramAct, "%d", &act) <= 0) {
|
|
char message[256];
|
|
snprintf(message, 256, "Invalid [ACT] parameter: %s", paramAct);
|
|
djui_chat_message_create(message);
|
|
return true;
|
|
}
|
|
|
|
// Warp
|
|
if (!dynos_warp_to_level(level, area, act)) {
|
|
char message[256];
|
|
snprintf(message, 256, "Unable to warp to: %s %s %s", paramLevel, paramArea, paramAct);
|
|
djui_chat_message_create(message);
|
|
return true;
|
|
}
|
|
|
|
// OK
|
|
char message[256];
|
|
snprintf(message, 256, "Warping to: %s %s %s...", paramLevel, paramArea, paramAct);
|
|
djui_chat_message_create(message);
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
return smlua_call_chat_command_hook(command);
|
|
}
|
|
|
|
void display_chat_commands(void) {
|
|
djui_chat_message_create("/players - List all players and their IDs");
|
|
if (gNetworkType == NT_SERVER || gIsModerator) {
|
|
djui_chat_message_create("/kick [NAME|ID] - Kick this player from the current game");
|
|
djui_chat_message_create("/ban [NAME|ID] - Ban this player from the current game");
|
|
djui_chat_message_create("/permban [NAME|ID] - Ban this player from any game you host");
|
|
djui_chat_message_create("/moderator [NAME|ID] - Make this player able to use commands like /kick, /ban, /permban on any game you host");
|
|
}
|
|
#if defined(DEVELOPMENT)
|
|
djui_chat_message_create("/warp [LEVEL] [AREA] [ACT] - Level can be either a numeric value or a shorthand name");
|
|
#endif
|
|
if (sConfirming != CCC_NONE) { djui_chat_message_create("/confirm"); }
|
|
smlua_display_chat_commands();
|
|
} |