diff --git a/src/pc/crash_handler.c b/src/pc/crash_handler.c index b725f5f33..8ffcb8013 100644 --- a/src/pc/crash_handler.c +++ b/src/pc/crash_handler.c @@ -450,12 +450,7 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) { extern s16 gPrevFrameObjectCount; crash_handler_add_info_int(&pText, 315, -4 + (8 * 4), "Objs", gPrevFrameObjectCount); - int modCount = 0; - for (int i = 0; i < gActiveMods.entryCount; i++) { - struct Mod* mod = gActiveMods.entries[i]; - if (mod->enabled) { modCount++; } - } - crash_handler_add_info_int(&pText, 380, -4 + (8 * 2), "Mods", modCount); + crash_handler_add_info_int(&pText, 380, -4 + (8 * 2), "Mods", gActiveMods.entryCount); // Mods crash_handler_set_text(245, 64, 0xFF, 0xFF, 0xFF, "%s", "Mods:"); @@ -464,7 +459,6 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) { int y = 72; for (int i = 0; i < gActiveMods.entryCount; i++) { struct Mod* mod = gActiveMods.entries[i]; - if (mod == NULL || !mod->enabled) { continue; } u8 g = (gPcDebug.lastModRun == mod) ? 0 : 0xFF; crash_handler_set_text(x, y, 0xFF, g, 200, "%.21s", mod->name); y += 8; diff --git a/src/pc/djui/djui_panel_modlist.c b/src/pc/djui/djui_panel_modlist.c index 63525dd6e..8d42ee6ea 100644 --- a/src/pc/djui/djui_panel_modlist.c +++ b/src/pc/djui/djui_panel_modlist.c @@ -2,6 +2,7 @@ #include "djui.h" #include "pc/mods/mods.h" +#include "pc/debuglog.h" struct DjuiThreePanel* gDjuiModList = NULL; @@ -15,18 +16,10 @@ void djui_panel_modlist_create(UNUSED struct DjuiBase* caller) { gDjuiModList = NULL; } - // count mods - int enabledCount = 0; - for (int i = 0; i < gActiveMods.entryCount; i++) { - struct Mod* mod = gActiveMods.entries[i]; - if (!mod->enabled) { continue; } - enabledCount++; - } - // only create if we have mods - if (enabledCount == 0) { return; } + if (gActiveMods.entryCount == 0) { return; } - f32 bodyHeight = (enabledCount * 32) + (enabledCount - 1) * 4; + f32 bodyHeight = (gActiveMods.entryCount * 32) + (gActiveMods.entryCount - 1) * 4; struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\M\\#1be700\\O\\#00b3ff\\D\\#ffef00\\S"); gDjuiModList = panel; @@ -44,7 +37,6 @@ void djui_panel_modlist_create(UNUSED struct DjuiBase* caller) { for (int i = 0; i < gActiveMods.entryCount; i++) { struct Mod* mod = gActiveMods.entries[i]; - if (!mod->enabled) { continue; } struct DjuiFlowLayout* row = djui_flow_layout_create(&body->base); djui_base_set_size_type(&row->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index b280679ef..a42298a03 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -118,7 +118,6 @@ void smlua_init(void) { LOG_INFO("Loading scripts:"); for (int i = 0; i < gActiveMods.entryCount; i++) { struct Mod* mod = gActiveMods.entries[i]; - if (!mod->enabled) { continue; } LOG_INFO(" %s", mod->relativePath); gLuaLoadingMod = mod; gLuaActiveMod = mod; diff --git a/src/pc/lua/smlua_sync_table.c b/src/pc/lua/smlua_sync_table.c index d9f078e86..26365a1fd 100644 --- a/src/pc/lua/smlua_sync_table.c +++ b/src/pc/lua/smlua_sync_table.c @@ -568,7 +568,6 @@ void smlua_sync_table_send_all(u8 toLocalIndex) { LUA_STACK_CHECK_BEGIN(); for (int i = 0; i < gActiveMods.entryCount; i++) { struct Mod* mod = gActiveMods.entries[i]; - if (!mod->enabled) { continue; } smlua_sync_table_send_all_file(toLocalIndex, mod->relativePath); } LUA_STACK_CHECK_END(); diff --git a/src/pc/mod_list.c b/src/pc/mod_list.c deleted file mode 100644 index 8b981fb56..000000000 --- a/src/pc/mod_list.c +++ /dev/null @@ -1,334 +0,0 @@ -#include -#include -#include -#include "mod_list.h" -#include "pc/fs/fs.h" -#include "pc/utils/misc.h" -#include "pc/debuglog.h" - -#define MAX_SESSION_CHARS 7 - -struct ModTable gModTableLocal = { .entries = NULL, .entryCount = 0, .totalSize = 0, .isRemote = false }; -struct ModTable gModTableRemote = { .entries = NULL, .entryCount = 0, .totalSize = 0, .isRemote = true }; -struct ModTable* gModTableCurrent = &gModTableLocal; - -static char sTmpSession[MAX_SESSION_CHARS] = { 0 }; -static char sTmpPath[SYS_MAX_PATH] = { 0 }; - -static bool acceptable_file(char* string) { - if (strchr(string, '/') != NULL) { return false; } - if (strchr(string, '\\') != NULL) { return false; } - string = strrchr(string, '.'); - return (string != NULL && !strcmp(string, ".lua")); -} - -static void mod_list_delete_tmp(void) { - struct dirent* dir; - DIR* d = opendir(sTmpPath); - if (!d) { return; } - - static char path[SYS_MAX_PATH] = { 0 }; - while ((dir = readdir(d)) != NULL) { - if (snprintf(path, SYS_MAX_PATH - 1, "%s/%s", sTmpPath, dir->d_name) < 0) { continue; } - if (!fs_sys_file_exists(path)) { continue; } - -#if defined(_WIN32) - // replace slashes - char* p = path; - while (*p) { - if (*p == '/') { *p = '\\'; } - p++; - } -#endif - if (unlink(path) == -1) { - LOG_ERROR("Failed to remove tmp file '%s'", path); - } - } - - closedir(d); -} - -//////////////////////////////////////////////// - -static bool mod_list_contains(struct ModTable* table, char* name) { - for (int i = 0; i < table->entryCount; i++) { - struct ModListEntry* entry = &table->entries[i]; - if (entry->name == NULL) { continue; } - if (!strcmp(entry->name, name)) { return true; } - } - return false; -} - -void mod_list_add_tmp(u16 index, u16 remoteIndex, char* name, size_t size) { - if (!acceptable_file(name)) { return; } - - struct ModTable* table = &gModTableRemote; - if (mod_list_contains(table, name)) { return; } - - struct ModListEntry* entry = &table->entries[index]; - entry->name = name; - entry->size = size; - table->totalSize += size; - - char sanitizedName[SYS_MAX_PATH] = { 0 }; - char* n = name; - char* s = sanitizedName; - while (*n != '\0') { - if (*n >= 'a' && *n <= 'z') { *s = *n; s++; } - if (*n >= 'A' && *n <= 'Z') { *s = *n; s++; } - if (*n >= '0' && *n <= '9') { *s = *n; s++; } - if (*n == '_' || *n == '-' || *n == '.') { *s = *n; s++; } - n++; - } - - if (snprintf(entry->path, SYS_MAX_PATH - 1, "%s/%s-%u-%s", sTmpPath, sTmpSession, index, sanitizedName) >= 0) { - entry->fp = fopen(entry->path, "wb"); - } else { - entry->fp = NULL; - } - - entry->remoteIndex = remoteIndex; - entry->complete = false; - entry->enabled = true; - entry->selectable = false; -} - -static char* extract_lua_field(char* fieldName, char* buffer) { - size_t length = strlen(fieldName); - if (strncmp(fieldName, buffer, length) == 0) { - char* s = &buffer[length]; - while (*s == ' ' || *s == '\t') { s++; } - return s; - } - return NULL; -} - -void mod_list_extract_lua_fields(struct ModListEntry* entry) { - FILE* f = entry->fp; - char buffer[512] = { 0 }; - - entry->displayName = NULL; - entry->incompatible = NULL; - entry->description = NULL; - - fseek(entry->fp, 0, SEEK_SET); - - while (!feof(f)) { - file_get_line(buffer, 512, f); - - // no longer in header - if (buffer[0] != '-' || buffer[1] != '-') { - return; - } - - // extract the field - char* extracted = NULL; - if (entry->displayName == NULL && (extracted = extract_lua_field("-- name:", buffer))) { - entry->displayName = calloc(33, sizeof(char)); - if (snprintf(entry->displayName, 32, "%s", extracted) < 0) {} - } else if (entry->incompatible == NULL && (extracted = extract_lua_field("-- incompatible:", buffer))) { - entry->incompatible = calloc(257, sizeof(char)); - if (snprintf(entry->incompatible, 256, "%s", extracted) < 0) {} - } else if (entry->description == NULL && (extracted = extract_lua_field("-- description:", buffer))) { - entry->description = calloc(513, sizeof(char)); - if (snprintf(entry->description, 512, "%s", extracted) < 0) {} - } - } - -} - -static void mod_list_add_local(u16 index, const char* path, char* name) { - if (!acceptable_file(name)) { return; } - - struct ModTable* table = &gModTableLocal; - if (mod_list_contains(table, name)) { return; } - - struct ModListEntry* entry = &table->entries[index]; - entry->name = strdup(name); - - snprintf(entry->path, SYS_MAX_PATH - 1, "%s/%s", path, name); - entry->fp = fopen(entry->path, "rb"); - - mod_list_extract_lua_fields(entry); - - fseek(entry->fp, 0, SEEK_END); - entry->size = ftell(entry->fp); - table->totalSize += entry->size; - fseek(entry->fp, 0, SEEK_SET); - - entry->remoteIndex = index; - entry->complete = true; - entry->enabled = false; - entry->selectable = true; -} - -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->displayName != NULL) { - free(entry->displayName); - entry->displayName = NULL; - } - - if (entry->incompatible != NULL) { - free(entry->incompatible); - entry->incompatible = NULL; - } - - if (entry->description != NULL) { - free(entry->description); - entry->description = 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 bool mod_list_incompatible_match(struct ModListEntry* a, struct ModListEntry* b) { - if (a->incompatible == NULL || b->incompatible == NULL) { - return false; - } - if (strlen(a->incompatible) == 0 || strlen(b->incompatible) == 0) { - return false; - } - - char* ai = a->incompatible; - char* bi = b->incompatible; - char* atoken = NULL; - char* btoken = NULL; - char* arest = NULL; - char* brest = NULL; - - for (atoken = strtok_r(ai, " ", &arest); atoken != NULL; atoken = strtok_r(NULL, " ", &arest)) { - for (btoken = strtok_r(bi, " ", &brest); btoken != NULL; btoken = strtok_r(NULL, " ", &brest)) { - if (!strcmp(atoken, btoken)) { - return true; - } - } - } - - return false; -} - -void mod_list_update_selectable(void) { - // reset selectable value - for (int i = 0; i < gModTableLocal.entryCount; i++) { - struct ModListEntry* entry = &gModTableLocal.entries[i]; - entry->selectable = true; - } - - // figure out which ones to deselect - for (int i = 0; i < gModTableLocal.entryCount; i++) { - struct ModListEntry* entry = &gModTableLocal.entries[i]; - if (entry->enabled) { continue; } - - for (int j = 0; j < gModTableLocal.entryCount; j++) { - if (j == i) { continue; } - struct ModListEntry* entry2 = &gModTableLocal.entries[j]; - if (!entry2->enabled) { continue; } - - if (mod_list_incompatible_match(entry, entry2)) { - entry->selectable = false; - break; - } - } - } - - mod_list_size_enforce(); -} - -static void mod_list_load_local(const char* path) { - if (!fs_sys_dir_exists(path)) { return; } - struct ModTable* table = &gModTableLocal; - - struct dirent* dir; - DIR* d = opendir(path); - if (!d) { return; } - - u16 count = 0; - while ((dir = readdir(d)) != NULL) { - if (!acceptable_file(dir->d_name)) { continue; } - if (mod_list_contains(table, dir->d_name)) { continue; } - count++; - } - - u16 totalCount = table->entryCount; - u16 index = 0; - if (table->entries == NULL) { - if (count == 0) { closedir(d); return; } - mod_list_alloc(table, count); - } else { - index = table->entryCount; - totalCount += count; - table->entries = (struct ModListEntry*)realloc(table->entries, totalCount * sizeof(struct ModListEntry)); - } - - rewinddir(d); - - LOG_INFO("Loading mods:"); - while ((dir = readdir(d)) != NULL) { - if (!acceptable_file(dir->d_name)) { continue; } - if (mod_list_contains(table, dir->d_name)) { continue; } - LOG_INFO(" %s", dir->d_name); - mod_list_add_local(index++, path, dir->d_name); - if (index > table->entryCount) { table->entryCount = index; } - } - - closedir(d); -} - -void mod_list_size_enforce(void) { - for (int i = 0; i < gModTableLocal.entryCount; i++) { - if (gModTableLocal.entries[i].size >= MAX_MOD_SIZE) { - gModTableLocal.entries[i].enabled = false; - gModTableLocal.entries[i].selectable = false; - } - } -} - -void mod_list_init(void) { - gModTableCurrent = &gModTableLocal; - srand(time(0)); - snprintf(sTmpSession, MAX_SESSION_CHARS, "%06X", (u32)(rand() % 0xFFFFFF)); - snprintf(sTmpPath, SYS_MAX_PATH - 1, "%s", fs_get_write_path("tmp")); - if (!fs_sys_dir_exists(sTmpPath)) { fs_sys_mkdir(sTmpPath); } - - char userModPath[SYS_MAX_PATH] = { 0 }; - snprintf(userModPath, SYS_MAX_PATH - 1, "%s", fs_get_write_path("mods")); - if (!fs_sys_dir_exists(userModPath)) { fs_sys_mkdir(userModPath); } - - mod_table_clear(&gModTableLocal); - mod_list_load_local(userModPath); - mod_list_load_local(MOD_PATH); - - mod_list_update_selectable(); -} - -void mod_list_shutdown(void) { - mod_table_clear(&gModTableLocal); - mod_table_clear(&gModTableRemote); - mod_list_delete_tmp(); -} diff --git a/src/pc/mod_list.h b/src/pc/mod_list.h deleted file mode 100644 index a0eed3f1c..000000000 --- a/src/pc/mod_list.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef MOD_LIST_H -#define MOD_LIST_H - -#include -#include "PR/ultratypes.h" -#include -#include -#include -#include "src/pc/platform.h" - -#define MOD_PATH "./mods" -#define MAX_MOD_SIZE (2 * 1048576) // 2MB - -struct ModListEntry { - char* name; - FILE* fp; - char path[SYS_MAX_PATH]; - size_t size; - u64 curOffset; - u16 remoteIndex; - char* displayName; - char* incompatible; - char* description; - bool tmp; - bool complete; - bool enabled; - bool selectable; -}; - -struct ModTable { - struct ModListEntry* entries; - u16 entryCount; - u8 isRemote; - u64 totalSize; -}; - -extern struct ModTable gModTableLocal; -extern struct ModTable gModTableRemote; -extern struct ModTable* gModTableCurrent; - -void mod_list_add_tmp(u16 index, u16 remoteIndex, char* name, size_t size); -void mod_list_extract_lua_fields(struct ModListEntry* entry); -void mod_table_clear(struct ModTable* table); -void mod_list_alloc(struct ModTable* table, u16 count); - -void mod_list_update_selectable(void); -void mod_list_size_enforce(void); - -void mod_list_init(void); -void mod_list_shutdown(void); - -#endif \ No newline at end of file diff --git a/src/pc/mods/mod.h b/src/pc/mods/mod.h index d6a902e66..142c67fa4 100644 --- a/src/pc/mods/mod.h +++ b/src/pc/mods/mod.h @@ -10,7 +10,10 @@ struct Mods; struct ModFile { char relativePath[SYS_MAX_PATH]; size_t size; + FILE* fp; + u64 curOffset; + bool complete; }; struct Mod { diff --git a/src/pc/mods/mods.c b/src/pc/mods/mods.c index 2b76510c3..47e5df31e 100644 --- a/src/pc/mods/mods.c +++ b/src/pc/mods/mods.c @@ -4,11 +4,42 @@ #include "pc/debuglog.h" #define MOD_DIRECTORY "mods" +#define MAX_SESSION_CHARS 7 struct Mods gLocalMods = { 0 }; struct Mods gRemoteMods = { 0 }; struct Mods gActiveMods = { 0 }; +char gRemoteModsBasePath[SYS_MAX_PATH] = { 0 }; + +bool mods_generate_remote_base_path(void) { + srand(time(0)); + + // ensure tmpPath exists + char tmpPath[SYS_MAX_PATH] = { 0 }; + if (snprintf(tmpPath, SYS_MAX_PATH - 1, "%s", fs_get_write_path(TMP_DIRECTORY)) < 0) { + LOG_ERROR("Failed to concat tmp path"); + return false; + } + if (!fs_sys_dir_exists(tmpPath)) { fs_sys_mkdir(tmpPath); } + + // generate session + char session[MAX_SESSION_CHARS + 1] = { 0 }; + if (snprintf(session, MAX_SESSION_CHARS, "%06X", (u32)(rand() % 0xFFFFFF)) < 0) { + LOG_ERROR("Failed to generate session"); + return false; + } + + // combine + if (!concat_path(gRemoteModsBasePath, tmpPath, session)) { + LOG_ERROR("Failed to combine session path"); + return false; + } + + // make directory + if (!fs_sys_dir_exists(gRemoteModsBasePath)) { fs_sys_mkdir(gRemoteModsBasePath); } +} + void mods_activate(struct Mods* mods) { mods_clear(&gActiveMods); @@ -35,23 +66,25 @@ void mods_activate(struct Mods* mods) { } // open file pointers - for (int i = 0; i < gActiveMods.entryCount; i++) { - struct Mod* mod = gActiveMods.entries[i]; - for (int j = 0; j < mod->fileCount; j++) { - struct ModFile* file = &mod->files[j]; + if (mods != &gRemoteMods) { + for (int i = 0; i < gActiveMods.entryCount; i++) { + struct Mod* mod = gActiveMods.entries[i]; + for (int j = 0; j < mod->fileCount; j++) { + struct ModFile* file = &mod->files[j]; + + char fullPath[SYS_MAX_PATH] = { 0 }; + if (!mod_file_full_path(fullPath, mod, file)) { + LOG_ERROR("Failed to concat path: '%s' + '%s'", mod->basePath, file->relativePath); + continue; + } + + file->fp = fopen(fullPath, "rb"); + if (file->fp == NULL) { + LOG_ERROR("Failed to open file '%s'", fullPath); + continue; + } - char fullPath[SYS_MAX_PATH] = { 0 }; - if (!mod_file_full_path(fullPath, mod, file)) { - LOG_ERROR("Failed to concat path: '%s' + '%s'", mod->basePath, file->relativePath); - continue; } - - file->fp = fopen(fullPath, "rb"); - if (file->fp == NULL) { - LOG_ERROR("Failed to open file '%s'", fullPath); - continue; - } - } } } @@ -160,4 +193,5 @@ void mods_shutdown(void) { mods_clear(&gRemoteMods); mods_clear(&gActiveMods); mods_clear(&gLocalMods); + mods_delete_tmp(); } diff --git a/src/pc/mods/mods.h b/src/pc/mods/mods.h index 416843a72..0247d4253 100644 --- a/src/pc/mods/mods.h +++ b/src/pc/mods/mods.h @@ -7,6 +7,7 @@ #include "mod.h" #define MAX_MOD_SIZE (2 * 1048576) // 2MB +#define TMP_DIRECTORY "tmp" struct Mods { struct Mod** entries; @@ -18,6 +19,9 @@ extern struct Mods gLocalMods; extern struct Mods gRemoteMods; extern struct Mods gActiveMods; +extern char gRemoteModsBasePath[]; + +bool mods_generate_remote_base_path(void); void mods_activate(struct Mods* mods); void mods_clear(struct Mods* mods); void mods_init(void); diff --git a/src/pc/mods/mods_utils.c b/src/pc/mods/mods_utils.c index 848c17c5e..6be20be3d 100644 --- a/src/pc/mods/mods_utils.c +++ b/src/pc/mods/mods_utils.c @@ -67,8 +67,77 @@ void mods_update_selectable(void) { mods_size_enforce(&gLocalMods); } +static void mods_delete_folder(char* path) { + LOG_INFO("Deleting tmp folder '%s'", path); + struct dirent* dir; + DIR* d = opendir(path); + if (!d) { return; } + + char fullPath[SYS_MAX_PATH] = { 0 }; + while ((dir = readdir(d)) != NULL) { + if (!strcmp(dir->d_name, ".")) { continue; } + if (!strcmp(dir->d_name, "..")) { continue; } + if (!concat_path(fullPath, path, dir->d_name)) { continue; } + + if (is_directory(fullPath)) { + mods_delete_folder(fullPath); + } else if (fs_sys_file_exists(fullPath)) { + if (unlink(fullPath) == -1) { + LOG_ERROR("Failed to remove tmp file '%s'", fullPath); + continue; + } + } + + } + + closedir(d); + rmdir(path); +} + +void mods_delete_tmp(void) { + // ensure tmpPath exists + char tmpPath[SYS_MAX_PATH] = { 0 }; + if (snprintf(tmpPath, SYS_MAX_PATH - 1, "%s", fs_get_write_path(TMP_DIRECTORY)) < 0) { + LOG_ERROR("Failed to concat tmp path"); + return; + } + + // sanity + if (strlen(tmpPath) < 1) { return; } + + // delete + mods_delete_folder(tmpPath); +} +////////////////////////////////////////////////////////////////////////////////////////// + bool mod_file_full_path(char* destination, struct Mod* mod, struct ModFile* modFile) { - return concat_path(destination, mod->basePath, modFile->relativePath); + if (!concat_path(destination, mod->basePath, modFile->relativePath)) { return false; } + normalize_path(destination); + return true; +} + +bool mod_file_create_directories(struct Mod* mod, struct ModFile* modFile) { + char path[SYS_MAX_PATH] = { 0 }; + if (!mod_file_full_path(path, mod, modFile)) { + return false; + } + + // sanity + if (strlen(path) < 1) { return false; } + + char tmpPath[SYS_MAX_PATH] = { 0 }; + char* p = path; + u16 index = 0; + while (*p != '\0') { + if (*p == '/' || *p == '\\') { + if (snprintf(tmpPath, index + 1, "%s", path) < 0) { } + if (!fs_sys_dir_exists(tmpPath)) { fs_sys_mkdir(tmpPath); } + } + index++; + p++; + } + + return true; } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/pc/mods/mods_utils.h b/src/pc/mods/mods_utils.h index be30e6001..b84679051 100644 --- a/src/pc/mods/mods_utils.h +++ b/src/pc/mods/mods_utils.h @@ -7,7 +7,10 @@ void mods_size_enforce(struct Mods* mods); void mods_update_selectable(void); +void mods_delete_tmp(void); + bool mod_file_full_path(char* destination, struct Mod* mod, struct ModFile* modFile); +bool mod_file_create_directories(struct Mod* mod, struct ModFile* modFile); bool str_ends_with(char* string, char* suffix); diff --git a/src/pc/network/discord/activity.c b/src/pc/network/discord/activity.c index 2c208cbbe..b891c0501 100644 --- a/src/pc/network/discord/activity.c +++ b/src/pc/network/discord/activity.c @@ -99,7 +99,6 @@ static bool discord_populate_details(char* details, bool shorten) { // add mods to activity for (int i = 0; i < gActiveMods.entryCount; i++) { struct Mod* mod = gActiveMods.entries[i]; - if (!mod->enabled) { continue; } if (displayDash) { strncat_len(details, " - ", 127, catLength); } if (displayComma) { strncat_len(details, ", ", 127, catLength); } diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index 80be440b9..ae9ee474d 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -327,6 +327,7 @@ void network_send_mod_list(void); void network_receive_mod_list(struct Packet* p); // packet_download.c +void network_start_download_requests(void); 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); diff --git a/src/pc/network/packets/packet_download.c b/src/pc/network/packets/packet_download.c index 66f31d119..ebe6da67b 100644 --- a/src/pc/network/packets/packet_download.c +++ b/src/pc/network/packets/packet_download.c @@ -1,7 +1,8 @@ #include #include "../network.h" #include "pc/djui/djui.h" -#include "pc/mod_list.h" +#include "pc/mods/mods.h" +#include "pc/mods/mods_utils.h" #include "pc/debuglog.h" #define CHUNK_SIZE 400 @@ -12,38 +13,60 @@ static bool sWaitingForOffset[OFFSET_COUNT] = { 0 }; u64 sTotalDownloadBytes = 0; extern float gDownloadProgress; -void network_send_next_download_request(void) { - SOFT_ASSERT(gNetworkType == NT_CLIENT); - for (int i = 0; i < gModTableRemote.entryCount; i++) { - struct ModListEntry* entry = &gModTableRemote.entries[i]; - if (entry->complete) { continue; } - //LOG_INFO("sending download request: %d, %d, %lld", i, entry->remoteIndex, entry->curOffset); - network_send_download_request(i, entry->remoteIndex, entry->curOffset); - return; +void network_start_download_requests(void) { + sTotalDownloadBytes = 0; + gDownloadProgress = 0; + for (int i = 0; i < gRemoteMods.entryCount; i++) { + struct Mod* mod = gRemoteMods.entries[i]; + mod->enabled = true; + for (int j = 0; j < mod->fileCount; j++) { + struct ModFile* file = &mod->files[j]; + char fullPath[SYS_MAX_PATH] = { 0 }; + if (!mod_file_full_path(fullPath, mod, file)) { + LOG_ERROR("unable to concat full path!"); + return; + } + mod_file_create_directories(mod, file); + file->fp = fopen(fullPath, "wb"); + if (file->fp == NULL) { + LOG_ERROR("unable to open for write: '%s'", fullPath); + return; + } + } } - network_send_join_request(); - djui_panel_modlist_create(NULL); + network_send_next_download_request(); } -void network_send_download_request(u16 clientIndex, u16 serverIndex, u64 offset) { +void network_send_next_download_request(void) { + SOFT_ASSERT(gNetworkType == NT_CLIENT); + for (int i = 0; i < gRemoteMods.entryCount; i++) { + struct Mod* mod = gRemoteMods.entries[i]; + for (int j = 0; j < mod->fileCount; j++) { + struct ModFile* file = &mod->files[j]; + if (file->complete) { continue; } + //LOG_INFO("sending download request: %d, %d, %lld", i, file->remoteIndex, file->curOffset); + network_send_download_request(i, j, file->curOffset); + return; + } + } + network_send_join_request(); +} + +void network_send_download_request(u16 modIndex, u16 fileIndex, u64 offset) { SOFT_ASSERT(gNetworkType == NT_CLIENT); struct Packet p = { 0 }; packet_init(&p, PACKET_DOWNLOAD_REQUEST, true, PLMT_NONE); - packet_write(&p, &clientIndex, sizeof(u16)); - packet_write(&p, &serverIndex, sizeof(u16)); + packet_write(&p, &modIndex, sizeof(u16)); + packet_write(&p, &fileIndex, sizeof(u16)); packet_write(&p, &offset, sizeof(u64)); - if (clientIndex == 0 && offset == 0) { - sTotalDownloadBytes = 0; - gDownloadProgress = 0; - } - - struct ModListEntry* entry = &gModTableRemote.entries[clientIndex]; + struct Mod* mod = gRemoteMods.entries[modIndex]; + struct ModFile* file = &mod->files[fileIndex]; for (int i = 0; i < OFFSET_COUNT; i++) { sOffset[i] = offset + CHUNK_SIZE * i; - sWaitingForOffset[i] = (sOffset[i] < entry->size); + sWaitingForOffset[i] = (sOffset[i] < file->size); } network_send_to((gNetworkPlayerServer != NULL) ? gNetworkPlayerServer->localIndex : 0, &p); @@ -52,59 +75,75 @@ void network_send_download_request(u16 clientIndex, u16 serverIndex, u64 offset) void network_receive_download_request(struct Packet* p) { SOFT_ASSERT(gNetworkType == NT_SERVER); - u16 clientIndex; - u16 serverIndex; + u16 modIndex; + u16 fileIndex; u64 offset; - packet_read(p, &clientIndex, sizeof(u16)); - packet_read(p, &serverIndex, sizeof(u16)); + packet_read(p, &modIndex, sizeof(u16)); + packet_read(p, &fileIndex, sizeof(u16)); packet_read(p, &offset, sizeof(u64)); - struct ModListEntry* entry = &gModTableLocal.entries[serverIndex]; - if (serverIndex >= gModTableLocal.entryCount) { - LOG_ERROR("Requested download of invalid index %u:%llu", serverIndex, offset); + if (modIndex >= gActiveMods.entryCount) { + LOG_ERROR("Requested download of invalid mod index %u:%llu", modIndex, offset); return; } + struct Mod* mod = gActiveMods.entries[modIndex]; + + if (fileIndex >= mod->fileCount) { + LOG_ERROR("Requested download of invalid file index %u:%llu", fileIndex, offset); + return; + } + + struct ModFile* file = &mod->files[fileIndex]; + for (int i = 0; i < OFFSET_COUNT; i++) { u64 o = offset + CHUNK_SIZE * i; - if (o >= entry->size) { break; } - network_send_download(clientIndex, serverIndex, o); + if (o >= file->size) { break; } + network_send_download(modIndex, fileIndex, o); } } -void network_send_download(u16 clientIndex, u16 serverIndex, u64 offset) { +void network_send_download(u16 modIndex, u16 fileIndex, u64 offset) { SOFT_ASSERT(gNetworkType == NT_SERVER); - if (serverIndex >= gModTableLocal.entryCount) { - LOG_ERROR("Requested download of invalid index %u:%llu", serverIndex, offset); + if (modIndex >= gActiveMods.entryCount) { + LOG_ERROR("Requested download of invalid mod index %u:%llu", modIndex, offset); return; } - struct ModListEntry* entry = &gModTableLocal.entries[serverIndex]; - if (offset >= entry->size) { - LOG_ERROR("Requested download of invalid offset %u:%llu", serverIndex, offset); + struct Mod* mod = gActiveMods.entries[modIndex]; + + if (fileIndex >= mod->fileCount) { + LOG_ERROR("Requested download of invalid file index %u:%llu", fileIndex, offset); return; } - if (entry->fp == NULL) { - LOG_ERROR("Requested download of invalid file pointer %u:%llu", serverIndex, offset); + struct ModFile* file = &mod->files[fileIndex]; + + if (offset >= file->size) { + LOG_ERROR("Requested download of invalid offset %u:%llu", modIndex, offset); + return; + } + + if (file->fp == NULL) { + LOG_ERROR("Requested download of invalid file pointer %u:%llu", modIndex, offset); return; } u16 chunkSize = 400; - if ((offset + chunkSize) > entry->size) { - chunkSize = entry->size - offset; + if ((offset + chunkSize) > file->size) { + chunkSize = file->size - offset; } u8 chunk[400] = { 0 }; - fseek(entry->fp, offset, SEEK_SET); - fread(chunk, chunkSize, 1, entry->fp); + fseek(file->fp, offset, SEEK_SET); + fread(chunk, chunkSize, 1, file->fp); struct Packet p = { 0 }; packet_init(&p, PACKET_DOWNLOAD, true, PLMT_NONE); - packet_write(&p, &clientIndex, sizeof(u16)); - packet_write(&p, &serverIndex, sizeof(u16)); + packet_write(&p, &modIndex, sizeof(u16)); + packet_write(&p, &fileIndex, sizeof(u16)); packet_write(&p, &offset, sizeof(u64)); packet_write(&p, &chunkSize, sizeof(u16)); packet_write(&p, chunk, chunkSize * sizeof(u8)); @@ -121,38 +160,46 @@ void network_receive_download(struct Packet* p) { } } - u16 clientIndex; - u16 serverIndex; + u16 modIndex; + u16 fileIndex; u64 offset; u16 chunkSize; u8 chunk[400] = { 0 }; - packet_read(p, &clientIndex, sizeof(u16)); - packet_read(p, &serverIndex, sizeof(u16)); + packet_read(p, &modIndex, sizeof(u16)); + packet_read(p, &fileIndex, sizeof(u16)); packet_read(p, &offset, sizeof(u64)); packet_read(p, &chunkSize, sizeof(u16)); packet_read(p, chunk, chunkSize * sizeof(u8)); //LOG_INFO("Received download %u:%llu", clientIndex, offset); - if (clientIndex >= gModTableRemote.entryCount) { - LOG_ERROR("Received download of invalid index %u:%llu", clientIndex, offset); + if (modIndex >= gRemoteMods.entryCount) { + LOG_ERROR("Received download of invalid mod index %u:%llu", modIndex, offset); return; } - struct ModListEntry* entry = &gModTableRemote.entries[clientIndex]; - if (offset >= entry->size) { - LOG_ERROR("Received download of invalid offset %u:%llu", clientIndex, offset); + struct Mod* mod = gRemoteMods.entries[modIndex]; + + if (fileIndex >= mod->fileCount) { + LOG_ERROR("Received download of invalid file index %u:%llu", modIndex, offset); return; } - if (entry->fp == NULL) { - LOG_ERROR("Received download of invalid file pointer %u:%llu", clientIndex, offset); + struct ModFile* file = &mod->files[fileIndex]; + + if (offset >= file->size) { + LOG_ERROR("Received download of invalid offset %u:%llu", modIndex, offset); return; } - if ((offset + chunkSize) > entry->size) { - LOG_ERROR("Received download of invalid chunk size %u:%llu:%u -- %llu", clientIndex, (u64)offset, chunkSize, (u64)entry->size); + if (file->fp == NULL) { + LOG_ERROR("Received download of invalid file pointer %u:%llu", modIndex, offset); + return; + } + + if ((offset + chunkSize) > file->size) { + LOG_ERROR("Received download of invalid chunk size %u:%llu:%u -- %llu", modIndex, (u64)offset, chunkSize, (u64)file->size); return; } @@ -168,35 +215,29 @@ void network_receive_download(struct Packet* p) { } if (!found) { - LOG_ERROR("Received download of unexpected offset [ %llu <-> %llu ] != %llu", entry->curOffset, entry->curOffset + CHUNK_SIZE * OFFSET_COUNT, offset); + LOG_ERROR("Received download of unexpected offset [ %llu <-> %llu ] != %llu", file->curOffset, file->curOffset + CHUNK_SIZE * OFFSET_COUNT, offset); return; } // write to the file - fseek(entry->fp, offset, SEEK_SET); - fwrite(chunk, sizeof(u8) * chunkSize, 1, entry->fp); + fseek(file->fp, offset, SEEK_SET); + fwrite(chunk, sizeof(u8) * chunkSize, 1, file->fp); // update progress sTotalDownloadBytes += chunkSize; - gDownloadProgress = (float)sTotalDownloadBytes / (float)gModTableRemote.totalSize; + gDownloadProgress = (float)sTotalDownloadBytes / (float)gRemoteMods.size; if (!waiting) { // check if we're finished with this file - //LOG_INFO("Checking download of '%s': %lld, %lld", entry->name, sOffset[OFFSET_COUNT - 1] + CHUNK_SIZE, entry->size); - if (sOffset[OFFSET_COUNT - 1] + CHUNK_SIZE >= entry->size) { - LOG_INFO("Finished download of '%s'", entry->name); - fclose(entry->fp); - - // parse mod header - entry->fp = fopen(entry->path, "rb"); - mod_list_extract_lua_fields(entry); - fclose(entry->fp); - - entry->fp = NULL; - entry->complete = true; + //LOG_INFO("Checking download of '%s': %lld, %lld", file->name, sOffset[OFFSET_COUNT - 1] + CHUNK_SIZE, file->size); + if (sOffset[OFFSET_COUNT - 1] + CHUNK_SIZE >= file->size) { + LOG_INFO("Finished download of '%s'", file->relativePath); + fclose(file->fp); + file->fp = NULL; + file->complete = true; } - entry->curOffset += (u64)CHUNK_SIZE * OFFSET_COUNT; + file->curOffset += (u64)CHUNK_SIZE * OFFSET_COUNT; network_send_next_download_request(); } } diff --git a/src/pc/network/packets/packet_join.c b/src/pc/network/packets/packet_join.c index 69a340111..458c36dc0 100644 --- a/src/pc/network/packets/packet_join.c +++ b/src/pc/network/packets/packet_join.c @@ -233,6 +233,7 @@ void network_receive_join(struct Packet* p) { gChangeLevel = 16; mods_activate(&gRemoteMods); + djui_panel_modlist_create(NULL); smlua_init(); network_send_network_players_request(); diff --git a/src/pc/network/packets/packet_mod_list.c b/src/pc/network/packets/packet_mod_list.c index 38289893b..ce5292794 100644 --- a/src/pc/network/packets/packet_mod_list.c +++ b/src/pc/network/packets/packet_mod_list.c @@ -1,12 +1,19 @@ #include #include "../network.h" -#include "pc/mod_list.h" +#include "pc/mods/mods.h" +#include "pc/mods/mods_utils.h" #include "pc/djui/djui.h" #include "pc/debuglog.h" void network_send_mod_list_request(void) { SOFT_ASSERT(gNetworkType == NT_CLIENT); - mod_table_clear(&gModTableRemote); + mods_clear(&gRemoteMods); + mods_clear(&gActiveMods); + + if (!mods_generate_remote_base_path()) { + LOG_ERROR("Failed to generate remote base path!"); + return; + } struct Packet p = { 0 }; packet_init(&p, PACKET_MOD_LIST_REQUEST, true, PLMT_NONE); @@ -33,23 +40,35 @@ void network_send_mod_list(void) { 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, &gActiveMods.entryCount, sizeof(u16)); + LOG_INFO("sent mod list (%u):", gActiveMods.entryCount); + for (u16 i = 0; i < gActiveMods.entryCount; i++) { + struct Mod* mod = gActiveMods.entries[i]; + + u16 nameLength = strlen(mod->name); + if (nameLength > 31) { nameLength = 31; } + + u16 relativePathLength = strlen(mod->relativePath); + u64 modSize = mod->size; - 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(u64)); - LOG_INFO(" '%s': %llu", entry->name, (u64)entry->size); + packet_write(&p, mod->name, sizeof(u8) * nameLength); + packet_write(&p, &relativePathLength, sizeof(u16)); + packet_write(&p, mod->relativePath, sizeof(u8) * relativePathLength); + packet_write(&p, &modSize, sizeof(u64)); + packet_write(&p, &mod->isDirectory, sizeof(u8)); + LOG_INFO(" '%s': %llu", mod->name, (u64)mod->size); + + packet_write(&p, &mod->fileCount, sizeof(u16)); + for (u16 j = 0; j < mod->fileCount; j++) { + struct ModFile* file = &mod->files[j]; + u16 relativePathLength = strlen(file->relativePath); + u64 fileSize = file->size; + packet_write(&p, &relativePathLength, sizeof(u16)); + packet_write(&p, file->relativePath, sizeof(u8) * relativePathLength); + packet_write(&p, &fileSize, sizeof(u64)); + LOG_INFO(" '%s': %llu", file->relativePath, (u64)file->size); + } } network_send_to(0, &p); } @@ -64,7 +83,7 @@ void network_receive_mod_list(struct Packet* p) { } } - if (gModTableRemote.entries != NULL) { + if (gRemoteMods.entries != NULL) { LOG_INFO("received mod list after allocating"); return; } @@ -90,35 +109,72 @@ void network_receive_mod_list(struct Packet* p) { return; } - u16 modEntryCount = 0; - gModTableCurrent = &gModTableRemote; + packet_read(p, &gRemoteMods.entryCount, sizeof(u16)); + gRemoteMods.entries = calloc(gRemoteMods.entryCount, sizeof(struct Mod*)); + if (gRemoteMods.entries == NULL) { + LOG_ERROR("Failed to allocate remote mod entries"); + return; + } - packet_read(p, &modEntryCount, sizeof(u16)); - mod_list_alloc(&gModTableRemote, modEntryCount); - - LOG_INFO("received mod list (%u):", modEntryCount); - for (int i = 0; i < modEntryCount; i++) { - u16 remoteIndex = 0; - packet_read(p, &remoteIndex, sizeof(u16)); + LOG_INFO("received mod list (%u):", gRemoteMods.entryCount); + size_t totalSize = 0; + for (u16 i = 0; i < gRemoteMods.entryCount; i++) { + gRemoteMods.entries[i] = calloc(1, sizeof(struct Mod)); + struct Mod* mod = gRemoteMods.entries[i]; + if (mod == NULL) { + LOG_ERROR("Failed to allocate remote mod!"); + return; + } + char name[32] = { 0 }; u16 nameLength = 0; + packet_read(p, &nameLength, sizeof(u16)); - - char* name = (char*)calloc(nameLength + 1, sizeof(char)); + if (nameLength > 31) { + LOG_ERROR("Received name with invalid length!"); + return; + } packet_read(p, name, nameLength * sizeof(u8)); + mod->name = strdup(name); - u64 size = 0; - packet_read(p, &size, sizeof(u64)); - if (size >= MAX_MOD_SIZE) { + u16 relativePathLength = 0; + packet_read(p, &relativePathLength, sizeof(u16)); + packet_read(p, mod->relativePath, relativePathLength * sizeof(u8)); + packet_read(p, &mod->size, sizeof(u64)); + packet_read(p, &mod->isDirectory, sizeof(u8)); + normalize_path(mod->relativePath); + totalSize += mod->size; + LOG_INFO(" '%s': %llu", mod->name, (u64)mod->size); + + if (snprintf(mod->basePath, SYS_MAX_PATH - 1, "%s", gRemoteModsBasePath) < 0) { + LOG_ERROR("Failed save remote base path!"); + return; + } + + if (mod->size >= MAX_MOD_SIZE) { djui_popup_create("Server had too large of a mod.\nQuitting.", 4); network_shutdown(false); return; } - mod_list_add_tmp(i, remoteIndex, name, size); + packet_read(p, &mod->fileCount, sizeof(u16)); + mod->files = calloc(mod->fileCount, sizeof(struct ModFile)); + if (mod->files == NULL) { + LOG_ERROR("Failed to allocate mod files!"); + return; + } - LOG_INFO(" '%s': %llu", name, size); + for (u16 j = 0; j < mod->fileCount; j++) { + struct ModFile* file = &mod->files[j]; + u16 relativePathLength = 0; + packet_read(p, &relativePathLength, sizeof(u16)); + packet_read(p, file->relativePath, relativePathLength * sizeof(u8)); + packet_read(p, &file->size, sizeof(u64)); + normalize_path(file->relativePath); + LOG_INFO(" '%s': %llu", file->relativePath, (u64)file->size); + } } + gRemoteMods.size = totalSize; - network_send_next_download_request(); + network_start_download_requests(); }