Merge pull request #103 from fgsfdsfgs/coop-dev

custom player colors (and other "unstable 3" changes)
This commit is contained in:
djoslin0 2021-04-08 00:11:02 -07:00 committed by GitHub
commit cb0c742514
29 changed files with 473 additions and 109 deletions

View File

@ -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.

View File

@ -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),

View File

@ -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(),
};

View File

@ -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),

View File

@ -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(),

View File

@ -3974,6 +3974,7 @@
<ClCompile Include="..\src\pc\network\packets\packet_keep_alive.c" />
<ClCompile Include="..\src\pc\network\packets\packet_leaving.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_warp.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_warp_2.c" />
<ClCompile Include="..\src\pc\network\packets\packet_network_players.c" />
<ClCompile Include="..\src\pc\network\packets\packet_object.c" />
<ClCompile Include="..\src\pc\network\packets\packet_player.c" />

View File

@ -15087,6 +15087,9 @@
<ClCompile Include="..\src\game\characters.c">
<Filter>Source Files\src\game</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_level_warp_2.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\actors\common0.h">

View File

@ -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 &

View File

@ -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'

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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];
}

View File

@ -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 shirt;
Lights1 pants;
};
/**
* The eye texture on succesive frames of Mario's blink animation.
* He intentionally blinks twice each time.
@ -72,12 +78,76 @@ 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
// 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
DEFINE_PLAYER_COLOR(0xff, 0x00, 0x00, /**/ 0x00, 0x00, 0xff),
// default luigi
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
// (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 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 =
(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);
}
/**
* Return the specified color for player globalIndex.
* 0 = shirt, 1 = pants
* Returns RGB, not RGBA!
*/
u8 *get_player_color(u8 globalIndex, const int which) {
// 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
return gPlayerColors[globalIndex].pants.l[0].l.col;
}
/**
* Geo node script that draws Mario's head on the title screen.
*/
@ -405,7 +475,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 +489,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 +505,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 +526,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;
}
@ -707,4 +790,32 @@ 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;
}
}
/**
* 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) {
// 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 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);
}
return gfx;
}

View File

@ -9,6 +9,9 @@
extern struct GraphNodeObject gMirrorMario[MAX_PLAYERS];
extern struct MarioBodyState gBodyStates[MAX_PLAYERS];
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);
@ -27,5 +30,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

View File

@ -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));

View File

@ -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;
}
}

View File

@ -1,6 +1,7 @@
#include <stdio.h>
#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;

View File

@ -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]);

View File

@ -33,6 +33,7 @@ enum PacketType {
PACKET_INSTANT_WARP,
PACKET_NETWORK_PLAYERS,
PACKET_DEATH,
PACKET_LEVEL_WARP_2,
///
PACKET_CUSTOM = 255,
};
@ -140,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
@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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
@ -345,7 +346,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];
}

View File

@ -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;
}

View File

@ -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);