Initial commit. Refactor successful

This commit is contained in:
Knaapchen 2022-09-16 14:43:04 +02:00
parent d999a6fc5a
commit 559544b3bb
26 changed files with 2245079 additions and 0 deletions

11
CMakeLists.txt Normal file
View File

@ -0,0 +1,11 @@
project (fugg)
cmake_minimum_required(VERSION 3.5.1)
set(CMAKE_C_FLAGS "-Os")
set(CMAKE_CXX_FLAGS "-Os")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
set(CMAKE_EXECUTABLE_SUFFIX ".js")
add_subdirectory(flyff-client)
add_subdirectory(fugg-core)
add_subdirectory(fugg-client)

View File

@ -0,0 +1,10 @@
add_subdirectory("wasm-rt")
add_library (
flyff-client
"src/client.cpp"
"include/client.h"
)
target_include_directories(flyff-client PUBLIC "include")
target_link_libraries (flyff-client LINK_PUBLIC wasm-rt)

1
flyff-client/README.md Normal file
View File

@ -0,0 +1 @@
# Decompiled Flyff Universe source

View File

@ -0,0 +1,405 @@
/* Automatically generated by wasm2c */
#ifndef CLIENT_H_GENERATED_
#define CLIENT_H_GENERATED_
#include <stdint.h>
#include "wasm-rt.h"
/* TODO(binji): only use stdint.h types in header */
#ifndef WASM_RT_CORE_TYPES_DEFINED
#define WASM_RT_CORE_TYPES_DEFINED
typedef uint8_t u8;
typedef int8_t s8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef int32_t s32;
typedef uint64_t u64;
typedef int64_t s64;
typedef float f32;
typedef double f64;
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* import: 'env' '_abort' */
extern void (*Z_envZ__abort)(void);
/* import: 'env' '__emval_decref' */
extern void (*Z_envZ___emval_decref)(u32);
/* import: 'env' '__emval_new_cstring' */
extern u32 (*Z_envZ___emval_new_cstring)(u32);
/* import: 'env' '_glActiveTexture' */
extern void (*Z_envZ__glActiveTexture)(u32);
/* import: 'env' '_glBindTexture' */
extern void (*Z_envZ__glBindTexture)(u32, u32);
/* import: 'env' '_glVertexAttribPointer' */
extern void (*Z_envZ__glVertexAttribPointer)(u32, u32, u32, u32, u32, u32);
/* import: 'env' '_glDisableVertexAttribArray' */
extern void (*Z_envZ__glDisableVertexAttribArray)(u32);
/* import: 'env' '__emval_set_property' */
extern void (*Z_envZ___emval_set_property)(u32, u32, u32);
/* import: 'env' '__emval_get_property' */
extern u32 (*Z_envZ___emval_get_property)(u32, u32);
/* import: 'env' '_glUniformMatrix4fv' */
extern void (*Z_envZ__glUniformMatrix4fv)(u32, u32, u32, u32);
/* import: 'env' '__emval_get_method_caller' */
extern u32 (*Z_envZ___emval_get_method_caller)(u32, u32);
/* import: 'env' '__emval_take_value' */
extern u32 (*Z_envZ___emval_take_value)(u32, u32);
/* import: 'env' '_glDisable' */
extern void (*Z_envZ__glDisable)(u32);
/* import: 'env' '_glBindBuffer' */
extern void (*Z_envZ__glBindBuffer)(u32, u32);
/* import: 'env' '__emval_run_destructors' */
extern void (*Z_envZ___emval_run_destructors)(u32);
/* import: 'env' '_glUniform1f' */
extern void (*Z_envZ__glUniform1f)(u32, f32);
/* import: 'env' '_glEnable' */
extern void (*Z_envZ__glEnable)(u32);
/* import: 'env' '__emval_get_global' */
extern u32 (*Z_envZ___emval_get_global)(u32);
/* import: 'env' '_glTexParameteri' */
extern void (*Z_envZ__glTexParameteri)(u32, u32, u32);
/* import: 'env' '__emval_call_void_method' */
extern void (*Z_envZ___emval_call_void_method)(u32, u32, u32, u32);
/* import: 'env' '_alSourcef' */
extern void (*Z_envZ__alSourcef)(u32, u32, f32);
/* import: 'env' '_glUseProgram' */
extern void (*Z_envZ__glUseProgram)(u32);
/* import: 'env' '_glEnableVertexAttribArray' */
extern void (*Z_envZ__glEnableVertexAttribArray)(u32);
/* import: 'env' '_alSourcei' */
extern void (*Z_envZ__alSourcei)(u32, u32, u32);
/* import: 'env' '__emval_as' */
extern f64 (*Z_envZ___emval_as)(u32, u32, u32);
/* import: 'env' '_glDrawArrays' */
extern void (*Z_envZ__glDrawArrays)(u32, u32, u32);
/* import: 'env' '_glDepthMask' */
extern void (*Z_envZ__glDepthMask)(u32);
/* import: 'env' '_glBlendFunc' */
extern void (*Z_envZ__glBlendFunc)(u32, u32);
/* import: 'env' '_glBindFramebuffer' */
extern void (*Z_envZ__glBindFramebuffer)(u32, u32);
/* import: 'env' '_glDrawElements' */
extern void (*Z_envZ__glDrawElements)(u32, u32, u32, u32);
/* import: 'env' '__emval_incref' */
extern void (*Z_envZ___emval_incref)(u32);
/* import: 'env' '_alSourceStop' */
extern void (*Z_envZ__alSourceStop)(u32);
/* import: 'env' '_glGetUniformLocation' */
extern u32 (*Z_envZ__glGetUniformLocation)(u32, u32);
/* import: 'env' '__emval_call_method' */
extern f64 (*Z_envZ___emval_call_method)(u32, u32, u32, u32, u32);
/* import: 'env' '_glUniform3fv' */
extern void (*Z_envZ__glUniform3fv)(u32, u32, u32);
/* import: 'env' '__embind_register_memory_view' */
extern void (*Z_envZ___embind_register_memory_view)(u32, u32, u32);
/* import: 'env' '_glViewport' */
extern void (*Z_envZ__glViewport)(u32, u32, u32, u32);
/* import: 'env' '_glTexImage2D' */
extern void (*Z_envZ__glTexImage2D)(u32, u32, u32, u32, u32, u32, u32, u32, u32);
/* import: 'env' '_glGetError' */
extern u32 (*Z_envZ__glGetError)(void);
/* import: 'env' '_glDeleteFramebuffers' */
extern void (*Z_envZ__glDeleteFramebuffers)(u32, u32);
/* import: 'env' '_alGetSourcei' */
extern void (*Z_envZ__alGetSourcei)(u32, u32, u32);
/* import: 'env' '_glColorMask' */
extern void (*Z_envZ__glColorMask)(u32, u32, u32, u32);
/* import: 'env' '__embind_register_function' */
extern void (*Z_envZ___embind_register_function)(u32, u32, u32, u32, u32, u32);
/* import: 'env' '_alDeleteSources' */
extern void (*Z_envZ__alDeleteSources)(u32, u32);
/* import: 'env' '_glGenTextures' */
extern void (*Z_envZ__glGenTextures)(u32, u32);
/* import: 'env' '_glDeleteBuffers' */
extern void (*Z_envZ__glDeleteBuffers)(u32, u32);
/* import: 'env' '_glBufferData' */
extern void (*Z_envZ__glBufferData)(u32, u32, u32, u32);
/* import: 'env' '_glGenBuffers' */
extern void (*Z_envZ__glGenBuffers)(u32, u32);
/* import: 'env' '_glScissor' */
extern void (*Z_envZ__glScissor)(u32, u32, u32, u32);
/* import: 'env' '_glStencilMask' */
extern void (*Z_envZ__glStencilMask)(u32);
/* import: 'env' '__embind_register_integer' */
extern void (*Z_envZ___embind_register_integer)(u32, u32, u32, u32, u32);
/* import: 'env' '_alSource3f' */
extern void (*Z_envZ__alSource3f)(u32, u32, f32, f32, f32);
/* import: 'env' '__emval_get_module_property' */
extern u32 (*Z_envZ___emval_get_module_property)(u32);
/* import: 'env' '_glFramebufferTexture2D' */
extern void (*Z_envZ__glFramebufferTexture2D)(u32, u32, u32, u32, u32);
/* import: 'env' '_glUniform2f' */
extern void (*Z_envZ__glUniform2f)(u32, f32, f32);
/* import: 'env' '_glUniform2fv' */
extern void (*Z_envZ__glUniform2fv)(u32, u32, u32);
/* import: 'env' '_glFrontFace' */
extern void (*Z_envZ__glFrontFace)(u32);
/* import: 'env' '_glGenFramebuffers' */
extern void (*Z_envZ__glGenFramebuffers)(u32, u32);
/* import: 'env' '__emval_typeof' */
extern u32 (*Z_envZ___emval_typeof)(u32);
/* import: 'env' '_emscripten_vibrate' */
extern u32 (*Z_envZ__emscripten_vibrate)(u32);
/* import: 'env' '_glUniform1i' */
extern void (*Z_envZ__glUniform1i)(u32, u32);
/* import: 'env' '_glGetProgramiv' */
extern void (*Z_envZ__glGetProgramiv)(u32, u32, u32);
/* import: 'env' '_glCheckFramebufferStatus' */
extern u32 (*Z_envZ__glCheckFramebufferStatus)(u32);
/* import: 'env' '_glClear' */
extern void (*Z_envZ__glClear)(u32);
/* import: 'env' '_glStencilFunc' */
extern void (*Z_envZ__glStencilFunc)(u32, u32, u32);
/* import: 'env' '_glGetIntegerv' */
extern void (*Z_envZ__glGetIntegerv)(u32, u32);
/* import: 'env' '_emscripten_exit_fullscreen' */
extern u32 (*Z_envZ__emscripten_exit_fullscreen)(void);
/* import: 'env' '_emscripten_request_fullscreen' */
extern u32 (*Z_envZ__emscripten_request_fullscreen)(u32, u32);
/* import: 'env' '_emscripten_performance_now' */
extern f64 (*Z_envZ__emscripten_performance_now)(void);
/* import: 'env' '_emscripten_cancel_main_loop' */
extern void (*Z_envZ__emscripten_cancel_main_loop)(void);
/* import: 'env' '_emscripten_set_main_loop' */
extern void (*Z_envZ__emscripten_set_main_loop)(u32, u32, u32);
/* import: 'env' '_glDetachShader' */
extern void (*Z_envZ__glDetachShader)(u32, u32);
/* import: 'env' '_emscripten_set_devicemotion_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_devicemotion_callback_on_thread)(u32, u32, u32, u32);
/* import: 'env' '_glDeleteProgram' */
extern void (*Z_envZ__glDeleteProgram)(u32);
/* import: 'env' '__emval_new' */
extern u32 (*Z_envZ___emval_new)(u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_beforeunload_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_beforeunload_callback_on_thread)(u32, u32, u32);
/* import: 'env' '_glDeleteShader' */
extern void (*Z_envZ__glDeleteShader)(u32);
/* import: 'env' '_glDepthFunc' */
extern void (*Z_envZ__glDepthFunc)(u32);
/* import: 'env' '_emscripten_resize_heap' */
extern u32 (*Z_envZ__emscripten_resize_heap)(u32);
/* import: 'env' '__embind_register_std_wstring' */
extern void (*Z_envZ___embind_register_std_wstring)(u32, u32, u32);
/* import: 'env' '_strftime' */
extern u32 (*Z_envZ__strftime)(u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_webglcontextrestored_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_webglcontextrestored_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_focusout_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_focusout_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_keyup_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_keyup_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_keydown_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_keydown_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_wheel_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_wheel_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_mouseleave_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_mouseleave_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_mousemove_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_mousemove_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_mouseup_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_mouseup_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_mousedown_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_mousedown_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_touchcancel_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_touchcancel_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_touchmove_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_touchmove_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_touchend_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_touchend_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_touchstart_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_touchstart_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_webgl_destroy_context' */
extern u32 (*Z_envZ__emscripten_webgl_destroy_context)(u32);
/* import: 'env' '_emscripten_set_orientationchange_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_orientationchange_callback_on_thread)(u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_resize_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_resize_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_visibilitychange_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_visibilitychange_callback_on_thread)(u32, u32, u32, u32);
/* import: 'env' '_glClearColor' */
extern void (*Z_envZ__glClearColor)(f32, f32, f32, f32);
/* import: 'env' '_glGetProgramInfoLog' */
extern void (*Z_envZ__glGetProgramInfoLog)(u32, u32, u32, u32);
/* import: 'env' '_glLinkProgram' */
extern void (*Z_envZ__glLinkProgram)(u32);
/* import: 'env' '_glAttachShader' */
extern void (*Z_envZ__glAttachShader)(u32, u32);
/* import: 'env' '_glGetShaderiv' */
extern void (*Z_envZ__glGetShaderiv)(u32, u32, u32);
/* import: 'env' '_glLineWidth' */
extern void (*Z_envZ__glLineWidth)(f32);
/* import: 'env' '__emscripten_date_now' */
extern f64 (*Z_envZ___emscripten_date_now)(void);
/* import: 'env' '__embind_register_float' */
extern void (*Z_envZ___embind_register_float)(u32, u32, u32);
/* import: 'env' '__embind_register_std_string' */
extern void (*Z_envZ___embind_register_std_string)(u32, u32);
/* import: 'env' '_emscripten_async_wget_data' */
extern void (*Z_envZ__emscripten_async_wget_data)(u32, u32, u32, u32);
/* import: 'env' '_alSourcePlay' */
extern void (*Z_envZ__alSourcePlay)(u32);
/* import: 'env' '_alListenerfv' */
extern void (*Z_envZ__alListenerfv)(u32, u32);
/* import: 'env' '_alListener3f' */
extern void (*Z_envZ__alListener3f)(u32, f32, f32, f32);
/* import: 'env' '_emscripten_set_webglcontextlost_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_webglcontextlost_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_set_element_css_size' */
extern u32 (*Z_envZ__emscripten_set_element_css_size)(u32, f64, f64);
/* import: 'env' '_emscripten_set_canvas_element_size' */
extern u32 (*Z_envZ__emscripten_set_canvas_element_size)(u32, u32, u32);
/* import: 'env' '_emscripten_webgl_make_context_current' */
extern u32 (*Z_envZ__emscripten_webgl_make_context_current)(u32);
/* import: 'env' '_emscripten_webgl_create_context' */
extern u32 (*Z_envZ__emscripten_webgl_create_context)(u32, u32);
/* import: 'env' '_emscripten_webgl_init_context_attributes' */
extern void (*Z_envZ__emscripten_webgl_init_context_attributes)(u32);
/* import: 'env' '_glUniform4f' */
extern void (*Z_envZ__glUniform4f)(u32, f32, f32, f32, f32);
/* import: 'env' '_glCompressedTexImage2D' */
extern void (*Z_envZ__glCompressedTexImage2D)(u32, u32, u32, u32, u32, u32, u32, u32);
/* import: 'env' '_glBindAttribLocation' */
extern void (*Z_envZ__glBindAttribLocation)(u32, u32, u32);
/* import: 'env' '_glGetActiveAttrib' */
extern void (*Z_envZ__glGetActiveAttrib)(u32, u32, u32, u32, u32, u32, u32);
/* import: 'env' '_emscripten_get_orientation_status' */
extern u32 (*Z_envZ__emscripten_get_orientation_status)(u32);
/* import: 'env' '_glCreateProgram' */
extern u32 (*Z_envZ__glCreateProgram)(void);
/* import: 'env' '_glGetShaderInfoLog' */
extern void (*Z_envZ__glGetShaderInfoLog)(u32, u32, u32, u32);
/* import: 'env' '_glCompileShader' */
extern void (*Z_envZ__glCompileShader)(u32);
/* import: 'env' '_glShaderSource' */
extern void (*Z_envZ__glShaderSource)(u32, u32, u32, u32);
/* import: 'env' '_glCreateShader' */
extern u32 (*Z_envZ__glCreateShader)(u32);
/* import: 'env' '_glCullFace' */
extern void (*Z_envZ__glCullFace)(u32);
/* import: 'env' '_emscripten_webgl_enable_extension' */
extern u32 (*Z_envZ__emscripten_webgl_enable_extension)(u32, u32);
/* import: 'env' '_glGetString' */
extern u32 (*Z_envZ__glGetString)(u32);
/* import: 'env' '_glStencilOp' */
extern void (*Z_envZ__glStencilOp)(u32, u32, u32);
/* import: 'env' '_emscripten_set_fullscreenchange_callback_on_thread' */
extern u32 (*Z_envZ__emscripten_set_fullscreenchange_callback_on_thread)(u32, u32, u32, u32, u32);
/* import: 'env' '_glDeleteTextures' */
extern void (*Z_envZ__glDeleteTextures)(u32, u32);
/* import: 'env' '_fd_seek' */
extern u32 (*Z_envZ__fd_seek)(u32, u32, u32, u32, u32);
/* import: 'env' '__embind_register_bigint' */
extern void (*Z_envZ___embind_register_bigint)(u32, u32, u32, u32, u32, u32, u32);
/* import: 'env' '_strftime_l' */
extern u32 (*Z_envZ__strftime_l)(u32, u32, u32, u32, u32);
/* import: 'env' '_environ_get' */
extern u32 (*Z_envZ__environ_get)(u32, u32);
/* import: 'env' '_environ_sizes_get' */
extern u32 (*Z_envZ__environ_sizes_get)(u32, u32);
/* import: 'env' '_fd_close' */
extern u32 (*Z_envZ__fd_close)(u32);
/* import: 'env' '_fd_write' */
extern u32 (*Z_envZ__fd_write)(u32, u32, u32, u32);
/* import: 'env' '_emscripten_memcpy_big' */
extern void (*Z_envZ__emscripten_memcpy_big)(u32, u32, u32);
/* import: 'env' '__emscripten_get_now_is_monotonic' */
extern u32 (*Z_envZ___emscripten_get_now_is_monotonic)(void);
/* import: 'env' '__gmtime_js' */
extern void (*Z_envZ___gmtime_js)(u32, u32);
/* import: 'env' '__localtime_js' */
extern void (*Z_envZ___localtime_js)(u32, u32);
/* import: 'env' '__mktime_js' */
extern u32 (*Z_envZ___mktime_js)(u32);
/* import: 'env' '__tzset_js' */
extern void (*Z_envZ___tzset_js)(u32, u32, u32);
/* import: 'env' '_glCopyTexSubImage2D' */
extern void (*Z_envZ__glCopyTexSubImage2D)(u32, u32, u32, u32, u32, u32, u32, u32);
/* import: 'env' '__embind_register_emval' */
extern void (*Z_envZ___embind_register_emval)(u32, u32);
/* import: 'env' '__embind_register_bool' */
extern void (*Z_envZ___embind_register_bool)(u32, u32, u32, u32, u32);
/* import: 'env' '__embind_register_void' */
extern void (*Z_envZ___embind_register_void)(u32, u32);
/* import: 'env' '_emscripten_log' */
extern void (*Z_envZ__emscripten_log)(u32, u32, u32);
/* import: 'env' '_alDeleteBuffers' */
extern void (*Z_envZ__alDeleteBuffers)(u32, u32);
/* import: 'env' '_alBufferData' */
extern void (*Z_envZ__alBufferData)(u32, u32, u32, u32, u32);
/* import: 'env' '_alGenBuffers' */
extern void (*Z_envZ__alGenBuffers)(u32, u32);
/* import: 'env' '_alGetEnumValue' */
extern u32 (*Z_envZ__alGetEnumValue)(u32);
/* import: 'env' '_alcCloseDevice' */
extern u32 (*Z_envZ__alcCloseDevice)(u32);
/* import: 'env' '_alcDestroyContext' */
extern void (*Z_envZ__alcDestroyContext)(u32);
/* import: 'env' '_alGenSources' */
extern void (*Z_envZ__alGenSources)(u32, u32);
/* import: 'env' '_alListenerf' */
extern void (*Z_envZ__alListenerf)(u32, f32);
/* import: 'env' '_alcMakeContextCurrent' */
extern u32 (*Z_envZ__alcMakeContextCurrent)(u32);
/* import: 'env' '_alcCreateContext' */
extern u32 (*Z_envZ__alcCreateContext)(u32, u32);
/* import: 'env' '_alcOpenDevice' */
extern u32 (*Z_envZ__alcOpenDevice)(u32);
/* import: 'env' '_emscripten_get_fullscreen_status' */
extern u32 (*Z_envZ__emscripten_get_fullscreen_status)(u32);
/* import: 'env' '_emscripten_force_exit' */
extern void (*Z_envZ__emscripten_force_exit)(u32);
/* import: 'env' '_glTexSubImage2D' */
extern void (*Z_envZ__glTexSubImage2D)(u32, u32, u32, u32, u32, u32, u32, u32, u32);
void Z_client_init(void);
void Z_client_free(void);
/* export: 'memory' */
extern wasm_rt_memory_t (*Z_clientZ_memory);
/* export: '___wasm_call_ctors' */
extern void (*Z_clientZ____wasm_call_ctors)(void);
/* export: '_malloc' */
extern u32 (*Z_clientZ__malloc)(u32);
/* export: '_free' */
extern void (*Z_clientZ__free)(u32);
/* export: '_main' */
extern u32 (*Z_clientZ__main)(u32, u32);
/* export: '___getTypeName' */
extern u32 (*Z_clientZ____getTypeName)(u32);
/* export: '__embind_initialize_bindings' */
extern void (*Z_clientZ___embind_initialize_bindings)(void);
/* export: 'table' */
extern wasm_rt_table_t (*Z_clientZ_table);
/* export: 'stackSave' */
extern u32 (*Z_clientZ_stackSave)(void);
/* export: 'stackRestore' */
extern void (*Z_clientZ_stackRestore)(u32);
/* export: 'stackAlloc' */
extern u32 (*Z_clientZ_stackAlloc)(u32);
/* export: 'dynCall_vij' */
extern void (*Z_clientZ_dynCall_vij)(u32, u32, u32, u32);
/* export: 'dynCall_ji' */
extern u32 (*Z_clientZ_dynCall_ji)(u32, u32);
/* export: 'dynCall_iiiijiii' */
extern u32 (*Z_clientZ_dynCall_iiiijiii)(u32, u32, u32, u32, u32, u32, u32, u32, u32);
/* export: 'dynCall_viijii' */
extern void (*Z_clientZ_dynCall_viijii)(u32, u32, u32, u32, u32, u32, u32);
/* export: 'dynCall_iiiiij' */
extern u32 (*Z_clientZ_dynCall_iiiiij)(u32, u32, u32, u32, u32, u32, u32);
/* export: 'dynCall_iiiiijj' */
extern u32 (*Z_clientZ_dynCall_iiiiijj)(u32, u32, u32, u32, u32, u32, u32, u32, u32);
/* export: 'dynCall_iiiiiijj' */
extern u32 (*Z_clientZ_dynCall_iiiiiijj)(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32);
/* export: 'dynCall_jiji' */
extern u32 (*Z_clientZ_dynCall_jiji)(u32, u32, u32, u32, u32);
#ifdef __cplusplus
}
#endif
#endif /* CLIENT_H_GENERATED_ */

