diff --git a/.github/macos/macports.yaml b/.github/macos/macports.yaml index a51ccec..87b3025 100644 --- a/.github/macos/macports.yaml +++ b/.github/macos/macports.yaml @@ -1,4 +1,4 @@ -version: '2.9.3' +version: '2.10.6' prefix: '/opt/local' variants: select: @@ -6,9 +6,11 @@ variants: - metal deselect: x11 ports: - - name: clang-18 - - name: llvm-18 + - name: libiconv + select: universal - name: libsdl2 select: universal - name: freetype select: universal + - name: clang-18 + - name: llvm-18 diff --git a/CMakeLists.txt b/CMakeLists.txt index 5525958..ab1e3a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,10 @@ if (APPLE) enable_language(OBJC OBJCXX) endif() +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + option(RECOMP_FLATPAK "Configure the build for Flatpak compatibility." OFF) +endif() + # Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24: if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") cmake_policy(SET CMP0135 NEW) @@ -41,6 +45,10 @@ set(RT64_STATIC TRUE) set(RT64_SDL_WINDOW_VULKAN TRUE) add_compile_definitions(HLSL_CPU) +if (RECOMP_FLATPAK) + add_compile_definitions(RECOMP_FLATPAK) +endif() + add_subdirectory(${CMAKE_SOURCE_DIR}/lib/rt64 ${CMAKE_BINARY_DIR}/rt64) # set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}") diff --git a/assets/recomp.rcss b/assets/recomp.rcss index 0b7bd7b..4aa0135 100644 --- a/assets/recomp.rcss +++ b/assets/recomp.rcss @@ -1656,6 +1656,7 @@ scrollbarhorizontal sliderbar { flex-direction: row; justify-content: space-between; width: 268dp; + min-width: 1dp; height: 128dp; margin-right: 10dp; } diff --git a/assets/scss/styles/components/InputConfig.scss b/assets/scss/styles/components/InputConfig.scss index 71ba960..c01374e 100644 --- a/assets/scss/styles/components/InputConfig.scss +++ b/assets/scss/styles/components/InputConfig.scss @@ -342,6 +342,8 @@ $stick-size: 200; flex-direction: row; justify-content: space-between; width: space(268); + // WORKAROUND FIX: prevents RMLui assert error + min-width: 1dp; height: space(128); margin-right: space(10); } diff --git a/flatpak/io.github.zelda64recomp.zelda64recomp.json b/flatpak/io.github.zelda64recomp.zelda64recomp.json index 8430401..179167a 100644 --- a/flatpak/io.github.zelda64recomp.zelda64recomp.json +++ b/flatpak/io.github.zelda64recomp.zelda64recomp.json @@ -28,7 +28,7 @@ "./N64Recomp us.rev1.toml", "./RSPRecomp aspMain.us.rev1.toml", "./RSPRecomp njpgdspMain.us.rev1.toml", - "cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_MAKE_PROGRAM=ninja -DPATCHES_C_COMPILER=clang -DPATCHES_LD=ld.lld -G Ninja -S . -B cmake-build", + "cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_MAKE_PROGRAM=ninja -DPATCHES_C_COMPILER=clang -DPATCHES_LD=ld.lld -DRECOMP_FLATPAK=ON -G Ninja -S . -B cmake-build", "cmake --build cmake-build --config Release --target Zelda64Recompiled --parallel", "rm -rf assets/scss", "mkdir -p /app/bin", diff --git a/include/recomp_ui.h b/include/recomp_ui.h index 66edca1..f609a52 100644 --- a/include/recomp_ui.h +++ b/include/recomp_ui.h @@ -69,6 +69,7 @@ namespace recompui { }; void set_config_tab(ConfigTab tab); + int config_tab_to_index(ConfigTab tab); Rml::ElementTabSet* get_config_tabset(); Rml::Element* get_mod_tab(); void set_config_tabset_mod_nav(); diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index 0aa75b9..c5e268a 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit 0aa75b98baaef9d23a0d2cf51c8b44fd857c8fe1 +Subproject commit c5e268aa0f71cf06a10a001da981dc3e02e7dff0 diff --git a/lib/rt64 b/lib/rt64 index 793abe0..ada6cc6 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit 793abe0bc39a842bab8176264eb0003324c58f1b +Subproject commit ada6cc62c421b142d9d90154765e44348115bd9e diff --git a/patches/save_patches.c b/patches/save_patches.c index 5eeba3a..2ebf234 100644 --- a/patches/save_patches.c +++ b/patches/save_patches.c @@ -11,7 +11,7 @@ void Sleep_Msec(u32 ms); extern u16 D_801F6AF0; extern u8 D_801F6AF2; -// @recomp Patched to not wait a hardcoded amount of time for the save to complete. +// @recomp Patched to wait a much shorter amount of time for the save to complete. RECOMP_PATCH void Sram_UpdateWriteToFlashDefault(SramContext* sramCtx) { if (sramCtx->status == 2) { if (SysFlashrom_IsBusy() != 0) { // if task running @@ -23,13 +23,13 @@ RECOMP_PATCH void Sram_UpdateWriteToFlashDefault(SramContext* sramCtx) { sramCtx->status = 4; } } - } else if (sramCtx->status == 4) { - // @recomp Patched to check status instead of using a hardcoded wait. + } else if (OSTIME_TO_TIMER(osGetTime() - sramCtx->startWriteOsTime) >= SECONDS_TO_TIMER_PRECISE(0, 25)) { + // @recomp Patched to wait a much shorter amount of time. sramCtx->status = 0; } } -// @recomp Patched to not wait a hardcoded amount of time for the save to complete. +// @recomp Patched to wait a much shorter amount of time for the save to complete. RECOMP_PATCH void Sram_UpdateWriteToFlashOwlSave(SramContext* sramCtx) { if (sramCtx->status == 7) { if (SysFlashrom_IsBusy() != 0) { // Is task running @@ -49,8 +49,8 @@ RECOMP_PATCH void Sram_UpdateWriteToFlashOwlSave(SramContext* sramCtx) { sramCtx->status = 4; } } - } else if (sramCtx->status == 4) { - // @recomp Patched to check status instead of using a hardcoded wait. + } else if (OSTIME_TO_TIMER(osGetTime() - sramCtx->startWriteOsTime) >= SECONDS_TO_TIMER_PRECISE(0, 25)) { + // @recomp Patched to wait a much shorter amount of time. sramCtx->status = 0; bzero(sramCtx->saveBuf, SAVE_BUFFER_SIZE); gSaveContext.save.isOwlSave = false; diff --git a/src/game/input.cpp b/src/game/input.cpp index 16775e7..f06a5b1 100644 --- a/src/game/input.cpp +++ b/src/game/input.cpp @@ -287,6 +287,10 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) { case SDL_EventType::SDL_DROPCOMPLETE: recompui::drop_files(DropState.files_dropped); break; + case SDL_EventType::SDL_CONTROLLERBUTTONUP: + // Always queue button up events to avoid missing them during binding. + recompui::queue_event(*event); + break; default: queue_if_enabled(event); break; diff --git a/src/main/main.cpp b/src/main/main.cpp index f075a6d..19aa1f1 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -48,7 +48,7 @@ #include "../../lib/rt64/src/contrib/stb/stb_image.h" -const std::string version_string = "1.2.0-dev"; +const std::string version_string = "1.2.0-rc9"; template void exit_error(const char* str, Ts ...args) { @@ -601,7 +601,14 @@ int main(int argc, char** argv) { // Force wasapi on Windows, as there seems to be some issue with sample queueing with directsound currently. SDL_setenv("SDL_AUDIODRIVER", "wasapi", true); #endif - //printf("Current dir: %ls\n", std::filesystem::current_path().c_str()); + +#if defined(__linux__) && defined(RECOMP_FLATPAK) + // When using Flatpak, applications tend to launch from the home directory by default. + // Mods might use the current working directory to store the data, so we switch it to a directory + // with persistent data storage and write permissions under Flatpak to ensure it works. + std::error_code ec; + std::filesystem::current_path("/var/data", ec); +#endif // Initialize SDL audio and set the output frequency. SDL_InitSubSystem(SDL_INIT_AUDIO); diff --git a/src/main/support.cpp b/src/main/support.cpp index daad4d2..6bdbb74 100644 --- a/src/main/support.cpp +++ b/src/main/support.cpp @@ -48,13 +48,11 @@ namespace zelda64 { std::filesystem::path get_program_path() { #if defined(__APPLE__) return get_bundle_resource_directory(); -#elif defined(__linux__) - std::error_code ec; - if (std::filesystem::exists("/.flatpak-info", ec)) { - return "/app/bin"; - } -#endif +#elif defined(__linux__) && defined(RECOMP_FLATPAK) + return "/app/bin"; +#else return ""; +#endif } std::filesystem::path get_asset_path(const char* asset) { diff --git a/src/ui/core/ui_context.cpp b/src/ui/core/ui_context.cpp index 2fbed61..cff69fc 100644 --- a/src/ui/core/ui_context.cpp +++ b/src/ui/core/ui_context.cpp @@ -36,7 +36,8 @@ namespace recompui { Element root_element; Element* autofocus_element = nullptr; std::vector loose_elements; - std::unordered_set to_update; + std::unordered_set to_update; + std::vector> to_set_text; bool captures_input = true; bool captures_mouse = true; Context(Rml::ElementDocument* document) : document(document), root_element(document) {} @@ -67,6 +68,8 @@ enum class ContextErrorType { AddResourceToWrongContext, UpdateElementWithoutContext, UpdateElementInWrongContext, + SetTextElementWithoutContext, + SetTextElementInWrongContext, GetResourceWithoutOpen, GetResourceFailed, DestroyResourceWithoutOpen, @@ -119,6 +122,12 @@ void context_error(recompui::ContextId id, ContextErrorType type) { case ContextErrorType::UpdateElementInWrongContext: error_message = "Attempted to update a UI element in a different UI context than the one that's open"; break; + case ContextErrorType::SetTextElementWithoutContext: + error_message = "Attempted to set the text of a UI element with no open UI context"; + break; + case ContextErrorType::SetTextElementInWrongContext: + error_message = "Attempted to set the text of a UI element in a different UI context than the one that's open"; + break; case ContextErrorType::GetResourceWithoutOpen: error_message = "Attempted to get a UI resource with no open UI context"; break; @@ -407,6 +416,40 @@ void recompui::ContextId::process_updates() { static_cast(cur_resource->get())->handle_event(update_event); } + + std::vector> to_set_text = std::move(opened_context->to_set_text); + + // Delete the Rml elements that are pending deletion. + for (auto cur_text_update : to_set_text) { + Element* element_ptr = std::get<0>(cur_text_update); + ResourceId resource = std::get<1>(cur_text_update); + std::string& text = std::get<2>(cur_text_update); + + // If the resource ID is valid, prefer that as we can quickly validate if the resource still exists. + if (resource != ResourceId::null()) { + resource_slotmap::key cur_key{ resource.slot_id }; + std::unique_ptr