From ed06b57649ade5daad4b731e0bda1f1f9aa36062 Mon Sep 17 00:00:00 2001 From: MysterD Date: Sun, 4 Oct 2020 16:41:55 -0700 Subject: [PATCH] Added mod registration system Allows mods to register themselves so that mismatches don't occur. This does not automagically detect when someone modified the game, so the mods will have to insert a function like this into their patch: static void __attribute__((constructor)) _register_this_mod() { network_register_mod("mod name here"); } --- Makefile | 2 +- build-windows-visual-studio/sm64ex.vcxproj | 2 + .../sm64ex.vcxproj.filters | 9 +++ src/menu/custom_menu.c | 4 +- src/menu/custom_menu.h | 2 +- src/pc/network/network.c | 7 +- src/pc/network/network.h | 3 + src/pc/network/packets/packet_join.c | 34 ++++++++- src/pc/utils/string_linked_list.c | 73 +++++++++++++++++++ src/pc/utils/string_linked_list.h | 15 ++++ 10 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 src/pc/utils/string_linked_list.c create mode 100644 src/pc/utils/string_linked_list.h diff --git a/Makefile b/Makefile index 74008f711..c919f2eb0 100644 --- a/Makefile +++ b/Makefile @@ -308,7 +308,7 @@ LEVEL_DIRS := $(patsubst levels/%,%,$(dir $(wildcard levels/*/header.h))) # Hi, I'm a PC SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers actors levels bin data assets src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes -SRC_DIRS += src/pc/network src/pc/network/packets src/pc/network/socket +SRC_DIRS += src/pc/network src/pc/network/packets src/pc/network/socket src/pc/utils ASM_DIRS := #ifeq ($(DISCORDRPC),1) diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index 3fa8f31f1..e066021fe 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -3986,6 +3986,7 @@ + @@ -4338,6 +4339,7 @@ + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index d30786582..033a6c51f 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -3433,6 +3433,9 @@ {7fd7fed2-3f22-4bbf-a118-8ff54107c341} + + {451cd85d-8a2c-4aa5-87c7-d1415974ba96} + @@ -15069,6 +15072,9 @@ Source Files\src\pc\network\packets + + Source Files\src\pc\utils + @@ -16021,5 +16027,8 @@ Header Files\src\pc\network + + Source Files\src\pc\utils + \ No newline at end of file diff --git a/src/menu/custom_menu.c b/src/menu/custom_menu.c index d905e95a8..ec9619dac 100644 --- a/src/menu/custom_menu.c +++ b/src/menu/custom_menu.c @@ -282,8 +282,8 @@ void custom_menu_goto_game(s16 saveFileNum) { sGotoGame = saveFileNum; } -void custom_menu_version_mismatch(void) { +void custom_menu_connection_error(char* message) { play_sound(SOUND_MARIO_MAMA_MIA, gDefaultSoundArgs); - strcpy(sConnectionJoinError, "Your versions don't match, both should rebuild!"); + strcpy(sConnectionJoinError, message); network_shutdown(); } diff --git a/src/menu/custom_menu.h b/src/menu/custom_menu.h index 69b734709..b3cb7cebc 100644 --- a/src/menu/custom_menu.h +++ b/src/menu/custom_menu.h @@ -8,6 +8,6 @@ void custom_menu_init(struct CustomMenu* head); void custom_menu_loop(void); void custom_menu_on_load_save_file(s8 saveFileNum); void custom_menu_goto_game(s16 saveFileNum); -void custom_menu_version_mismatch(void); +void custom_menu_connection_error(char* message); #endif // CUSTOM_MENU_H diff --git a/src/pc/network/network.c b/src/pc/network/network.c index bb5818e48..fc17e35f7 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -23,13 +23,13 @@ struct NetworkSystem* gNetworkSystem = &gNetworkSystemSocket; u8 networkLoadingLevel = 0; bool gNetworkLevelLoaded = false; clock_t gLastNetworkSend = 0; +struct StringLinkedList gRegisteredMods = { 0 }; struct ServerSettings gServerSettings = { .playerInteractions = PLAYER_INTERACTIONS_SOLID, .playerKnockbackStrength = 25, }; - void network_set_system(enum NetworkSystemType nsType) { switch (nsType) { case NS_SOCKET: gNetworkSystem = &gNetworkSystemSocket; break; @@ -176,6 +176,11 @@ void network_update(void) { } } +void network_register_mod(char* modName) { + if (string_linked_list_contains(&gRegisteredMods, modName)) { return; } + string_linked_list_append(&gRegisteredMods, modName); +} + void network_shutdown(void) { network_forget_all_reliable(); if (gNetworkType == NT_NONE) { return; } diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 2f78e41dd..5ad600d4f 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -7,6 +7,7 @@ #include #include "network_player.h" #include "packets/packet.h" +#include "pc/utils/string_linked_list.h" #include "../cliopts.h" #define SET_BIT(val, num) ((((u8)(val)) & 0x01) << (num)); @@ -81,6 +82,7 @@ extern bool gNetworkLevelLoaded; extern struct SyncObject gSyncObjects[]; extern struct ServerSettings gServerSettings; extern clock_t gLastNetworkSend; +extern struct StringLinkedList gRegisteredMods; // network.c void network_set_system(enum NetworkSystemType nsType); @@ -91,6 +93,7 @@ void network_send_to(u8 localIndex, struct Packet* p); 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); #endif diff --git a/src/pc/network/packets/packet_join.c b/src/pc/network/packets/packet_join.c index 17165896b..bc9da5b15 100644 --- a/src/pc/network/packets/packet_join.c +++ b/src/pc/network/packets/packet_join.c @@ -60,6 +60,20 @@ void network_send_join(struct Packet* joinRequestPacket) { packet_write(&p, &gServerSettings.playerKnockbackStrength, sizeof(u8)); packet_write(&p, &gServerSettings.stayInLevelAfterStar, sizeof(u8)); packet_write(&p, eeprom, sizeof(u8) * 512); + + u8 modCount = string_linked_list_count(&gRegisteredMods); + packet_write(&p, &modCount, sizeof(u8)); + + struct StringLinkedList* node = &gRegisteredMods; + char nullchar = '\0'; + while (node != NULL && node->string != NULL) { + int length = strlen(node->string); + packet_write(&p, node->string, sizeof(char) * length); + packet_write(&p, &nullchar, sizeof(char)); + LOG_INFO("sending registered mod: %s", node->string); + node = node->next; + } + network_send_to(joinRequestPacket->localIndex , &p); LOG_INFO("sending join packet"); @@ -73,6 +87,7 @@ void network_receive_join(struct Packet* p) { char hash[HASH_LENGTH] = GIT_HASH; char remoteHash[HASH_LENGTH] = { 0 }; u8 myGlobalIndex = UNKNOWN_GLOBAL_INDEX; + u8 modCount = 0; if (gNetworkPlayerLocal != NULL && gNetworkPlayerLocal->connected) { LOG_ERROR("Received join packet, but already in-game!"); @@ -82,7 +97,7 @@ void network_receive_join(struct Packet* p) { // verify version packet_read(p, &remoteHash, sizeof(u8) * HASH_LENGTH); if (memcmp(hash, remoteHash, HASH_LENGTH) != 0) { - custom_menu_version_mismatch(); + custom_menu_connection_error("Your versions don't match, both should rebuild!"); return; } @@ -92,6 +107,23 @@ void network_receive_join(struct Packet* p) { packet_read(p, &gServerSettings.playerKnockbackStrength, sizeof(u8)); packet_read(p, &gServerSettings.stayInLevelAfterStar, sizeof(u8)); packet_read(p, eeprom, sizeof(u8) * 512); + packet_read(p, &modCount, sizeof(u8)); + + struct StringLinkedList head = { 0 }; + for (int i = 0; i < modCount; i++) { + char* modName = (char*) &p->buffer[p->cursor]; + int length = strlen(modName); + LOG_INFO("host has mod: %s", modName); + string_linked_list_append(&head, modName); + p->cursor += length + 1; + } + + if (string_linked_list_mismatch(&gRegisteredMods, &head)) { + string_linked_list_free(&head); + custom_menu_connection_error("Your mods don't match!"); + return; + } + string_linked_list_free(&head); network_player_connected(NPT_SERVER, 0); network_player_connected(NPT_LOCAL, myGlobalIndex); diff --git a/src/pc/utils/string_linked_list.c b/src/pc/utils/string_linked_list.c new file mode 100644 index 000000000..ef795aea5 --- /dev/null +++ b/src/pc/utils/string_linked_list.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include "string_linked_list.h" + +void string_linked_list_append(struct StringLinkedList* node, char* string) { + int length = strlen(string); + while (1) { + if (node->string == NULL) { + node->string = malloc(sizeof(char) * (length + 1)); + memset(node->string, 0, sizeof(char) * (length + 1)); + strncpy(node->string, string, length); + return; + } + if (node->next == NULL) { + node->next = malloc(sizeof(struct StringLinkedList)); + memset(node->next, 0, sizeof(struct StringLinkedList)); + } + node = node->next; + } +} + +bool string_linked_list_contains(struct StringLinkedList* node, char* string) { + int length1 = strlen(string); + while (node != NULL && node->string != NULL) { + int length2 = strlen(node->string); + if (length1 == length2 && (strcmp(string, node->string) == 0)) { + return true; + } + node = node->next; + } + return false; +} + +bool string_linked_list_mismatch(struct StringLinkedList* a, struct StringLinkedList* b) { + struct StringLinkedList* a1 = a; + while (a1 != NULL && a1->string != NULL) { + if (!string_linked_list_contains(b, a1->string)) { return true; } + a1 = a1->next; + } + + struct StringLinkedList* b1 = b; + while (b1 != NULL && b1->string != NULL) { + if (!string_linked_list_contains(a, b1->string)) { return true; } + b1 = b1->next; + } + + return false; +} + +int string_linked_list_count(struct StringLinkedList* node) { + int count = 0; + while (node != NULL) { + if (node->string != NULL) { + count++; + } + node = node->next; + } + return count; +} + +void string_linked_list_free(struct StringLinkedList* node) { + struct StringLinkedList* head = node; + struct StringLinkedList* prevNode = head; + while (node != NULL) { + if (node->string != NULL) { free(node->string); } + node = node->next; + if (prevNode != NULL && prevNode != head) { free(prevNode); } + prevNode = node; + } + + if (prevNode != NULL && prevNode != head) { free(prevNode); } +} diff --git a/src/pc/utils/string_linked_list.h b/src/pc/utils/string_linked_list.h new file mode 100644 index 000000000..30f3f4869 --- /dev/null +++ b/src/pc/utils/string_linked_list.h @@ -0,0 +1,15 @@ +#ifndef STRING_LINKED_LIST_H +#define STRING_LINKED_LIST_H + +struct StringLinkedList { + char* string; + struct StringLinkedList* next; +}; + +void string_linked_list_append(struct StringLinkedList* node, char* string); +bool string_linked_list_contains(struct StringLinkedList* node, char* string); +bool string_linked_list_mismatch(struct StringLinkedList* a, struct StringLinkedList* b); +int string_linked_list_count(struct StringLinkedList* node); +void string_linked_list_free(struct StringLinkedList* node); + +#endif \ No newline at end of file