Remove 'fix_essentials', add 'use_fakeapi'

This commit is contained in:
Inori 2019-08-20 05:21:30 -04:00
parent a2c38ba281
commit 339d32da74
11 changed files with 59 additions and 77 deletions

View file

@ -82,41 +82,46 @@ In the RMXP version of RGSS, fonts are loaded directly from system specific sear
If a requested font is not found, no error is generated. Instead, a built-in font is used (currently "Liberation Sans").
## Win32API
Win32API exists in mkxp-z as both `Win32API.new` and `MiniFFI.new` (This class is available under macOS, linux and Windows and "Win32API" as a name makes no sense on the former two platforms). It functions nearly the same as Ruby 1.8's Win32API, for better or worse. The third and fourth arguments are now optional (if you just want a function that takes no arguments and returns nothing, for instance), and `new` will yield to blocks.
Being simple as it is, it remains mostly as the lazy option/last resort to add C functions from shared libraries if you can't/don't want to build MKXP yourself.
## What doesn't work (yet)
* Win32API calls outside of Windows (Win32API is just an alias to the MiniFFI class, which *does* work with other operating systems, but you can obviously only load libraries made for the platform you're on)*
* Some Win32API calls don't play nicely with SDL. Building with the `fix_essentials` option will attempt to fix this.
* `rubyscreen.dll` doesn't work, and `Graphics.snap_to_bitmap` is unconditionally overridden by the SpriteResizer script. This can't be worked around without modifying Ruby in ways I don't have any desire to. When built with `fix_essentials` enabled, RGSS2 Graphics functions are bound, so wrap the definition of the Win32API-based `snap_to_bitmap` in an if statement. Or just delete the thing if you don't care about being able to swap executables in and out. As another consequence of `rubyscreen.dll` not being compatible, screenshots also don't work -- but the Graphics module now has a `screenshot` method to compensate for this.
* Some Win32API calls don't play nicely with SDL. Building with the `use_fakeapi` option will attempt to fix this.
* `rubyscreen.dll` doesn't work, and `Graphics.snap_to_bitmap` is unconditionally overridden by the SpriteResizer script. This can't be worked around without modifying Ruby in ways I don't have any desire to. RGSS2 Graphics functions are bound in RGSS1 mode, so wrap the definition of the Win32API-based `snap_to_bitmap` in an if statement, or delete it. As another consequence of `rubyscreen.dll` not being compatible, screenshots also don't work -- but the Graphics module now has a `screenshot` method to compensate for this.
* The current implementation of `load_data` is case-sensitive. If you try to load `Data/MapXXX`, you will not find `Data/mapXXX`.
* `load_data` is slow. In fact, it's too slow to handle `pbResolveBitmap` firing a million times a second, so if `fix_essentials` is used Graphics files can only be loaded from outside of the game's archive. You could remove that code if you want, but you'll lag. Very hard.
* `load_data` is slow. In fact, it's too slow to handle `pbResolveBitmap` firing a million times a second, so Graphics files can only be loaded from outside of the game's archive. You could remove that code if you want, but you'll lag if not using loose files. Very hard.
* `FileSystem::openRead` is not compatible with absolute paths in Windows (this affects `Bitmap.new` or `Audio.bgm_play`, for instance, another reason why Win32API `Graphics.snap_to_bitmap` breaks).
* Movie playback
* wma audio files
* Creating Bitmaps with sizes greater than the OpenGL texture size limit (around 8192 on modern cards)^
\* Once games can be played comfortably on Windows, I may try to have a 'fake' Win32API class written for other operating systems which intercepts and interprets some of the common calls that get used, a bit like what's already being done with the `fix_essentials` option. SDL2 can handle a lot of the things that are performed with WinAPI.
\* Once games can be played comfortably on Windows, I may try to have a 'fake' Win32API class written for other operating systems which intercepts and interprets some of the common calls that get used, a bit like what's already being done with the `use_fakeapi` option. SDL2 can handle a lot of the things that are performed with WinAPI.
^ There is an exception to this, called *mega surface*. When a Bitmap bigger than the texture limit is created from a file, it is not stored in VRAM, but regular RAM. Its sole purpose is to be used as a tileset bitmap. Any other operation to it (besides blitting to a regular Bitmap) will result in an error. (This breaks SLLD after the professor's speech, Zeta after you leave the cave, but Pokemon Uranium seems to be fine as far as I've tested)
## Win32API
Win32API exists in mkxp-z, objectively functioning nearly the same as before for better or worse. The third and fourth arguments are now optional (if you just want a function that takes no arguments and returns nothing, for instance), and Win32API objects will yield themselves to any blocks given to `initialize`.
However, the Win32API class is also available when built for Linux and macOS, under the name `MiniFFI` instead (Win32API is just an extra name for it in Windows). It will only load shared libraries built for your platform.
Being simple as it is, it remains mostly as the lazy option/last resort if you can't/don't want to build MKXP yourself.
## Nonstandard RGSS extensions
To alleviate possible porting of heavily Win32API reliant scripts, certain functionality that you won't find in the RGSS spec has been added. Currently this amounts to the following:
# Input
* The `Input.press?` family of functions accepts three additional button constants: `::MOUSELEFT`, `::MOUSEMIDDLE` and `::MOUSERIGHT` for the respective mouse buttons.
* The `Input` module has two additional functions, `#mouse_x` and `#mouse_y` to query the mouse pointer position relative to the game screen.
# Graphics
* The `Graphics` module has two additional properties: `fullscreen` represents the current fullscreen mode (`true` = fullscreen, `false` = windowed), `show_cursor` hides the system cursor inside the game window when `false`.
* Calling `Graphics.screenshot(path)` will save a screenshot to `path` in BMP format.
* The `Graphics` module has one additional function: `Graphics.screenshot(path)` will save a screenshot to `path` in BMP format.
Commonly used Win32API routines will eventually have equivalent functions directly bound, like `Graphics.screenshot` for `Win32API.new('rubyscreen.dll,'TakeScreenshot','p','i')`.
-------------------------
## Building on Windows (MSYS+MinGW)
1. Install [MSYS](https://www.msys2.org) and launch it. Run `pacman -Syu`, and close the console when it asks you to, then launch MSYS using the `MSYS MinGW 32-bit` shortcut that’s been added to your Start menu. Run `pacman -Su` this time.
@ -173,7 +178,7 @@ cd mkxp-z
# is a bit annoying) so you have to set include and link paths yourself.
# for mingw32, includes will be at /mingw32/lib/ruby/1.8/i386-mingw32
meson build -Druby_lib=msvcrt-ruby18 -Dfix_essentials=true \
meson build -Druby_lib=msvcrt-ruby18 -Duse_fakeapi=true \
-Dcpp_args=-I/mingw32/lib/ruby/1.8/i386-mingw32
cd build

View file

@ -522,19 +522,7 @@ static void runRMXPScripts(BacktraceData &btData)
btData.scriptNames.insert(buf, scriptName);
int state;
#if defined(__WIN32__) && defined(USE_ESSENTIALS_FIXES)
// I can hack around RGSS Linker and have it work properly,
// but (A) working with essentials is already hacky enough
// and (B) we can simply just use F-MOD as MKXP's audio backend
// if we absolutely had to.
// GENERATE WIKI PAGES is just excluded because of a difference
// in ruby's regex code from 1.8.1 -> 1.8.7 that I haven't worked out yet
if (strcmp(scriptName, "RGSS Linker")
&& strcmp(scriptName, "F-mod main script")
&& strcmp(scriptName, "GENERATE WIKI PAGES"))
#endif
evalString(string, fname, &state);
if (state)
break;

View file

@ -179,8 +179,6 @@ RB_METHOD(kernelLoadData)
VALUE filename;
rb_get_args(argc, argv, "S", &filename RB_ARG_END);
#ifdef USE_ESSENTIALS_FIXES
// Until a faster method for getting RGSSAD data is
// written (could just copy RMXP, keeping stuff in
// memory and just passing char pointers can't be
@ -198,7 +196,6 @@ RB_METHOD(kernelLoadData)
rb_funcall(f, rb_intern("close"), 0);
return ret;
}
#endif
return kernelLoadDataInt(RSTRING_PTR(filename), true);
}

