loading screen (#495)

* loading screen

* fix compile error

* Fix animation comparisons after character anim commit

* Cleaned up character sound/anim lookup code

* hopefully fix problems with queued mods

* use dj's changes

* fix compile errors due to upstream merge
This commit is contained in:
Isaac0-dev 2023-11-05 09:55:34 +10:00 committed by Agent X
parent e8b6a8cffa
commit b12b479d70
29 changed files with 427 additions and 66 deletions

View file

@ -25,6 +25,7 @@ bool dynos_warp_exit_level(s32 aDelay);
bool dynos_warp_to_castle(s32 aLevel);
// -- dynos packs -- //
void dynos_gfx_init(void);
void dynos_packs_init(void);
int dynos_pack_get_count(void);
const char* dynos_pack_get_name(s32 index);

View file

@ -62,8 +62,11 @@ bool dynos_warp_to_castle(s32 aLevel) {
// -- dynos packs -- //
void dynos_packs_init(void) {
void dynos_gfx_init(void) {
DynOS_Gfx_Init();
}
void dynos_packs_init(void) {
DynOS_Pack_Init();
}

View file

@ -1,11 +1,17 @@
#include "dynos.cpp.h"
#include "src/pc/loading.h"
void DynOS_Gfx_GeneratePacks(const char* directory) {
DIR *modsDir = opendir(directory);
if (!modsDir) { return; }
struct dirent *dir = NULL;
while ((dir = readdir(modsDir)) != NULL) {
DIR* d = opendir(directory);
u32 pathCount = 0;
while ((dir = readdir(d)) != NULL) pathCount++;
closedir(d);
for (u32 i = 0; (dir = readdir(modsDir)) != NULL; ++i) {
// Skip . and ..
if (SysPath(dir->d_name) == ".") continue;
if (SysPath(dir->d_name) == "..") continue;
@ -15,21 +21,24 @@ void DynOS_Gfx_GeneratePacks(const char* directory) {
if (fs_sys_dir_exists(_LevelPackFolder.c_str())) {
DynOS_Lvl_GeneratePack(_LevelPackFolder);
}
SysPath _ActorPackFolder = fstring("%s/%s/actors", directory, dir->d_name);
if (fs_sys_dir_exists(_ActorPackFolder.c_str())) {
DynOS_Actor_GeneratePack(_ActorPackFolder);
}
SysPath _BehaviorPackFolder = fstring("%s/%s/data", directory, dir->d_name);
if (fs_sys_dir_exists(_BehaviorPackFolder.c_str())) {
DynOS_Bhv_GeneratePack(_BehaviorPackFolder);
}
SysPath _TexturePackFolder = fstring("%s/%s", directory, dir->d_name);
SysPath _TexturePackOutputFolder = fstring("%s/%s/textures", directory, dir->d_name);
if (fs_sys_dir_exists(_TexturePackFolder.c_str())) {
DynOS_Tex_GeneratePack(_TexturePackFolder, _TexturePackOutputFolder, true);
}
if (gIsThreaded) REFRESH_MUTEX(gCurrLoadingSegment.percentage = (f32) i / (f32) pathCount);
}
closedir(modsDir);

View file

@ -374,3 +374,6 @@ REFRESHING = "Obnovování..."
ENTER_PASSWORD = "Zadejte heslo soukromé hry:"
SEARCH = "Hledat"
NONE_FOUND = "Nebyly nalezeny žádné hry."
[LOADING_SCREEN]
LOADING = "Načítání"

View file

@ -374,3 +374,6 @@ REFRESHING = "herladen..."
ENTER_PASSWORD = "Typ het wachtwoord van de privé lobby:"
SEARCH = "Zoek"
NONE_FOUND = "Er zijn geen lobby's gevonden."
[LOADING_SCREEN]
LOADING = "Bezig met laden"

View file

@ -374,3 +374,6 @@ REFRESHING = "Refreshing..."
ENTER_PASSWORD = "Enter the private lobby's password:"
SEARCH = "Search"
NONE_FOUND = "No lobbies were found."
[LOADING_SCREEN]
LOADING = "Loading"

View file

@ -374,3 +374,6 @@ REFRESHING = "Actualisation..."
ENTER_PASSWORD = "Entrez le mot de passe de la partie:"
SEARCH = "Rechercher"
NONE_FOUND = "Aucune partie n'a été trouvée."
[LOADING_SCREEN]
LOADING = "Chargement"

View file

@ -374,3 +374,6 @@ REFRESHING = "Aktualisiere..."
ENTER_PASSWORD = "Gib das Passwort für die Lobby ein:"
SEARCH = "Suchen"
NONE_FOUND = "Keine Lobbys gefunden."
[LOADING_SCREEN]
LOADING = "Wird geladen"

View file

@ -371,3 +371,6 @@ REFRESHING = "Refreshing..."
ENTER_PASSWORD = "Enter the private lobby's password:"
SEARCH = "Search"
NONE_FOUND = "No lobbies were found."
[LOADING_SCREEN]
LOADING = "Caricamento"

View file

@ -31,7 +31,7 @@ UNKNOWN = "desconhecido"
LOBBY_HOST = "o host da partida"
[CHAT]
KICKING = "Expulso '@'!"
KICKING = "Expulso '@'!"
BANNING = "Banindo '@'!"
SERVER_ONLY = "Apenas o servidor pode usar este comando."
PERM_BANNING = "'@' permanentemente banido!"
@ -374,3 +374,6 @@ REFRESHING = "Recarregando..."
ENTER_PASSWORD = "Coloque a senha para a partida privada:"
SEARCH = "Pesquisar"
NONE_FOUND = "Nenhuma partida foi encontrada."
[LOADING_SCREEN]
LOADING = "Carregando"

View file

@ -372,4 +372,7 @@ REFRESH = "Обновить"
REFRESHING = "Обновление..."
ENTER_PASSWORD = "Введите пароль закрытой группы:"
SEARCH = "Поиск"
NONE_FOUND = "Группы не найдены."
NONE_FOUND = "Группы не найдены."
[LOADING_SCREEN]
LOADING = "Загрузка"

View file

@ -324,7 +324,7 @@ struct Character gCharacters[CT_MAX] = {
.torsoRotMult = 1.0f,
// anim
.animOffsetEnabled = false,
// character anims
.animSlowLedgeGrab = MARIO_ANIM_SLOW_LEDGE_GRAB,
.animFallOverBackwards = MARIO_ANIM_FALL_OVER_BACKWARDS,
@ -601,7 +601,7 @@ struct Character gCharacters[CT_MAX] = {
.torsoRotMult = 1.0f,
// anim
.animOffsetEnabled = false,
// character anims
.animSlowLedgeGrab = MARIO_ANIM_SLOW_LEDGE_GRAB,
.animFallOverBackwards = MARIO_ANIM_FALL_OVER_BACKWARDS,
@ -881,7 +881,7 @@ struct Character gCharacters[CT_MAX] = {
.animOffsetLowYPoint = 11,
.animOffsetFeet = 25,
.animOffsetHand = -10,
// character anims
.animSlowLedgeGrab = MARIO_ANIM_SLOW_LEDGE_GRAB,
.animFallOverBackwards = MARIO_ANIM_FALL_OVER_BACKWARDS,
@ -1158,7 +1158,7 @@ struct Character gCharacters[CT_MAX] = {
.torsoRotMult = 1.0f,
// anim
.animOffsetEnabled = true,
// character anims
.animSlowLedgeGrab = MARIO_ANIM_SLOW_LEDGE_GRAB,
.animFallOverBackwards = MARIO_ANIM_FALL_OVER_BACKWARDS,
@ -1521,7 +1521,7 @@ struct Character* get_character(struct MarioState* m) {
static s32 get_character_sound(struct MarioState* m, enum CharacterSound characterSound) {
if (m == NULL || m->marioObj == NULL) { return 0; }
s32 override = 0;
if (smlua_call_event_hooks_mario_character_sound_param_ret_int(HOOK_CHARACTER_SOUND, m, characterSound, &override)) {
return override;
@ -1612,7 +1612,7 @@ void update_character_anim_offset(struct MarioState* m) {
s32 get_character_anim(struct MarioState* m, enum CharacterAnimID characterAnim) {
if (m == NULL || m->marioObj == NULL) { return 0; }
struct Character* character = ((m == NULL || m->character == NULL) ? &gCharacters[CT_MARIO] : m->character);
if (!character || characterAnim < 0 || characterAnim >= CHAR_ANIM_MAX) { return 0; }
return character->anims[characterAnim];

View file

@ -43,7 +43,8 @@ static inline int arg_uint(UNUSED const char *name, const char *value, unsigned
return 1;
}
inline void parse_cli_opts(int argc, char* argv[]) {
bool parse_cli_opts(int argc, char* argv[]) {
// Initialize options with false values.
memset(&gCLIOpts, 0, sizeof(gCLIOpts));
@ -88,7 +89,9 @@ inline void parse_cli_opts(int argc, char* argv[]) {
// Print help
else if (strcmp(argv[i], "--help") == 0) {
print_help();
game_exit();
return false;
}
}
return true;
}

View file

@ -26,6 +26,6 @@ struct PCCLIOptions {
extern struct PCCLIOptions gCLIOpts;
void parse_cli_opts(int argc, char* argv[]);
bool parse_cli_opts(int argc, char* argv[]);
#endif // _CLIOPTS_H

View file

@ -279,6 +279,23 @@ static const struct ConfigOption options[] = {
// FunctionConfigOption functions
struct QueuedMods {
char* path;
struct QueuedMods *next;
};
static struct QueuedMods *sQueuedEnableModsHead = NULL;
void enable_queued_mods() {
while (sQueuedEnableModsHead) {
struct QueuedMods *next = sQueuedEnableModsHead->next;
mods_enable(sQueuedEnableModsHead->path);
free(sQueuedEnableModsHead->path);
free(sQueuedEnableModsHead);
sQueuedEnableModsHead = next;
}
}
static void enable_mod_read(char** tokens, UNUSED int numTokens) {
char combined[256] = { 0 };
for (int i = 1; i < numTokens; i++) {
@ -286,7 +303,16 @@ static void enable_mod_read(char** tokens, UNUSED int numTokens) {
strncat(combined, tokens[i], 255);
}
mods_enable(combined);
struct QueuedMods* queued = malloc(sizeof(struct QueuedMods));
queued->path = strdup(combined);
queued->next = NULL;
if (!sQueuedEnableModsHead) {
sQueuedEnableModsHead = queued;
} else {
struct QueuedMods* tail = sQueuedEnableModsHead;
while (tail->next) { tail = tail->next; }
tail->next = queued;
}
}
static void enable_mod_write(FILE* file) {

View file

@ -120,6 +120,7 @@ extern bool configFadeoutDistantSounds;
extern unsigned int configDjuiTheme;
extern bool configCoopCompatibility;
void enable_queued_mods();
void configfile_load(void);
void configfile_save(const char *filename);
const char *configfile_name(void);

View file

@ -275,8 +275,7 @@ static void crash_handler_produce_one_frame(void) {
// Render frame
end_master_display_list();
alloc_display_list(0);
extern void send_display_list(struct SPTask *spTask);
send_display_list(&gGfxPool->spTask);
gfx_run((Gfx*) gGfxSPTask->task.t.data_ptr); // send_display_list
display_and_vsync();
gfx_end_frame();
}
@ -302,7 +301,7 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) {
#elif __linux__
static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *context) {
#endif
LOG_INFO("game crashed! preparing crash screen...");
printf("game crashed! preparing crash screen...\n");
memset(sCrashHandlerText, 0, sizeof(sCrashHandlerText));
CrashHandlerText *pText = &sCrashHandlerText[0];
gDjuiDisabled = true;
@ -658,6 +657,11 @@ static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *cont
}
#endif
// Incase it crashed before the game window opened
if (!gGfxInited) gfx_init(&WAPI, &RAPI, TITLE);
djui_init();
djui_unicode_init();
// Main loop
while (true) {
WAPI.main_loop(crash_handler_produce_one_frame);
@ -670,17 +674,17 @@ AT_STARTUP static void init_crash_handler(void) {
// Windows
SetUnhandledExceptionFilter(crash_handler);
#elif __linux__
// Linux
struct sigaction linux_crash_handler;
struct sigaction linuxCrashHandler;
linuxCrashHandler.sa_handler = (void*) &crash_handler;
sigemptyset(&linuxCrashHandler.sa_mask);
linuxCrashHandler.sa_flags = SA_SIGINFO; // Get extra info about the crash
linux_crash_handler.sa_handler = (void *)crash_handler;
sigemptyset(&linux_crash_handler.sa_mask);
linux_crash_handler.sa_flags = SA_SIGINFO; // Get extra info about the crash
sigaction(SIGBUS, &linux_crash_handler, NULL);
sigaction(SIGFPE, &linux_crash_handler, NULL);
sigaction(SIGILL, &linux_crash_handler, NULL);
sigaction(SIGSEGV, &linux_crash_handler, NULL);
sigaction(SIGBUS, &linuxCrashHandler, NULL);
sigaction(SIGFPE, &linuxCrashHandler, NULL);
sigaction(SIGILL, &linuxCrashHandler, NULL);
sigaction(SIGSEGV, &linuxCrashHandler, NULL);
#endif
}

View file

@ -5,7 +5,7 @@
#define CTX_BEGIN(_ctx) debug_context_begin(_ctx)
#define CTX_END(_ctx) debug_context_end(_ctx)
#define CTX_WITHIN(_ctx) debug_context_within(_ctx)
#define CTX_EXTENT(__ctx, __func) CTX_BEGIN(__ctx); __func(); CTX_END(__ctx);
#define CTX_EXTENT(_ctx, _f) { CTX_BEGIN(_ctx); _f(); CTX_END(_ctx); }
enum DebugContext {
CTX_NONE,

View file

@ -24,9 +24,26 @@ static u32 sDjuiLuaErrorTimeout = 0;
bool gDjuiInMainMenu = true;
bool gDjuiDisabled = false;
bool gDjuiRenderBehindHud = false;
static bool sDjuiInited = false;
bool sDjuiRendered60fps = false;
void reset_djui_text(void);
void reset_djui(void) {
sSavedDisplayListHead = NULL;
sDjuiPauseOptions = NULL;
sDjuiLuaError = NULL;
sDjuiLuaErrorTimeout = 0;
if (gDjuiRoot) djui_base_destroy(&gDjuiRoot->base);
if (gDjuiConsole) djui_base_destroy(&gDjuiConsole->panel->base);
extern u32 sDjuiConsoleMessages;
sDjuiConsoleMessages = 0;
sDjuiInited = false;
}
void patch_djui_before(void) {
sDjuiRendered60fps = false;
}
@ -68,6 +85,7 @@ void djui_init(void) {
djui_panel_playerlist_create(NULL);
djui_console_create();
sDjuiInited = true;
}
void djui_init_late(void) {
@ -91,6 +109,7 @@ void djui_connect_menu_open(void) {
}
void djui_lua_error(char* text) {
if (!sDjuiLuaError) { return; }
djui_text_set_text(sDjuiLuaError, text);
djui_base_set_visible(&sDjuiLuaError->base, true);
sDjuiLuaErrorTimeout = 30 * 5;
@ -105,7 +124,7 @@ void djui_reset_hud_params(void) {
}
void djui_render(void) {
if (gDjuiDisabled) { return; }
if (!sDjuiInited || gDjuiDisabled) { return; }
djui_reset_hud_params();
sSavedDisplayListHead = gDisplayListHead;

View file

@ -46,3 +46,5 @@ void djui_connect_menu_open(void);
void djui_lua_error(char* text);
void djui_render(void);
void djui_reset_hud_params(void);
void reset_djui(void);

View file

@ -25,6 +25,7 @@
#include "../platform.h"
#include "../configfile.h"
#include "../fs/fs.h"
#include "../pc_main.h"
#include "macros.h"
@ -1779,6 +1780,8 @@ void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi, co
gfx_rapi->init();
gfx_cc_precomp();
gGfxInited = true;
}
struct GfxRenderingAPI *gfx_get_current_rendering_api(void) {

193
src/pc/loading.c Normal file
View file

@ -0,0 +1,193 @@
#include "gfx_dimensions.h"
#include "game/segment2.h"
#include "djui/djui.h"
#include "pc/djui/djui_unicode.h"
#include "controller/controller_keyboard.h"
#include "pc_main.h"
#include "loading.h"
#include "pc/utils/misc.h"
struct LoadingSegment gCurrLoadingSegment = { "", 0 };
struct LoadingScreen {
struct DjuiBase base;
struct DjuiText* splashText;
struct DjuiText* loadingText;
struct DjuiText* loadingDesc;
struct DjuiProgressBar *loadingBar;
};
struct LoadingScreen* sLoading = NULL;
pthread_t gLoadingThreadId;
pthread_mutex_t gLoadingThreadMutex = PTHREAD_MUTEX_INITIALIZER;
bool gIsThreaded = false;
extern Vp D_8032CF00;
extern u8 gRenderingInterpolated;
static void loading_screen_produce_one_frame() {
// Start frame
gfx_start_frame();
config_gfx_pool();
init_render_image();
create_dl_ortho_matrix();
djui_gfx_displaylist_begin();
// Fix scaling issues
gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&D_8032CF00));
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - BORDER_HEIGHT);
// Clear screen
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 240.f, 0.f);
create_dl_scale_matrix(MENU_MTX_NOPUSH, (GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT) / 130.f, 3.f, 1.f);
gDPSetEnvColor(gDisplayListHead++, 0x00, 0x00, 0x00, 0xFF);
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
// Render loading screen elements
if (sLoading) { djui_base_render(&sLoading->base); }
// Render frame
djui_gfx_displaylist_end();
end_master_display_list();
alloc_display_list(0);
gfx_run((Gfx*) gGfxSPTask->task.t.data_ptr); // send_display_list
display_and_vsync();
gfx_end_frame();
}
static bool loading_screen_on_render(struct DjuiBase* base) {
pthread_mutex_lock(&gLoadingThreadMutex);
u32 windowWidth, windowHeight;
WAPI.get_dimensions(&windowWidth, &windowHeight);
f32 scale = djui_gfx_get_scale();
windowWidth /= scale;
windowHeight /= scale;
// Fill the screen
djui_base_set_size(base, windowWidth, windowHeight);
// Splash text
djui_base_set_location(&sLoading->splashText->base, (windowWidth / 2) - 416, 0);
{
// Loading... text
char* loadingStr = DLANG(LOADING_SCREEN, LOADING);
char tmp[20] = "";
switch ((u8) floor(clock_elapsed()) % 3) {
case 0: snprintf(tmp, 20, "%s...", loadingStr); break;
case 1: snprintf(tmp, 20, "%s.", loadingStr); break;
default: snprintf(tmp, 20, "%s..", loadingStr); break;
}
djui_text_set_text(sLoading->loadingText, tmp);
djui_base_set_visible(&sLoading->loadingText->base, sLoading->loadingText->base.y.value + 50 < sLoading->loadingDesc->base.y.value);
}
{
// Loading text description
char buffer[256] = "";
if (strlen(gCurrLoadingSegment.str) > 0) {
if (gCurrLoadingSegment.percentage > 0) {
snprintf(buffer, 256, "%s... %d%%", gCurrLoadingSegment.str, (u8) floor(gCurrLoadingSegment.percentage * 100));
} else {
snprintf(buffer, 256, "%s...", gCurrLoadingSegment.str);
}
}
djui_text_set_text(sLoading->loadingDesc, buffer);
djui_base_set_location(&sLoading->loadingDesc->base, 0, windowHeight - 250);
}
// Loading bar
djui_base_set_location(&sLoading->loadingBar->base, windowWidth / 4, windowHeight - 100);
djui_base_set_visible(&sLoading->loadingBar->base, gCurrLoadingSegment.percentage > 0 && strlen(gCurrLoadingSegment.str) > 0);
djui_base_compute(base);
pthread_mutex_unlock(&gLoadingThreadMutex);
return true;
}
static void loading_screen_destroy(struct DjuiBase* base) {
struct LoadingScreen* load = (struct LoadingScreen*)base;
free(load);
sLoading = NULL;
}
void render_loading_screen() {
struct LoadingScreen* load = malloc(sizeof(struct LoadingScreen));
struct DjuiBase* base = &load->base;
djui_base_init(NULL, base, loading_screen_on_render, loading_screen_destroy);
{
// Splash text
struct DjuiText* splashDjuiText = djui_text_create(base, "\\#ff0800\\SM\\#1be700\\64\\#00b3ff\\EX\\#ffef00\\COOP");
djui_text_set_font(splashDjuiText, gDjuiFonts[1]);
djui_text_set_font_scale(splashDjuiText, gDjuiFonts[1]->defaultFontScale * 4);
djui_text_set_alignment(splashDjuiText, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP);
djui_base_set_size(&splashDjuiText->base, 800, 800);
load->splashText = splashDjuiText;
}
{
// "Loading..." text
struct DjuiText *text = djui_text_create(base, "");
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&text->base, 1.0f, 32 * 4);
djui_base_set_color(&text->base, 200, 200, 200, 255);
djui_base_set_location(&text->base, 0, 400);
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
djui_text_set_font(text, gDjuiFonts[0]);
djui_text_set_font_scale(text, gDjuiFonts[0]->defaultFontScale * 2);
load->loadingText = text;
}
{
// Current loading stage text
struct DjuiText *text = djui_text_create(base, "");
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&text->base, 1.0f, 32 * 4);
djui_base_set_color(&text->base, 200, 200, 200, 255);
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP);
djui_text_set_font(text, gDjuiFonts[0]);
djui_text_set_font_scale(text, gDjuiFonts[0]->defaultFontScale * 2);
load->loadingDesc = text;
}
{
// Loading bar
struct DjuiProgressBar *progressBar = djui_progress_bar_create(base, &gCurrLoadingSegment.percentage, 0.0f, 1.0f, false);
djui_base_set_visible(&progressBar->base, false);
progressBar->base.width.value = 0.5;
load->loadingBar = progressBar;
}
sLoading = load;
// Loading screen loop
while (!gGameInited) {
WAPI.main_loop(loading_screen_produce_one_frame);
}
pthread_join(gLoadingThreadId, NULL);
// Reset some things after rendering the loading screen
reset_djui();
alloc_display_list_reset();
gDisplayListHead = NULL;
djui_init();
djui_unicode_init();
rendering_init();
configWindow.settings_changed = true;
}

25
src/pc/loading.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef LOADING_HEADER
#define LOADING_HEADER
#include <pthread.h>
struct LoadingSegment {
char str[256];
f32 percentage;
};
extern struct LoadingSegment gCurrLoadingSegment;
#define REFRESH_MUTEX(...) \
pthread_mutex_lock(&gLoadingThreadMutex); \
__VA_ARGS__; \
pthread_mutex_unlock(&gLoadingThreadMutex); \
extern pthread_t gLoadingThreadId;
extern pthread_mutex_t gLoadingThreadMutex;
extern bool gIsThreaded;
void render_loading_screen();
#endif

View file

@ -10,10 +10,7 @@
#include "pc/crash_handler.h"
#include "src/game/hud.h"
#include "pc/debug_context.h"
#include "pc/network/network.h"
#include "pc/network/network_player.h"
#include "pc/network/socket/socket.h"
#include "pc/chat_commands.h"
#include "pc/pc_main.h"
#if defined(DEVELOPMENT)
#include "../mods/mods.h"
@ -92,6 +89,8 @@ struct LuaHookedEvent {
static struct LuaHookedEvent sHookedEvents[HOOK_MAX] = { 0 };
int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct Mod* activeMod) {
if (!gGameInited) { return 0; } // Don't call hooks while the game is booting
struct Mod* prev = gLuaActiveMod;
gLuaActiveMod = activeMod;
gLuaLastHookMod = activeMod;

View file

@ -322,7 +322,7 @@ static bool mod_load_files(struct Mod* mod, char* modName, char* fullPath) {
const char* fileTypes[] = { ".bin", ".col", NULL };
if (!mod_load_files_dir(mod, fullPath, "actors", fileTypes)) { return false; }
}
// deal with behaviors directory
{
const char* fileTypes[] = { ".bhv", NULL };
@ -525,11 +525,11 @@ bool mod_load(struct Mods* mods, char* basePath, char* modName) {
}
// print
LOG_INFO(" %s", mod->name);
// LOG_INFO(" %s", mod->name);
for (int i = 0; i < mod->fileCount; i++) {
struct ModFile* file = &mod->files[i];
mod_cache_add(mod, file, true);
LOG_INFO(" - %s", file->relativePath);
// LOG_INFO(" - %s", file->relativePath);
}
return true;

View file

@ -230,6 +230,7 @@ bool mod_import_file(char* path) {
djui_language_replace(DLANG(NOTIF, IMPORT_MOD_SUCCESS), msg, SYS_MAX_PATH, '@', basename);
djui_popup_create(msg, 2);
} else if (isDynos) {
dynos_gfx_init();
dynos_packs_init();
djui_language_replace(DLANG(NOTIF, IMPORT_DYNOS_SUCCESS), msg, SYS_MAX_PATH, '@', basename);
djui_popup_create(msg, 2);

View file

@ -4,7 +4,7 @@
#include "mod_cache.h"
#include "data/dynos.c.h"
#include "pc/debuglog.h"
#include "pc/pc_main.h"
#include "pc/loading.h"
#define MAX_SESSION_CHARS 7
@ -147,7 +147,18 @@ static void mods_sort(struct Mods* mods) {
}
}
static void mods_load(struct Mods* mods, char* modsBasePath) {
static u32 mods_count_directory(char* modsBasePath) {
struct dirent* dir = NULL;
DIR* d = opendir(modsBasePath);
u32 pathCount = 0;
while ((dir = readdir(d)) != NULL) pathCount++;
closedir(d);
return pathCount;
}
static void mods_load(struct Mods* mods, char* modsBasePath, bool isUserModPath) {
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Generating DynOS Packs in %s mod path (%s)", isUserModPath ? "user" : "local", modsBasePath)); }
// generate bins
dynos_generate_packs(modsBasePath);
@ -174,10 +185,13 @@ static void mods_load(struct Mods* mods, char* modsBasePath) {
LOG_ERROR("Could not open directory '%s'", modsBasePath);
return;
}
f32 count = (f32) mods_count_directory(modsBasePath);
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading Mods in %s mod path (%s)", isUserModPath ? "user" : "local", modsBasePath)); }
// iterate
char path[SYS_MAX_PATH] = { 0 };
while ((dir = readdir(d)) != NULL) {
for (u32 i = 0; (dir = readdir(d)) != NULL; ++i) {
// sanity check / fill path[]
if (!directory_sanity_check(dir, modsBasePath, path)) { continue; }
@ -185,10 +199,11 @@ static void mods_load(struct Mods* mods, char* modsBasePath) {
if (!mod_load(mods, modsBasePath, dir->d_name)) {
break;
}
if (gIsThreaded) { REFRESH_MUTEX(gCurrLoadingSegment.percentage = (f32) i / count); }
}
closedir(d);
if (gIsThreaded) { REFRESH_MUTEX(gCurrLoadingSegment.percentage = 1); }
}
void mods_refresh_local(void) {
@ -208,13 +223,13 @@ void mods_refresh_local(void) {
mods_clear(&gLocalMods);
// load mods
if (hasUserPath) { mods_load(&gLocalMods, userModPath); }
if (hasUserPath) { mods_load(&gLocalMods, userModPath, true); }
const char* exePath = path_to_executable();
char defaultModsPath[SYS_MAX_PATH] = { 0 };
path_get_folder((char*)exePath, defaultModsPath);
strncat(defaultModsPath, MOD_DIRECTORY, SYS_MAX_PATH-1);
mods_load(&gLocalMods, defaultModsPath);
mods_load(&gLocalMods, defaultModsPath, false);
// sort
mods_sort(&gLocalMods);
@ -242,6 +257,8 @@ void mods_enable(char* relativePath) {
}
void mods_init(void) {
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Caching mods")); }
// load mod cache
mod_cache_load();
mods_refresh_local();

View file

@ -19,6 +19,7 @@
#include "audio/audio_null.h"
#include "pc_main.h"
#include "loading.h"
#include "cliopts.h"
#include "configfile.h"
#include "controller/controller_api.h"
@ -238,8 +239,10 @@ void audio_shutdown(void) {
}
void game_deinit(void) {
smlua_call_event_hooks(HOOK_ON_EXIT);
configfile_save(configfile_name());
if (gGameInited) {
smlua_call_event_hooks(HOOK_ON_EXIT);
configfile_save(configfile_name());
}
controller_shutdown();
audio_custom_shutdown();
audio_shutdown();
@ -256,24 +259,28 @@ void game_exit(void) {
exit(0);
}
void main_func(void) {
void *main_game_init(void*) {
const char *gamedir = gCLIOpts.GameDir[0] ? gCLIOpts.GameDir : FS_BASEDIR;
const char *userpath = gCLIOpts.SavePath[0] ? gCLIOpts.SavePath : sys_user_path();
fs_init(sys_ropaths, gamedir, userpath);
sync_objects_init_system();
djui_unicode_init();
djui_init();
dynos_packs_init();
mods_init();
dynos_gfx_init();
// load config
configfile_load();
if (!djui_language_init(configLanguage)) {
snprintf(configLanguage, MAX_CONFIG_STRING, "%s", "");
}
configWindow.settings_changed = true;
if (!djui_language_init(configLanguage)) { snprintf(configLanguage, MAX_CONFIG_STRING, "%s", ""); }
dynos_packs_init();
sync_objects_init_system();
dynos_pack_init();
mods_init();
enable_queued_mods();
if (gIsThreaded) {
REFRESH_MUTEX(
gCurrLoadingSegment.percentage = 0;
snprintf(gCurrLoadingSegment.str, 256, "Starting game");
);
}
// If coop_custom_palette_* values are not found in sm64config.txt, the custom palette config will use the default values (Mario's palette)
// But if no preset is found, that means the current palette is a custom palette
@ -292,7 +299,6 @@ void main_func(void) {
if (gCLIOpts.FullScreen == 1) { configWindow.fullscreen = true; }
else if (gCLIOpts.FullScreen == 2) { configWindow.fullscreen = false; }
// incase the loading screen failed, or is disabled
if (!gGfxInited) {
gfx_init(&WAPI, &RAPI, TITLE);
WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_text_input);
@ -310,9 +316,36 @@ void main_func(void) {
thread5_game_loop(NULL);
gGameInited = true;
}
int main(int argc, char *argv[]) {
// Handle terminal arguments
if (!parse_cli_opts(argc, argv)) { return 0; }
// Create the window straight away
if (!gGfxInited) {
gfx_init(&WAPI, &RAPI, TITLE);
WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_text_input);
}
// Start the thread for setting up the game
if (pthread_mutex_init(&gLoadingThreadMutex, NULL) == 0 && pthread_create(&gLoadingThreadId, NULL, main_game_init, (void*) 1) == 0) {
gIsThreaded = true;
render_loading_screen(); // Render the loading screen while the game is setup
gIsThreaded = false;
} else {
main_game_init(NULL); // Failsafe incase threading doesn't work
}
pthread_mutex_destroy(&gLoadingThreadMutex);
// Initialize djui
djui_init();
djui_unicode_init();
djui_init_late();
// init network
// Init network
if (gCLIOpts.Network == NT_CLIENT) {
network_set_system(NS_SOCKET);
snprintf(gGetHostName, MAX_CONFIG_STRING, "%s", gCLIOpts.JoinIp);
@ -322,6 +355,12 @@ void main_func(void) {
} else if (gCLIOpts.Network == NT_SERVER) {
network_set_system(NS_SOCKET);
configHostPort = gCLIOpts.NetworkPort;
// Horrible, hacky fix for mods that access marioObj straight away
// best fix: host with the standard main menu method
static struct Object sHackyObject = { 0 };
gMarioStates[0].marioObj = &sHackyObject;
network_init(NT_SERVER, false);
djui_panel_shutdown();
djui_panel_modlist_create(NULL);
@ -329,8 +368,7 @@ void main_func(void) {
network_init(NT_NONE, false);
}
gGameInited = true;
// Main loop
while (true) {
debug_context_reset();
CTX_BEGIN(CTX_FRAME);
@ -346,10 +384,5 @@ void main_func(void) {
}
bassh_deinit();
}
int main(int argc, char *argv[]) {
parse_cli_opts(argc, argv);
main_func();
return 0;
}

View file

@ -60,8 +60,6 @@ extern bool gCoopCompatibility;
#define TITLE "sm64coopdx"
#endif
#define LOAD_STEPS 6
#define AT_STARTUP __attribute__((constructor))
extern bool gGameInited;