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());
@ -212,14 +212,14 @@ static std::string getLuaHelp(std::string path)
{
std::string help;
if (getline(script, help) &&
help.substr(0,3) == "-- ")
return help.substr(3);
help.substr(0,helpprefix.length()) == helpprefix)
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;
getdir(path, files);
@ -229,10 +229,16 @@ static std::map<string,string> listLuaScripts(std::string path)
{
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;
}
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;
}
@ -275,6 +281,18 @@ static command_result runLuaScript(color_ostream &out, std::string name, vector<
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)
{
if (!command.empty())
@ -348,10 +366,16 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
return CR_OK;
}
}
auto filename = getHackPath() + "scripts/" + parts[0] + ".lua";
if (fileExists(filename))
auto filename = getHackPath() + "scripts/" + parts[0];
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());
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.reset_color();
}
auto scripts = listLuaScripts(getHackPath() + "scripts/");
auto scripts = listScripts(plug_mgr, getHackPath() + "scripts/");
if (!scripts.empty())
{
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);
if(res == CR_NOT_IMPLEMENTED)
{
auto filename = getHackPath() + "scripts/" + first + ".lua";
if (fileExists(filename))
auto filename = getHackPath() + "scripts/" + first;
if (fileExists(filename + ".lua"))
res = runLuaScript(con, first, parts);
else if (plug_mgr->eval_ruby && fileExists(filename + ".rb"))
res = runRubyScript(plug_mgr, first, parts);
else
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_onstatechange = (command_result (*)(color_ostream &, state_change_event)) LookupPlugin(plug, "plugin_onstatechange");
plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect");
plugin_eval_ruby = (command_result (*)(const char*)) LookupPlugin(plug, "plugin_eval_ruby");
index_lua(plug);
this->name = *plug_name;
plugin_lib = plug;
@ -538,6 +539,7 @@ PluginManager::PluginManager(Core * core)
const string searchstr = ".plug.dll";
#endif
cmdlist_mutex = new mutex();
eval_ruby = NULL;
vector <string> filez;
getdir(path, filez);
for(size_t i = 0; i < filez.size();i++)
@ -620,6 +622,8 @@ void PluginManager::registerCommands( Plugin * p )
{
belongs[cmds[i].name] = p;
}
if (p->plugin_eval_ruby)
eval_ruby = p->plugin_eval_ruby;
cmdlist_mutex->unlock();
}
@ -632,5 +636,7 @@ void PluginManager::unregisterCommands( Plugin * p )
{
belongs.erase(cmds[i].name);
}
if (p->plugin_eval_ruby)
eval_ruby = NULL;
cmdlist_mutex->unlock();
}
}

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

@ -353,6 +353,7 @@ module DFHack
end
def empty? ; length == 0 ; 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
class StaticArray < MemStruct
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
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;
// serialize 'accesses' to the ruby thread
@ -123,11 +126,6 @@ static command_result plugin_eval_rb(const char *command)
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)
@ -136,7 +134,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
if (!onupdate_active)
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)
@ -157,7 +155,7 @@ DFhackCExport command_result plugin_onstatechange ( color_ostream &out, state_ch
#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)
@ -178,7 +176,7 @@ static command_result df_rubyeval(color_ostream &out, std::vector <std::string>
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}"