diff --git a/autogen/convert_functions.py b/autogen/convert_functions.py index 78f1e1fc..e5f2b250 100644 --- a/autogen/convert_functions.py +++ b/autogen/convert_functions.py @@ -41,6 +41,7 @@ in_files = [ "src/pc/lua/utils/smlua_collision_utils.h", "src/pc/lua/utils/smlua_model_utils.h", "src/pc/lua/utils/smlua_text_utils.h", + "src/pc/lua/utils/smlua_audio_utils.h", "src/game/object_helpers.c", "src/game/obj_behaviors.c", "src/game/obj_behaviors_2.c", @@ -58,7 +59,7 @@ override_allowed_functions = { "src/game/save_file.h": [ "save_file_get_", "save_file_set_flags", "save_file_clear_flags" ], "src/pc/lua/utils/smlua_model_utils.h": [ "smlua_model_util_get_id" ], "src/game/object_list_processor.h": [ "set_object_respawn_info_bits" ], - "src/game/mario_misc.h": [ "bhv_toad.*", "bhv_unlock_door.*" ] + "src/game/mario_misc.h": [ "bhv_toad.*", "bhv_unlock_door.*" ], } override_disallowed_functions = { @@ -84,7 +85,8 @@ override_disallowed_functions = { "src/game/spawn_sound.c": [ "spawner" ], "src/pc/lua/utils/smlua_obj_utils.h": [ "spawn_object_remember_field" ], "src/game/camera.h": [ "update_camera", "init_camera", "stub_camera", "^reset_camera", "move_point_along_spline" ], - "src/game/behavior_actions.h": [ "bhv_dust_smoke_loop", "bhv_init_room" ] + "src/game/behavior_actions.h": [ "bhv_dust_smoke_loop", "bhv_init_room" ], + "src/pc/lua/utils/smlua_audio_utils.h": [ "smlua_audio_utils_override"], } lua_function_params = { diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 25c923b2..dd93f768 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -7017,6 +7017,14 @@ function save_file_set_flags(flags) -- ... end +--- @param sequenceId integer +--- @param bankId integer +--- @param m64Name string +--- @return nil +function smlua_audio_utils_replace_sequence(sequenceId, bankId, m64Name) + -- ... +end + --- @param startX number --- @param startY number --- @param startZ number diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 65ef7ac0..b66f80f7 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -1302,6 +1302,11 @@
+- smlua_audio_utils.h + - [smlua_audio_utils_replace_sequence](#smlua_audio_utils_replace_sequence) + +
+ - smlua_collision_utils.h - [collision_find_surface_on_ray](#collision_find_surface_on_ray) - [get_water_surface_pseudo_floor](#get_water_surface_pseudo_floor) @@ -24550,6 +24555,34 @@ The `reliable` field will ensure that the packet arrives, but should be used spa
+--- +# functions from smlua_audio_utils.h + +
+ + +## [smlua_audio_utils_replace_sequence](#smlua_audio_utils_replace_sequence) + +### Lua Example +`smlua_audio_utils_replace_sequence(sequenceId, bankId, m64Name)` + +### Parameters +| Field | Type | +| ----- | ---- | +| sequenceId | `integer` | +| bankId | `integer` | +| m64Name | `string` | + +### Returns +- None + +### C Prototype +`void smlua_audio_utils_replace_sequence(u8 sequenceId, u8 bankId, const char* m64Name);` + +[:arrow_up_small:](#) + +
+ --- # functions from smlua_collision_utils.h diff --git a/src/audio/load.c b/src/audio/load.c index 00bd0327..ba2ffbb8 100644 --- a/src/audio/load.c +++ b/src/audio/load.c @@ -10,6 +10,7 @@ #include "pc/platform.h" #include "pc/fs/fs.h" +#include "pc/lua/utils/smlua_audio_utils.h" #define ALIGN16(val) (((val) + 0xF) & ~0xF) @@ -1374,6 +1375,7 @@ void *sequence_dma_immediate(s32 seqId, s32 arg1) { seqLength = gSeqFileHeader->seqArray[seqId].len + 0xf; seqLength = ALIGN16(seqLength); seqData = gSeqFileHeader->seqArray[seqId].offset; + ptr = alloc_bank_or_seq(&gSeqLoadedPool, 1, seqLength, arg1, seqId); if (ptr == NULL) { return NULL; @@ -1396,6 +1398,7 @@ void *sequence_dma_async(s32 seqId, s32 arg1, struct SequencePlayer *seqPlayer) seqLength = gSeqFileHeader->seqArray[seqId].len + 0xf; seqLength = ALIGN16(seqLength); seqData = gSeqFileHeader->seqArray[seqId].offset; + ptr = alloc_bank_or_seq(&gSeqLoadedPool, 1, seqLength, arg1, seqId); if (ptr == NULL) { eu_stubbed_printf_0("Heap Overflow Error\n"); @@ -1558,6 +1561,25 @@ void load_sequence_internal(u32 player, u32 seqId, s32 loadAsync) { struct SequencePlayer *seqPlayer = &gSequencePlayers[player]; UNUSED u32 padding[2]; + // do custom music override + { + s32 bankId = 0; + if (smlua_audio_utils_override(seqId, &bankId, &sequenceData)) { + sequence_player_disable(seqPlayer); + seqPlayer->defaultBank[0] = bankId; + if (!bank_load_immediate(bankId, 2)) { return; } + seqPlayer->seqId = seqId; + gSeqLoadStatus[seqId] = SOUND_LOAD_STATUS_COMPLETE; + init_sequence_player(player); + seqPlayer->scriptState.depth = 0; + seqPlayer->delay = 0; + seqPlayer->enabled = TRUE; + seqPlayer->seqData = sequenceData; + seqPlayer->scriptState.pc = sequenceData; + return; + } + } + if (seqId >= gSequenceCount) { return; } diff --git a/src/game/level_update.c b/src/game/level_update.c index 84e07148..9a9e0fbd 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -1561,4 +1561,7 @@ void fake_lvl_init_from_save_file(void) { save_file_move_cap_to_default_location(); select_mario_cam_mode(); set_yoshi_as_not_dead(); + fadeout_music(30); + + gChangeLevel = gLevelValues.entryLevel; } diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index 5a4fea1d..dd5dfdc6 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -143,6 +143,7 @@ void smlua_update(void) { void smlua_shutdown(void) { smlua_text_utils_reset_all(); + smlua_audio_utils_reset_all(); smlua_cobject_allowlist_shutdown(); smlua_cpointer_allowlist_shutdown(); lua_State* L = gLuaState; diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 7c23fb56..5a50f171 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -24,6 +24,7 @@ #include "src/pc/lua/utils/smlua_collision_utils.h" #include "src/pc/lua/utils/smlua_model_utils.h" #include "src/pc/lua/utils/smlua_text_utils.h" +#include "src/pc/lua/utils/smlua_audio_utils.h" #include "src/engine/surface_load.h" #include "src/game/object_list_processor.h" #include "src/game/behavior_actions.h" @@ -13182,6 +13183,24 @@ int smlua_func_find_unimportant_object(UNUSED lua_State* L) { return 1; } +/* +int smlua_func_geo_choose_area_ext(lua_State* L) { + if(!smlua_functions_valid_param_count(L, 3)) { return 0; } + + s32 callContext = smlua_to_integer(L, 1); + if (!gSmLuaConvertSuccess) { return 0; } + struct GraphNode* node = (struct GraphNode*)smlua_to_cobject(L, 2, LOT_GRAPHNODE); + if (!gSmLuaConvertSuccess) { return 0; } +// Mat4 mtx = (Mat4)smlua_to_cobject(L, 3, LOT_???); <--- UNIMPLEMENTED + if (!gSmLuaConvertSuccess) { return 0; } + + extern Gfx *geo_choose_area_ext(UNUSED s32 callContext, struct GraphNode *node, UNUSED Mat4 mtx); + UNIMPLEMENTED -->(L, geo_choose_area_ext(callContext, node, mtx)); + + return 1; +} +*/ + int smlua_func_geo_offset_klepto_debug(lua_State* L) { if(!smlua_functions_valid_param_count(L, 3)) { return 0; } @@ -14597,6 +14616,25 @@ int smlua_func_save_file_set_flags(lua_State* L) { return 1; } + ///////////////////////// + // smlua_audio_utils.h // +///////////////////////// + +int smlua_func_smlua_audio_utils_replace_sequence(lua_State* L) { + if(!smlua_functions_valid_param_count(L, 3)) { return 0; } + + u8 sequenceId = smlua_to_integer(L, 1); + if (!gSmLuaConvertSuccess) { return 0; } + u8 bankId = smlua_to_integer(L, 2); + if (!gSmLuaConvertSuccess) { return 0; } + const char* m64Name = smlua_to_string(L, 3); + if (!gSmLuaConvertSuccess) { return 0; } + + smlua_audio_utils_replace_sequence(sequenceId, bankId, m64Name); + + return 1; +} + ///////////////////////////// // smlua_collision_utils.h // ///////////////////////////// @@ -16827,6 +16865,7 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "enable_time_stop_including_mario", smlua_func_enable_time_stop_including_mario); smlua_bind_function(L, "find_object_with_behavior", smlua_func_find_object_with_behavior); smlua_bind_function(L, "find_unimportant_object", smlua_func_find_unimportant_object); + //smlua_bind_function(L, "geo_choose_area_ext", smlua_func_geo_choose_area_ext); <--- UNIMPLEMENTED smlua_bind_function(L, "geo_offset_klepto_debug", smlua_func_geo_offset_klepto_debug); //smlua_bind_function(L, "geo_offset_klepto_held_object", smlua_func_geo_offset_klepto_held_object); <--- UNIMPLEMENTED //smlua_bind_function(L, "geo_switch_anim_state", smlua_func_geo_switch_anim_state); <--- UNIMPLEMENTED @@ -16930,6 +16969,9 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "save_file_get_total_star_count", smlua_func_save_file_get_total_star_count); smlua_bind_function(L, "save_file_set_flags", smlua_func_save_file_set_flags); + // smlua_audio_utils.h + smlua_bind_function(L, "smlua_audio_utils_replace_sequence", smlua_func_smlua_audio_utils_replace_sequence); + // smlua_collision_utils.h smlua_bind_function(L, "collision_find_surface_on_ray", smlua_func_collision_find_surface_on_ray); smlua_bind_function(L, "get_water_surface_pseudo_floor", smlua_func_get_water_surface_pseudo_floor); diff --git a/src/pc/lua/utils/smlua_audio_utils.c b/src/pc/lua/utils/smlua_audio_utils.c new file mode 100644 index 00000000..7bb2e394 --- /dev/null +++ b/src/pc/lua/utils/smlua_audio_utils.c @@ -0,0 +1,119 @@ +#include "types.h" +#include "pc/mods/mods.h" +#include "pc/lua/smlua.h" +#include "pc/debuglog.h" + +#define MAX_OVERRIDE 64 + +struct AudioOverride { + bool enabled; + bool loaded; + const char* filename; + u64 length; + u8 bank; + u8* buffer; +}; + +struct AudioOverride sAudioOverrides[MAX_OVERRIDE] = { 0 }; + +static smlua_audio_utils_reset(struct AudioOverride* override) { + if (override == NULL) { return; } + + override->enabled = false; + override->loaded = false; + + if (override->filename) { + free(override->filename); + override->filename = NULL; + } + + override->length = 0; + override->bank = 0; + + if (override->buffer != NULL) { + free(override->filename); + override->filename = NULL; + } +} + +void smlua_audio_utils_reset_all(void) { + for (s32 i = 0; i < MAX_OVERRIDE; i++) { + smlua_audio_utils_reset(&sAudioOverrides[i]); + } +} + +bool smlua_audio_utils_override(u8 sequenceId, s32* bankId, void** seqData) { + if (sequenceId >= MAX_OVERRIDE) { return false; } + struct AudioOverride* override = &sAudioOverrides[sequenceId]; + if (!override->enabled) { return false; } + + if (override->loaded) { + *seqData = override->buffer; + *bankId = override->bank; + return true; + } + + static u8* buffer = NULL; + static long int length = 0; + + FILE* fp = fopen(override->filename, "rb"); + if (!fp) { return false; } + fseek(fp, 0L, SEEK_END); + length = ftell(fp); + + buffer = malloc(length+1); + if (buffer == NULL) { + LOG_ERROR("Failed to malloc m64 sound file"); + fclose(fp); + return false; + } + + fseek(fp, 0L, SEEK_SET); + fread(buffer, length, 1, fp); + + fclose(fp); + + // cache + override->loaded = true; + override->buffer = buffer; + override->length = length; + + *seqData = buffer; + *bankId = override->bank; + return true; +} + +void smlua_audio_utils_replace_sequence(u8 sequenceId, u8 bankId, const char* m64Name) { + if (gLuaActiveMod == NULL) { return; } + if (sequenceId >= MAX_OVERRIDE) { + LOG_LUA("Invalid sequenceId given to smlua_audio_utils_replace_sequence(): %d", sequenceId); + return; + } + + char m64path[SYS_MAX_PATH] = { 0 }; + if (snprintf(m64path, SYS_MAX_PATH-1, "sound/%s.m64", m64Name) < 0) { + LOG_LUA("Could not find m64 at path: %s", m64path); + return; + } + + for (s32 i = 0; i < gLuaActiveMod->fileCount; i++) { + struct ModFile* file = &gLuaActiveMod->files[i]; + if (!strcmp(file->relativePath, m64path)) { + + char fullPath[SYS_MAX_PATH] = { 0 }; + if (snprintf(fullPath, SYS_MAX_PATH - 1, "%s/%s", gLuaActiveMod->basePath, m64path) < 0) { + LOG_ERROR("Failed to concat full path to m64: %s", m64Name); + return; + } + + struct AudioOverride* override = &sAudioOverrides[sequenceId]; + smlua_audio_utils_reset(override); + override->filename = strdup(fullPath); + override->enabled = true; + override->bank = bankId; + return; + } + } + + LOG_LUA("Could not find m64 at path: %s", m64path); +} diff --git a/src/pc/lua/utils/smlua_audio_utils.h b/src/pc/lua/utils/smlua_audio_utils.h new file mode 100644 index 00000000..c2891cc3 --- /dev/null +++ b/src/pc/lua/utils/smlua_audio_utils.h @@ -0,0 +1,8 @@ +#ifndef SMLUA_AUDIO_UTILS_H +#define SMLUA_AUDIO_UTILS_H + +bool smlua_audio_utils_override(u8 sequenceId, s32* bankId, void** seqData); + +void smlua_audio_utils_replace_sequence(u8 sequenceId, u8 bankId, const char* m64Name); + +#endif \ No newline at end of file diff --git a/src/pc/mods/mod.c b/src/pc/mods/mod.c index 1af16c45..c0b33fb6 100644 --- a/src/pc/mods/mod.c +++ b/src/pc/mods/mod.c @@ -295,6 +295,44 @@ static bool mod_load_files(struct Mod* mod, char* modName, char* fullPath) { closedir(d); } } + + // deal with sound directory + { + // concat sound directory + char soundPath[SYS_MAX_PATH] = { 0 }; + if (!concat_path(soundPath, fullPath, "sound")) { + LOG_ERROR("Could not concat directory '%s' + '%s'", fullPath, "sound"); + return false; + } + + // open sound directory + struct dirent* dir = NULL; + DIR* d = opendir(soundPath); + if (d) { + // iterate mod directory + char path[SYS_MAX_PATH] = { 0 }; + char relativePath[SYS_MAX_PATH] = { 0 }; + while ((dir = readdir(d)) != NULL) { + // sanity check / fill path[] + if (!directory_sanity_check(dir, soundPath, path)) { continue; } + if (snprintf(relativePath, SYS_MAX_PATH - 1, "sound/%s", dir->d_name) < 0) { + LOG_ERROR("Could not concat sound path!"); + return false; + } + + // only consider m64 files + if (!str_ends_with(path, ".m64")) { + continue; + } + + // allocate file + struct ModFile* file = mod_allocate_file(mod, relativePath); + if (file == NULL) { return false; } + } + + closedir(d); + } + } return true; } diff --git a/src/pc/network/network.c b/src/pc/network/network.c index d4412299..dfa37403 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -4,6 +4,7 @@ #include "object_fields.h" #include "object_constants.h" #include "behavior_table.h" +#include "src/game/hardcoded.h" #ifdef DISCORD_SDK #include "discord/discord.h" #endif