From 701fddf4dd354d2206b0b18f0af9c61f1d756a61 Mon Sep 17 00:00:00 2001 From: Isaac <62234577+Isaac0-dev@users.noreply.github.com> Date: Tue, 10 May 2022 16:11:39 +1000 Subject: [PATCH] Moderator (#80) --- Makefile | 9 +- data/dynos.c.h | 3 + data/dynos.cpp.h | 10 ++ data/dynos_c.cpp | 5 + data/dynos_gfx_update.cpp | 3 + data/dynos_level.cpp | 11 ++ data/dynos_main.cpp | 20 ++++ data/dynos_mgr_actor.cpp | 37 +++++- data/dynos_mgr_col.cpp | 10 ++ data/dynos_mgr_lvl.cpp | 16 +++ data/dynos_mgr_movtexqc.cpp | 9 ++ data/dynos_mgr_tex.cpp | 9 ++ mods/shell-rush/level.lua | 24 +--- mods/shell-rush/main.lua | 2 +- mods/shell-rush/powerup.lua | 14 +++ mods/shell-rush/race.lua | 2 +- .../behaviors/flying_bookend_switch.inc.c | 8 +- src/game/behaviors/piranha_bubbles.inc.c | 2 + src/game/game_init.c | 4 - src/game/game_init.h | 4 - src/game/mario.c | 22 ---- src/game/mario_misc.c | 5 +- src/game/object_helpers.c | 38 ++++++ src/pc/chat_commands.c | 109 +++++++++++++----- src/pc/configfile.c | 16 +++ src/pc/djui/djui_panel_join_message.c | 2 +- src/pc/djui/djui_panel_pause.c | 7 +- src/pc/djui/djui_popup.c | 39 +++---- src/pc/lua/smlua.c | 2 + src/pc/lua/smlua_hooks.c | 2 +- src/pc/lua/smlua_hooks.h | 1 + src/pc/lua/utils/smlua_audio_utils.c | 16 +++ src/pc/mods/mod.c | 2 +- src/pc/mods/mod_cache.c | 24 ++-- src/pc/mods/mod_cache.h | 2 +- src/pc/network/moderator_list.c | 47 ++++++++ src/pc/network/moderator_list.h | 13 +++ src/pc/network/network.c | 26 ++++- src/pc/network/network.h | 2 +- src/pc/network/network_player.c | 5 +- src/pc/network/packets/packet.c | 2 + src/pc/network/packets/packet.h | 19 +++ src/pc/network/packets/packet_command_mod.c | 61 ++++++++++ src/pc/network/packets/packet_join.c | 4 +- src/pc/network/packets/packet_kick.c | 2 +- src/pc/network/packets/packet_mod_list.c | 4 +- .../network/packets/packet_network_players.c | 6 + src/pc/network/socket/socket.c | 52 ++++++--- src/pc/network/version.c | 4 - src/pc/network/version.h | 1 - src/pc/pc_main.c | 2 +- 51 files changed, 562 insertions(+), 177 deletions(-) create mode 100644 src/pc/network/moderator_list.c create mode 100644 src/pc/network/moderator_list.h create mode 100644 src/pc/network/packets/packet_command_mod.c diff --git a/Makefile b/Makefile index 09b6a1f4..44fca33d 100644 --- a/Makefile +++ b/Makefile @@ -728,7 +728,7 @@ else ifeq ($(WINDOWS_BUILD),1) LD := $(CXX) endif else - LD := $(CROSS)ld + LD := $(CXX) endif AR := $(CROSS)ar @@ -906,17 +906,22 @@ else LDFLAGS += -Llib/lua/linux -l:liblua53.a endif -# Network +# Network/Discord/Bass (ugh, needs cleanup) ifeq ($(WINDOWS_BUILD),1) LDFLAGS += -L"ws2_32" -lwsock32 ifeq ($(DISCORD_SDK),1) LDFLAGS += -Wl,-Bdynamic -L./lib/discordsdk/ -L./lib/bass/ -ldiscord_game_sdk -lbass -lbass_fx -Wl,-Bstatic + else + LDFLAGS += -Wl,-Bdynamic -L./lib/bass/ -lbass -lbass_fx -Wl,-Bstatic endif else ifeq ($(DISCORD_SDK),1) LDFLAGS += -ldiscord_game_sdk -lbass -lbass_fx -Wl,-rpath . -Wl,-rpath lib/discordsdk -Wl,-rpath lib/bass + else + LDFLAGS += -lbass -lbass_fx -Wl,-rpath . -Wl,-rpath lib/bass endif endif + # Prevent a crash with -sopt export LANG := C diff --git a/data/dynos.c.h b/data/dynos.c.h index 682fc668..98b47353 100644 --- a/data/dynos.c.h +++ b/data/dynos.c.h @@ -53,5 +53,8 @@ const char* dynos_level_get_token(u32 index); Trajectory* dynos_level_get_trajectory(const char* name); void dynos_level_load_background(void *ptr); +// -- other -- // +void dynos_mod_shutdown(void); + #endif #endif diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h index d0cec21a..a38e15a9 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -12,6 +12,8 @@ extern "C" { #define POINTER_CODE (u32) 0x52544E50 #define LUA_VAR_CODE (u32) 0x5641554C +#define MOD_PACK_INDEX 99 + // // Enums // @@ -644,6 +646,8 @@ void *DynOS_SwapCmd(void *aCmd); void *DynOS_UpdateCmd(void *aCmd); void DynOS_UpdateGfx(); bool DynOS_IsTransitionActive(); +void DynOS_Mod_Update(); +void DynOS_Mod_Shutdown(); void DynOS_ReturnToMainMenu(); // @@ -695,6 +699,7 @@ s32 DynOS_Level_GetCount(); const s32 *DynOS_Level_GetList(); s32 DynOS_Level_GetCourse(s32 aLevel); void DynOS_Level_Override(void* originalScript, void* newScript); +void DynOS_Level_Unoverride(); const void *DynOS_Level_GetScript(s32 aLevel); const u8 *DynOS_Level_GetName(s32 aLevel, bool aDecaps, bool aAddCourseNumber); const u8 *DynOS_Level_GetActName(s32 aLevel, s32 aAct, bool aDecaps, bool aAddStarNumber); @@ -764,6 +769,7 @@ void DynOS_Actor_Valid(const void* aGeoref, ActorGfx& aActorGfx); void DynOS_Actor_Invalid(const void* aGeoref, s32 aPackIndex); void DynOS_Actor_Override(void** aSharedChild); void DynOS_Actor_Override_All(void); +void DynOS_Actor_ModShutdown(); // // Anim Manager @@ -784,6 +790,7 @@ void DynOS_Tex_Activate(DataNode* aNode, bool aCustomTexture); void DynOS_Tex_Deactivate(DataNode* aNode); void DynOS_Tex_AddCustom(const SysPath &aFilename, const char *aTexName); bool DynOS_Tex_Get(const char* aTexName, struct TextureInfo* aOutTexInfo); +void DynOS_Tex_ModShutdown(); // // Lvl Manager @@ -797,6 +804,7 @@ DataNode* DynOS_Lvl_GetMovtexQuadCollection(s32 index); Trajectory* DynOS_Lvl_GetTrajectory(const char* aName); void DynOS_Lvl_LoadBackground(void *aPtr); void* DynOS_Lvl_Override(void *aCmd); +void DynOS_Lvl_ModShutdown(); // // Col Manager @@ -804,6 +812,7 @@ void* DynOS_Lvl_Override(void *aCmd); void DynOS_Col_Activate(const SysPath &aFilePath, const char *aCollisionName); Collision* DynOS_Col_Get(const char* collisionName); +void DynOS_Col_ModShutdown(); // // Movtexqc Manager @@ -812,6 +821,7 @@ Collision* DynOS_Col_Get(const char* collisionName); void DynOS_MovtexQC_Register(const char* name, s16 level, s16 area, s16 type); DataNode* DynOS_MovtexQC_GetFromId(u32 id); DataNode* DynOS_MovtexQC_GetFromIndex(s32 index); +void DynOS_MovtexQC_ModShutdown(); // // Bin diff --git a/data/dynos_c.cpp b/data/dynos_c.cpp index 2ee95abd..42196c13 100644 --- a/data/dynos_c.cpp +++ b/data/dynos_c.cpp @@ -156,4 +156,9 @@ void dynos_level_load_background(void *ptr) { DynOS_Lvl_LoadBackground(ptr); } +// -- other -- // +void dynos_mod_shutdown(void) { + DynOS_Mod_Shutdown(); +} + } \ No newline at end of file diff --git a/data/dynos_gfx_update.cpp b/data/dynos_gfx_update.cpp index 55949777..a7f3a4b1 100644 --- a/data/dynos_gfx_update.cpp +++ b/data/dynos_gfx_update.cpp @@ -2,6 +2,9 @@ extern "C" { } +bool gDynosModShutdown = false; + void DynOS_Gfx_Update() { + DynOS_Mod_Update(); DynOS_Tex_Update(); } diff --git a/data/dynos_level.cpp b/data/dynos_level.cpp index 85137fde..a2aea408 100644 --- a/data/dynos_level.cpp +++ b/data/dynos_level.cpp @@ -46,6 +46,7 @@ struct DynosWarp { }; static void *sDynosLevelScripts[LEVEL_COUNT] = { NULL }; +static void *sDynosLevelScriptsOriginal[LEVEL_COUNT] = { NULL }; static Array sDynosLevelWarps[LEVEL_COUNT] = { Array() }; static Array sDynosLevelList = Array(); // Ordered by Course Id, COURSE_NONE excluded @@ -90,6 +91,7 @@ static s32 DynOS_Level_PreprocessMasterScript(u8 aType, void *aCmd) { void *_Script = (void *) DynOS_Level_CmdGet(aCmd, 0x0C); if (sDynosLevelNum >= 0 && sDynosLevelNum < LEVEL_COUNT && !sDynosLevelScripts[sDynosLevelNum]) { sDynosLevelScripts[sDynosLevelNum] = _Script; + sDynosLevelScriptsOriginal[sDynosLevelNum] = _Script; } sDynosLevelNum = -1; return 2; @@ -237,6 +239,15 @@ void DynOS_Level_Override(void* originalScript, void* newScript) { } } +void DynOS_Level_Unoverride() { + for (s32 i = 0; i < LEVEL_COUNT; i++) { + sDynosCurrentLevelNum = i; + sDynosLevelWarps[i].Clear(); + sDynosLevelScripts[i] = sDynosLevelScriptsOriginal[i]; + DynOS_Level_ParseScript(sDynosLevelScripts[i], DynOS_Level_PreprocessScript); + } +} + const void *DynOS_Level_GetScript(s32 aLevel) { DynOS_Level_Init(); return sDynosLevelScripts[aLevel]; diff --git a/data/dynos_main.cpp b/data/dynos_main.cpp index 80b175d0..c66439ff 100644 --- a/data/dynos_main.cpp +++ b/data/dynos_main.cpp @@ -66,3 +66,23 @@ void DynOS_UpdateGfx() { bool DynOS_IsTransitionActive() { return gWarpTransition.isActive; } + +// +// Misc +// +static bool sDynosModShutdown = false; + +void DynOS_Mod_Update() { + if (sDynosModShutdown) { + sDynosModShutdown = false; + DynOS_Actor_ModShutdown(); + DynOS_Col_ModShutdown(); + DynOS_Lvl_ModShutdown(); + DynOS_MovtexQC_ModShutdown(); + DynOS_Tex_ModShutdown(); + } +} + +void DynOS_Mod_Shutdown() { + sDynosModShutdown = true; +} diff --git a/data/dynos_mgr_actor.cpp b/data/dynos_mgr_actor.cpp index cf9832c8..009051a7 100644 --- a/data/dynos_mgr_actor.cpp +++ b/data/dynos_mgr_actor.cpp @@ -44,18 +44,19 @@ void DynOS_Actor_AddCustom(const SysPath &aFilename, const char *aActorName) { return; } + // Alloc and init the actors gfx list + ActorGfx actorGfx = { 0 }; + actorGfx.mGfxData = _GfxData; + actorGfx.mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode(geoLayout, false); + actorGfx.mPackIndex = MOD_PACK_INDEX; + actorGfx.mGraphNode->georef = georef; + // Add to custom actors if (georef == NULL) { DynosCustomActors().Add({ actorName, geoLayout }); georef = geoLayout; } - // Alloc and init the actors gfx list - ActorGfx actorGfx; - actorGfx.mGfxData = _GfxData; - actorGfx.mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode(geoLayout, false); - actorGfx.mPackIndex = 99; - // Add to list DynOS_Actor_Valid(georef, actorGfx); } @@ -150,3 +151,27 @@ void DynOS_Actor_Override_All(void) { } } } + +void DynOS_Actor_ModShutdown() { + auto& _DynosCustomActors = DynosCustomActors(); + while (_DynosCustomActors.Count() > 0) { + auto& pair = _DynosCustomActors[0]; + DynOS_Actor_Invalid(pair.second, MOD_PACK_INDEX); + free((void*)pair.first); + _DynosCustomActors.Remove(0); + } + + auto& _ValidActors = DynosValidActors(); + for (auto it = _ValidActors.cbegin(); it != _ValidActors.cend();) { + auto& actorGfx = it->second; + if (actorGfx.mPackIndex == MOD_PACK_INDEX) { + free(actorGfx.mGraphNode); + DynOS_Gfx_Free(actorGfx.mGfxData); + _ValidActors.erase(it++); + } else { + ++it; + } + } + + DynOS_Actor_Override_All(); +} diff --git a/data/dynos_mgr_col.cpp b/data/dynos_mgr_col.cpp index 591e5600..c7346a99 100644 --- a/data/dynos_mgr_col.cpp +++ b/data/dynos_mgr_col.cpp @@ -54,3 +54,13 @@ Collision* DynOS_Col_Get(const char* collisionName) { // check builtin collisions return (Collision*)DynOS_Builtin_LvlCol_GetFromName(collisionName); } + +void DynOS_Col_ModShutdown() { + auto& _DynosCollisions = DynosCollisions(); + while (_DynosCollisions.Count() > 0) { + auto& pair = _DynosCollisions[0]; + free((void*)pair.first); + Delete(pair.second); + _DynosCollisions.Remove(0); + } +} diff --git a/data/dynos_mgr_lvl.cpp b/data/dynos_mgr_lvl.cpp index 3742e733..54a1fb5e 100644 --- a/data/dynos_mgr_lvl.cpp +++ b/data/dynos_mgr_lvl.cpp @@ -20,6 +20,22 @@ Array> &DynOS_Lvl_GetArray() { return sDynosCustomLevelScripts; } +void DynOS_Lvl_ModShutdown() { + DynOS_Level_Unoverride(); + + auto& _CustomLevelScripts = DynOS_Lvl_GetArray(); + while (_CustomLevelScripts.Count() > 0) { + auto& pair = _CustomLevelScripts[0]; + DynOS_Tex_Invalid(pair.second); + Delete(pair.second); + free((void*)pair.first); + _CustomLevelScripts.Remove(0); + } + + auto& _OverrideLevelScripts = DynosOverrideLevelScripts(); + _OverrideLevelScripts.Clear(); +} + void DynOS_Lvl_Activate(s32 modIndex, const SysPath &aFilename, const char *aLevelName) { auto& _CustomLevelScripts = DynOS_Lvl_GetArray(); auto& _OverrideLevelScripts = DynosOverrideLevelScripts(); diff --git a/data/dynos_mgr_movtexqc.cpp b/data/dynos_mgr_movtexqc.cpp index 0d2fdb40..e47b72f3 100644 --- a/data/dynos_mgr_movtexqc.cpp +++ b/data/dynos_mgr_movtexqc.cpp @@ -67,3 +67,12 @@ DataNode* DynOS_MovtexQC_GetFromIndex(s32 index) { return mMovtexQCs[index]; } + +void DynOS_MovtexQC_ModShutdown() { + auto& _DynosRegisteredMovtexQCs = DynosRegisteredMovtexQCs(); + while (_DynosRegisteredMovtexQCs.Count() > 0) { + auto& registered = _DynosRegisteredMovtexQCs[0]; + Delete(registered.dataNode); + _DynosRegisteredMovtexQCs.Remove(0); + } +} diff --git a/data/dynos_mgr_tex.cpp b/data/dynos_mgr_tex.cpp index 59ce38a4..a07f790f 100644 --- a/data/dynos_mgr_tex.cpp +++ b/data/dynos_mgr_tex.cpp @@ -422,6 +422,7 @@ void DynOS_Tex_AddCustom(const SysPath &aFilename, const char *aTexName) { // Load SysPath _PackFolder = ""; DataNode* _Node = DynOS_Tex_LoadFromBinary(_PackFolder, aFilename, _TexName, false); + free(_TexName); if (_Node) { DynOS_Tex_Activate(_Node, true); } @@ -468,3 +469,11 @@ bool DynOS_Tex_Get(const char* aTexName, struct TextureInfo* aOutTexInfo) { aOutTexInfo->texture = (u8*)info->pointer; return true; } + +void DynOS_Tex_ModShutdown() { + auto& _DynosCustomTexs = DynosCustomTexs(); + while (_DynosCustomTexs.Count() > 0) { + auto& pair = _DynosCustomTexs[0]; + DynOS_Tex_Deactivate(pair.second); + } +} diff --git a/mods/shell-rush/level.lua b/mods/shell-rush/level.lua index 72644f9d..ea281717 100644 --- a/mods/shell-rush/level.lua +++ b/mods/shell-rush/level.lua @@ -95,26 +95,10 @@ function spawn_custom_level_objects() return end - -- look for existing powerups - local obj = obj_get_first(OBJ_LIST_LEVEL) - while obj ~= nil do - local behaviorId = get_id_from_behavior(obj.behavior) - - if behaviorId == id_bhvItemBox then - -- find closest position to put it in - local objPos = { x = obj.oPosX, y = obj.oPosY, z = obj.oPosZ } - for i in pairs(gLevelData.powerups) do - local powPos = gLevelData.powerups[i].pos - local tempPos = { x = powPos.x, y = objPos.y, z = powPos.z } - local dist = vec3f_dist(objPos, tempPos) - if dist < 5 then - gLevelData.powerups[i].obj = obj - end - end - end - - -- iterate - obj = obj_get_next(obj) + -- only handle powerups if we're sync valid + np = gNetworkPlayers[0] + if (not np.currAreaSyncValid) or (not np.currLevelSyncValid) then + return end -- spawn missing powerups diff --git a/mods/shell-rush/main.lua b/mods/shell-rush/main.lua index a14090ae..e1dd570b 100644 --- a/mods/shell-rush/main.lua +++ b/mods/shell-rush/main.lua @@ -1,6 +1,6 @@ -- name: Shell Rush -- description: Race around SM64 levels on shells.\n\nCollect powerups such as red shells, green shells, bananas, and mushrooms.\n\nOnly use a save that has lowered the water in the moat. --- incompatible: gamemode +-- incompatible: gamemode moveset DEBUG = false UNST22 = true -- gotta work around unst 22 bugs :( diff --git a/mods/shell-rush/powerup.lua b/mods/shell-rush/powerup.lua index 5b77e81a..3383a7ec 100644 --- a/mods/shell-rush/powerup.lua +++ b/mods/shell-rush/powerup.lua @@ -261,6 +261,20 @@ function select_powerup() local s = gPlayerSyncTable[0] local pick = math.random(1, POWERUP_MAX-1) local luck = math.random() < 0.33 + + -- don't give mushrooms when first place + local rank = 0 + for i in pairs(gRankings) do + if gRankings[i].playerIndex == 0 then + rank = i + end + end + if rank <= 1 then + if pick == POWERUP_MUSHROOM then + pick = POWERUP_GREEN_SHELL + end + end + if luck then s.powerup[0] = pick s.powerup[1] = pick diff --git a/mods/shell-rush/race.lua b/mods/shell-rush/race.lua index 8e653cbf..c89665ba 100644 --- a/mods/shell-rush/race.lua +++ b/mods/shell-rush/race.lua @@ -123,7 +123,7 @@ function race_update() end local np = gNetworkPlayers[0] - if gGlobalSyncTable.gotoLevel ~= -1 then + if gGlobalSyncTable.gotoLevel ~= -1 and np.currAreaSyncValid and np.currLevelSyncValid then if np.currLevelNum ~= gGlobalSyncTable.gotoLevel then if gGlobalSyncTable.gotoLevel == LEVEL_CASTLE_GROUNDS then warp_to_castle(LEVEL_VCUTM) diff --git a/src/game/behaviors/flying_bookend_switch.inc.c b/src/game/behaviors/flying_bookend_switch.inc.c index ceaa36f8..73af23eb 100644 --- a/src/game/behaviors/flying_bookend_switch.inc.c +++ b/src/game/behaviors/flying_bookend_switch.inc.c @@ -208,11 +208,13 @@ void bookshelf_manager_act_2(void) { if (o->oTimer > 100) { if (o->oSyncID != 0 && gSyncObjects[o->oSyncID].owned) { o->parentObj = cur_obj_nearest_object_with_behavior(bhvHauntedBookshelf); - o->parentObj->oAction = 1; - o->oPosX = o->parentObj->oPosX; o->oAction = 3; network_send_object(o); - network_send_object(o->parentObj); + if (o->parentObj != NULL) { + o->parentObj->oAction = 1; + o->oPosX = o->parentObj->oPosX; + network_send_object(o->parentObj); + } } } else if (o->oTimer == 30) { play_puzzle_jingle(); diff --git a/src/game/behaviors/piranha_bubbles.inc.c b/src/game/behaviors/piranha_bubbles.inc.c index f1d8dad1..52d7bdb0 100644 --- a/src/game/behaviors/piranha_bubbles.inc.c +++ b/src/game/behaviors/piranha_bubbles.inc.c @@ -28,10 +28,12 @@ void bhv_piranha_plant_waking_bubbles_loop(void) { */ void bhv_piranha_plant_bubble_loop(void) { struct Object *parent = o->parentObj; // the Piranha Plant + if (parent == NULL) { return; } f32 scale = 0; s32 i; s32 frame = parent->header.gfx.animInfo.animFrame; // TODO: rename lastFrame if it is inaccurate + if (parent->header.gfx.animInfo.curAnim == NULL) { return; } s32 lastFrame = parent->header.gfx.animInfo.curAnim->loopEnd - 2; s32 UNUSED unused; f32 doneShrinkingFrame; // the first frame after shrinking is done diff --git a/src/game/game_init.c b/src/game/game_init.c index 9c4d5eef..2eff4276 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -30,11 +30,7 @@ // FIXME: I'm not sure all of these variables belong in this file, but I don't // know of a good way to split them -#ifdef UNSTABLE_BRANCH struct Controller gControllers[MAX_PLAYERS]; -#else -struct Controller gControllers[3]; -#endif struct SPTask *gGfxSPTask; Gfx *gDisplayListHead; u8 *gGfxPoolEnd; diff --git a/src/game/game_init.h b/src/game/game_init.h index e2033acb..49bfd7d7 100644 --- a/src/game/game_init.h +++ b/src/game/game_init.h @@ -22,11 +22,7 @@ struct DemoInput u8 buttonMask; }; -#ifdef UNSTABLE_BRANCH extern struct Controller gControllers[MAX_PLAYERS]; -#else -extern struct Controller gControllers[3]; -#endif extern OSContStatus gControllerStatuses[4]; extern OSContPad gControllerPads[4]; extern OSMesgQueue gGameVblankQueue; diff --git a/src/game/mario.c b/src/game/mario.c index 376017c0..43ebb2e1 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -2159,28 +2159,6 @@ void init_single_mario(struct MarioState* m) { m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE; } - // offset spawning - u8 connectedPlayers = network_player_connected_count(); - u8 globalIndex = gNetworkPlayers[m->playerIndex].globalIndex; - u16 spawnAngle = m->faceAngle[1] + 0x4000 + 0x10000 * ((f32)globalIndex / ((f32)connectedPlayers + 1)); - f32 spawnMag = 60.0f * ((connectedPlayers + 1) / 2.0f); - if (spawnMag > 120) { spawnMag = 120; } - - // figure out if we should apply offset - u8 nearbyPlayers = 1; - for (s32 i = 1; i < MAX_PLAYERS; i++) { - struct NetworkPlayer *np = &gNetworkPlayers[i]; - if (!np->connected) { continue; } - if (np->currCourseNum == gCurrCourseNum && np->currLevelNum == gCurrLevelNum && np->currActNum == gCurrActStarNum && np->currAreaIndex == gCurrAreaIndex) { - nearbyPlayers++; - } - } - - if (nearbyPlayers > 1) { - m->pos[0] -= spawnMag * sins(spawnAngle); - m->pos[2] -= spawnMag * coss(spawnAngle); - } - m->floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &m->floor); if (m->pos[1] < m->floorHeight) { diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index e52dd04a..003c619e 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -652,6 +652,7 @@ Gfx* geo_switch_mario_cap_on_off(s32 callContext, struct GraphNode* node, UNUSED struct MarioBodyState* bodyState = geo_get_body_state(); if (callContext == GEO_CONTEXT_RENDER) { + if (switchCase == NULL || bodyState == NULL) { return NULL; } switchCase->selectedCase = bodyState->capState & 1; while (next != node) { if (next->type == GRAPH_NODE_TYPE_TRANSLATION_ROTATION) { @@ -773,9 +774,9 @@ Gfx* geo_render_mirror_mario(s32 callContext, struct GraphNode* node, UNUSED Mat gMirrorMario[i].pos[0] = mirroredX + MIRROR_X; gMirrorMario[i].angle[1] = -gMirrorMario[i].angle[1]; gMirrorMario[i].scale[0] *= -1.0f; - ((struct GraphNode *) &gMirrorMario)->flags |= 1; + gMirrorMario[i].node.flags |= GRAPH_RENDER_ACTIVE; } else { - ((struct GraphNode *) &gMirrorMario)->flags &= ~1; + gMirrorMario[i].node.flags &= ~GRAPH_RENDER_ACTIVE; } break; } diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index 6f7183c5..49df0b63 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -245,6 +245,7 @@ Gfx *geo_choose_area_ext(UNUSED s32 callContext, struct GraphNode *node, UNUSED } void obj_update_pos_from_parent_transformation(Mat4 a0, struct Object *a1) { + if (a1 == NULL) { return; } f32 spC = a1->oParentRelativePosX; f32 sp8 = a1->oParentRelativePosY; f32 sp4 = a1->oParentRelativePosZ; @@ -255,6 +256,7 @@ void obj_update_pos_from_parent_transformation(Mat4 a0, struct Object *a1) { } void obj_apply_scale_to_matrix(struct Object *obj, Mat4 dst, Mat4 src) { + if (obj == NULL) { return; } dst[0][0] = src[0][0] * obj->header.gfx.scale[0]; dst[1][0] = src[1][0] * obj->header.gfx.scale[1]; dst[2][0] = src[2][0] * obj->header.gfx.scale[2]; @@ -306,6 +308,7 @@ void create_transformation_from_matrices(Mat4 a0, Mat4 a1, Mat4 a2) { } void obj_set_held_state(struct Object *obj, const BehaviorScript *heldBehavior) { + if (obj == NULL) { return; } obj->parentObj = o; if (obj->oFlags & OBJ_FLAG_HOLDABLE) { @@ -363,6 +366,7 @@ void cur_obj_forward_vel_approach_upward(f32 target, f32 increment) { } s32 approach_f32_signed(f32 *value, f32 target, f32 increment) { + if (value == NULL) { return 0; } s32 reachedTarget = FALSE; *value += increment; @@ -436,6 +440,8 @@ s32 cur_obj_rotate_yaw_toward(s16 target, s16 increment) { } s16 obj_angle_to_object(struct Object *obj1, struct Object *obj2) { + if (obj1 == NULL || obj2 == NULL) { return 0; } + f32 z1, x1, z2, x2; s16 angle; @@ -447,6 +453,7 @@ s16 obj_angle_to_object(struct Object *obj1, struct Object *obj2) { } s16 obj_pitch_to_object(struct Object* obj, struct Object* target) { + if (obj == NULL) { return 0; } f32 a, b, c, d; a = target->oPosX - obj->oPosX; c = target->oPosZ - obj->oPosZ; @@ -459,6 +466,7 @@ s16 obj_pitch_to_object(struct Object* obj, struct Object* target) { } s16 obj_angle_to_point(struct Object *obj, f32 pointX, f32 pointZ) { + if (obj == NULL) { return 0; } f32 z1, x1, z2, x2; s16 angle; @@ -470,6 +478,7 @@ s16 obj_angle_to_point(struct Object *obj, f32 pointX, f32 pointZ) { } s16 obj_turn_toward_object(struct Object *obj, struct Object *target, s16 angleIndex, s16 turnAmount) { + if (obj == NULL || target == NULL) { return 0; } f32 a, b, c, d; UNUSED s32 unused; s16 targetAngle = 0; @@ -505,18 +514,21 @@ s16 obj_turn_toward_object(struct Object *obj, struct Object *target, s16 angleI } void obj_set_parent_relative_pos(struct Object *obj, s16 relX, s16 relY, s16 relZ) { + if (obj == NULL) { return; } obj->oParentRelativePosX = relX; obj->oParentRelativePosY = relY; obj->oParentRelativePosZ = relZ; } void obj_set_pos(struct Object *obj, s16 x, s16 y, s16 z) { + if (obj == NULL) { return; } obj->oPosX = x; obj->oPosY = y; obj->oPosZ = z; } void obj_set_angle(struct Object *obj, s16 pitch, s16 yaw, s16 roll) { + if (obj == NULL) { return; } obj->oFaceAnglePitch = pitch; obj->oFaceAngleYaw = yaw; obj->oFaceAngleRoll = roll; @@ -762,6 +774,7 @@ void linear_mtxf_transpose_mul_vec3f(Mat4 m, Vec3f dst, Vec3f v) { } void obj_apply_scale_to_transform(struct Object *obj) { + if (obj == NULL) { return; } f32 scaleX = obj->header.gfx.scale[0]; f32 scaleY = obj->header.gfx.scale[1]; f32 scaleZ = obj->header.gfx.scale[2]; @@ -780,18 +793,21 @@ void obj_apply_scale_to_transform(struct Object *obj) { } void obj_copy_scale(struct Object *dst, struct Object *src) { + if (dst == NULL || src == NULL) { return; } dst->header.gfx.scale[0] = src->header.gfx.scale[0]; dst->header.gfx.scale[1] = src->header.gfx.scale[1]; dst->header.gfx.scale[2] = src->header.gfx.scale[2]; } void obj_scale_xyz(struct Object *obj, f32 xScale, f32 yScale, f32 zScale) { + if (obj == NULL) { return; } obj->header.gfx.scale[0] = xScale; obj->header.gfx.scale[1] = yScale; obj->header.gfx.scale[2] = zScale; } void obj_scale(struct Object *obj, f32 scale) { + if (obj == NULL) { return; } obj->header.gfx.scale[0] = scale; obj->header.gfx.scale[1] = scale; obj->header.gfx.scale[2] = scale; @@ -828,6 +844,7 @@ void cur_obj_init_animation_with_accel_and_sound(s32 animIndex, f32 accel) { } void obj_init_animation_with_sound(struct Object *obj, const struct Animation * const* animations, s32 animIndex) { + if (obj == NULL) { return; } struct Animation **anims = (struct Animation **)animations; obj->oAnimations = (struct Animation **)animations; if (anims != NULL) { @@ -837,6 +854,7 @@ void obj_init_animation_with_sound(struct Object *obj, const struct Animation * } void cur_obj_enable_rendering_and_become_tangible(struct Object *obj) { + if (obj == NULL) { return; } obj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE; obj->oIntangibleTimer = 0; } @@ -846,6 +864,7 @@ void cur_obj_enable_rendering(void) { } void cur_obj_disable_rendering_and_become_intangible(struct Object *obj) { + if (obj == NULL) { return; } obj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; obj->oIntangibleTimer = -1; } @@ -863,6 +882,7 @@ void cur_obj_hide(void) { } void cur_obj_set_pos_relative(struct Object *other, f32 dleft, f32 dy, f32 dforward) { + if (other == NULL) { return; } f32 facingZ = coss(other->oMoveAngleYaw); f32 facingX = sins(other->oMoveAngleYaw); @@ -895,6 +915,7 @@ void cur_obj_unused_init_on_floor(void) { } void obj_set_face_angle_to_move_angle(struct Object *obj) { + if (obj == NULL) { return; } obj->oFaceAnglePitch = obj->oMoveAnglePitch; obj->oFaceAngleYaw = obj->oMoveAngleYaw; obj->oFaceAngleRoll = obj->oMoveAngleRoll; @@ -1614,6 +1635,7 @@ f32 increment_velocity_toward_range(f32 value, f32 center, f32 zeroThreshold, f3 } s32 obj_check_if_collided_with_object(struct Object *obj1, struct Object *obj2) { + if (obj1 == NULL) { return FALSE; } s32 i; for (i = 0; i < obj1->numCollidedObjs; i++) { if (obj1->collidedObjs[i] == obj2) { @@ -1751,10 +1773,12 @@ void set_mario_interact_hoot_if_in_range(UNUSED s32 sp0, UNUSED s32 sp4, f32 sp8 } void obj_set_billboard(struct Object *obj) { + if (obj == NULL) { return; } obj->header.gfx.node.flags |= GRAPH_RENDER_BILLBOARD; } void obj_set_cylboard(struct Object *obj) { + if (obj == NULL) { return; } obj->header.gfx.node.flags |= GRAPH_RENDER_CYLBOARD; } @@ -1771,6 +1795,7 @@ void cur_obj_set_hurtbox_radius_and_height(f32 radius, f32 height) { void obj_spawn_loot_coins(struct Object *obj, s32 numCoins, f32 sp30, const BehaviorScript *coinBehavior, s16 posJitter, s16 model) { + if (obj == NULL) { return; } s32 i; f32 spawnHeight; struct Surface *floor; @@ -2076,6 +2101,7 @@ void obj_set_gfx_pos_at_obj_pos(struct Object *obj1, struct Object *obj2) { * coordinates, and then add it to the vector at posIndex. */ void obj_translate_local(struct Object *obj, s16 posIndex, s16 localTranslateIndex) { + if (obj == NULL) { return; } f32 dx = obj->rawData.asF32[localTranslateIndex + 0]; f32 dy = obj->rawData.asF32[localTranslateIndex + 1]; f32 dz = obj->rawData.asF32[localTranslateIndex + 2]; @@ -2089,6 +2115,7 @@ void obj_translate_local(struct Object *obj, s16 posIndex, s16 localTranslateInd } void obj_build_transform_from_pos_and_angle(struct Object *obj, s16 posIndex, s16 angleIndex) { + if (obj == NULL) { return; } f32 translate[3]; s16 rotation[3]; @@ -2104,6 +2131,7 @@ void obj_build_transform_from_pos_and_angle(struct Object *obj, s16 posIndex, s1 } void obj_set_throw_matrix_from_transform(struct Object *obj) { + if (obj == NULL) { return; } if (obj->oFlags & OBJ_FLAG_0020) { obj_build_transform_from_pos_and_angle(obj, O_POS_INDEX, O_FACE_ANGLE_INDEX); obj_apply_scale_to_transform(obj); @@ -2117,6 +2145,7 @@ void obj_set_throw_matrix_from_transform(struct Object *obj) { } void obj_build_transform_relative_to_parent(struct Object *obj) { + if (obj == NULL) { return; } struct Object *parent = obj->parentObj; obj_build_transform_from_pos_and_angle(obj, O_PARENT_RELATIVE_POS_INDEX, O_FACE_ANGLE_INDEX); @@ -2135,6 +2164,7 @@ void obj_build_transform_relative_to_parent(struct Object *obj) { } void obj_create_transform_from_self(struct Object *obj) { + if (obj == NULL) { return; } obj->oFlags &= ~OBJ_FLAG_TRANSFORM_RELATIVE_TO_PARENT; obj->oFlags |= OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM; @@ -2219,6 +2249,7 @@ s32 cur_obj_follow_path(UNUSED s32 unusedArg) { } void chain_segment_init(struct ChainSegment *segment) { + if (segment == NULL) { return; } segment->posX = 0.0f; segment->posY = 0.0f; segment->posZ = 0.0f; @@ -2238,17 +2269,20 @@ void obj_scale_random(struct Object *obj, f32 rangeLength, f32 minScale) { } void obj_translate_xyz_random(struct Object *obj, f32 rangeLength) { + if (obj == NULL) { return; } obj->oPosX += random_float() * rangeLength - rangeLength * 0.5f; obj->oPosY += random_float() * rangeLength - rangeLength * 0.5f; obj->oPosZ += random_float() * rangeLength - rangeLength * 0.5f; } void obj_translate_xz_random(struct Object *obj, f32 rangeLength) { + if (obj == NULL) { return; } obj->oPosX += random_float() * rangeLength - rangeLength * 0.5f; obj->oPosZ += random_float() * rangeLength - rangeLength * 0.5f; } void obj_build_vel_from_transform(struct Object *a0) { + if (a0 == NULL) { return; } f32 spC = a0->oUnkC0; f32 sp8 = a0->oUnkBC; f32 sp4 = a0->oForwardVel; @@ -2272,6 +2306,7 @@ s16 cur_obj_reflect_move_angle_off_wall(void) { } void cur_obj_spawn_particles(struct SpawnParticlesInfo *info) { + if (info == NULL) { return; } struct Object *particle; s32 i; f32 scale; @@ -2309,6 +2344,7 @@ void cur_obj_spawn_particles(struct SpawnParticlesInfo *info) { } void obj_set_hitbox(struct Object *obj, struct ObjectHitbox *hitbox) { + if (obj == NULL || hitbox == NULL) { return; } if (!(obj->oFlags & OBJ_FLAG_30)) { obj->oFlags |= OBJ_FLAG_30; @@ -3018,6 +3054,7 @@ void cur_obj_shake_screen(s32 shake) { } s32 obj_attack_collided_from_other_object(struct Object *obj) { + if (obj == NULL) { return FALSE; } s32 numCollidedObjs; struct Object *other; s32 touchedOtherObject = FALSE; @@ -3053,6 +3090,7 @@ s32 cur_obj_was_attacked_or_ground_pounded(void) { } void obj_copy_behavior_params(struct Object *dst, struct Object *src) { + if (dst == NULL || src == NULL) { return; } dst->oBehParams = src->oBehParams; dst->oBehParams2ndByte = src->oBehParams2ndByte; } diff --git a/src/pc/chat_commands.c b/src/pc/chat_commands.c index b4ee1351..a56ff157 100644 --- a/src/pc/chat_commands.c +++ b/src/pc/chat_commands.c @@ -4,16 +4,12 @@ #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 "level_table.h" -enum ChatConfirmCommand { - CCC_NONE, - CCC_KICK, - CCC_BAN, - CCC_PERMBAN, -}; +extern int gIsModerator; static enum ChatConfirmCommand sConfirming = CCC_NONE; static u8 sConfirmPlayerIndex = 0; @@ -49,26 +45,38 @@ bool exec_chat_command(char* command) { sConfirming = CCC_NONE; if (ccc != CCC_NONE && strcmp("/confirm", command) == 0) { - if (gNetworkType == NT_SERVER && 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); - network_send_kick(np->localIndex, EKT_KICKED); - network_player_disconnected(np->localIndex); - return true; + if (gNetworkType == NT_SERVER || gIsModerator == 1) { + 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 && 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); - network_send_kick(np->localIndex, EKT_BANNED); - ban_list_add(gNetworkSystem->get_id_str(np->localIndex), false); - network_player_disconnected(np->localIndex); - return true; + if (gNetworkType == NT_SERVER || gIsModerator == 1) { + 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]; @@ -81,6 +89,16 @@ bool exec_chat_command(char* command) { 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) { @@ -102,8 +120,8 @@ bool exec_chat_command(char* command) { } if (str_starts_with("/kick ", command)) { - if (gNetworkType != NT_SERVER) { - djui_chat_message_create("Only the server can use this command."); + if (gNetworkType != NT_SERVER && gIsModerator == 0) { + djui_chat_message_create("You do not have permission to use this command."); return true; } @@ -129,8 +147,8 @@ bool exec_chat_command(char* command) { } if (str_starts_with("/ban ", command)) { - if (gNetworkType != NT_SERVER) { - djui_chat_message_create("Only the server can use this command."); + if (gNetworkType != NT_SERVER && gIsModerator == 0) { + djui_chat_message_create("You do not have permission to use this command."); return true; } @@ -156,8 +174,8 @@ bool exec_chat_command(char* command) { } if (str_starts_with("/permban ", command)) { - if (gNetworkType != NT_SERVER) { - djui_chat_message_create("Only the server can use this command."); + if (gNetworkType != NT_SERVER && gIsModerator == 0) { + djui_chat_message_create("You do not have permission to use this command."); return true; } @@ -182,6 +200,32 @@ bool exec_chat_command(char* command) { 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(DEBUG) && defined(DEVELOPMENT) if (gNetworkSystem == &gNetworkSystemSocket && str_starts_with("/warp ", command)) { static const struct { const char *name; s32 num; } sLevelNumByName[] = { @@ -269,10 +313,11 @@ bool exec_chat_command(char* command) { void display_chat_commands(void) { djui_chat_message_create("/players - List all players and their IDs"); - if (gNetworkType == NT_SERVER) { + if (gNetworkType == NT_SERVER || gIsModerator == 1) { 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(DEBUG) && defined(DEVELOPMENT) djui_chat_message_create("/warp [LEVEL] [AREA] [ACT] - Level can be either a numeric value or a shorthand name"); diff --git a/src/pc/configfile.c b/src/pc/configfile.c index cf827e6a..a026093a 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -16,6 +16,8 @@ #include "pc/mods/mods.h" #include "pc/network/ban_list.h" #include "pc/crash_handler.h" +#include "pc/network/moderator_list.h" + #define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0])) @@ -258,6 +260,19 @@ static void ban_write(FILE* file) { } } +static void moderator_read(char** tokens, UNUSED int numTokens) { + moderator_list_add(tokens[1], true); +} + +static void moderator_write(FILE* file) { + for (unsigned int i = 0; i < gModeratorCount; i++) { + if (gModeratorAddresses == NULL) { break; } + if (gModeratorAddresses[i] == NULL) { continue; } + if (!gModerator[i]) { continue; } + fprintf(file, "%s %s\n", "moderator:", gModeratorAddresses[i]); + } +} + static void dynos_pack_read(char** tokens, int numTokens) { if (numTokens < 3) { return; } char fullPackName[256] = { 0 }; @@ -290,6 +305,7 @@ static void dynos_pack_write(FILE* file) { static const struct FunctionConfigOption functionOptions[] = { { .name = "enable-mod:", .read = enable_mod_read, .write = enable_mod_write }, { .name = "ban:", .read = ban_read, .write = ban_write }, + { .name = "moderator:", .read = moderator_read, .write = moderator_write }, { .name = "dynos-pack:", .read = dynos_pack_read, .write = dynos_pack_write }, }; diff --git a/src/pc/djui/djui_panel_join_message.c b/src/pc/djui/djui_panel_join_message.c index c119b7a4..b42a00f5 100644 --- a/src/pc/djui/djui_panel_join_message.c +++ b/src/pc/djui/djui_panel_join_message.c @@ -16,7 +16,7 @@ void djui_panel_join_message_error(char* message) { } void djui_panel_join_message_cancel(struct DjuiBase* caller) { - network_shutdown(true); + network_shutdown(true, false); djui_panel_menu_back(caller); } diff --git a/src/pc/djui/djui_panel_pause.c b/src/pc/djui/djui_panel_pause.c index 49aff01c..16669434 100644 --- a/src/pc/djui/djui_panel_pause.c +++ b/src/pc/djui/djui_panel_pause.c @@ -1,6 +1,7 @@ #include "djui.h" #include "pc/cheats.h" #include "src/pc/pc_main.h" +#include "src/pc/network/network.h" bool gDjuiPanelPauseCreated = false; @@ -9,13 +10,13 @@ static void djui_panel_pause_resume(UNUSED struct DjuiBase* caller) { } static void djui_panel_pause_quit_yes(UNUSED struct DjuiBase* caller) { - game_exit(); + network_shutdown(true, false); } static void djui_panel_pause_quit(struct DjuiBase* caller) { djui_panel_confirm_create(caller, "\\#ff0800\\Q\\#1be700\\U\\#00b3ff\\I\\#ffef00\\T", - "Are you sure you want to quit?", + "Are you sure you want to disconnect?", djui_panel_pause_quit_yes); } @@ -47,7 +48,7 @@ void djui_panel_pause_create(struct DjuiBase* caller) { djui_base_set_size(&button2->base, 1.0f, 64); djui_interactable_hook_click(&button2->base, djui_panel_pause_resume); - struct DjuiButton* button3 = djui_button_create(&body->base, "Quit"); + struct DjuiButton* button3 = djui_button_create(&body->base, "Disconnect"); djui_base_set_size_type(&button3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size(&button3->base, 1.0f, 64); djui_interactable_hook_click(&button3->base, djui_panel_pause_quit); diff --git a/src/pc/djui/djui_popup.c b/src/pc/djui/djui_popup.c index cdd9dee9..f0a68b14 100644 --- a/src/pc/djui/djui_popup.c +++ b/src/pc/djui/djui_popup.c @@ -68,30 +68,25 @@ void djui_popup_update(void) { struct DjuiPopupList* next = node->next; djui_base_set_location(&node->popup->base, 4, y); y += node->popup->base.height.value + 4; - if (gNetworkType != NT_NONE && gNetworkPlayerLocal != NULL) { - f32 elapsed = (clock_elapsed() - node->createTime); + f32 elapsed = (clock_elapsed() - node->createTime); - // fade out - f32 alpha = fmin(DJUI_POPUP_LIFETIME - elapsed, 1.0f); - alpha *= alpha; - if (elapsed > DJUI_POPUP_LIFETIME) { alpha = 0; } - djui_base_set_color(&node->popup->base, 0, 0, 0, 220 * alpha); - djui_base_set_border_color(&node->popup->base, 0, 0, 0, 180 * alpha); - djui_base_set_color(&node->popup->text->base, 220, 220, 220, 255 * alpha); - djui_text_set_drop_shadow(node->popup->text, 0, 0, 0, 64 * alpha); + // fade out + f32 alpha = fmin(DJUI_POPUP_LIFETIME - elapsed, 1.0f); + alpha *= alpha; + if (elapsed > DJUI_POPUP_LIFETIME) { alpha = 0; } + djui_base_set_color(&node->popup->base, 0, 0, 0, 220 * alpha); + djui_base_set_border_color(&node->popup->base, 0, 0, 0, 180 * alpha); + djui_base_set_color(&node->popup->text->base, 220, 220, 220, 255 * alpha); + djui_text_set_drop_shadow(node->popup->text, 0, 0, 0, 64 * alpha); - // remove/deallocate popup - if (alpha == 0) { - if (last != NULL) { last->next = next; } - if (node == sPopupListHead) { sPopupListHead = next; } - djui_base_destroy(&node->popup->base); - free(node); - node = next; - continue; - } - } else { - // prevent popups from fading out when we're not connected - node->createTime = clock_elapsed(); + // remove/deallocate popup + if (alpha == 0) { + if (last != NULL) { last->next = next; } + if (node == sPopupListHead) { sPopupListHead = next; } + djui_base_destroy(&node->popup->base); + free(node); + node = next; + continue; } // iterate diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index 700882d0..ed09391a 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -180,8 +180,10 @@ void smlua_update(void) { void smlua_shutdown(void) { smlua_text_utils_reset_all(); smlua_audio_utils_reset_all(); + audio_custom_shutdown(); smlua_cobject_allowlist_shutdown(); smlua_cpointer_allowlist_shutdown(); + smlua_clear_hooks(); lua_State* L = gLuaState; if (L != NULL) { lua_close(L); diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index c5d588a0..fc1f3c18 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -977,7 +977,7 @@ int smlua_hook_on_sync_table_change(lua_State* L) { // misc // ////////// -static void smlua_clear_hooks(void) { +void smlua_clear_hooks(void) { for (int i = 0; i < HOOK_MAX; i++) { struct LuaHookedEvent* hooked = &sHookedEvents[i]; for (int j = 0; j < hooked->count; j++) { diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index 0796f51c..cbc2a4ba 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -88,6 +88,7 @@ u32 smlua_get_action_interaction_type(struct MarioState* m); bool smlua_call_chat_command_hook(char* command); void smlua_display_chat_commands(void); +void smlua_clear_hooks(void); void smlua_bind_hooks(void); #endif diff --git a/src/pc/lua/utils/smlua_audio_utils.c b/src/pc/lua/utils/smlua_audio_utils.c index 7e51deb0..b6e294f0 100644 --- a/src/pc/lua/utils/smlua_audio_utils.c +++ b/src/pc/lua/utils/smlua_audio_utils.c @@ -163,6 +163,22 @@ static bool audio_sanity_check(struct BassAudio* audio, bool isStream, const cha } struct BassAudio* audio_load_internal(const char* filename, bool isStream) { + // check file type + bool validFileType = false; + const char* fileTypes[] = { ".mp3", ".aiff", ".ogg", NULL }; + const char** ft = fileTypes; + while (*ft != NULL) { + if (str_ends_with((char*)filename, (char*)*ft)) { + validFileType = true; + break; + } + ft++; + } + if (!validFileType) { + LOG_LUA_LINE("Tried to load audio file with invalid file type: %s", filename); + return NULL; + } + // find mod file in mod list bool foundModFile = false; struct ModFile* modFile = NULL; diff --git a/src/pc/mods/mod.c b/src/pc/mods/mod.c index ce6cacd2..a9f602e0 100644 --- a/src/pc/mods/mod.c +++ b/src/pc/mods/mod.c @@ -289,7 +289,7 @@ static bool mod_load_files(struct Mod* mod, char* modName, char* fullPath) { // deal with sound directory { const char* fileTypes[] = { ".m64", ".mp3", ".aiff", ".ogg", NULL }; - if (!mod_load_files_dir(mod, fullPath, "levels", fileTypes)) { return false; } + if (!mod_load_files_dir(mod, fullPath, "sound", fileTypes)) { return false; } } return true; diff --git a/src/pc/mods/mod_cache.c b/src/pc/mods/mod_cache.c index c586fe07..8c1fd433 100644 --- a/src/pc/mods/mod_cache.c +++ b/src/pc/mods/mod_cache.c @@ -102,27 +102,16 @@ struct ModCacheEntry* mod_cache_get_from_hash(u8* dataHash) { return NULL; } -static bool mod_cache_has_path(const char* path) { - if (path == NULL || strlen(path) == 0) { return NULL; } - struct ModCacheEntry* node = sModCacheHead; - while (node != NULL) { - struct ModCacheEntry* next = node->next; - if (!strcmp(node->path, path)) { - return true; - } - node = next; - } - return false; -} - -struct ModCacheEntry* mod_cache_get_from_path(const char* path) { +struct ModCacheEntry* mod_cache_get_from_path(const char* path, bool validate) { if (path == NULL || strlen(path) == 0) { return NULL; } struct ModCacheEntry* node = sModCacheHead; struct ModCacheEntry* prev = NULL; while (node != NULL) { struct ModCacheEntry* next = node->next; if (!strcmp(node->path, path)) { - if (mod_cache_is_valid(node)) { + if (!validate) { + return node; + } else if (mod_cache_is_valid(node)) { return node; } else { mod_cache_remove_node(node, prev); @@ -220,7 +209,10 @@ void mod_cache_add(struct Mod* mod, struct ModFile* file, bool useFilePath) { file->cachedPath = strdup(modFilePath); // if we already have the filepath, don't MD5 it again - if (useFilePath && mod_cache_has_path(file->cachedPath)) { + struct ModCacheEntry* entry = mod_cache_get_from_path(file->cachedPath, false); + if (useFilePath && entry) { + memcpy(file->dataHash, entry->dataHash, 16); + mod_cache_add_internal(file->dataHash, 0, strdup(file->cachedPath)); return; } diff --git a/src/pc/mods/mod_cache.h b/src/pc/mods/mod_cache.h index a9d20bcd..ea9029a4 100644 --- a/src/pc/mods/mod_cache.h +++ b/src/pc/mods/mod_cache.h @@ -12,7 +12,7 @@ struct ModCacheEntry { void mod_cache_shutdown(void); struct ModCacheEntry* mod_cache_get_from_hash(u8* dataHash); -struct ModCacheEntry* mod_cache_get_from_path(const char* path); +struct ModCacheEntry* mod_cache_get_from_path(const char* path, bool validate); void mod_cache_add(struct Mod* mod, struct ModFile* modFile, bool useFilePath); void mod_cache_load(void); void mod_cache_save(void); diff --git a/src/pc/network/moderator_list.c b/src/pc/network/moderator_list.c new file mode 100644 index 00000000..ddf40b7e --- /dev/null +++ b/src/pc/network/moderator_list.c @@ -0,0 +1,47 @@ +#include +#include +#include "PR/ultratypes.h" +#include "moderator_list.h" +#include "pc/debuglog.h" + +char** gModeratorAddresses = NULL; +bool* gModerator = NULL; +u16 gModeratorCount = 0; + +void moderator_list_add(char* address, bool perm) { + u16 index = gModeratorCount++; + if (gModeratorAddresses == NULL) { + gModeratorAddresses = malloc(sizeof(char*) * gModeratorCount); + gModerator = malloc(sizeof(bool) * gModeratorCount); + } else { + gModeratorAddresses = realloc(gModeratorAddresses, sizeof(char*) * gModeratorCount); + assert(gModeratorAddresses != NULL); + gModerator = realloc(gModerator, sizeof(bool) * gModeratorCount); + assert(gModerator != NULL); + } + if (gModeratorAddresses == NULL) { + LOG_ERROR("Failed to allocate gModeratorAddresses"); + return; + } + if (gModerator == NULL) { + LOG_ERROR("Failed to allocate gModerator"); + return; + } + gModeratorAddresses[index] = strdup(address); + gModerator[index] = perm; +} + +bool moderator_list_contains(char* address) { + if (gModeratorAddresses == NULL || address == NULL) { + return false; + } + + for (s32 i = 0; i < gModeratorCount; i++) { + if (gModeratorAddresses[i] == NULL) { continue; } + if (strcmp(address, gModeratorAddresses[i]) == 0) { + return true; + } + } + + return false; +} diff --git a/src/pc/network/moderator_list.h b/src/pc/network/moderator_list.h new file mode 100644 index 00000000..e390087f --- /dev/null +++ b/src/pc/network/moderator_list.h @@ -0,0 +1,13 @@ +#ifndef MODERATOR_LIST_H +#define MODERATOR_LIST_H + +#include + +extern char** gModeratorAddresses; +extern bool* gModerator; +extern u16 gModeratorCount; + +void moderator_list_add(char* address, bool perm); +bool moderator_list_contains(char* address); + +#endif \ No newline at end of file diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 0e145730..fdbd0a90 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -192,7 +192,7 @@ void network_send_to(u8 localIndex, struct Packet* p) { if (gNetworkSystem == NULL) { LOG_ERROR("no network system attached"); return; } if (localIndex == 0 && !network_allow_unknown_local_index(p->buffer[0])) { LOG_ERROR("\n####################\nsending to myself, packetType: %d\n####################\n", p->packetType); - SOFT_ASSERT(false); + // SOFT_ASSERT(false); - Crash? return; } @@ -418,7 +418,7 @@ void network_register_mod(char* modName) { string_linked_list_append(&gRegisteredMods, modName); } -void network_shutdown(bool sendLeaving) { +void network_shutdown(bool sendLeaving, bool exiting) { if (gDjuiChatBox != NULL) { djui_base_destroy(&gDjuiChatBox->base); gDjuiChatBox = NULL; @@ -440,4 +440,26 @@ void network_shutdown(bool sendLeaving) { } gNetworkType = NT_NONE; + + if (exiting) { return; } + + // reset other stuff + extern u8* gOverrideEeprom; + gOverrideEeprom = NULL; + dynos_mod_shutdown(); + mods_clear(&gActiveMods); + mods_clear(&gRemoteMods); + smlua_shutdown(); + extern s16 gChangeLevel; + gChangeLevel = LEVEL_CASTLE_GROUNDS; + + extern s16 gMenuMode; + gMenuMode = -1; + + djui_panel_shutdown(); + extern bool gDjuiInMainMenu; + if (!gDjuiInMainMenu) { + gDjuiInMainMenu = true; + djui_panel_main_create(NULL); + } } diff --git a/src/pc/network/network.h b/src/pc/network/network.h index d57ef4d8..77a05709 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -130,6 +130,6 @@ void network_receive(u8 localIndex, void* addr, u8* data, u16 dataLength); void* network_duplicate_address(u8 localIndex); void network_update(void); void network_register_mod(char* modName); -void network_shutdown(bool sendLeaving); +void network_shutdown(bool sendLeaving, bool exiting); #endif diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c index 19e99901..d05f40ec 100644 --- a/src/pc/network/network_player.c +++ b/src/pc/network/network_player.c @@ -157,7 +157,7 @@ void network_player_update(void) { #ifndef DEVELOPMENT if (elapsed > NETWORK_PLAYER_TIMEOUT * 1.5f) { LOG_INFO("dropping due to no server connectivity"); - network_shutdown(false); + network_shutdown(false, false); } #endif @@ -264,6 +264,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode smlua_call_event_hooks_mario_param(HOOK_ON_PLAYER_CONNECTED, &gMarioStates[localIndex]); + return localIndex; } @@ -273,7 +274,7 @@ u8 network_player_disconnected(u8 globalIndex) { LOG_ERROR("player disconnected, but it's local.. this shouldn't happen!"); return UNKNOWN_GLOBAL_INDEX; } else { - network_shutdown(true); + network_shutdown(true, false); } } diff --git a/src/pc/network/packets/packet.c b/src/pc/network/packets/packet.c index 293dabc0..78ef2533 100644 --- a/src/pc/network/packets/packet.c +++ b/src/pc/network/packets/packet.c @@ -51,6 +51,8 @@ void packet_process(struct Packet* p) { case PACKET_JOIN: network_receive_join(p); break; case PACKET_CHAT: network_receive_chat(p); break; case PACKET_KICK: network_receive_kick(p); break; + case PACKET_COMMAND: network_recieve_chat_command(p); break; + case PACKET_MODERATOR: network_recieve_moderator(); break; case PACKET_KEEP_ALIVE: network_receive_keep_alive(p); break; case PACKET_LEAVING: network_receive_leaving(p); break; case PACKET_SAVE_FILE: network_receive_save_file(p); break; diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index 04c8a30f..94be11bc 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -70,6 +70,9 @@ enum PacketType { PACKET_REQUEST_FAILED, PACKET_LUA_CUSTOM, + + PACKET_COMMAND, + PACKET_MODERATOR, /// PACKET_CUSTOM = 255, @@ -113,6 +116,14 @@ enum KickReasonType { EKT_BANNED, }; +enum ChatConfirmCommand { + CCC_NONE, + CCC_KICK, + CCC_BAN, + CCC_PERMBAN, + CCC_MODERATOR, +}; + struct LSTNetworkType { enum { LST_NETWORK_TYPE_INTEGER, @@ -230,6 +241,14 @@ void network_receive_chat(struct Packet* p); void network_send_kick(u8 localIndex, enum KickReasonType kickReason); void network_receive_kick(struct Packet* p); +// packet_command_mod.c +void network_send_chat_command(u8 localIndex, enum ChatConfirmCommand CCC); +void network_recieve_chat_command(struct Packet* p); + +// packet_moderator.c +void network_send_moderator(u8 localIndex); +void network_recieve_moderator(void); + // packet_keep_alive.c void network_send_keep_alive(u8 localIndex); void network_receive_keep_alive(struct Packet* p); diff --git a/src/pc/network/packets/packet_command_mod.c b/src/pc/network/packets/packet_command_mod.c new file mode 100644 index 00000000..7816a4f5 --- /dev/null +++ b/src/pc/network/packets/packet_command_mod.c @@ -0,0 +1,61 @@ +#include +#include "../network.h" +#include "pc/djui/djui_chat_message.h" +#include "pc/network/ban_list.h" +#include "pc/network/moderator_list.h" + +int gIsModerator; + +void network_send_chat_command(u8 globalIndex, enum ChatConfirmCommand ccc) { + if (gIsModerator == 1) { + u8 cccType = ccc; + struct Packet p = { 0 }; + packet_init(&p, PACKET_COMMAND, false, PLMT_NONE); + packet_write(&p, &globalIndex, sizeof(u8)); + packet_write(&p, &cccType, sizeof(u8)); + network_send_to(gNetworkPlayerServer->localIndex, &p); + } +} + +void network_recieve_chat_command(struct Packet* p) { + if (!moderator_list_contains(gNetworkSystem->get_id_str(p->localIndex))) { + return; + } + enum ChatConfirmCommand CCC; + u8 player; + packet_read(p, &player, sizeof(u8)); + packet_read(p, &CCC, sizeof(u8)); + if (gNetworkType == NT_SERVER && CCC == CCC_KICK) { + struct NetworkPlayer* np = &gNetworkPlayers[player]; + if (!np->connected) { return; } + network_send_kick(np->localIndex, EKT_KICKED); + network_player_disconnected(np->localIndex); + char message[256] = { 0 }; + snprintf(message, 256, "\\#fff982\\Kicked '%s%s\\#fff982\\'!", network_get_player_text_color_string(np->localIndex), np->name); + djui_chat_message_create(message); + } + if (gNetworkType == NT_SERVER && CCC == CCC_BAN) { + struct NetworkPlayer* np = &gNetworkPlayers[player]; + if (!np->connected) { return; } + network_send_kick(np->localIndex, EKT_BANNED); + ban_list_add(gNetworkSystem->get_id_str(np->localIndex), false); + network_player_disconnected(np->localIndex); + char message[256] = { 0 }; + snprintf(message, 256, "\\#fff982\\Banned '%s%s\\#fff982\\'!", network_get_player_text_color_string(np->localIndex), np->name); + djui_chat_message_create(message); + } +} + +void network_send_moderator(u8 localIndex) { + struct Packet p = { 0 }; + packet_init(&p, PACKET_MODERATOR, false, PLMT_NONE); + network_send_to(localIndex, &p); +} + +void network_recieve_moderator(void) { + if (gIsModerator == 1) { + return; + } + gIsModerator = 1; + djui_chat_message_create("\\#fff982\\You are now a Moderator."); +} \ No newline at end of file diff --git a/src/pc/network/packets/packet_join.c b/src/pc/network/packets/packet_join.c index 313c9819..b464ba4a 100644 --- a/src/pc/network/packets/packet_join.c +++ b/src/pc/network/packets/packet_join.c @@ -153,7 +153,7 @@ void network_receive_join(struct Packet* p) { packet_read(p, &remoteVersion, sizeof(u8) * MAX_VERSION_LENGTH); LOG_INFO("server has version: %s", version); if (memcmp(version, remoteVersion, MAX_VERSION_LENGTH) != 0) { - network_shutdown(true); + network_shutdown(true, false); LOG_ERROR("version mismatch"); char mismatchMessage[256] = { 0 }; snprintf(mismatchMessage, 256, "\\#ffa0a0\\Error:\\#c8c8c8\\ Version mismatch.\n\nYour version: \\#a0a0ff\\%s\\#c8c8c8\\\nTheir version: \\#a0a0ff\\%s\\#c8c8c8\\\n\nSomeone is out of date!\n", version, remoteVersion); @@ -186,7 +186,7 @@ void network_receive_join(struct Packet* p) { } if (string_linked_list_mismatch(&gRegisteredMods, &head)) { - network_shutdown(true); + network_shutdown(true, false); struct StringBuilder* builder = string_builder_create(512); string_builder_append(builder, "\\#ffa0a0\\Error:\\#c8c8c8\\ mods don't match.\n\n"); diff --git a/src/pc/network/packets/packet_kick.c b/src/pc/network/packets/packet_kick.c index b231e6db..4a77b020 100644 --- a/src/pc/network/packets/packet_kick.c +++ b/src/pc/network/packets/packet_kick.c @@ -32,5 +32,5 @@ void network_receive_kick(struct Packet* p) { case EKT_BANNED: djui_panel_join_message_error("\\#ffa0a0\\Error:\\#c8c8c8\\ The server banned you."); break; default: djui_panel_join_message_error("\\#ffa0a0\\Error:\\#c8c8c8\\ Host has closed the connection."); break; } - network_shutdown(false); + network_shutdown(false, false); } diff --git a/src/pc/network/packets/packet_mod_list.c b/src/pc/network/packets/packet_mod_list.c index eb9be536..efd9084f 100644 --- a/src/pc/network/packets/packet_mod_list.c +++ b/src/pc/network/packets/packet_mod_list.c @@ -121,7 +121,7 @@ void network_receive_mod_list(struct Packet* p) { packet_read(p, &remoteVersion, sizeof(u8) * MAX_VERSION_LENGTH); LOG_INFO("server has version: %s", version); if (memcmp(version, remoteVersion, MAX_VERSION_LENGTH) != 0) { - network_shutdown(true); + network_shutdown(true, false); LOG_ERROR("version mismatch"); char mismatchMessage[256] = { 0 }; snprintf(mismatchMessage, 256, "\\#ffa0a0\\Error:\\#c8c8c8\\ Version mismatch.\n\nYour version: \\#a0a0ff\\%s\\#c8c8c8\\\nTheir version: \\#a0a0ff\\%s\\#c8c8c8\\\n\nSomeone is out of date!\n", version, remoteVersion); @@ -205,7 +205,7 @@ void network_receive_mod_list_entry(struct Packet* p) { // sanity check mod size if (mod->size >= MAX_MOD_SIZE) { djui_popup_create("Server had too large of a mod.\nQuitting.", 4); - network_shutdown(false); + network_shutdown(false, false); return; } diff --git a/src/pc/network/packets/packet_network_players.c b/src/pc/network/packets/packet_network_players.c index f0913947..607e1fce 100644 --- a/src/pc/network/packets/packet_network_players.c +++ b/src/pc/network/packets/packet_network_players.c @@ -5,6 +5,7 @@ #include "src/game/behavior_actions.h" #include "pc/debuglog.h" #include "pc/configfile.h" +#include "pc/network/moderator_list.h" static void network_send_to_network_players(u8 sendToLocalIndex) { SOFT_ASSERT(gNetworkType == NT_SERVER); @@ -57,6 +58,11 @@ void network_receive_network_players_request(struct Packet* p) { return; } network_send_to_network_players(localIndex); + + if (moderator_list_contains(gNetworkSystem->get_id_str(p->localIndex))) { + LOG_INFO("sending moderator packet to localIndex: %d", p->localIndex); + network_send_moderator(p->localIndex); + } } void network_send_network_players(u8 exceptLocalIndex) { diff --git a/src/pc/network/socket/socket.c b/src/pc/network/socket/socket.c index 4bf70b22..f2541658 100644 --- a/src/pc/network/socket/socket.c +++ b/src/pc/network/socket/socket.c @@ -4,8 +4,8 @@ #include "pc/debuglog.h" #include "pc/djui/djui.h" -static SOCKET curSocket = INVALID_SOCKET; -static struct sockaddr_in addr[MAX_PLAYERS] = { 0 }; +static SOCKET sCurSocket = INVALID_SOCKET; +static struct sockaddr_in sAddr[MAX_PLAYERS] = { 0 }; static int socket_bind(SOCKET socket, unsigned int port) { struct sockaddr_in rxAddr; @@ -40,7 +40,7 @@ static int socket_receive(SOCKET socket, struct sockaddr_in* rxAddr, u8* buffer, int rc = recvfrom(socket, (char*)buffer, bufferLength, 0, (struct sockaddr*)rxAddr, &rxAddrSize); for (int i = 1; i < MAX_PLAYERS; i++) { - if (memcmp(rxAddr, &addr[i], sizeof(struct sockaddr_in)) == 0) { + if (memcmp(rxAddr, &sAddr[i], sizeof(struct sockaddr_in)) == 0) { *localIndex = i; break; } @@ -65,21 +65,32 @@ static bool ns_socket_initialize(enum NetworkType networkType) { if (port == 0) { port = DEFAULT_PORT; } // create a receiver socket to receive datagrams - curSocket = socket_initialize(); - if (curSocket == INVALID_SOCKET) { return false; } + sCurSocket = socket_initialize(); + if (sCurSocket == INVALID_SOCKET) { return false; } // connect if (networkType == NT_SERVER) { + int reuse = 1; + if (setsockopt(sCurSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) { + LOG_ERROR("setsockopt(SO_REUSEADDR) failed"); + } + +#ifdef SO_REUSEPORT + if (setsockopt(sCurSocket, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0) { + LOG_ERROR("setsockopt(SO_REUSEPORT) failed"); + } +#endif + // bind the socket to any address and the specified port. - int rc = socket_bind(curSocket, port); + int rc = socket_bind(sCurSocket, port); if (rc != NO_ERROR) { return false; } LOG_INFO("bound to port %u", port); } else { // save the port to send to - addr[0].sin_family = AF_INET; - addr[0].sin_port = htons(port); + sAddr[0].sin_family = AF_INET; + sAddr[0].sin_port = htons(port); domain_resolution(); - addr[0].sin_addr.s_addr = inet_addr(configJoinIp); + sAddr[0].sin_addr.s_addr = inet_addr(configJoinIp); LOG_INFO("connecting to %s %u", configJoinIp, port); } @@ -109,27 +120,27 @@ static s64 ns_socket_get_id(UNUSED u8 localId) { static char* ns_socket_get_id_str(u8 localId) { if (localId == UNKNOWN_LOCAL_INDEX) { localId = 0; } static char id_str[INET_ADDRSTRLEN] = { 0 }; - snprintf(id_str, INET_ADDRSTRLEN, "%s", inet_ntoa(addr[localId].sin_addr)); + snprintf(id_str, INET_ADDRSTRLEN, "%s", inet_ntoa(sAddr[localId].sin_addr)); return id_str; } static void ns_socket_save_id(u8 localId, UNUSED s64 networkId) { SOFT_ASSERT(localId > 0); SOFT_ASSERT(localId < MAX_PLAYERS); - addr[localId] = addr[0]; + sAddr[localId] = sAddr[0]; LOG_INFO("saved addr for id %d", localId); } static void ns_socket_clear_id(u8 localId) { if (localId == 0) { return; } SOFT_ASSERT(localId < MAX_PLAYERS); - memset(&addr[localId], 0, sizeof(struct sockaddr_in)); + memset(&sAddr[localId], 0, sizeof(struct sockaddr_in)); LOG_INFO("cleared addr for id %d", localId); } static void* ns_socket_dup_addr(u8 localIndex) { void* address = malloc(sizeof(struct sockaddr_in)); - memcpy(address, &addr[localIndex], sizeof(struct sockaddr_in)); + memcpy(address, &sAddr[localIndex], sizeof(struct sockaddr_in)); return address; } @@ -144,10 +155,10 @@ static void ns_socket_update(void) { u8 data[PACKET_LENGTH + 1]; u16 dataLength = 0; u8 localIndex = UNKNOWN_LOCAL_INDEX; - int rc = socket_receive(curSocket, &addr[0], data, PACKET_LENGTH + 1, &dataLength, &localIndex); + int rc = socket_receive(sCurSocket, &sAddr[0], data, PACKET_LENGTH + 1, &dataLength, &localIndex); SOFT_ASSERT(dataLength < PACKET_LENGTH); if (rc != NO_ERROR) { break; } - network_receive(localIndex, &addr[0], data, dataLength); + network_receive(localIndex, &sAddr[0], data, dataLength); } while (true); } @@ -157,10 +168,10 @@ static int ns_socket_send(u8 localIndex, void* address, u8* data, u16 dataLength if (gNetworkType == NT_CLIENT && gNetworkPlayers[localIndex].type != NPT_SERVER) { return SOCKET_ERROR; } } - struct sockaddr_in* userAddr = &addr[localIndex]; + struct sockaddr_in* userAddr = &sAddr[localIndex]; if (localIndex == 0 && address != NULL) { userAddr = (struct sockaddr_in*)address; } - int rc = socket_send(curSocket, userAddr, data, dataLength); + int rc = socket_send(sCurSocket, userAddr, data, dataLength); if (rc) { LOG_ERROR(" localIndex: %d, packetType: %d, dataLength: %d", localIndex, data[0], dataLength); } @@ -168,8 +179,11 @@ static int ns_socket_send(u8 localIndex, void* address, u8* data, u16 dataLength } static void ns_socket_shutdown(void) { - socket_shutdown(curSocket); - curSocket = INVALID_SOCKET; + socket_shutdown(sCurSocket); + sCurSocket = INVALID_SOCKET; + for (u16 i = 0; i < MAX_PLAYERS; i++) { + memset(&sAddr[i], 0, sizeof(struct sockaddr_in)); + } LOG_INFO("shutdown"); } diff --git a/src/pc/network/version.c b/src/pc/network/version.c index 477f9591..dca26ad1 100644 --- a/src/pc/network/version.c +++ b/src/pc/network/version.c @@ -3,11 +3,7 @@ #include "types.h" static char sVersionString[MAX_VERSION_LENGTH] = { 0 }; -#ifdef UNSTABLE_BRANCH -#define VERSION_TEXT "unst " -#else #define VERSION_TEXT "beta " -#endif char* get_version(void) { snprintf(sVersionString, MAX_VERSION_LENGTH, "%s%d.%d", VERSION_TEXT, VERSION_NUMBER, MINOR_VERSION_NUMBER); diff --git a/src/pc/network/version.h b/src/pc/network/version.h index 5a2b550d..3c6ae6db 100644 --- a/src/pc/network/version.h +++ b/src/pc/network/version.h @@ -1,7 +1,6 @@ #ifndef VERSION_H #define VERSION_H -#define UNSTABLE_BRANCH #define VERSION_NUMBER 27 #define MINOR_VERSION_NUMBER 0 diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 2afe9e7d..9b58b305 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -258,7 +258,7 @@ void game_deinit(void) { audio_custom_shutdown(); audio_shutdown(); gfx_shutdown(); - network_shutdown(true); + network_shutdown(true, true); smlua_shutdown(); mods_shutdown(); inited = false;