// blindly copied imports from fastdwarf #include "Core.h" #include "Console.h" #include "Export.h" #include "PluginManager.h" #include "VersionInfo.h" #include "DataDefs.h" #include "df/world.h" #include "df/unit.h" #include "tinythread.h" using namespace DFHack; // DFHack stuff static int df_loadruby(void); static void df_unloadruby(void); static void df_rubythread(void*); static command_result df_rubyload(color_ostream &out, std::vector & parameters); static command_result df_rubyeval(color_ostream &out, std::vector & parameters); static void ruby_bind_dfhack(void); // inter-thread communication stuff enum RB_command { RB_IDLE, RB_INIT, RB_DIE, RB_EVAL, RB_CUSTOM, }; tthread::mutex *m_irun; tthread::mutex *m_mutex; static RB_command r_type; static const char *r_command; static command_result r_result; static tthread::thread *r_thread; static int onupdate_active; DFHACK_PLUGIN("ruby") DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { // fail silently instead of spamming the console with 'failed to initialize' if libruby is not present // the error is still logged in stderr.log if (!df_loadruby()) return CR_OK; m_irun = new tthread::mutex(); m_mutex = new tthread::mutex(); r_type = RB_INIT; r_thread = new tthread::thread(df_rubythread, 0); while (r_type != RB_IDLE) tthread::this_thread::yield(); m_irun->lock(); if (r_result == CR_FAILURE) return CR_FAILURE; onupdate_active = 0; commands.push_back(PluginCommand("rb_load", "Ruby interpreter. Loads the given ruby script.", df_rubyload)); commands.push_back(PluginCommand("rb_eval", "Ruby interpreter. Eval() a ruby string.", df_rubyeval)); return CR_OK; } DFhackCExport command_result plugin_shutdown ( color_ostream &out ) { if (!r_thread) return CR_OK; m_mutex->lock(); r_type = RB_DIE; r_command = 0; m_irun->unlock(); r_thread->join(); delete r_thread; r_thread = 0; delete m_irun; m_mutex->unlock(); delete m_mutex; df_unloadruby(); return CR_OK; } // send a single ruby line to be evaluated by the ruby thread static command_result plugin_eval_rb(const char *command) { command_result ret; // serialize 'accesses' to the ruby thread m_mutex->lock(); if (!r_thread) // raced with plugin_shutdown ? return CR_OK; r_type = RB_EVAL; r_command = command; m_irun->unlock(); // could use a condition_variable or something... while (r_type != RB_IDLE) tthread::this_thread::yield(); // XXX non-atomic with previous r_type change check ret = r_result; m_irun->lock(); m_mutex->unlock(); return ret; } static command_result plugin_eval_rb(std::string &command) { return plugin_eval_rb(command.c_str()); } DFhackCExport command_result plugin_onupdate ( color_ostream &out ) { if (!r_thread) return CR_OK; if (!onupdate_active) return CR_OK; return plugin_eval_rb("DFHack.onupdate"); } DFhackCExport command_result plugin_onstatechange ( color_ostream &out, state_change_event e) { if (!r_thread) return CR_OK; std::string cmd = "DFHack.onstatechange "; switch (e) { #define SCASE(s) case SC_ ## s : cmd += ":" # s ; break SCASE(WORLD_LOADED); SCASE(WORLD_UNLOADED); SCASE(MAP_LOADED); SCASE(MAP_UNLOADED); SCASE(VIEWSCREEN_CHANGED); SCASE(CORE_INITIALIZED); SCASE(BEGIN_UNLOAD); #undef SCASE } return plugin_eval_rb(cmd); } static command_result df_rubyload(color_ostream &out, std::vector & parameters) { if (parameters.size() == 1 && (parameters[0] == "help" || parameters[0] == "?")) { out.print("This command loads the ruby script whose path is given as parameter, and run it.\n"); return CR_OK; } std::string cmd = "load '"; cmd += parameters[0]; // TODO escape singlequotes cmd += "'"; return plugin_eval_rb(cmd); } static command_result df_rubyeval(color_ostream &out, std::vector & parameters) { command_result ret; if (parameters.size() == 1 && (parameters[0] == "help" || parameters[0] == "?")) { out.print("This command executes an arbitrary ruby statement.\n"); return CR_OK; } std::string full = ""; for (unsigned i=0 ; i> 1) #define RUBY_METHOD_FUNC(func) ((VALUE(*)(...))func) VALUE *rb_eRuntimeError; void (*ruby_sysinit)(int *, const char ***); void (*ruby_init)(void); void (*ruby_init_loadpath)(void); void (*ruby_script)(const char*); void (*ruby_finalize)(void); ID (*rb_intern)(const char*); VALUE (*rb_raise)(VALUE, const char*, ...); VALUE (*rb_funcall)(VALUE, ID, int, ...); VALUE (*rb_define_module)(const char*); void (*rb_define_singleton_method)(VALUE, const char*, VALUE(*)(...), int); void (*rb_define_const)(VALUE, const char*, VALUE); void (*rb_load_protect)(VALUE, int, int*); VALUE (*rb_gv_get)(const char*); VALUE (*rb_str_new)(const char*, long); VALUE (*rb_str_new2)(const char*); char* (*rb_string_value_ptr)(VALUE*); VALUE (*rb_eval_string_protect)(const char*, int*); VALUE (*rb_ary_shift)(VALUE); VALUE (*rb_float_new)(double); double (*rb_num2dbl)(VALUE); VALUE (*rb_int2inum)(long); VALUE (*rb_uint2inum)(unsigned long); unsigned long (*rb_num2ulong)(VALUE); // end of rip(ruby.h) DFHack::DFLibrary *libruby_handle; // load the ruby library, initialize function pointers static int df_loadruby(void) { const char *libpath = #ifdef WIN32 "./libruby.dll"; #else "hack/libruby.so"; #endif libruby_handle = OpenPlugin(libpath); if (!libruby_handle) { fprintf(stderr, "Cannot initialize ruby plugin: failed to load %s\n", libpath); return 0; } if (!(rb_eRuntimeError = (VALUE*)LookupPlugin(libruby_handle, "rb_eRuntimeError"))) return 0; // XXX does msvc support decltype ? might need a #define decltype typeof // or just assign to *(void**)(&s) = ... // ruby_sysinit is optional (ruby1.9 only) ruby_sysinit = (decltype(ruby_sysinit))LookupPlugin(libruby_handle, "ruby_sysinit"); #define rbloadsym(s) if (!(s = (decltype(s))LookupPlugin(libruby_handle, #s))) return 0 rbloadsym(ruby_init); rbloadsym(ruby_init_loadpath); rbloadsym(ruby_script); rbloadsym(ruby_finalize); rbloadsym(rb_intern); rbloadsym(rb_raise); rbloadsym(rb_funcall); rbloadsym(rb_define_module); rbloadsym(rb_define_singleton_method); rbloadsym(rb_define_const); rbloadsym(rb_load_protect); rbloadsym(rb_gv_get); rbloadsym(rb_str_new); rbloadsym(rb_str_new2); rbloadsym(rb_string_value_ptr); rbloadsym(rb_eval_string_protect); rbloadsym(rb_ary_shift); rbloadsym(rb_float_new); rbloadsym(rb_num2dbl); rbloadsym(rb_int2inum); rbloadsym(rb_uint2inum); rbloadsym(rb_num2ulong); #undef rbloadsym return 1; } static void df_unloadruby(void) { if (libruby_handle) { ClosePlugin(libruby_handle); libruby_handle = 0; } } // ruby thread code static void dump_rb_error(void) { VALUE s, err; err = rb_gv_get("$!"); s = rb_funcall(err, rb_intern("class"), 0); s = rb_funcall(s, rb_intern("name"), 0); Core::printerr("E: %s: ", rb_string_value_ptr(&s)); s = rb_funcall(err, rb_intern("message"), 0); Core::printerr("%s\n", rb_string_value_ptr(&s)); err = rb_funcall(err, rb_intern("backtrace"), 0); for (int i=0 ; i<8 ; ++i) if ((s = rb_ary_shift(err)) != Qnil) Core::printerr(" %s\n", rb_string_value_ptr(&s)); } static color_ostream_proxy *console_proxy; // ruby thread main loop static void df_rubythread(void *p) { int state, running; if (ruby_sysinit) { // ruby1.9 specific API static int argc; static const char *argv[] = { "dfhack", 0 }; ruby_sysinit(&argc, (const char ***)&argv); } // initialize the ruby interpreter ruby_init(); ruby_init_loadpath(); // default value for the $0 "current script name" ruby_script("dfhack"); // create the ruby objects to map DFHack to ruby methods ruby_bind_dfhack(); console_proxy = new color_ostream_proxy(Core::getInstance().getConsole()); r_result = CR_OK; r_type = RB_IDLE; running = 1; while (running) { // wait for new command m_irun->lock(); switch (r_type) { case RB_IDLE: case RB_INIT: break; case RB_DIE: running = 0; ruby_finalize(); break; case RB_EVAL: state = 0; rb_eval_string_protect(r_command, &state); if (state) dump_rb_error(); break; case RB_CUSTOM: // TODO handle ruby custom commands break; } r_result = CR_OK; r_type = RB_IDLE; m_irun->unlock(); tthread::this_thread::yield(); } } #define BOOL_ISFALSE(v) ((v) == Qfalse || (v) == Qnil || (v) == INT2FIX(0)) // main DFHack ruby module static VALUE rb_cDFHack; // DFHack module ruby methods, binds specific dfhack methods // enable/disable calls to DFHack.onupdate() static VALUE rb_dfonupdateactive(VALUE self) { if (onupdate_active) return Qtrue; else return Qfalse; } static VALUE rb_dfonupdateactiveset(VALUE self, VALUE val) { onupdate_active = (BOOL_ISFALSE(val) ? 0 : 1); return Qtrue; } static VALUE rb_dfresume(VALUE self) { Core::getInstance().Resume(); return Qtrue; } static VALUE rb_dfsuspend(VALUE self) { Core::getInstance().Suspend(); return Qtrue; } // returns the delta to apply to dfhack xml addrs wrt actual memory addresses // usage: real_addr = addr_from_xml + this_delta; static VALUE rb_dfrebase_delta(void) { uint32_t expected_base_address; uint32_t actual_base_address = 0; #ifdef WIN32 expected_base_address = 0x00400000; actual_base_address = (uint32_t)GetModuleHandle(0); #else expected_base_address = 0x08048000; FILE *f = fopen("/proc/self/maps", "r"); char line[256]; while (fgets(line, sizeof(line), f)) { if (strstr(line, "libs/Dwarf_Fortress")) { actual_base_address = strtoul(line, 0, 16); break; } } #endif return rb_int2inum(actual_base_address - expected_base_address); } static VALUE rb_dfprint_str(VALUE self, VALUE s) { console_proxy->print("%s", rb_string_value_ptr(&s)); return Qnil; } static VALUE rb_dfprint_err(VALUE self, VALUE s) { Core::printerr("%s", rb_string_value_ptr(&s)); return Qnil; } /* TODO needs main dfhack support this needs a custom DFHack::Plugin subclass to pass the cmdname to invoke(), to match the ruby callback // register a ruby method as dfhack console command // usage: DFHack.register("moo", "this commands prints moo on the console") { DFHack.puts "moo !" } static VALUE rb_dfregister(VALUE self, VALUE name, VALUE descr) { commands.push_back(PluginCommand(rb_string_value_ptr(&name), rb_string_value_ptr(&descr), df_rubycustom)); return Qtrue; } */ static VALUE rb_dfregister(VALUE self, VALUE name, VALUE descr) { rb_raise(*rb_eRuntimeError, "not implemented"); return Qnil; } static VALUE rb_dfget_global_address(VALUE self, VALUE name) { return rb_uint2inum(Core::getInstance().vinfo->getAddress(rb_string_value_ptr(&name))); } static VALUE rb_dfget_vtable(VALUE self, VALUE name) { return rb_uint2inum((uint32_t)Core::getInstance().vinfo->getVTable(rb_string_value_ptr(&name))); } // read the c++ class name from a vtable pointer, inspired from doReadClassName // XXX virtual classes only! dark pointer arithmetic, use with caution ! static VALUE rb_dfget_rtti_classname(VALUE self, VALUE vptr) { char *ptr = (char*)rb_num2ulong(vptr); #ifdef WIN32 char *rtti = *(char**)(ptr - 0x4); char *typeinfo = *(char**)(rtti + 0xC); // skip the .?AV, trim @@ from end return rb_str_new(typeinfo+0xc, strlen(typeinfo+0xc)-2); #else char *typeinfo = *(char**)(ptr - 0x4); char *typestring = *(char**)(typeinfo + 0x4); while (*typestring >= '0' && *typestring <= '9') typestring++; return rb_str_new2(typestring); #endif } static VALUE rb_dfget_vtable_ptr(VALUE self, VALUE objptr) { // actually, rb_dfmemory_read_int32 return rb_uint2inum(*(uint32_t*)rb_num2ulong(objptr)); } // raw memory access // used by the ruby class definitions // XXX may cause game crash ! double-check your addresses ! static VALUE rb_dfmalloc(VALUE self, VALUE len) { char *ptr = (char*)malloc(FIX2INT(len)); if (!ptr) rb_raise(*rb_eRuntimeError, "no memory"); memset(ptr, 0, FIX2INT(len)); return rb_uint2inum((long)ptr); } static VALUE rb_dffree(VALUE self, VALUE ptr) { free((void*)rb_num2ulong(ptr)); return Qtrue; } // memory reading (buffer) static VALUE rb_dfmemory_read(VALUE self, VALUE addr, VALUE len) { return rb_str_new((char*)rb_num2ulong(addr), rb_num2ulong(len)); } // memory reading (integers/floats) static VALUE rb_dfmemory_read_int8(VALUE self, VALUE addr) { return rb_int2inum(*(char*)rb_num2ulong(addr)); } static VALUE rb_dfmemory_read_int16(VALUE self, VALUE addr) { return rb_int2inum(*(short*)rb_num2ulong(addr)); } static VALUE rb_dfmemory_read_int32(VALUE self, VALUE addr) { return rb_int2inum(*(int*)rb_num2ulong(addr)); } static VALUE rb_dfmemory_read_float(VALUE self, VALUE addr) { return rb_float_new(*(float*)rb_num2ulong(addr)); } // memory writing (buffer) static VALUE rb_dfmemory_write(VALUE self, VALUE addr, VALUE raw) { // no stable api for raw.length between rb1.8/rb1.9 ... int strlen = FIX2INT(rb_funcall(raw, rb_intern("length"), 0)); memcpy((void*)rb_num2ulong(addr), rb_string_value_ptr(&raw), strlen); return Qtrue; } // memory writing (integers/floats) static VALUE rb_dfmemory_write_int8(VALUE self, VALUE addr, VALUE val) { *(char*)rb_num2ulong(addr) = rb_num2ulong(val); return Qtrue; } static VALUE rb_dfmemory_write_int16(VALUE self, VALUE addr, VALUE val) { *(short*)rb_num2ulong(addr) = rb_num2ulong(val); return Qtrue; } static VALUE rb_dfmemory_write_int32(VALUE self, VALUE addr, VALUE val) { *(int*)rb_num2ulong(addr) = rb_num2ulong(val); return Qtrue; } static VALUE rb_dfmemory_write_float(VALUE self, VALUE addr, VALUE val) { *(float*)rb_num2ulong(addr) = rb_num2dbl(val); return Qtrue; } // stl::string static VALUE rb_dfmemory_stlstring_init(VALUE self, VALUE addr) { // XXX THIS IS TERRIBLE std::string *ptr = new std::string; memcpy((void*)rb_num2ulong(addr), (void*)ptr, sizeof(*ptr)); return Qtrue; } static VALUE rb_dfmemory_read_stlstring(VALUE self, VALUE addr) { std::string *s = (std::string*)rb_num2ulong(addr); return rb_str_new(s->c_str(), s->length()); } static VALUE rb_dfmemory_write_stlstring(VALUE self, VALUE addr, VALUE val) { std::string *s = (std::string*)rb_num2ulong(addr); int strlen = FIX2INT(rb_funcall(val, rb_intern("length"), 0)); s->assign(rb_string_value_ptr(&val), strlen); return Qtrue; } // vector access static VALUE rb_dfmemory_vec_init(VALUE self, VALUE addr) { std::vector *ptr = new std::vector; memcpy((void*)rb_num2ulong(addr), (void*)ptr, sizeof(*ptr)); return Qtrue; } // vector static VALUE rb_dfmemory_vec8_length(VALUE self, VALUE addr) { std::vector *v = (std::vector*)rb_num2ulong(addr); return rb_uint2inum(v->size()); } static VALUE rb_dfmemory_vec8_ptrat(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx))); } static VALUE rb_dfmemory_vec8_insert(VALUE self, VALUE addr, VALUE idx, VALUE val) { std::vector *v = (std::vector*)rb_num2ulong(addr); v->insert(v->begin()+FIX2INT(idx), rb_num2ulong(val)); return Qtrue; } static VALUE rb_dfmemory_vec8_delete(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); v->erase(v->begin()+FIX2INT(idx)); return Qtrue; } // vector static VALUE rb_dfmemory_vec16_length(VALUE self, VALUE addr) { std::vector *v = (std::vector*)rb_num2ulong(addr); return rb_uint2inum(v->size()); } static VALUE rb_dfmemory_vec16_ptrat(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx))); } static VALUE rb_dfmemory_vec16_insert(VALUE self, VALUE addr, VALUE idx, VALUE val) { std::vector *v = (std::vector*)rb_num2ulong(addr); v->insert(v->begin()+FIX2INT(idx), rb_num2ulong(val)); return Qtrue; } static VALUE rb_dfmemory_vec16_delete(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); v->erase(v->begin()+FIX2INT(idx)); return Qtrue; } // vector static VALUE rb_dfmemory_vec32_length(VALUE self, VALUE addr) { std::vector *v = (std::vector*)rb_num2ulong(addr); return rb_uint2inum(v->size()); } static VALUE rb_dfmemory_vec32_ptrat(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx))); } static VALUE rb_dfmemory_vec32_insert(VALUE self, VALUE addr, VALUE idx, VALUE val) { std::vector *v = (std::vector*)rb_num2ulong(addr); v->insert(v->begin()+FIX2INT(idx), rb_num2ulong(val)); return Qtrue; } static VALUE rb_dfmemory_vec32_delete(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); v->erase(v->begin()+FIX2INT(idx)); return Qtrue; } // vector static VALUE rb_dfmemory_vecbool_length(VALUE self, VALUE addr) { std::vector *v = (std::vector*)rb_num2ulong(addr); return rb_uint2inum(v->size()); } static VALUE rb_dfmemory_vecbool_at(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); return v->at(FIX2INT(idx)) ? Qtrue : Qfalse; } static VALUE rb_dfmemory_vecbool_setat(VALUE self, VALUE addr, VALUE idx, VALUE val) { std::vector *v = (std::vector*)rb_num2ulong(addr); v->at(FIX2INT(idx)) = (BOOL_ISFALSE(val) ? 0 : 1); return Qtrue; } static VALUE rb_dfmemory_vecbool_insert(VALUE self, VALUE addr, VALUE idx, VALUE val) { std::vector *v = (std::vector*)rb_num2ulong(addr); v->insert(v->begin()+FIX2INT(idx), (BOOL_ISFALSE(val) ? 0 : 1)); return Qtrue; } static VALUE rb_dfmemory_vecbool_delete(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); v->erase(v->begin()+FIX2INT(idx)); return Qtrue; } // BitArray static VALUE rb_dfmemory_bitarray_length(VALUE self, VALUE addr) { DFHack::BitArray *b = (DFHack::BitArray*)rb_num2ulong(addr); return rb_uint2inum(b->size*8); // b->size is in bytes } static VALUE rb_dfmemory_bitarray_resize(VALUE self, VALUE addr, VALUE sz) { DFHack::BitArray *b = (DFHack::BitArray*)rb_num2ulong(addr); b->resize(rb_num2ulong(sz)); return Qtrue; } static VALUE rb_dfmemory_bitarray_isset(VALUE self, VALUE addr, VALUE idx) { DFHack::BitArray *b = (DFHack::BitArray*)rb_num2ulong(addr); return b->is_set(rb_num2ulong(idx)) ? Qtrue : Qfalse; } static VALUE rb_dfmemory_bitarray_set(VALUE self, VALUE addr, VALUE idx, VALUE val) { DFHack::BitArray *b = (DFHack::BitArray*)rb_num2ulong(addr); b->set(rb_num2ulong(idx), (BOOL_ISFALSE(val) ? 0 : 1)); return Qtrue; } /* call an arbitrary object virtual method */ static VALUE rb_dfvcall(VALUE self, VALUE cppobj, VALUE cppvoff, VALUE a0, VALUE a1, VALUE a2, VALUE a3) { #ifdef WIN32 int (__fastcall *fptr)(char **me, int dummy_edx, int, int, int, int); #else int (*fptr)(char **me, int, int, int, int); #endif char **that = (char**)rb_num2ulong(cppobj); int ret; fptr = (decltype(fptr))*(void**)(*that + rb_num2ulong(cppvoff)); ret = fptr(that, #ifdef WIN32 0, #endif rb_num2ulong(a0), rb_num2ulong(a1), rb_num2ulong(a2), rb_num2ulong(a3)); return rb_int2inum(ret); } // define module DFHack and its methods static void ruby_bind_dfhack(void) { rb_cDFHack = rb_define_module("DFHack"); // global DFHack commands rb_define_singleton_method(rb_cDFHack, "onupdate_active", RUBY_METHOD_FUNC(rb_dfonupdateactive), 0); rb_define_singleton_method(rb_cDFHack, "onupdate_active=", RUBY_METHOD_FUNC(rb_dfonupdateactiveset), 1); rb_define_singleton_method(rb_cDFHack, "resume", RUBY_METHOD_FUNC(rb_dfresume), 0); rb_define_singleton_method(rb_cDFHack, "do_suspend", RUBY_METHOD_FUNC(rb_dfsuspend), 0); rb_define_singleton_method(rb_cDFHack, "get_global_address", RUBY_METHOD_FUNC(rb_dfget_global_address), 1); rb_define_singleton_method(rb_cDFHack, "get_vtable", RUBY_METHOD_FUNC(rb_dfget_vtable), 1); rb_define_singleton_method(rb_cDFHack, "get_rtti_classname", RUBY_METHOD_FUNC(rb_dfget_rtti_classname), 1); rb_define_singleton_method(rb_cDFHack, "get_vtable_ptr", RUBY_METHOD_FUNC(rb_dfget_vtable_ptr), 1); rb_define_singleton_method(rb_cDFHack, "register_dfcommand", RUBY_METHOD_FUNC(rb_dfregister), 2); rb_define_singleton_method(rb_cDFHack, "print_str", RUBY_METHOD_FUNC(rb_dfprint_str), 1); rb_define_singleton_method(rb_cDFHack, "print_err", RUBY_METHOD_FUNC(rb_dfprint_err), 1); rb_define_singleton_method(rb_cDFHack, "malloc", RUBY_METHOD_FUNC(rb_dfmalloc), 1); rb_define_singleton_method(rb_cDFHack, "free", RUBY_METHOD_FUNC(rb_dffree), 1); rb_define_singleton_method(rb_cDFHack, "vmethod_do_call", RUBY_METHOD_FUNC(rb_dfvcall), 6); rb_define_const(rb_cDFHack, "REBASE_DELTA", rb_dfrebase_delta()); rb_define_singleton_method(rb_cDFHack, "memory_read", RUBY_METHOD_FUNC(rb_dfmemory_read), 2); rb_define_singleton_method(rb_cDFHack, "memory_read_int8", RUBY_METHOD_FUNC(rb_dfmemory_read_int8), 1); rb_define_singleton_method(rb_cDFHack, "memory_read_int16", RUBY_METHOD_FUNC(rb_dfmemory_read_int16), 1); rb_define_singleton_method(rb_cDFHack, "memory_read_int32", RUBY_METHOD_FUNC(rb_dfmemory_read_int32), 1); rb_define_singleton_method(rb_cDFHack, "memory_read_float", RUBY_METHOD_FUNC(rb_dfmemory_read_float), 1); rb_define_singleton_method(rb_cDFHack, "memory_write", RUBY_METHOD_FUNC(rb_dfmemory_write), 2); rb_define_singleton_method(rb_cDFHack, "memory_write_int8", RUBY_METHOD_FUNC(rb_dfmemory_write_int8), 2); rb_define_singleton_method(rb_cDFHack, "memory_write_int16", RUBY_METHOD_FUNC(rb_dfmemory_write_int16), 2); rb_define_singleton_method(rb_cDFHack, "memory_write_int32", RUBY_METHOD_FUNC(rb_dfmemory_write_int32), 2); rb_define_singleton_method(rb_cDFHack, "memory_write_float", RUBY_METHOD_FUNC(rb_dfmemory_write_float), 2); rb_define_singleton_method(rb_cDFHack, "memory_stlstring_init", RUBY_METHOD_FUNC(rb_dfmemory_stlstring_init), 1); rb_define_singleton_method(rb_cDFHack, "memory_read_stlstring", RUBY_METHOD_FUNC(rb_dfmemory_read_stlstring), 1); rb_define_singleton_method(rb_cDFHack, "memory_write_stlstring", RUBY_METHOD_FUNC(rb_dfmemory_write_stlstring), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector_init", RUBY_METHOD_FUNC(rb_dfmemory_vec_init), 1); rb_define_singleton_method(rb_cDFHack, "memory_vector8_length", RUBY_METHOD_FUNC(rb_dfmemory_vec8_length), 1); rb_define_singleton_method(rb_cDFHack, "memory_vector8_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec8_ptrat), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector8_insert", RUBY_METHOD_FUNC(rb_dfmemory_vec8_insert), 3); rb_define_singleton_method(rb_cDFHack, "memory_vector8_delete", RUBY_METHOD_FUNC(rb_dfmemory_vec8_delete), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector16_length", RUBY_METHOD_FUNC(rb_dfmemory_vec16_length), 1); rb_define_singleton_method(rb_cDFHack, "memory_vector16_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec16_ptrat), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector16_insert", RUBY_METHOD_FUNC(rb_dfmemory_vec16_insert), 3); rb_define_singleton_method(rb_cDFHack, "memory_vector16_delete", RUBY_METHOD_FUNC(rb_dfmemory_vec16_delete), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector32_length", RUBY_METHOD_FUNC(rb_dfmemory_vec32_length), 1); rb_define_singleton_method(rb_cDFHack, "memory_vector32_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec32_ptrat), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector32_insert", RUBY_METHOD_FUNC(rb_dfmemory_vec32_insert), 3); rb_define_singleton_method(rb_cDFHack, "memory_vector32_delete", RUBY_METHOD_FUNC(rb_dfmemory_vec32_delete), 2); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_length", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_length), 1); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_at", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_at), 2); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_setat", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_setat), 3); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_insert", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_insert), 3); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_delete", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_delete), 2); rb_define_singleton_method(rb_cDFHack, "memory_bitarray_length", RUBY_METHOD_FUNC(rb_dfmemory_bitarray_length), 1); rb_define_singleton_method(rb_cDFHack, "memory_bitarray_resize", RUBY_METHOD_FUNC(rb_dfmemory_bitarray_resize), 2); rb_define_singleton_method(rb_cDFHack, "memory_bitarray_isset", RUBY_METHOD_FUNC(rb_dfmemory_bitarray_isset), 2); rb_define_singleton_method(rb_cDFHack, "memory_bitarray_set", RUBY_METHOD_FUNC(rb_dfmemory_bitarray_set), 3); // load the default ruby-level definitions int state=0; // windows cmake installs files in df/, linux installs files in df/hack/ rb_eval_string_protect("File.exist?('hack/ruby.rb') ? load('hack/ruby.rb') : load('ruby.rb')", &state); if (state) dump_rb_error(); }