Better Modloading Support

This commit is contained in:
DepressedTWM 2026-08-21 10:39:24 +04:00
parent 48dda7da8c
commit 95ab9c4434
9 changed files with 139 additions and 50 deletions

View File

@ -326,6 +326,7 @@ set(BINDING_SOURCE
binding-mri/gamepad-binding.cpp
binding-mri/profiler-binding.cpp
binding-mri/audioplayback-binding.cpp
binding-mri/physfs-binding.cpp
)
source_group("Binding Source" FILES ${BINDING_SOURCE} ${BINDING_HEADERS})

View File

@ -95,6 +95,7 @@ void shaderBindingInit();
void keybindingsBindingInit();
void lightmapBindingInit();
void ProfilerInit();
void PhysFS_binding_init();
RB_METHOD(mriPrint);
RB_METHOD(mriP);
@ -150,6 +151,7 @@ static void mriBindingInit(){
keybindingsBindingInit();
lightmapBindingInit();
ProfilerInit();
PhysFS_binding_init();
_rb_define_module_function(rb_mKernel, "rgss_main", mriRgssMain);
_rb_define_module_function(rb_mKernel, "rgss_stop", mriRgssStop);

View File

@ -1,25 +1,14 @@
//https://silverhammermba.github.io/emberb/c/
//https://docs.ruby-lang.org/capi/en/master/d8/d68/include_2ruby_2internal_2intern_2string_8h.html
#include "binding-util.h"
#include "sharedstate.h"
#include "filesystem.h"
#include "util.h"
#include "debugwriter.h"
#include "ruby/encoding.h"
#include "ruby/intern.h"
#include "ruby/thread.h"
#include "modloader.h"
#include "config.h"
#include <ruby.h>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <system_error>
#include <vector>
#include <physfs.h>
#include <string>
namespace fs = std::filesystem;
#include <vector>
VALUE meow(const std::vector<std::string> vec){
VALUE ary = rb_ary_new_capa((long)vec.size());
for (const std::string &s : vec) {
@ -38,22 +27,53 @@ static VALUE hooks(int argc, VALUE *argv, VALUE self) {
hook_path = StringValueCStr(v_path);
}
std::vector<std::string> files = {};
if(!std::filesystem::exists(hook_path)){
std::vector<std::string> files;
if (!PHYSFS_exists(hook_path.c_str())) {
return meow(files);
}
for (const auto &entry : std::filesystem::directory_iterator(hook_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 != ".rb") continue;
PHYSFS_Stat dir_stat{};
std::string full = p.string();
Debug() << "[MODLOADER] Executing hook: " << full;
files.push_back(full);
if (
PHYSFS_stat(hook_path.c_str(), &dir_stat) == 0 ||
dir_stat.filetype != PHYSFS_FILETYPE_DIRECTORY
) {
return meow(files);
}
char **list = PHYSFS_enumerateFiles(hook_path.c_str());
if (list == nullptr) {
return meow(files);
}
for (char **entry = list; *entry != nullptr; ++entry) {
std::string name = *entry;
std::string full_path = hook_path;
if (!full_path.empty() && full_path.back() != '/') {
full_path += '/';
}
full_path += name;
PHYSFS_Stat file_stat{};
if (PHYSFS_stat(full_path.c_str(), &file_stat) == 0) {
continue;
}
if (file_stat.filetype != PHYSFS_FILETYPE_REGULAR) {
continue;
}
if (name.size() < 3 ||
name.compare(name.size() - 3, 3, ".rb") != 0) {
continue;
}
Debug() << "[MODLOADER] Executing hook: " << full_path;
files.push_back(full_path);
}
PHYSFS_freeList(list);
return meow(files);
}

View File

@ -1,6 +1,5 @@
module Kernel
alias_method :original_puts, :puts
def puts(*args)
string = ""
args.each do |arg|
@ -9,7 +8,6 @@ module Kernel
MKXP.puts string
return nil
end
module_function :puts
end
@ -17,15 +15,7 @@ module RPG
module Cache
@cache = {}
def self.load_bitmap(folder_name, filename, hue = 0)
if ModLoader::IS_ENABLED
if File.exist?("/mod-storage/" + folder_name + filename)
path = Graphics.adapted_file("/mod-storage/" + folder_name + filename)
else
path = Graphics.adapted_file(folder_name + filename)
end
else
path = Graphics.adapted_file(folder_name + filename)
end
if not @cache.include?(path) or @cache[path].disposed?
if filename != ""
@cache[path] = Bitmap.new(path)
@ -1323,7 +1313,7 @@ module RPG
return unless ModLoader::IS_ENABLED
return unless path.is_a?(String)
ModLoader.hooks(path).each do |item|
eval(File.read(item), b)
eval(PhysFS.read(item), b)
end
end
end

View File

@ -0,0 +1,70 @@
#include <physfs.h>
#include "binding-util.h"
#include "sharedstate.h"
#include "filesystem.h"
#include "util.h"
#include <ruby.h>
#include <stdexcept>
#include <string>
VALUE module = Qnil;
VALUE rb_ePhysFSError = Qnil;
std::string toStdString(VALUE v) {
Check_Type(v, T_STRING);
return std::string{ RSTRING_PTR(v), static_cast<std::size_t>(RSTRING_LEN(v)) };
}
static VALUE rb_PhysFS_Exist(VALUE, VALUE path) {
if(PHYSFS_exists(StringValuePtr(path)) > 0){
return Qtrue;
}else{
return Qfalse;
}
}
static VALUE rb_PhysFS_Directory(VALUE, VALUE path) {
if(PHYSFS_isDirectory(StringValuePtr(path)) > 0){
return Qtrue;
}else{
return Qfalse;
}
}
std::vector<char> loadFully(const char* path) {
PHYSFS_File* file = PHYSFS_openRead(path);
if (!file){
WarnMsg("Failed to load PhysFS file %s", path);
return {};
}
const auto length = PHYSFS_fileLength(file);
std::vector<char> buffer;
if (length > 0) {
buffer.resize(static_cast<std::size_t>(length));
const auto got = PHYSFS_readBytes(file, buffer.data(), static_cast<PHYSFS_uint64>(length));
if (got != length && !PHYSFS_eof(file)) {
PHYSFS_close(file);
WarnMsg("PhysFS readBytes failed for '%s'", path);
}
buffer.resize(static_cast<std::size_t>(got));
}
PHYSFS_close(file);
return buffer;
}
static VALUE rb_PhysFS_Read(VALUE, VALUE path) {
try {
const auto buf = loadFully(StringValuePtr(path));
return rb_str_new(buf.data(), static_cast<long>(buf.size()));
} catch (const std::exception& e) {
rb_raise(rb_ePhysFSError, "%s", e.what());
}
return Qnil;
}
void PhysFS_binding_init(){
VALUE module = rb_define_module("PhysFS");
rb_ePhysFSError = rb_define_class_under(module, "Error", rb_eStandardError);
rb_define_module_function(module, "exist?", rb_PhysFS_Exist, 1);
rb_define_module_function(module, "directory?", rb_PhysFS_Directory, 1);
rb_define_module_function(module, "read", rb_PhysFS_Read, 1);
}

View File

@ -40,9 +40,13 @@ module Graphics
def self.adapted_file(path, extention = ".png")
file_tag = RESOLUTIONS[Settings[:resolution] || 999]&.[](:file_tag) || ""
if PhysFS.exist?(path + file_tag + extention)
return path + file_tag
else
if File.exist?(path + file_tag + extention)
return path + file_tag
end
end
path
end
end

0
scripts/Graphics.rb Normal file
View File

View File

@ -17,6 +17,7 @@ end
begin
RPG::Mod.exec_hooks("hooks/Main/start", binding)
print PhysFS.exist?("gaysex")
$console = Graphics.fullscreen
Graphics.frame_rate = 60
Font.default_size = 20

View File

@ -15,11 +15,12 @@
#include <SDL3/SDL_video.h>
#include <SDL3/SDL_timer.h>
#include <SDL3_image/SDL_image.h>
#include <physfs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "the_modded_machine.png.xxd"
namespace fs = std::filesystem;
static bool stop_render = false;
const static std::size_t N = 46;
@ -94,7 +95,7 @@ void ModLoader(Config conf, SDL_Window* win){
std::string full = p.string();
if (ext == ".zip") {
int ok = PHYSFS_mount(full.c_str(), "/mod-storage", 0);
int ok = PHYSFS_mount(full.c_str(), "", 0);
mod_list.emplace_back(full);
modloader_add_to_log("Added mod " + full);
mods_count++;