View file

@ -240,22 +240,21 @@ void graphicsBindingInit()
INIT_GRA_PROP_BIND( FrameRate, "frame_rate" );
INIT_GRA_PROP_BIND( FrameCount, "frame_count" );
#ifndef USE_ESSENTIALS_FIXES
if (rgssVer >= 2)
{
#endif
_rb_define_module_function(module, "width", graphicsWidth);
_rb_define_module_function(module, "height", graphicsHeight);
_rb_define_module_function(module, "wait", graphicsWait);
_rb_define_module_function(module, "fadeout", graphicsFadeout);
_rb_define_module_function(module, "fadein", graphicsFadein);
_rb_define_module_function(module, "snap_to_bitmap", graphicsSnapToBitmap);
_rb_define_module_function(module, "resize_screen", graphicsResizeScreen);
// Typically, these functions are only used in RGSS2+, but
// Essentials really wants them badly
_rb_define_module_function(module, "width", graphicsWidth);
_rb_define_module_function(module, "height", graphicsHeight);
_rb_define_module_function(module, "wait", graphicsWait);
_rb_define_module_function(module, "fadeout", graphicsFadeout);
_rb_define_module_function(module, "fadein", graphicsFadein);
_rb_define_module_function(module, "snap_to_bitmap", graphicsSnapToBitmap);
_rb_define_module_function(module, "resize_screen", graphicsResizeScreen);
INIT_GRA_PROP_BIND( Brightness, "brightness" );
#ifndef USE_ESSENTIALS_FIXES
}
#endif
INIT_GRA_PROP_BIND( Brightness, "brightness" );
// end
if (rgssVer >= 3)
{

View file

@ -6,14 +6,6 @@ if ver.version_compare('>1.8') == true
else
lib = get_option('ruby_lib')
binding_dependencies += compiler.find_library(lib)
if host_system == 'windows'
if lib.endswith('-static') and (get_option('fix_essentials') == false)
# if fixing up essentials this'll have been added already
binding_dependencies += compiler.find_library('wsock32')
endif
else
binding_dependencies += compiler.find_library('dl')
endif
add_project_arguments('-DOLD_RUBY', language: 'cpp')
endif

View file

@ -2,8 +2,7 @@
// it's just as basic but should work fine for the moment
#include <SDL.h>
#if defined(__WIN32__) && defined(USE_ESSENTIALS_FIXES)
#include <windows.h>
#ifdef USE_FAKEAPI
#include "fake-api.h"
#endif
@ -42,12 +41,10 @@ MiniFFI_alloc(VALUE self)
return Data_Wrap_Struct(self, 0, SDL_UnloadObject, 0);
}
// Probably should do something else for macOS and Linux if I get around to them,
// this would probably be a *very* long list for those
static void*
MiniFFI_GetFunctionHandle(void *libhandle, const char *func)
{
#if defined(__WIN32__) && defined(USE_ESSENTIALS_FIXES)
#ifdef USE_FAKEAPI
#define CAPTURE(n) if (!strcmp(#n,func)) return (void*)&MKXP_##n
CAPTURE(GetCurrentThreadId);
CAPTURE(GetWindowThreadProcessId);
@ -61,6 +58,9 @@ MiniFFI_GetFunctionHandle(void *libhandle, const char *func)
CAPTURE(GetWindowRect);
CAPTURE(RegisterHotKey);
CAPTURE(GetKeyboardState);
#ifndef __WIN32__
// Functions needed on Linux and macOS go here
#endif
#endif
return SDL_LoadFunction(libhandle, func);
}
@ -256,8 +256,9 @@ MiniFFIBindingInit()
_rb_define_method(cMiniFFI, "initialize", MiniFFI_initialize);
_rb_define_method(cMiniFFI, "call", MiniFFI_call);
rb_define_alias(cMiniFFI, "Call", "call");
#ifdef __WIN32__
// Preferably use MiniFFI, the name Win32API makes no sense
// on things that aren't Windows but I'm leaving it here
// for compatibility
rb_define_const(rb_cObject, "Win32API", cMiniFFI);
#endif
}

