mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-22 12:05:11 +00:00
More progress on mod table rewrite
This commit is contained in:
parent
0a3d0b2033
commit
0983474429
9 changed files with 248 additions and 45 deletions
|
@ -13,7 +13,7 @@
|
|||
#include "gfx/gfx_window_manager_api.h"
|
||||
#include "controller/controller_api.h"
|
||||
#include "fs/fs.h"
|
||||
#include "pc/mod_list.h"
|
||||
#include "pc/mods/mods.h"
|
||||
#include "pc/network/ban_list.h"
|
||||
#include "pc/crash_handler.h"
|
||||
|
||||
|
@ -217,21 +217,27 @@ static const struct ConfigOption options[] = {
|
|||
// FunctionConfigOption functions
|
||||
|
||||
static void enable_mod_read(char** tokens, UNUSED int numTokens) {
|
||||
for (unsigned int i = 0; i < gModTableLocal.entryCount; i++) {
|
||||
struct ModListEntry* entry = &gModTableLocal.entries[i];
|
||||
if (!strcmp(tokens[1], entry->name)) {
|
||||
entry->enabled = true;
|
||||
char combined[256] = { 0 };
|
||||
for (int i = 1; i < numTokens; i++) {
|
||||
if (i != 1) { strncat(combined, " ", 255); }
|
||||
strncat(combined, tokens[i], 255);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < gLocalMods.entryCount; i++) {
|
||||
struct Mod* mod = gLocalMods.entries[i];
|
||||
if (!strcmp(combined, mod->relativePath)) {
|
||||
mod->enabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_mod_write(FILE* file) {
|
||||
for (unsigned int i = 0; i < gModTableLocal.entryCount; i++) {
|
||||
struct ModListEntry* entry = &gModTableLocal.entries[i];
|
||||
if (entry == NULL) { continue; }
|
||||
if (!entry->enabled) { continue; }
|
||||
fprintf(file, "%s %s\n", "enable-mod:", entry->name);
|
||||
for (unsigned int i = 0; i < gLocalMods.entryCount; i++) {
|
||||
struct Mod* mod = gLocalMods.entries[i];
|
||||
if (mod == NULL) { continue; }
|
||||
if (!mod->enabled) { continue; }
|
||||
fprintf(file, "%s %s\n", "enable-mod:", mod->relativePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
#include "pc/utils/misc.h"
|
||||
#include "pc/configfile.h"
|
||||
#include "pc/cheats.h"
|
||||
#include "pc/mod_list.h"
|
||||
#include "pc/mods/mods.h"
|
||||
#include "pc/mods/mods_utils.h"
|
||||
|
||||
static struct DjuiFlowLayout* sModLayout = NULL;
|
||||
static struct DjuiThreePanel* sDescriptionPanel = NULL;
|
||||
|
@ -43,10 +44,11 @@ static void djui_panel_host_mods_description_create() {
|
|||
|
||||
static void djui_mod_checkbox_on_hover(struct DjuiBase* base) {
|
||||
char* description = "";
|
||||
if (base->tag >= 0 && base->tag < gModTableLocal.entryCount) {
|
||||
char* d = gModTableLocal.entries[base->tag].description;
|
||||
if (base->tag >= 0 && base->tag < gLocalMods.entryCount) {
|
||||
struct Mod* mod = gLocalMods.entries[base->tag];
|
||||
char* d = mod->description;
|
||||
if (d != NULL) {
|
||||
description = gModTableLocal.entries[base->tag].description;
|
||||
description = mod->description;
|
||||
}
|
||||
}
|
||||
djui_text_set_text(sTooltip, description);
|
||||
|
@ -57,15 +59,15 @@ static void djui_mod_checkbox_on_hover_end(UNUSED struct DjuiBase* base) {
|
|||
}
|
||||
|
||||
static void djui_mod_checkbox_on_value_change(UNUSED struct DjuiBase* base) {
|
||||
mod_list_update_selectable();
|
||||
mods_update_selectable();
|
||||
|
||||
u16 index = 0;
|
||||
struct DjuiBaseChild* node = sModLayout->base.child;
|
||||
while (node != NULL) {
|
||||
if (index >= gModTableLocal.entryCount) { break; }
|
||||
struct ModListEntry* entry = &gModTableLocal.entries[index];
|
||||
if (index >= gLocalMods.entryCount) { break; }
|
||||
struct Mod* mod = gLocalMods.entries[index];
|
||||
|
||||
djui_base_set_enabled(node->base, entry->selectable);
|
||||
djui_base_set_enabled(node->base, mod->selectable);
|
||||
|
||||
// iterate
|
||||
index++;
|
||||
|
@ -86,7 +88,7 @@ static void djui_panel_host_mods_destroy(struct DjuiBase* base) {
|
|||
void djui_panel_host_mods_create(struct DjuiBase* caller) {
|
||||
f32 bodyHeight = (416) + 64 * 1 + 16 * 1;
|
||||
|
||||
mod_list_update_selectable();
|
||||
mods_update_selectable();
|
||||
|
||||
struct DjuiBase* defaultBase = NULL;
|
||||
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\M\\#1be700\\O\\#00b3ff\\D\\#ffef00\\S");
|
||||
|
@ -95,13 +97,13 @@ void djui_panel_host_mods_create(struct DjuiBase* caller) {
|
|||
struct DjuiPaginated* paginated = djui_paginated_create(&body->base, 8);
|
||||
sModLayout = paginated->layout;
|
||||
struct DjuiBase* layoutBase = &paginated->layout->base;
|
||||
for (int i = 0; i < gModTableLocal.entryCount; i++) {
|
||||
struct ModListEntry* entry = &gModTableLocal.entries[i];
|
||||
struct DjuiCheckbox* checkbox = djui_checkbox_create(layoutBase, entry->displayName ? entry->displayName : entry->name, &entry->enabled);
|
||||
for (int i = 0; i < gLocalMods.entryCount; i++) {
|
||||
struct Mod* mod = gLocalMods.entries[i];
|
||||
struct DjuiCheckbox* checkbox = djui_checkbox_create(layoutBase, mod->name, &mod->enabled);
|
||||
checkbox->base.tag = i;
|
||||
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&checkbox->base, 1.0f, 32);
|
||||
djui_base_set_enabled(&checkbox->base, entry->selectable);
|
||||
djui_base_set_enabled(&checkbox->base, mod->selectable);
|
||||
djui_interactable_hook_hover(&checkbox->base, djui_mod_checkbox_on_hover, djui_mod_checkbox_on_hover_end);
|
||||
djui_interactable_hook_value_change(&checkbox->base, djui_mod_checkbox_on_value_change);
|
||||
if (i == 0) { defaultBase = &checkbox->base; }
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
void mod_clear(struct Mod* mod) {
|
||||
for (int j = 0; j < mod->fileCount; j++) {
|
||||
struct ModFile* file = &mod->files[j];
|
||||
file = file;
|
||||
if (file->fp != NULL) {
|
||||
fclose(file->fp);
|
||||
file->fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mod->name != NULL) {
|
||||
|
@ -30,6 +33,8 @@ void mod_clear(struct Mod* mod) {
|
|||
}
|
||||
|
||||
mod->fileCount = 0;
|
||||
mod->size = 0;
|
||||
free(mod);
|
||||
}
|
||||
|
||||
static struct ModFile* mod_allocate_file(struct Mod* mod, char* relativePath) {
|
||||
|
@ -51,6 +56,28 @@ static struct ModFile* mod_allocate_file(struct Mod* mod, char* relativePath) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// figure out full path
|
||||
char fullPath[SYS_MAX_PATH] = { 0 };
|
||||
if (!mod_file_full_path(fullPath, mod, file)) {
|
||||
LOG_ERROR("Failed to concat path: '%s' + '%s'", mod->basePath, relativePath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// open file
|
||||
FILE* f = fopen(fullPath, "rb");
|
||||
if (f == NULL) {
|
||||
LOG_ERROR("Failed to open '%s'", fullPath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get size
|
||||
fseek(f, 0, SEEK_END);
|
||||
file->size = ftell(f);
|
||||
mod->size += file->size;
|
||||
|
||||
// close file
|
||||
fclose(f);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
@ -112,7 +139,7 @@ static bool mod_load_files(struct Mod* mod, char* modName, char* fullPath) {
|
|||
while ((dir = readdir(d)) != NULL) {
|
||||
// sanity check / fill path[]
|
||||
if (!directory_sanity_check(dir, actorsPath, path)) { continue; }
|
||||
if (snprintf(relativePath, SYS_MAX_PATH - 1, "%s/actors/%s", modName, dir->d_name) < 0) {
|
||||
if (snprintf(relativePath, SYS_MAX_PATH - 1, "actors/%s", dir->d_name) < 0) {
|
||||
LOG_ERROR("Could not concat actor path!");
|
||||
return false;
|
||||
}
|
||||
|
@ -229,23 +256,28 @@ bool mod_load(struct Mods* mods, char* basePath, char* modName) {
|
|||
}
|
||||
|
||||
// make sure mod is unique
|
||||
for (int i = 0; i < mods->modCount; i++) {
|
||||
struct Mod* compareMod = &mods->entries[i];
|
||||
for (int i = 0; i < mods->entryCount; i++) {
|
||||
struct Mod* compareMod = mods->entries[i];
|
||||
if (!strcmp(compareMod->relativePath, modName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate mod
|
||||
u16 modIndex = mods->modCount++;
|
||||
mods->entries = realloc(mods->entries, sizeof(struct Mod) * mods->modCount);
|
||||
u16 modIndex = mods->entryCount++;
|
||||
mods->entries = realloc(mods->entries, sizeof(struct Mod*) * mods->entryCount);
|
||||
if (mods->entries == NULL) {
|
||||
LOG_ERROR("Failed to allocate entries!");
|
||||
mods_clear(mods);
|
||||
return false;
|
||||
}
|
||||
struct Mod* mod = &mods->entries[modIndex];
|
||||
memset(mod, 0, sizeof(struct Mod));
|
||||
mods->entries[modIndex] = calloc(1, sizeof(struct Mod));
|
||||
struct Mod* mod = mods->entries[modIndex];
|
||||
if (mod == NULL) {
|
||||
LOG_ERROR("Failed to allocate mod!");
|
||||
mods_clear(mods);
|
||||
return false;
|
||||
}
|
||||
|
||||
// set paths
|
||||
char* cpyPath = isDirectory ? fullPath : basePath;
|
||||
|
|
|
@ -9,6 +9,8 @@ struct Mods;
|
|||
|
||||
struct ModFile {
|
||||
char relativePath[SYS_MAX_PATH];
|
||||
size_t size;
|
||||
FILE* fp;
|
||||
};
|
||||
|
||||
struct Mod {
|
||||
|
@ -21,6 +23,8 @@ struct Mod {
|
|||
u16 fileCount;
|
||||
bool isDirectory;
|
||||
bool enabled;
|
||||
bool selectable;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
void mod_clear(struct Mod* mod);
|
||||
|
|
|
@ -5,19 +5,55 @@
|
|||
|
||||
#define MOD_DIRECTORY "mods"
|
||||
|
||||
static struct Mods gLocalMods = { 0 };
|
||||
struct Mods gLocalMods = { 0 };
|
||||
struct Mods gRemoteMods = { 0 };
|
||||
struct Mods gActiveMods = { 0 };
|
||||
|
||||
void mods_clear(struct Mods* mods) {
|
||||
for (int i = 0; i < mods->modCount; i ++) {
|
||||
struct Mod* mod = &mods->entries[i];
|
||||
mod_clear(mod);
|
||||
void mods_activate(struct Mods* mods) {
|
||||
mods_clear(&gActiveMods);
|
||||
|
||||
// count enabled
|
||||
u16 enabledCount = 0;
|
||||
for (int i = 0; i < mods->entryCount; i++) {
|
||||
struct Mod* mod = mods->entries[i];
|
||||
if (mod->enabled) { enabledCount++; }
|
||||
}
|
||||
|
||||
if (mods->entries != NULL) {
|
||||
free(mods->entries);
|
||||
mods->entries = NULL;
|
||||
// allocate
|
||||
gActiveMods.entries = calloc(enabledCount, sizeof(struct Mod*));
|
||||
if (gActiveMods.entries == NULL) {
|
||||
LOG_ERROR("Failed to allocate active mods table!");
|
||||
return;
|
||||
}
|
||||
|
||||
// copy enabled entries
|
||||
for (int i = 0; i < mods->entryCount; i++) {
|
||||
struct Mod* mod = mods->entries[i];
|
||||
if (mod->enabled) {
|
||||
gActiveMods.entries[gActiveMods.entryCount++] = mod;
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
|
||||
char fullPath[SYS_MAX_PATH] = { 0 };
|
||||
if (!mod_file_full_path(fullPath, mod, file)) {
|
||||
LOG_ERROR("Failed to concat path: '%s' + '%s'", mod->basePath, relativePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
file->fp = fopen(fullPath, "rb");
|
||||
if (file->fp == NULL) {
|
||||
LOG_ERROR("Failed to open file '%s'", fullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
mods->modCount = 0;
|
||||
}
|
||||
|
||||
static void mods_load(struct Mods* mods, char* modsBasePath) {
|
||||
|
@ -78,8 +114,50 @@ void mods_init(void) {
|
|||
// load mods
|
||||
if (hasUserPath) { mods_load(&gLocalMods, userModPath); }
|
||||
mods_load(&gLocalMods, "./" MOD_DIRECTORY);
|
||||
|
||||
// calculate total size
|
||||
gLocalMods.size = 0;
|
||||
for (int i = 0; i < gLocalMods.entryCount; i++) {
|
||||
struct Mod* mod = gLocalMods.entries[i];
|
||||
gLocalMods.size += mod->size;
|
||||
}
|
||||
}
|
||||
|
||||
void mods_clear(struct Mods* mods) {
|
||||
if (mods == &gActiveMods) {
|
||||
// don't clear the mods of gActiveMods since they're a copy
|
||||
// just close all file pointers
|
||||
for (int i = 0; i < mods->entryCount; i ++) {
|
||||
struct Mod* mod = mods->entries[i];
|
||||
for (int j = 0; j < mod->fileCount; j++) {
|
||||
struct ModFile* file = &mod->files[j];
|
||||
if (file->fp != NULL) {
|
||||
fclose(file->fp);
|
||||
file->fp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// clear mods of gLocalMods and gRemoteMods
|
||||
for (int i = 0; i < mods->entryCount; i ++) {
|
||||
struct Mod* mod = mods->entries[i];
|
||||
mod_clear(mod);
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup entries
|
||||
if (mods->entries != NULL) {
|
||||
free(mods->entries);
|
||||
mods->entries = NULL;
|
||||
}
|
||||
|
||||
// cleanup params
|
||||
mods->entryCount = 0;
|
||||
mods->size = 0;
|
||||
}
|
||||
|
||||
void mods_shutdown(void) {
|
||||
mods_clear(&gRemoteMods);
|
||||
mods_clear(&gActiveMods);
|
||||
mods_clear(&gLocalMods);
|
||||
}
|
||||
|
|
|
@ -6,11 +6,18 @@
|
|||
#include "src/pc/platform.h"
|
||||
#include "mod.h"
|
||||
|
||||
#define MAX_MOD_SIZE (2 * 1048576) // 2MB
|
||||
|
||||
struct Mods {
|
||||
struct Mod* entries;
|
||||
u16 modCount;
|
||||
struct Mod** entries;
|
||||
u16 entryCount;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
extern struct Mods gLocalMods;
|
||||
extern struct Mods gRemoteMods;
|
||||
extern struct Mods gActiveMods;
|
||||
|
||||
void mods_clear(struct Mods* mods);
|
||||
void mods_init(void);
|
||||
void mods_shutdown(void);
|
||||
|
|
|
@ -1,8 +1,78 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include "mods.h"
|
||||
#include "mods_utils.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
void mods_size_enforce(void) {
|
||||
for (int i = 0; i < gLocalMods.entryCount; i++) {
|
||||
struct Mod* mod = gLocalMods.entries[i];
|
||||
if (mod->size >= MAX_MOD_SIZE) {
|
||||
mod->enabled = false;
|
||||
mod->selectable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool mods_incompatible_match(struct Mod* a, struct Mod* 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 mods_update_selectable(void) {
|
||||
// reset selectable value
|
||||
for (int i = 0; i < gLocalMods.entryCount; i++) {
|
||||
struct Mod* mod = gLocalMods.entries[i];
|
||||
mod->selectable = true;
|
||||
}
|
||||
|
||||
// figure out which ones to deselect
|
||||
for (int i = 0; i < gLocalMods.entryCount; i++) {
|
||||
struct Mod* mod = gLocalMods.entries[i];
|
||||
if (mod->enabled) { continue; }
|
||||
|
||||
for (int j = 0; j < gLocalMods.entryCount; j++) {
|
||||
if (j == i) { continue; }
|
||||
struct Mod* mod2 = gLocalMods.entries[j];
|
||||
if (!mod2->enabled) { continue; }
|
||||
|
||||
if (mods_incompatible_match(mod, mod2)) {
|
||||
mod->selectable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mods_size_enforce();
|
||||
}
|
||||
|
||||
bool mod_file_full_path(char* destination, struct Mod* mod, struct ModFile* modFile) {
|
||||
return concat_path(destination, mod->basePath, modFile->relativePath);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool str_ends_with(char* string, char* suffix) {
|
||||
if (string == NULL || suffix == NULL) { return false; }
|
||||
|
||||
|
@ -14,6 +84,7 @@ bool str_ends_with(char* string, char* suffix) {
|
|||
return !strcmp(&string[stringLength - suffixLength], suffix);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* extract_lua_field(char* fieldName, char* buffer) {
|
||||
size_t length = strlen(fieldName);
|
||||
|
@ -25,6 +96,8 @@ char* extract_lua_field(char* fieldName, char* buffer) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool path_exists(char* path) {
|
||||
struct stat sb = { 0 };
|
||||
return (stat(path, &sb) == 0);
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#include <types.h>
|
||||
#include "src/pc/platform.h"
|
||||
|
||||
void mods_size_enforce(void);
|
||||
void mods_update_selectable(void);
|
||||
bool mod_file_full_path(char* destination, struct Mod* mod, struct ModFile* modFile);
|
||||
|
||||
bool str_ends_with(char* string, char* suffix);
|
||||
|
||||
char* extract_lua_field(char* fieldName, char* buffer);
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
#include "pc/network/network_player.h"
|
||||
#include "pc/djui/djui.h"
|
||||
|
||||
#include "pc/mod_list.h"
|
||||
#include "pc/mods/mods.h"
|
||||
|
||||
OSMesg D_80339BEC;
|
||||
|
@ -171,7 +170,6 @@ void game_deinit(void) {
|
|||
gfx_shutdown();
|
||||
network_shutdown(true);
|
||||
smlua_shutdown();
|
||||
mod_list_shutdown();
|
||||
mods_shutdown();
|
||||
inited = false;
|
||||
}
|
||||
|
@ -222,7 +220,6 @@ void main_func(void) {
|
|||
const char *userpath = gCLIOpts.SavePath[0] ? gCLIOpts.SavePath : sys_user_path();
|
||||
fs_init(sys_ropaths, gamedir, userpath);
|
||||
|
||||
mod_list_init();
|
||||
mods_init();
|
||||
configfile_load(configfile_name());
|
||||
if (configPlayerModel >= CT_MAX) { configPlayerModel = 0; }
|
||||
|
|
Loading…
Reference in a new issue