From 501ff1b02bc6b9e92fba1cd9e89628b2a9545e5c Mon Sep 17 00:00:00 2001 From: DepressedTWM Date: Mon, 27 Jul 2026 16:09:52 +0400 Subject: [PATCH] Mrowg --- MODDING.md | 1 + binding-mri/binding-mri.cpp | 3 + binding-mri/filesystem-binding.cpp | 3 +- binding-mri/sunshine-binding.cpp | 6 ++ changelogs/0.1.2.txt | 1 + scripts/CMakeLists.txt | 3 +- scripts/Data_Settings.rb | 60 +++++++++++--- scripts/Data_Settings_Setters.rb | 19 ++++- scripts/ModAPI.rb | 3 + scripts/_scripts.txt | 3 + src/main.cpp | 16 +--- src/modloader.cpp | 127 +++-------------------------- src/modloader.h | 4 +- 13 files changed, 97 insertions(+), 152 deletions(-) create mode 100644 MODDING.md create mode 100644 scripts/ModAPI.rb diff --git a/MODDING.md b/MODDING.md new file mode 100644 index 0000000..c08bbdc --- /dev/null +++ b/MODDING.md @@ -0,0 +1 @@ +# How Sunshine ModLoader work diff --git a/binding-mri/binding-mri.cpp b/binding-mri/binding-mri.cpp index 8465ae4..a08c0cd 100644 --- a/binding-mri/binding-mri.cpp +++ b/binding-mri/binding-mri.cpp @@ -32,6 +32,7 @@ #include "boost-hash.h" #include "meow.h" #include "sunshine.h" +#include "modloader.h" #include #include @@ -178,6 +179,7 @@ static void mriBindingInit(){ SunshineBindingInit(); steamBindingInit(); shaderBindingInit(); + ModLoader(); ModLoaderBindingInit(); keybindingsBindingInit(); lightmapBindingInit(); @@ -198,6 +200,7 @@ static void mriBindingInit(){ _rb_define_module_function(mod, "puts", mkxpPuts); _rb_define_module_function(mod, "raw_key_states", mkxpRawKeyStates); _rb_define_module_function(mod, "mouse_in_window", mkxpMouseInWindow); + } static void printP(int argc, VALUE *argv, const char *convMethod, const char *sep){ diff --git a/binding-mri/filesystem-binding.cpp b/binding-mri/filesystem-binding.cpp index c995efd..98137ee 100644 --- a/binding-mri/filesystem-binding.cpp +++ b/binding-mri/filesystem-binding.cpp @@ -186,8 +186,7 @@ RB_METHOD(_marshalLoad){ VALUE marsh = rb_const_get(rb_cObject, rb_intern("Marshal")); VALUE v[] = { port, utf8Proc }; - return rb_marshal_load(port); // uh.. well.. it works now at least. - //return rb_funcall_with_block(marsh, rb_intern("_mkxp_load_alias"), 1, &port, utf8Proc); + return rb_marshal_load(port); } void fileIntBindingInit(){ diff --git a/binding-mri/sunshine-binding.cpp b/binding-mri/sunshine-binding.cpp index 007aec9..e868482 100644 --- a/binding-mri/sunshine-binding.cpp +++ b/binding-mri/sunshine-binding.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "ruby/backward/cxxanyargs.hpp" #include "ruby/internal/arithmetic/double.h" @@ -21,6 +22,10 @@ static VALUE sunshine_set_crash_privacy(VALUE, VALUE v) { return v; } +static VALUE sunshine_set_hint(VALUE, VALUE h, VALUE v) { + return SDL_SetHint(StringValueCStr(h), StringValueCStr(v)); +} + static VALUE obj_clone(VALUE self){ return rb_obj_clone(self); } @@ -57,6 +62,7 @@ void SunshineBindingInit(){ rb_const_set(module, rb_intern("SECURITYSTATE"), rb_str_new_cstr(securitystate)); rb_define_singleton_method(module, "crashprivacy", RUBY_METHOD_FUNC(sunshine_get_crash_privacy), 0); rb_define_singleton_method(module, "crashprivacy=", RUBY_METHOD_FUNC(sunshine_set_crash_privacy), 1); + rb_define_singleton_method(module, "setSDLHint", RUBY_METHOD_FUNC(sunshine_set_hint), 2); //если методы доступны то просто не перезаписываем их if (!rb_respond_to(rb_cObject, rb_intern("class"))) { rb_define_method(rb_cObject, "class", rb_obj_class, 0); diff --git a/changelogs/0.1.2.txt b/changelogs/0.1.2.txt index 94addbc..4b6796d 100644 --- a/changelogs/0.1.2.txt +++ b/changelogs/0.1.2.txt @@ -10,3 +10,4 @@ Added help screen in Settings "Skip Text (R)" fixed Fixed language selection Replaced Japanese font with pixel one +Added SDL_HINT_INVALID_PARAM_CHECKS controller in Settings>Advanced diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index a533a70..c8019ff 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -86,7 +86,8 @@ set(scripts Input.rb Dynamic_Light.rb Gamepad_Colors.rb - Dynamic_Resolution.rb) + Dynamic_Resolution.rb + ModAPI.rb) find_program(RUBY_EXE ruby DOC "Location of the Ruby executable") diff --git a/scripts/Data_Settings.rb b/scripts/Data_Settings.rb index d41cd8a..92fb9da 100644 --- a/scripts/Data_Settings.rb +++ b/scripts/Data_Settings.rb @@ -32,7 +32,9 @@ module Settings # Advanced :crashlog_privacy => false, - + :streamer_privacy => false, + :SDL_HINT_INVALID_PARAM_CHECKS => false, + #controls :gamepad_led => true, :gamepad_deadzone => 5, @@ -44,7 +46,7 @@ module Settings :debug_text_scene_title => true, :debug_picture_names => false, :debug_lightmap => false, - + :SDL_HINT_SHUTDOWN_DBUS_ON_QUIT => false, #Hidden :is_dejavu => false, @@ -125,6 +127,12 @@ end class Window_Settings # if parameter is linked to data in class Settings, then default value in this structure is ignored DATA = { + "Help" => [ + { :type => :base, :name => "(!) - It's Dangerous!" }, + { :type => :base, :name => "(WIP) - Work In Progress" }, + { :type => :base, :name => "(GRR) - Game Restart Required" }, + { :type => :base, :name => "(LRR) - Location Reload Required" }, + ], "Audio" => [ { :type => :slider, @@ -140,6 +148,7 @@ class Window_Settings :min => 0, :max => 100 }, + { :type => :sep, :name => "Game tracks"}, { :type => :bool, :name => "ITS TIME FOR FIGHT CRIME", @@ -165,13 +174,13 @@ class Window_Settings :name => "Frameskip", :parameter => :frameskip }, - { :type => :sep, :name => "Other"}, { :type => :enum, :name => "Scaling mode", :parameter => :scaling_mode, :values => ["Nearest Neighbor", "Smooth(old)"] }, + { :type => :sep, :name => "Effects"}, { :type => :bool, :name => "Dynamic Light", @@ -182,11 +191,6 @@ class Window_Settings :name => "World machine shader", :parameter => :twm_shader }, - { - :type => :bool, - :name => "Colorblind mode", - :parameter => :colorblind - }, ], "UI" => [ { @@ -208,6 +212,12 @@ class Window_Settings }, ], "Gameplay" => [ + { :type => :sep, :name => "Vanila" }, + { + :type => :bool, + :name => "Colorblind mode", + :parameter => :colorblind + }, { :type => :enum, :name => "Default movement", @@ -219,8 +229,9 @@ class Window_Settings :name => "Skip Text (R)", :parameter => :skip_text }, + { :type => :sep, :name => "Sunshine" }, { - :type => :bool, + :type => :bool, :name => "Purple message box for Entity", :parameter => :en_purple_messagebox }, @@ -241,7 +252,7 @@ class Window_Settings }, { :type => :bool, - :name => "World machine shader on Entity footprints", + :name => "World machine shader on Entity footprints(WIP)", :parameter => :twm_shader_footprint }, ], @@ -325,7 +336,6 @@ class Window_Settings :parameter => :controls_nav_right, :bind => Input::R }, - #{ :type => :sep, :name => "Other" }, { :type => :action, :name => "Reset Controls", @@ -333,11 +343,22 @@ class Window_Settings }, ], "Advanced" => [ + { :type => :sep, :name => "Privacy" }, { :type => :bool, :name => "Crashlog privacy", :parameter => :crashlog_privacy - + }, + { + :type => :bool, + :name => "Streamer privacy", + :parameter => :streamer_privacy + }, + { :type => :sep, :name => "Other" }, + { + :type => :bool, + :name => "SDL_HINT_INVALID_PARAM_CHECKS (!)", + :parameter => :SDL_HINT_INVALID_PARAM_CHECKS }, ], "Debug" => [ @@ -371,6 +392,11 @@ class Window_Settings :name => "Debug lightmap", :parameter => :debug_lightmap }, + { + :type => :bool, + :name => "SDL_HINT_SHUTDOWN_DBUS_ON_QUIT", + :parameter => :SDL_HINT_SHUTDOWN_DBUS_ON_QUIT + }, { :type => :sep }, { :type => :key, @@ -378,12 +404,20 @@ class Window_Settings :parameter => :controls_debug, :bind => Input::DEBUGACTION }, - { :type => :sep }, + { :type => :seps}, { :type => :action, :name => "Clear image cache", :action => Proc.new { RPG::Cache.clear } } ], + "Mods" => [ + { :type => :base, :name => "Modloader enabled? #{ModLoader::IS_ENABLED}" }, + ], } + + # Part of ModAPI + def self.add_setting(setting) + DATA["Mods"] << setting + end end diff --git a/scripts/Data_Settings_Setters.rb b/scripts/Data_Settings_Setters.rb index 4b6067a..0fe8dff 100644 --- a/scripts/Data_Settings_Setters.rb +++ b/scripts/Data_Settings_Setters.rb @@ -62,13 +62,28 @@ module Settings $game_switches[251] = value != 0 end def skip_text(value) - # idk how to set skip_text parameter - # TODO: fix skip_text settings setter + $game_switches[253] = value != 0 end def frameskip(value) Graphics.frameskip = value end + + def SDL_HINT_INVALID_PARAM_CHECKS(value) + if value + Sunshine.setSDLHint("SDL_HINT_INVALID_PARAM_CHECKS", "1") + else + Sunshine.setSDLHint("SDL_HINT_INVALID_PARAM_CHECKS", "2") + end + end + + def SDL_HINT_SHUTDOWN_DBUS_ON_QUIT(value) + if value + Sunshine.setSDLHint("SDL_HINT_SHUTDOWN_DBUS_ON_QUIT", "1") + else + Sunshine.setSDLHint("SDL_HINT_SHUTDOWN_DBUS_ON_QUIT", "0") + end + end end end end diff --git a/scripts/ModAPI.rb b/scripts/ModAPI.rb new file mode 100644 index 0000000..839bfcc --- /dev/null +++ b/scripts/ModAPI.rb @@ -0,0 +1,3 @@ +module ModAPI + APIVER = 1 +end diff --git a/scripts/_scripts.txt b/scripts/_scripts.txt index c7a0202..cbd29c5 100644 --- a/scripts/_scripts.txt +++ b/scripts/_scripts.txt @@ -108,3 +108,6 @@ Particles EdText Main + +ModAPI + diff --git a/src/main.cpp b/src/main.cpp index c539b4e..c148ad0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,10 +51,6 @@ #include "i18n.h" #include "security.h" -#ifndef ps2 - #include "modloader.h" -#endif - #include "sunshine.h" #include "define.h" @@ -302,16 +298,6 @@ int main(int argc, char *argv[]){ return 0; } } - - #ifndef ps2 - std::string new_path = ModLoader(conf); - if(new_path != ""){ - if (chdir(new_path.c_str()) != 0){ - crash(Exception::MEOW, "Unable to switch into new gameFolder %s", new_path); - return 0; - } - } - #endif extern int screenMain(Config &conf); if (conf.screenMode) @@ -379,7 +365,7 @@ int main(int argc, char *argv[]){ /* Load and post key bindings */ rtData.bindingUpdateMsg.post(loadBindings(conf)); - + /* Start RGSS thread */ SDL_Thread *rgssThread = SDL_CreateThread(rgssThreadFun, "rgss", &rtData); diff --git a/src/modloader.cpp b/src/modloader.cpp index fd3889c..0fd9a9f 100644 --- a/src/modloader.cpp +++ b/src/modloader.cpp @@ -25,36 +25,9 @@ #include #include #include +#include namespace fs = std::filesystem; -// Get directory for storing cached builds -//TODO: support for other OS and platforms -std::string getCacheDir(){ -#ifdef _WIN32 - return SDL_getenv("Temp"); -#elif __linux__ - return std::string(SDL_getenv("HOME")) + "/.cache"; -#elif BSD - return std::string(SDL_getenv("HOME")) + "/.cache"; -#elif __APPLE__ - return "~/Library/Caches"; -#elif __ANDROID__ - return std::string str(SDL_GetAndroidCachePath()); -#else - return "idk"; -#endif -} - -//helper -bool ensure_parent_dir(const std::filesystem::path& p){ - if (p.has_parent_path()){ - std::error_code ec; - std::filesystem::create_directories(p.parent_path(), ec); - return !ec; - } - return true; -} - std::string sha512(const std::string str){ unsigned char hash[SHA512_DIGEST_LENGTH]; @@ -98,19 +71,14 @@ std::string sha256_file(const std::string &fn) { return out; } -#ifdef __EMSCRIPTEN__ -std::string ModLoader(Config conf){ return ""; } -#else -std::string ModLoader(Config conf){ - std::string path = conf.Modloader.ModsDirPath; +void ModLoader(){ + std::string path = "mods"; if (!fs::exists(path) || !std::filesystem::is_directory(path)) { Debug() << "[MODLOADER] Mods directory not found, skip."; - return ""; } if (fs::is_empty(path)){ Debug() << "[MODLOADER] Mods directory empty, skip."; - return ""; } //buildID - unique ID of a certain combination of mods @@ -118,16 +86,18 @@ std::string ModLoader(Config conf){ std::string buildID_tmp = ""; std::vector mod_list = {}; try{ - //1.check if any zip(mod) file, 2. calculate sha256 hash of zip(mod) files - for (const auto &entry : std::filesystem::directory_iterator(path, std::filesystem::directory_options::skip_permission_denied)) { + //1.check if any zip(mod) file, 2. calculate sha256 hash of zip(mod) files 3.mount mod via PhysFS + for (const auto &entry : std::filesystem::directory_iterator(path, std::filesystem::directory_options::skip_permission_denied)) { std::error_code ec; auto p = entry.path(); if (!std::filesystem::is_regular_file(p, ec) || ec) continue; - auto ext = p.extension().string(); if (ext != ".zip") continue; - std::string full = p.string(); + int ok = PHYSFS_mount(full.c_str(), "/", 0); + if (!ok) { + crash(Exception::ModLoaderError, "PhysFS_mount failed: %s", PHYSFS_getLastError()); + } Debug() << "[MODLOADER] " << full; mod_list.push_back(full); mods_count++; @@ -138,84 +108,9 @@ std::string ModLoader(Config conf){ buildID = sha512(buildID_tmp); Debug() << "[MODLOADER] BuildID: " << buildID; - std::string path3 = getCacheDir() + "/sunshine-" + buildID; - int err = 0; - modloader_is_enabled = true; - if(!std::filesystem::exists(path3)){ - std::error_code ec; - fs::create_directory(path3, ec); - if (ec) { - crash(Exception::ModLoaderError, "Failed to create destination: %s", ec.message().c_str()); - } - - fs::copy(conf.gameFolder, path3, fs::copy_options::recursive | fs::copy_options::overwrite_existing, ec); - if (ec) { - crash(Exception::ModLoaderError, "Copy error: %s", ec.message().c_str()); - } - - //Extracting zipsodpsofspo idk - for (size_t i = 0; i < mod_list.size(); ++i){ - zip_t* za = zip_open(mod_list[i].c_str(), ZIP_RDONLY, &err); - if (!za){ - crash(Exception::ModLoaderError, "Failed to open zip"); - } - - zip_int64_t n = zip_get_num_entries(za, 0); - for (zip_uint64_t i2 = 0; i2 < static_cast(n); ++i2) { - zip_stat_t st; - if (zip_stat_index(za, i2, 0, &st) != 0) { - crash(Exception::ModLoaderError, "zip_stat_index failed"); - } - - std::string name = st.name; - std::filesystem::path target = path3 / std::filesystem::path(name); - - // If entry name ends with '/', treat as directory - if (!name.empty() && name.back() == '/') { - std::error_code ec; - std::filesystem::create_directories(target, ec); - if (ec) crash(Exception::MEOW, "Failed to create dir"); - continue; - } - - if (!ensure_parent_dir(target)){ - crash(Exception::ModLoaderError, "Failed to create parent dirs"); - } - - zip_file_t* zf = zip_fopen_index(za, i2, 0); - if (!zf) { - crash(Exception::ModLoaderError, "zip_fopen_index failed"); - } - std::ofstream out(target, std::ios::binary); - if (!out) { - crash(Exception::ModLoaderError, "Failed to open output file %s", target.c_str()); - zip_fclose(zf); - } - - const zip_uint64_t bufsize = 4096; - std::vector buf(bufsize); - zip_int64_t bytes_read; - zip_uint64_t remaining = st.size; - while (remaining > 0) { - zip_uint64_t to_read = std::min(bufsize, remaining); - bytes_read = zip_fread(zf, buf.data(), to_read); - if (bytes_read < 0) { - crash(Exception::ModLoaderError, "zip_fread error for %s", name.c_str()); - break; - } - out.write(buf.data(), bytes_read); - remaining -= bytes_read; - } - zip_fclose(zf); - } - zip_close(za); - } - return path3; - }else{ - return path3; - } + + modloader_is_enabled = true; }catch(const std::exception& e){ crash(Exception::ModLoaderError, "Something is wrong, Exception: %s ", e.what()); } } -#endif diff --git a/src/modloader.h b/src/modloader.h index f4460b8..4d82416 100644 --- a/src/modloader.h +++ b/src/modloader.h @@ -1,7 +1,5 @@ //modloader bruh -#include -#include "config.h" -std::string ModLoader(Config conf); +void ModLoader(); inline bool modloader_is_enabled = false; inline unsigned int mods_count = 0;