Allowed enabling/disabling of mods through the UI

This commit is contained in:
MysterD 2022-01-23 15:45:42 -08:00
parent 79a659781c
commit fe11e25e0b
17 changed files with 356 additions and 202 deletions

View file

@ -466,7 +466,9 @@
<ClCompile Include="..\src\pc\djui\djui_panel_controls.c" /> <ClCompile Include="..\src\pc\djui\djui_panel_controls.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_host.c" /> <ClCompile Include="..\src\pc\djui\djui_panel_host.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_host_message.c" /> <ClCompile Include="..\src\pc\djui\djui_panel_host_message.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_host_mods.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_host_save.c" /> <ClCompile Include="..\src\pc\djui\djui_panel_host_save.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_host_settings.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_join.c" /> <ClCompile Include="..\src\pc\djui\djui_panel_join.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_join_message.c" /> <ClCompile Include="..\src\pc\djui\djui_panel_join_message.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_menu.c" /> <ClCompile Include="..\src\pc\djui\djui_panel_menu.c" />
@ -931,7 +933,9 @@
<ClInclude Include="..\src\pc\djui\djui_panel_controls.h" /> <ClInclude Include="..\src\pc\djui\djui_panel_controls.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_host.h" /> <ClInclude Include="..\src\pc\djui\djui_panel_host.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_host_message.h" /> <ClInclude Include="..\src\pc\djui\djui_panel_host_message.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_host_mods.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_host_save.h" /> <ClInclude Include="..\src\pc\djui\djui_panel_host_save.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_host_settings.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_join.h" /> <ClInclude Include="..\src\pc\djui\djui_panel_join.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_join_message.h" /> <ClInclude Include="..\src\pc\djui\djui_panel_join_message.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_menu.h" /> <ClInclude Include="..\src\pc\djui\djui_panel_menu.h" />

View file

@ -4854,6 +4854,12 @@
<ClCompile Include="..\src\pc\djui\djui_progress_bar.c"> <ClCompile Include="..\src\pc\djui\djui_progress_bar.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter> <Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_host_settings.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_host_mods.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\actors\common0.h"> <ClCompile Include="..\actors\common0.h">
@ -5989,5 +5995,11 @@
<ClInclude Include="..\src\pc\djui\djui_progress_bar.h"> <ClInclude Include="..\src\pc\djui\djui_progress_bar.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter> <Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_host_settings.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_host_mods.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -13,6 +13,7 @@
#include "gfx/gfx_window_manager_api.h" #include "gfx/gfx_window_manager_api.h"
#include "controller/controller_api.h" #include "controller/controller_api.h"
#include "fs/fs.h" #include "fs/fs.h"
#include "pc/mod_list.h"
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0])) #define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
@ -295,12 +296,25 @@ void configfile_load(const char *filename) {
if (numTokens >= 2) { if (numTokens >= 2) {
const struct ConfigOption *option = NULL; const struct ConfigOption *option = NULL;
// enable mods
if (!strcmp(tokens[0], "enable-mod:")) {
for (unsigned int i = 0; i < gModTableLocal.entryCount; i++) {
struct ModListEntry* entry = &gModTableLocal.entries[i];
if (!strcmp(tokens[1], entry->name)) {
entry->enabled = true;
break;
}
}
continue;
}
for (unsigned int i = 0; i < ARRAY_LEN(options); i++) { for (unsigned int i = 0; i < ARRAY_LEN(options); i++) {
if (strcmp(tokens[0], options[i].name) == 0) { if (strcmp(tokens[0], options[i].name) == 0) {
option = &options[i]; option = &options[i];
break; break;
} }
} }
if (option == NULL) if (option == NULL)
printf("unknown option '%s'\n", tokens[0]); printf("unknown option '%s'\n", tokens[0]);
else { else {
@ -384,5 +398,12 @@ void configfile_save(const char *filename) {
} }
} }
// save enabled mods
for (unsigned int i = 0; i < gModTableLocal.entryCount; i++) {
struct ModListEntry* entry = &gModTableLocal.entries[i];
if (!entry->enabled) { continue; }
fprintf(file, "%s %s\n", "enable-mod:", entry->name);
}
fclose(file); fclose(file);
} }

View file

@ -37,6 +37,8 @@
#include "djui_panel_debug.h" #include "djui_panel_debug.h"
#include "djui_panel_main.h" #include "djui_panel_main.h"
#include "djui_panel_host.h" #include "djui_panel_host.h"
#include "djui_panel_host_settings.h"
#include "djui_panel_host_mods.h"
#include "djui_panel_host_save.h" #include "djui_panel_host_save.h"
#include "djui_panel_host_message.h" #include "djui_panel_host_message.h"
#include "djui_panel_join.h" #include "djui_panel_join.h"

View file

