From 75033c0e84baa01aaa9e78b559a80d40e3adaa3d Mon Sep 17 00:00:00 2001 From: MysterD Date: Sun, 18 Oct 2020 22:21:25 -0700 Subject: [PATCH 01/14] Beta 2 release --- src/pc/network/version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pc/network/version.c b/src/pc/network/version.c index 7ee4b14b..849ce60c 100644 --- a/src/pc/network/version.c +++ b/src/pc/network/version.c @@ -3,7 +3,7 @@ #include "types.h" static char sVersionString[MAX_VERSION_LENGTH] = { 0 }; -#ifdef UNSTABLE_BRANCH +//#ifdef UNSTABLE_BRANCH #define VERSION_TEXT "unst " #else #define VERSION_TEXT "beta " From 2ac19eb1bae1217eefa64d2c64e5c684a830be2b Mon Sep 17 00:00:00 2001 From: MysterD Date: Sun, 18 Oct 2020 22:24:37 -0700 Subject: [PATCH 02/14] Whoops, actual release --- src/pc/network/version.c | 2 +- src/pc/network/version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pc/network/version.c b/src/pc/network/version.c index 849ce60c..7ee4b14b 100644 --- a/src/pc/network/version.c +++ b/src/pc/network/version.c @@ -3,7 +3,7 @@ #include "types.h" static char sVersionString[MAX_VERSION_LENGTH] = { 0 }; -//#ifdef UNSTABLE_BRANCH +#ifdef UNSTABLE_BRANCH #define VERSION_TEXT "unst " #else #define VERSION_TEXT "beta " diff --git a/src/pc/network/version.h b/src/pc/network/version.h index 573456d6..1dc7d0a4 100644 --- a/src/pc/network/version.h +++ b/src/pc/network/version.h @@ -1,7 +1,7 @@ #ifndef VERSION_H #define VERSION_H -#define UNSTABLE_BRANCH +//#define UNSTABLE_BRANCH #define VERSION_NUMBER 2 #define MAX_VERSION_LENGTH 10 From bff0fc915539a50a067381c49e98299ed56d745f Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sun, 14 Feb 2021 03:11:19 -0700 Subject: [PATCH 03/14] Link to build instructions --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6d584a15..7db0f111 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Online cooperative multiplayer mod for SM64, aiming to synchronize all entities and every level for two players. Fork of [sm64pc/sm64ex](https://github.com/sm64pc/sm64ex). +Build instructions are available on the [sm64ex wiki](https://github.com/sm64pc/sm64ex/wiki). + Feel free to report bugs and contribute, but remember, there must be **no upload of any copyrighted asset**. Run `./extract_assets.py --clean && make clean` or `make distclean` to remove ROM-originated content. From fc44f9138618b9c9ca23bcf8dde7722112d288c9 Mon Sep 17 00:00:00 2001 From: Avery Date: Sat, 6 Mar 2021 21:07:55 -0800 Subject: [PATCH 04/14] make discord max party size equal to MAX_PLAYERS --- src/pc/network/discord/lobby.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pc/network/discord/lobby.c b/src/pc/network/discord/lobby.c index d556dad7..1d2561f3 100644 --- a/src/pc/network/discord/lobby.c +++ b/src/pc/network/discord/lobby.c @@ -18,7 +18,7 @@ static void on_lobby_create_callback(UNUSED void* data, enum EDiscordResult resu gCurActivity.type = DiscordActivityType_Playing; snprintf(gCurActivity.party.id, 128, "%lld", lobby->id); gCurActivity.party.size.current_size = 1; - gCurActivity.party.size.max_size = 2; + gCurActivity.party.size.max_size = MAX_PLAYERS; char secretJoin[128] = ""; snprintf(secretJoin, 128, "%lld:%s", lobby->id, lobby->secret); @@ -59,7 +59,7 @@ void discord_lobby_create(void) { struct IDiscordLobbyTransaction* txn = { 0 }; DISCORD_REQUIRE(app.lobbies->get_lobby_create_transaction(app.lobbies, &txn)); - txn->set_capacity(txn, 2); + txn->set_capacity(txn, MAX_PLAYERS); txn->set_type(txn, DiscordLobbyType_Public); //txn->set_metadata(txn, "a", "123"); @@ -94,4 +94,4 @@ struct IDiscordLobbyEvents* discord_lobby_initialize(void) { events.on_member_disconnect = on_member_disconnect; events.on_network_message = discord_network_on_message; return &events; -} \ No newline at end of file +} From 5eba0cb0f67e70f64be790391066c2243f23131d Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 5 Apr 2021 03:21:37 +0300 Subject: [PATCH 05/14] djoslin0's new warp code --- build-windows-visual-studio/sm64ex.vcxproj | 1 + .../sm64ex.vcxproj.filters | 3 + developer/network.sh | 6 +- developer/proto-4.sh | 23 +-- src/game/area.c | 18 ++- src/game/level_update.c | 28 ++-- src/game/level_update.h | 4 + src/pc/network/packets/packet.c | 1 + src/pc/network/packets/packet.h | 6 + src/pc/network/packets/packet_level_warp_2.c | 143 ++++++++++++++++++ 10 files changed, 191 insertions(+), 42 deletions(-) create mode 100644 src/pc/network/packets/packet_level_warp_2.c diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index dc68a31d..d536ee68 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -3974,6 +3974,7 @@ + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index 49a46088..a4103955 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -15087,6 +15087,9 @@ Source Files\src\game + + Source Files\src\pc\network\packets + diff --git a/developer/network.sh b/developer/network.sh index 795ded53..8d0b2e08 100644 --- a/developer/network.sh +++ b/developer/network.sh @@ -18,9 +18,9 @@ fi #exit # no debug, direct -#$FILE --server 27015 --configfile sm64config_server.txt & -#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & -#exit +$FILE --server 27015 --configfile sm64config_server.txt & +$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & +exit # debug on server #$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & diff --git a/developer/proto-4.sh b/developer/proto-4.sh index 623295c6..128afe9c 100644 --- a/developer/proto-4.sh +++ b/developer/proto-4.sh @@ -12,26 +12,6 @@ if [ ! -f "$FILE" ]; then FILE=./build/us_pc/sm64.us.f3dex2e fi -# no debug, discord -#$FILE --discord 2 --configfile sm64config_server.txt & -#$FILE --discord 1 --configfile sm64config_client.txt & -#exit - -# no debug, direct -#$FILE --server 27015 --configfile sm64config_server.txt & -#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & -#exit - -# debug on server -#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & -#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt' -ex 'quit' -#exit - -################### -# debug on client # -################### - -#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_p1.txt' -ex 'quit' $FILE --server 27015 --configfile sm64config_p1.txt & sleep 2 $FILE --client 127.0.0.1 27015 --configfile sm64config_p2.txt & @@ -39,4 +19,7 @@ sleep 2 $FILE --client 127.0.0.1 27015 --configfile sm64config_p3.txt & sleep 2 $FILE --client 127.0.0.1 27015 --configfile sm64config_p4.txt & + +#sleep 2 +#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_p1.txt' -ex 'quit' #winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --client 127.0.0.1 27015 --configfile sm64config_p4.txt' -ex 'quit' diff --git a/src/game/area.c b/src/game/area.c index aff25635..cafd4207 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -257,6 +257,15 @@ void load_area(s32 index) { load_obj_warp_nodes(); geo_call_global_function_nodes(&gCurrentArea->unk04->node, GEO_CONTEXT_AREA_LOAD); } + + if (!network_is_warp_2_duplicate()) { + if (gNetworkType != NT_NONE) { + network_send_level_warp_2(TRUE, gNetworkPlayerLocal->globalIndex); + } + if (gNetworkType == NT_CLIENT) { + sCurrPlayMode = PLAY_MODE_SYNC_LEVEL; + } + } } void unload_area(void) { @@ -442,15 +451,8 @@ void render_game(void) { } // only render 'synchronizing' text if we've been waiting for a while - static u8 syncLevelTime = 0; if (sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) { - if (syncLevelTime < 30) { - syncLevelTime++; - } else { - render_sync_level_screen(); - } - } else { - syncLevelTime = 0; + render_sync_level_screen(); } D_8032CE74 = NULL; diff --git a/src/game/level_update.c b/src/game/level_update.c index 52d8def9..a334233a 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -53,6 +53,10 @@ u8 gControlledWarpGlobalIndex = 0; extern s8 sReceivedLoadedActNum; u8 gRejectInstantWarp = 0; +s16 gChangeLevel = -1; +s16 gChangeAreaIndex = -1; +s16 gChangeActNum = -1; + #ifdef VERSION_JP const char *credits01[] = { "1GAME DIRECTOR", "SHIGERU MIYAMOTO" }; const char *credits02[] = { "2ASSISTANT DIRECTORS", "YOSHIAKI KOIZUMI", "TAKASHI TEZUKA" }; @@ -1090,15 +1094,9 @@ s32 play_mode_normal(void) { } } else if (!gReceiveWarp.received) { if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL) { - set_play_mode(PLAY_MODE_SYNC_LEVEL); - network_send_level_warp_begin(); + set_play_mode(PLAY_MODE_CHANGE_LEVEL); } else if (sTransitionTimer != 0) { - if (sWarpDest.type == WARP_TYPE_CHANGE_AREA) { - set_play_mode(PLAY_MODE_SYNC_LEVEL); - network_send_level_warp_begin(); - } else { - set_play_mode(PLAY_MODE_CHANGE_AREA); - } + set_play_mode(PLAY_MODE_CHANGE_AREA); } else if (sCurrPlayMode == PLAY_MODE_NORMAL && pressed_pause()) { lower_background_noise(1); cancel_rumble(); @@ -1129,8 +1127,7 @@ s32 play_mode_paused(void) { fade_into_special_warp(0, 0); gSavedCourseNum = COURSE_NONE; } - set_play_mode(PLAY_MODE_SYNC_LEVEL); - network_send_level_warp_begin(); + set_play_mode(PLAY_MODE_CHANGE_LEVEL); } else if (gPauseScreenMode == 3) { // We should only be getting "int 3" to here initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); @@ -1150,7 +1147,7 @@ s32 play_mode_sync_level(void) { set_menu_mode(-1); gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN; - check_received_warp(); + //check_received_warp(); return 0; } @@ -1262,6 +1259,15 @@ static s32 play_mode_unused(void) { s32 update_level(void) { s32 changeLevel = 0; + if (gChangeLevel != -1) { + gHudDisplay.flags = HUD_DISPLAY_NONE; + sTransitionTimer = 0; + sTransitionUpdate = NULL; + changeLevel = gChangeLevel; + gChangeLevel = -1; + return changeLevel; + } + switch (sCurrPlayMode) { case PLAY_MODE_NORMAL: changeLevel = play_mode_normal(); diff --git a/src/game/level_update.h b/src/game/level_update.h index eeea9baa..52f5d9a2 100644 --- a/src/game/level_update.h +++ b/src/game/level_update.h @@ -76,6 +76,10 @@ extern s16 sTransitionTimer; extern void (*sTransitionUpdate)(s16 *); extern u8 unused3[4]; +extern s16 gChangeLevel; +extern s16 gChangeAreaIndex; +extern s16 gChangeActNum; + struct WarpDest { u8 type; u8 levelNum; diff --git a/src/pc/network/packets/packet.c b/src/pc/network/packets/packet.c index 800cc8db..b7d44f68 100644 --- a/src/pc/network/packets/packet.c +++ b/src/pc/network/packets/packet.c @@ -56,6 +56,7 @@ void packet_receive(struct Packet* p) { case PACKET_INSTANT_WARP: network_receive_instant_warp(p); break; case PACKET_NETWORK_PLAYERS: network_receive_network_players(p); break; case PACKET_DEATH: network_receive_death(p); break; + case PACKET_LEVEL_WARP_2: network_receive_level_warp_2(p); break; /// case PACKET_CUSTOM: network_receive_custom(p); break; default: LOG_ERROR("received unknown packet: %d", p->buffer[0]); diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index e14b0db3..2f2835f9 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -33,6 +33,7 @@ enum PacketType { PACKET_INSTANT_WARP, PACKET_NETWORK_PLAYERS, PACKET_DEATH, + PACKET_LEVEL_WARP_2, /// PACKET_CUSTOM = 255, }; @@ -171,4 +172,9 @@ void network_receive_network_players(struct Packet* p); void network_send_death(void); void network_receive_death(struct Packet* p); +// packet_level_warp_2.c +void network_send_level_warp_2(u8 eventBegins, u8 controlledGlobalIndex); +void network_receive_level_warp_2(struct Packet* p); +u8 network_is_warp_2_duplicate(void); + #endif diff --git a/src/pc/network/packets/packet_level_warp_2.c b/src/pc/network/packets/packet_level_warp_2.c new file mode 100644 index 00000000..9cb574d4 --- /dev/null +++ b/src/pc/network/packets/packet_level_warp_2.c @@ -0,0 +1,143 @@ +#include "../network.h" +#include "game/level_update.h" +#include "game/object_list_processor.h" +//#define DISABLE_MODULE_LOG +#include "pc/debuglog.h" + +#define SERVER_RETAIN_WARP_SECONDS 1 + +extern u8 gControlledWarpGlobalIndex; +extern float gPaintingMarioYEntry; + +#pragma pack(1) +struct PacketLevelWarp2Data { + s16 levelNum; + s16 areaIndex; + s16 actNum; + + u8 warpType; + u8 warpLevelNum; + u8 warpAreaIdx; + u8 warpNodeId; + u32 warpArg; + + s8 inWarpCheckpoint; + s16 ttcSpeedSetting; + s16 D_80339EE0; + f32 paintingMarioYEntry; + u8 controlledWarpGlobalIndex; +}; + +struct PacketLevelWarp2Data sSavedLevelWarp2Data = { 0 }; +static clock_t sSavedClockTime = 0; + +static void populate_packet_data(struct PacketLevelWarp2Data* data) { + data->levelNum = gCurrLevelNum; + data->areaIndex = gCurrAreaIndex; + data->actNum = gCurrActNum; + + data->warpType = sWarpDest.type; + data->warpLevelNum = sWarpDest.levelNum; + data->warpAreaIdx = sWarpDest.areaIdx; + data->warpNodeId = sWarpDest.nodeId; + data->warpArg = sWarpDest.arg; + + data->inWarpCheckpoint = gInWarpCheckpoint; + data->ttcSpeedSetting = gTTCSpeedSetting; + data->D_80339EE0 = D_80339EE0; + data->paintingMarioYEntry = gPaintingMarioYEntry; + data->controlledWarpGlobalIndex = gControlledWarpGlobalIndex; +} + +void network_send_level_warp_2(u8 eventBegins, u8 controlledGlobalIndex) { + struct PacketLevelWarp2Data data = { 0 }; + if (eventBegins) { + gControlledWarpGlobalIndex = controlledGlobalIndex; + populate_packet_data(&data); + if (gNetworkType == NT_SERVER) { + sSavedLevelWarp2Data = data; + sSavedClockTime = clock(); + } + } else { + data = sSavedLevelWarp2Data; + } + + struct Packet p; + packet_init(&p, PACKET_LEVEL_WARP_2, true, false); + packet_write(&p, &data, sizeof(struct PacketLevelWarp2Data)); + + if (gNetworkType == NT_SERVER) { + network_send(&p); + } else { + network_send_to(gNetworkPlayerServer->localIndex, &p); + } + + LOG_INFO("send warp: %d, %d, %d", gCurrLevelNum, gCurrAreaIndex, gCurrActNum); +} + +static void do_warp(struct PacketLevelWarp2Data* data) { + if (gCurrLevelNum != data->levelNum ) { gChangeLevel = data->levelNum; } + + sWarpDest.type = data->warpType; + sWarpDest.levelNum = data->warpLevelNum; + sWarpDest.areaIdx = data->warpAreaIdx; + sWarpDest.nodeId = data->warpNodeId; + sWarpDest.arg = data->warpArg; + + gInWarpCheckpoint = data->inWarpCheckpoint; + gTTCSpeedSetting = data->ttcSpeedSetting; + D_80339EE0 = data->D_80339EE0; + gPaintingMarioYEntry = data->paintingMarioYEntry; + gControlledWarpGlobalIndex = data->controlledWarpGlobalIndex; + + gCurrLevelNum = data->levelNum; + gCurrAreaIndex = data->areaIndex; + gCurrActNum = data->actNum; + + LOG_INFO("do warp: %d, %d, %d", gCurrLevelNum, gCurrAreaIndex, gCurrActNum); +} + +void network_receive_level_warp_2(struct Packet* p) { + struct PacketLevelWarp2Data remote = { 0 }; + packet_read(p, &remote, sizeof(struct PacketLevelWarp2Data)); + LOG_INFO("rx warp: %d, %d, %d", remote.levelNum, remote.areaIndex, remote.actNum); + + u8 levelOrAreaDifference = (gCurrLevelNum != remote.levelNum) || (gCurrAreaIndex != remote.areaIndex); + + if (gNetworkType == NT_SERVER) { + f32 elapsed = (clock() - sSavedClockTime) / (f32)CLOCKS_PER_SEC; + if (elapsed < SERVER_RETAIN_WARP_SECONDS || !levelOrAreaDifference) { + network_send_level_warp_2(FALSE, gNetworkPlayerLocal->globalIndex); + return; + } + } + + if (levelOrAreaDifference) { + do_warp(&remote); + } + + if (gNetworkType == NT_CLIENT) { + sSavedLevelWarp2Data = remote; + sSavedClockTime = clock(); + } + + if (gNetworkType == NT_SERVER) { + network_send_level_warp_2(TRUE, remote.controlledWarpGlobalIndex); + } else { + sCurrPlayMode = PLAY_MODE_NORMAL; + network_on_init_level(); + } +} + +u8 network_is_warp_2_duplicate(void) { + struct PacketLevelWarp2Data data = { 0 }; + populate_packet_data(&data); + + if (data.levelNum == 1 && data.areaIndex == 1) { return TRUE; } + + if (gNetworkType == NT_SERVER) { + f32 elapsed = (clock() - sSavedClockTime) / (f32)CLOCKS_PER_SEC; + if (elapsed >= SERVER_RETAIN_WARP_SECONDS) { return FALSE; } + } + return (memcmp(&sSavedLevelWarp2Data, &data, sizeof(struct PacketLevelWarp2Data)) == 0); +} \ No newline at end of file From ee71f19e6e0af8bdc84c3c4f8203c41a7b7f5e01 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 5 Apr 2021 04:21:14 +0300 Subject: [PATCH 06/14] partially fix jitter with two of the same model --- src/game/mario_misc.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index 43f81eb6..5909d1d9 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -405,7 +405,8 @@ Gfx* geo_switch_mario_eyes(s32 callContext, struct GraphNode* node, UNUSED Mat4* Gfx* geo_mario_tilt_torso(s32 callContext, struct GraphNode* node, Mat4* mtx) { Mat4 * curTransform = mtx; struct GraphNodeGenerated* asGenerated = (struct GraphNodeGenerated*) node; - struct MarioBodyState* bodyState = geo_get_body_state(); + u8 plrIdx = geo_get_processing_object_index(); + struct MarioBodyState* bodyState = &gBodyStates[plrIdx]; s32 action = bodyState->action; if (callContext == GEO_CONTEXT_RENDER) { @@ -418,6 +419,11 @@ Gfx* geo_mario_tilt_torso(s32 callContext, struct GraphNode* node, Mat4* mtx) { rotNode->rotation[0] = bodyState->torsoAngle[1]; rotNode->rotation[1] = bodyState->torsoAngle[2]; rotNode->rotation[2] = bodyState->torsoAngle[0]; + if (plrIdx != 0) { + // only interpolate angles for the local player + vec3s_copy(rotNode->prevRotation, rotNode->rotation); + rotNode->prevTimestamp = gGlobalTimer; + } // update torso position in bodyState get_pos_from_transform_mtx(bodyState->torsoPos, *curTransform, *gCurGraphNodeCamera->matrixPtr); } @@ -429,7 +435,8 @@ Gfx* geo_mario_tilt_torso(s32 callContext, struct GraphNode* node, Mat4* mtx) { */ Gfx* geo_mario_head_rotation(s32 callContext, struct GraphNode* node, UNUSED Mat4* c) { struct GraphNodeGenerated* asGenerated = (struct GraphNodeGenerated*) node; - struct MarioBodyState* bodyState = geo_get_body_state(); + u8 plrIdx = geo_get_processing_object_index(); + struct MarioBodyState* bodyState = &gBodyStates[plrIdx]; s32 action = bodyState->action; if (callContext == GEO_CONTEXT_RENDER) { @@ -449,6 +456,12 @@ Gfx* geo_mario_head_rotation(s32 callContext, struct GraphNode* node, UNUSED Mat vec3s_set(bodyState->headAngle, 0, 0, 0); vec3s_set(rotNode->rotation, 0, 0, 0); } + + if (plrIdx != 0) { + // only interpolate angles for the local player + vec3s_copy(rotNode->prevRotation, rotNode->rotation); + rotNode->prevTimestamp = gGlobalTimer; + } } return NULL; } From e0a07a41b81f17c3ee5e5738e82e8b5d47d323d2 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 5 Apr 2021 04:21:23 +0300 Subject: [PATCH 07/14] everyone except host is luigi --- src/game/mario.c | 2 +- src/pc/network/packets/packet_player.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/mario.c b/src/game/mario.c index 0e10061a..953f0ccf 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -2123,7 +2123,7 @@ static void init_single_mario(struct MarioState* m) { } // set mario/luigi model - enum CharacterType characterType = (gNetworkPlayers[0].globalIndex == 1) ? CT_LUIGI : CT_MARIO; + enum CharacterType characterType = (globalIndex == 0) ? CT_MARIO : CT_LUIGI; m->character = &gCharacters[characterType]; m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[m->character->modelId]; } diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c index 768be58a..28ad72be 100644 --- a/src/pc/network/packets/packet_player.c +++ b/src/pc/network/packets/packet_player.c @@ -345,7 +345,7 @@ void network_receive_player(struct Packet* p) { } // set model - enum CharacterType characterType = (np->globalIndex == 1) ? CT_LUIGI : CT_MARIO; + enum CharacterType characterType = (np->globalIndex == 0) ? CT_MARIO : CT_LUIGI; m->character = &gCharacters[characterType]; m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[m->character->modelId]; } From 66c11d93296677e1da14de491199f4b98312cc84 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 6 Apr 2021 00:18:04 +0300 Subject: [PATCH 08/14] added new GBI command: G_COPYMEM exclusively for copying lights around for now; required for my retarded model color implementation --- include/PR/gbi.h | 32 ++++++++++++++++++++++++++++++++ src/pc/gfx/gfx_pc.c | 23 ++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/include/PR/gbi.h b/include/PR/gbi.h index bd981be8..dd1bb440 100644 --- a/include/PR/gbi.h +++ b/include/PR/gbi.h @@ -118,6 +118,11 @@ #define G_SPECIAL_2 0xd4 #define G_SPECIAL_3 0xd3 +#ifdef F3DEX_GBI_2E +/* extended commands */ +#define G_COPYMEM 0xd2 +#endif + #define G_VTX 0x01 #define G_MODIFYVTX 0x02 #define G_CULLDL 0x03 @@ -1790,6 +1795,22 @@ typedef union { (uintptr_t)(adrs) \ }} +#ifdef F3DEX_GBI_2E +#define gCopyMemEXT(pkt, c, idx, dst, src, len) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + _g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL((src)/8,16,8)| \ + _SHIFTL((dst)/8,8,8)|_SHIFTL((idx),0,8)); \ + _g->words.w1 = (uintptr_t)(((len)-1)/8); \ +} +#define gsCopyMemEXT(c, idx, dst, src, len) \ +{{ \ + (_SHIFTL((c),24,8)|_SHIFTL((src)/8,16,8)| \ + _SHIFTL((dst)/8,8,8)|_SHIFTL((idx),0,8)), \ + (uintptr_t)(((len)-1)/8) \ +}} +#endif + #define gSPNoOp(pkt) gDma0p(pkt, G_SPNOOP, 0, 0) #define gsSPNoOp() gsDma0p(G_SPNOOP, 0, 0) @@ -2541,6 +2562,17 @@ typedef union { gsDma1p( G_MOVEMEM, l, sizeof(Light),((n)-1)*2+G_MV_L0) #endif /* F3DEX_GBI_2 */ +/* + * EXTENDED COMMAND + * Copy one light's parameters to the other. + */ +#ifdef F3DEX_GBI_2E +# define gSPCopyLightEXT(pkt, dst, src) \ + gCopyMemEXT((pkt),G_COPYMEM,G_MV_LIGHT,(dst)*24+24,(src)*24+24,sizeof(Light)) +# define gsSPCopyLightEXT(dst, src) \ + gsCopyMemEXT( G_COPYMEM,G_MV_LIGHT,(dst)*24+24,(src)*24+24,sizeof(Light)) +#endif + /* * gSPLightColor changes color of light without recalculating light direction * col is a 32 bit word with r,g,b,a (alpha is ignored) diff --git a/src/pc/gfx/gfx_pc.c b/src/pc/gfx/gfx_pc.c index a78f2ffd..876d9f54 100644 --- a/src/pc/gfx/gfx_pc.c +++ b/src/pc/gfx/gfx_pc.c @@ -47,7 +47,7 @@ #define RATIO_Y (gfx_current_dimensions.height / (2.0f * HALF_SCREEN_HEIGHT)) #define MAX_BUFFERED 256 -#define MAX_LIGHTS 2 +#define MAX_LIGHTS 8 #define MAX_VERTICES 64 #ifdef EXTERNAL_DATA @@ -1123,6 +1123,10 @@ static void gfx_sp_movemem(uint8_t index, uint8_t offset, const void* data) { case G_MV_L0: case G_MV_L1: case G_MV_L2: + case G_MV_L3: + case G_MV_L4: + case G_MV_L5: + case G_MV_L6: // NOTE: reads out of bounds if it is an ambient light memcpy(rsp.current_lights + (index - G_MV_L0) / 2, data, sizeof(Light_t)); break; @@ -1130,6 +1134,18 @@ static void gfx_sp_movemem(uint8_t index, uint8_t offset, const void* data) { } } +#ifdef F3DEX_GBI_2E +static void gfx_sp_copymem(uint8_t idx, uint8_t dstofs, uint8_t srcofs, uint8_t words) { + if (idx == G_MV_LIGHT) { + const int srcidx = srcofs / 24 - 2; + const int dstidx = dstofs / 24 - 2; + if (srcidx <= MAX_LIGHTS && dstidx <= MAX_LIGHTS) { + memcpy(rsp.current_lights + dstidx, rsp.current_lights + srcidx, sizeof(Light_t)); + } + } +} +#endif + static void gfx_sp_moveword(uint8_t index, uint16_t offset, uint32_t data) { switch (index) { case G_MW_NUMLIGHT: @@ -1538,6 +1554,11 @@ static void gfx_run_dl(Gfx* cmd) { gfx_sp_moveword(C0(0, 8), C0(8, 16), cmd->words.w1); #endif break; +#ifdef F3DEX_GBI_2E + case (uint8_t)G_COPYMEM: + gfx_sp_copymem(C0(0, 8), C0(8, 8) * 8, C0(16, 8) * 8, C1(0, 8)); + break; +#endif case (uint8_t)G_TEXTURE: #ifdef F3DEX_GBI_2 gfx_sp_texture(C1(16, 16), C1(0, 16), C0(11, 3), C0(8, 3), C0(1, 7)); From 3317154ec2d649e90a71c8047861685502ac2e36 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 6 Apr 2021 00:21:51 +0300 Subject: [PATCH 09/14] implement changeable model colors in a very dumb way: the custom colors are set for lights 3, 4, 5, 6 in a GEO_ASM callback, then copied to lights 1, 2 using gsSPCopyLightEXT --- actors/luigi/geo.inc.c | 1 + actors/luigi/model.inc.c | 6 ++- actors/mario/geo.inc.c | 1 + actors/mario/model.inc.c | 84 ++++++++++++++++++++-------------------- src/game/mario_misc.c | 58 ++++++++++++++++++++++++++- src/game/mario_misc.h | 2 + 6 files changed, 107 insertions(+), 45 deletions(-) diff --git a/actors/luigi/geo.inc.c b/actors/luigi/geo.inc.c index aa714c0b..e11583e9 100644 --- a/actors/luigi/geo.inc.c +++ b/actors/luigi/geo.inc.c @@ -788,6 +788,7 @@ const GeoLayout luigi_geo[] = { GEO_OPEN_NODE(), GEO_SCALE(0, 17202), GEO_OPEN_NODE(), + GEO_ASM(0, geo_mario_set_player_colors), GEO_ASM(0, geo_mirror_mario_backface_culling), GEO_ASM(0, geo_mirror_mario_set_alpha), GEO_SWITCH_CASE(0, geo_switch_mario_stand_run), diff --git a/actors/luigi/model.inc.c b/actors/luigi/model.inc.c index dac16ab4..e3a2f823 100644 --- a/actors/luigi/model.inc.c +++ b/actors/luigi/model.inc.c @@ -3225,7 +3225,8 @@ Gfx mat_luigi_body[] = { gsDPPipeSync(), gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 0, 0, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0), gsDPSetTileSize(0, 0, 0, 124, 124), - gsSPSetLights1(luigi_body_lights), + gsSPCopyLightEXT(1, 3), // gsSPSetLights1(luigi_body_lights) + gsSPCopyLightEXT(2, 4), // gsSPEndDisplayList(), }; @@ -3265,7 +3266,8 @@ Gfx mat_luigi_cap[] = { gsDPPipeSync(), gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 0, 0, 0, G_TX_CLAMP | G_TX_NOMIRROR, 5, 0, G_TX_CLAMP | G_TX_NOMIRROR, 5, 0), gsDPSetTileSize(0, 0, 0, 124, 124), - gsSPSetLights1(luigi_cap_lights), + gsSPCopyLightEXT(1, 5), // gsSPSetLights1(luigi_cap_lights) + gsSPCopyLightEXT(2, 6), // gsSPEndDisplayList(), }; diff --git a/actors/mario/geo.inc.c b/actors/mario/geo.inc.c index 736d31f0..fce1ac75 100644 --- a/actors/mario/geo.inc.c +++ b/actors/mario/geo.inc.c @@ -1811,6 +1811,7 @@ const GeoLayout mario_geo[] = { GEO_OPEN_NODE(), GEO_SCALE(0x00, 16384), GEO_OPEN_NODE(), + GEO_ASM(0, geo_mario_set_player_colors), GEO_ASM(0, geo_mirror_mario_backface_culling), GEO_ASM(0, geo_mirror_mario_set_alpha), GEO_SWITCH_CASE(0, geo_switch_mario_stand_run), diff --git a/actors/mario/model.inc.c b/actors/mario/model.inc.c index 9d39ba24..1d9c8df7 100644 --- a/actors/mario/model.inc.c +++ b/actors/mario/model.inc.c @@ -381,8 +381,8 @@ const Gfx mario_butt_dl[] = { const Gfx mario_butt[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA), - gsSPLight(&mario_blue_lights_group.l, 1), - gsSPLight(&mario_blue_lights_group.a, 2), + gsSPCopyLightEXT(1, 3), // gsSPLight(&mario_blue_lights_group.l, 1), + gsSPCopyLightEXT(2, 4), // gsSPLight(&mario_blue_lights_group.a, 2), gsSPDisplayList(mario_butt_dl), gsSPEndDisplayList(), }; @@ -499,8 +499,8 @@ const Gfx mario_left_arm_shared_dl[] = { // 0x0400D1D8 - 0x0400D1F8 const Gfx mario_left_arm[] = { - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_left_arm_shared_dl), gsSPEndDisplayList(), }; @@ -760,8 +760,8 @@ const Gfx mario_right_arm_shared_dl[] = { // 0x0400DDE8 - 0x0400DE08 const Gfx mario_right_arm[] = { - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_right_arm_shared_dl), gsSPEndDisplayList(), }; @@ -979,8 +979,8 @@ const Gfx mario_left_thigh_dl[] = { const Gfx mario_left_thigh[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA), - gsSPLight(&mario_blue_lights_group.l, 1), - gsSPLight(&mario_blue_lights_group.a, 2), + gsSPCopyLightEXT(1, 3), // gsSPLight(&mario_blue_lights_group.l, 1), + gsSPCopyLightEXT(2, 4), // gsSPLight(&mario_blue_lights_group.a, 2), gsSPDisplayList(mario_left_thigh_dl), gsSPEndDisplayList(), }; @@ -1160,8 +1160,8 @@ const Gfx mario_right_thigh_shared_dl[] = { // 0x0400EFB8 - 0x0400EFD8 const Gfx mario_right_thigh[] = { - gsSPLight(&mario_blue_lights_group.l, 1), - gsSPLight(&mario_blue_lights_group.a, 2), + gsSPCopyLightEXT(1, 3), // gsSPLight(&mario_blue_lights_group.l, 1), + gsSPCopyLightEXT(2, 4), // gsSPLight(&mario_blue_lights_group.a, 2), gsSPDisplayList(mario_right_thigh_shared_dl), gsSPEndDisplayList(), }; @@ -1589,8 +1589,8 @@ const Gfx mario_tshirt_shared_dl[] = { // 0x04010348 - 0x04010370 const Gfx mario_torso_dl[] = { gsSPDisplayList(mario_pants_overalls_shared_dl), - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_tshirt_shared_dl), gsSPEndDisplayList(), }; @@ -2080,8 +2080,8 @@ const Gfx mario_face_back_hair_cap_on_dl[] = { // 0x04011960 - 0x040119A0 const Gfx mario_face_cap_on_dl[] = { gsSPDisplayList(mario_face_part_cap_on_dl), - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_face_cap_dl), gsSPLight(&mario_brown2_lights_group.l, 1), gsSPLight(&mario_brown2_lights_group.a, 2), @@ -3270,8 +3270,8 @@ const Gfx mario_medium_poly_butt_dl[] = { const Gfx mario_medium_poly_butt[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA), - gsSPLight(&mario_blue_lights_group.l, 1), - gsSPLight(&mario_blue_lights_group.a, 2), + gsSPCopyLightEXT(1, 3), // gsSPLight(&mario_blue_lights_group.l, 1), + gsSPCopyLightEXT(2, 4), // gsSPLight(&mario_blue_lights_group.a, 2), gsSPDisplayList(mario_medium_poly_butt_dl), gsSPEndDisplayList(), }; @@ -3322,8 +3322,8 @@ const Gfx mario_medium_poly_left_arm_shared_dl[] = { // 0x04014840 - 0x04014860 const Gfx mario_medium_poly_left_arm[] = { - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_medium_poly_left_arm_shared_dl), gsSPEndDisplayList(), }; @@ -3483,8 +3483,8 @@ const Gfx mario_medium_poly_right_arm_shared_dl[] = { // 0x04014F40 - 0x04014F60 const Gfx mario_medium_poly_right_arm[] = { - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_medium_poly_right_arm_shared_dl), gsSPEndDisplayList(), }; @@ -3659,8 +3659,8 @@ const Gfx mario_medium_poly_left_thigh_dl[] = { const Gfx mario_medium_poly_left_thigh[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA), - gsSPLight(&mario_blue_lights_group.l, 1), - gsSPLight(&mario_blue_lights_group.a, 2), + gsSPCopyLightEXT(1, 3), // gsSPLight(&mario_blue_lights_group.l, 1), + gsSPCopyLightEXT(2, 4), // gsSPLight(&mario_blue_lights_group.a, 2), gsSPDisplayList(mario_medium_poly_left_thigh_dl), gsSPEndDisplayList(), }; @@ -3808,8 +3808,8 @@ const Gfx mario_medium_poly_right_thigh_shared_dl[] = { // 0x04015D00 - 0x04015D20 const Gfx mario_medium_poly_right_thigh[] = { - gsSPLight(&mario_blue_lights_group.l, 1), - gsSPLight(&mario_blue_lights_group.a, 2), + gsSPCopyLightEXT(1, 3), // gsSPLight(&mario_blue_lights_group.l, 1), + gsSPCopyLightEXT(2, 4), // gsSPLight(&mario_blue_lights_group.a, 2), gsSPDisplayList(mario_medium_poly_right_thigh_shared_dl), gsSPEndDisplayList(), }; @@ -4081,8 +4081,8 @@ const Gfx mario_medium_poly_tshirt_shared_dl[] = { // 0x040168A0 - 0x040168C8 const Gfx mario_medium_poly_torso_dl[] = { gsSPDisplayList(mario_medium_poly_pants_overalls_shared_dl), - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_medium_poly_tshirt_shared_dl), gsSPEndDisplayList(), }; @@ -4149,8 +4149,8 @@ const Gfx mario_low_poly_butt_dl[] = { const Gfx mario_low_poly_butt[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA), - gsSPLight(&mario_blue_lights_group.l, 1), - gsSPLight(&mario_blue_lights_group.a, 2), + gsSPCopyLightEXT(1, 3), // gsSPLight(&mario_blue_lights_group.l, 1), + gsSPCopyLightEXT(2, 4), // gsSPLight(&mario_blue_lights_group.a, 2), gsSPDisplayList(mario_low_poly_butt_dl), gsSPEndDisplayList(), }; @@ -4196,8 +4196,8 @@ const Gfx mario_low_poly_left_arm_shared_dl[] = { // 0x04016C70 - 0x04016C90 const Gfx mario_low_poly_left_arm[] = { - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_low_poly_left_arm_shared_dl), gsSPEndDisplayList(), }; @@ -4287,8 +4287,8 @@ const Gfx mario_low_poly_right_arm_shared_dl[] = { // 0x04016FB0 - 0x04016FD0 const Gfx mario_low_poly_right_arm[] = { - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_low_poly_right_arm_shared_dl), gsSPEndDisplayList(), }; @@ -4394,8 +4394,8 @@ const Gfx mario_low_poly_left_thigh_dl[] = { const Gfx mario_low_poly_left_thigh[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA), - gsSPLight(&mario_blue_lights_group.l, 1), - gsSPLight(&mario_blue_lights_group.a, 2), + gsSPCopyLightEXT(1, 3), // gsSPLight(&mario_blue_lights_group.l, 1), + gsSPCopyLightEXT(2, 4), // gsSPLight(&mario_blue_lights_group.a, 2), gsSPDisplayList(mario_low_poly_left_thigh_dl), gsSPEndDisplayList(), }; @@ -4513,8 +4513,8 @@ const Gfx mario_low_poly_right_thigh_shared_dl[] = { // 0x04017818 - 0x04017838 const Gfx mario_low_poly_right_thigh[] = { - gsSPLight(&mario_blue_lights_group.l, 1), - gsSPLight(&mario_blue_lights_group.a, 2), + gsSPCopyLightEXT(1, 3), // gsSPLight(&mario_blue_lights_group.l, 1), + gsSPCopyLightEXT(2, 4), // gsSPLight(&mario_blue_lights_group.a, 2), gsSPDisplayList(mario_low_poly_right_thigh_shared_dl), gsSPEndDisplayList(), }; @@ -4684,8 +4684,8 @@ const Gfx mario_low_poly_tshirt_shared_dl[] = { // 0x04017E78 - 0x04017EA0 const Gfx mario_low_poly_torso_dl[] = { gsSPDisplayList(mario_low_poly_pants_overalls_shared_dl), - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_low_poly_tshirt_shared_dl), gsSPEndDisplayList(), }; @@ -4854,8 +4854,8 @@ const Gfx mario_low_poly_face_back_hair_cap_on_dl[] = { // 0x04018420 - 0x04018460 const Gfx mario_low_poly_face_cap_on_dl[] = { gsSPDisplayList(mario_low_poly_face_part_cap_on_dl), - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_low_poly_face_cap_dl), gsSPLight(&mario_brown2_lights_group.l, 1), gsSPLight(&mario_brown2_lights_group.a, 2), @@ -6625,8 +6625,8 @@ const Gfx mario_cap_unused_dl[] = { gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, mario_texture_m_logo), gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 32 * 32 - 1, CALC_DXT(32, G_IM_SIZ_16b_BYTES)), - gsSPLight(&mario_red_lights_group.l, 1), - gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_cap_unused_m_logo_dl), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF), gsDPPipeSync(), diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index 5909d1d9..d4661926 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -23,6 +23,7 @@ #include "save_file.h" #include "skybox.h" #include "sound_init.h" +#include "pc/network/network.h" #define TOAD_STAR_1_REQUIREMENT 12 #define TOAD_STAR_2_REQUIREMENT 25 @@ -51,6 +52,11 @@ enum UnlockDoorStarStates { UNLOCK_DOOR_STAR_DONE }; +struct PlayerColor { + Lights1 pants; + Lights1 shirt; +}; + /** * The eye texture on succesive frames of Mario's blink animation. * He intentionally blinks twice each time. @@ -71,6 +77,18 @@ static s8 gMarioAttackScaleAnimation[3 * 6] = { struct MarioBodyState gBodyStates[MAX_PLAYERS]; struct GraphNodeObject gMirrorMario[MAX_PLAYERS]; // copy of Mario's geo node for drawing mirror Mario +struct PlayerColor gPlayerColors[MAX_PLAYERS] = { + // default mario + { + gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x28, 0x28, 0x28), + gdSPDefLights1(0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x28, 0x28, 0x28), + }, + // default luigi + { + gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xfe, 0x28, 0x28, 0x28), + gdSPDefLights1(0x00, 0x4c, 0x00, 0x00, 0x98, 0x00, 0x28, 0x28, 0x28), + }, +}; // This whole file is weirdly organized. It has to be the same file due // to rodata boundaries and function aligns, which means the programmer @@ -78,6 +96,20 @@ struct GraphNodeObject gMirrorMario[MAX_PLAYERS]; // copy of Mario's geo node f // (message NPC related things, the Mario head geo, and Mario geo // functions) +/** + * Set the Light1 struct from player colors. + * The 4th component is the shade factor (difference between ambient and diffuse), + * usually set to 1. + */ +void set_player_colors(u8 globalIndex, const u8 pants[4], const u8 shirt[4]) { + const u8 pAmb[3] = { pants[0] >> pants[4], pants[1] >> pants[4], pants[2] >> pants[4] }; + const u8 sAmb[3] = { shirt[0] >> shirt[4], shirt[1] >> shirt[4], shirt[2] >> shirt[4] }; + gPlayerColors[globalIndex].pants = + (Lights1) gdSPDefLights1(pAmb[0], pAmb[1], pAmb[2], pants[0], pants[1], pants[2], 0x28, 0x28, 0x28); + gPlayerColors[globalIndex].shirt = + (Lights1) gdSPDefLights1(sAmb[0], sAmb[1], sAmb[2], shirt[0], shirt[1], shirt[2], 0x28, 0x28, 0x28); +} + /** * Geo node script that draws Mario's head on the title screen. */ @@ -720,4 +752,28 @@ Gfx* geo_mirror_mario_backface_culling(s32 callContext, struct GraphNode* node, asGenerated->fnNode.node.flags = (asGenerated->fnNode.node.flags & 0xFF) | (LAYER_OPAQUE << 8); } return gfx; -} \ No newline at end of file +} + +/** + * Generate DL that sets player color depending on player number. + */ +Gfx* geo_mario_set_player_colors(s32 callContext, struct GraphNode* node, UNUSED Mat4* c) { + struct GraphNodeGenerated* asGenerated = (struct GraphNodeGenerated*) node; + Gfx* gfx = NULL; + u8 index = geo_get_processing_object_index(); + u8 colorIndex = gNetworkPlayers[index].globalIndex; + struct MarioBodyState* bodyState = &gBodyStates[index]; + + if (callContext == GEO_CONTEXT_RENDER) { + gfx = alloc_display_list(5 * sizeof(*gfx)); + gSPLight(gfx + 0, &gPlayerColors[colorIndex].pants.l, 3); + gSPLight(gfx + 1, &gPlayerColors[colorIndex].pants.a, 4); + gSPLight(gfx + 2, &gPlayerColors[colorIndex].shirt.l, 5); + gSPLight(gfx + 3, &gPlayerColors[colorIndex].shirt.a, 6); + gSPEndDisplayList(gfx + 4); + // put on transparent if vanish effect, opaque otherwise + const u32 layer = ((bodyState->modelState >> 8) & 1) ? LAYER_TRANSPARENT : LAYER_OPAQUE; + asGenerated->fnNode.node.flags = (asGenerated->fnNode.node.flags & 0xFF) | (layer << 8); + } + return gfx; +} diff --git a/src/game/mario_misc.h b/src/game/mario_misc.h index 9a1f956f..37ca3361 100644 --- a/src/game/mario_misc.h +++ b/src/game/mario_misc.h @@ -9,6 +9,7 @@ extern struct GraphNodeObject gMirrorMario[MAX_PLAYERS]; extern struct MarioBodyState gBodyStates[MAX_PLAYERS]; +void set_player_colors(u8 globalIndex, const u8 pants[4], const u8 shirt[4]); Gfx *geo_draw_mario_head_goddard(s32 callContext, struct GraphNode *node, Mat4 *c); void bhv_toad_message_loop(void); void bhv_toad_message_init(void); @@ -27,5 +28,6 @@ Gfx *geo_mario_rotate_wing_cap_wings(s32 callContext, struct GraphNode *node, UN Gfx *geo_switch_mario_hand_grab_pos(s32 callContext, struct GraphNode *b, Mat4 *mtx); Gfx *geo_render_mirror_mario(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c); Gfx *geo_mirror_mario_backface_culling(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c); +Gfx *geo_mario_set_player_colors(s32 callContext, struct GraphNode *node, UNUSED Mat4 *c); #endif // MARIO_MISC_H From c406222342c36ab07e62ce696962a98f0777ee93 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 6 Apr 2021 02:30:37 +0300 Subject: [PATCH 10/14] colorize chat messages with player color --- src/game/chat.c | 36 +++++++++++++++++++++----- src/game/chat.h | 1 + src/game/mario_misc.c | 22 +++++++++++++--- src/game/mario_misc.h | 4 ++- src/pc/network/network_player.c | 5 ++-- src/pc/network/packets/packet.h | 2 +- src/pc/network/packets/packet_chat.c | 7 +++-- src/pc/network/packets/packet_player.c | 3 ++- 8 files changed, 63 insertions(+), 17 deletions(-) diff --git a/src/game/chat.c b/src/game/chat.c index bfca1066..1f346237 100644 --- a/src/game/chat.c +++ b/src/game/chat.c @@ -5,6 +5,7 @@ #include "chat.h" #include "game_init.h" #include "ingame_menu.h" +#include "mario_misc.h" #include "segment2.h" #include "gfx_dimensions.h" #include "config.h" @@ -23,6 +24,7 @@ struct ChatMessage { u8 dialog[CHAT_DIALOG_MAX]; enum ChatMessageType type; u16 life; + u8 color[3]; }; static char inputMessage[CHAT_DIALOG_MAX] = { 0 }; @@ -70,21 +72,34 @@ static void render_chat_message(struct ChatMessage* chatMessage, u8 index) { u8 textR, textG, textB; switch (chatMessage->type) { - case CMT_LOCAL: textR = 200; textG = 200; textB = 255; break; - case CMT_INPUT: textR = 0; textG = 0; textB = 0; break; - case CMT_SYSTEM: textR = 255; textG = 255; textB = 190; break; - default: textR = 255; textG = 255; textB = 255; + case CMT_LOCAL: textR = 200; textG = 200; textB = 255; break; + case CMT_INPUT: textR = 0; textG = 0; textB = 0; break; + case CMT_SYSTEM: textR = 255; textG = 255; textB = 190; break; + default: textR = 255; textG = 255; textB = 255; break; } gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + gDPSetEnvColor(gDisplayListHead++, textR, textG, textB, 255 * alphaScale); print_generic_string(CHAT_X, CHAT_Y, chatMessage->dialog); + + if (chatMessage->type == CMT_REMOTE || chatMessage->type == CMT_SYSTEM) { + // if it's someone else's message, highlight the icon with their color + u8 starR = chatMessage->color[0]; + u8 starG = chatMessage->color[1]; + u8 starB = chatMessage->color[2]; + gDPSetEnvColor(gDisplayListHead++, starR, starG, starB, 255 * alphaScale); + create_dl_translation_matrix(MENU_MTX_PUSH, CHAT_X, CHAT_Y, 0.0f); + render_generic_char(chatMessage->dialog[0]); + gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); + } + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); } -void chat_add_message(char* ascii, enum ChatMessageType chatMessageType) { +void chat_add_message_ext(char* ascii, enum ChatMessageType chatMessageType, const u8 color[3]) { u8 character = '?'; switch (chatMessageType) { case CMT_INPUT: @@ -98,10 +113,18 @@ void chat_add_message(char* ascii, enum ChatMessageType chatMessageType) { str_ascii_to_dialog(ascii, &msg->dialog[2], MIN(strlen(ascii), CHAT_DIALOG_MAX - 3)); msg->life = (sSelectedFileNum != 0) ? CHAT_LIFE_MAX : CHAT_LIFE_MAX / 3; msg->type = chatMessageType; + msg->color[0] = color[0]; + msg->color[1] = color[1]; + msg->color[2] = color[2]; onMessageIndex = (onMessageIndex + 1) % CHAT_MESSAGES_MAX; play_sound((msg->type == CMT_LOCAL) ? SOUND_MENU_MESSAGE_DISAPPEAR : SOUND_MENU_MESSAGE_APPEAR, gDefaultSoundArgs); } +void chat_add_message(char* ascii, enum ChatMessageType chatMessageType) { + const u8 defaultColor[3] = { 255, 255, 255 }; + chat_add_message_ext(ascii, chatMessageType, defaultColor); +} + static void chat_stop_input(void) { sInChatInput = FALSE; keyboard_stop_text_input(); @@ -112,7 +135,8 @@ static void chat_send_input(void) { keyboard_stop_text_input(); if (strlen(gTextInput) == 0) { return; } chat_add_message(gTextInput, CMT_LOCAL); - network_send_chat(gTextInput); + // our message has the same color as our shirt + network_send_chat(gTextInput, get_player_color(gNetworkPlayerLocal->globalIndex, 0)); } void chat_start_input(void) { diff --git a/src/game/chat.h b/src/game/chat.h index e1dfd0a1..4e9034fd 100644 --- a/src/game/chat.h +++ b/src/game/chat.h @@ -10,6 +10,7 @@ enum ChatMessageType { void render_chat(void); void chat_add_message(char* ascii, enum ChatMessageType chatMessageType); +void chat_add_message_ext(char* ascii, enum ChatMessageType chatMessageType, const u8 color[3]); void chat_start_input(void); #endif \ No newline at end of file diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index d4661926..4c9b04de 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -53,8 +53,8 @@ enum UnlockDoorStarStates { }; struct PlayerColor { - Lights1 pants; Lights1 shirt; + Lights1 pants; }; /** @@ -80,13 +80,13 @@ struct GraphNodeObject gMirrorMario[MAX_PLAYERS]; // copy of Mario's geo node f struct PlayerColor gPlayerColors[MAX_PLAYERS] = { // default mario { - gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x28, 0x28, 0x28), gdSPDefLights1(0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x28, 0x28, 0x28), + gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x28, 0x28, 0x28), }, // default luigi { - gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xfe, 0x28, 0x28, 0x28), gdSPDefLights1(0x00, 0x4c, 0x00, 0x00, 0x98, 0x00, 0x28, 0x28, 0x28), + gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xfe, 0x28, 0x28, 0x28), }, }; @@ -101,7 +101,7 @@ struct PlayerColor gPlayerColors[MAX_PLAYERS] = { * The 4th component is the shade factor (difference between ambient and diffuse), * usually set to 1. */ -void set_player_colors(u8 globalIndex, const u8 pants[4], const u8 shirt[4]) { +void set_player_colors(u8 globalIndex, const u8 shirt[4], const u8 pants[4]) { const u8 pAmb[3] = { pants[0] >> pants[4], pants[1] >> pants[4], pants[2] >> pants[4] }; const u8 sAmb[3] = { shirt[0] >> shirt[4], shirt[1] >> shirt[4], shirt[2] >> shirt[4] }; gPlayerColors[globalIndex].pants = @@ -110,6 +110,20 @@ void set_player_colors(u8 globalIndex, const u8 pants[4], const u8 shirt[4]) { (Lights1) gdSPDefLights1(sAmb[0], sAmb[1], sAmb[2], shirt[0], shirt[1], shirt[2], 0x28, 0x28, 0x28); } +/** + * Return the specified color for player globalIndex. + * 0 = shirt, 1 = pants + * Returns RGB, not RGBA! + */ +u8 *get_player_color(u8 globalIndex, const int which) { + if (globalIndex >= MAX_PLAYERS) + globalIndex = 0; + if (which == 0) + return gPlayerColors[globalIndex].shirt.l[0].l.col; + else + return gPlayerColors[globalIndex].pants.l[0].l.col; +} + /** * Geo node script that draws Mario's head on the title screen. */ diff --git a/src/game/mario_misc.h b/src/game/mario_misc.h index 37ca3361..3c4a76b6 100644 --- a/src/game/mario_misc.h +++ b/src/game/mario_misc.h @@ -9,7 +9,9 @@ extern struct GraphNodeObject gMirrorMario[MAX_PLAYERS]; extern struct MarioBodyState gBodyStates[MAX_PLAYERS]; -void set_player_colors(u8 globalIndex, const u8 pants[4], const u8 shirt[4]); +void set_player_colors(u8 globalIndex, const u8 shirt[4], const u8 pants[4]); +u8 *get_player_color(u8 globalIndex, const int which); + Gfx *geo_draw_mario_head_goddard(s32 callContext, struct GraphNode *node, Mat4 *c); void bhv_toad_message_loop(void); void bhv_toad_message_init(void); diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c index 7c85fdbb..8c8716ba 100644 --- a/src/pc/network/network_player.c +++ b/src/pc/network/network_player.c @@ -1,6 +1,7 @@ #include #include "network_player.h" #include "game/chat.h" +#include "game/mario_misc.h" #include "pc/debuglog.h" struct NetworkPlayer gNetworkPlayers[MAX_PLAYERS] = { 0 }; @@ -105,7 +106,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) { gNetworkSystem->save_id(i); for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; } if (type == NPT_SERVER) { gNetworkPlayerServer = np; } - else { chat_add_message("player connected", CMT_SYSTEM); } + else { chat_add_message_ext("player connected", CMT_SYSTEM, get_player_color(np->globalIndex, 0)); } LOG_INFO("player connected, local %d, global %d", i, np->globalIndex); extern s16 sCurrPlayMode; if (gNetworkType == NT_SERVER && sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) { @@ -142,7 +143,7 @@ u8 network_player_disconnected(u8 globalIndex) { gNetworkSystem->clear_id(i); for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; } LOG_INFO("player disconnected, local %d, global %d", i, globalIndex); - chat_add_message("player disconnected", CMT_SYSTEM); + chat_add_message_ext("player disconnected", CMT_SYSTEM, get_player_color(globalIndex, 0)); return i; } return UNKNOWN_GLOBAL_INDEX; diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index 2f2835f9..77734d2d 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -141,7 +141,7 @@ void network_send_custom(u8 customId, bool reliable, bool levelAreaMustMatch, vo void network_receive_custom(struct Packet* p); // packet_chat.c -void network_send_chat(char* message); +void network_send_chat(char* message, u8 rgb[3]); void network_receive_chat(struct Packet* p); // packet_kick.c diff --git a/src/pc/network/packets/packet_chat.c b/src/pc/network/packets/packet_chat.c index 59b0a581..ed98c6dc 100644 --- a/src/pc/network/packets/packet_chat.c +++ b/src/pc/network/packets/packet_chat.c @@ -17,10 +17,11 @@ static void print_sync_object_table(void) { } #endif -void network_send_chat(char* message) { +void network_send_chat(char* message, u8 rgb[3]) { u16 messageLength = strlen(message); struct Packet p; packet_init(&p, PACKET_CHAT, true, false); + packet_write(&p, rgb, 3 * sizeof(u8)); packet_write(&p, &messageLength, sizeof(u16)); packet_write(&p, message, messageLength * sizeof(u8)); network_send(&p); @@ -34,13 +35,15 @@ void network_send_chat(char* message) { void network_receive_chat(struct Packet* p) { u16 remoteMessageLength = 0; char remoteMessage[255] = { 0 }; + u8 rgb[3] = { 255, 255, 255}; + packet_read(p, rgb, 3 * sizeof(u8)); packet_read(p, &remoteMessageLength, sizeof(u16)); if (remoteMessageLength > 255) { remoteMessageLength = 254; } packet_read(p, &remoteMessage, remoteMessageLength * sizeof(u8)); // add the message - chat_add_message(remoteMessage, CMT_REMOTE); + chat_add_message_ext(remoteMessage, CMT_REMOTE, rgb); LOG_INFO("rx chat: %s", remoteMessage); #ifdef DEVELOPMENT diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c index 28ad72be..1f510178 100644 --- a/src/pc/network/packets/packet_player.c +++ b/src/pc/network/packets/packet_player.c @@ -10,6 +10,7 @@ #include "engine/surface_collision.h" #include "game/object_list_processor.h" #include "game/chat.h" +#include "game/mario_misc.h" #include "pc/configfile.h" #pragma pack(1) @@ -336,7 +337,7 @@ void network_receive_player(struct Packet* p) { // inform of player death if (oldData.action != ACT_BUBBLED && data.action == ACT_BUBBLED) { - chat_add_message("player died", CMT_SYSTEM); + chat_add_message_ext("player died", CMT_SYSTEM, get_player_color(globalIndex, 0)); } // action changed, reset timer From 06f20111288e9423a787a9aa6244a7bf41996560 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 6 Apr 2021 02:30:54 +0300 Subject: [PATCH 11/14] bump unstable version number --- src/pc/network/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pc/network/version.h b/src/pc/network/version.h index 573456d6..b65d1360 100644 --- a/src/pc/network/version.h +++ b/src/pc/network/version.h @@ -2,7 +2,7 @@ #define VERSION_H #define UNSTABLE_BRANCH -#define VERSION_NUMBER 2 +#define VERSION_NUMBER 3 #define MAX_VERSION_LENGTH 10 char* get_version(void); From 5c8e4b293cede459436f9d561c4533ffdd25124a Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 6 Apr 2021 02:32:06 +0300 Subject: [PATCH 12/14] bump MAX_PLAYERS to 16 --- include/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/types.h b/include/types.h index 5c08c8f2..41195c5f 100644 --- a/include/types.h +++ b/include/types.h @@ -392,7 +392,7 @@ struct MarioState // HOWEVER, simply increasing this to 3 will not magically work // many things will have to be overhauled! #ifdef UNSTABLE_BRANCH -#define MAX_PLAYERS 4 +#define MAX_PLAYERS 16 #else #define MAX_PLAYERS 2 #endif From d24798d26f73207ca6149228e8782f51ba16ac85 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 6 Apr 2021 18:08:41 +0300 Subject: [PATCH 13/14] add more player colors --- src/game/mario_misc.c | 52 +++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index 4c9b04de..a62abf3d 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -77,19 +77,41 @@ static s8 gMarioAttackScaleAnimation[3 * 6] = { struct MarioBodyState gBodyStates[MAX_PLAYERS]; struct GraphNodeObject gMirrorMario[MAX_PLAYERS]; // copy of Mario's geo node for drawing mirror Mario -struct PlayerColor gPlayerColors[MAX_PLAYERS] = { + +// ambient color is always half the diffuse color, so we can pull a macro +#define DEFINE_PLAYER_COLOR(sr, sg, sb, pr, pg, pb) \ + { \ + gdSPDefLights1((sr >> 1), (sg >> 1), (sb >> 1), sr, sg, sb, 0x28, 0x28, 0x28), \ + gdSPDefLights1((pr >> 1), (pg >> 1), (pb >> 1), pr, pg, pb, 0x28, 0x28, 0x28), \ + } + +struct PlayerColor gPlayerColors[] = { // default mario - { - gdSPDefLights1(0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x28, 0x28, 0x28), - gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x28, 0x28, 0x28), - }, + DEFINE_PLAYER_COLOR(0xff, 0x00, 0x00, /**/ 0x00, 0x00, 0xff), // default luigi - { - gdSPDefLights1(0x00, 0x4c, 0x00, 0x00, 0x98, 0x00, 0x28, 0x28, 0x28), - gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xfe, 0x28, 0x28, 0x28), - }, + DEFINE_PLAYER_COLOR(0x00, 0x98, 0x00, /**/ 0x00, 0x00, 0xfe), +#if MAX_PLAYERS > 2 + // fake waluigi + DEFINE_PLAYER_COLOR(0x6d, 0x3c, 0x9a, /**/ 0x2c, 0x26, 0x3f), + // fake wario + DEFINE_PLAYER_COLOR(0xf9, 0xeb, 0x30, /**/ 0x7f, 0x20, 0x7a), + // light blue + DEFINE_PLAYER_COLOR(0x00, 0xdf, 0xff, /**/ 0x00, 0x00, 0xf0), + // sponge + DEFINE_PLAYER_COLOR(0xff, 0x7f, 0x00, /**/ 0x00, 0x7f, 0xa0), + // blue man group + DEFINE_PLAYER_COLOR(0x00, 0x00, 0xf0, /**/ 0x00, 0x00, 0x4f), + // thanks doc + DEFINE_PLAYER_COLOR(0xff, 0x00, 0xff, /**/ 0x00, 0xff, 0x00), + // white + DEFINE_PLAYER_COLOR(0xff, 0xff, 0xff, /**/ 0x10, 0x10, 0x10), + // grey + DEFINE_PLAYER_COLOR(0x6f, 0x6f, 0x6f, /**/ 0xe0, 0xe0, 0xe0), +#endif }; +static const size_t gNumPlayerColors = sizeof(gPlayerColors) / sizeof(*gPlayerColors); + // This whole file is weirdly organized. It has to be the same file due // to rodata boundaries and function aligns, which means the programmer // treated this like a "misc" file for vaguely Mario related things @@ -102,6 +124,8 @@ struct PlayerColor gPlayerColors[MAX_PLAYERS] = { * usually set to 1. */ void set_player_colors(u8 globalIndex, const u8 shirt[4], const u8 pants[4]) { + // choose the last color in the table for extra players + if (globalIndex >= gNumPlayerColors) globalIndex = gNumPlayerColors - 1; const u8 pAmb[3] = { pants[0] >> pants[4], pants[1] >> pants[4], pants[2] >> pants[4] }; const u8 sAmb[3] = { shirt[0] >> shirt[4], shirt[1] >> shirt[4], shirt[2] >> shirt[4] }; gPlayerColors[globalIndex].pants = @@ -116,8 +140,8 @@ void set_player_colors(u8 globalIndex, const u8 shirt[4], const u8 pants[4]) { * Returns RGB, not RGBA! */ u8 *get_player_color(u8 globalIndex, const int which) { - if (globalIndex >= MAX_PLAYERS) - globalIndex = 0; + // choose the last color in the table for extra players + if (globalIndex >= gNumPlayerColors) globalIndex = gNumPlayerColors - 1; if (which == 0) return gPlayerColors[globalIndex].shirt.l[0].l.col; else @@ -779,13 +803,17 @@ Gfx* geo_mario_set_player_colors(s32 callContext, struct GraphNode* node, UNUSED struct MarioBodyState* bodyState = &gBodyStates[index]; if (callContext == GEO_CONTEXT_RENDER) { + // extra players get last color + if (colorIndex >= gNumPlayerColors) colorIndex = gNumPlayerColors - 1; gfx = alloc_display_list(5 * sizeof(*gfx)); + // put the player colors into lights 3, 4, 5, 6 + // they will be later copied to lights 1, 2 with gsSPCopyLightEXT gSPLight(gfx + 0, &gPlayerColors[colorIndex].pants.l, 3); gSPLight(gfx + 1, &gPlayerColors[colorIndex].pants.a, 4); gSPLight(gfx + 2, &gPlayerColors[colorIndex].shirt.l, 5); gSPLight(gfx + 3, &gPlayerColors[colorIndex].shirt.a, 6); gSPEndDisplayList(gfx + 4); - // put on transparent if vanish effect, opaque otherwise + // put on transparent layer if vanish effect, opaque otherwise const u32 layer = ((bodyState->modelState >> 8) & 1) ? LAYER_TRANSPARENT : LAYER_OPAQUE; asGenerated->fnNode.node.flags = (asGenerated->fnNode.node.flags & 0xFF) | (layer << 8); } From 8c28b0c26910d7ad5e509be9791ba7561562f43b Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 6 Apr 2021 18:09:07 +0300 Subject: [PATCH 14/14] windows: bump SO_SNDBUF size when playing with >4 players --- src/pc/network/socket/socket_windows.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/pc/network/socket/socket_windows.c b/src/pc/network/socket/socket_windows.c index a9a17220..c524a41a 100644 --- a/src/pc/network/socket/socket_windows.c +++ b/src/pc/network/socket/socket_windows.c @@ -27,6 +27,17 @@ SOCKET socket_initialize(void) { return INVALID_SOCKET; } +#if MAX_PLAYERS > 4 + // on windows, the send buffer for the socket needs to be increased + // for the many players case to avoid WSAEWOULDBLOCK on send + // not actually sure this is the "proper" way to fix it + int bufsiz = 128 * 1024; // 128kb, default is apparently 8kb or 16kb + rc = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (const char *)&bufsiz, sizeof(bufsiz)); + if (rc != NO_ERROR) { + LOG_ERROR("setsockopt(SO_SNDBUF) failed with error: %d", rc); + } +#endif + return sock; }