2240323
flyff-client/src/client.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
add_library (
wasm-rt
"src/wasm-rt-impl.cpp"
"src/wasm-rt-impl.h"
"include/wasm-rt.h"
)
target_include_directories(wasm-rt PUBLIC "include")

View File

@ -0,0 +1,297 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WASM_RT_H_
#define WASM_RT_H_
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#ifndef WASM_SYMBOL
#define WASM_SYMBOL(module, method) \
Z_ ## module ## Z_ ## method
#endif
#ifndef WASM_IMPORT_IMPL
#define WASM_IMPORT_IMPL(module, method) \
decltype(WASM_SYMBOL(module, method)) WASM_SYMBOL(module, method)
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __has_builtin
#define __has_builtin(x) 0 // Compatibility with non-clang compilers.
#endif
#if __has_builtin(__builtin_expect)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#define LIKELY(x) __builtin_expect(!!(x), 1)
#else
#define UNLIKELY(x) (x)
#define LIKELY(x) (x)
#endif
#if __has_builtin(__builtin_memcpy)
#define wasm_rt_memcpy __builtin_memcpy
#else
#define wasm_rt_memcpy memcpy
#endif
/**
* Enable memory checking via a signal handler via the following definition:
*
* #define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1
*
* This is usually 10%-25% faster, but requires OS-specific support.
*/
/** Check whether the signal handler is supported at all. */
#if (defined(__linux__) || defined(__unix__) || defined(__APPLE__)) && \
defined(__WORDSIZE) && __WORDSIZE == 64
/* If the signal handler is supported, then use it by default. */
#ifndef WASM_RT_MEMCHECK_SIGNAL_HANDLER
#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1
#endif
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
#define WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX 1
#endif
#else
/* The signal handler is not supported, error out if the user was trying to
* enable it. */
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
#error "Signal handler is not supported for this OS/Architecture!"
#endif
#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 0
#define WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX 0
/**
* When the signal handler is not used, stack depth is limited explicitly.
* The maximum stack depth before trapping can be configured by defining
* this symbol before including wasm-rt when building the generated c files,
* for example:
*
* ```
* cc -c -DWASM_RT_MAX_CALL_STACK_DEPTH=100 my_module.c -o my_module.o
* ```
*/
#ifndef WASM_RT_MAX_CALL_STACK_DEPTH
#define WASM_RT_MAX_CALL_STACK_DEPTH 500
#endif
/** Current call stack depth. */
extern uint32_t wasm_rt_call_stack_depth;
#endif
#if defined(_MSC_VER)
#define WASM_RT_NO_RETURN __declspec(noreturn)
#else
#define WASM_RT_NO_RETURN __attribute__((noreturn))
#endif
#if defined(__APPLE__) && WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
#define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 1
#else
#define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 0
#endif
/** Reason a trap occurred. Provide this to `wasm_rt_trap`. */
typedef enum {
WASM_RT_TRAP_NONE, /** No error. */
WASM_RT_TRAP_OOB, /** Out-of-bounds access in linear memory. */
WASM_RT_TRAP_INT_OVERFLOW, /** Integer overflow on divide or truncation. */
WASM_RT_TRAP_DIV_BY_ZERO, /** Integer divide by zero. */
WASM_RT_TRAP_INVALID_CONVERSION, /** Conversion from NaN to integer. */
WASM_RT_TRAP_UNREACHABLE, /** Unreachable instruction executed. */
WASM_RT_TRAP_CALL_INDIRECT, /** Invalid call_indirect, for any reason. */
#if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS
WASM_RT_TRAP_EXHAUSTION = WASM_RT_TRAP_OOB,
#else
WASM_RT_TRAP_EXHAUSTION, /** Call stack exhausted. */
#endif
} wasm_rt_trap_t;
/** Value types. Used to define function signatures. */
typedef enum {
WASM_RT_I32,
WASM_RT_I64,
WASM_RT_F32,
WASM_RT_F64,
} wasm_rt_type_t;
/**
* A function type for all `funcref` functions in a Table. All functions are
* stored in this canonical form, but must be cast to their proper signature to
* call.
*/
typedef void (*wasm_rt_funcref_t)(void);
/** A single element of a Table. */
typedef struct {
/** The index as returned from `wasm_rt_register_func_type`. */
uint32_t func_type;
/** The function. The embedder must know the actual C signature of the
* function and cast to it before calling. */
wasm_rt_funcref_t func;
} wasm_rt_elem_t;
/** A Memory object. */
typedef struct {
/** The linear memory data, with a byte length of `size`. */
uint8_t* data;
/** The current and maximum page count for this Memory object. If there is no
* maximum, `max_pages` is 0xffffffffu (i.e. UINT32_MAX). */
uint32_t pages, max_pages;
/** The current size of the linear memory, in bytes. */
uint32_t size;
} wasm_rt_memory_t;
/** A Table object. */
typedef struct {
/** The table element data, with an element count of `size`. */
wasm_rt_elem_t* data;
/** The maximum element count of this Table object. If there is no maximum,
* `max_size` is 0xffffffffu (i.e. UINT32_MAX). */
uint32_t max_size;
/** The current element count of the table. */
uint32_t size;
} wasm_rt_table_t;
/** Initialize the runtime. */
void wasm_rt_init(void);
/** Free the runtime's state. */
void wasm_rt_free(void);
/**
* Stop execution immediately and jump back to the call to `wasm_rt_try`.
* The result of `wasm_rt_try` will be the provided trap reason.
*
* This is typically called by the generated code, and not the embedder.
*/
WASM_RT_NO_RETURN void wasm_rt_trap(wasm_rt_trap_t);
/**
* Return a human readable error string based on a trap type.
*/
const char* wasm_rt_strerror(wasm_rt_trap_t trap);
/**
* Register a function type with the given signature. The returned function
* index is guaranteed to be the same for all calls with the same signature.
* The following varargs must all be of type `wasm_rt_type_t`, first the
* params` and then the `results`.
*
* ```
* // Register (func (param i32 f32) (result i64)).
* wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
* => returns 1
*
* // Register (func (result i64)).
* wasm_rt_register_func_type(0, 1, WASM_RT_I32);
* => returns 2
*
* // Register (func (param i32 f32) (result i64)) again.
* wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
* => returns 1
* ```
*/
uint32_t wasm_rt_register_func_type(uint32_t params, uint32_t results, ...);
/**
* Initialize a Memory object with an initial page size of `initial_pages` and
* a maximum page size of `max_pages`.
*
* ```
* wasm_rt_memory_t my_memory;
* // 1 initial page (65536 bytes), and a maximum of 2 pages.
* wasm_rt_allocate_memory(&my_memory, 1, 2);
* ```
*/
void wasm_rt_allocate_memory(wasm_rt_memory_t*,
uint32_t initial_pages,
uint32_t max_pages);
/**
* Grow a Memory object by `pages`, and return the previous page count. If
* this new page count is greater than the maximum page count, the grow fails
* and 0xffffffffu (UINT32_MAX) is returned instead.
*
* ```
* wasm_rt_memory_t my_memory;
* ...
* // Grow memory by 10 pages.
* uint32_t old_page_size = wasm_rt_grow_memory(&my_memory, 10);
* if (old_page_size == UINT32_MAX) {
* // Failed to grow memory.
* }
* ```
*/
uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages);
/**
* Free a Memory object.
*/
void wasm_rt_free_memory(wasm_rt_memory_t*);
/**
* Initialize a Table object with an element count of `elements` and a maximum
* page size of `max_elements`.
*
* ```
* wasm_rt_table_t my_table;
* // 5 elemnets and a maximum of 10 elements.
* wasm_rt_allocate_table(&my_table, 5, 10);
* ```
*/
void wasm_rt_allocate_table(wasm_rt_table_t*,
uint32_t elements,
uint32_t max_elements);
/**
* Free a Table object.
*/
void wasm_rt_free_table(wasm_rt_table_t*);
#ifdef _WIN32
float wasm_rt_truncf(float x);
double wasm_rt_trunc(double x);
float wasm_rt_nearbyintf(float x);
double wasm_rt_nearbyint(double x);
float wasm_rt_fabsf(float x);
double wasm_rt_fabs(double x);
#else
#define wasm_rt_truncf(x) truncf(x)
#define wasm_rt_trunc(x) trunc(x)
#define wasm_rt_nearbyintf(x) nearbyintf(x)
#define wasm_rt_nearbyint(x) nearbyint(x)
#define wasm_rt_fabsf(x) fabsf(x)
#define wasm_rt_fabs(x) fabs(x)
#endif
#ifdef __cplusplus
}
#endif
#endif /* WASM_RT_H_ */