View file

@ -1,5 +1,8 @@
project('mkxp-z', 'cpp', 'c', version: '1.0', default_options: ['cpp_std=c++11'])
# The meson build is mostly directly copied from the old CMakeLists,
# it still needs to be cleaned up
xxd = find_program('xxd', native: true)
host_system = host_machine.system()
compiler = meson.get_compiler('cpp')
@ -8,8 +11,8 @@ if get_option('workdir_current')
add_project_arguments('-DWORKDIR_CURRENT', language: 'cpp')
endif
if get_option('fix_essentials')
add_project_arguments('-DUSE_ESSENTIALS_FIXES', language: 'cpp')
if get_option('use_fakeapi')
add_project_arguments('-DUSE_FAKEAPI', language: 'cpp')
endif
if not get_option('console')

View file

@ -4,4 +4,4 @@ option('workdir_current', type: 'boolean', value: false, description: 'Keep curr
option('ruby_lib', type: 'string', value: 'ruby', description: 'Name of legacy Ruby library')
option('console', type: 'boolean', value: false, description: 'Whether to debug information in the console')
option('fix_essentials', type: 'boolean', value: false, description: 'Try to fix incompatibilities between Essentials and MKXP')
option('use_fakeapi', type: 'boolean', value: false, description: 'Attempt to repair Win32API calls that do not work with MKXP')

View file

@ -733,7 +733,6 @@ char* FileSystem::normalize(const char *pathname, bool preferred, bool absolute)
cwk_path_normalize((path_abs) ? path_abs : (char*)pathname, path_nml, 512);
if (path_abs) delete path_abs;
Debug() << pathname << ":" << path_nml;
return path_nml;
}

