From 9bad513abba7b1a1b4ad201b9df14b169cf51761 Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sat, 21 Feb 2026 22:31:59 -0600 Subject: [PATCH 01/12] Sorting in coopnet lobbies, have mode prioritize gamemode, other improvements --- bin/custom_textures.c | 8 + lang/English.ini | 5 + src/pc/configfile.c | 4 + src/pc/configfile.h | 2 + src/pc/djui/djui_panel_join_lobbies.c | 165 +++++++++++++++++- src/pc/djui/djui_panel_join_lobbies.h | 23 +++ src/pc/mods/mods.c | 7 + .../custom_selectionbox_down_icon.rgba16.png | Bin 0 -> 1741 bytes .../custom_selectionbox_up_icon.rgba16.png | Bin 0 -> 1738 bytes 9 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 textures/segment2/custom_selectionbox_down_icon.rgba16.png create mode 100644 textures/segment2/custom_selectionbox_up_icon.rgba16.png diff --git a/bin/custom_textures.c b/bin/custom_textures.c index 8136a1fcb..7ec6e78bc 100644 --- a/bin/custom_textures.c +++ b/bin/custom_textures.c @@ -31,6 +31,14 @@ ALIGNED8 const Texture texture_selectionbox_forward_icon[] = { #include "textures/segment2/custom_selectionbox_forward_icon.rgba16.inc.c" }; +ALIGNED8 const Texture texture_selectionbox_up_icon[] = { +#include "textures/segment2/custom_selectionbox_up_icon.rgba16.inc.c" +}; + +ALIGNED8 const Texture texture_selectionbox_down_icon[] = { +#include "textures/segment2/custom_selectionbox_down_icon.rgba16.inc.c" +}; + ALIGNED8 const Texture texture_coopdx_logo[] = { #include "textures/segment2/custom_coopdx_logo.rgba32.inc.c" }; diff --git a/lang/English.ini b/lang/English.ini index 14ec1d462..d0e44db51 100644 --- a/lang/English.ini +++ b/lang/English.ini @@ -431,6 +431,11 @@ REFRESHING = "Refreshing..." ENTER_PASSWORD = "Enter the private lobby's password:" SEARCH = "Search" NO_LOBBIES_FOUND = "No lobbies were found." +SORT_BY = "Sort By" +SORTING_NONE = "None" +SORTING_NAME = "Name" +SORTING_GAMEMODE = "Gamemode" +SORTING_PLAYERS = "Players" [CHANGELOG] CHANGELOG_TITLE = "CHANGELOG" diff --git a/src/pc/configfile.c b/src/pc/configfile.c index f2267a7db..8f23905c1 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -174,6 +174,8 @@ unsigned int configHostSaveSlot = 1; char configJoinIp[MAX_CONFIG_STRING] = ""; unsigned int configJoinPort = DEFAULT_PORT; unsigned int configNetworkSystem = 0; +unsigned int configCoopNetSortSelected = 0; +bool configCoopNetSortInverted = false; unsigned int configPlayerInteraction = 1; unsigned int configPlayerKnockbackStrength = 25; unsigned int configStayInLevelAfterStar = 0; @@ -333,6 +335,8 @@ static const struct ConfigOption options[] = { {.name = "coop_join_ip", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configJoinIp, .maxStringLength = MAX_CONFIG_STRING}, {.name = "coop_join_port", .type = CONFIG_TYPE_UINT, .uintValue = &configJoinPort}, {.name = "coop_network_system", .type = CONFIG_TYPE_UINT, .uintValue = &configNetworkSystem}, + {.name = "coop_coop_net_sort_selected", .type = CONFIG_TYPE_UINT, .uintValue = &configCoopNetSortSelected}, + {.name = "coop_coop_net_sort_inverted", .type = CONFIG_TYPE_BOOL, .uintValue = &configCoopNetSortInverted}, {.name = "coop_player_interaction", .type = CONFIG_TYPE_UINT, .uintValue = &configPlayerInteraction}, {.name = "coop_player_knockback_strength", .type = CONFIG_TYPE_UINT, .uintValue = &configPlayerKnockbackStrength}, {.name = "coop_stay_in_level_after_star", .type = CONFIG_TYPE_UINT, .uintValue = &configStayInLevelAfterStar}, diff --git a/src/pc/configfile.h b/src/pc/configfile.h index d537970e4..8374097cb 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -139,6 +139,8 @@ extern unsigned int configHostSaveSlot; extern char configJoinIp[MAX_CONFIG_STRING]; extern unsigned int configJoinPort; extern unsigned int configNetworkSystem; +extern unsigned int configCoopNetSortSelected; +extern bool configCoopNetSortInverted; extern unsigned int configPlayerInteraction; extern unsigned int configPlayerKnockbackStrength; extern unsigned int configStayInLevelAfterStar; diff --git a/src/pc/djui/djui_panel_join_lobbies.c b/src/pc/djui/djui_panel_join_lobbies.c index bc0d7514f..6005c8da8 100644 --- a/src/pc/djui/djui_panel_join_lobbies.c +++ b/src/pc/djui/djui_panel_join_lobbies.c @@ -3,6 +3,7 @@ #include "djui_panel.h" #include "djui_panel_menu.h" #include "djui_panel_join_message.h" +#include "djui_panel_join_lobbies.h" #include "djui_lobby_entry.h" #include "djui_panel_rules.h" #include "pc/network/network.h" @@ -17,13 +18,85 @@ #define DJUI_DESC_PANEL_WIDTH (410.0f + (16 * 2.0f)) +extern ALIGNED8 u8 texture_selectionbox_up_icon[]; +extern ALIGNED8 u8 texture_selectionbox_down_icon[]; + +static struct LobbySortType sLobbySorting[] = { + { + "SORTING_NONE", + LOBBY_SORTING_NONE, + }, + { + "SORTING_NAME", + LOBBY_SORTING_NAME, + }, + { + "SORTING_GAMEMODE", + LOBBY_SORTING_GAMEMODE, + }, + { + "SORTING_PLAYERS", + LOBBY_SORTING_PLAYERS, + }, +}; +static const int numSortOptions = sizeof(sLobbySorting) / sizeof(sLobbySorting[0]); + +static struct CoopnetLobby** sCoopnetLobbies = NULL; +static unsigned int sCoopnetLobbyCount = 0; + static struct DjuiPaginated* sLobbyPaginated = NULL; static struct DjuiFlowLayout* sLobbyLayout = NULL; static struct DjuiButton* sRefreshButton = NULL; static struct DjuiThreePanel* sDescriptionPanel = NULL; static struct DjuiText* sTooltip = NULL; +static struct DjuiSelectionbox* sSelectionbox = NULL; +static struct DjuiImage* sSortInvertImage = NULL; +static unsigned int sSavedLobbyStartCount = 0; + static char* sPassword = NULL; +static void free_coopnet_lobbies() { + for (unsigned int i = 0; i < sCoopnetLobbyCount; i++) + { + struct CoopnetLobby* lobby = sCoopnetLobbies[i]; + if (!lobby) { continue; } + free(lobby->playerText); + free(lobby->hostName); + free(lobby->mode); + free(lobby->description); + free(lobby); + } + + free(sCoopnetLobbies); + sCoopnetLobbies = NULL; + sCoopnetLobbyCount = 0; +} + +static int sort_coopnet_lobby_comp(const void* a, const void* b) { + const struct CoopnetLobby* lobbyA = *(const struct CoopnetLobby**)a; + const struct CoopnetLobby* lobbyB = *(const struct CoopnetLobby**)b; + + int retValue = 0; + enum LobbySorting sortBy = sLobbySorting[configCoopNetSortSelected].sortType; + if (sortBy == LOBBY_SORTING_NAME) { + retValue = strcmp(lobbyA->hostName, lobbyB->hostName); + } else if (sortBy == LOBBY_SORTING_GAMEMODE) { + retValue = strcmp(lobbyA->mode, lobbyB->mode); + } else if (sortBy == LOBBY_SORTING_PLAYERS) { + retValue = lobbyA->playerCount - lobbyB->playerCount; + } else if (sortBy == LOBBY_SORTING_NONE) { + retValue = lobbyA->lobbyId > lobbyB->lobbyId ? 1 : -1; + } + + retValue *= configCoopNetSortInverted ? -1 : 1; + if (lobbyA->disabled != lobbyB->disabled) { + retValue = lobbyA->disabled ? 1 : -1; + } else if (retValue == 0) { + retValue = lobbyA->lobbyId > lobbyB->lobbyId ? 1 : -1; + } + return retValue; +} + static void djui_panel_join_lobby_description_create(void) { f32 bodyHeight = 600; @@ -56,6 +129,7 @@ static void djui_panel_join_lobby_description_create(void) { sDescriptionPanel = panel; } + static void djui_lobby_on_hover(struct DjuiBase* base) { struct DjuiLobbyEntry* entry = (struct DjuiLobbyEntry*)base; djui_text_set_text(sTooltip, entry->description); @@ -74,6 +148,22 @@ void djui_panel_join_lobby(struct DjuiBase* caller) { djui_panel_join_message_create(caller); } +static void djui_panel_join_on_sorting_change(UNUSED struct DjuiBase* base) { + qsort(sCoopnetLobbies, sCoopnetLobbyCount, sizeof(sCoopnetLobbies[0]), sort_coopnet_lobby_comp); + djui_base_destroy_children(&sLobbyLayout->base); + for (unsigned int i = 0; i < sCoopnetLobbyCount; i++) { + struct CoopnetLobby* lobby = sCoopnetLobbies[i]; + struct DjuiLobbyEntry* entry = djui_lobby_entry_create(&sLobbyLayout->base, lobby->hostName, lobby->mode, lobby->playerText, lobby->description, lobby->disabled, djui_panel_join_lobby, djui_lobby_on_hover, djui_lobby_on_hover_end); + entry->base.tag = (s64)lobby->lobbyId; + } +} + +static void djui_panel_join_invert_sort(UNUSED struct DjuiBase* caller) { + configCoopNetSortInverted = !configCoopNetSortInverted; + sSortInvertImage->textureInfo.texture = configCoopNetSortInverted ? texture_selectionbox_up_icon : texture_selectionbox_down_icon; + djui_panel_join_on_sorting_change(NULL); +} + void djui_panel_join_query(uint64_t aLobbyId, UNUSED uint64_t aOwnerId, uint16_t aConnections, uint16_t aMaxConnections, UNUSED const char* aGame, const char* aVersion, const char* aHostName, const char* aMode, const char* aDescription) { if (!sLobbyLayout) { return; } if (!sLobbyPaginated) { return; } @@ -82,7 +172,6 @@ void djui_panel_join_query(uint64_t aLobbyId, UNUSED uint64_t aOwnerId, uint16_t char playerText[64] = ""; snprintf(playerText, 63, "%u/%u", aConnections, aMaxConnections); - char mode[64] = ""; snprintf(mode, 64, "%s", aMode); @@ -93,16 +182,47 @@ void djui_panel_join_query(uint64_t aLobbyId, UNUSED uint64_t aOwnerId, uint16_t snprintf(mode, 64, "\\#ff0000\\[%s]", aVersion); } - struct DjuiBase* layoutBase = &sLobbyLayout->base; - struct DjuiLobbyEntry* entry = djui_lobby_entry_create(layoutBase, (char*)aHostName, (char*)mode, playerText, (char*)aDescription, disabled, djui_panel_join_lobby, djui_lobby_on_hover, djui_lobby_on_hover_end); - entry->base.tag = (s64)aLobbyId; - djui_paginated_update_page_buttons(sLobbyPaginated); + struct CoopnetLobby* lobby = malloc(sizeof(struct CoopnetLobby)); + + if (!lobby) { + LOG_ERROR("Failed to allocate memory to lobby!"); + return; + } + + lobby->lobbyId = aLobbyId; + lobby->playerCount = aConnections; + lobby->playerText = strdup(playerText); + lobby->hostName = strdup(aHostName); + lobby->mode = strdup(mode); + lobby->description = strdup(aDescription); + lobby->disabled = disabled; + + struct CoopnetLobby** lobbies = realloc(sCoopnetLobbies, (sCoopnetLobbyCount + 1) * sizeof(struct CoopnetLobby*)); + if (!lobbies) { + LOG_ERROR("Failed to reallocate memory to lobbies!"); + return; + } + sCoopnetLobbies = lobbies; + sCoopnetLobbies[sCoopnetLobbyCount] = lobby; + sCoopnetLobbyCount++; } void djui_panel_join_query_finish(void) { if (!sLobbyLayout) { return; } if (!sLobbyPaginated) { return; } if (!sRefreshButton) { return; } + + qsort(sCoopnetLobbies, sCoopnetLobbyCount, sizeof(sCoopnetLobbies[0]), sort_coopnet_lobby_comp); + + djui_base_destroy_children(&sLobbyLayout->base); + djui_base_set_enabled(&sLobbyLayout->base, true); + struct DjuiBase* layoutBase = &sLobbyLayout->base; + for (unsigned int i = 0; i < sCoopnetLobbyCount; i++) { + struct CoopnetLobby* lobby = sCoopnetLobbies[i]; + struct DjuiLobbyEntry* entry = djui_lobby_entry_create(layoutBase, lobby->hostName, lobby->mode, lobby->playerText, lobby->description, lobby->disabled, djui_panel_join_lobby, djui_lobby_on_hover, djui_lobby_on_hover_end); + entry->base.tag = (s64)lobby->lobbyId; + } + djui_text_set_text(sRefreshButton->text, DLANG(LOBBIES, REFRESH)); djui_base_set_enabled(&sRefreshButton->base, true); @@ -113,7 +233,9 @@ void djui_panel_join_query_finish(void) { djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); djui_text_set_drop_shadow(text, 64, 64, 64, 100); } + sLobbyPaginated->startIndex = sSavedLobbyStartCount; djui_paginated_update_page_buttons(sLobbyPaginated); + djui_panel_join_on_sorting_change(NULL); } void djui_panel_join_lobbies_on_destroy(UNUSED struct DjuiBase* caller) { @@ -122,6 +244,8 @@ void djui_panel_join_lobbies_on_destroy(UNUSED struct DjuiBase* caller) { sRefreshButton = NULL; sLobbyLayout = NULL; sLobbyPaginated = NULL; + sSavedLobbyStartCount = 0; + free_coopnet_lobbies(); if (sDescriptionPanel != NULL) { djui_base_destroy(&sDescriptionPanel->base); @@ -130,10 +254,18 @@ void djui_panel_join_lobbies_on_destroy(UNUSED struct DjuiBase* caller) { } void djui_panel_join_lobbies_refresh(UNUSED struct DjuiBase* caller) { + sSavedLobbyStartCount = sLobbyPaginated->startIndex; + djui_base_set_enabled(&sLobbyLayout->base, false); djui_base_destroy_children(&sLobbyLayout->base); + for (unsigned int i = 0; i < sCoopnetLobbyCount; i++) { + struct CoopnetLobby* lobby = sCoopnetLobbies[i]; + struct DjuiLobbyEntry* entry = djui_lobby_entry_create(&sLobbyLayout->base, lobby->hostName, lobby->mode, lobby->playerText, lobby->description, true, djui_panel_join_lobby, djui_lobby_on_hover, djui_lobby_on_hover_end); + entry->base.tag = (s64)lobby->lobbyId; + } djui_text_set_text(sRefreshButton->text, DLANG(LOBBIES, REFRESHING)); djui_base_set_enabled(&sRefreshButton->base, false); djui_paginated_update_page_buttons(sLobbyPaginated); + free_coopnet_lobbies(); ns_coopnet_query(djui_panel_join_query, djui_panel_join_query_finish, sPassword); } @@ -142,6 +274,9 @@ void djui_panel_join_lobbies_value_changed(UNUSED struct DjuiBase* caller) { } void djui_panel_join_lobbies_create(struct DjuiBase* caller, const char* password) { + if (configCoopNetSortSelected > numSortOptions) { + configCoopNetSortSelected = numSortOptions; + } if (sPassword) { free(sPassword); sPassword = NULL; } sPassword = strdup(password); bool private = (strlen(password) > 0); @@ -158,6 +293,26 @@ void djui_panel_join_lobbies_create(struct DjuiBase* caller, const char* passwor true); struct DjuiBase* body = djui_three_panel_get_body(panel); { + char* sortChoices[sizeof(sLobbySorting)]; + for (int i = 0; i < numSortOptions; i++) { + sortChoices[i] = djui_language_get("LOBBIES", sLobbySorting[i].langKey); + } + struct DjuiFlowLayout* flowLayout = djui_flow_layout_create(body); + djui_base_set_color(&flowLayout->base, 0, 0, 0, 0); + djui_base_set_size_type(&flowLayout->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&flowLayout->base, 1.0f, 32.0f); + sSelectionbox = djui_selectionbox_create(&flowLayout->base, DLANG(LOBBIES, SORT_BY), sortChoices, numSortOptions, &configCoopNetSortSelected, djui_panel_join_on_sorting_change); + djui_base_set_size(&sSelectionbox->base, 0.925, 32); + struct DjuiButton* button = djui_button_create(&flowLayout->base, "", DJUI_BUTTON_STYLE_NORMAL, djui_panel_join_invert_sort); + djui_base_set_alignment(&button->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM); + djui_base_set_size_type(&button->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&button->base, 32, 32); + sSortInvertImage = djui_image_create(&button->base, configCoopNetSortInverted ? texture_selectionbox_up_icon : texture_selectionbox_down_icon, 16, 16, G_IM_FMT_RGBA, G_IM_SIZ_16b); + djui_base_set_size(&sSortInvertImage->base, 16, 16); + djui_base_set_alignment(&sSortInvertImage->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + djui_flow_layout_set_margin(flowLayout, 16); + djui_flow_layout_set_flow_direction(flowLayout, DJUI_FLOW_DIR_RIGHT); + sLobbyPaginated = djui_paginated_create(body, 10); sLobbyLayout = sLobbyPaginated->layout; djui_flow_layout_set_margin(sLobbyLayout, 4); diff --git a/src/pc/djui/djui_panel_join_lobbies.h b/src/pc/djui/djui_panel_join_lobbies.h index cda56f95e..2e9921b08 100644 --- a/src/pc/djui/djui_panel_join_lobbies.h +++ b/src/pc/djui/djui_panel_join_lobbies.h @@ -1,3 +1,26 @@ #pragma once +enum LobbySorting { + LOBBY_SORTING_NONE, + LOBBY_SORTING_NAME, + LOBBY_SORTING_GAMEMODE, + LOBBY_SORTING_PLAYERS, + LOBBY_SORTING_COUNT, +}; + +struct LobbySortType { + const char* langKey; + enum LobbySorting sortType; +}; + +struct CoopnetLobby { + uint64_t lobbyId; + int playerCount; + char* hostName; + char* mode; + char* playerText; + char* description; + bool disabled; +}; + void djui_panel_join_lobbies_create(struct DjuiBase* caller, const char* password); diff --git a/src/pc/mods/mods.c b/src/pc/mods/mods.c index 9af7ab2b3..9f0d662ab 100644 --- a/src/pc/mods/mods.c +++ b/src/pc/mods/mods.c @@ -35,6 +35,13 @@ void mods_get_main_mod_name(char* destination, u32 maxSize) { for (u16 i = 0; i < gLocalMods.entryCount; i++) { struct Mod* mod = gLocalMods.entries[i]; if (!mod->enabled) { continue; } + LOG_CONSOLE("%s", mod->category) + // always make gamemodes the main mod + if ((mod->category && strcmp(mod->category, "gamemode") == 0) + || (mod->incompatible && strcmp(mod->incompatible, "gamemode") == 0)) { + picked = mod; + break; + } size_t size = mod_get_lua_size(mod); if (size > pickedSize) { picked = mod; diff --git a/textures/segment2/custom_selectionbox_down_icon.rgba16.png b/textures/segment2/custom_selectionbox_down_icon.rgba16.png new file mode 100644 index 0000000000000000000000000000000000000000..ac6be8ddbd4004d60edc46f9fb2cfaca26ab9f76 GIT binary patch literal 1741 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKU|E?N5>XQ2>tmIipR1RclAn~S zSCLx)lxJYDv9BmdOwLX%QAkQn&&;z`dcS+Wl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3 za#eP+Wr~u$9hXgo70`g()RIJnirk#MVyg;UC9t_xKsHENUr7P1q$Jx`DZ)2E!8yMu zRl!uxRL?-kj!VI&C?(A*$i)q+8OXC$$|xx*u+rBrFE7_CH`dE9O4m2Ew6xSWFw!?N z(gmu}Ew0QfNvzP#D^>;>0WrfRwK%ybv!En1KTiQQ?NYIsRz8p8Cv zVyO3l0ih3)(KpmH&_`CDT9JuEIY&Q`ZIv9;(lUYZQ>kFA zXP^fO0l3ogj8vd8xILv0b&@_PtHIo4qmSWg8?XYTyb06?5d-FVVBw(;FFk-9c=?l> z2P|}ofTc_9C81^p2FAurV0>W20|SG`#L|i9wOs;5j@uhMKXE^y!QJf{!ONSKw7AFQ z%96|;qZ?=T{9KxL?DbxA&uyp5x`d?ni~V8EnYuN|#p~K86|)zX=Yy4J7F&O>dH4NZ z@viSN1#ZP&aqB-h?n}s+m~g;YdiLilHV>EZn(JOUCK@Zt+wL5)WxKRY*q&EgvqJ5@ zufM7uyo;$X>YhnlH4Rw;i~KPb;^+~FEk}B!`A%!|915}IhhTs%~=-w zI%pEVYhfC*o%gbz`|@YaXMeD(eY2BgeI|cfoU8uSt?OblqM9dv-Zbq-)8*2P{lSl; z{zMmbT3^nruxmOdu_eyw?w-4w=hyP(EAG;YFJ-)KeL?y8Y_WX|V$;$O`n^a=09F&6 z1s;*b3=G`DAk4@xYmNj^(ALw%F~p+x?U|i|3<^BVj^E=a?y?SQ3$HlgurW{h-#cF+ zhI8T$LH|o9WWG_jUD0~uBZp;Qw2J6;539Nq*4Qf{7q)CVHXmpZgQu&X%Q~loCIFqR BR6+m% literal 0 HcmV?d00001 diff --git a/textures/segment2/custom_selectionbox_up_icon.rgba16.png b/textures/segment2/custom_selectionbox_up_icon.rgba16.png new file mode 100644 index 0000000000000000000000000000000000000000..6bc6269442c94b8123a2d1a54ecbf28fc006b4ee GIT binary patch literal 1738 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKU|E?N5>XQ2>tmIipR1RclAn~S zSCLx)lxJYDv9BmdOwLX%QAkQn&&;z`dcS+Wl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3 za#eP+Wr~u$9hXgo70`g()RIJnirk#MVyg;UC9t_xKsHENUr7P1q$Jx`DZ)2E!8yMu zRl!uxRL?-kj!VI&C?(A*$i)q+8OXC$$|xx*u+rBrFE7_CH`dE9O4m2Ew6xSWFw!?N z(gmu}Ew0QfNvzP#D^>;>0WrfRwK%ybv!En1KTiQQ?NYIsRz8p8Cv zVyO3l0ih3)(KpmH&_`CDT9JuEIY&Q`ZIv9;(lUYZQ>kFA zXP^fO0l3ogj8vd8xILv0b&@_PtHIo4qmSWg8?XYTyb06?5d-FVVBw(;FFk-9c=?l> z2P|}ofTfFlLF`cm2FAurV0>W20|SG`#L|i9wOs;5j@uhMKXE^y!QJf{!ONSKw7AFQ z%96|;qZ?=T{9KxL?DbxA&uyp5x`d?ni~V8EnYuN|#p~K86|)zX=Yy4J7F&O>dH4NZ z@viSN1#ZP&aqB-h?n}s+m~g;YdiLilHV>EZn(JOUCK@Zt+wL5)WxKRY*q&EgvqJ5@ zufM7uyo;$X>YhnlH4Rw;i~KPb;^+~FEk}B!`A%!|915}IhhTs%~=-w zI%pEVYhfC*o%gbz`|@YaXMeD(eY2BgeI|cfoU8uSt?OblqM9dv-Zbq-)8*2P{lSl; z{zMmbT3^nruxmOdu_eyw?w-4w=hyP(EAG;YFJ-)KeL?y8Y_WX|V$;$O`n^a=09F&6 z1s;*b3=G`DAk4@xYmNj^(8|-rF~p+xZQn*-1_hqOfBw7v)$^GuA>f<1wmiCRp^DNM yRqso|Dya=+Dbt0mizdB2;j5?ImouNoR_vu^$b}VM%Jx807(8A5T-G@yGywpH=}?^j literal 0 HcmV?d00001 From 694de51b8ce766a8cd3d89254471c7a7887b1374 Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sat, 21 Feb 2026 22:35:54 -0600 Subject: [PATCH 02/12] Orient player sorting properly --- src/pc/djui/djui_panel_join_lobbies.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pc/djui/djui_panel_join_lobbies.c b/src/pc/djui/djui_panel_join_lobbies.c index 6005c8da8..75df9178f 100644 --- a/src/pc/djui/djui_panel_join_lobbies.c +++ b/src/pc/djui/djui_panel_join_lobbies.c @@ -83,7 +83,7 @@ static int sort_coopnet_lobby_comp(const void* a, const void* b) { } else if (sortBy == LOBBY_SORTING_GAMEMODE) { retValue = strcmp(lobbyA->mode, lobbyB->mode); } else if (sortBy == LOBBY_SORTING_PLAYERS) { - retValue = lobbyA->playerCount - lobbyB->playerCount; + retValue = lobbyB->playerCount - lobbyA->playerCount; } else if (sortBy == LOBBY_SORTING_NONE) { retValue = lobbyA->lobbyId > lobbyB->lobbyId ? 1 : -1; } From 3f69f13be12a454897dcf37168e2c32342958c47 Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sat, 21 Feb 2026 22:39:43 -0600 Subject: [PATCH 03/12] remove dbg --- src/pc/mods/mods.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pc/mods/mods.c b/src/pc/mods/mods.c index 9f0d662ab..9d7191abd 100644 --- a/src/pc/mods/mods.c +++ b/src/pc/mods/mods.c @@ -35,7 +35,6 @@ void mods_get_main_mod_name(char* destination, u32 maxSize) { for (u16 i = 0; i < gLocalMods.entryCount; i++) { struct Mod* mod = gLocalMods.entries[i]; if (!mod->enabled) { continue; } - LOG_CONSOLE("%s", mod->category) // always make gamemodes the main mod if ((mod->category && strcmp(mod->category, "gamemode") == 0) || (mod->incompatible && strcmp(mod->incompatible, "gamemode") == 0)) { From e6e92aea29dfae6a3aa1ac77ed608f40f727370b Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sat, 21 Feb 2026 22:45:12 -0600 Subject: [PATCH 04/12] Update lang name --- lang/English.ini | 8 ++++---- src/pc/djui/djui_panel_join_lobbies.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lang/English.ini b/lang/English.ini index d0e44db51..3aeb58d31 100644 --- a/lang/English.ini +++ b/lang/English.ini @@ -432,10 +432,10 @@ ENTER_PASSWORD = "Enter the private lobby's password:" SEARCH = "Search" NO_LOBBIES_FOUND = "No lobbies were found." SORT_BY = "Sort By" -SORTING_NONE = "None" -SORTING_NAME = "Name" -SORTING_GAMEMODE = "Gamemode" -SORTING_PLAYERS = "Players" +NONE = "None" +NAME = "Name" +GAMEMODE = "Gamemode" +PLAYERS = "Players" [CHANGELOG] CHANGELOG_TITLE = "CHANGELOG" diff --git a/src/pc/djui/djui_panel_join_lobbies.c b/src/pc/djui/djui_panel_join_lobbies.c index 75df9178f..3cc73c93b 100644 --- a/src/pc/djui/djui_panel_join_lobbies.c +++ b/src/pc/djui/djui_panel_join_lobbies.c @@ -23,19 +23,19 @@ extern ALIGNED8 u8 texture_selectionbox_down_icon[]; static struct LobbySortType sLobbySorting[] = { { - "SORTING_NONE", + "NONE", LOBBY_SORTING_NONE, }, { - "SORTING_NAME", + "NAME", LOBBY_SORTING_NAME, }, { - "SORTING_GAMEMODE", + "GAMEMODE", LOBBY_SORTING_GAMEMODE, }, { - "SORTING_PLAYERS", + "PLAYERS", LOBBY_SORTING_PLAYERS, }, }; From d2b781b37b7ff4b2d8f2a4dc6b14f116946a7841 Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sun, 22 Feb 2026 14:08:37 -0600 Subject: [PATCH 05/12] Add languages, prioritize romhacks aswell when selecting mode text --- lang/French.ini | 5 +++++ lang/German.ini | 5 +++++ lang/Italian.ini | 5 +++++ lang/Russian.ini | 5 +++++ src/pc/mods/mods.c | 7 +++++++ 5 files changed, 27 insertions(+) diff --git a/lang/French.ini b/lang/French.ini index b0dfe3be2..08c5bef6d 100644 --- a/lang/French.ini +++ b/lang/French.ini @@ -431,6 +431,11 @@ REFRESHING = "Actualisation..." ENTER_PASSWORD = "Entrez le mot de passe de la partie:" SEARCH = "Rechercher" NO_LOBBIES_FOUND = "Aucune partie n'a été trouvée." +SORT_BY = "Trier par" +NONE = "Aucun" +NAME = "Pseudo" +GAMEMODE = "Mode de jeu" +PLAYERS = "Joueurs" [CHANGELOG] CHANGELOG_TITLE = "MODIFICATIONS" diff --git a/lang/German.ini b/lang/German.ini index 46d0bf440..7d09ce1ff 100644 --- a/lang/German.ini +++ b/lang/German.ini @@ -431,6 +431,11 @@ REFRESHING = "Aktualisiere..." ENTER_PASSWORD = "Gebe das Lobby-Passwort ein:" SEARCH = "Suchen" NO_LOBBIES_FOUND = "Keine Lobbys gefunden." +SORT_BY = "Sortieren nach" +NONE = "Keine" +NAME = "Name" +GAMEMODE = "Spielmodus" +PLAYERS = "Spieler" [CHANGELOG] CHANGELOG_TITLE = "ÄNDERUNGSPROTOKOLL" diff --git a/lang/Italian.ini b/lang/Italian.ini index e0827a2f6..4fc917652 100644 --- a/lang/Italian.ini +++ b/lang/Italian.ini @@ -429,6 +429,11 @@ REFRESHING = "Ricaricando..." ENTER_PASSWORD = "Scrivi la password della stanza privata:" SEARCH = "Cerca" NO_LOBBIES_FOUND = "Non è stata trovata alcuna stanza." +SORT_BY = "Ordina per" +NONE = "Nulla" +NAME = "Nome" +GAMEMODE = "Modalità di gioco" +PLAYERS = "Giocatori" [CHANGELOG] CHANGELOG_TITLE = "REGISTRO DELLE MODIFICHE" diff --git a/lang/Russian.ini b/lang/Russian.ini index 52861a4cf..d26da9921 100644 --- a/lang/Russian.ini +++ b/lang/Russian.ini @@ -430,6 +430,11 @@ REFRESHING = "Обновление..." ENTER_PASSWORD = "Введите пароль закрытой группы:" SEARCH = "Поиск" NO_LOBBIES_FOUND = "Группы не найдены." +SORT_BY = "Сортировка" +NONE = "Нет" +NAME = "По имени" +GAMEMODE = "По игровому режиму" +PLAYERS = "По игрокам" [CHANGELOG] CHANGELOG_TITLE = "ЖУРНАЛ ИЗМЕНЕНИЙ" diff --git a/src/pc/mods/mods.c b/src/pc/mods/mods.c index 9d7191abd..bccafa30b 100644 --- a/src/pc/mods/mods.c +++ b/src/pc/mods/mods.c @@ -29,6 +29,7 @@ struct LocalEnabledPath { struct LocalEnabledPath* sLocalEnabledPaths = NULL; void mods_get_main_mod_name(char* destination, u32 maxSize) { + struct Mod* selectedRomhack = NULL; struct Mod* picked = NULL; size_t pickedSize = 0; @@ -41,6 +42,11 @@ void mods_get_main_mod_name(char* destination, u32 maxSize) { picked = mod; break; } + // prioritize romhacks + if ((mod->category && strcmp(mod->category, "romhack") == 0) + || (mod->incompatible && strcmp(mod->incompatible, "romhack") == 0)) { + selectedRomhack = mod; + } size_t size = mod_get_lua_size(mod); if (size > pickedSize) { picked = mod; @@ -48,6 +54,7 @@ void mods_get_main_mod_name(char* destination, u32 maxSize) { } } + if (selectedRomhack) { picked = selectedRomhack; } snprintf(destination, maxSize, "%s", picked ? picked->name : "Super Mario 64"); } From 4497aad826e08c372e9d17bb32fe4aabd902a964 Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sun, 22 Feb 2026 14:20:30 -0600 Subject: [PATCH 06/12] Add portuguese --- lang/Portuguese.ini | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lang/Portuguese.ini b/lang/Portuguese.ini index e935499a6..42c240758 100644 --- a/lang/Portuguese.ini +++ b/lang/Portuguese.ini @@ -412,7 +412,7 @@ MUTE_FOCUS_LOSS = "Silenciar quando a janela estiver desfocada" [LANGUAGE] LANGUAGE = "IDIOMA" -Czech = "Tcheco (Čeština)" +Czech = "Tcheco (Čeština)" Dutch = "Holandês (Nederlands)" French = "Francês (Français)" German = "Alemão (Deutsch)" @@ -431,6 +431,11 @@ REFRESHING = "Recarregando..." ENTER_PASSWORD = "Digite a senha da sala privada:" SEARCH = "Pesquisar" NO_LOBBIES_FOUND = "Nenhuma sala encontrada." +SORT_BY = "Sortieren nach" +NONE = "Keine" +NAME = "Name" +GAMEMODE = "Spielmodus" +PLAYERS = "Spieler" [CHANGELOG] CHANGELOG_TITLE = "ALTERAÇÕES" From 032f2c3d1e4107b00702f6b480f7b4d21bef7a1c Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sun, 22 Feb 2026 14:51:54 -0600 Subject: [PATCH 07/12] Add spanish and dutch translations --- lang/Dutch.ini | 5 +++++ lang/Spanish.ini | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/lang/Dutch.ini b/lang/Dutch.ini index a06530f8b..0e2e49de5 100644 --- a/lang/Dutch.ini +++ b/lang/Dutch.ini @@ -431,6 +431,11 @@ REFRESHING = "herladen..." ENTER_PASSWORD = "Typ het wachtwoord van de privé lobby:" SEARCH = "Zoek" NO_LOBBIES_FOUND = "Er zijn geen lobby's gevonden." +SORT_BY = "Sorteer op" +NONE = "Geen" +NAME = "Naam" +GAMEMODE = "Spelmodus" +PLAYERS = "Spelers" [CHANGELOG] CHANGELOG_TITLE = "WIJZIGINGENLOGBOEK" diff --git a/lang/Spanish.ini b/lang/Spanish.ini index f083c8ba2..d8fd35902 100644 --- a/lang/Spanish.ini +++ b/lang/Spanish.ini @@ -431,6 +431,11 @@ REFRESHING = "Refrescando..." ENTER_PASSWORD = "Escribe la contraseña de la partida privada:" SEARCH = "Buscar" NO_LOBBIES_FOUND = "No se han encontrado partidas." +SORT_BY = "Ordenar por" +NONE = "Nada" +NAME = "Nombre" +GAMEMODE = "Modo de juego" +PLAYERS = "Jugadores" [CHANGELOG] CHANGELOG_TITLE = "REGISTRO DE CAMBIOS" From 30c312dac5773ad1308c1ca498c3d8569de59c41 Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sun, 22 Feb 2026 14:57:46 -0600 Subject: [PATCH 08/12] Update russian translation to allow gamemode to fit --- lang/Russian.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/Russian.ini b/lang/Russian.ini index d26da9921..dc8583f9a 100644 --- a/lang/Russian.ini +++ b/lang/Russian.ini @@ -433,7 +433,7 @@ NO_LOBBIES_FOUND = "Группы не найдены." SORT_BY = "Сортировка" NONE = "Нет" NAME = "По имени" -GAMEMODE = "По игровому режиму" +GAMEMODE = "По режиму игры" PLAYERS = "По игрокам" [CHANGELOG] From 0b51aadf64066c68b28bd236e68eebabc24f1654 Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sun, 22 Feb 2026 15:24:59 -0600 Subject: [PATCH 09/12] Add Japenese, revert Russian lang change, make selectionbox big --- lang/Japanese.ini | 5 +++++ lang/Russian.ini | 2 +- src/pc/djui/djui_panel_join_lobbies.c | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lang/Japanese.ini b/lang/Japanese.ini index 322c449e8..f36ed03fb 100644 --- a/lang/Japanese.ini +++ b/lang/Japanese.ini @@ -434,6 +434,11 @@ ENTER_PASSWORD = "部屋のパスワードを入力してください:" SEARCH = "検索" NONE_FOUND = "部屋が見つかりませんでした" NO_LOBBIES_FOUND = "ロビーは見つからなかった。" +SORT_BY = "並べ替え" +NONE = "なし" +NAME = "名前" +GAMEMODE = "ゲームモード" +PLAYERS = "プレイヤ" [CHANGELOG] CHANGELOG_TITLE = "CHANGELOG" diff --git a/lang/Russian.ini b/lang/Russian.ini index dc8583f9a..d26da9921 100644 --- a/lang/Russian.ini +++ b/lang/Russian.ini @@ -433,7 +433,7 @@ NO_LOBBIES_FOUND = "Группы не найдены." SORT_BY = "Сортировка" NONE = "Нет" NAME = "По имени" -GAMEMODE = "По режиму игры" +GAMEMODE = "По игровому режиму" PLAYERS = "По игрокам" [CHANGELOG] diff --git a/src/pc/djui/djui_panel_join_lobbies.c b/src/pc/djui/djui_panel_join_lobbies.c index 3cc73c93b..4cb947b17 100644 --- a/src/pc/djui/djui_panel_join_lobbies.c +++ b/src/pc/djui/djui_panel_join_lobbies.c @@ -303,6 +303,7 @@ void djui_panel_join_lobbies_create(struct DjuiBase* caller, const char* passwor djui_base_set_size(&flowLayout->base, 1.0f, 32.0f); sSelectionbox = djui_selectionbox_create(&flowLayout->base, DLANG(LOBBIES, SORT_BY), sortChoices, numSortOptions, &configCoopNetSortSelected, djui_panel_join_on_sorting_change); djui_base_set_size(&sSelectionbox->base, 0.925, 32); + djui_base_set_size(&sSelectionbox->rect->base, 0.55, 1); struct DjuiButton* button = djui_button_create(&flowLayout->base, "", DJUI_BUTTON_STYLE_NORMAL, djui_panel_join_invert_sort); djui_base_set_alignment(&button->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM); djui_base_set_size_type(&button->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); From 5ae56adbd94fd7d477efd2077092f171dd3c4884 Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sun, 22 Feb 2026 15:41:07 -0600 Subject: [PATCH 10/12] update japanese translation --- lang/Japanese.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/Japanese.ini b/lang/Japanese.ini index f36ed03fb..185a58cfa 100644 --- a/lang/Japanese.ini +++ b/lang/Japanese.ini @@ -438,7 +438,7 @@ SORT_BY = "並べ替え" NONE = "なし" NAME = "名前" GAMEMODE = "ゲームモード" -PLAYERS = "プレイヤ" +PLAYERS = "プレイヤー" [CHANGELOG] CHANGELOG_TITLE = "CHANGELOG" From cf0604872a4e0429595ae446338d2ac6baa4ab5e Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:08:03 -0600 Subject: [PATCH 11/12] Update japenese (again) --- lang/Japanese.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/Japanese.ini b/lang/Japanese.ini index 185a58cfa..727c28cf0 100644 --- a/lang/Japanese.ini +++ b/lang/Japanese.ini @@ -438,7 +438,7 @@ SORT_BY = "並べ替え" NONE = "なし" NAME = "名前" GAMEMODE = "ゲームモード" -PLAYERS = "プレイヤー" +PLAYERS = "プレイヤー数" [CHANGELOG] CHANGELOG_TITLE = "CHANGELOG" From 4cd6349e4c5756fc6a7554c54e1a2105296c9d7e Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Tue, 24 Feb 2026 14:14:14 -0600 Subject: [PATCH 12/12] Add czech language using google translate --- lang/Czech.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lang/Czech.ini b/lang/Czech.ini index ddf7ae547..e3288b251 100644 --- a/lang/Czech.ini +++ b/lang/Czech.ini @@ -431,6 +431,11 @@ REFRESHING = "Obnovování..." ENTER_PASSWORD = "Zadejte heslo soukromé hry:" SEARCH = "Hledat" NO_LOBBIES_FOUND = "Nebyly nalezeny žádné hry." +SORT_BY = "Seřadit podle" +NONE = "Žádné" +NAME = "Jméno" +GAMEMODE = "Herní mód" +PLAYERS = "Hráči" [CHANGELOG] CHANGELOG_TITLE = "ZÁZNAM ZMĚN"