mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-10-19 11:42:39 +00:00
Finish up new mod table system
This commit is contained in:
parent
f880784f8e
commit
7d0cc7b693
16 changed files with 341 additions and 532 deletions
|
@ -450,12 +450,7 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) {
|
||||||
extern s16 gPrevFrameObjectCount;
|
extern s16 gPrevFrameObjectCount;
|
||||||
crash_handler_add_info_int(&pText, 315, -4 + (8 * 4), "Objs", gPrevFrameObjectCount);
|
crash_handler_add_info_int(&pText, 315, -4 + (8 * 4), "Objs", gPrevFrameObjectCount);
|
||||||
|
|
||||||
int modCount = 0;
|
crash_handler_add_info_int(&pText, 380, -4 + (8 * 2), "Mods", gActiveMods.entryCount);
|
||||||
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);
|
|
||||||
|
|
||||||
// Mods
|
// Mods
|
||||||
crash_handler_set_text(245, 64, 0xFF, 0xFF, 0xFF, "%s", "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;
|
int y = 72;
|
||||||
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
||||||
struct Mod* mod = gActiveMods.entries[i];
|
struct Mod* mod = gActiveMods.entries[i];
|
||||||
if (mod == NULL || !mod->enabled) { continue; }
|
|
||||||
u8 g = (gPcDebug.lastModRun == mod) ? 0 : 0xFF;
|
u8 g = (gPcDebug.lastModRun == mod) ? 0 : 0xFF;
|
||||||
crash_handler_set_text(x, y, 0xFF, g, 200, "%.21s", mod->name);
|
crash_handler_set_text(x, y, 0xFF, g, 200, "%.21s", mod->name);
|
||||||
y += 8;
|
y += 8;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "djui.h"
|
#include "djui.h"
|
||||||
#include "pc/mods/mods.h"
|
#include "pc/mods/mods.h"
|
||||||
|
#include "pc/debuglog.h"
|
||||||
|
|
||||||
struct DjuiThreePanel* gDjuiModList = NULL;
|
struct DjuiThreePanel* gDjuiModList = NULL;
|
||||||
|
|
||||||
|
@ -15,18 +16,10 @@ void djui_panel_modlist_create(UNUSED struct DjuiBase* caller) {
|
||||||
gDjuiModList = NULL;
|
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
|
// 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");
|
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\M\\#1be700\\O\\#00b3ff\\D\\#ffef00\\S");
|
||||||
gDjuiModList = panel;
|
gDjuiModList = panel;
|
||||||
|
|
||||||
|
@ -44,7 +37,6 @@ void djui_panel_modlist_create(UNUSED struct DjuiBase* caller) {
|
||||||
|
|
||||||
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
||||||
struct Mod* mod = gActiveMods.entries[i];
|
struct Mod* mod = gActiveMods.entries[i];
|
||||||
if (!mod->enabled) { continue; }
|
|
||||||
|
|
||||||
struct DjuiFlowLayout* row = djui_flow_layout_create(&body->base);
|
struct DjuiFlowLayout* row = djui_flow_layout_create(&body->base);
|
||||||
djui_base_set_size_type(&row->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
djui_base_set_size_type(&row->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||||
|
|
|
@ -118,7 +118,6 @@ void smlua_init(void) {
|
||||||
LOG_INFO("Loading scripts:");
|
LOG_INFO("Loading scripts:");
|
||||||
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
||||||
struct Mod* mod = gActiveMods.entries[i];
|
struct Mod* mod = gActiveMods.entries[i];
|
||||||
if (!mod->enabled) { continue; }
|
|
||||||
LOG_INFO(" %s", mod->relativePath);
|
LOG_INFO(" %s", mod->relativePath);
|
||||||
gLuaLoadingMod = mod;
|
gLuaLoadingMod = mod;
|
||||||
gLuaActiveMod = mod;
|
gLuaActiveMod = mod;
|
||||||
|
|
|
@ -568,7 +568,6 @@ void smlua_sync_table_send_all(u8 toLocalIndex) {
|
||||||
LUA_STACK_CHECK_BEGIN();
|
LUA_STACK_CHECK_BEGIN();
|
||||||
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
||||||
struct Mod* mod = gActiveMods.entries[i];
|
struct Mod* mod = gActiveMods.entries[i];
|
||||||
if (!mod->enabled) { continue; }
|
|
||||||
smlua_sync_table_send_all_file(toLocalIndex, mod->relativePath);
|
smlua_sync_table_send_all_file(toLocalIndex, mod->relativePath);
|
||||||
}
|
}
|
||||||
LUA_STACK_CHECK_END();
|
LUA_STACK_CHECK_END();
|
||||||
|
|
|
@ -1,334 +0,0 @@
|
||||||
#include <dirent.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#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();
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
#ifndef MOD_LIST_H
|
|
||||||
#define MOD_LIST_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "PR/ultratypes.h"
|
|
||||||
#include <types.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#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
|
|
|
@ -10,7 +10,10 @@ struct Mods;
|
||||||
struct ModFile {
|
struct ModFile {
|
||||||
char relativePath[SYS_MAX_PATH];
|
char relativePath[SYS_MAX_PATH];
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
|
u64 curOffset;
|
||||||
|
bool complete;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Mod {
|
struct Mod {
|
||||||
|
|
|
@ -4,11 +4,42 @@
|
||||||
#include "pc/debuglog.h"
|
#include "pc/debuglog.h"
|
||||||
|
|
||||||
#define MOD_DIRECTORY "mods"
|
#define MOD_DIRECTORY "mods"
|
||||||
|
#define MAX_SESSION_CHARS 7
|
||||||
|
|
||||||
struct Mods gLocalMods = { 0 };
|
struct Mods gLocalMods = { 0 };
|
||||||
struct Mods gRemoteMods = { 0 };
|
struct Mods gRemoteMods = { 0 };
|
||||||
struct Mods gActiveMods = { 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) {
|
void mods_activate(struct Mods* mods) {
|
||||||
mods_clear(&gActiveMods);
|
mods_clear(&gActiveMods);
|
||||||
|
|
||||||
|
@ -35,23 +66,25 @@ void mods_activate(struct Mods* mods) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// open file pointers
|
// open file pointers
|
||||||
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
if (mods != &gRemoteMods) {
|
||||||
struct Mod* mod = gActiveMods.entries[i];
|
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
||||||
for (int j = 0; j < mod->fileCount; j++) {
|
struct Mod* mod = gActiveMods.entries[i];
|
||||||
struct ModFile* file = &mod->files[j];
|
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(&gRemoteMods);
|
||||||
mods_clear(&gActiveMods);
|
mods_clear(&gActiveMods);
|
||||||
mods_clear(&gLocalMods);
|
mods_clear(&gLocalMods);
|
||||||
|
mods_delete_tmp();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "mod.h"
|
#include "mod.h"
|
||||||
|
|
||||||
#define MAX_MOD_SIZE (2 * 1048576) // 2MB
|
#define MAX_MOD_SIZE (2 * 1048576) // 2MB
|
||||||
|
#define TMP_DIRECTORY "tmp"
|
||||||
|
|
||||||
struct Mods {
|
struct Mods {
|
||||||
struct Mod** entries;
|
struct Mod** entries;
|
||||||
|
@ -18,6 +19,9 @@ extern struct Mods gLocalMods;
|
||||||
extern struct Mods gRemoteMods;
|
extern struct Mods gRemoteMods;
|
||||||
extern struct Mods gActiveMods;
|
extern struct Mods gActiveMods;
|
||||||
|
|
||||||
|
extern char gRemoteModsBasePath[];
|
||||||
|
|
||||||
|
bool mods_generate_remote_base_path(void);
|
||||||
void mods_activate(struct Mods* mods);
|
void mods_activate(struct Mods* mods);
|
||||||
void mods_clear(struct Mods* mods);
|
void mods_clear(struct Mods* mods);
|
||||||
void mods_init(void);
|
void mods_init(void);
|
||||||
|
|
|
@ -67,8 +67,77 @@ void mods_update_selectable(void) {
|
||||||
mods_size_enforce(&gLocalMods);
|
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) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -7,7 +7,10 @@
|
||||||
|
|
||||||
void mods_size_enforce(struct Mods* mods);
|
void mods_size_enforce(struct Mods* mods);
|
||||||
void mods_update_selectable(void);
|
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_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);
|
bool str_ends_with(char* string, char* suffix);
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,6 @@ static bool discord_populate_details(char* details, bool shorten) {
|
||||||
// add mods to activity
|
// add mods to activity
|
||||||
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
for (int i = 0; i < gActiveMods.entryCount; i++) {
|
||||||
struct Mod* mod = gActiveMods.entries[i];
|
struct Mod* mod = gActiveMods.entries[i];
|
||||||
if (!mod->enabled) { continue; }
|
|
||||||
if (displayDash) { strncat_len(details, " - ", 127, catLength); }
|
if (displayDash) { strncat_len(details, " - ", 127, catLength); }
|
||||||
if (displayComma) { strncat_len(details, ", ", 127, catLength); }
|
if (displayComma) { strncat_len(details, ", ", 127, catLength); }
|
||||||
|
|
||||||
|
|
|
@ -327,6 +327,7 @@ 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_start_download_requests(void);
|
||||||
void network_send_next_download_request(void);
|
void network_send_next_download_request(void);
|
||||||
void network_send_download_request(u16 clientIndex, u16 serverIndex, u64 offset);
|
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);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../network.h"
|
#include "../network.h"
|
||||||
#include "pc/djui/djui.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"
|
#include "pc/debuglog.h"
|
||||||
|
|
||||||
#define CHUNK_SIZE 400
|
#define CHUNK_SIZE 400
|
||||||
|
@ -12,38 +13,60 @@ static bool sWaitingForOffset[OFFSET_COUNT] = { 0 };
|
||||||
u64 sTotalDownloadBytes = 0;
|
u64 sTotalDownloadBytes = 0;
|
||||||
extern float gDownloadProgress;
|
extern float gDownloadProgress;
|
||||||
|
|
||||||
void network_send_next_download_request(void) {
|
void network_start_download_requests(void) {
|
||||||
SOFT_ASSERT(gNetworkType == NT_CLIENT);
|
sTotalDownloadBytes = 0;
|
||||||
for (int i = 0; i < gModTableRemote.entryCount; i++) {
|
gDownloadProgress = 0;
|
||||||
struct ModListEntry* entry = &gModTableRemote.entries[i];
|
for (int i = 0; i < gRemoteMods.entryCount; i++) {
|
||||||
if (entry->complete) { continue; }
|
struct Mod* mod = gRemoteMods.entries[i];
|
||||||
//LOG_INFO("sending download request: %d, %d, %lld", i, entry->remoteIndex, entry->curOffset);
|
mod->enabled = true;
|
||||||
network_send_download_request(i, entry->remoteIndex, entry->curOffset);
|
for (int j = 0; j < mod->fileCount; j++) {
|
||||||
return;
|
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();
|
network_send_next_download_request();
|
||||||
djui_panel_modlist_create(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
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, &clientIndex, sizeof(u16));
|
packet_write(&p, &modIndex, sizeof(u16));
|
||||||
packet_write(&p, &serverIndex, sizeof(u16));
|
packet_write(&p, &fileIndex, sizeof(u16));
|
||||||
packet_write(&p, &offset, sizeof(u64));
|
packet_write(&p, &offset, sizeof(u64));
|
||||||
|
|
||||||
if (clientIndex == 0 && offset == 0) {
|
struct Mod* mod = gRemoteMods.entries[modIndex];
|
||||||
sTotalDownloadBytes = 0;
|
struct ModFile* file = &mod->files[fileIndex];
|
||||||
gDownloadProgress = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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] < file->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
network_send_to((gNetworkPlayerServer != NULL) ? gNetworkPlayerServer->localIndex : 0, &p);
|
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) {
|
void network_receive_download_request(struct Packet* p) {
|
||||||
SOFT_ASSERT(gNetworkType == NT_SERVER);
|
SOFT_ASSERT(gNetworkType == NT_SERVER);
|
||||||
|
|
||||||
u16 clientIndex;
|
u16 modIndex;
|
||||||
u16 serverIndex;
|
u16 fileIndex;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
packet_read(p, &clientIndex, sizeof(u16));
|
packet_read(p, &modIndex, sizeof(u16));
|
||||||
packet_read(p, &serverIndex, sizeof(u16));
|
packet_read(p, &fileIndex, sizeof(u16));
|
||||||
packet_read(p, &offset, sizeof(u64));
|
packet_read(p, &offset, sizeof(u64));
|
||||||
|
|
||||||
struct ModListEntry* entry = &gModTableLocal.entries[serverIndex];
|
if (modIndex >= gActiveMods.entryCount) {
|
||||||
if (serverIndex >= gModTableLocal.entryCount) {
|
LOG_ERROR("Requested download of invalid mod index %u:%llu", modIndex, offset);
|
||||||
LOG_ERROR("Requested download of invalid index %u:%llu", serverIndex, offset);
|
|
||||||
return;
|
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++) {
|
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 >= file->size) { break; }
|
||||||
network_send_download(clientIndex, serverIndex, o);
|
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);
|
SOFT_ASSERT(gNetworkType == NT_SERVER);
|
||||||
|
|
||||||
if (serverIndex >= gModTableLocal.entryCount) {
|
if (modIndex >= gActiveMods.entryCount) {
|
||||||
LOG_ERROR("Requested download of invalid index %u:%llu", serverIndex, offset);
|
LOG_ERROR("Requested download of invalid mod index %u:%llu", modIndex, offset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModListEntry* entry = &gModTableLocal.entries[serverIndex];
|
struct Mod* mod = gActiveMods.entries[modIndex];
|
||||||
if (offset >= entry->size) {
|
|
||||||
LOG_ERROR("Requested download of invalid offset %u:%llu", serverIndex, offset);
|
if (fileIndex >= mod->fileCount) {
|
||||||
|
LOG_ERROR("Requested download of invalid file index %u:%llu", fileIndex, offset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->fp == NULL) {
|
struct ModFile* file = &mod->files[fileIndex];
|
||||||
LOG_ERROR("Requested download of invalid file pointer %u:%llu", serverIndex, offset);
|
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 chunkSize = 400;
|
u16 chunkSize = 400;
|
||||||
if ((offset + chunkSize) > entry->size) {
|
if ((offset + chunkSize) > file->size) {
|
||||||
chunkSize = entry->size - offset;
|
chunkSize = file->size - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 chunk[400] = { 0 };
|
u8 chunk[400] = { 0 };
|
||||||
fseek(entry->fp, offset, SEEK_SET);
|
fseek(file->fp, offset, SEEK_SET);
|
||||||
fread(chunk, chunkSize, 1, entry->fp);
|
fread(chunk, chunkSize, 1, file->fp);
|
||||||
|
|
||||||
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, &clientIndex, sizeof(u16));
|
packet_write(&p, &modIndex, sizeof(u16));
|
||||||
packet_write(&p, &serverIndex, sizeof(u16));
|
packet_write(&p, &fileIndex, 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));
|
||||||
|
@ -121,38 +160,46 @@ void network_receive_download(struct Packet* p) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 clientIndex;
|
u16 modIndex;
|
||||||
u16 serverIndex;
|
u16 fileIndex;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u16 chunkSize;
|
u16 chunkSize;
|
||||||
u8 chunk[400] = { 0 };
|
u8 chunk[400] = { 0 };
|
||||||
|
|
||||||
packet_read(p, &clientIndex, sizeof(u16));
|
packet_read(p, &modIndex, sizeof(u16));
|
||||||
packet_read(p, &serverIndex, sizeof(u16));
|
packet_read(p, &fileIndex, 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));
|
||||||
|
|
||||||
//LOG_INFO("Received download %u:%llu", clientIndex, offset);
|
//LOG_INFO("Received download %u:%llu", clientIndex, offset);
|
||||||
|
|
||||||
if (clientIndex >= gModTableRemote.entryCount) {
|
if (modIndex >= gRemoteMods.entryCount) {
|
||||||
LOG_ERROR("Received download of invalid index %u:%llu", clientIndex, offset);
|
LOG_ERROR("Received download of invalid mod index %u:%llu", modIndex, offset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModListEntry* entry = &gModTableRemote.entries[clientIndex];
|
struct Mod* mod = gRemoteMods.entries[modIndex];
|
||||||
if (offset >= entry->size) {
|
|
||||||
LOG_ERROR("Received download of invalid offset %u:%llu", clientIndex, offset);
|
if (fileIndex >= mod->fileCount) {
|
||||||
|
LOG_ERROR("Received download of invalid file index %u:%llu", modIndex, offset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->fp == NULL) {
|
struct ModFile* file = &mod->files[fileIndex];
|
||||||
LOG_ERROR("Received download of invalid file pointer %u:%llu", clientIndex, offset);
|
|
||||||
|
if (offset >= file->size) {
|
||||||
|
LOG_ERROR("Received download of invalid offset %u:%llu", modIndex, offset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((offset + chunkSize) > entry->size) {
|
if (file->fp == NULL) {
|
||||||
LOG_ERROR("Received download of invalid chunk size %u:%llu:%u -- %llu", clientIndex, (u64)offset, chunkSize, (u64)entry->size);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,35 +215,29 @@ void network_receive_download(struct Packet* p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write to the file
|
// write to the file
|
||||||
fseek(entry->fp, offset, SEEK_SET);
|
fseek(file->fp, offset, SEEK_SET);
|
||||||
fwrite(chunk, sizeof(u8) * chunkSize, 1, entry->fp);
|
fwrite(chunk, sizeof(u8) * chunkSize, 1, file->fp);
|
||||||
|
|
||||||
// update progress
|
// update progress
|
||||||
sTotalDownloadBytes += chunkSize;
|
sTotalDownloadBytes += chunkSize;
|
||||||
gDownloadProgress = (float)sTotalDownloadBytes / (float)gModTableRemote.totalSize;
|
gDownloadProgress = (float)sTotalDownloadBytes / (float)gRemoteMods.size;
|
||||||
|
|
||||||
if (!waiting) {
|
if (!waiting) {
|
||||||
// check if we're finished with this file
|
// 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);
|
//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 >= entry->size) {
|
if (sOffset[OFFSET_COUNT - 1] + CHUNK_SIZE >= file->size) {
|
||||||
LOG_INFO("Finished download of '%s'", entry->name);
|
LOG_INFO("Finished download of '%s'", file->relativePath);
|
||||||
fclose(entry->fp);
|
fclose(file->fp);
|
||||||
|
file->fp = NULL;
|
||||||
// parse mod header
|
file->complete = true;
|
||||||
entry->fp = fopen(entry->path, "rb");
|
|
||||||
mod_list_extract_lua_fields(entry);
|
|
||||||
fclose(entry->fp);
|
|
||||||
|
|
||||||
entry->fp = NULL;
|
|
||||||
entry->complete = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->curOffset += (u64)CHUNK_SIZE * OFFSET_COUNT;
|
file->curOffset += (u64)CHUNK_SIZE * OFFSET_COUNT;
|
||||||
network_send_next_download_request();
|
network_send_next_download_request();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,6 +233,7 @@ void network_receive_join(struct Packet* p) {
|
||||||
gChangeLevel = 16;
|
gChangeLevel = 16;
|
||||||
|
|
||||||
mods_activate(&gRemoteMods);
|
mods_activate(&gRemoteMods);
|
||||||
|
djui_panel_modlist_create(NULL);
|
||||||
smlua_init();
|
smlua_init();
|
||||||
|
|
||||||
network_send_network_players_request();
|
network_send_network_players_request();
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../network.h"
|
#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/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_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 };
|
struct Packet p = { 0 };
|
||||||
packet_init(&p, PACKET_MOD_LIST_REQUEST, true, PLMT_NONE);
|
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);
|
LOG_INFO("sending version: %s", version);
|
||||||
packet_write(&p, &version, sizeof(u8) * MAX_VERSION_LENGTH);
|
packet_write(&p, &version, sizeof(u8) * MAX_VERSION_LENGTH);
|
||||||
|
|
||||||
u16 activeCount = 0;
|
packet_write(&p, &gActiveMods.entryCount, sizeof(u16));
|
||||||
for (u16 i = 0; i < gModTableLocal.entryCount; i++) {
|
LOG_INFO("sent mod list (%u):", gActiveMods.entryCount);
|
||||||
struct ModListEntry* entry = &gModTableLocal.entries[i];
|
for (u16 i = 0; i < gActiveMods.entryCount; i++) {
|
||||||
if (entry->enabled) { activeCount++; }
|
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, &nameLength, sizeof(u16));
|
||||||
packet_write(&p, entry->name, sizeof(u8) * nameLength);
|
packet_write(&p, mod->name, sizeof(u8) * nameLength);
|
||||||
packet_write(&p, &entry->size, sizeof(u64));
|
packet_write(&p, &relativePathLength, sizeof(u16));
|
||||||
LOG_INFO(" '%s': %llu", entry->name, (u64)entry->size);
|
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);
|
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");
|
LOG_INFO("received mod list after allocating");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -90,35 +109,72 @@ void network_receive_mod_list(struct Packet* p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 modEntryCount = 0;
|
packet_read(p, &gRemoteMods.entryCount, sizeof(u16));
|
||||||
gModTableCurrent = &gModTableRemote;
|
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));
|
LOG_INFO("received mod list (%u):", gRemoteMods.entryCount);
|
||||||
mod_list_alloc(&gModTableRemote, modEntryCount);
|
size_t totalSize = 0;
|
||||||
|
for (u16 i = 0; i < gRemoteMods.entryCount; i++) {
|
||||||
LOG_INFO("received mod list (%u):", modEntryCount);
|
gRemoteMods.entries[i] = calloc(1, sizeof(struct Mod));
|
||||||
for (int i = 0; i < modEntryCount; i++) {
|
struct Mod* mod = gRemoteMods.entries[i];
|
||||||
u16 remoteIndex = 0;
|
if (mod == NULL) {
|
||||||
packet_read(p, &remoteIndex, sizeof(u16));
|
LOG_ERROR("Failed to allocate remote mod!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char name[32] = { 0 };
|
||||||
u16 nameLength = 0;
|
u16 nameLength = 0;
|
||||||
|
|
||||||
packet_read(p, &nameLength, sizeof(u16));
|
packet_read(p, &nameLength, sizeof(u16));
|
||||||
|
if (nameLength > 31) {
|
||||||
char* name = (char*)calloc(nameLength + 1, sizeof(char));
|
LOG_ERROR("Received name with invalid length!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
packet_read(p, name, nameLength * sizeof(u8));
|
packet_read(p, name, nameLength * sizeof(u8));
|
||||||
|
mod->name = strdup(name);
|
||||||
|
|
||||||
u64 size = 0;
|
u16 relativePathLength = 0;
|
||||||
packet_read(p, &size, sizeof(u64));
|
packet_read(p, &relativePathLength, sizeof(u16));
|
||||||
if (size >= MAX_MOD_SIZE) {
|
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);
|
djui_popup_create("Server had too large of a mod.\nQuitting.", 4);
|
||||||
network_shutdown(false);
|
network_shutdown(false);
|
||||||
return;
|
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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue