mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 05:25:14 +00:00
Moderator (#80)
This commit is contained in:
parent
c7cfa1be54
commit
701fddf4dd
51 changed files with 562 additions and 177 deletions
9
Makefile
9
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<TexData>* aNode, bool aCustomTexture);
|
|||
void DynOS_Tex_Deactivate(DataNode<TexData>* 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<MovtexQC>* 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<MovtexQC>* DynOS_MovtexQC_GetFromId(u32 id);
|
||||
DataNode<MovtexQC>* DynOS_MovtexQC_GetFromIndex(s32 index);
|
||||
void DynOS_MovtexQC_ModShutdown();
|
||||
|
||||
//
|
||||
// Bin
|
||||
|
|
|
@ -156,4 +156,9 @@ void dynos_level_load_background(void *ptr) {
|
|||
DynOS_Lvl_LoadBackground(ptr);
|
||||
}
|
||||
|
||||
// -- other -- //
|
||||
void dynos_mod_shutdown(void) {
|
||||
DynOS_Mod_Shutdown();
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,9 @@
|
|||
extern "C" {
|
||||
}
|
||||
|
||||
bool gDynosModShutdown = false;
|
||||
|
||||
void DynOS_Gfx_Update() {
|
||||
DynOS_Mod_Update();
|
||||
DynOS_Tex_Update();
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ struct DynosWarp {
|
|||
};
|
||||
|
||||
static void *sDynosLevelScripts[LEVEL_COUNT] = { NULL };
|
||||
static void *sDynosLevelScriptsOriginal[LEVEL_COUNT] = { NULL };
|
||||
static Array<DynosWarp> sDynosLevelWarps[LEVEL_COUNT] = { Array<DynosWarp>() };
|
||||
static Array<s32> sDynosLevelList = Array<s32>(); // 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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,22 @@ Array<Pair<const char*, GfxData*>> &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();
|
||||
|
|
|
@ -67,3 +67,12 @@ DataNode<MovtexQC>* 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -422,6 +422,7 @@ void DynOS_Tex_AddCustom(const SysPath &aFilename, const char *aTexName) {
|
|||
// Load
|
||||
SysPath _PackFolder = "";
|
||||
DataNode<TexData>* _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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 :(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 },
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
47
src/pc/network/moderator_list.c
Normal file
47
src/pc/network/moderator_list.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
13
src/pc/network/moderator_list.h
Normal file
13
src/pc/network/moderator_list.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef MODERATOR_LIST_H
|
||||
#define MODERATOR_LIST_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern char** gModeratorAddresses;
|
||||
extern bool* gModerator;
|
||||
extern u16 gModeratorCount;
|
||||
|
||||
void moderator_list_add(char* address, bool perm);
|
||||
bool moderator_list_contains(char* address);
|
||||
|
||||
#endif
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
61
src/pc/network/packets/packet_command_mod.c
Normal file
61
src/pc/network/packets/packet_command_mod.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
#include <stdio.h>
|
||||
#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.");
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define UNSTABLE_BRANCH
|
||||
#define VERSION_NUMBER 27
|
||||
#define MINOR_VERSION_NUMBER 0
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue