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_host.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_settings.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_menu.c" />
@ -931,7 +933,9 @@
<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_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_settings.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_menu.h" />

View file

@ -4854,6 +4854,12 @@
<ClCompile Include="..\src\pc\djui\djui_progress_bar.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</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>
<ClCompile Include="..\actors\common0.h">
@ -5989,5 +5995,11 @@
<ClInclude Include="..\src\pc\djui\djui_progress_bar.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</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>
</Project>

View file

@ -13,6 +13,7 @@
#include "gfx/gfx_window_manager_api.h"
#include "controller/controller_api.h"
#include "fs/fs.h"
#include "pc/mod_list.h"
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
@ -295,12 +296,25 @@ void configfile_load(const char *filename) {
if (numTokens >= 2) {
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++) {
if (strcmp(tokens[0], options[i].name) == 0) {
option = &options[i];
break;
}
}
if (option == NULL)
printf("unknown option '%s'\n", tokens[0]);
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);
}

View file

@ -37,6 +37,8 @@
#include "djui_panel_debug.h"
#include "djui_panel_main.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_message.h"
#include "djui_panel_join.h"

View file

@ -13,7 +13,6 @@
#endif
struct DjuiInputbox* sInputboxPort = NULL;
static unsigned int sKnockbackIndex = 0;
static void djui_panel_host_network_system_change(UNUSED struct DjuiBase* base) {
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) {
if (!djui_panel_host_port_valid()) {
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) {
#ifdef DISCORD_SDK
f32 bodyHeight = 32 * 8 + 64 * 2 + 16 * 10;
#else
f32 bodyHeight = 32 * 7 + 64 * 2 + 16 * 9;
#endif
f32 bodyHeight = 32 * 3 + 64 * 3 + 16 * 5;
struct DjuiBase* defaultBase = NULL;
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);
}
char* iChoices[3] = { "Non-solid", "Solid", "Friendly Fire" };
struct DjuiSelectionbox* selectionbox2 = djui_selectionbox_create(&body->base, "Player interaction", iChoices, 3, &configPlayerInteraction);
djui_base_set_size_type(&selectionbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&selectionbox2->base, 1.0f, 32);
struct DjuiButton* button1 = djui_button_create(&body->base, "Settings");
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_CENTER, DJUI_VALIGN_TOP);
djui_interactable_hook_click(&button1->base, djui_panel_host_settings_create);
char* kChoices[3] = { "Weak", "Normal", "Too much" };
sKnockbackIndex = (configPlayerKnockbackStrength <= 20)
? 0
: ((configPlayerKnockbackStrength <= 40) ? 1 : 2);
struct DjuiSelectionbox* selectionbox3 = djui_selectionbox_create(&body->base, "Knockback strength", kChoices, 3, &sKnockbackIndex);
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 DjuiButton* button2 = djui_button_create(&body->base, "Mods");
djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button2->base, 1.0f, 64);
djui_base_set_alignment(&button2->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP);
djui_interactable_hook_click(&button2->base, djui_panel_host_mods_create);
struct DjuiRect* rect3 = djui_rect_create(&body->base);
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
LOG_INFO("Loading scripts:");
for (int i = 0; i < gModEntryCount; i++) {
struct ModListEntry* entry = &gModEntries[i];
struct ModTable* table = (gNetworkType == NT_SERVER) ? &gModTableLocal : &gModTableRemote;
for (int i = 0; i < table->entryCount; i++) {
struct ModListEntry* entry = &table->entries[i];
if (!entry->enabled) { continue; }
LOG_INFO(" %s", entry->path);
smlua_load_script(entry->path);
}

View file

@ -6,9 +6,8 @@
#define MAX_SESSION_CHARS 7
struct ModListEntry* gModEntries = NULL;
u16 gModEntryCount = 0;
u64 gModTotalSize = 0;
struct ModTable gModTableLocal = { .entries = NULL, .entryCount = 0, .totalSize = 0, .isRemote = false };
struct ModTable gModTableRemote = { .entries = NULL, .entryCount = 0, .totalSize = 0, .isRemote = true };
static char sTmpSession[MAX_SESSION_CHARS] = { 0 };
static char sTmpPath[PATH_MAX] = { 0 };
@ -18,82 +17,6 @@ static bool acceptable_file(char* string) {
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) {
struct dirent* dir;
@ -122,13 +45,98 @@ static void mod_list_delete_tmp(void) {
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) {
snprintf(sTmpSession, MAX_SESSION_CHARS, "%06X", (u32)(rand() % 0xFFFFFF));
snprintf(sTmpPath, PATH_MAX - 1, "%s", fs_get_write_path("tmp"));
if (!fs_sys_dir_exists(sTmpPath)) { fs_sys_mkdir(sTmpPath); }
mod_list_load_local();
}
void mod_list_shutdown(void) {
mod_list_clear();
mod_table_clear(&gModTableLocal);
mod_table_clear(&gModTableRemote);
mod_list_delete_tmp();
}
}

View file

@ -8,24 +8,33 @@
#define MOD_PATH "./mods"
#pragma pack(1)
struct ModListEntry {
char* name;
FILE* fp;
char path[PATH_MAX];
size_t size;
u64 curOffset;
u16 remoteIndex;
bool tmp;
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_load(void);
void mod_list_clear(void);
void mod_table_clear(struct ModTable* table);
void mod_list_alloc(struct ModTable* table, u16 count);
void mod_list_init(void);
void mod_list_shutdown(void);

View file

@ -97,7 +97,6 @@ bool network_init(enum NetworkType inNetworkType) {
gNetworkType = inNetworkType;
if (gNetworkType == NT_SERVER) {
mod_list_load();
smlua_init();
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
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_receive_mod_list(struct Packet* p);
// 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_send_download(u16 index, u64 offset);
void network_send_download(u16 clientIndex, u16 serverIndex, u64 offset);
void network_receive_download(struct Packet* p);

View file

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

View file

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

View file

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