From 5c4677ca77fd2558eebabf853493e1f2c25caa4b Mon Sep 17 00:00:00 2001 From: MysterD Date: Mon, 5 Jul 2021 16:53:09 -0700 Subject: [PATCH] Added a join message screen Displays an animation while joining Shows version mismatch error in join message screen Shows mod mismatch error in join message screen (displays mismatching mods now) Displays party is full / host closed connection in join message screen Added string builder --- build-windows-visual-studio/sm64ex.vcxproj | 4 + .../sm64ex.vcxproj.filters | 12 +++ src/pc/djui/djui.h | 1 + src/pc/djui/djui_panel.c | 5 ++ src/pc/djui/djui_panel_join.c | 2 +- src/pc/djui/djui_panel_join_message.c | 75 +++++++++++++++++++ src/pc/djui/djui_panel_join_message.h | 7 ++ src/pc/djui/djui_panel_main.c | 3 + src/pc/djui/djui_panel_main.h | 2 + src/pc/network/discord/discord.c | 2 +- src/pc/network/network.c | 4 +- src/pc/network/network.h | 2 +- src/pc/network/network_player.c | 4 +- src/pc/network/packets/packet.c | 7 +- src/pc/network/packets/packet_join.c | 48 +++++++++--- src/pc/network/packets/packet_kick.c | 7 +- src/pc/pc_main.c | 2 +- src/pc/utils/string_builder.c | 16 ++++ src/pc/utils/string_builder.h | 15 ++++ 19 files changed, 193 insertions(+), 25 deletions(-) create mode 100644 src/pc/djui/djui_panel_join_message.c create mode 100644 src/pc/djui/djui_panel_join_message.h create mode 100644 src/pc/utils/string_builder.c create mode 100644 src/pc/utils/string_builder.h diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index f14a61b4d..3238b1914 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -3948,6 +3948,7 @@ + @@ -4036,6 +4037,7 @@ + @@ -4388,6 +4390,7 @@ + @@ -4426,6 +4429,7 @@ + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index 2fde8f968..afc2678a0 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -15246,6 +15246,12 @@ Source Files\src\pc\djui\panel + + Source Files\src\pc\djui\panel + + + Source Files\src\pc\utils + @@ -16312,5 +16318,11 @@ Source Files\src\pc\djui\panel + + Source Files\src\pc\djui\panel + + + Source Files\src\pc\utils + \ No newline at end of file diff --git a/src/pc/djui/djui.h b/src/pc/djui/djui.h index b47956a6e..4e0736d85 100644 --- a/src/pc/djui/djui.h +++ b/src/pc/djui/djui.h @@ -35,6 +35,7 @@ #include "djui_panel_host.h" #include "djui_panel_host_message.h" #include "djui_panel_join.h" +#include "djui_panel_join_message.h" #include "djui_panel_options.h" #include "djui_panel_camera.h" #include "djui_panel_controls.h" diff --git a/src/pc/djui/djui_panel.c b/src/pc/djui/djui_panel.c index 1b9a3765a..962c7d7b4 100644 --- a/src/pc/djui/djui_panel.c +++ b/src/pc/djui/djui_panel.c @@ -15,6 +15,7 @@ static f32 sMoveAmount = 0; void djui_panel_add(struct DjuiBase* caller, struct DjuiBase* panelBase, struct DjuiBase* defaultElementBase) { bool firstPanel = (sPanelList == NULL); + gDjuiPanelJoinMessageVisible = false; // remember element that triggered this panel add if (sPanelList != NULL) { @@ -76,6 +77,8 @@ void djui_panel_back(void) { // play a sound play_sound(SOUND_MENU_CLICK_FILE_SELECT, gDefaultSoundArgs); + + gDjuiPanelJoinMessageVisible = false; } void djui_panel_update(void) { @@ -130,5 +133,7 @@ void djui_panel_shutdown(void) { sPanelRemoving = NULL; sMoveAmount = 0; gInteractableOverridePad = false; + gDjuiPanelJoinMessageVisible = false; + gDjuiPanelMainCreated = false; djui_cursor_set_visible(false); } \ No newline at end of file diff --git a/src/pc/djui/djui_panel_join.c b/src/pc/djui/djui_panel_join.c index 4d442499e..3c45adeb9 100644 --- a/src/pc/djui/djui_panel_join.c +++ b/src/pc/djui/djui_panel_join.c @@ -16,9 +16,9 @@ Enter \\#d0d0ff\\direct connection\\#c8c8c8\\ IP and port:\ "; void djui_panel_join_do_join(struct DjuiBase* caller) { - djui_panel_shutdown(); network_set_system(NS_SOCKET); network_init(NT_CLIENT); + djui_panel_join_message_create(caller); } void djui_panel_join_create(struct DjuiBase* caller) { diff --git a/src/pc/djui/djui_panel_join_message.c b/src/pc/djui/djui_panel_join_message.c new file mode 100644 index 000000000..8a1ddb530 --- /dev/null +++ b/src/pc/djui/djui_panel_join_message.c @@ -0,0 +1,75 @@ +#include "djui.h" +#include "src/pc/network/network.h" +#include "src/pc/utils/misc.h" +#include "src/pc/configfile.h" + +#define DJUI_JOIN_MESSAGE_ELAPSE 60 +bool gDjuiPanelJoinMessageVisible = false; +static struct DjuiText* sPanelText = NULL; +static bool sDisplayingError = false; + +void djui_panel_join_message_error(char* message) { + djui_panel_join_message_create(NULL); + sDisplayingError = true; + djui_text_set_text(sPanelText, message); +} + +void djui_panel_join_message_cancel(struct DjuiBase* caller) { + network_shutdown(true); + djui_panel_menu_back(caller); +} + +void djui_panel_join_message_render_pre(struct DjuiBase* base, UNUSED bool* unused) { + if (sDisplayingError) { return; } + struct DjuiText* text1 = (struct DjuiText*)base; + u16 lastElapse = (base->tag / DJUI_JOIN_MESSAGE_ELAPSE); + base->tag = (base->tag + 1) % (DJUI_JOIN_MESSAGE_ELAPSE * 3); + u16 elapse = (base->tag / DJUI_JOIN_MESSAGE_ELAPSE); + if (lastElapse != elapse) { + switch (base->tag / DJUI_JOIN_MESSAGE_ELAPSE) { + case 0: djui_text_set_text(text1, "..."); break; + case 1: djui_text_set_text(text1, "."); break; + default: djui_text_set_text(text1, ".."); break; + } + } +} + +void djui_panel_join_message_create(struct DjuiBase* caller) { + // make sure main panel was created + if (!gDjuiPanelMainCreated) { djui_panel_main_create(caller); } + + // don't recreate panel if it's already visible + if (gDjuiPanelJoinMessageVisible) { return; } + + f32 bodyHeight = 64 + 16; + + u16 directLines = 8; + f32 directTextHeight = 32 * 0.8125f * directLines + 8; + bodyHeight += directTextHeight + 16; + + struct DjuiBase* defaultBase = NULL; + struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\J\\#1be700\\O\\#00b3ff\\I\\#ffef00\\N\\#1be700\\I\\#00b3ff\\N\\#ffef00\\G"); + struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel); + { + struct DjuiText* text1 = djui_text_create(&body->base, "..."); + djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&text1->base, 1.0f, directTextHeight); + djui_base_set_color(&text1->base, 200, 200, 200, 255); + djui_text_set_alignment(text1, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + text1->base.tag = 0; + text1->base.on_render_pre = djui_panel_join_message_render_pre; + sPanelText = text1; + + struct DjuiButton* button1 = djui_button_create(&body->base, "Cancel"); + djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&button1->base, 1.0f, 64); + djui_base_set_alignment(&button1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP); + djui_button_set_style(button1, 1); + djui_interactable_hook_click(&button1->base, djui_panel_join_message_cancel); + defaultBase = &button1->base; + } + + djui_panel_add(caller, &panel->base, defaultBase); + gDjuiPanelJoinMessageVisible = true; + sDisplayingError = false; +} diff --git a/src/pc/djui/djui_panel_join_message.h b/src/pc/djui/djui_panel_join_message.h new file mode 100644 index 000000000..2a6d7d5b5 --- /dev/null +++ b/src/pc/djui/djui_panel_join_message.h @@ -0,0 +1,7 @@ +#pragma once +#include "djui.h" + +extern bool gDjuiPanelJoinMessageVisible; + +void djui_panel_join_message_error(char* message); +void djui_panel_join_message_create(struct DjuiBase* caller); diff --git a/src/pc/djui/djui_panel_main.c b/src/pc/djui/djui_panel_main.c index 795a0e13b..5c2622186 100644 --- a/src/pc/djui/djui_panel_main.c +++ b/src/pc/djui/djui_panel_main.c @@ -1,6 +1,8 @@ #include "djui.h" #include "src/pc/controller/controller_sdl.h" +bool gDjuiPanelMainCreated = false; + void djui_panel_main_create(struct DjuiBase* caller) { f32 bodyHeight = 64 * 4 + 16 * 3; @@ -43,4 +45,5 @@ void djui_panel_main_create(struct DjuiBase* caller) { djui_panel_add(caller, &panel->base, defaultBase); gInteractableOverridePad = true; + gDjuiPanelMainCreated = true; } diff --git a/src/pc/djui/djui_panel_main.h b/src/pc/djui/djui_panel_main.h index c96a1b7e3..e15eeea67 100644 --- a/src/pc/djui/djui_panel_main.h +++ b/src/pc/djui/djui_panel_main.h @@ -1,4 +1,6 @@ #pragma once #include "djui.h" +extern bool gDjuiPanelMainCreated; + void djui_panel_main_create(struct DjuiBase* caller); diff --git a/src/pc/network/discord/discord.c b/src/pc/network/discord/discord.c index 430ad38ae..014efc8f7 100644 --- a/src/pc/network/discord/discord.c +++ b/src/pc/network/discord/discord.c @@ -148,7 +148,7 @@ static bool ns_discord_initialize(enum NetworkType networkType) { DISCORD_REQUIRE(rc); } else if (rc) { LOG_ERROR("DiscordCreate failed: %d", rc); - djui_show_popup("Could not detect Discord.\n\nTry closing the game,\nrestarting Discord,\nand opening the game again."); + djui_show_popup("\\#ffa0a0\\Error:\\#c8c8c8\\ Could not detect Discord.\n\nTry closing the game, restarting Discord, and opening the game again."); gDiscordFailed = true; return false; } diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 8c97e69dd..79594db34 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -262,12 +262,12 @@ void network_register_mod(char* modName) { string_linked_list_append(&gRegisteredMods, modName); } -void network_shutdown(void) { +void network_shutdown(bool sendLeaving) { network_forget_all_reliable(); if (gNetworkType == NT_NONE) { return; } if (gNetworkSystem == NULL) { LOG_ERROR("no network system attached"); return; } - if (gNetworkPlayerLocal != NULL) { network_send_leaving(gNetworkPlayerLocal->globalIndex); } + if (gNetworkPlayerLocal != NULL && sendLeaving) { network_send_leaving(gNetworkPlayerLocal->globalIndex); } network_player_shutdown(); gNetworkSystem->shutdown(); diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 60b4e7ded..99e114ee4 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -99,7 +99,7 @@ void network_send(struct Packet* p); void network_receive(u8 localIndex, u8* data, u16 dataLength); void network_update(void); void network_register_mod(char* modName); -void network_shutdown(void); +void network_shutdown(bool sendLeaving); // TODO: replace void chat_add_message(char* message); diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c index 70025721b..0ae0653d5 100644 --- a/src/pc/network/network_player.c +++ b/src/pc/network/network_player.c @@ -106,7 +106,7 @@ void network_player_update(void) { } } if (!connectionAlive) { - network_shutdown(); + network_shutdown(true); } } #endif @@ -194,7 +194,7 @@ u8 network_player_disconnected(u8 globalIndex) { LOG_ERROR("player disconnected, but it's local.. this shouldn't happen!"); return UNKNOWN_GLOBAL_INDEX; } else { - network_shutdown(); + network_shutdown(true); } } diff --git a/src/pc/network/packets/packet.c b/src/pc/network/packets/packet.c index 8510da5c8..56a4c0bdb 100644 --- a/src/pc/network/packets/packet.c +++ b/src/pc/network/packets/packet.c @@ -72,8 +72,11 @@ void packet_receive(struct Packet* p) { 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); + if (gNetworkType == NT_SERVER && p->localIndex == UNKNOWN_LOCAL_INDEX && packetType != PACKET_JOIN_REQUEST && packetType != PACKET_ACK) { + if (packetType != PACKET_PLAYER) { + LOG_INFO("closing connection for packetType: %d", packetType); + network_send_kick(EKT_CLOSE_CONNECTION); + } return; } diff --git a/src/pc/network/packets/packet_join.c b/src/pc/network/packets/packet_join.c index 84754ec28..173eadf6b 100644 --- a/src/pc/network/packets/packet_join.c +++ b/src/pc/network/packets/packet_join.c @@ -10,10 +10,11 @@ #include "src/pc/fs/fs.h" #include "PR/os_eeprom.h" #include "pc/network/version.h" +#include "pc/djui/djui.h" +#include "pc/utils/string_builder.h" #define DISABLE_MODULE_LOG 1 #include "pc/debuglog.h" - extern u8* gOverrideEeprom; static u8 eeprom[512] = { 0 }; @@ -108,17 +109,11 @@ void network_receive_join(struct Packet* p) { packet_read(p, &remoteVersion, sizeof(u8) * MAX_VERSION_LENGTH); LOG_INFO("server has version: %s", version); if (memcmp(version, remoteVersion, MAX_VERSION_LENGTH) != 0) { + network_shutdown(true); LOG_ERROR("version mismatch"); - - // todo: hack: remove me in the future - // needed because the old style only had 8 characters for the version - if (strcmp("beta", remoteVersion) != 0) { - remoteVersion[8] = '\0'; - } - - char mismatchMessage[128] = { 0 }; - snprintf(mismatchMessage, 128, "Version mismatch.\n\nYour version - %s\nTheir version - %s\n\nSomeone is out of date!\n", version, remoteVersion); - djui_show_popup(mismatchMessage); + char mismatchMessage[256] = { 0 }; + snprintf(mismatchMessage, 256, "\\#ffa0a0\\Error:\\#c8c8c8\\ Version mismatch.\n\nYour version: \\#a0a0ff\\%s\\#c8c8c8\\\nTheir version: \\#a0a0ff\\%s\\#c8c8c8\\\n\nSomeone is out of date!\n", version, remoteVersion); + djui_panel_join_message_error(mismatchMessage); return; } @@ -142,8 +137,36 @@ void network_receive_join(struct Packet* p) { } if (string_linked_list_mismatch(&gRegisteredMods, &head)) { + network_shutdown(true); + + struct StringBuilder* builder = string_builder_create(512); + string_builder_append(builder, "\\#ffa0a0\\Error:\\#c8c8c8\\ mods don't match.\n\n"); + + string_builder_append(builder, "\\#c8c8c8\\Yours: "); + struct StringLinkedList* node = &gRegisteredMods; + bool first = true; + while (node != NULL) { + string_builder_append(builder, first ? "\\#%s\\%s" : ", \\#%s\\%s", + string_linked_list_contains(&head, node->string) ? "a0ffa0" : "ffa0a0" + , node->string); + first = false; + node = node->next; + } + + string_builder_append(builder, "\n\n\\#c8c8c8\\Theirs: "); + node = &head; + first = true; + while (node != NULL) { + string_builder_append(builder, first ? "\\#%s\\%s" : ", \\#%s\\%s", + string_linked_list_contains(&gRegisteredMods, node->string) ? "a0ffa0" : "ffa0a0" + , node->string); + first = false; + node = node->next; + } + + djui_panel_join_message_error(builder->string); + string_builder_destroy(builder); string_linked_list_free(&head); - djui_show_popup("Your mods don't match!"); return; } string_linked_list_free(&head); @@ -153,6 +176,7 @@ void network_receive_join(struct Packet* p) { save_file_load_all(TRUE); + djui_panel_shutdown(); extern s16 gChangeLevel; gChangeLevel = 16; } diff --git a/src/pc/network/packets/packet_kick.c b/src/pc/network/packets/packet_kick.c index 57d9da47a..53c8c5d7b 100644 --- a/src/pc/network/packets/packet_kick.c +++ b/src/pc/network/packets/packet_kick.c @@ -1,6 +1,7 @@ #include #include "../network.h" #include "pc/debuglog.h" +#include "pc/djui/djui.h" void network_send_kick(enum KickReasonType kickReason) { u8 kickReasonType = kickReason; @@ -26,8 +27,8 @@ void network_receive_kick(struct Packet* p) { enum KickReasonType kickReason = kickReasonType; switch (kickReason) { - case EKT_FULL_PARTY: djui_show_popup("The party is full."); break; - default: djui_show_popup("Host has closed the connection."); break; + case EKT_FULL_PARTY: djui_panel_join_message_error("\\#ffa0a0\\Error:\\#c8c8c8\\ The party is full."); break; + default: djui_panel_join_message_error("\\#ffa0a0\\Error:\\#c8c8c8\\ Host has closed the connection."); break; } - network_shutdown(); + network_shutdown(false); } diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 18eff5ce1..67ea52450 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -158,7 +158,7 @@ void game_deinit(void) { controller_shutdown(); audio_shutdown(); gfx_shutdown(); - network_shutdown(); + network_shutdown(true); inited = false; } diff --git a/src/pc/utils/string_builder.c b/src/pc/utils/string_builder.c new file mode 100644 index 000000000..6e829bbe9 --- /dev/null +++ b/src/pc/utils/string_builder.c @@ -0,0 +1,16 @@ +#include +#include +#include "string_builder.h" + +struct StringBuilder* string_builder_create(int bufferLength) { + struct StringBuilder* builder = malloc(sizeof(struct StringBuilder)); + builder->string = malloc(sizeof(char) * bufferLength); + builder->string[0] = '\0'; + builder->bufferLength = bufferLength; + return builder; +} + +void string_builder_destroy(struct StringBuilder* builder) { + free(builder->string); + free(builder); +} diff --git a/src/pc/utils/string_builder.h b/src/pc/utils/string_builder.h new file mode 100644 index 000000000..da6084e00 --- /dev/null +++ b/src/pc/utils/string_builder.h @@ -0,0 +1,15 @@ +#ifndef STRING_BUILDER_H +#define STRING_BUILDER_H + +#include + +struct StringBuilder { + char* string; + int bufferLength; +}; + +struct StringBuilder* string_builder_create(int bufferLength); +#define string_builder_append(_builder, ...) snprintf((_builder->string + strlen(_builder->string)), (_builder->bufferLength - strlen(_builder->string)), __VA_ARGS__) +void string_builder_destroy(struct StringBuilder* builder); + +#endif \ No newline at end of file