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