ruby: handle .rb files in df/hack/scripts/

develop
jj 2012-06-24 19:52:40 +02:00
parent 3f4d2e4792
commit 552da8417e
7 changed files with 90 additions and 22 deletions

@ -204,7 +204,7 @@ struct sortable
}; };
}; };
static std::string getLuaHelp(std::string path) static std::string getScriptHelp(std::string path, std::string helpprefix)
{ {
ifstream script(path.c_str()); ifstream script(path.c_str());
@ -212,14 +212,14 @@ static std::string getLuaHelp(std::string path)
{ {
std::string help; std::string help;
if (getline(script, help) && if (getline(script, help) &&
help.substr(0,3) == "-- ") help.substr(0,helpprefix.length()) == helpprefix)
return help.substr(3); return help.substr(helpprefix.length());
} }
return "Lua script."; return "No help available.";
} }
static std::map<string,string> listLuaScripts(std::string path) static std::map<string,string> listScripts(PluginManager *plug_mgr, std::string path)
{ {
std::vector<string> files; std::vector<string> files;
getdir(path, files); getdir(path, files);
@ -229,10 +229,16 @@ static std::map<string,string> listLuaScripts(std::string path)
{ {
if (hasEnding(files[i], ".lua")) if (hasEnding(files[i], ".lua"))
{ {
std::string help = getLuaHelp(path + files[i]); std::string help = getScriptHelp(path + files[i], "-- ");
pset[files[i].substr(0, files[i].size()-4)] = help; pset[files[i].substr(0, files[i].size()-4)] = help;
} }
else if (plug_mgr->eval_ruby && hasEnding(files[i], ".rb"))
{
std::string help = getScriptHelp(path + files[i], "# ");
pset[files[i].substr(0, files[i].size()-3)] = help;
}
} }
return pset; return pset;
} }
@ -275,6 +281,18 @@ static command_result runLuaScript(color_ostream &out, std::string name, vector<
return ok ? CR_OK : CR_FAILURE; return ok ? CR_OK : CR_FAILURE;
} }
static command_result runRubyScript(PluginManager *plug_mgr, std::string name, vector<string> &args)
{
std::string rbcmd = "$script_args = [";
for (size_t i = 0; i < args.size(); i++)
rbcmd += "'" + args[i] + "', ";
rbcmd += "]\n";
rbcmd += "load './hack/scripts/" + name + ".rb'";
return plug_mgr->eval_ruby(rbcmd.c_str());
}
command_result Core::runCommand(color_ostream &out, const std::string &command) command_result Core::runCommand(color_ostream &out, const std::string &command)
{ {
if (!command.empty()) if (!command.empty())
@ -348,10 +366,16 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
return CR_OK; return CR_OK;
} }
} }
auto filename = getHackPath() + "scripts/" + parts[0] + ".lua"; auto filename = getHackPath() + "scripts/" + parts[0];
if (fileExists(filename)) if (fileExists(filename + ".lua"))
{
string help = getScriptHelp(filename + ".lua", "-- ");
con.print("%s: %s\n", parts[0].c_str(), help.c_str());
return CR_OK;
}
if (plug_mgr->eval_ruby && fileExists(filename + ".rb"))
{ {
string help = getLuaHelp(filename); string help = getScriptHelp(filename + ".rb", "# ");
con.print("%s: %s\n", parts[0].c_str(), help.c_str()); con.print("%s: %s\n", parts[0].c_str(), help.c_str());
return CR_OK; return CR_OK;
} }
@ -499,7 +523,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
con.print(" %-22s- %s\n",(*iter).name.c_str(), (*iter).description.c_str()); con.print(" %-22s- %s\n",(*iter).name.c_str(), (*iter).description.c_str());
con.reset_color(); con.reset_color();
} }
auto scripts = listLuaScripts(getHackPath() + "scripts/"); auto scripts = listScripts(plug_mgr, getHackPath() + "scripts/");
if (!scripts.empty()) if (!scripts.empty())
{ {
con.print("\nscripts:\n"); con.print("\nscripts:\n");
@ -604,9 +628,11 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
command_result res = plug_mgr->InvokeCommand(con, first, parts); command_result res = plug_mgr->InvokeCommand(con, first, parts);
if(res == CR_NOT_IMPLEMENTED) if(res == CR_NOT_IMPLEMENTED)
{ {
auto filename = getHackPath() + "scripts/" + first + ".lua"; auto filename = getHackPath() + "scripts/" + first;
if (fileExists(filename)) if (fileExists(filename + ".lua"))
res = runLuaScript(con, first, parts); res = runLuaScript(con, first, parts);
else if (plug_mgr->eval_ruby && fileExists(filename + ".rb"))
res = runRubyScript(plug_mgr, first, parts);
else else
con.printerr("%s is not a recognized command.\n", first.c_str()); con.printerr("%s is not a recognized command.\n", first.c_str());
} }

@ -188,6 +188,7 @@ bool Plugin::load(color_ostream &con)
plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown"); plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown");
plugin_onstatechange = (command_result (*)(color_ostream &, state_change_event)) LookupPlugin(plug, "plugin_onstatechange"); plugin_onstatechange = (command_result (*)(color_ostream &, state_change_event)) LookupPlugin(plug, "plugin_onstatechange");
plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect"); plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect");
plugin_eval_ruby = (command_result (*)(const char*)) LookupPlugin(plug, "plugin_eval_ruby");
index_lua(plug); index_lua(plug);
this->name = *plug_name; this->name = *plug_name;
plugin_lib = plug; plugin_lib = plug;
@ -538,6 +539,7 @@ PluginManager::PluginManager(Core * core)
const string searchstr = ".plug.dll"; const string searchstr = ".plug.dll";
#endif #endif
cmdlist_mutex = new mutex(); cmdlist_mutex = new mutex();
eval_ruby = NULL;
vector <string> filez; vector <string> filez;
getdir(path, filez); getdir(path, filez);
for(size_t i = 0; i < filez.size();i++) for(size_t i = 0; i < filez.size();i++)
@ -620,6 +622,8 @@ void PluginManager::registerCommands( Plugin * p )
{ {
belongs[cmds[i].name] = p; belongs[cmds[i].name] = p;
} }
if (p->plugin_eval_ruby)
eval_ruby = p->plugin_eval_ruby;
cmdlist_mutex->unlock(); cmdlist_mutex->unlock();
} }
@ -632,5 +636,7 @@ void PluginManager::unregisterCommands( Plugin * p )
{ {
belongs.erase(cmds[i].name); belongs.erase(cmds[i].name);
} }
if (p->plugin_eval_ruby)
eval_ruby = NULL;
cmdlist_mutex->unlock(); cmdlist_mutex->unlock();
} }

@ -209,6 +209,7 @@ namespace DFHack
command_result (*plugin_onupdate)(color_ostream &); command_result (*plugin_onupdate)(color_ostream &);
command_result (*plugin_onstatechange)(color_ostream &, state_change_event); command_result (*plugin_onstatechange)(color_ostream &, state_change_event);
RPCService* (*plugin_rpcconnect)(color_ostream &); RPCService* (*plugin_rpcconnect)(color_ostream &);
command_result (*plugin_eval_ruby)(const char*);
}; };
class DFHACK_EXPORT PluginManager class DFHACK_EXPORT PluginManager
{ {
@ -237,6 +238,7 @@ namespace DFHack
{ {
return all_plugins.size(); return all_plugins.size();
} }
command_result (*eval_ruby)(const char*);
// DATA // DATA
private: private:
tthread::mutex * cmdlist_mutex; tthread::mutex * cmdlist_mutex;

@ -33,6 +33,20 @@ df/hack/ on linux), the library should be named 'libruby.dll' (.so on linux).
You can download a tested version at http://github.com/jjyg/dfhack/downloads/ You can download a tested version at http://github.com/jjyg/dfhack/downloads/
Ruby scripts
------------
The ruby plugin allows the creation of '.rb' scripts in df/hack/scripts/.
If you create such a script, e.g. 'test.rb', that will add a new dfhack console
command 'test'.
The script can access the console command arguments through the global variable
'$script_args', which is an array of ruby Strings.
The help string displayed in dfhack 'ls' command is the first line of the
script, if it is a comment (starts with '# ').
DFHack callbacks DFHack callbacks
---------------- ----------------

@ -353,6 +353,7 @@ module DFHack
end end
def empty? ; length == 0 ; end def empty? ; length == 0 ; end
def flatten ; map { |e| e.respond_to?(:flatten) ? e.flatten : e }.flatten ; end def flatten ; map { |e| e.respond_to?(:flatten) ? e.flatten : e }.flatten ; end
def index(elem=nil, &b) ; (0...length).find { |i| b ? b[self[i]] : self[i] == elem } ; end
end end
class StaticArray < MemStruct class StaticArray < MemStruct
attr_accessor :_tglen, :_length, :_indexenum, :_tg attr_accessor :_tglen, :_length, :_indexenum, :_tg

@ -96,8 +96,11 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
} }
// send a single ruby line to be evaluated by the ruby thread // send a single ruby line to be evaluated by the ruby thread
static command_result plugin_eval_rb(const char *command) DFhackCExport command_result plugin_eval_ruby(const char *command)
{ {
if (!r_thread)
return CR_FAILURE;
command_result ret; command_result ret;
// serialize 'accesses' to the ruby thread // serialize 'accesses' to the ruby thread
@ -123,11 +126,6 @@ static command_result plugin_eval_rb(const char *command)
return ret; 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 ) DFhackCExport command_result plugin_onupdate ( color_ostream &out )
{ {
if (!r_thread) if (!r_thread)
@ -136,7 +134,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
if (!onupdate_active) if (!onupdate_active)
return CR_OK; return CR_OK;
return plugin_eval_rb("DFHack.onupdate"); return plugin_eval_ruby("DFHack.onupdate");
} }
DFhackCExport command_result plugin_onstatechange ( color_ostream &out, state_change_event e) DFhackCExport command_result plugin_onstatechange ( color_ostream &out, state_change_event e)
@ -157,7 +155,7 @@ DFhackCExport command_result plugin_onstatechange ( color_ostream &out, state_ch
#undef SCASE #undef SCASE
} }
return plugin_eval_rb(cmd); return plugin_eval_ruby(cmd.c_str());
} }
static command_result df_rubyeval(color_ostream &out, std::vector <std::string> & parameters) static command_result df_rubyeval(color_ostream &out, std::vector <std::string> & parameters)
@ -178,7 +176,7 @@ static command_result df_rubyeval(color_ostream &out, std::vector <std::string>
full += " "; full += " ";
} }
return plugin_eval_rb(full); return plugin_eval_ruby(full.c_str());
} }

@ -0,0 +1,21 @@
# slay all creatures of a given race (default = goblins)
race = $script_args[0] || 'GOBLIN'
all_races = df.world.raws.creatures.all.map { |cr| cr.creature_id }
raw_race = df.match_rawname(race, all_races)
raise 'invalid race' if not raw_race
race_nr = df.world.raws.creatures.all.index { |cr| cr.creature_id == raw_race }
count = 0
df.suspend {
df.world.units.active.each { |u|
if u.race == race_nr and u.body.blood_count != 0
u.body.blood_count = 0
count += 1
end
}
}
puts "slain #{count} #{raw_race}"