View File

@ -0,0 +1,402 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "wasm-rt-impl.h"
#include <assert.h>
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// is not set for emcc.
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
#include <signal.h>
#include <unistd.h>
#endif
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#endif
#define PAGE_SIZE 65536
typedef struct FuncType {
wasm_rt_type_t* params;
wasm_rt_type_t* results;
uint32_t param_count;
uint32_t result_count;
} FuncType;
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
bool g_signal_handler_installed = false;
char* g_alt_stack;
#else
uint32_t wasm_rt_call_stack_depth;
uint32_t g_saved_call_stack_depth;
#endif
jmp_buf g_jmp_buf;
FuncType* g_func_types;
uint32_t g_func_type_count;
void wasm_rt_trap(wasm_rt_trap_t code) {
printf("WASM Runtime trapped!: %s\n", wasm_rt_strerror(code));
assert(code != WASM_RT_TRAP_NONE);
#if !WASM_RT_MEMCHECK_SIGNAL_HANDLER
wasm_rt_call_stack_depth = g_saved_call_stack_depth;
#endif
WASM_RT_LONGJMP(g_jmp_buf, code);
}
static bool func_types_are_equal(FuncType* a, FuncType* b) {
if (a->param_count != b->param_count || a->result_count != b->result_count)
return 0;
uint32_t i;
for (i = 0; i < a->param_count; ++i)
if (a->params[i] != b->params[i])
return 0;
for (i = 0; i < a->result_count; ++i)
if (a->results[i] != b->results[i])
return 0;
return 1;
}
uint32_t wasm_rt_register_func_type(uint32_t param_count,
uint32_t result_count,
...) {
FuncType func_type;
func_type.param_count = param_count;
func_type.params = (wasm_rt_type_t*)malloc(param_count * sizeof(wasm_rt_type_t));
func_type.result_count = result_count;
func_type.results = (wasm_rt_type_t*)malloc(result_count * sizeof(wasm_rt_type_t));
va_list args;
va_start(args, result_count);
uint32_t i;
for (i = 0; i < param_count; ++i)
func_type.params[i] = va_arg(args, wasm_rt_type_t);
for (i = 0; i < result_count; ++i)
func_type.results[i] = va_arg(args, wasm_rt_type_t);
va_end(args);
for (i = 0; i < g_func_type_count; ++i) {
if (func_types_are_equal(&g_func_types[i], &func_type)) {
free(func_type.params);
free(func_type.results);
return i + 1;
}
}
uint32_t idx = g_func_type_count++;
g_func_types = (FuncType*)realloc(g_func_types, g_func_type_count * sizeof(FuncType));
g_func_types[idx] = func_type;
return idx + 1;
}
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
static void signal_handler(int sig, siginfo_t* si, void* unused) {
if (si->si_code == SEGV_ACCERR) {
wasm_rt_trap(WASM_RT_TRAP_OOB);
} else {
wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION);
}
}
#endif
#ifdef _WIN32
static void* os_mmap(size_t size) {
return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
}
static int os_munmap(void* addr, size_t size) {
BOOL succeeded = VirtualFree(addr, size, MEM_RELEASE);
return succeeded ? 0 : -1;
}
static int os_mprotect(void* addr, size_t size) {
DWORD old;
BOOL succeeded = VirtualProtect((LPVOID)addr, size, PAGE_READWRITE, &old);
return succeeded ? 0 : -1;
}
static void os_print_last_error(const char* msg) {
DWORD errorMessageID = GetLastError();
if (errorMessageID != 0) {
LPSTR messageBuffer = 0;
// The api creates the buffer that holds the message
size_t size = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&messageBuffer, 0, NULL);
(void)size;
printf("%s. %s\n", msg, messageBuffer);
LocalFree(messageBuffer);
} else {
printf("%s. No error code.\n", msg);
}
}
#else
static void* os_mmap(size_t size) {
int map_prot = PROT_NONE;
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
uint8_t* addr = (uint8_t*)mmap(NULL, size, map_prot, map_flags, -1, 0);
if (addr == MAP_FAILED)
return NULL;
return addr;
}
static int os_munmap(void* addr, size_t size) {
return munmap(addr, size);
}
static int os_mprotect(void* addr, size_t size) {
return mprotect(addr, size, PROT_READ | PROT_WRITE);
}
static void os_print_last_error(const char* msg) {
perror(msg);
}
#endif
void wasm_rt_init(void) {
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
if (!g_signal_handler_installed) {
g_signal_handler_installed = true;
/* Use alt stack to handle SIGSEGV from stack overflow */
g_alt_stack = malloc(SIGSTKSZ);
if (g_alt_stack == NULL) {
perror("malloc failed");
abort();
}
stack_t ss;
ss.ss_sp = g_alt_stack;
ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ;
if (sigaltstack(&ss, NULL) != 0) {
perror("sigaltstack failed");
abort();
}
struct sigaction sa;
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = signal_handler;
/* Install SIGSEGV and SIGBUS handlers, since macOS seems to use SIGBUS. */
if (sigaction(SIGSEGV, &sa, NULL) != 0 ||
sigaction(SIGBUS, &sa, NULL) != 0) {
perror("sigaction failed");
abort();
}
}
#endif
}
void wasm_rt_free(void) {
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
free(g_alt_stack);
#endif
}
void wasm_rt_allocate_memory(wasm_rt_memory_t* memory,
uint32_t initial_pages,
uint32_t max_pages) {
uint32_t byte_length = initial_pages * PAGE_SIZE;
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
/* Reserve 8GiB. */
void* addr = os_mmap(0x200000000ul);
if (addr == (void*)-1) {
os_print_last_error("os_mmap failed.");
abort();
}
int ret = os_mprotect(addr, byte_length);
if (ret != 0) {
os_print_last_error("os_mprotect failed.");
abort();
}
memory->data = addr;
#else
memory->data = (uint8_t*)calloc(byte_length, 1);
#endif
memory->size = byte_length;
memory->pages = initial_pages;
memory->max_pages = max_pages;
}
uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) {
uint32_t old_pages = memory->pages;
uint32_t new_pages = memory->pages + delta;
if (new_pages == 0) {
return 0;
}
if (new_pages < old_pages || new_pages > memory->max_pages) {
return (uint32_t)-1;
}
uint32_t old_size = old_pages * PAGE_SIZE;
uint32_t new_size = new_pages * PAGE_SIZE;
uint32_t delta_size = delta * PAGE_SIZE;
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
uint8_t* new_data = memory->data;
int ret = os_mprotect(new_data + old_size, delta_size);
if (ret != 0) {
return (uint32_t)-1;
}
#else
uint8_t* new_data = (uint8_t*)realloc(memory->data, new_size);
if (new_data == NULL) {
return (uint32_t)-1;
}
#if !WABT_BIG_ENDIAN
memset(new_data + old_size, 0, delta_size);
#endif
#endif
#if WABT_BIG_ENDIAN
memmove(new_data + new_size - old_size, new_data, old_size);
memset(new_data, 0, delta_size);
#endif
memory->pages = new_pages;
memory->size = new_size;
memory->data = new_data;
return old_pages;
}
void wasm_rt_free_memory(wasm_rt_memory_t* memory) {
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
os_munmap(memory->data, memory->size); // ignore error?
#else
free(memory->data);
#endif
}
#ifdef _WIN32
static float quiet_nanf(float x) {
uint32_t tmp;
memcpy(&tmp, &x, 4);
tmp |= 0x7fc00000lu;
memcpy(&x, &tmp, 4);
return x;
}
static double quiet_nan(double x) {
uint64_t tmp;
memcpy(&tmp, &x, 8);
tmp |= 0x7ff8000000000000llu;
memcpy(&x, &tmp, 8);
return x;
}
double wasm_rt_trunc(double x) {
if (isnan(x)) {
return quiet_nan(x);
}
return trunc(x);
}
float wasm_rt_truncf(float x) {
if (isnan(x)) {
return quiet_nanf(x);
}
return truncf(x);
}
float wasm_rt_nearbyintf(float x) {
if (isnan(x)) {
return quiet_nanf(x);
}
return nearbyintf(x);
}
double wasm_rt_nearbyint(double x) {
if (isnan(x)) {
return quiet_nan(x);
}
return nearbyint(x);
}
float wasm_rt_fabsf(float x) {
if (isnan(x)) {
uint32_t tmp;
memcpy(&tmp, &x, 4);
tmp = tmp & ~(1 << 31);
memcpy(&x, &tmp, 4);
return x;
}
return fabsf(x);
}
double wasm_rt_fabs(double x) {
if (isnan(x)) {
uint64_t tmp;
memcpy(&tmp, &x, 8);
tmp = tmp & ~(1ll << 63);
memcpy(&x, &tmp, 8);
return x;
}
return fabs(x);
}
#endif
void wasm_rt_allocate_table(wasm_rt_table_t* table,
uint32_t elements,
uint32_t max_elements) {
table->size = elements;
table->max_size = max_elements;
table->data = (wasm_rt_elem_t*)calloc(table->size, sizeof(wasm_rt_elem_t));
}
void wasm_rt_free_table(wasm_rt_table_t* table) {
free(table->data);
}
const char* wasm_rt_strerror(wasm_rt_trap_t trap) {
switch (trap) {
case WASM_RT_TRAP_NONE:
return "No error";
case WASM_RT_TRAP_OOB:
#if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS
return "Out-of-bounds access in linear memory or call stack exhausted";
#else
return "Out-of-bounds access in linear memory";
case WASM_RT_TRAP_EXHAUSTION:
return "Call stack exhausted";
#endif
case WASM_RT_TRAP_INT_OVERFLOW:
return "Integer overflow on divide or truncation";
case WASM_RT_TRAP_DIV_BY_ZERO:
return "Integer divide by zero";
case WASM_RT_TRAP_INVALID_CONVERSION:
return "Conversion from NaN to integer";
case WASM_RT_TRAP_UNREACHABLE:
return "Unreachable instruction executed";
case WASM_RT_TRAP_CALL_INDIRECT:
return "Invalid call_indirect";
}
return "invalid trap code";
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WASM_RT_IMPL_H_
#define WASM_RT_IMPL_H_
#include <setjmp.h>
#include "wasm-rt.h"
#ifdef __cplusplus
extern "C" {
#endif
/** A setjmp buffer used for handling traps. */
extern jmp_buf g_jmp_buf;
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
#define WASM_RT_SETJMP(buf) sigsetjmp(buf, 1)
#define WASM_RT_LONGJMP(buf, val) siglongjmp(buf, val)
#else
#define WASM_RT_SETJMP(buf) setjmp(buf)
#define WASM_RT_LONGJMP(buf, val) longjmp(buf, val)
/** Saved call stack depth that will be restored in case a trap occurs. */
extern uint32_t g_saved_call_stack_depth;
#endif
/**
* Convenience macro to use before calling a wasm function. On first execution
* it will return `WASM_RT_TRAP_NONE` (i.e. 0). If the function traps, it will
* jump back and return the trap that occurred.
*
* ```
* wasm_rt_trap_t code = wasm_rt_impl_try();
* if (code != 0) {
* printf("A trap occurred with code: %d\n", code);
* ...
* }
*
* // Call the potentially-trapping function.
* my_wasm_func();
* ```
*/
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
#define wasm_rt_impl_try() WASM_RT_SETJMP(g_jmp_buf)
#else
#define wasm_rt_impl_try() \
(g_saved_call_stack_depth = wasm_rt_call_stack_depth, \
WASM_RT_SETJMP(g_jmp_buf))
#endif
#ifdef __cplusplus
}
#endif
#endif /* WASM_RT_IMPL_H_ */

View File

@ -0,0 +1,31 @@
add_definitions(-std=c++14 -Os)
add_executable(
fugg-client
"src/main.cpp"
"src/client.cpp"
# Symbols that flyff-client imports.
"src/interop/export/gl.cpp"
"src/interop/export/al.cpp"
"src/interop/export/callback.cpp"
"src/interop/export/embind.cpp"
"src/interop/export/env.cpp"
"src/interop/export/platform.cpp"
)
target_include_directories(fugg-client PUBLIC "include")
target_link_libraries (fugg-client LINK_PUBLIC fugg-core flyff-client)
set_target_properties(
fugg-client
PROPERTIES LINK_FLAGS "\
-lembind \
-sINITIAL_MEMORY=2048MB \
-fsanitize=undefined \
-sASSERTIONS=1 \
-sSAFE_HEAP=1 \
-sDEMANGLE_SUPPORT=1 \
-sEXPORTED_RUNTIME_METHODS=UTF8ToString,stringToUTF8 \
-sMIN_WEBGL_VERSION=2 \
-sMAX_WEBGL_VERSION=2"
)

View File

@ -0,0 +1,53 @@
#include "client.h"
#include "interop/imports.h"
#include <iostream>
namespace fugg
{
// Emscripten runtime:
// 1. Pre-run
// 2. Init runtime
// 3. Pre-main
// 4. Call main
// 5. Post-run
using namespace interop;
using wasm::kMemory;
using wasm::kTable;
Client::Client() {
// 1. Pre-run: There are no pre-runs in this binary.
// 2. Init runtime: `___wasm_call_ctors` is added to on init runtime.
(*import::__wasm_call_ctors)();
}
Client& Client::instance() {
static bool initialised = false;
if(!initialised) {
// Initialise the WebAssembly runtime.
wasm_rt_init();
// Initialise the client.
import::init();
// Only init the module once.
initialised = true;
}
// Constructor will be called.
static Client instance;
// Whole module is initialised now.
return instance;
}
void Client::initialise() {
}
int Client::main() const {
// 3. Pre-main: There are no pre-mains in this binary.
// 4. Call main: `_main` is main in the binary.
// TODO: Fix arguments.
return (*import::_main)(0, 0);
}
}

17
fugg-client/src/client.h Normal file
View File

@ -0,0 +1,17 @@
#include "fugg.h"
namespace fugg {
class Client {
Client();
public:
static Client& instance();
Client(Client const&) = delete;
void operator=(Client const&) = delete;
void initialise();
// Execute the `main` function of the flyff-client.
int main() const;
};
}

View File

@ -0,0 +1,294 @@
#include <wasm-rt.h>
#include <client.h>
#include <iostream>
#include <AL/al.h>
#include <AL/alc.h>
#include <fugg.h>
#define TRACE_AL_CALLS 0
/* import: 'a' 'u' */
// "u": "_alSourcef",
WASM_IMPORT_IMPL(env, _alSourcef) = [](u32 a, u32 b, f32 c) {
#if TRACE_AL_CALLS
std::cout << "_alSourcef("
<< a << ", "
<< b << ", "
<< c
<< ")" << std::endl;
#endif
alSourcef(a, b, c);
};
// "w": "_alSourcei",
WASM_IMPORT_IMPL(env, _alSourcei) = [](u32 a, u32 b, u32 c) {
#if TRACE_AL_CALLS
std::cout << "_alSourcei("
<< a << ", "
<< b << ", "
<< c
<< ")" << std::endl;
#endif
alSourcei(a, b, c);
};
/* import: 'a' 'F' */
/* _alSourceStop*/
WASM_IMPORT_IMPL(env, _alSourceStop) = [](u32 a) {
#if TRACE_AL_CALLS
std::cout << "_alSourceStop("
<< a
<< ")" << std::endl;
#endif
alSourceStop(a);
};
// "L": "_alGetSourcei",
WASM_IMPORT_IMPL(env, _alGetSourcei) = [](u32 a, u32 b, u32 c) {
const auto& value = fugg::module_ptr<ALint>(c);
#if TRACE_AL_CALLS
std::cout << "_alGetSourcei("
<< a << ", "
<< b << ", "
<< value
<< ")" << std::endl;
#endif
alGetSourcei(a, b, value);
};
/* import: 'a' 'Q' */
// "Q": "_alDeleteSources"
WASM_IMPORT_IMPL(env, _alDeleteSources) = [](u32 a, u32 b) {
const auto& sources = fugg::module_ptr<const ALuint>(b);
#if TRACE_AL_CALLS
std::cout << "_alDeleteSources("
<< a << ", "
<< sources
<< ")" << std::endl;
#endif
alDeleteSources(a, sources);
};
/* _alSource3f */
WASM_IMPORT_IMPL(env, _alSource3f) = [](u32 a, u32 b, f32 c, f32 d, f32 e) {
#if TRACE_AL_CALLS
std::cout << "_alSource3f("
<< a << ", "
<< b << ", "
<< c << ", "
<< d << ", "
<< e
<< ")" << std::endl;
#endif
alSource3f(a, b, c, d, e);
};
/* import: 'a' 'bb' */
// "bb": "_alSourcePlay",
WASM_IMPORT_IMPL(env, _alSourcePlay) = [](u32 a) {
#if TRACE_AL_CALLS
std::cout << "_alSourcePlay("
<< a
<< ")" << std::endl;
#endif
alSourcePlay(a);
};
/* import: 'a' 'cb' */
// "cb": "_alListenerfv",
WASM_IMPORT_IMPL(env, _alListenerfv) = [](u32 a, u32 b) {
const auto& values = fugg::module_ptr<const ALfloat>(b);
#if TRACE_AL_CALLS
std::cout << "_alListenerfv("
<< a << ", "
<< values
<< ")" << std::endl;
#endif
alListenerfv(a, values);
};
/* import: 'a' 'db' */
// "db": "_alListener3f",
WASM_IMPORT_IMPL(env, _alListener3f) = [](u32 a, f32 b, f32 c, f32 d) {
#if TRACE_AL_CALLS
std::cout << "_alListener3f("
<< a << ", "
<< b << ", "
<< c << ", "
<< d
<< ")" << std::endl;
#endif
alListener3f(a, b, c, d);
};
/* import: 'a' 'Sb' */
/* _alDeleteBuffers */
WASM_IMPORT_IMPL(env, _alDeleteBuffers) = [](u32 a, u32 b) {
const auto& buffers = fugg::module_ptr<const ALuint>(b);
#if TRACE_AL_CALLS
std::cout << "_alDeleteBuffers("
<< a << ", "
<< buffers
<< ")" << std::endl;
#endif
alDeleteBuffers(a, buffers);
};
/* import: 'a' 'Tb' */
/* _alBufferData */
WASM_IMPORT_IMPL(env, _alBufferData) = [](u32 a, u32 b, u32 c, u32 d, u32 e) {
const auto& data = fugg::module_ptr<const ALvoid>(c);
#if TRACE_AL_CALLS
std::cout << "_alBufferData("
<< a << ", "
<< b << ", "
<< data << ", "
<< d << ", "
<< e
<< ")" << std::endl;
#endif
alBufferData(a, b, data, d, e);
};
/* import: 'a' 'Ub' */
// "Ub": "_alGenBuffers",
WASM_IMPORT_IMPL(env, _alGenBuffers) = [](u32 a, u32 b) {
const auto& buffers = fugg::module_ptr<ALuint>(b);
#if TRACE_AL_CALLS
std::cout << "_alGenBuffers("
<< a << ", "
<< buffers
<< ")" << std::endl;
#endif
alGenBuffers(a, buffers);
};
/* import: 'a' 'Vb' */
// "Vb": "_alGetEnumValue",
WASM_IMPORT_IMPL(env, _alGetEnumValue) = [](u32 a) {
const auto& ename = fugg::module_ptr<const ALchar>(a);
#if TRACE_AL_CALLS
std::cout << "_alGetEnumValue("
<< ename
<< ")" << std::endl;
#endif
return static_cast<u32>(
alGetEnumValue(ename)
);
};
/* import: 'a' 'Wb' */
// "Wb": "_alcCloseDevice",
WASM_IMPORT_IMPL(env, _alcCloseDevice) = [](u32 a) {
// ALCdevice is not data, but an index.
const auto& device = reinterpret_cast<ALCdevice*>(a);
#if TRACE_AL_CALLS
std::cout << "_alcCloseDevice("
<< device
<< ")" << std::endl;
#endif
return static_cast<u32>(
alcCloseDevice(device)
);
};
/* import: 'a' 'Yb' */
// "Yb": "_alGenSources",
WASM_IMPORT_IMPL(env, _alGenSources) = [](u32 a, u32 b) {
const auto& sources = fugg::module_ptr<ALuint>(b);
#if TRACE_AL_CALLS
std::cout << "_alGenSources("
<< a << ", "
<< sources
<< ")" << std::endl;
#endif
alGenSources(a, sources);
};
/* import: 'a' 'Zb' */
// "Zb": "_alListenerf",
WASM_IMPORT_IMPL(env, _alListenerf) = [](u32 a, f32 b) {
#if TRACE_AL_CALLS
std::cout << "_alListenerf("
<< a << ", "
<< b
<< ")" << std::endl;
#endif
alListenerf(a, b);
};
/* import: 'a' '_b' */
// "_b": "_alcMakeContextCurrent",
WASM_IMPORT_IMPL(env, _alcMakeContextCurrent) = [](u32 a) {
// ALCcontext is not data, but an index.
const auto& context = reinterpret_cast<ALCcontext*>(a);
#if TRACE_AL_CALLS
std::cout << "_alcMakeContextCurrent("
<< context
<< ")" << std::endl;
#endif
return static_cast<u32>(
alcMakeContextCurrent(context)
);
};
/* import: 'a' '$b' */
/* _alcCreateContext */
WASM_IMPORT_IMPL(env, _alcCreateContext) = [](u32 a, u32 b) {
// ALCdevice is not data, but an index.
const auto& device = reinterpret_cast<ALCdevice*>(a);
const auto& attr_list = fugg::module_ptr<const ALCint>(b);
#if TRACE_AL_CALLS
std::cout << "_alcCreateContext("
<< device << ", "
<< attr_list
<< ")" << std::endl;
#endif
return reinterpret_cast<u32>(
alcCreateContext(device, attr_list)
);
};
/* import: 'a' 'Xb' */
// "Xb": "_alcDestroyContext",
WASM_IMPORT_IMPL(env, _alcDestroyContext) = [](u32 a) {
// ALCcontext is not data, but an index.
const auto& context = reinterpret_cast<ALCcontext*>(a);
#if TRACE_AL_CALLS
std::cout << "_alcDestroyContext("
<< context
<< ")" << std::endl;
#endif
alcDestroyContext(context);
};
/* import: 'a' 'ac' */
// "ac": "_alcOpenDevice",
WASM_IMPORT_IMPL(env, _alcOpenDevice) = [](u32 a) {
const auto& devicename = fugg::module_ptr<const ALchar>(a);
#if TRACE_AL_CALLS
std::cout << "_alcOpenDevice("
<< devicename
<< ")" << std::endl;
#endif
return reinterpret_cast<u32>(
alcOpenDevice(devicename)
);
};

View File

@ -0,0 +1,669 @@
#include <emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/val.h>
#include "fugg.h"
#define TRACE_CALLBACK_CALLS 0
u32 original_resize_callback = 0;
/* import: 'a' 'Qa' */
// "Qa": "_emscripten_set_resize_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_resize_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
// From https://emscripten.org/docs/api_reference/html5.h.html
// For the resize callback, pass in target = EMSCRIPTEN_EVENT_TARGET_WINDOW to get resize events from the Window object.
const auto& target =
reinterpret_cast<void*>(a) <= EMSCRIPTEN_EVENT_TARGET_SCREEN ?
reinterpret_cast<const char*>(a) : fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_resize_callback_on_thread("
// << target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_ui_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_resize_callback = callback_;
auto hook = [](int eventType, const EmscriptenUiEvent* event, void* userData) {
assert(original_resize_callback);
const auto& callback = fugg::function_ref<em_ui_callback_func>(original_resize_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenUiEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_resize_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_devicemotion_callback = 0;
/* import: 'a' 'sa' */
// "sa": "_emscripten_set_devicemotion_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_devicemotion_callback_on_thread) = [](u32 a, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& user_data = fugg::module_ptr<void>(a);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_devicemotion_callback_on_thread("
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_devicemotion_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_devicemotion_callback = callback_;
auto hook = [](int eventType, const EmscriptenDeviceMotionEvent* event, void* userData) {
assert(original_devicemotion_callback);
const auto& callback = fugg::function_ref<em_devicemotion_callback_func>(original_devicemotion_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenDeviceMotionEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_devicemotion_callback_on_thread(user_data, use_capture, hook, target_thread)
);
};
u32 original_beforeunload_callback = 0;
/* import: 'a' 'va' */
// "va": "_emscripten_set_beforeunload_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_beforeunload_callback_on_thread) = [](u32 a, u32 callback_, u32 target_thread) {
const auto& user_data = fugg::module_ptr<void>(a);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_beforeunload_callback_on_thread("
<< user_data << ", "
<< emscripten_rt::fn<em_beforeunload_callback>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_beforeunload_callback = callback_;
auto hook = [](int eventType, const void* event, void* userData) {
assert(original_beforeunload_callback);
const auto& callback = fugg::function_ref<em_beforeunload_callback>(original_beforeunload_callback);
return callback(
eventType,
reinterpret_cast<const void*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_beforeunload_callback_on_thread(user_data, hook, target_thread)
);
};
u32 original_focusout_callback = 0;
/* import: 'a' 'Ca' */
/* _emscripten_set_focusout_callback_on_thread */
WASM_IMPORT_IMPL(env, _emscripten_set_focusout_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_focusout_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_focus_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_focusout_callback = callback_;
auto hook = [](int eventType, const EmscriptenFocusEvent* event, void* userData) {
assert(original_focusout_callback);
const auto& callback = fugg::function_ref<em_focus_callback_func>(original_focusout_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenFocusEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_focusout_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_keyup_callback = 0;
/* import: 'a' 'Da' */
/* _emscripten_set_keyup_callback_on_thread */
WASM_IMPORT_IMPL(env, _emscripten_set_keyup_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_keyup_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_key_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_keyup_callback = callback_;
auto hook = [](int eventType, const EmscriptenKeyboardEvent* event, void* userData) {
assert(original_keyup_callback);
const auto& callback = fugg::function_ref<em_key_callback_func>(original_keyup_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenKeyboardEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_keyup_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_keydown_callback = 0;
/* import: 'a' 'Ea' */
/* _emscripten_set_keydown_callback_on_thread */
WASM_IMPORT_IMPL(env, _emscripten_set_keydown_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_keydown_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_key_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_keydown_callback = callback_;
auto hook = [](int eventType, const EmscriptenKeyboardEvent* event, void* userData) {
assert(original_keydown_callback);
const auto& callback = fugg::function_ref<em_key_callback_func>(original_keydown_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenKeyboardEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_keydown_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_wheel_callback = 0;
/* import: 'a' 'Fa' */
/* _emscripten_set_wheel_callback_on_thread */
WASM_IMPORT_IMPL(env, _emscripten_set_wheel_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_wheel_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_wheel_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_wheel_callback = callback_;
auto hook = [](int eventType, const EmscriptenWheelEvent* event, void* userData) {
assert(original_wheel_callback);
const auto& callback = fugg::function_ref<em_wheel_callback_func>(original_wheel_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenWheelEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_wheel_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_mouseleave_callback = 0;
/* import: 'a' 'Ga' */
// "Ga": "_emscripten_set_mouseleave_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_mouseleave_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_mouseleave_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_mouse_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_mouseleave_callback = callback_;
auto hook = [](int eventType, const EmscriptenMouseEvent* event, void* userData) {
assert(original_mouseleave_callback);
const auto& callback = fugg::function_ref<em_mouse_callback_func>(original_mouseleave_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenMouseEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_mouseleave_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_mousemove_callback = 0;
/* import: 'a' 'Ha' */
// "Ha": "_emscripten_set_mousemove_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_mousemove_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_mousemove_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_mouse_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_mousemove_callback = callback_;
auto hook = [](int eventType, const EmscriptenMouseEvent* event, void* userData) {
assert(original_mousemove_callback);
const auto& callback = fugg::function_ref<em_mouse_callback_func>(original_mousemove_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenMouseEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_mousemove_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_mouseup_callback = 0;
/* import: 'a' 'Ia' */
// "Ia": "_emscripten_set_mouseup_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_mouseup_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_mouseup_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_mouse_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_mouseup_callback = callback_;
auto hook = [](int eventType, const EmscriptenMouseEvent* event, void* userData) {
assert(original_mouseup_callback);
const auto& callback = fugg::function_ref<em_mouse_callback_func>(original_mouseup_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenMouseEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_mouseup_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 orignal_mousedown_callback = 0;
/* import: 'a' 'Ja' */
// "Ja": "_emscripten_set_mousedown_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_mousedown_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_mousedown_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_mouse_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
orignal_mousedown_callback = callback_;
auto hook = [](int eventType, const EmscriptenMouseEvent* event, void* userData) {
assert(orignal_mousedown_callback);
const auto& callback = fugg::function_ref<em_mouse_callback_func>(orignal_mousedown_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenMouseEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_mousedown_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_touchcancel_callback = 0;
/* import: 'a' 'Ka' */
// "Ka": "_emscripten_set_touchcancel_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_touchcancel_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_touchcancel_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_touch_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_touchcancel_callback = callback_;
auto hook = [](int eventType, const EmscriptenTouchEvent* event, void* userData) {
assert(original_touchcancel_callback);
const auto& callback = fugg::function_ref<em_touch_callback_func>(original_touchcancel_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenTouchEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_touchcancel_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_touchmove_callback = 0;
/* import: 'a' 'La' */
// "La": "_emscripten_set_touchmove_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_touchmove_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_touchmove_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_touch_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_touchmove_callback = callback_;
auto hook = [](int eventType, const EmscriptenTouchEvent* event, void* userData) {
assert(original_touchmove_callback);
const auto& callback = fugg::function_ref<em_touch_callback_func>(original_touchmove_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenTouchEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_touchmove_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_touchend_callback = 0;
/* import: 'a' 'Ma' */
// "Ma": "_emscripten_set_touchend_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_touchend_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_touchend_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_touch_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_touchend_callback = callback_;
auto hook = [](int eventType, const EmscriptenTouchEvent* event, void* userData) {
assert(original_touchend_callback);
const auto& callback = fugg::function_ref<em_touch_callback_func>(original_touchend_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenTouchEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_touchend_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_touchstart_callback = 0;
/* import: 'a' 'Na' */
// "Na": "_emscripten_set_touchstart_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_touchstart_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_touchstart_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_touch_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_touchstart_callback = callback_;
auto hook = [](int eventType, const EmscriptenTouchEvent* event, void* userData) {
assert(original_touchstart_callback);
const auto& callback = fugg::function_ref<em_touch_callback_func>(original_touchstart_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenTouchEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_touchstart_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_orientationchange_callback = 0;
/* import: 'a' 'Pa' */
// "Pa": "_emscripten_set_orientationchange_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_orientationchange_callback_on_thread) = [](u32 a, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& user_data = fugg::module_ptr<void>(a);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_orientationchange_callback_on_thread("
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_orientationchange_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_orientationchange_callback = callback_;
auto hook = [](int eventType, const EmscriptenOrientationChangeEvent* event, void* userData) {
assert(original_orientationchange_callback);
const auto& callback = fugg::function_ref<em_orientationchange_callback_func>(original_orientationchange_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenOrientationChangeEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_orientationchange_callback_on_thread(user_data, use_capture, hook, target_thread)
);
};
u32 original_visibilitychange_callback = 0;
/* import: 'a' 'Ra' */
// "Ra": "_emscripten_set_visibilitychange_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_visibilitychange_callback_on_thread) = [](u32 a, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& user_data = fugg::module_ptr<void>(a);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_visibilitychange_callback_on_thread("
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_visibilitychange_callback_func>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_visibilitychange_callback = callback_;
auto hook = [](int eventType, const EmscriptenVisibilityChangeEvent* event, void* userData) {
assert(original_visibilitychange_callback);
const auto& callback = fugg::function_ref<em_visibilitychange_callback_func>(original_visibilitychange_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenVisibilityChangeEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_visibilitychange_callback_on_thread(user_data, use_capture, hook, target_thread)
);
};
u32 original_webglcontextrestored_callback = 0;
/* import: 'a' 'Ba' */
/* _emscripten_set_webglcontextrestored_callback_on_thread */
WASM_IMPORT_IMPL(env, _emscripten_set_webglcontextrestored_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_webglcontextrestored_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_webgl_context_callback>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_webglcontextrestored_callback = callback_;
auto hook = [](int eventType, const void* event, void* userData) {
assert(original_webglcontextrestored_callback);
const auto& callback = fugg::function_ref<em_webgl_context_callback>(original_webglcontextrestored_callback);
return callback(
eventType,
reinterpret_cast<const void*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_webglcontextrestored_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_webglcontextlost_callback = 0;
/* import: 'a' 'eb' */
// "eb": "_emscripten_set_webglcontextlost_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_webglcontextlost_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_webglcontextlost_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_webgl_context_callback>(callback_) << ", "
<< target_thread << ")" << std::endl;
#endif
original_webglcontextlost_callback = callback_;
auto hook = [](int eventType, const void* event, void* userData) {
assert(original_webglcontextlost_callback);
const auto& callback = fugg::function_ref<em_webgl_context_callback>(original_webglcontextlost_callback);
return callback(
eventType,
reinterpret_cast<const void*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_webglcontextlost_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};
u32 original_fullscreenchange_callback = 0;
/* import: 'a' 'yb' */
// "yb": "_emscripten_set_fullscreenchange_callback_on_thread",
WASM_IMPORT_IMPL(env, _emscripten_set_fullscreenchange_callback_on_thread) = [](u32 a, u32 b, u32 use_capture, u32 callback_, u32 target_thread) {
const auto& target = fugg::module_ptr<const char>(a);
const auto& user_data = fugg::module_ptr<void>(b);
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_fullscreenchange_callback_on_thread("
<< target << ", "
<< user_data << ", "
<< use_capture << ", "
<< emscripten_rt::fn<em_fullscreenchange_callback_func>(callback_) << ", "
<< target_thread << ", "
<< ")" << std::endl;
#endif
original_fullscreenchange_callback = callback_;
auto hook = [](int eventType, const EmscriptenFullscreenChangeEvent* event, void* userData) {
assert(original_fullscreenchange_callback);
const auto& callback = fugg::function_ref<em_fullscreenchange_callback_func>(original_fullscreenchange_callback);
return callback(
eventType,
reinterpret_cast<const EmscriptenFullscreenChangeEvent*>(fugg::app_ptr(event)),
reinterpret_cast<void*>(fugg::app_ptr(userData))
);
};
return static_cast<u32>(
emscripten_set_fullscreenchange_callback_on_thread(target, user_data, use_capture, hook, target_thread)
);
};

View File

@ -0,0 +1,586 @@
#include <wasm-rt.h>
#include <client.h>
#include <fugg.h>
#include <emscripten.h>
#include <emscripten/bind.h>
#include <iostream>
#include "embind.h"
#define TRACE_EM_CALLS 0
namespace fugg {
namespace embind {
std::map<TypeID, const TypeInfo *const> kTypeMap = { };
std::map<std::string, const FunctionEntry *const> kFunctionMap = { };
std::map<emscripten::internal::EM_METHOD_CALLER, MethodCaller*> kMethodCallers = { };
}
}
using namespace fugg::embind;
GenericWireType to_wasm_wire_type(
const TypeID& type,
const GenericWireType& val
) {
auto type_info = kTypeMap.at(type);
switch(type_info->type) {
case Type::Void:
case Type::Bool:
case Type::Integer:
case Type::Float:
case Type::Emval:
// Do nothing.
return val;
case Type::String: {
struct WireData {
size_t length;
char data[1];
};
auto pointee = reinterpret_cast<WireData*>(
static_cast<uintptr_t>(val)
);
return static_cast<emscripten::internal::EM_GENERIC_WIRE_TYPE>(
fugg::app_ptr(pointee)
);
} break;
case Type::MemoryView: {
// TOOD:
assert(0);
} break;
default:
assert(0);
}
}
void* from_wasm_wire_type(
const size_t arg_count,
const TypeID* types_,
void* args_
) {
auto args = reinterpret_cast<emscripten::internal::GenericWireType*>(args_);
for(auto i = 0; i < arg_count; i++) {
const auto& type_info = kTypeMap[types_[i]];
auto val = &args[i];
switch(type_info->type) {
case Type::Void:
case Type::Bool:
case Type::Integer:
case Type::Float:
case Type::Emval:
// Do nothing.
break;
case Type::String: {
// Offset the pointer.
val->w[0].p = fugg::wasm::kMemory.address_of(val->w[0].p);
} break;
case Type::MemoryView: {
struct WireData {
const size_t length;
void* data;
};
auto data = reinterpret_cast<WireData*>(val);
data->data = fugg::module_ptr(data->data);
} break;
default:
assert(0);
}
}
return args;
}
/* import: 'a' 'b' */
/* __emval_decref */
WASM_IMPORT_IMPL(env, __emval_decref) = [](u32 a) {
emscripten::internal::_emval_decref(
reinterpret_cast<emscripten::EM_VAL>(a)
);
};
// void (*Z_aZ_b)(u32) = [](u32 a) {
// emscripten::internal::_emval_decref(
// reinterpret_cast<emscripten::EM_VAL>(a)
// );
// };
/* import: 'a' 'c' */
/* __emval_new_cstring */
WASM_IMPORT_IMPL(env, __emval_new_cstring) = [](u32 value_) {
const auto& value = fugg::module_ptr<const char>(value_);
#if TRACE_EM_CALLS
std::cout << "_emval_new_cstring("
<< value
<< ")" << std::endl;
#endif
// Returns a handle, so no interop required.
return reinterpret_cast<u32>(
emscripten::internal::_emval_new_cstring(value)
);
};
/* __emval_set_property */
WASM_IMPORT_IMPL(env, __emval_set_property) = [](u32 a, u32 b, u32 c) {
emscripten::internal::_emval_set_property(
reinterpret_cast<emscripten::EM_VAL>(a),
reinterpret_cast<emscripten::EM_VAL>(b),
reinterpret_cast<emscripten::EM_VAL>(c)
);
};
/* __emval_get_property */
WASM_IMPORT_IMPL(env, __emval_get_property) = [](u32 a, u32 b) {
return reinterpret_cast<u32>(
emscripten::internal::_emval_get_property(
reinterpret_cast<emscripten::EM_VAL>(a),
reinterpret_cast<emscripten::EM_VAL>(b)
)
);
};
/* import: 'a' 'k' */
/* __emval_get_method_caller */
WASM_IMPORT_IMPL(env, __emval_get_method_caller) = [](u32 argCount_, u32 argTypes_) {
const auto& arg_count = argCount_;
const auto& arg_types = fugg::ptr_array<TypeID>(argTypes_, argCount_);
#if TRACE_EM_CALLS
std::cout << "_emval_get_method_caller("
<< arg_count << ", "
<< arg_types << ")" << std::endl;
#endif
const auto& method_caller = emscripten::internal::_emval_get_method_caller(arg_count, arg_types);
if(!kMethodCallers.count(method_caller)) {
const auto& return_type = arg_types[0];
kMethodCallers.emplace(method_caller, new MethodCaller {
.return_type = return_type,
// First argument is return type, so reduce argument count by 1
.arg_count = arg_count - 1,
.arg_types = &arg_types[1]
});
#if TRACE_EM_CALLS
std::cout << "Added method caller with id " << reinterpret_cast<void*>(method_caller)
<< " -> " << kTypeMap[return_type]->name << std::endl;
#endif
}
return reinterpret_cast<u32>(method_caller);
};
/* import: 'a' 'l' */
/* __emval_take_value */
WASM_IMPORT_IMPL(env, __emval_take_value) = [](u32 type_, u32 argv_) {
TypeID type = fugg::module_ptr<TypeID>(type_);
auto argv = fugg::module_ptr<void>(argv_);
#if TRACE_EM_CALLS
std::cout << "_emval_take_value("
<< type << ", "
<< argv << ")" << std::endl;
#endif
return reinterpret_cast<u32>(
emscripten::internal::_emval_take_value(
type,
// EM_VAR_ARGS calls `readValueFromPointer` so interop is required.
// emscripten/val.h:396: Constructing array of size 1.
from_wasm_wire_type(1, &type, argv)
)
);
};
/* import: 'a' 'o' */
/* __emval_run_destructors */
WASM_IMPORT_IMPL(env, __emval_run_destructors) = [](u32 a) {
#if TRACE_EM_CALLS
std::cout << "_emval_run_destructors("
<< reinterpret_cast<void*>(a) << ")" << std::endl;
#endif
emscripten::internal::_emval_run_destructors(
// EM_DESTRUCTORS is a handle, so no interop required.
reinterpret_cast<Destructors>(a)
);
};
/* __emval_get_global */
WASM_IMPORT_IMPL(env, __emval_get_global) = [](u32 name_) {
const auto& name = fugg::module_ptr<const char>(name_);
#if TRACE_EM_CALLS
std::cout << "_emval_get_global("
<< name
<< ")" << std::endl;
#endif
// This should be fine because the return value of _emval_get_global is just some number, not a real address.
return reinterpret_cast<u32>(
emscripten::internal::_emval_get_global(name)
);
};
/* import: 'a' 't' */
/* __emval_call_void_method */
WASM_IMPORT_IMPL(env, __emval_call_void_method) = [](u32 caller_, u32 handle_, u32 methodName_, u32 argv_) {
// EM_METHOD_CALLER is used as an index, so no interop is required.
const auto& caller = reinterpret_cast<emscripten::internal::EM_METHOD_CALLER>(caller_);
const auto& handle = reinterpret_cast<Value>(handle_);
const auto& method_name = fugg::module_ptr<const char>(methodName_);
const auto& argv = fugg::module_ptr<void>(argv_);
const auto& method_caller = kMethodCallers[caller];
#if TRACE_EM_CALLS
std::cout << "_emval_call_void_method("
<< caller << ", "
<< handle << ", "
<< method_name << ", "
<< argv << ")" << std::endl;
#endif
emscripten::internal::_emval_call_void_method(
caller,
handle,
method_name,
from_wasm_wire_type(method_caller->arg_count, method_caller->arg_types, argv)
);
};
/* import: 'a' 'y' */
/* __emval_as */
WASM_IMPORT_IMPL(env, __emval_as) = [](u32 a, u32 b, u32 c) {
// EM_VAL is just a number of the handle, so no interop required.
const auto& value = reinterpret_cast<emscripten::EM_VAL>(a);
const auto& return_type = fugg::module_ptr<TypeID>(b);
const auto& destructors = fugg::module_ptr<emscripten::internal::EM_DESTRUCTORS>(c);
#if TRACE_EM_CALLS
std::cout << "_emval_as("
<< value << ", "
<< return_type << " (" << kTypeMap[return_type]->name << ")" << ", "
<< destructors
<< std::endl;
#endif
return to_wasm_wire_type(
return_type,
emscripten::internal::_emval_as(value, return_type, destructors)
);
};
/* import: 'a' 'E' */
/* __emval_incref */
WASM_IMPORT_IMPL(env, __emval_incref) = [](u32 a) {
emscripten::internal::_emval_incref(
reinterpret_cast<emscripten::EM_VAL>(a)
);
};
/* import: 'a' 'H' */
/* __emval_call_method */
WASM_IMPORT_IMPL(env, __emval_call_method) = [](u32 a, u32 b, u32 c, u32 d, u32 argv_) {
const auto& caller = reinterpret_cast<emscripten::internal::EM_METHOD_CALLER>(a);
const auto& handle = reinterpret_cast<emscripten::EM_VAL>(b);
const auto& method_name = fugg::module_ptr<const char>(c);
const auto& destructors = fugg::module_ptr<emscripten::internal::EM_DESTRUCTORS>(d);
const auto& method_caller = kMethodCallers.at(caller);
const auto& argv = fugg::module_ptr<void>(argv_);
#if TRACE_EM_CALLS
std::cout << "_emval_call_method("
<< caller << ", "
<< handle << ", "
<< method_name << ", "
<< destructors << ", "
<< argv << ")" << std::endl;
#endif
auto result = emscripten::internal::_emval_call_method(
caller,
handle,
method_name,
destructors,
from_wasm_wire_type(method_caller->arg_count, method_caller->arg_types, argv)
);
return to_wasm_wire_type(
method_caller->return_type,
result
);
};
/* __emval_get_module_property */
WASM_IMPORT_IMPL(env, __emval_get_module_property) = [](u32 a) {
const auto& name = fugg::module_ptr<const char>(a);
#if TRACE_EM_CALLS
std::cout << "_emval_get_module_property(" << name << ")" << std::endl;
#endif
return reinterpret_cast<u32>(
emscripten::internal::_emval_get_module_property(name)
);
};
/* __emval_typeof */
WASM_IMPORT_IMPL(env, __emval_typeof) = [](u32 a) {
return reinterpret_cast<u32>(
emscripten::internal::_emval_typeof(
reinterpret_cast<emscripten::EM_VAL>(a)
)
);
};
/* __embind_register_function */
WASM_IMPORT_IMPL(env, __embind_register_function) = [](u32 a, u32 arg_count, u32 c, u32 d, u32 invoker_, u32 function_) {
const auto& name = fugg::module_ptr<const char>(a);
// This is an array, but not an array of pointers.
const auto& arg_types = fugg::module_ptr<emscripten::internal::TYPEID>(c);
const auto& signature = fugg::module_ptr<const char>(d);
// The invoker seems to convert the types received by the function.
const auto& invoker = fugg::function_ref<emscripten::internal::GenericFunction>(invoker_);
const auto& function = fugg::function_ref<emscripten::internal::GenericFunction>(function_);
kFunctionMap.emplace(name, new FunctionEntry {
.invoker = invoker_,
.fn = function_
});
#if TRACE_EM_CALLS
std::cout << "_embind_register_function("
<< name << ", "
<< arg_count << ", "
<< arg_types << ", "
<< signature << ", "
<< invoker << ", "
<< function
<< ")" << std::endl;
#endif
// if(std::string(name) != "platform_text_edited") {
// emscripten::internal::_embind_register_function(name, arg_count, arg_types, signature, invoker, function);
// } else {
std::cout << "Skipping registration of " << static_cast<const char*>(name)
<< " with " << arg_count << " arguments." << std::endl;
// }
};
/* import: 'a' 'ua' */
/* __emval_new */
WASM_IMPORT_IMPL(env, __emval_new) = [](u32 a, u32 arg_count, u32 arg_types_, u32 argv_) {
auto value = reinterpret_cast<emscripten::EM_VAL>(a);
// To prevent double converting pointers in the arg_type array, create a new
// array.
auto test_arg_types = new void*[arg_count];
using TypeID = void*;
auto arg_types = fugg::module_ptr<TypeID>(arg_types_);
for(int i = 0; i < arg_count; i++)
test_arg_types[i] = fugg::module_ptr(arg_types[i]);
auto argv = fugg::module_ptr<void>(argv_);
#if TRACE_EM_CALLS
std::cout << "_emval_new("
<< value << ", "
<< arg_count << ", "
<< arg_types << "(raw: " << reinterpret_cast<void*>(arg_types_) << "), "
<< argv << ")" << std::endl;
#endif
return reinterpret_cast<u32>(
emscripten::internal::_emval_new(
value,
arg_count,
test_arg_types,
from_wasm_wire_type(arg_count, test_arg_types, argv)
)
);
};
/* import: 'a' 'ya' */
// "ya": "_emscripten_resize_heap",
WASM_IMPORT_IMPL(env, _emscripten_resize_heap) = [](u32 a) {
printf("Flyff apparantly wants to resize the heap!");
// Original code calls `abortOnMemoryGrowth()`
return static_cast<u32>(0);
};
/* import: 'a' 'za' */
/* __embind_register_std_wstring */
WASM_IMPORT_IMPL(env, __embind_register_std_wstring) = [](u32 a, u32 char_size, u32 c) {
const auto& string_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
const auto& name = fugg::module_ptr<const char>(c);
#if TRACE_EM_CALLS
std::cout << "_embind_register_std_wstring("
<< string_type << ", "
<< char_size << ", "
<< name << ")" << std::endl;
#endif
kTypeMap.emplace(string_type, new TypeInfo {
.name = std::string(name),
.type = Type::WideString
});
emscripten::internal::_embind_register_std_wstring(string_type, char_size, name);
};
/* import: 'a' '_a' */
/* __embind_register_float */
WASM_IMPORT_IMPL(env, __embind_register_float) = [](u32 a, u32 b, u32 size) {
const auto& float_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
const auto& name = fugg::module_ptr<const char>(b);
#if TRACE_EM_CALLS
std::cout << "_embind_register_float("
<< float_type << ", "
<< name << ", "
<< size << ")" << std::endl;
#endif
kTypeMap.emplace(float_type, new TypeInfo {
.name = std::string(name),
.type = Type::Float
});
emscripten::internal::_embind_register_float(float_type, name, size);
};
/* import: 'a' '$a' */
/* __embind_register_std_string */
WASM_IMPORT_IMPL(env, __embind_register_std_string) = [](u32 a, u32 b) {
const auto& string_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
const auto& name = fugg::module_ptr<const char>(b);
#if TRACE_EM_CALLS
std::cout << "_embind_register_std_string("
<< string_type << ", "
<< name << ")" << std::endl;
#endif
kTypeMap.emplace(string_type, new TypeInfo {
.name = std::string(name),
.type = Type::String
});
emscripten::internal::_embind_register_std_string(string_type, name);
};
/* import: 'a' 'Bb' */
/* __embind_register_bigint */
WASM_IMPORT_IMPL(env, __embind_register_bigint) = [](u32 registerType, u32 name_, u32 size, u32 min_range, u32 max_range, u32 f, u32 g) {
// Does nothing in JS.
};
/* import: 'a' 'Ob' */
/* __embind_register_emval */
WASM_IMPORT_IMPL(env, __embind_register_emval) = [](u32 a, u32 b) {
const auto& emval_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
const auto& name = fugg::module_ptr<const char>(b);
#if TRACE_EM_CALLS
std::cout << "_embind_register_emval("
<< emval_type << ", "
<< name << ")" << std::endl;
#endif
kTypeMap.emplace(emval_type, new TypeInfo {
.name = std::string(name),
.type = Type::Emval
});
emscripten::internal::_embind_register_emval(emval_type, name);
};
/* import: 'a' 'Pb' */
/* __embind_register_bool */
WASM_IMPORT_IMPL(env, __embind_register_bool) = [](u32 a, u32 b, u32 size, u32 true_value, u32 false_value) {
const auto& bool_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
const auto& name = fugg::module_ptr<const char>(b);
#if TRACE_EM_CALLS
std::cout << "_embind_register_bool("
<< bool_type << ", "
<< name << ", "
<< size << ", "
<< true_value << ", "
<< false_value << ")" << std::endl;
#endif
kTypeMap.emplace(bool_type, new TypeInfo {
.name = std::string(name),
.type = Type::Bool
});
emscripten::internal::_embind_register_bool(bool_type, name, size, true_value, false_value);
};
/* import: 'a' 'Qb' */
/* __embind_register_void */
WASM_IMPORT_IMPL(env, __embind_register_void) = [](u32 a, u32 b) {
const auto& void_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
const auto& name = fugg::module_ptr<const char>(b);
#if TRACE_EM_CALLS
std::cout << "_embind_register_void("
<< void_type << ", "
<< name << ")" << std::endl;
#endif
kTypeMap.emplace(void_type, new TypeInfo {
.name = std::string(name),
.type = Type::Void
});
emscripten::internal::_embind_register_void(void_type, name);
};
/* import: 'a' 'J' */
/* __embind_register_memory_view */
WASM_IMPORT_IMPL(env, __embind_register_memory_view) = [](u32 a, u32 b, u32 c) {
const auto& memory_view_type = fugg::module_ptr<emscripten::internal::TYPEID>(a);
const auto& typed_array_index = b;
const auto& name = fugg::module_ptr<const char>(c);
#if TRACE_EM_CALLS
std::cout << "_embind_register_memory_view("
<< memory_view_type << ", "
<< typed_array_index << ", "
<< name << ")" << std::endl;
#endif
kTypeMap.emplace(memory_view_type, new TypeInfo {
.name = std::string(name),
.type = Type::MemoryView
});
emscripten::internal::_embind_register_memory_view(memory_view_type, typed_array_index, name);
};
/* __embind_register_integer */
WASM_IMPORT_IMPL(env, __embind_register_integer) = [](u32 integer_type_, u32 name_, u32 size, u32 min_range, u32 max_range) {
const auto& integer_type = fugg::module_ptr<TypeID>(integer_type_);
const auto& name = fugg::module_ptr<const char>(name_);
#if TRACE_EM_CALLS
std::cout << "_embind_register_integer("
<< integer_type << ", "
<< name << ", "
<< size << ", "
<< min_range << ", "
<< max_range << ")" << std::endl;
#endif
kTypeMap.emplace(integer_type, new TypeInfo {
.name = std::string(name),
.type = Type::Integer
});
emscripten::internal::_embind_register_integer(integer_type, name, size, min_range, max_range);
};

View File

@ -0,0 +1,47 @@
#include <emscripten.h>
#include <emscripten/bind.h>
namespace fugg {
namespace embind {
using TypeID = emscripten::internal::TYPEID;
using GenericWireType = emscripten::internal::EM_GENERIC_WIRE_TYPE;
using VariableArguments = emscripten::internal::GenericWireType*;
using Value = emscripten::EM_VAL;
using Destructors = emscripten::internal::EM_DESTRUCTORS;
enum class Type {
// Primitives
Void,
Bool,
Integer,
Float,
Emval,
// Complex
String,
WideString,
MemoryView,
};
struct TypeInfo {
std::string name;
Type type;
};
struct FunctionEntry {
uintptr_t invoker;
uintptr_t fn;
};
struct MethodCaller {
const emscripten::internal::TYPEID return_type;
const unsigned int arg_count;
const emscripten::internal::TYPEID* arg_types;
};
extern std::map<TypeID, const TypeInfo *const> kTypeMap;
extern std::map<std::string, const FunctionEntry *const> kFunctionMap;
extern std::map<emscripten::internal::EM_METHOD_CALLER, MethodCaller*> kMethodCallers;
}
}

View File

@ -0,0 +1,333 @@
#include <wasm-rt.h>
#include <client.h>
#include <fugg.h>
#include <stdio.h>
#include <assert.h>
#include <emscripten.h>
#include <emscripten/html5.h>
#include <iostream>
/* import: 'a' 'qa' */
// "qa": "_emscripten_set_main_loop",
WASM_IMPORT_IMPL(env, _emscripten_set_main_loop) = [](u32 a, u32 fps, u32 simulate_infinite_loop) {
static u32 original_main_loop = 0;
auto main_loop_override = []() {
// std::cout << "This is fugg main loop being called! Calling original loop... at " << reinterpret_cast<void*>(original_main_loop) << std::endl;
const auto& func = fugg::function_ref<em_callback_func>(original_main_loop);
func();
};
original_main_loop = a;
#if TRACE_CALLBACK_CALLS
std::cout << "_emscripten_set_main_loop("
<< func << " (" << reinterpret_cast<void*>(a) << "), "
<< fps << ", "
<< simulate_infinite_loop << ")" << std::endl;
#endif
emscripten_set_main_loop(main_loop_override, fps, simulate_infinite_loop);
};
/* import: 'a' 'pa' */
// "pa": "_emscripten_cancel_main_loop",
WASM_IMPORT_IMPL(env, _emscripten_cancel_main_loop) = []() {
emscripten_cancel_main_loop();
};
/* import: 'a' 'ab' */
// "ab": "_emscripten_async_wget_data",
WASM_IMPORT_IMPL(env, _emscripten_async_wget_data) = [](u32 url_, u32 arg_, u32 onload_, u32 onerror_) {
// This function is only called by the flyff runtime, so we introduce
// stubs to refer the onload and onerror on to actual flyff functions.
// See `onload_stub` and `onerror_stub`.
struct wget_data {
u32 onload;
u32 onerror;
u32 original_arg;
};
auto onload_stub = [](void* arg_, void *data_, int size) {
const auto& interop_data = reinterpret_cast<wget_data*>(arg_);
const auto& onload = fugg::function_ref<em_async_wget_onload_func>(interop_data->onload);
// This pointer can stay unchanged, it came from inside and is going inside.
const auto& arg = reinterpret_cast<void*>(interop_data->original_arg);
const auto& data = reinterpret_cast<void*>(fugg::app_ptr(data_));
#if TRACE_EM_CALLS
std::cout << "onload_stub: Calling function at " << reinterpret_cast<void*>(onload) << "("
<< arg << ", "
<< data << ", "
<< size << ")" << std::endl;
#endif
onload(arg, data, size);
delete interop_data;
};
auto onerror_stub = [](void* arg_) {
const auto& interop_data = reinterpret_cast<wget_data*>(arg_);
const auto& onerror = fugg::function_ref<em_arg_callback_func>(interop_data->onerror);
const auto& arg = reinterpret_cast<void*>(interop_data->original_arg);
#if TRACE_EM_CALLS
std::cout << "onerror_stub: Calling function at " << reinterpret_cast<void*>(onerror) << "("
<< arg << ")" << std::endl;
#endif
onerror(arg);
delete interop_data;
};
const auto& url = fugg::module_ptr<const char>(url_);
const auto data = new wget_data {
.onload = onload_,
.onerror = onerror_,
.original_arg = arg_
};
#if TRACE_EM_CALLS
std::cout << "_emscripten_async_wget_data("
<< url << ", "
<< arg_ << ", "
<< reinterpret_cast<void*>(onload_) << ", "
<< reinterpret_cast<void*>(onerror_) << ")" << std::endl;
#endif
std::cout << "Client: Downloading " << static_cast<const char*>(url) << std::endl;
// This function can allocate, which will call the Flyff runtime allocate.
emscripten_async_wget_data(url, data, onload_stub, onerror_stub);
};
/* import: 'a' 'fb' */
// "fb": "_emscripten_set_element_css_size",
WASM_IMPORT_IMPL(env, _emscripten_set_element_css_size) = [](u32 target_, f64 width, f64 height) {
const auto& target = fugg::module_ptr<const char>(target_);
#if TRACE_EM_CALLS
std::cout << "_emscripten_set_element_css_size("
<< target << ", "
<< width << ", "
<< height << ")" << std::endl;
#endif
return static_cast<u32>(
emscripten_set_element_css_size(target, width, height)
);
};
/* import: 'a' 'gb' */
// "gb": "_emscripten_set_canvas_element_size",
WASM_IMPORT_IMPL(env, _emscripten_set_canvas_element_size) = [](u32 target_, u32 width, u32 height) {
const auto& target = fugg::module_ptr<const char>(target_);
#if TRACE_EM_CALLS
std::cout << "_emscripten_set_canvas_element_size("
<< target << ", "
<< width << ", "
<< height << ")" << std::endl;
#endif
return static_cast<u32>(
emscripten_set_canvas_element_size(target, width, height)
);
};
/* import: 'a' 'ob' */
// "ob": "_emscripten_get_orientation_status",
WASM_IMPORT_IMPL(env, _emscripten_get_orientation_status) = [](u32 a) {
return static_cast<u32>(
emscripten_get_orientation_status(
fugg::module_ptr<EmscriptenOrientationChangeEvent>(a)
)
);
};
/* import: 'a' 'Ab' */
/* _fd_seek */
WASM_IMPORT_IMPL(env, _fd_seek) = [](u32 a, u32 b, u32 c, u32 d, u32 e) {
// For some reason, it only returns 70.
return static_cast<u32>(70);
};
WASM_IMPORT_IMPL(env, _abort) = [](void) {
puts("abort() called!");
assert(0);
};
// "la": "_emscripten_exit_fullscreen",
WASM_IMPORT_IMPL(env, _emscripten_exit_fullscreen) = []() {
return static_cast<u32>(
emscripten_exit_fullscreen()
);
};
// "ma": "_emscripten_request_fullscreen",
WASM_IMPORT_IMPL(env, _emscripten_request_fullscreen) = [](u32 a, u32 b) {
return static_cast<u32>(
emscripten_request_fullscreen(
reinterpret_cast<const char*>(a),
b
)
);
};
/* import: 'a' 'oa' */
// "oa": "_emscripten_performance_now",
WASM_IMPORT_IMPL(env, _emscripten_performance_now) = []() {
return emscripten_performance_now();
};
/* import: 'a' 'Za' */
/* __emscripten_date_now */
WASM_IMPORT_IMPL(env, __emscripten_date_now) = []() {
return emscripten_get_now();
};
// "da": "_emscripten_vibrate",
WASM_IMPORT_IMPL(env, _emscripten_vibrate) = [](u32 a) {
return static_cast<u32>(
emscripten_vibrate(a)
);
};
/* import: 'a' 'Aa' */
/* _strftime */
WASM_IMPORT_IMPL(env, _strftime) = [](u32 a, u32 b, u32 c, u32 d) {
return static_cast<u32>(
strftime(
fugg::module_ptr<char>(a),
b,
fugg::module_ptr<char>(c),
fugg::module_ptr<const tm>(d)
)
);
};
/* import: 'a' 'Oa' */
// "Oa": "_emscripten_webgl_destroy_context",
WASM_IMPORT_IMPL(env, _emscripten_webgl_destroy_context) = [](u32 a) {
return static_cast<u32>(
emscripten_webgl_destroy_context(a)
);
};
/* import: 'a' 'Cb' */
/* _strftime_l */
WASM_IMPORT_IMPL(env, _strftime_l) = [](u32 a, u32 b, u32 c, u32 d, u32 e) {
return static_cast<u32>(
strftime_l(
reinterpret_cast<char*>(a),
b,
reinterpret_cast<char*>(c),
reinterpret_cast<const tm*>(d),
reinterpret_cast<locale_t>(e)
)
);
};
/* import: 'a' 'Db' */
/* _environ_get */
WASM_IMPORT_IMPL(env, _environ_get) = [](u32 a, u32 b) {
puts("_environ_get");
// FIXME:
return static_cast<u32>(0);
};
/* import: 'a' 'Eb' */
/* _environ_sizes_get */
WASM_IMPORT_IMPL(env, _environ_sizes_get) = [](u32, u32) {
puts("_environ_sizes_get");
// FIXME:
return static_cast<u32>(0);
};
/* import: 'a' 'Fb' */
/* _fd_close */
WASM_IMPORT_IMPL(env, _fd_close) = [](u32 a) {
// For some reason returns 52...
return static_cast<u32>(52);
};
/* import: 'a' 'Gb' */
/* _fd_write */
WASM_IMPORT_IMPL(env, _fd_write) = [](u32 a, u32 b, u32 c, u32 d) {
puts("fd_write");
// FIXME:
return static_cast<u32>(0);
};
/* import: 'a' 'Hb' */
// "Hb": "_emscripten_memcpy_big",
WASM_IMPORT_IMPL(env, _emscripten_memcpy_big) = [](u32 dest_, u32 src_, u32 length) {
// WASM runtime calls this, so no need to change the pointers since it's "internal".
// Right?
const auto& dest = fugg::module_ptr<void>(dest_);
const auto& src = fugg::module_ptr<void>(src_);
#if TRACE_ALLOC
std::cout << "_emscripten_memcpy_big("
<< dest << ", "
<< src << ", "
<< length << ")" << std::endl;
#endif
wasm_rt_memcpy(dest, src, length);
};
/* import: 'a' 'Ib' */
/* __emscripten_get_now_is_monotonic */
WASM_IMPORT_IMPL(env, __emscripten_get_now_is_monotonic) = []() {
return static_cast<u32>(true);
};
/* import: 'a' 'Jb' */
/* __gmtime_js */
WASM_IMPORT_IMPL(env, __gmtime_js) = [](u32 a, u32 b) {
// FIXME:
// puts("__gmtime_js is not implemented yet.");
};
/* import: 'a' 'Kb' */
/* __localtime_js */
WASM_IMPORT_IMPL(env, __localtime_js) = [](u32 a, u32 b) {
// FIXME:
// puts("__localtime_js is not implemented yet.");
};
/* import: 'a' 'Lb' */
/* __mktime_js */
WASM_IMPORT_IMPL(env, __mktime_js) = [](u32 a) {
// FIXME:
// puts("__mktime_js is not implemented yet.");
return static_cast<u32>(0);
};
/* import: 'a' 'Mb' */
/* __tzset_js */
WASM_IMPORT_IMPL(env, __tzset_js) = [](u32 a, u32 b, u32 c) {
// FIXME:
// puts("__tzset_js is not implemented yet.");
};
/* import: 'a' 'Rb' */
// "Rb": "_emscripten_log",
WASM_IMPORT_IMPL(env, _emscripten_log) = [](u32 flags, u32 b, u32 c) {
const auto& format = fugg::module_ptr<const char>(b);
emscripten_log(flags, format, c);
};
/* import: 'a' 'bc' */
// "bc": "_emscripten_get_fullscreen_status",
WASM_IMPORT_IMPL(env, _emscripten_get_fullscreen_status) = [](u32 a) {
const auto& fullscreen_status = fugg::module_ptr<EmscriptenFullscreenChangeEvent>(a);
#if TRACE_EM_CALLS
std::cout << "_emscripten_get_fullscreen_status("
<< fullscreen_status << ")" << std::endl;
#endif
return static_cast<u32>(
emscripten_get_fullscreen_status(fullscreen_status)
);
};
/* import: 'a' 'cc' */
// "cc": "_emscripten_force_exit",
WASM_IMPORT_IMPL(env, _emscripten_force_exit) = [](u32 a) {
emscripten_force_exit(a);
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,112 @@
#include <wasm-rt.h>
#include <client.h>
#include <fugg.h>
#include <emscripten/bind.h>
#include <iostream>
#include "embind.h"
void platform_text_edited_hook(u32 ptr, u32 selection_start, u32 selection_end) {
// Emscripten doesn't understand sending pointers, so we have to receive an int.
auto text = reinterpret_cast<const char*>(fugg::app_ptr(ptr));
using PlatformTextEditedFn = void (*)(const char*, u32, u32);
const auto& platform_text_edited = fugg::function_ref<PlatformTextEditedFn>(
fugg::embind::kFunctionMap["platform_text_edited"]->fn
);
platform_text_edited(
text, selection_start, selection_end
);
}
void platform_got_devicemotion_permission_hook() {
using PlatformGotDeviceMotionPermissionFn = void (*)(void);
auto platform_got_devicemotion_permission = fugg::function_ref<PlatformGotDeviceMotionPermissionFn>(
fugg::embind::kFunctionMap["platform_got_devicemotion_permission"]->fn
);
platform_got_devicemotion_permission();
}
void platform_captcha_completed_hook(std::string token) {
struct WireType {
size_t length;
char data[1];
};
WireType* wt = (WireType*)malloc(sizeof(size_t) + token.length());
wt->length = token.length();
memcpy(wt->data, token.data(), token.length());
using PlatformCaptchaCompletedFn = void (*)(std::string);
using PlatformCaptchaCompletedInvoker = void (*)(PlatformCaptchaCompletedFn, WireType*);
// Don't transform this, as it will be passed to a function inside the runtime (the invoker).
auto platform_captcha_completed = reinterpret_cast<PlatformCaptchaCompletedFn>(
fugg::embind::kFunctionMap["platform_captcha_completed"]->fn
);
// Do transform this, as it's being called from outside.
auto platform_captcha_completed_invoker = fugg::function_ref<PlatformCaptchaCompletedInvoker>(
fugg::embind::kFunctionMap["platform_captcha_completed"]->invoker
);
platform_captcha_completed_invoker(
platform_captcha_completed,
reinterpret_cast<WireType*>(fugg::app_ptr(wt))
);
}
using PlatformWebsocketFn = void (*)(emscripten::val event);
void platform_websocket_open_hook(emscripten::val event) {
// std::cout << "platform_websocket_open_hook:" << std::endl;// event=" << event << std::endl;
const auto& platform_websocket_open = fugg::function_ref<PlatformWebsocketFn>(
fugg::embind::kFunctionMap["platform_websocket_open"]->fn
);
platform_websocket_open(event);
}
void platform_websocket_close_hook(emscripten::val event) {
// std::cout << "platform_websocket_close_hook:" << std::endl;// code=" << code << std::endl;
const auto& platform_websocket_close = fugg::function_ref<PlatformWebsocketFn>(
fugg::embind::kFunctionMap["platform_websocket_close"]->fn
);
platform_websocket_close(event);
}
void platform_websocket_message_hook(emscripten::val event) {
// std::cout << "platform_websocket_message: Got " << event["data"]["byteLength"].as<unsigned long>() << " bytes" << std::endl;
struct Test {
emscripten::EM_VAL handle;
};
auto test = new Test { event.as_handle() };
using PlatformWebsocketFn = void (*)(Test* event);
const auto& platform_websocket_message = fugg::function_ref<PlatformWebsocketFn>(
fugg::embind::kFunctionMap["platform_websocket_message"]->fn
);
platform_websocket_message(reinterpret_cast<Test*>(fugg::app_ptr(test)));
delete test;
}
EMSCRIPTEN_BINDINGS(my_module) {
emscripten::function("platform_text_edited", &platform_text_edited_hook);
emscripten::function("platform_got_devicemotion_permission", &platform_got_devicemotion_permission_hook);
emscripten::function("platform_captcha_completed", &platform_captcha_completed_hook);
emscripten::function("platform_websocket_open", &platform_websocket_open_hook);
emscripten::function("platform_websocket_close", &platform_websocket_close_hook);
emscripten::function("platform_websocket_message", &platform_websocket_message_hook);
}

View File

@ -0,0 +1,17 @@
#include <wasm-rt.h>
#include <client.h>
namespace fugg {
namespace interop {
namespace import {
static const auto& init = &Z_client_init;
static const auto& __wasm_call_ctors = &Z_clientZ____wasm_call_ctors;
static const auto& _main = &Z_clientZ__main;
static const auto& _malloc = &Z_clientZ__malloc;
static const auto& _free = &Z_clientZ__free;
}
}
}

70
fugg-client/src/main.cpp Normal file
View File

@ -0,0 +1,70 @@
#include "fugg.h"
#include "client.h"
#include <iostream>
#include <emscripten/heap.h>
#include "interop/imports.h"
void *malloc (size_t __size) {
using namespace fugg::interop;
// This malloc is always called from the runtime.
if((*import::_malloc) != nullptr) {
// Since this malloc is always called from the interop, we need to
// transform it to point to the actual address where the WASM runtime memory
// resides.
const auto& ptr = fugg::module_ptr<void>(
(*import::_malloc)(__size)
);
#if TRACE_ALLOC
std::cout << "FLYFF: Allocated " << __size << " bytes at " << ptr << std::endl;
#endif
return ptr;
} else {
auto ptr = emscripten_builtin_malloc(__size);
#if TRACE_ALLOC
std::cout << "FUGG: Allocated " << __size << " bytes at " << ptr << std::endl;
#endif
return ptr;
}
}
void free (void *__ptr) {
using namespace fugg::interop;
// printf("Trying to free ptr %p\n", __ptr);
if((*import::_free) != nullptr) {
auto ptr = fugg::app_ptr(__ptr);
(*import::_free)(ptr);
#if TRACE_ALLOC
std::cout << "FLYFF: Free'd pointer at " << ptr << std::endl;
#endif
} else {
emscripten_builtin_free(__ptr);
#if TRACE_ALLOC
printf("FUGG: Free'd pointer at %p\n", __ptr);
#endif
}
}
int main() {
std::cout << "Hello world from fugg!" << std::endl;
std::cout << "Initialising runtime... ";
auto& client = fugg::Client::instance();
client.initialise();
std::cout << "Ok!" << std::endl;
std::cout << "Starting Flyff..." << std::endl;
return client.main();
}

7
fugg-core/CMakeLists.txt Normal file
View File

@ -0,0 +1,7 @@
add_library (
fugg-core
"include/fugg.h"
)
target_include_directories(fugg-core PUBLIC "include")
target_link_libraries (fugg-core LINK_PUBLIC flyff-client)

4
fugg-core/include/fugg.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
#include "../src/memory.h"
#include "../src/table.h"

86
fugg-core/src/memory.h Normal file
View File

@ -0,0 +1,86 @@
#pragma once
#include <client.h>
#include <wasm-rt.h>
namespace fugg {
namespace wasm {
class Memory {
wasm_rt_memory_t** memory;
public:
explicit Memory(wasm_rt_memory_t** memory) : memory(memory) { }
uintptr_t address_of(uintptr_t offset) const {
if(offset != NULL)
return reinterpret_cast<uintptr_t>(&(*memory)->data[offset]);
else
return NULL;
}
uintptr_t start() {
return reinterpret_cast<uintptr_t>(
(*memory)->data
);
}
};
static auto kMemory = Memory { &Z_clientZ_memory };
}
template<typename T>
static T* module_ptr(uintptr_t address) {
return reinterpret_cast<T*>(
wasm::kMemory.address_of(address)
);
}
template<typename T>
static T* module_ptr(T* &address) {
return module_ptr<T>(reinterpret_cast<uintptr_t>(address));
}
static uintptr_t app_ptr(uintptr_t offset) {
if(offset != NULL)
return offset - wasm::kMemory.start();
else
return NULL;
}
static uintptr_t app_ptr(const void* offset) {
return app_ptr(reinterpret_cast<uintptr_t>(offset));
}
// Value does not have to be offset.
template<typename T>
class Value {
T value;
public:
explicit Value(const T& value) : value(value) { }
Value<T>& operator=(T value) {
this->value = value;
return *this;
}
operator T() const {
return value;
}
};
// Modifies the array to let the pointers be accessible from outside the WASM runtime
template<typename T>
static T* ptr_array(uintptr_t address, size_t length) {
auto src = reinterpret_cast<uintptr_t*>(
wasm::kMemory.address_of(address)
);
for(unsigned int i = 0; i < length; i++) {
src[i] = wasm::kMemory.address_of(src[i]);
}
return reinterpret_cast<T*>(src);
}
}

30
fugg-core/src/table.h Normal file
View File

@ -0,0 +1,30 @@
#pragma once
#include <client.h>
#include <wasm-rt.h>
namespace fugg {
namespace wasm
{
class Table {
wasm_rt_table_t** table;
public:
explicit Table(wasm_rt_table_t** table) : table(table) { }
wasm_rt_elem_t* element(uintptr_t address) const {
return &(*table)->data[address];
}
};
static auto kTable = Table { &Z_clientZ_table };
}
template<typename T>
static T function_ref(uintptr_t address) {
const auto& element = wasm::kTable.element(address);
return reinterpret_cast<T>(element->func);
}
}

7
setup.sh Executable file
View File

@ -0,0 +1,7 @@
# Download and install the latest SDK tools.
./vendor/emsdk/emsdk install latest
# Make the "latest" SDK "active" for the current user. (writes .emscripten file)
./vendor/emsdk/emsdk activate latest
source ./vendor/emsdk/emsdk_env.sh