View file

@ -42,10 +42,8 @@
#ifdef __WINDOWS__
#include "resource.h"
#ifdef USE_ESSENTIALS_FIXES
#include <Winsock2.h>
#endif
#endif
#include "icon.png.xxd"
@ -269,8 +267,8 @@ int main(int argc, char *argv[])
return 0;
}
#if defined(__WINDOWS__) && defined(USE_ESSENTIALS_FIXES)
// Init winsock, allows Win32API socket to work
#if defined(__WINDOWS__)
// Init winsock, allows socket ops in Ruby to work
// MKXP itself doesn't need it so it's a little
// hands-off
WSAData wsadata = {0};
@ -386,7 +384,7 @@ int main(int argc, char *argv[])
alcCloseDevice(alcDev);
SDL_DestroyWindow(win);
#if defined(__WINDOWS__) && defined(USE_ESSENTIALS_FIXES)
#if defined(__WINDOWS__)
if (wsadata.wVersion) WSACleanup();
#endif
Sound_Quit();

View file

@ -20,9 +20,7 @@ if host_system == 'darwin'
add_project_arguments('-DUSE_MAC_OPENAL', language: 'cpp')
endif
elif host_system == 'windows'
if get_option('fix_essentials') == true
main_dependencies += compiler.find_library('wsock32')
endif
main_dependencies += compiler.find_library('wsock32')
endif
if get_option('shared_fluid') == true
@ -90,8 +88,7 @@ main_headers = files(
'tileatlasvx.h',
'sharedmidistate.h',
'fluid-fun.h',
'sdl-util.h',
'fake-api.h'
'sdl-util.h'
)
main_source = files(
@ -138,8 +135,11 @@ main_source = files(
'tileatlasvx.cpp',
'autotilesvx.cpp',
'midisource.cpp',
'fluid-fun.cpp',
'fake-api.cpp'
'fluid-fun.cpp'
)
main = [main_source, main_headers]
if get_option('use_fakeapi') == true
main += files('fake-api.cpp', 'fake-api.h')
endif