mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 13:35:12 +00:00
Added player connected/disconnected events
Changed synchronizing text to be more descriptive Added 'player connected', 'player disconnected', 'network shutdown' chat messages Prevented someone from joining through Discord while in another lobby Added the distinction of sending a packet to all vs to a specific player Enforced lobby size of 2, multiple joiners in a direct connection will be booted Stored network destination for each player Detected network drops
This commit is contained in:
parent
6cf5e5da68
commit
f8bffd3b2a
25 changed files with 564 additions and 79 deletions
|
@ -3958,12 +3958,18 @@
|
|||
<ClCompile Include="..\src\pc\network\discord\discord_network.c" />
|
||||
<ClCompile Include="..\src\pc\network\discord\user.c" />
|
||||
<ClCompile Include="..\src\pc\network\network.c" />
|
||||
<ClCompile Include="..\src\pc\network\network_player.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_chat.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_collect_coin.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_collect_item.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_collect_star.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_custom.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_kick.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_inside_painting.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_join.c" />
|
||||
<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_object.c" />
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_player.c" />
|
||||
|
@ -4327,6 +4333,7 @@
|
|||
<ClInclude Include="..\src\pc\network\discord\discord_network.h" />
|
||||
<ClInclude Include="..\src\pc\network\discord\user.h" />
|
||||
<ClInclude Include="..\src\pc\network\network.h" />
|
||||
<ClInclude Include="..\src\pc\network\network_player.h" />
|
||||
<ClInclude Include="..\src\pc\network\socket\socket.h" />
|
||||
<ClInclude Include="..\src\pc\network\socket\socket_linux.h" />
|
||||
<ClInclude Include="..\src\pc\network\socket\socket_windows.h" />
|
||||
|
|
|
@ -15048,6 +15048,24 @@
|
|||
<ClCompile Include="..\src\pc\network\packets\packet_chat.c">
|
||||
<Filter>Source Files\src\pc\network\packets</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\pc\network\network_player.c">
|
||||
<Filter>Source Files\src\pc\network</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_join.c">
|
||||
<Filter>Source Files\src\pc\network\packets</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\pc\network\packets\packet.c">
|
||||
<Filter>Source Files\src\pc\network\packets</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_keep_alive.c">
|
||||
<Filter>Source Files\src\pc\network\packets</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_kick.c">
|
||||
<Filter>Source Files\src\pc\network\packets</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\pc\network\packets\packet_leaving.c">
|
||||
<Filter>Source Files\src\pc\network\packets</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\actors\common0.h">
|
||||
|
@ -15997,5 +16015,8 @@
|
|||
<ClInclude Include="..\src\game\chat.h">
|
||||
<Filter>Header Files\src\game</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\pc\network\network_player.h">
|
||||
<Filter>Header Files\src\pc\network</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -13,6 +13,7 @@
|
|||
#include "pc/network/network.h"
|
||||
#include "audio_defines.h"
|
||||
#include "audio/external.h"
|
||||
#include "menu/file_select.h"
|
||||
|
||||
#define CHAT_DIALOG_MAX 96
|
||||
#define CHAT_MESSAGES_MAX 16
|
||||
|
@ -90,14 +91,21 @@ static void render_chat_message(struct ChatMessage* chatMessage, u8 index) {
|
|||
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||
}
|
||||
|
||||
void chat_add_message(char* ascii, u8 isLocal) {
|
||||
message[onMessageIndex].dialog[0] = isLocal ? 0xFD : 0xFA;
|
||||
message[onMessageIndex].dialog[1] = 0x9E;
|
||||
str_ascii_to_dialog(ascii, &message[onMessageIndex].dialog[2], MIN(strlen(ascii), CHAT_DIALOG_MAX - 3));
|
||||
message[onMessageIndex].life = CHAT_LIFE_MAX;
|
||||
message[onMessageIndex].isLocal = isLocal ? 1 : 0;
|
||||
void chat_add_message(char* ascii, enum ChatMessageType chatMessageType) {
|
||||
u8 character = '?';
|
||||
switch (chatMessageType) {
|
||||
case CMT_LOCAL: character = 0xFD; break;
|
||||
case CMT_REMOTE: character = 0xFA; break;
|
||||
case CMT_SYSTEM: character = 0xF9; break;
|
||||
}
|
||||
struct ChatMessage* msg = &message[onMessageIndex];
|
||||
msg->dialog[0] = character;
|
||||
msg->dialog[1] = 0x9E;
|
||||
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->isLocal = (chatMessageType == CMT_LOCAL);
|
||||
onMessageIndex = (onMessageIndex + 1) % CHAT_MESSAGES_MAX;
|
||||
play_sound(isLocal ? SOUND_MENU_MESSAGE_DISAPPEAR : SOUND_MENU_MESSAGE_APPEAR, gDefaultSoundArgs);
|
||||
play_sound(msg->isLocal ? SOUND_MENU_MESSAGE_DISAPPEAR : SOUND_MENU_MESSAGE_APPEAR, gDefaultSoundArgs);
|
||||
}
|
||||
|
||||
static void chat_stop_input(void) {
|
||||
|
@ -118,7 +126,6 @@ void chat_start_input(void) {
|
|||
keyboard_start_text_input(TIM_SINGLE_LINE, CHAT_DIALOG_MAX - 3, chat_stop_input, chat_send_input);
|
||||
}
|
||||
|
||||
|
||||
void render_chat(void) {
|
||||
u8 count = 0;
|
||||
if (sInChatInput) {
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
#ifndef CHAT_H
|
||||
#define CHAT_H
|
||||
|
||||
enum ChatMessageType {
|
||||
CMT_LOCAL,
|
||||
CMT_REMOTE,
|
||||
CMT_SYSTEM,
|
||||
};
|
||||
|
||||
void render_chat(void);
|
||||
void chat_add_message(char* ascii, u8 isLocal);
|
||||
void chat_add_message(char* ascii, enum ChatMessageType chatMessageType);
|
||||
void chat_start_input(void);
|
||||
|
||||
#endif
|
|
@ -25,6 +25,7 @@
|
|||
#include "types.h"
|
||||
#include "macros.h"
|
||||
#include "pc/cheats.h"
|
||||
#include "pc/network/network.h"
|
||||
#ifdef BETTERCAMERA
|
||||
#include "bettercamera.h"
|
||||
#endif
|
||||
|
@ -2823,25 +2824,45 @@ s16 render_pause_courses_and_castle(void) {
|
|||
}
|
||||
|
||||
s16 render_sync_level_screen(void) {
|
||||
char* message;
|
||||
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
message = network_player_any_connected() ? "Waiting for player..." : "Waiting for player to connect...";
|
||||
} else {
|
||||
message = network_player_any_connected() ? "Waiting for player..." : "Not connected to anyone.\nPlease restart the game.";
|
||||
}
|
||||
|
||||
static f32 alphaScalar = 0.0f;
|
||||
static clock_t lastDisplay = 0;
|
||||
f32 elapsed = (clock() - lastDisplay) / (f32)CLOCKS_PER_SEC;
|
||||
if (elapsed > 1.0f) {
|
||||
alphaScalar = 0;
|
||||
} else if (alphaScalar < 1.0f) {
|
||||
alphaScalar += 0.3f;
|
||||
if (alphaScalar > 1) { alphaScalar = 1; }
|
||||
}
|
||||
u8 alpha = (((f32)fabs(sin(gGlobalTimer / 20.0f)) * alphaScalar) * 255);
|
||||
lastDisplay = clock();
|
||||
|
||||
// black screen
|
||||
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 240.0f, 0);
|
||||
create_dl_scale_matrix(MENU_MTX_NOPUSH,
|
||||
GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT / 130.0f, 3.0f, 1.0f);
|
||||
create_dl_scale_matrix(MENU_MTX_NOPUSH, GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT / 130.0f, 3.0f, 1.0f);
|
||||
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
|
||||
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
|
||||
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||
|
||||
// print text
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
||||
f32 textWidth = get_generic_ascii_string_width(message);
|
||||
f32 textHeight = get_generic_ascii_string_height(message);
|
||||
|
||||
// synchronizing text
|
||||
u8 colorFade = sins(gDialogColorFadeTimer) * 50.0f + 200.0f;
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
||||
gDPSetEnvColor(gDisplayListHead++, colorFade, colorFade, colorFade, 255);
|
||||
f32 xPos = (SCREEN_WIDTH - textWidth) / 2.0f;
|
||||
f32 yPos = (SCREEN_HEIGHT + textHeight) / 2.0f;
|
||||
|
||||
#define TEXT_SYNCHRONIZING 0x1C,0x22,0x17,0x0C,0x11,0x1B,0x18,0x17,0x12,0x02,0x12,0x17,0x10,0xFF
|
||||
u8 synchronizing[] = { TEXT_SYNCHRONIZING };
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, alpha);
|
||||
print_generic_ascii_string(xPos, yPos, message);
|
||||
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, 80, 200, synchronizing);
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1046,11 +1046,11 @@ s32 play_mode_normal(void) {
|
|||
if (sCurrPlayMode == PLAY_MODE_NORMAL) {
|
||||
if (!gReceiveWarp) {
|
||||
if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL) {
|
||||
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL);
|
||||
set_play_mode(PLAY_MODE_SYNC_LEVEL);
|
||||
network_send_level_warp_begin();
|
||||
} else if (sTransitionTimer != 0) {
|
||||
if (sWarpDest.type == WARP_TYPE_CHANGE_AREA) {
|
||||
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_AREA);
|
||||
set_play_mode(PLAY_MODE_SYNC_LEVEL);
|
||||
network_send_level_warp_begin();
|
||||
} else {
|
||||
set_play_mode(PLAY_MODE_CHANGE_AREA);
|
||||
|
@ -1085,7 +1085,7 @@ s32 play_mode_paused(void) {
|
|||
fade_into_special_warp(0, 0);
|
||||
gSavedCourseNum = COURSE_NONE;
|
||||
}
|
||||
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL);
|
||||
set_play_mode(PLAY_MODE_SYNC_LEVEL);
|
||||
network_send_level_warp_begin();
|
||||
} else if (gPauseScreenMode == 3) {
|
||||
// We should only be getting "int 3" to here
|
||||
|
|
|
@ -31,7 +31,7 @@ static void debug_warp_level(u8 level) {
|
|||
sWarpDest.nodeId = node->destNode;
|
||||
sWarpDest.arg = 0;
|
||||
|
||||
sCurrPlayMode = (gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL;
|
||||
sCurrPlayMode = PLAY_MODE_SYNC_LEVEL;
|
||||
network_send_level_warp_begin();
|
||||
return;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ static void debug_warp_level(u8 level) {
|
|||
sWarpDest.nodeId = node->destNode;
|
||||
sWarpDest.arg = 0;
|
||||
|
||||
sCurrPlayMode = (gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL;
|
||||
sCurrPlayMode = PLAY_MODE_SYNC_LEVEL;
|
||||
network_send_level_warp_begin();
|
||||
return;
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ static void debug_warp_area() {
|
|||
sWarpDest.nodeId = node->destNode;
|
||||
sWarpDest.arg = 0;
|
||||
|
||||
sCurrPlayMode = (gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL;
|
||||
sCurrPlayMode = PLAY_MODE_SYNC_LEVEL;
|
||||
network_send_level_warp_begin();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -13,8 +13,13 @@ static void on_activity_update_callback(UNUSED void* data, enum EDiscordResult r
|
|||
}
|
||||
|
||||
static void on_activity_join_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordLobby* lobby) {
|
||||
LOG_INFO("> on_activity_join_callback returned %d, lobby %lld", result, lobby->id);
|
||||
LOG_INFO("> on_activity_join_callback returned %d, lobby %lld, owner %lld", result, lobby->id, lobby->owner_id);
|
||||
DISCORD_REQUIRE(result);
|
||||
if (gNetworkType != NT_NONE) {
|
||||
LOG_ERROR("Joined lobby when already connected somewhere!");
|
||||
exit(0);
|
||||
return;
|
||||
}
|
||||
network_init(NT_CLIENT);
|
||||
|
||||
gCurActivity.type = DiscordActivityType_Playing;
|
||||
|
@ -27,6 +32,7 @@ static void on_activity_join_callback(UNUSED void* data, enum EDiscordResult res
|
|||
discord_network_init(lobby->id);
|
||||
discord_activity_update(false);
|
||||
|
||||
gNetworkUserIds[0] = lobby->owner_id;
|
||||
network_send_join_request();
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,8 @@ static void ns_discord_shutdown(void) {
|
|||
|
||||
struct NetworkSystem gNetworkSystemDiscord = {
|
||||
.initialize = ns_discord_initialize,
|
||||
.save_id = ns_discord_save_id,
|
||||
.clear_id = ns_discord_clear_id,
|
||||
.update = ns_discord_update,
|
||||
.send = ns_discord_network_send,
|
||||
.shutdown = ns_discord_shutdown,
|
||||
|
|
|
@ -2,33 +2,60 @@
|
|||
#include "lobby.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
int ns_discord_network_send(u8* data, u16 dataLength) {
|
||||
int64_t gNetworkUserIds[MAX_PLAYERS] = { 0 };
|
||||
|
||||
u8 discord_user_id_to_local_index(int64_t userId) {
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
if (gNetworkPlayers[i].connected && gNetworkUserIds[i] == userId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return UNKNOWN_LOCAL_INDEX;
|
||||
}
|
||||
|
||||
int ns_discord_network_send(u8 localIndex, u8* data, u16 dataLength) {
|
||||
if (!gDiscordInitialized) { return 1; }
|
||||
if (gCurLobbyId == 0) { return 2; }
|
||||
int32_t memberCount = 0;
|
||||
DISCORD_REQUIRE(app.lobbies->member_count(app.lobbies, gCurLobbyId, &memberCount));
|
||||
if (memberCount <= 1) { return 3; }
|
||||
|
||||
for (int i = 0; i < memberCount; i++) {
|
||||
DiscordUserId userId;
|
||||
DISCORD_REQUIRE(app.lobbies->get_member_user_id(app.lobbies, gCurLobbyId, i, &userId));
|
||||
if (userId == app.userId) { continue; }
|
||||
DISCORD_REQUIRE(app.lobbies->send_network_message(app.lobbies, gCurLobbyId, userId, 0, data, dataLength));
|
||||
}
|
||||
DISCORD_REQUIRE(app.lobbies->send_network_message(app.lobbies, gCurLobbyId, gNetworkUserIds[localIndex], 0, data, dataLength));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void discord_network_on_message(UNUSED void* eventData, int64_t lobbyId, int64_t userId, uint8_t channelId, uint8_t* data, uint32_t dataLength) {
|
||||
network_receive((u8*)data, (u16)dataLength);
|
||||
gNetworkUserIds[0] = userId;
|
||||
|
||||
u8 localIndex = UNKNOWN_LOCAL_INDEX;
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
if (gNetworkUserIds[i] == userId) {
|
||||
localIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
network_receive(localIndex, (u8*)data, (u16)dataLength);
|
||||
}
|
||||
|
||||
void discord_network_flush(void) {
|
||||
app.lobbies->flush_network(app.lobbies);
|
||||
}
|
||||
|
||||
void ns_discord_save_id(u8 localId) {
|
||||
assert(localId > 0);
|
||||
assert(localId < MAX_PLAYERS);
|
||||
gNetworkUserIds[localId] = gNetworkUserIds[0];
|
||||
LOG_INFO("saved user id %d == %lld", localId, gNetworkUserIds[localId]);
|
||||
}
|
||||
|
||||
void ns_discord_clear_id(u8 localId) {
|
||||
assert(localId > 0);
|
||||
assert(localId < MAX_PLAYERS);
|
||||
gNetworkUserIds[localId] = 0;
|
||||
LOG_INFO("cleared user id %d == %lld", localId, gNetworkUserIds[localId]);
|
||||
}
|
||||
|
||||
void discord_network_init(int64_t lobbyId) {
|
||||
DISCORD_REQUIRE(app.lobbies->connect_network(app.lobbies, lobbyId));
|
||||
DISCORD_REQUIRE(app.lobbies->open_network_channel(app.lobbies, lobbyId, 0, false));
|
||||
LOG_INFO("network initialized");
|
||||
}
|
||||
|
||||
void discord_network_shutdown(void) {
|
||||
|
|
|
@ -2,9 +2,14 @@
|
|||
#define DISCORD_NETWORK_H
|
||||
#include "discord.h"
|
||||
|
||||
int ns_discord_network_send(u8* data, u16 dataLength);
|
||||
extern int64_t gNetworkUserIds[MAX_PLAYERS];
|
||||
|
||||
u8 discord_user_id_to_local_index(int64_t userId);
|
||||
int ns_discord_network_send(u8 localIndex, u8* data, u16 dataLength);
|
||||
void discord_network_on_message(UNUSED void* eventData, int64_t lobbyId, int64_t userId, uint8_t channelId, uint8_t* data, uint32_t dataLength);
|
||||
void discord_network_flush(void);
|
||||
void ns_discord_save_id(u8 localId);
|
||||
void ns_discord_clear_id(u8 localId);
|
||||
void discord_network_init(int64_t lobbyId);
|
||||
void discord_network_shutdown(void);
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@ static bool isHosting = false;
|
|||
DiscordLobbyId gCurLobbyId = 0;
|
||||
|
||||
static void on_lobby_create_callback(UNUSED void* data, enum EDiscordResult result, struct DiscordLobby* lobby) {
|
||||
LOG_INFO("> on_lobby_update returned %d\n", (int)result);
|
||||
LOG_INFO("Lobby id: %lld\n", lobby->id);
|
||||
LOG_INFO("Lobby type: %u\n", lobby->type);
|
||||
LOG_INFO("Lobby owner id: %lld\n", lobby->owner_id);
|
||||
LOG_INFO("Lobby secret: %s\n", lobby->secret);
|
||||
LOG_INFO("Lobby capacity: %u\n", lobby->capacity);
|
||||
LOG_INFO("Lobby locked: %d\n", lobby->locked);
|
||||
LOG_INFO("> on_lobby_update returned %d", (int)result);
|
||||
LOG_INFO("Lobby id: %lld", lobby->id);
|
||||
LOG_INFO("Lobby type: %u", lobby->type);
|
||||
LOG_INFO("Lobby owner id: %lld", lobby->owner_id);
|
||||
LOG_INFO("Lobby secret: %s", lobby->secret);
|
||||
LOG_INFO("Lobby capacity: %u", lobby->capacity);
|
||||
LOG_INFO("Lobby locked: %d", lobby->locked);
|
||||
|
||||
gCurActivity.type = DiscordActivityType_Playing;
|
||||
snprintf(gCurActivity.party.id, 128, "%lld", lobby->id);
|
||||
|
@ -47,6 +47,10 @@ static void on_member_update(UNUSED void* data, int64_t lobbyId, int64_t userId)
|
|||
|
||||
static void on_member_disconnect(UNUSED void* data, int64_t lobbyId, int64_t userId) {
|
||||
LOG_INFO("> on_member_disconnect lobby: %lld, user: %lld", lobbyId, userId);
|
||||
u8 localIndex = discord_user_id_to_local_index(userId);
|
||||
if (localIndex != UNKNOWN_LOCAL_INDEX && gNetworkPlayers[localIndex].connected) {
|
||||
network_player_disconnected(gNetworkPlayers[localIndex].globalIndex);
|
||||
}
|
||||
gCurActivity.party.size.current_size--;
|
||||
discord_activity_update(isHosting);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ struct NetworkSystem* gNetworkSystem = &gNetworkSystemDiscord;
|
|||
#define LOADING_LEVEL_THRESHOLD 10
|
||||
u8 networkLoadingLevel = 0;
|
||||
bool gNetworkLevelLoaded = false;
|
||||
clock_t gLastNetworkSend = 0;
|
||||
|
||||
struct ServerSettings gServerSettings = {
|
||||
.playerInteractions = PLAYER_INTERACTIONS_SOLID,
|
||||
|
@ -53,6 +54,12 @@ bool network_init(enum NetworkType inNetworkType) {
|
|||
// set network type
|
||||
gNetworkType = inNetworkType;
|
||||
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
network_player_connected(NPT_LOCAL, 0);
|
||||
extern u8* gOverrideEeprom;
|
||||
gOverrideEeprom = NULL;
|
||||
}
|
||||
|
||||
LOG_INFO("initialized");
|
||||
|
||||
return true;
|
||||
|
@ -71,12 +78,14 @@ void network_on_loaded_level(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void network_send(struct Packet* p) {
|
||||
void network_send_to(u8 localIndex, struct Packet* p) {
|
||||
// sanity checks
|
||||
if (gNetworkType == NT_NONE) { return; }
|
||||
if (p->error) { LOG_ERROR("packet error!"); return; }
|
||||
if (gNetworkSystem == NULL) { LOG_ERROR("no network system attached"); return; }
|
||||
|
||||
p->localIndex = localIndex;
|
||||
|
||||
// remember reliable packets
|
||||
network_remember_reliable(p);
|
||||
|
||||
|
@ -85,20 +94,35 @@ void network_send(struct Packet* p) {
|
|||
memcpy(&p->buffer[p->dataLength], &hash, sizeof(u32));
|
||||
|
||||
// send
|
||||
int rc = gNetworkSystem->send(p->buffer, p->cursor + sizeof(u32));
|
||||
int rc = gNetworkSystem->send(localIndex, p->buffer, p->cursor + sizeof(u32));
|
||||
if (rc != NO_ERROR) { return; }
|
||||
p->sent = true;
|
||||
|
||||
gLastNetworkSend = clock();
|
||||
}
|
||||
|
||||
void network_receive(u8* data, u16 dataLength) {
|
||||
void network_send(struct Packet* p) {
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
if (!gNetworkPlayers[i].connected) { continue; }
|
||||
p->localIndex = i;
|
||||
network_send_to(i, p);
|
||||
}
|
||||
}
|
||||
|
||||
void network_receive(u8 localIndex, u8* data, u16 dataLength) {
|
||||
// receive packet
|
||||
struct Packet p = {
|
||||
.localIndex = localIndex,
|
||||
.cursor = 3,
|
||||
.buffer = { 0 },
|
||||
.dataLength = dataLength,
|
||||
};
|
||||
memcpy(p.buffer, data, dataLength);
|
||||
|
||||
if (localIndex != UNKNOWN_LOCAL_INDEX && localIndex != 0) {
|
||||
gNetworkPlayers[localIndex].lastReceived = clock();
|
||||
}
|
||||
|
||||
// subtract and check hash
|
||||
p.dataLength -= sizeof(u32);
|
||||
if (!packet_check_hash(&p)) {
|
||||
|
@ -121,7 +145,8 @@ void network_update(void) {
|
|||
}
|
||||
|
||||
// send out update packets
|
||||
if (gNetworkType != NT_NONE) {
|
||||
if (gNetworkType != NT_NONE && network_player_any_connected()) {
|
||||
network_player_update();
|
||||
if (sCurrPlayMode == PLAY_MODE_NORMAL || sCurrPlayMode == PLAY_MODE_PAUSED) {
|
||||
network_update_player();
|
||||
network_update_objects();
|
||||
|
@ -141,8 +166,10 @@ void network_update(void) {
|
|||
|
||||
void network_shutdown(void) {
|
||||
if (gNetworkType == NT_NONE) { return; }
|
||||
|
||||
if (gNetworkSystem == NULL) { LOG_ERROR("no network system attached"); return; }
|
||||
|
||||
if (gNetworkPlayerLocal != NULL) { network_send_leaving(gNetworkPlayerLocal->globalIndex); }
|
||||
network_player_shutdown();
|
||||
gNetworkSystem->shutdown();
|
||||
|
||||
gNetworkType = NT_NONE;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <time.h>
|
||||
#include <types.h>
|
||||
#include <assert.h>
|
||||
#include "network_player.h"
|
||||
#include "packets/packet.h"
|
||||
#include "../cliopts.h"
|
||||
|
||||
|
@ -28,8 +29,10 @@ enum NetworkSystemType {
|
|||
|
||||
struct NetworkSystem {
|
||||
bool (*initialize)(enum NetworkType);
|
||||
void (*save_id)(u8 localIndex);
|
||||
void (*clear_id)(u8 localIndex);
|
||||
void (*update)(void);
|
||||
int (*send)(u8* data, u16 dataLength);
|
||||
int (*send)(u8 localIndex, u8* data, u16 dataLength);
|
||||
void (*shutdown)(void);
|
||||
};
|
||||
|
||||
|
@ -66,18 +69,21 @@ struct ServerSettings {
|
|||
};
|
||||
|
||||
// Networking-specific externs
|
||||
extern bool gNetworkLevelLoaded;
|
||||
extern struct NetworkSystem* gNetworkSystem;
|
||||
extern enum NetworkType gNetworkType;
|
||||
extern bool gNetworkLevelLoaded;
|
||||
extern struct SyncObject gSyncObjects[];
|
||||
extern struct ServerSettings gServerSettings;
|
||||
extern clock_t gLastNetworkSend;
|
||||
|
||||
// network.c
|
||||
void network_set_system(enum NetworkSystemType nsType);
|
||||
bool network_init(enum NetworkType inNetworkType);
|
||||
void network_on_init_level(void);
|
||||
void network_on_loaded_level(void);
|
||||
void network_send_to(u8 localIndex, struct Packet* p);
|
||||
void network_send(struct Packet* p);
|
||||
void network_receive(u8* data, u16 dataLength);
|
||||
void network_receive(u8 localIndex, u8* data, u16 dataLength);
|
||||
void network_update(void);
|
||||
void network_shutdown(void);
|
||||
|
||||
|
|
131
src/pc/network/network_player.c
Normal file
131
src/pc/network/network_player.c
Normal file
|
@ -0,0 +1,131 @@
|
|||
#include <stdio.h>
|
||||
#include "network_player.h"
|
||||
#include "game/chat.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
struct NetworkPlayer gNetworkPlayers[MAX_PLAYERS] = { 0 };
|
||||
struct NetworkPlayer* gNetworkPlayerLocal = NULL;
|
||||
struct NetworkPlayer* gNetworkPlayerServer = NULL;
|
||||
|
||||
bool network_player_any_connected(void) {
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
if (gNetworkPlayers[i].connected) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void network_player_update(void) {
|
||||
float elapsed = (clock() - gLastNetworkSend) / (float)CLOCKS_PER_SEC;
|
||||
if (elapsed > NETWORK_PLAYER_TIMEOUT / 3.0f) {
|
||||
network_send_keep_alive();
|
||||
}
|
||||
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[i];
|
||||
if (!np->connected) { continue; }
|
||||
float elapsed = (clock() - np->lastReceived) / (float)CLOCKS_PER_SEC;
|
||||
if (elapsed > NETWORK_PLAYER_TIMEOUT) {
|
||||
network_player_disconnected(i);
|
||||
}
|
||||
}
|
||||
} else if (gNetworkType == NT_CLIENT) {
|
||||
bool connectionAlive = false;
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[i];
|
||||
if (!np->connected) { continue; }
|
||||
float elapsed = (clock() - np->lastReceived) / (float)CLOCKS_PER_SEC;
|
||||
if (elapsed <= NETWORK_PLAYER_TIMEOUT * 1.5f) {
|
||||
connectionAlive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!connectionAlive) {
|
||||
network_shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
|
||||
if (type == NPT_LOCAL) {
|
||||
gNetworkPlayers[0].connected = true;
|
||||
gNetworkPlayers[0].type = type;
|
||||
gNetworkPlayers[0].localIndex = 0;
|
||||
gNetworkPlayers[0].globalIndex = globalIndex;
|
||||
gNetworkPlayerLocal = &gNetworkPlayers[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (globalIndex != UNKNOWN_GLOBAL_INDEX) {
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[i];
|
||||
if (!np->connected) { continue; }
|
||||
if (np->globalIndex != globalIndex) { continue; }
|
||||
np->localIndex = i;
|
||||
np->lastReceived = clock();
|
||||
gNetworkSystem->save_id(i);
|
||||
LOG_ERROR("player connected, reusing local %d, global %d, duplicate event?", i, globalIndex);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[i];
|
||||
if (np->connected) { continue; }
|
||||
np->connected = true;
|
||||
np->localIndex = i;
|
||||
np->globalIndex = (gNetworkType == NT_SERVER) ? i : globalIndex;
|
||||
np->type = type;
|
||||
np->lastReceived = clock();
|
||||
gNetworkSystem->save_id(i);
|
||||
if (type == NPT_SERVER) { gNetworkPlayerServer = np; }
|
||||
chat_add_message("player connected", CMT_SYSTEM);
|
||||
LOG_INFO("player connected, local %d, global %d", i, globalIndex);
|
||||
return i;
|
||||
}
|
||||
|
||||
LOG_ERROR("player connected, but unable to allocate!");
|
||||
return UNKNOWN_GLOBAL_INDEX;
|
||||
}
|
||||
|
||||
u8 network_player_disconnected(u8 globalIndex) {
|
||||
if (globalIndex == 0) {
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
LOG_ERROR("player disconnected, but it's local.. this shouldn't happen!");
|
||||
return UNKNOWN_GLOBAL_INDEX;
|
||||
} else {
|
||||
network_shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
if (globalIndex == UNKNOWN_GLOBAL_INDEX) {
|
||||
LOG_ERROR("player disconnected, but unknown global index!");
|
||||
return UNKNOWN_GLOBAL_INDEX;
|
||||
}
|
||||
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[i];
|
||||
if (!np->connected) { continue; }
|
||||
if (np->globalIndex != globalIndex) { continue; }
|
||||
if (gNetworkType == NT_SERVER) { network_send_leaving(np->globalIndex); }
|
||||
np->connected = false;
|
||||
gNetworkSystem->clear_id(i);
|
||||
LOG_INFO("player disconnected, local %d, global %d", i, globalIndex);
|
||||
chat_add_message("player disconnected", CMT_SYSTEM);
|
||||
return i;
|
||||
}
|
||||
return UNKNOWN_GLOBAL_INDEX;
|
||||
}
|
||||
|
||||
void network_player_shutdown(void) {
|
||||
gNetworkPlayerLocal = NULL;
|
||||
gNetworkPlayerServer = NULL;
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
struct NetworkPlayer* networkPlayer = &gNetworkPlayers[i];
|
||||
networkPlayer->connected = false;
|
||||
gNetworkSystem->clear_id(i);
|
||||
}
|
||||
|
||||
chat_add_message("network shutdown", CMT_SYSTEM);
|
||||
LOG_INFO("cleared all network players");
|
||||
}
|
36
src/pc/network/network_player.h
Normal file
36
src/pc/network/network_player.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef NETWORK_PLAYER_H
|
||||
#define NETWORK_PLAYER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "network.h"
|
||||
|
||||
#define UNKNOWN_LOCAL_INDEX ((u8)-1)
|
||||
#define UNKNOWN_GLOBAL_INDEX ((u8)-1)
|
||||
#define UNKNOWN_NETWORK_INDEX ((u64)-1)
|
||||
#define NETWORK_PLAYER_TIMEOUT 10
|
||||
|
||||
enum NetworkPlayerType {
|
||||
NPT_LOCAL,
|
||||
NPT_SERVER,
|
||||
NPT_CLIENT,
|
||||
};
|
||||
|
||||
struct NetworkPlayer {
|
||||
bool connected;
|
||||
enum NetworkPlayerType type;
|
||||
u8 localIndex;
|
||||
u8 globalIndex;
|
||||
clock_t lastReceived;
|
||||
};
|
||||
|
||||
extern struct NetworkPlayer gNetworkPlayers[];
|
||||
extern struct NetworkPlayer* gNetworkPlayerLocal;
|
||||
extern struct NetworkPlayer* gNetworkPlayerServer;
|
||||
|
||||
bool network_player_any_connected(void);
|
||||
void network_player_update(void);
|
||||
u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex);
|
||||
u8 network_player_disconnected(u8 globalIndex);
|
||||
void network_player_shutdown(void);
|
||||
|
||||
#endif
|
|
@ -3,7 +3,15 @@
|
|||
#include "pc/debuglog.h"
|
||||
|
||||
void packet_receive(struct Packet* p) {
|
||||
switch ((u8)p->buffer[0]) {
|
||||
u8 packetType = (u8)p->buffer[0];
|
||||
|
||||
// refuse packets from unknown players other than join request
|
||||
if (gNetworkType == NT_SERVER && p->localIndex == UNKNOWN_LOCAL_INDEX && packetType != PACKET_JOIN_REQUEST) {
|
||||
network_send_kick(EKT_CLOSE_CONNECTION);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (packetType) {
|
||||
case PACKET_ACK: network_receive_ack(p); break;
|
||||
case PACKET_PLAYER: network_receive_player(p); break;
|
||||
case PACKET_OBJECT: network_receive_object(p); break;
|
||||
|
@ -19,6 +27,10 @@ void packet_receive(struct Packet* p) {
|
|||
case PACKET_JOIN_REQUEST: network_receive_join_request(p); break;
|
||||
case PACKET_JOIN: network_receive_join(p); break;
|
||||
case PACKET_CHAT: network_receive_chat(p); break;
|
||||
case PACKET_KICK: network_receive_kick(p); break;
|
||||
case PACKET_KEEP_ALIVE: network_receive_keep_alive(p); break;
|
||||
case PACKET_LEAVING: network_receive_leaving(p); break;
|
||||
///
|
||||
case PACKET_CUSTOM: network_receive_custom(p); break;
|
||||
default: LOG_ERROR("received unknown packet: %d", p->buffer[0]);
|
||||
}
|
||||
|
|
|
@ -25,10 +25,15 @@ enum PacketType {
|
|||
PACKET_JOIN_REQUEST,
|
||||
PACKET_JOIN,
|
||||
PACKET_CHAT,
|
||||
PACKET_KICK,
|
||||
PACKET_KEEP_ALIVE,
|
||||
PACKET_LEAVING,
|
||||
///
|
||||
PACKET_CUSTOM = 255,
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
u8 localIndex;
|
||||
u16 dataLength;
|
||||
u16 cursor;
|
||||
bool error;
|
||||
|
@ -38,6 +43,11 @@ struct Packet {
|
|||
u8 buffer[PACKET_LENGTH];
|
||||
};
|
||||
|
||||
enum KickReasonType {
|
||||
EKT_CLOSE_CONNECTION,
|
||||
EKT_FULL_PARTY,
|
||||
};
|
||||
|
||||
// packet.c
|
||||
void packet_receive(struct Packet* packet);
|
||||
|
||||
|
@ -107,8 +117,8 @@ void network_receive_reservation(struct Packet* p);
|
|||
|
||||
// packet_join.c
|
||||
void network_send_join_request(void);
|
||||
void network_receive_join_request(UNUSED struct Packet* p);
|
||||
void network_send_join(void);
|
||||
void network_receive_join_request(struct Packet* p);
|
||||
void network_send_join(struct Packet* joinRequestPacket);
|
||||
void network_receive_join(struct Packet* p);
|
||||
|
||||
// packet_custom.c
|
||||
|
@ -120,4 +130,16 @@ void network_receive_custom(struct Packet* p);
|
|||
void network_send_chat(char* message);
|
||||
void network_receive_chat(struct Packet* p);
|
||||
|
||||
// packet_kick.c
|
||||
void network_send_kick(enum KickReasonType kickReason);
|
||||
void network_receive_kick(struct Packet* p);
|
||||
|
||||
// packet_keep_alive.c
|
||||
void network_send_keep_alive(void);
|
||||
void network_receive_keep_alive(struct Packet* p);
|
||||
|
||||
// packet_leaving.c
|
||||
void network_send_leaving(u8 globalIndex);
|
||||
void network_receive_leaving(struct Packet* p);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "src/menu/custom_menu.h"
|
||||
#include "src/pc/fs/fs.h"
|
||||
#include "PR/os_eeprom.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
#define HASH_LENGTH 8
|
||||
extern u8* gOverrideEeprom;
|
||||
|
@ -22,15 +23,17 @@ void network_send_join_request(void) {
|
|||
|
||||
struct Packet p;
|
||||
packet_init(&p, PACKET_JOIN_REQUEST, true);
|
||||
network_send(&p);
|
||||
network_send_to(0, &p);
|
||||
LOG_INFO("sending join request");
|
||||
}
|
||||
|
||||
void network_receive_join_request(UNUSED struct Packet* p) {
|
||||
void network_receive_join_request(struct Packet* p) {
|
||||
assert(gNetworkType == NT_SERVER);
|
||||
network_send_join();
|
||||
LOG_INFO("received join request");
|
||||
network_send_join(p);
|
||||
}
|
||||
|
||||
void network_send_join(void) {
|
||||
void network_send_join(struct Packet* joinRequestPacket) {
|
||||
assert(gNetworkType == NT_SERVER);
|
||||
|
||||
fs_file_t* fp = fs_open(SAVE_FILENAME);
|
||||
|
@ -39,38 +42,60 @@ void network_send_join(void) {
|
|||
fs_close(fp);
|
||||
}
|
||||
|
||||
// do connection event
|
||||
joinRequestPacket->localIndex = network_player_connected(NPT_CLIENT, joinRequestPacket->localIndex);
|
||||
if (joinRequestPacket->localIndex == UNKNOWN_LOCAL_INDEX) {
|
||||
network_send_kick(EKT_FULL_PARTY);
|
||||
return;
|
||||
}
|
||||
|
||||
char hash[HASH_LENGTH] = GIT_HASH;
|
||||
|
||||
struct Packet p;
|
||||
packet_init(&p, PACKET_JOIN, true);
|
||||
packet_write(&p, &hash, sizeof(u8) * HASH_LENGTH);
|
||||
packet_write(&p, &joinRequestPacket->localIndex, sizeof(u8));
|
||||
packet_write(&p, &gCurrSaveFileNum, sizeof(s16));
|
||||
packet_write(&p, &gServerSettings.playerInteractions, sizeof(u8));
|
||||
packet_write(&p, &gServerSettings.playerKnockbackStrength, sizeof(u8));
|
||||
packet_write(&p, &gServerSettings.stayInLevelAfterStar, sizeof(u8));
|
||||
packet_write(&p, eeprom, sizeof(u8) * 512);
|
||||
network_send(&p);
|
||||
network_send_to(joinRequestPacket->localIndex , &p);
|
||||
|
||||
LOG_INFO("sending join packet");
|
||||
}
|
||||
|
||||
void network_receive_join(struct Packet* p) {
|
||||
assert(gNetworkType == NT_CLIENT);
|
||||
LOG_INFO("received join packet");
|
||||
|
||||
gOverrideEeprom = eeprom;
|
||||
char hash[HASH_LENGTH] = GIT_HASH;
|
||||
char remoteHash[HASH_LENGTH] = { 0 };
|
||||
u8 myGlobalIndex = UNKNOWN_GLOBAL_INDEX;
|
||||
|
||||
// find all reserved objects
|
||||
if (network_player_any_connected()) {
|
||||
LOG_ERROR("Received join packet, but already in-game!");
|
||||
return;
|
||||
}
|
||||
|
||||
// verify version
|
||||
packet_read(p, &remoteHash, sizeof(u8) * HASH_LENGTH);
|
||||
if (memcmp(hash, remoteHash, HASH_LENGTH) != 0) {
|
||||
custom_menu_version_mismatch();
|
||||
return;
|
||||
}
|
||||
|
||||
packet_read(p, &myGlobalIndex, sizeof(u8));
|
||||
packet_read(p, &gCurrSaveFileNum, sizeof(s16));
|
||||
packet_read(p, &gServerSettings.playerInteractions, sizeof(u8));
|
||||
packet_read(p, &gServerSettings.playerKnockbackStrength, sizeof(u8));
|
||||
packet_read(p, &gServerSettings.stayInLevelAfterStar, sizeof(u8));
|
||||
packet_read(p, eeprom, sizeof(u8) * 512);
|
||||
|
||||
network_player_connected(NPT_SERVER, 0);
|
||||
network_player_connected(NPT_LOCAL, myGlobalIndex);
|
||||
|
||||
save_file_load_all(TRUE);
|
||||
if (memcmp(hash, remoteHash, HASH_LENGTH) != 0) {
|
||||
custom_menu_version_mismatch();
|
||||
return;
|
||||
}
|
||||
custom_menu_goto_game(gCurrSaveFileNum);
|
||||
}
|
||||
|
|
15
src/pc/network/packets/packet_keep_alive.c
Normal file
15
src/pc/network/packets/packet_keep_alive.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <stdio.h>
|
||||
#include "../network.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
void network_send_keep_alive(void) {
|
||||
struct Packet p;
|
||||
packet_init(&p, PACKET_KEEP_ALIVE, FALSE);
|
||||
network_send(&p);
|
||||
gLastNetworkSend = clock();
|
||||
LOG_INFO("sending keep alive");
|
||||
}
|
||||
|
||||
void network_receive_keep_alive(struct Packet* p) {
|
||||
LOG_INFO("received keep alive");
|
||||
}
|
31
src/pc/network/packets/packet_kick.c
Normal file
31
src/pc/network/packets/packet_kick.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include <stdio.h>
|
||||
#include "../network.h"
|
||||
#include "menu/custom_menu_system.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
void network_send_kick(enum KickReasonType kickReason) {
|
||||
struct Packet p;
|
||||
packet_init(&p, PACKET_KICK, FALSE);
|
||||
packet_write(&p, &kickReason, sizeof(enum KickReasonType));
|
||||
network_send_to(0, &p);
|
||||
}
|
||||
|
||||
void network_receive_kick(struct Packet* p) {
|
||||
if (gNetworkType != NT_CLIENT) {
|
||||
LOG_ERROR("Kicking non-client... refuse!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (network_player_any_connected() && gNetworkPlayers[p->localIndex].type != NPT_SERVER) {
|
||||
LOG_ERROR("Kick came from non-server... refuse!");
|
||||
return;
|
||||
}
|
||||
|
||||
enum KickReasonType kickReason;
|
||||
packet_read(p, &kickReason, sizeof(enum KickReasonType));
|
||||
switch (kickReason) {
|
||||
case EKT_FULL_PARTY: custom_menu_error("The party is full."); break;
|
||||
default: custom_menu_error("Host has closed the connection."); break;
|
||||
}
|
||||
network_shutdown();
|
||||
}
|
43
src/pc/network/packets/packet_leaving.c
Normal file
43
src/pc/network/packets/packet_leaving.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include <stdio.h>
|
||||
#include "../network.h"
|
||||
#include "menu/custom_menu_system.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
void network_send_leaving(u8 globalIndex) {
|
||||
if (gNetworkPlayerLocal == NULL) {
|
||||
LOG_ERROR("Local network player not initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gNetworkType != NT_SERVER) {
|
||||
if (gNetworkPlayerServer == NULL) {
|
||||
LOG_ERROR("Server network player not initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
globalIndex = gNetworkPlayerLocal->globalIndex;
|
||||
}
|
||||
|
||||
struct Packet p;
|
||||
packet_init(&p, PACKET_LEAVING, TRUE);
|
||||
packet_write(&p, &globalIndex, sizeof(u8));
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
network_send(&p);
|
||||
} else {
|
||||
network_send_to(gNetworkPlayerServer->localIndex, &p);
|
||||
}
|
||||
LOG_INFO("Sending leaving event for %d", globalIndex);
|
||||
}
|
||||
|
||||
void network_receive_leaving(struct Packet* p) {
|
||||
if (gNetworkType != NT_SERVER && network_player_any_connected() && gNetworkPlayers[p->localIndex].type != NPT_SERVER) {
|
||||
LOG_ERROR("Leaving came from non-server... refuse!");
|
||||
return;
|
||||
}
|
||||
|
||||
u8 globalIndex = 0;
|
||||
packet_read(p, &globalIndex, sizeof(u8));
|
||||
|
||||
LOG_INFO("Received leaving event for %d", globalIndex);
|
||||
network_player_disconnected(globalIndex);
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
#include "../network.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
// two-player hack: the localIndex for resending packets can be 0... this means reply to last person received from. THIS WILL NOT WORK with more than two players
|
||||
|
||||
#define RELIABLE_RESEND_RATE 0.10f
|
||||
#define MAX_RESEND_ATTEMPTS 20
|
||||
|
||||
|
@ -41,7 +43,7 @@ void network_send_ack(struct Packet* p) {
|
|||
struct Packet ack = { 0 };
|
||||
packet_init(&ack, PACKET_ACK, false);
|
||||
packet_write(&ack, &seqId, sizeof(u16));
|
||||
network_send(&ack);
|
||||
network_send_to(0, &ack);
|
||||
}
|
||||
|
||||
void network_receive_ack(struct Packet* p) {
|
||||
|
@ -94,7 +96,7 @@ void network_update_reliable(void) {
|
|||
float maxElapsed = (node->sendAttempts * node->sendAttempts * RELIABLE_RESEND_RATE) / ((float)MAX_RESEND_ATTEMPTS);
|
||||
if (elapsed > maxElapsed) {
|
||||
// resend
|
||||
network_send(&node->p);
|
||||
network_send_to(node->p.localIndex, &node->p);
|
||||
node->lastSend = clock();
|
||||
node->sendAttempts++;
|
||||
if (node->sendAttempts >= MAX_RESEND_ATTEMPTS) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "menu/custom_menu.h"
|
||||
|
||||
static SOCKET curSocket = INVALID_SOCKET;
|
||||
struct sockaddr_in txAddr = { 0 };
|
||||
static struct sockaddr_in addr[MAX_PLAYERS] = { 0 };
|
||||
|
||||
static int socket_bind(SOCKET socket, unsigned int port) {
|
||||
struct sockaddr_in rxAddr;
|
||||
|
@ -31,11 +31,19 @@ static int socket_send(SOCKET socket, struct sockaddr_in* addr, u8* buffer, u16
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int socket_receive(SOCKET socket, struct sockaddr_in* rxAddr, u8* buffer, u16 bufferLength, u16* receiveLength) {
|
||||
static int socket_receive(SOCKET socket, struct sockaddr_in* rxAddr, u8* buffer, u16 bufferLength, u16* receiveLength, u8* localIndex) {
|
||||
*receiveLength = 0;
|
||||
|
||||
int rxAddrSize = sizeof(struct sockaddr_in);
|
||||
int rc = recvfrom(socket, (char*)buffer, bufferLength, 0, (struct sockaddr*)rxAddr, &rxAddrSize);
|
||||
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
if (memcmp(rxAddr, &addr[i], sizeof(struct sockaddr_in)) == 0) {
|
||||
*localIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == SOCKET_ERROR) {
|
||||
int error = SOCKET_LAST_ERROR;
|
||||
if (error != SOCKET_EWOULDBLOCK && error != SOCKET_ECONNRESET) {
|
||||
|
@ -49,6 +57,7 @@ static int socket_receive(SOCKET socket, struct sockaddr_in* rxAddr, u8* buffer,
|
|||
}
|
||||
|
||||
static bool ns_socket_initialize(enum NetworkType networkType) {
|
||||
|
||||
// sanity check port
|
||||
unsigned int port = (networkType == NT_CLIENT) ? configJoinPort : configHostPort;
|
||||
if (port == 0) { port = DEFAULT_PORT; }
|
||||
|
@ -65,9 +74,9 @@ static bool ns_socket_initialize(enum NetworkType networkType) {
|
|||
LOG_INFO("bound to port %u", port);
|
||||
} else {
|
||||
// save the port to send to
|
||||
txAddr.sin_family = AF_INET;
|
||||
txAddr.sin_port = htons(port);
|
||||
txAddr.sin_addr.s_addr = inet_addr(configJoinIp);
|
||||
addr[0].sin_family = AF_INET;
|
||||
addr[0].sin_port = htons(port);
|
||||
addr[0].sin_addr.s_addr = inet_addr(configJoinIp);
|
||||
LOG_INFO("connecting to %s %u", configJoinIp, port);
|
||||
}
|
||||
|
||||
|
@ -87,20 +96,39 @@ static bool ns_socket_initialize(enum NetworkType networkType) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void ns_socket_save_id(u8 localId) {
|
||||
assert(localId > 0);
|
||||
assert(localId < MAX_PLAYERS);
|
||||
addr[localId] = addr[0];
|
||||
LOG_INFO("saved addr for id %d", localId);
|
||||
}
|
||||
|
||||
static void ns_socket_clear_id(u8 localId) {
|
||||
assert(localId > 0);
|
||||
assert(localId < MAX_PLAYERS);
|
||||
memset(&addr[localId], 0, sizeof(struct sockaddr_in));
|
||||
LOG_INFO("cleared addr for id %d", localId);
|
||||
}
|
||||
|
||||
static void ns_socket_update(void) {
|
||||
if (gNetworkType == NT_NONE) { return; }
|
||||
do {
|
||||
// receive packet
|
||||
u8 data[PACKET_LENGTH];
|
||||
u16 dataLength = 0;
|
||||
int rc = socket_receive(curSocket, &txAddr, data, PACKET_LENGTH, &dataLength);
|
||||
u8 localIndex = UNKNOWN_LOCAL_INDEX;
|
||||
int rc = socket_receive(curSocket, &addr[0], data, PACKET_LENGTH, &dataLength, &localIndex);
|
||||
if (rc != NO_ERROR) { break; }
|
||||
network_receive(data, dataLength);
|
||||
network_receive(localIndex, data, dataLength);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
static int ns_socket_send(u8* data, u16 dataLength) {
|
||||
return socket_send(curSocket, &txAddr, data, dataLength);
|
||||
static int ns_socket_send(u8 localIndex, u8* data, u16 dataLength) {
|
||||
if (localIndex != 0) {
|
||||
if (gNetworkType == NT_SERVER && gNetworkPlayers[localIndex].type != NPT_CLIENT) { return SOCKET_ERROR; }
|
||||
if (gNetworkType == NT_CLIENT && gNetworkPlayers[localIndex].type != NPT_SERVER) { return SOCKET_ERROR; }
|
||||
}
|
||||
return socket_send(curSocket, &addr[localIndex], data, dataLength);
|
||||
}
|
||||
|
||||
static void ns_socket_shutdown(void) {
|
||||
|
@ -111,6 +139,8 @@ static void ns_socket_shutdown(void) {
|
|||
|
||||
struct NetworkSystem gNetworkSystemSocket = {
|
||||
.initialize = ns_socket_initialize,
|
||||
.save_id = ns_socket_save_id,
|
||||
.clear_id = ns_socket_clear_id,
|
||||
.update = ns_socket_update,
|
||||
.send = ns_socket_send,
|
||||
.shutdown = ns_socket_shutdown,
|
||||
|
|
|
@ -7,5 +7,4 @@
|
|||
#define SOCKET_LAST_ERROR WSAGetLastError()
|
||||
#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define SOCKET_ECONNRESET WSAECONNRESET
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue