ruby: compiles
							parent
							
								
									109edc5e77
								
							
						
					
					
						commit
						b2846492f4
					
				| @ -0,0 +1,7 @@ | ||||
| find_package(Ruby) | ||||
| if(RUBY_FOUND) | ||||
|     include_directories("${dfhack_SOURCE_DIR}/depends/tthread" ${RUBY_INCLUDE_PATH}) | ||||
|     DFHACK_PLUGIN(ruby ruby.cpp LINK_LIBRARIES dfhack-tinythread) | ||||
| else(RUBY_FOUND) | ||||
|     MESSAGE(STATUS "Required library (ruby) not found - ruby plugin can't be built.") | ||||
| endif(RUBY_FOUND) | ||||
| @ -0,0 +1,609 @@ | ||||
| // blindly copied imports from fastdwarf
 | ||||
| #include "Core.h" | ||||
| #include "Console.h" | ||||
| #include "Export.h" | ||||
| #include "PluginManager.h" | ||||
| 
 | ||||
| #include "DataDefs.h" | ||||
| #include "df/world.h" | ||||
| #include "df/unit.h" | ||||
| 
 | ||||
| #include "tinythread.h" | ||||
| 
 | ||||
| #include <ruby.h> | ||||
| 
 | ||||
| using std::string; | ||||
| using std::vector; | ||||
| using namespace DFHack; | ||||
| 
 | ||||
| 
 | ||||
| static void df_rubythread(void*); | ||||
| static command_result df_rubyload(color_ostream &out, vector <string> & parameters); | ||||
| static command_result df_rubyeval(color_ostream &out, vector <string> & parameters); | ||||
| static void ruby_bind_dfhack(void); | ||||
| 
 | ||||
| // inter-thread communication stuff
 | ||||
| enum RB_command { | ||||
|     RB_IDLE, | ||||
|     RB_INIT, | ||||
|     RB_DIE, | ||||
|     RB_LOAD, | ||||
|     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 interface
 | ||||
| DFHACK_PLUGIN("ruby") | ||||
| 
 | ||||
| DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) | ||||
| { | ||||
|     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)); | ||||
| 
 | ||||
|     commands.push_back(PluginCommand("r", | ||||
|                 "Ruby interpreter dev. Eval() a ruby string.", | ||||
|                 df_rubyeval)); | ||||
| 
 | ||||
|     return CR_OK; | ||||
| } | ||||
| 
 | ||||
| DFhackCExport command_result plugin_shutdown ( color_ostream &out ) | ||||
| { | ||||
|     m_mutex->lock(); | ||||
|     if (!r_thread) | ||||
|         return CR_OK; | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|     return CR_OK; | ||||
| } | ||||
| 
 | ||||
| DFhackCExport command_result plugin_onupdate ( color_ostream &out ) | ||||
| { | ||||
|     if (!onupdate_active) | ||||
|         return CR_OK; | ||||
| 
 | ||||
|     command_result ret; | ||||
| 
 | ||||
|     m_mutex->lock(); | ||||
|     if (!r_thread) | ||||
|         return CR_OK; | ||||
| 
 | ||||
|     r_type = RB_EVAL; | ||||
|     r_command = "DFHack.onupdate"; | ||||
|     m_irun->unlock(); | ||||
| 
 | ||||
|     while (r_type != RB_IDLE) | ||||
|         tthread::this_thread::yield(); | ||||
| 
 | ||||
|     ret = r_result; | ||||
| 
 | ||||
|     m_irun->lock(); | ||||
|     m_mutex->unlock(); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static command_result df_rubyload(color_ostream &out, vector <string> & parameters) | ||||
| { | ||||
|     command_result ret; | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     // serialize 'accesses' to the ruby thread
 | ||||
|     m_mutex->lock(); | ||||
|     if (!r_thread) | ||||
|         // raced with plugin_shutdown ?
 | ||||
|         return CR_OK; | ||||
| 
 | ||||
|     r_type = RB_LOAD; | ||||
|     r_command = parameters[0].c_str(); | ||||
|     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 df_rubyeval(color_ostream &out, vector <string> & 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 = ""; | ||||
|     full += "DFHack.puts(("; | ||||
| 
 | ||||
|     for (unsigned i=0 ; i<parameters.size() ; ++i) { | ||||
|         full += parameters[i]; | ||||
|         full += " "; | ||||
|     } | ||||
| 
 | ||||
|     full += ").inspect)"; | ||||
| 
 | ||||
|     m_mutex->lock(); | ||||
|     if (!r_thread) | ||||
|         return CR_OK; | ||||
| 
 | ||||
|     r_type = RB_EVAL; | ||||
|     r_command = full.c_str(); | ||||
|     m_irun->unlock(); | ||||
| 
 | ||||
|     while (r_type != RB_IDLE) | ||||
|         tthread::this_thread::yield(); | ||||
| 
 | ||||
|     ret = r_result; | ||||
| 
 | ||||
|     m_irun->lock(); | ||||
|     m_mutex->unlock(); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // 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)); | ||||
| } | ||||
| 
 | ||||
| // ruby thread main loop
 | ||||
| static void df_rubythread(void *p) | ||||
| { | ||||
|     int state, running; | ||||
| 
 | ||||
|     // 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(); | ||||
| 
 | ||||
|     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_LOAD: | ||||
|             state = 0; | ||||
|             rb_load_protect(rb_str_new2(r_command), Qfalse, &state); | ||||
|             if (state) | ||||
|                 dump_rb_error(); | ||||
|             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(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // ruby classes
 | ||||
| static VALUE rb_cDFHack; | ||||
| static VALUE rb_c_WrapData; | ||||
| 
 | ||||
| 
 | ||||
| // 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 = (val == Qtrue || val == INT2FIX(1)) ? 1 : 0; | ||||
|     return Qtrue; | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_dfresume(VALUE self) | ||||
| { | ||||
|     Core::getInstance().Resume(); | ||||
|     return Qtrue; | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_dfsuspend(VALUE self) | ||||
| { | ||||
|     Core::getInstance().Suspend(); | ||||
|     return Qtrue; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| static VALUE rb_dfgetversion(VALUE self) | ||||
| { | ||||
|     return rb_str_new2(getcore().vinfo->getVersion().c_str()); | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| // TODO color_ostream proxy yadda yadda
 | ||||
| static VALUE rb_dfprint_str(VALUE self, VALUE s) | ||||
| { | ||||
|     //getcore().con.print("%s", rb_string_value_ptr(&s));
 | ||||
|     Core::printerr("%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; | ||||
| } | ||||
| 
 | ||||
| // raw memory access
 | ||||
| // WARNING: may cause game crash ! double-check your addresses !
 | ||||
| static VALUE rb_dfmemread(VALUE self, VALUE addr, VALUE len) | ||||
| { | ||||
|     return rb_str_new((char*)rb_num2ulong(addr), rb_num2ulong(len)); | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_dfmemwrite(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; | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_dfmalloc(VALUE self, VALUE len) | ||||
| { | ||||
|     return rb_uint2inum((long)malloc(FIX2INT(len))); | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_dffree(VALUE self, VALUE ptr) | ||||
| { | ||||
|     free((void*)rb_num2ulong(ptr)); | ||||
|     return Qtrue; | ||||
| } | ||||
| 
 | ||||
| // raw c++ wrappers
 | ||||
| // return the nth element of a vector
 | ||||
| static VALUE rb_dfvectorat(VALUE self, VALUE vect_addr, VALUE idx) | ||||
| { | ||||
|     vector<uint32_t> *v = (vector<uint32_t>*)rb_num2ulong(vect_addr); | ||||
|     return rb_uint2inum(v->at(FIX2INT(idx))); | ||||
| } | ||||
| 
 | ||||
| // return a c++ string as a ruby string (nul-terminated)
 | ||||
| static VALUE rb_dfreadstring(VALUE self, VALUE str_addr) | ||||
| { | ||||
|     string *s = (string*)rb_num2ulong(str_addr); | ||||
|     return rb_str_new2(s->c_str()); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* XXX 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 the address of the struct in DF memory (for raw memread/write)
 | ||||
| static VALUE rb_memaddr(VALUE self) | ||||
| { | ||||
|     void *data; | ||||
|     Data_Get_Struct(self, void, data); | ||||
| 
 | ||||
|     return rb_uint2inum((uint32_t)data); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // BEGIN GENERATED SECTION
 | ||||
| 
 | ||||
| // begin generated T_cursor binding
 | ||||
| static VALUE rb_c_T_cursor; | ||||
| 
 | ||||
| static VALUE rb_m_T_cursor_x(VALUE self) { | ||||
|     struct df::global::T_cursor *var; | ||||
|     Data_Get_Struct(self, struct df::global::T_cursor, var); | ||||
|     return rb_uint2inum(var->x); | ||||
| } | ||||
| static VALUE rb_m_T_cursor_x_set(VALUE self, VALUE val) { | ||||
|     struct df::global::T_cursor *var; | ||||
|     Data_Get_Struct(self, struct df::global::T_cursor, var); | ||||
|     var->x = rb_num2ulong(val); | ||||
|     return Qtrue; | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_m_T_cursor_y(VALUE self) { | ||||
|     struct df::global::T_cursor *var; | ||||
|     Data_Get_Struct(self, struct df::global::T_cursor, var); | ||||
|     return rb_uint2inum(var->y); | ||||
| } | ||||
| static VALUE rb_m_T_cursor_y_set(VALUE self, VALUE val) { | ||||
|     struct df::global::T_cursor *var; | ||||
|     Data_Get_Struct(self, struct df::global::T_cursor, var); | ||||
|     var->y = rb_num2ulong(val); | ||||
|     return Qtrue; | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_m_T_cursor_z(VALUE self) { | ||||
|     struct df::global::T_cursor *var; | ||||
|     Data_Get_Struct(self, struct df::global::T_cursor, var); | ||||
|     return rb_uint2inum(var->z); | ||||
| } | ||||
| static VALUE rb_m_T_cursor_z_set(VALUE self, VALUE val) { | ||||
|     struct df::global::T_cursor *var; | ||||
|     Data_Get_Struct(self, struct df::global::T_cursor, var); | ||||
|     var->z = rb_num2ulong(val); | ||||
|     return Qtrue; | ||||
| } | ||||
| 
 | ||||
| // link methods to the class
 | ||||
| static void ruby_bind_T_cursor(void) { | ||||
|     // create a class, child of WrapData, in module DFHack
 | ||||
|     rb_c_T_cursor = rb_define_class_under(rb_cDFHack, "T_cursor", rb_c_WrapData); | ||||
| 
 | ||||
|     // reader for 'x' (0 = no arg)
 | ||||
|     rb_define_method(rb_c_T_cursor, "x",  RUBY_METHOD_FUNC(rb_m_T_cursor_x), 0); | ||||
|     // writer for 'x' (1 arg)
 | ||||
|     rb_define_method(rb_c_T_cursor, "x=", RUBY_METHOD_FUNC(rb_m_T_cursor_x_set), 1); | ||||
|     rb_define_method(rb_c_T_cursor, "y",  RUBY_METHOD_FUNC(rb_m_T_cursor_y), 0); | ||||
|     rb_define_method(rb_c_T_cursor, "y=", RUBY_METHOD_FUNC(rb_m_T_cursor_y_set), 1); | ||||
|     rb_define_method(rb_c_T_cursor, "z",  RUBY_METHOD_FUNC(rb_m_T_cursor_z), 0); | ||||
|     rb_define_method(rb_c_T_cursor, "z=", RUBY_METHOD_FUNC(rb_m_T_cursor_z_set), 1); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // create an instance of T_cursor from global::cursor
 | ||||
| // this method is linked to DFHack.cursor in ruby_bind_dfhack()
 | ||||
| static VALUE rb_global_cursor(VALUE self) { | ||||
|     return Data_Wrap_Struct(rb_c_T_cursor, 0, 0, df::global::cursor); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // begin generated unit binding
 | ||||
| static VALUE rb_c_unit; | ||||
| 
 | ||||
| static VALUE rb_m_unit_id(VALUE self) { | ||||
|     struct df::unit *var; | ||||
|     Data_Get_Struct(self, struct df::unit, var); | ||||
| 
 | ||||
|     return rb_uint2inum(var->id); | ||||
| } | ||||
| static VALUE rb_m_unit_id_set(VALUE self, VALUE val) { | ||||
|     struct df::unit *var; | ||||
|     Data_Get_Struct(self, struct df::unit, var); | ||||
|     var->id = rb_num2ulong(val); | ||||
|     return Qtrue; | ||||
| } | ||||
| 
 | ||||
| static void ruby_bind_unit(void) { | ||||
|     // ruby class name must begin with uppercase
 | ||||
|     rb_c_unit = rb_define_class_under(rb_cDFHack, "Unit", rb_c_WrapData); | ||||
| 
 | ||||
|     rb_define_method(rb_c_unit, "id",  RUBY_METHOD_FUNC(rb_m_unit_id), 0); | ||||
|     rb_define_method(rb_c_unit, "id=", RUBY_METHOD_FUNC(rb_m_unit_id_set), 1); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // begin generated world binding
 | ||||
| static VALUE rb_c_world; | ||||
| static VALUE rb_c_world_T_units; | ||||
| 
 | ||||
| static VALUE rb_m_world_T_units_all(VALUE self) { | ||||
|     struct df::world::T_units *var; | ||||
|     Data_Get_Struct(self, struct df::world::T_units, var); | ||||
| 
 | ||||
|     // read a vector
 | ||||
|     VALUE ret = rb_ary_new(); | ||||
|     for (unsigned i=0 ; i<var->all.size() ; ++i) | ||||
|         rb_ary_push(ret, Data_Wrap_Struct(rb_c_unit, 0, 0, var->all[i])); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_m_world_units(VALUE self) { | ||||
|     struct df::world *var; | ||||
|     Data_Get_Struct(self, struct df::world, var); | ||||
|     return Data_Wrap_Struct(rb_c_world_T_units, 0, 0, &var->units); | ||||
| } | ||||
| 
 | ||||
| static void ruby_bind_world(void) { | ||||
|     rb_c_world = rb_define_class_under(rb_cDFHack, "World", rb_c_WrapData); | ||||
|     rb_c_world_T_units = rb_define_class_under(rb_c_world, "T_units", rb_c_WrapData); | ||||
| 
 | ||||
|     rb_define_method(rb_c_world, "units", RUBY_METHOD_FUNC(rb_m_world_units), 0); | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_global_world(VALUE self) { | ||||
|     return Data_Wrap_Struct(rb_c_world, 0, 0, df::global::world); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| static VALUE rb_dfcreatures(VALUE self) | ||||
| { | ||||
|     OffsetGroup *ogc = getcore().vinfo->getGroup("Creatures"); | ||||
|     vector <df_creature*> *v = (vector<df_creature*>*)ogc->getAddress("vector"); | ||||
| 
 | ||||
|     VALUE ret = rb_ary_new(); | ||||
|     for (unsigned i=0 ; i<v->size() ; ++i) | ||||
|         rb_ary_push(ret, Data_Wrap_Struct(rb_cCreature, 0, 0, v->at(i))); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_getlaborname(VALUE self, VALUE idx) | ||||
| { | ||||
|     return rb_str_new2(getcore().vinfo->getLabor(FIX2INT(idx)).c_str()); | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_getskillname(VALUE self, VALUE idx) | ||||
| { | ||||
|     return rb_str_new2(getcore().vinfo->getSkill(FIX2INT(idx)).c_str()); | ||||
| } | ||||
| 
 | ||||
| static VALUE rb_mapblock(VALUE self, VALUE x, VALUE y, VALUE z) | ||||
| { | ||||
|     Maps *map; | ||||
|     Data_Get_Struct(self, Maps, map); | ||||
|     df_block *block; | ||||
| 
 | ||||
|     block = map->getBlock(FIX2INT(x)/16, FIX2INT(y)/16, FIX2INT(z)); | ||||
|     if (!block) | ||||
|         return Qnil; | ||||
| 
 | ||||
|     return Data_Wrap_Struct(rb_cMapBlock, 0, 0, block); | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // 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, "resume", RUBY_METHOD_FUNC(rb_dfresume), 0); | ||||
|     //rb_define_singleton_method(rb_cDFHack, "version", RUBY_METHOD_FUNC(rb_dfgetversion), 0);
 | ||||
|     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, "memread", RUBY_METHOD_FUNC(rb_dfmemread), 2); | ||||
|     rb_define_singleton_method(rb_cDFHack, "memwrite", RUBY_METHOD_FUNC(rb_dfmemwrite), 2); | ||||
|     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, "vectorat", RUBY_METHOD_FUNC(rb_dfvectorat), 2); | ||||
|     rb_define_singleton_method(rb_cDFHack, "readstring", RUBY_METHOD_FUNC(rb_dfreadstring), 1); | ||||
|     rb_define_singleton_method(rb_cDFHack, "register_dfcommand", RUBY_METHOD_FUNC(rb_dfregister), 2); | ||||
| 
 | ||||
|     // accessors for dfhack globals
 | ||||
|     rb_define_singleton_method(rb_cDFHack, "cursor", RUBY_METHOD_FUNC(rb_global_cursor), 0); | ||||
|     rb_define_singleton_method(rb_cDFHack, "world", RUBY_METHOD_FUNC(rb_global_world), 0); | ||||
| 
 | ||||
|     // parent class for all wrapped objects
 | ||||
|     rb_c_WrapData = rb_define_class_under(rb_cDFHack, "WrapData", rb_cObject); | ||||
|     rb_define_method(rb_c_WrapData, "memaddr", RUBY_METHOD_FUNC(rb_memaddr), 0); | ||||
| 
 | ||||
|     // call generated bindings
 | ||||
|     ruby_bind_T_cursor(); | ||||
|     ruby_bind_unit(); | ||||
|     ruby_bind_world(); | ||||
| 
 | ||||
|     // load the default ruby-level definitions
 | ||||
|     int state=0; | ||||
|     rb_load_protect(rb_str_new2("./hack/plugins/ruby.rb"), Qfalse, &state); | ||||
|     if (state) | ||||
|         dump_rb_error(); | ||||
| } | ||||
| @ -0,0 +1,44 @@ | ||||
| module DFHack | ||||
| 	def suspend | ||||
| 		if block_given? | ||||
| 			begin | ||||
| 				do_suspend | ||||
| 				yield | ||||
| 			ensure | ||||
| 				resume | ||||
| 			end | ||||
| 		else | ||||
| 			do_suspend | ||||
| 		end | ||||
| 	end | ||||
| 
 | ||||
| 	def puts(*a) | ||||
| 		a.flatten.each { |l| | ||||
| 			print_str(l.to_s.chomp + "\n") | ||||
| 		} | ||||
| 	end | ||||
| 
 | ||||
| 	def puts_err(*a) | ||||
| 		a.flatten.each { |l| | ||||
| 			print_err(l.to_s.chomp + "\n") | ||||
| 		} | ||||
| 	end | ||||
| 
 | ||||
| 	def test | ||||
| 		puts "starting" | ||||
| 
 | ||||
| 		suspend { | ||||
| 			c = cursor | ||||
| 			puts "cursor pos: #{c.x} #{c.y} #{c.z}" | ||||
| 
 | ||||
| 			puts "unit[0] id: #{world.units.all[0].id}" | ||||
| 		} | ||||
| 
 | ||||
| 		puts "done" | ||||
| 	end | ||||
| end | ||||
| 
 | ||||
| end | ||||
| 
 | ||||
| # load user-specified startup file | ||||
| load 'ruby_custom.rb' if File.exist?('ruby_custom.rb') | ||||
		Loading…
	
		Reference in New Issue