@ -13,7 +13,6 @@
#endif #endif
struct DjuiInputbox* sInputboxPort = NULL; struct DjuiInputbox* sInputboxPort = NULL;
static unsigned int sKnockbackIndex = 0;
static void djui_panel_host_network_system_change(UNUSED struct DjuiBase* base) { static void djui_panel_host_network_system_change(UNUSED struct DjuiBase* base) {
djui_base_set_enabled(&sInputboxPort->base, DJUI_HOST_NS_IS_SOCKET); djui_base_set_enabled(&sInputboxPort->base, DJUI_HOST_NS_IS_SOCKET);
@ -40,14 +39,6 @@ static void djui_panel_host_port_text_change(struct DjuiBase* caller) {
} }
} }
static void djui_panel_host_knockback_change(UNUSED struct DjuiBase* caller) {
switch (sKnockbackIndex) {
case 0: configPlayerKnockbackStrength = 10; break;
case 1: configPlayerKnockbackStrength = 25; break;
default: configPlayerKnockbackStrength = 75; break;
}
}
static void djui_panel_host_do_host(struct DjuiBase* caller) { static void djui_panel_host_do_host(struct DjuiBase* caller) {
if (!djui_panel_host_port_valid()) { if (!djui_panel_host_port_valid()) {
djui_interactable_set_input_focus(&sInputboxPort->base); djui_interactable_set_input_focus(&sInputboxPort->base);
@ -59,11 +50,7 @@ static void djui_panel_host_do_host(struct DjuiBase* caller) {
} }
void djui_panel_host_create(struct DjuiBase* caller) { void djui_panel_host_create(struct DjuiBase* caller) {
#ifdef DISCORD_SDK f32 bodyHeight = 32 * 3 + 64 * 3 + 16 * 5;
f32 bodyHeight = 32 * 8 + 64 * 2 + 16 * 10;
#else
f32 bodyHeight = 32 * 7 + 64 * 2 + 16 * 9;
#endif
struct DjuiBase* defaultBase = NULL; struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\H\\#1be700\\O\\#00b3ff\\S\\#ffef00\\T"); struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\H\\#1be700\\O\\#00b3ff\\S\\#ffef00\\T");
@ -122,39 +109,17 @@ void djui_panel_host_create(struct DjuiBase* caller) {
djui_interactable_hook_click(&button1->base, djui_panel_host_save_create); djui_interactable_hook_click(&button1->base, djui_panel_host_save_create);
} }
char* iChoices[3] = { "Non-solid", "Solid", "Friendly Fire" }; struct DjuiButton* button1 = djui_button_create(&body->base, "Settings");
struct DjuiSelectionbox* selectionbox2 = djui_selectionbox_create(&body->base, "Player interaction", iChoices, 3, &configPlayerInteraction); djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size_type(&selectionbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size(&button1->base, 1.0f, 64);
djui_base_set_size(&selectionbox2->base, 1.0f, 32); djui_base_set_alignment(&button1->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP);
djui_interactable_hook_click(&button1->base, djui_panel_host_settings_create);
char* kChoices[3] = { "Weak", "Normal", "Too much" }; struct DjuiButton* button2 = djui_button_create(&body->base, "Mods");
sKnockbackIndex = (configPlayerKnockbackStrength <= 20) djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
? 0 djui_base_set_size(&button2->base, 1.0f, 64);
: ((configPlayerKnockbackStrength <= 40) ? 1 : 2); djui_base_set_alignment(&button2->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP);
struct DjuiSelectionbox* selectionbox3 = djui_selectionbox_create(&body->base, "Knockback strength", kChoices, 3, &sKnockbackIndex); djui_interactable_hook_click(&button2->base, djui_panel_host_mods_create);
djui_base_set_size_type(&selectionbox3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&selectionbox3->base, 1.0f, 32);
djui_interactable_hook_value_change(&selectionbox3->base, djui_panel_host_knockback_change);
struct DjuiCheckbox* checkbox1 = djui_checkbox_create(&body->base, "Stay in level after star", &configStayInLevelAfterStar);
djui_base_set_size_type(&checkbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox1->base, 1.0f, 32);
struct DjuiCheckbox* checkbox2 = djui_checkbox_create(&body->base, "Skip intro cutscene", &configSkipIntro);
djui_base_set_size_type(&checkbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox2->base, 1.0f, 32);
struct DjuiCheckbox* checkbox3 = djui_checkbox_create(&body->base, "Share lives", &configShareLives);
djui_base_set_size_type(&checkbox3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox3->base, 1.0f, 32);
struct DjuiCheckbox* checkbox4 = djui_checkbox_create(&body->base, "Enable cheats", &configEnableCheats);
djui_base_set_size_type(&checkbox4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox4->base, 1.0f, 32);
struct DjuiCheckbox* checkbox5 = djui_checkbox_create(&body->base, "Bubble on death", &configBubbleDeath);
djui_base_set_size_type(&checkbox5->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox5->base, 1.0f, 32);
struct DjuiRect* rect3 = djui_rect_create(&body->base); struct DjuiRect* rect3 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size_type(&rect3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);

View file

@ -0,0 +1,33 @@
#include <stdio.h>
#include "djui.h"
#include "game/save_file.h"
#include "pc/network/network.h"
#include "pc/utils/misc.h"
#include "pc/configfile.h"
#include "pc/cheats.h"
#include "pc/mod_list.h"
void djui_panel_host_mods_create(struct DjuiBase* caller) {
f32 bodyHeight = 32 * gModTableLocal.entryCount + 64 * 1 + 16 * (gModTableLocal.entryCount + 1);
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\M\\#1be700\\O\\#00b3ff\\D\\#ffef00\\S");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
for (int i = 0; i < gModTableLocal.entryCount; i++) {
struct ModListEntry* entry = &gModTableLocal.entries[i];
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, entry->name, &entry->enabled);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32);
}
struct DjuiButton* button1 = djui_button_create(&body->base, "Back");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 1.0f, 64);
djui_button_set_style(button1, 1);
djui_interactable_hook_click(&button1->base, djui_panel_menu_back);
defaultBase = &button1->base;
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_host_mods_create(struct DjuiBase* caller);

View file

@ -0,0 +1,69 @@
#include <stdio.h>
#include "djui.h"
#include "game/save_file.h"
#include "pc/network/network.h"
#include "pc/utils/misc.h"
#include "pc/configfile.h"
#include "pc/cheats.h"
static unsigned int sKnockbackIndex = 0;
static void djui_panel_host_settings_knockback_change(UNUSED struct DjuiBase* caller) {
switch (sKnockbackIndex) {
case 0: configPlayerKnockbackStrength = 10; break;
case 1: configPlayerKnockbackStrength = 25; break;
default: configPlayerKnockbackStrength = 75; break;
}
}
void djui_panel_host_settings_create(struct DjuiBase* caller) {
f32 bodyHeight = 32 * 7 + 64 * 1 + 16 * 7;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\S\\#1be700\\E\\#00b3ff\\T\\#ffef00\\T\\#ff0800\\I\\#1be700\\N\\#00b3ff\\G\\#ffef00\\S");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
char* iChoices[3] = { "Non-solid", "Solid", "Friendly Fire" };
struct DjuiSelectionbox* selectionbox1 = djui_selectionbox_create(&body->base, "Player interaction", iChoices, 3, &configPlayerInteraction);
djui_base_set_size_type(&selectionbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&selectionbox1->base, 1.0f, 32);
char* kChoices[3] = { "Weak", "Normal", "Too much" };
sKnockbackIndex = (configPlayerKnockbackStrength <= 20)
? 0
: ((configPlayerKnockbackStrength <= 40) ? 1 : 2);
struct DjuiSelectionbox* selectionbox2 = djui_selectionbox_create(&body->base, "Knockback strength", kChoices, 3, &sKnockbackIndex);
djui_base_set_size_type(&selectionbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&selectionbox2->base, 1.0f, 32);
djui_interactable_hook_value_change(&selectionbox2->base, djui_panel_host_settings_knockback_change);
struct DjuiCheckbox* checkbox1 = djui_checkbox_create(&body->base, "Stay in level after star", &configStayInLevelAfterStar);
djui_base_set_size_type(&checkbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox1->base, 1.0f, 32);
struct DjuiCheckbox* checkbox2 = djui_checkbox_create(&body->base, "Skip intro cutscene", &configSkipIntro);
djui_base_set_size_type(&checkbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox2->base, 1.0f, 32);
struct DjuiCheckbox* checkbox3 = djui_checkbox_create(&body->base, "Share lives", &configShareLives);
djui_base_set_size_type(&checkbox3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox3->base, 1.0f, 32);
struct DjuiCheckbox* checkbox4 = djui_checkbox_create(&body->base, "Enable cheats", &configEnableCheats);
djui_base_set_size_type(&checkbox4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox4->base, 1.0f, 32);
struct DjuiCheckbox* checkbox5 = djui_checkbox_create(&body->base, "Bubble on death", &configBubbleDeath);
djui_base_set_size_type(&checkbox5->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox5->base, 1.0f, 32);
struct DjuiButton* button1 = djui_button_create(&body->base, "Back");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 1.0f, 64);
djui_button_set_style(button1, 1);
djui_interactable_hook_click(&button1->base, djui_panel_menu_back);
defaultBase = &button1->base;
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_host_settings_create(struct DjuiBase* caller);

View file

@ -92,8 +92,10 @@ void smlua_init(void) {
// load scripts // load scripts
LOG_INFO("Loading scripts:"); LOG_INFO("Loading scripts:");
for (int i = 0; i < gModEntryCount; i++) { struct ModTable* table = (gNetworkType == NT_SERVER) ? &gModTableLocal : &gModTableRemote;
struct ModListEntry* entry = &gModEntries[i]; for (int i = 0; i < table->entryCount; i++) {
struct ModListEntry* entry = &table->entries[i];
if (!entry->enabled) { continue; }
LOG_INFO(" %s", entry->path); LOG_INFO(" %s", entry->path);
smlua_load_script(entry->path); smlua_load_script(entry->path);
} }

View file

@ -6,9 +6,8 @@
#define MAX_SESSION_CHARS 7 #define MAX_SESSION_CHARS 7
struct ModListEntry* gModEntries = NULL; struct ModTable gModTableLocal = { .entries = NULL, .entryCount = 0, .totalSize = 0, .isRemote = false };
u16 gModEntryCount = 0; struct ModTable gModTableRemote = { .entries = NULL, .entryCount = 0, .totalSize = 0, .isRemote = true };
u64 gModTotalSize = 0;
static char sTmpSession[MAX_SESSION_CHARS] = { 0 }; static char sTmpSession[MAX_SESSION_CHARS] = { 0 };
static char sTmpPath[PATH_MAX] = { 0 }; static char sTmpPath[PATH_MAX] = { 0 };
@ -18,82 +17,6 @@ static bool acceptable_file(char* string) {
return (string != NULL && !strcmp(string, ".lua")); return (string != NULL && !strcmp(string, ".lua"));
} }
void mod_list_alloc(u16 count) {
mod_list_clear();
gModEntryCount = count;
gModEntries = (struct ModListEntry*)calloc(gModEntryCount, sizeof(struct ModListEntry));
}
void mod_list_add(u16 index, char* name, size_t size, bool tmpFile) {
if (!acceptable_file(name)) { return; }
struct ModListEntry* entry = &gModEntries[index];
entry->name = name;
entry->size = size;
gModTotalSize += size;
if (tmpFile) {
snprintf(entry->path, PATH_MAX - 1, "%s/%s-%s", sTmpPath, sTmpSession, name);
} else {
snprintf(entry->path, PATH_MAX - 1, "%s/%s", MOD_PATH, name);
}
entry->fp = fopen(entry->path, tmpFile ? "wb" : "rb");
if (!tmpFile) {
fseek(entry->fp, 0, SEEK_END);
entry->size = ftell(entry->fp);
fseek(entry->fp, 0, SEEK_SET);
}
entry->complete = !tmpFile;
}
void mod_list_load(void) {
struct dirent* dir;
DIR* d = opendir(MOD_PATH);
if (!d) { closedir(d); return; }
u16 count = 0;
while ((dir = readdir(d)) != NULL) {
if (!acceptable_file(dir->d_name)) { continue; }
count++;
}
mod_list_alloc(count);
rewinddir(d);
u16 index = 0;
LOG_INFO("Loading mods:");
gModTotalSize = 0;
while ((dir = readdir(d)) != NULL) {
if (!acceptable_file(dir->d_name)) { continue; }
LOG_INFO(" %s", dir->d_name);
mod_list_add(index++, strdup(dir->d_name), 0, false);
}
closedir(d);
}
void mod_list_clear(void) {
for (int i = 0; i < gModEntryCount; i++) {
struct ModListEntry* entry = &gModEntries[i];
if (entry->name != NULL) {
free(entry->name);
entry->name = NULL;
}
if (entry->fp != NULL) {
fclose(entry->fp);
entry->fp = NULL;
}
entry->size = 0;
}
if (gModEntries != NULL) {
free(gModEntries);
gModEntries = NULL;
}
gModEntryCount = 0;
}
static void mod_list_delete_tmp(void) { static void mod_list_delete_tmp(void) {
struct dirent* dir; struct dirent* dir;
@ -122,13 +45,98 @@ static void mod_list_delete_tmp(void) {
closedir(d); closedir(d);
} }
////////////////////////////////////////////////
void mod_list_add(u16 index, char* name, size_t size, bool tmpFile) {
if (!acceptable_file(name)) { return; }
struct ModTable* table = tmpFile ? &gModTableRemote : &gModTableLocal;
struct ModListEntry* entry = &table->entries[index];
entry->name = name;
entry->size = size;
table->totalSize += size;
if (tmpFile) {
snprintf(entry->path, PATH_MAX - 1, "%s/%s-%s", sTmpPath, sTmpSession, name);
}
else {
snprintf(entry->path, PATH_MAX - 1, "%s/%s", MOD_PATH, name);
}
entry->fp = fopen(entry->path, tmpFile ? "wb" : "rb");
if (!tmpFile) {
fseek(entry->fp, 0, SEEK_END);
entry->size = ftell(entry->fp);
fseek(entry->fp, 0, SEEK_SET);
}
entry->complete = !tmpFile;
entry->enabled = false;
}
void mod_table_clear(struct ModTable* table) {
for (int i = 0; i < table->entryCount; i++) {
struct ModListEntry* entry = &table->entries[i];
if (entry->name != NULL) {
free(entry->name);
entry->name = NULL;
}
if (entry->fp != NULL) {
fclose(entry->fp);
entry->fp = NULL;
}
entry->size = 0;
}
if (table->entries != NULL) {
free(table->entries);
table->entries = NULL;
}
table->entryCount = 0;
table->totalSize = 0;
}
void mod_list_alloc(struct ModTable* table, u16 count) {
mod_table_clear(table);
table->entryCount = count;
table->entries = (struct ModListEntry*)calloc(count, sizeof(struct ModListEntry));
}
static void mod_list_load_local(void) {
struct dirent* dir;
DIR* d = opendir(MOD_PATH);
if (!d) { closedir(d); return; }
u16 count = 0;
while ((dir = readdir(d)) != NULL) {
if (!acceptable_file(dir->d_name)) { continue; }
count++;
}
mod_list_alloc(&gModTableLocal, count);
rewinddir(d);
u16 index = 0;
LOG_INFO("Loading mods:");
while ((dir = readdir(d)) != NULL) {
if (!acceptable_file(dir->d_name)) { continue; }
LOG_INFO(" %s", dir->d_name);
mod_list_add(index++, strdup(dir->d_name), 0, false);
}
closedir(d);
}
void mod_list_init(void) { void mod_list_init(void) {
snprintf(sTmpSession, MAX_SESSION_CHARS, "%06X", (u32)(rand() % 0xFFFFFF)); snprintf(sTmpSession, MAX_SESSION_CHARS, "%06X", (u32)(rand() % 0xFFFFFF));
snprintf(sTmpPath, PATH_MAX - 1, "%s", fs_get_write_path("tmp")); snprintf(sTmpPath, PATH_MAX - 1, "%s", fs_get_write_path("tmp"));
if (!fs_sys_dir_exists(sTmpPath)) { fs_sys_mkdir(sTmpPath); } if (!fs_sys_dir_exists(sTmpPath)) { fs_sys_mkdir(sTmpPath); }
mod_list_load_local();
} }
void mod_list_shutdown(void) { void mod_list_shutdown(void) {
mod_list_clear(); mod_table_clear(&gModTableLocal);
mod_table_clear(&gModTableRemote);
mod_list_delete_tmp(); mod_list_delete_tmp();
} }

View file

@ -8,24 +8,33 @@
#define MOD_PATH "./mods" #define MOD_PATH "./mods"
#pragma pack(1)
struct ModListEntry { struct ModListEntry {
char* name; char* name;
FILE* fp; FILE* fp;
char path[PATH_MAX]; char path[PATH_MAX];
size_t size; size_t size;
u64 curOffset; u64 curOffset;
u16 remoteIndex;
bool tmp; bool tmp;
bool complete; bool complete;
bool enabled;
}; };
extern struct ModListEntry* gModEntries;
extern u16 gModEntryCount;
extern u64 gModTotalSize;
void mod_list_alloc(u16 count); #pragma pack(1)
struct ModTable {
struct ModListEntry* entries;
u16 entryCount;
u8 isRemote;
u64 totalSize;
};
extern struct ModTable gModTableLocal;
extern struct ModTable gModTableRemote;
void mod_list_add(u16 index, char* name, size_t size, bool tmpFile); void mod_list_add(u16 index, char* name, size_t size, bool tmpFile);
void mod_table_clear(struct ModTable* table);
void mod_list_load(void); void mod_list_alloc(struct ModTable* table, u16 count);
void mod_list_clear(void);
void mod_list_init(void); void mod_list_init(void);
void mod_list_shutdown(void); void mod_list_shutdown(void);

View file

@ -97,7 +97,6 @@ bool network_init(enum NetworkType inNetworkType) {
gNetworkType = inNetworkType; gNetworkType = inNetworkType;
if (gNetworkType == NT_SERVER) { if (gNetworkType == NT_SERVER) {
mod_list_load();
smlua_init(); smlua_init();
network_player_connected(NPT_LOCAL, 0, configPlayerModel, configPlayerPalette, configPlayerName); network_player_connected(NPT_LOCAL, 0, configPlayerModel, configPlayerPalette, configPlayerName);

View file

@ -289,14 +289,15 @@ void network_receive_player_settings(struct Packet* p);
// packet_mod_list.c // packet_mod_list.c
void network_send_mod_list_request(void); void network_send_mod_list_request(void);
void network_receive_mod_list_request(struct Packet* p); void network_receive_mod_list_request(UNUSED struct Packet* p);
void network_send_mod_list(void); void network_send_mod_list(void);
void network_receive_mod_list(struct Packet* p); void network_receive_mod_list(struct Packet* p);
// packet_download.c // packet_download.c
void network_send_download_request(u16 index, u64 offset); void network_send_next_download_request(void);
void network_send_download_request(u16 clientIndex, u16 serverIndex, u64 offset);
void network_receive_download_request(struct Packet* p); void network_receive_download_request(struct Packet* p);
void network_send_download(u16 index, u64 offset); void network_send_download(u16 clientIndex, u16 serverIndex, u64 offset);
void network_receive_download(struct Packet* p); void network_receive_download(struct Packet* p);

View file

@ -11,32 +11,33 @@ static bool sWaitingForOffset[OFFSET_COUNT] = { 0 };
u64 sTotalDownloadBytes = 0; u64 sTotalDownloadBytes = 0;
extern float gDownloadProgress; extern float gDownloadProgress;
static void network_send_next_download_request(void) { void network_send_next_download_request(void) {
SOFT_ASSERT(gNetworkType == NT_CLIENT); SOFT_ASSERT(gNetworkType == NT_CLIENT);
for (int i = 0; i < gModEntryCount; i++) { for (int i = 0; i < gModTableRemote.entryCount; i++) {
struct ModListEntry* entry = &gModEntries[i]; struct ModListEntry* entry = &gModTableRemote.entries[i];
if (entry->complete) { continue; } if (entry->complete) { continue; }
network_send_download_request(i, entry->curOffset); network_send_download_request(i, entry->remoteIndex, entry->curOffset);
return; return;
} }
network_send_join_request(); network_send_join_request();
} }
void network_send_download_request(u16 index, u64 offset) { void network_send_download_request(u16 clientIndex, u16 serverIndex, u64 offset) {
SOFT_ASSERT(gNetworkType == NT_CLIENT); SOFT_ASSERT(gNetworkType == NT_CLIENT);
struct Packet p = { 0 }; struct Packet p = { 0 };
packet_init(&p, PACKET_DOWNLOAD_REQUEST, true, PLMT_NONE); packet_init(&p, PACKET_DOWNLOAD_REQUEST, true, PLMT_NONE);
packet_write(&p, &index, sizeof(u16)); packet_write(&p, &clientIndex, sizeof(u16));
packet_write(&p, &serverIndex, sizeof(u16));
packet_write(&p, &offset, sizeof(u64)); packet_write(&p, &offset, sizeof(u64));
if (index == 0 && offset == 0) { if (clientIndex == 0 && offset == 0) {
sTotalDownloadBytes = 0; sTotalDownloadBytes = 0;
gDownloadProgress = 0; gDownloadProgress = 0;
} }
struct ModListEntry* entry = &gModEntries[index]; struct ModListEntry* entry = &gModTableRemote.entries[clientIndex];
for (int i = 0; i < OFFSET_COUNT; i++) { for (int i = 0; i < OFFSET_COUNT; i++) {
sOffset[i] = offset + CHUNK_SIZE * i; sOffset[i] = offset + CHUNK_SIZE * i;
sWaitingForOffset[i] = (sOffset[i] < entry->size); sWaitingForOffset[i] = (sOffset[i] < entry->size);
@ -48,40 +49,42 @@ void network_send_download_request(u16 index, u64 offset) {
void network_receive_download_request(struct Packet* p) { void network_receive_download_request(struct Packet* p) {
SOFT_ASSERT(gNetworkType == NT_SERVER); SOFT_ASSERT(gNetworkType == NT_SERVER);
u16 index; u16 clientIndex;
u16 serverIndex;
u64 offset; u64 offset;
packet_read(p, &index, sizeof(u16)); packet_read(p, &clientIndex, sizeof(u16));
packet_read(p, &serverIndex, sizeof(u16));
packet_read(p, &offset, sizeof(u64)); packet_read(p, &offset, sizeof(u64));
struct ModListEntry* entry = &gModEntries[index]; struct ModListEntry* entry = &gModTableLocal.entries[serverIndex];
if (index >= gModEntryCount) { if (serverIndex >= gModTableLocal.entryCount) {
LOG_ERROR("Requested download of invalid index %u:%llu", index, offset); LOG_ERROR("Requested download of invalid index %u:%llu", serverIndex, offset);
return; return;
} }
for (int i = 0; i < OFFSET_COUNT; i++) { for (int i = 0; i < OFFSET_COUNT; i++) {
u64 o = offset + CHUNK_SIZE * i; u64 o = offset + CHUNK_SIZE * i;
if (o >= entry->size) { break; } if (o >= entry->size) { break; }
network_send_download(index, o); network_send_download(clientIndex, serverIndex, o);
} }
} }
void network_send_download(u16 index, u64 offset) { void network_send_download(u16 clientIndex, u16 serverIndex, u64 offset) {
SOFT_ASSERT(gNetworkType == NT_SERVER); SOFT_ASSERT(gNetworkType == NT_SERVER);
if (index >= gModEntryCount) { if (serverIndex >= gModTableLocal.entryCount) {
LOG_ERROR("Requested download of invalid index %u:%llu", index, offset); LOG_ERROR("Requested download of invalid index %u:%llu", serverIndex, offset);
return; return;
} }
struct ModListEntry* entry = &gModEntries[index]; struct ModListEntry* entry = &gModTableLocal.entries[serverIndex];
if (offset >= entry->size) { if (offset >= entry->size) {
LOG_ERROR("Requested download of invalid offset %u:%llu", index, offset); LOG_ERROR("Requested download of invalid offset %u:%llu", serverIndex, offset);
return; return;
} }
if (entry->fp == NULL) { if (entry->fp == NULL) {
LOG_ERROR("Requested download of invalid file pointer %u:%llu", index, offset); LOG_ERROR("Requested download of invalid file pointer %u:%llu", serverIndex, offset);
return; return;
} }
@ -97,7 +100,8 @@ void network_send_download(u16 index, u64 offset) {
struct Packet p = { 0 }; struct Packet p = { 0 };
packet_init(&p, PACKET_DOWNLOAD, true, PLMT_NONE); packet_init(&p, PACKET_DOWNLOAD, true, PLMT_NONE);
packet_write(&p, &index, sizeof(u16)); packet_write(&p, &clientIndex, sizeof(u16));
packet_write(&p, &serverIndex, sizeof(u16));
packet_write(&p, &offset, sizeof(u64)); packet_write(&p, &offset, sizeof(u64));
packet_write(&p, &chunkSize, sizeof(u16)); packet_write(&p, &chunkSize, sizeof(u16));
packet_write(&p, chunk, chunkSize * sizeof(u8)); packet_write(&p, chunk, chunkSize * sizeof(u8));
@ -112,34 +116,36 @@ void network_receive_download(struct Packet* p) {
return; return;
} }
u16 index; u16 clientIndex;
u16 serverIndex;
u64 offset; u64 offset;
u16 chunkSize; u16 chunkSize;
u8 chunk[400] = { 0 }; u8 chunk[400] = { 0 };
packet_read(p, &index, sizeof(u16)); packet_read(p, &clientIndex, sizeof(u16));
packet_read(p, &serverIndex, sizeof(u16));
packet_read(p, &offset, sizeof(u64)); packet_read(p, &offset, sizeof(u64));
packet_read(p, &chunkSize, sizeof(u16)); packet_read(p, &chunkSize, sizeof(u16));
packet_read(p, chunk, chunkSize * sizeof(u8)); packet_read(p, chunk, chunkSize * sizeof(u8));
if (index >= gModEntryCount) { if (clientIndex >= gModTableRemote.entryCount) {
LOG_ERROR("Received download of invalid index %u:%llu", index, offset); LOG_ERROR("Received download of invalid index %u:%llu", clientIndex, offset);
return; return;
} }
struct ModListEntry* entry = &gModEntries[index]; struct ModListEntry* entry = &gModTableRemote.entries[clientIndex];
if (offset >= entry->size) { if (offset >= entry->size) {
LOG_ERROR("Received download of invalid offset %u:%llu", index, offset); LOG_ERROR("Received download of invalid offset %u:%llu", clientIndex, offset);
return; return;
} }
if (entry->fp == NULL) { if (entry->fp == NULL) {
LOG_ERROR("Received download of invalid file pointer %u:%llu", index, offset); LOG_ERROR("Received download of invalid file pointer %u:%llu", clientIndex, offset);
return; return;
} }
if ((offset + chunkSize) > entry->size) { if ((offset + chunkSize) > entry->size) {
LOG_ERROR("Received download of invalid chunk size %u:%llu:%u", index, offset, chunkSize); LOG_ERROR("Received download of invalid chunk size %u:%llu:%u", clientIndex, offset, chunkSize);
return; return;
} }
@ -165,7 +171,7 @@ void network_receive_download(struct Packet* p) {
// update progress // update progress
sTotalDownloadBytes += chunkSize; sTotalDownloadBytes += chunkSize;
gDownloadProgress = (float)sTotalDownloadBytes / (float)gModTotalSize; gDownloadProgress = (float)sTotalDownloadBytes / (float)gModTableRemote.totalSize;
if (!waiting) { if (!waiting) {
// check if we're finished with this file // check if we're finished with this file

View file

@ -1,40 +1,24 @@
#include <stdio.h> #include <stdio.h>
#include "../network.h" #include "../network.h"
#include "pc/mod_list.h" #include "pc/mod_list.h"
#include "pc/djui/djui.h"
#include "pc/debuglog.h" #include "pc/debuglog.h"
void network_send_mod_list_request(void) { void network_send_mod_list_request(void) {
SOFT_ASSERT(gNetworkType == NT_CLIENT); SOFT_ASSERT(gNetworkType == NT_CLIENT);
mod_list_shutdown(); mod_table_clear(&gModTableRemote);
struct Packet p = { 0 }; struct Packet p = { 0 };
packet_init(&p, PACKET_MOD_LIST_REQUEST, true, PLMT_NONE); packet_init(&p, PACKET_MOD_LIST_REQUEST, true, PLMT_NONE);
char version[MAX_VERSION_LENGTH] = { 0 };
snprintf(version, MAX_VERSION_LENGTH, "%s", get_version());
packet_write(&p, &version, sizeof(u8) * MAX_VERSION_LENGTH);
network_send_to((gNetworkPlayerServer != NULL) ? gNetworkPlayerServer->localIndex : 0, &p); network_send_to((gNetworkPlayerServer != NULL) ? gNetworkPlayerServer->localIndex : 0, &p);
LOG_INFO("sending mod list request"); LOG_INFO("sending mod list request");
} }
void network_receive_mod_list_request(struct Packet* p) { void network_receive_mod_list_request(UNUSED struct Packet* p) {
SOFT_ASSERT(gNetworkType == NT_SERVER); SOFT_ASSERT(gNetworkType == NT_SERVER);
LOG_INFO("received mod list request"); LOG_INFO("received mod list request");
char version[MAX_VERSION_LENGTH] = { 0 };
snprintf(version, MAX_VERSION_LENGTH, "%s", get_version());
char remoteVersion[MAX_VERSION_LENGTH] = { 0 };
packet_read(p, &remoteVersion, sizeof(u8) * MAX_VERSION_LENGTH);
LOG_INFO("client has version: %s", remoteVersion);
if (memcmp(version, remoteVersion, MAX_VERSION_LENGTH) != 0) {
LOG_INFO("client version mismatch: %s != %s", remoteVersion, version);
// TODO: send version mismatch packet
return;
}
network_send_mod_list(); network_send_mod_list();
} }
@ -44,11 +28,24 @@ void network_send_mod_list(void) {
struct Packet p = { 0 }; struct Packet p = { 0 };
packet_init(&p, PACKET_MOD_LIST, true, PLMT_NONE); packet_init(&p, PACKET_MOD_LIST, true, PLMT_NONE);
packet_write(&p, &gModEntryCount, sizeof(u16)); char version[MAX_VERSION_LENGTH] = { 0 };
LOG_INFO("sent mod list (%u):", gModEntryCount); snprintf(version, MAX_VERSION_LENGTH, "%s", get_version());
for (int i = 0; i < gModEntryCount; i++) { LOG_INFO("sending version: %s", version);
struct ModListEntry* entry = &gModEntries[i]; packet_write(&p, &version, sizeof(u8) * MAX_VERSION_LENGTH);
u16 activeCount = 0;
for (u16 i = 0; i < gModTableLocal.entryCount; i++) {
struct ModListEntry* entry = &gModTableLocal.entries[i];
if (entry->enabled) { activeCount++; }
}
packet_write(&p, &activeCount, sizeof(u16));
LOG_INFO("sent mod list (%u):", gModTableLocal.entryCount);
for (u16 i = 0; i < gModTableLocal.entryCount; i++) {
struct ModListEntry* entry = &gModTableLocal.entries[i];
if (!entry->enabled) { continue; }
u16 nameLength = strlen(entry->name); u16 nameLength = strlen(entry->name);
packet_write(&p, &i, sizeof(u16));
packet_write(&p, &nameLength, sizeof(u16)); packet_write(&p, &nameLength, sizeof(u16));
packet_write(&p, entry->name, sizeof(u8) * nameLength); packet_write(&p, entry->name, sizeof(u8) * nameLength);
packet_write(&p, &entry->size, sizeof(u16)); packet_write(&p, &entry->size, sizeof(u16));
@ -60,7 +57,7 @@ void network_send_mod_list(void) {
void network_receive_mod_list(struct Packet* p) { void network_receive_mod_list(struct Packet* p) {
SOFT_ASSERT(gNetworkType == NT_CLIENT); SOFT_ASSERT(gNetworkType == NT_CLIENT);
SOFT_ASSERT(p->localIndex == UNKNOWN_LOCAL_INDEX); SOFT_ASSERT(p->localIndex == UNKNOWN_LOCAL_INDEX);
if (gModEntries != NULL) { if (gModTableRemote.entries != NULL) {
LOG_INFO("received mod list after allocating"); LOG_INFO("received mod list after allocating");
return; return;
} }
@ -69,13 +66,32 @@ void network_receive_mod_list(struct Packet* p) {
gNetworkServerAddr = network_duplicate_address(0); gNetworkServerAddr = network_duplicate_address(0);
} }
char version[MAX_VERSION_LENGTH] = { 0 };
snprintf(version, MAX_VERSION_LENGTH, "%s", get_version());
LOG_INFO("client has version: %s", version);
// verify version
char remoteVersion[MAX_VERSION_LENGTH] = { 0 };
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");
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;
}
u16 modEntryCount = 0; u16 modEntryCount = 0;
packet_read(p, &modEntryCount, sizeof(u16)); packet_read(p, &modEntryCount, sizeof(u16));
mod_list_alloc(modEntryCount); mod_list_alloc(&gModTableRemote, modEntryCount);
LOG_INFO("received mod list (%u):", modEntryCount); LOG_INFO("received mod list (%u):", modEntryCount);
gModTotalSize = 0;
for (int i = 0; i < modEntryCount; i++) { for (int i = 0; i < modEntryCount; i++) {
u16 remoteIndex = 0;
packet_read(p, &remoteIndex, sizeof(u16));
u16 nameLength = 0; u16 nameLength = 0;
packet_read(p, &nameLength, sizeof(u16)); packet_read(p, &nameLength, sizeof(u16));
@ -86,12 +102,11 @@ void network_receive_mod_list(struct Packet* p) {
packet_read(p, &size, sizeof(u16)); packet_read(p, &size, sizeof(u16));
mod_list_add(i, name, size, true); mod_list_add(i, name, size, true);
gModTableRemote.entries[i].enabled = true;
gModTableRemote.entries[i].remoteIndex = remoteIndex;
LOG_INFO(" '%s': %u", name, size); LOG_INFO(" '%s': %u", name, size);
} }
if (modEntryCount <= 0) { network_send_next_download_request();
network_send_join_request();
} else {
network_send_download_request(0, 0);
}
} }

View file

@ -221,6 +221,7 @@ void main_func(void) {
const char *userpath = gCLIOpts.SavePath[0] ? gCLIOpts.SavePath : sys_user_path(); const char *userpath = gCLIOpts.SavePath[0] ? gCLIOpts.SavePath : sys_user_path();
fs_init(sys_ropaths, gamedir, userpath); fs_init(sys_ropaths, gamedir, userpath);
mod_list_init();
configfile_load(configfile_name()); configfile_load(configfile_name());
if (configPlayerModel >= CT_MAX) { configPlayerModel = 0; } if (configPlayerModel >= CT_MAX) { configPlayerModel = 0; }
if (configPlayerPalette >= 16) { configPlayerPalette = 0; } if (configPlayerPalette >= 16) { configPlayerPalette = 0; }
@ -307,7 +308,6 @@ void main_func(void) {
audio_init(); audio_init();
sound_init(); sound_init();
mod_list_init();
network_player_init(); network_player_init();
thread5_game_loop(NULL); thread5_game_loop(NULL);