|
|
|
@ -35,7 +35,6 @@ distribution.
|
|
|
|
|
#include <forward_list>
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
#include <cstdarg>
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
#include "Error.h"
|
|
|
|
|
#include "MemAccess.h"
|
|
|
|
@ -61,8 +60,6 @@ using namespace std;
|
|
|
|
|
#include "LuaTools.h"
|
|
|
|
|
#include "DFHackVersion.h"
|
|
|
|
|
|
|
|
|
|
#include "MiscUtils.h"
|
|
|
|
|
|
|
|
|
|
using namespace DFHack;
|
|
|
|
|
|
|
|
|
|
#include "df/plotinfost.h"
|
|
|
|
@ -99,7 +96,7 @@ using df::global::world;
|
|
|
|
|
// FIXME: A lot of code in one file, all doing different things... there's something fishy about it.
|
|
|
|
|
|
|
|
|
|
static bool parseKeySpec(std::string keyspec, int *psym, int *pmod, std::string *pfocus = NULL);
|
|
|
|
|
size_t loadScriptFiles(Core* core, color_ostream& out, const vector<std::string>& prefix, const std::string& folder);
|
|
|
|
|
size_t loadScriptFiles(Core* core, color_ostream& out, const std::vector<std::string>& prefix, const std::string& folder);
|
|
|
|
|
|
|
|
|
|
namespace DFHack {
|
|
|
|
|
|
|
|
|
@ -160,9 +157,9 @@ struct CommandDepthCounter
|
|
|
|
|
};
|
|
|
|
|
thread_local int CommandDepthCounter::depth = 0;
|
|
|
|
|
|
|
|
|
|
void Core::cheap_tokenise(string const& input, vector<string> &output)
|
|
|
|
|
void Core::cheap_tokenise(std::string const& input, std::vector<std::string>& output)
|
|
|
|
|
{
|
|
|
|
|
string *cur = NULL;
|
|
|
|
|
std::string *cur = NULL;
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
|
|
// Check the first non-space character
|
|
|
|
@ -234,7 +231,7 @@ void fHKthread(void * iodata)
|
|
|
|
|
PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr;
|
|
|
|
|
if(plug_mgr == 0 || core == 0)
|
|
|
|
|
{
|
|
|
|
|
cerr << "Hotkey thread has croaked." << endl;
|
|
|
|
|
std::cerr << "Hotkey thread has croaked." << std::endl;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
bool keep_going = true;
|
|
|
|
@ -256,10 +253,10 @@ void fHKthread(void * iodata)
|
|
|
|
|
struct sortable
|
|
|
|
|
{
|
|
|
|
|
bool recolor;
|
|
|
|
|
string name;
|
|
|
|
|
string description;
|
|
|
|
|
std::string name;
|
|
|
|
|
std::string description;
|
|
|
|
|
//FIXME: Nuke when MSVC stops failing at being C++11 compliant
|
|
|
|
|
sortable(bool recolor_,const string& name_,const string & description_): recolor(recolor_), name(name_), description(description_){};
|
|
|
|
|
sortable(bool recolor_,const std::string& name_,const std::string & description_): recolor(recolor_), name(name_), description(description_){};
|
|
|
|
|
bool operator <(const sortable & rhs) const
|
|
|
|
|
{
|
|
|
|
|
if( name < rhs.name )
|
|
|
|
@ -268,9 +265,9 @@ struct sortable
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static string dfhack_version_desc()
|
|
|
|
|
static std::string dfhack_version_desc()
|
|
|
|
|
{
|
|
|
|
|
stringstream s;
|
|
|
|
|
std::stringstream s;
|
|
|
|
|
s << Version::dfhack_version() << " ";
|
|
|
|
|
if (Version::is_release())
|
|
|
|
|
s << "(release)";
|
|
|
|
@ -284,11 +281,11 @@ static string dfhack_version_desc()
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
struct ScriptArgs {
|
|
|
|
|
const string *pcmd;
|
|
|
|
|
vector<string> *pargs;
|
|
|
|
|
const std::string *pcmd;
|
|
|
|
|
std::vector<std::string> *pargs;
|
|
|
|
|
};
|
|
|
|
|
struct ScriptEnableState {
|
|
|
|
|
const string *pcmd;
|
|
|
|
|
const std::string *pcmd;
|
|
|
|
|
bool pstate;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
@ -307,7 +304,7 @@ static bool init_run_script(color_ostream &out, lua_State *state, void *info)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static command_result runLuaScript(color_ostream &out, std::string name, vector<string> &args)
|
|
|
|
|
static command_result runLuaScript(color_ostream &out, std::string name, std::vector<std::string> &args)
|
|
|
|
|
{
|
|
|
|
|
ScriptArgs data;
|
|
|
|
|
data.pcmd = &name;
|
|
|
|
@ -346,25 +343,25 @@ command_result Core::runCommand(color_ostream &out, const std::string &command)
|
|
|
|
|
{
|
|
|
|
|
if (!command.empty())
|
|
|
|
|
{
|
|
|
|
|
vector <string> parts;
|
|
|
|
|
std::vector <std::string> parts;
|
|
|
|
|
Core::cheap_tokenise(command,parts);
|
|
|
|
|
if(parts.size() == 0)
|
|
|
|
|
return CR_NOT_IMPLEMENTED;
|
|
|
|
|
|
|
|
|
|
string first = parts[0];
|
|
|
|
|
std::string first = parts[0];
|
|
|
|
|
parts.erase(parts.begin());
|
|
|
|
|
|
|
|
|
|
if (first[0] == '#')
|
|
|
|
|
return CR_OK;
|
|
|
|
|
|
|
|
|
|
cerr << "Invoking: " << command << endl;
|
|
|
|
|
std::cerr << "Invoking: " << command << std::endl;
|
|
|
|
|
return runCommand(out, first, parts);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return CR_NOT_IMPLEMENTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool is_builtin(color_ostream &con, const string &command) {
|
|
|
|
|
bool is_builtin(color_ostream &con, const std::string &command) {
|
|
|
|
|
CoreSuspender suspend;
|
|
|
|
|
auto L = Lua::Core::State;
|
|
|
|
|
Lua::StackUnwinder top(L);
|
|
|
|
@ -385,7 +382,7 @@ bool is_builtin(color_ostream &con, const string &command) {
|
|
|
|
|
return lua_toboolean(L, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void get_commands(color_ostream &con, vector<string> &commands) {
|
|
|
|
|
void get_commands(color_ostream &con, std::vector<std::string> &commands) {
|
|
|
|
|
CoreSuspender suspend;
|
|
|
|
|
auto L = Lua::Core::State;
|
|
|
|
|
Lua::StackUnwinder top(L);
|
|
|
|
@ -431,10 +428,10 @@ static bool try_autocomplete(color_ostream &con, const std::string &first, std::
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Core::addScriptPath(string path, bool search_before)
|
|
|
|
|
bool Core::addScriptPath(std::string path, bool search_before)
|
|
|
|
|
{
|
|
|
|
|
lock_guard<mutex> lock(script_path_mutex);
|
|
|
|
|
vector<string> &vec = script_paths[search_before ? 0 : 1];
|
|
|
|
|
std::lock_guard<std::mutex> lock(script_path_mutex);
|
|
|
|
|
std::vector<std::string> &vec = script_paths[search_before ? 0 : 1];
|
|
|
|
|
if (std::find(vec.begin(), vec.end(), path) != vec.end())
|
|
|
|
|
return false;
|
|
|
|
|
if (!Filesystem::isdir(path))
|
|
|
|
@ -443,13 +440,13 @@ bool Core::addScriptPath(string path, bool search_before)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Core::removeScriptPath(string path)
|
|
|
|
|
bool Core::removeScriptPath(std::string path)
|
|
|
|
|
{
|
|
|
|
|
lock_guard<mutex> lock(script_path_mutex);
|
|
|
|
|
std::lock_guard<std::mutex> lock(script_path_mutex);
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
|
|
|
{
|
|
|
|
|
vector<string> &vec = script_paths[i];
|
|
|
|
|
std::vector<std::string> &vec = script_paths[i];
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
auto it = std::find(vec.begin(), vec.end(), path);
|
|
|
|
@ -464,14 +461,14 @@ bool Core::removeScriptPath(string path)
|
|
|
|
|
|
|
|
|
|
void Core::getScriptPaths(std::vector<std::string> *dest)
|
|
|
|
|
{
|
|
|
|
|
lock_guard<mutex> lock(script_path_mutex);
|
|
|
|
|
std::lock_guard<std::mutex> lock(script_path_mutex);
|
|
|
|
|
dest->clear();
|
|
|
|
|
string df_path = this->p->getPath() + "/";
|
|
|
|
|
std::string df_path = this->p->getPath() + "/";
|
|
|
|
|
for (auto it = script_paths[0].begin(); it != script_paths[0].end(); ++it)
|
|
|
|
|
dest->push_back(*it);
|
|
|
|
|
dest->push_back(df_path + CONFIG_PATH + "scripts");
|
|
|
|
|
if (df::global::world && isWorldLoaded()) {
|
|
|
|
|
string save = World::ReadWorldFolder();
|
|
|
|
|
std::string save = World::ReadWorldFolder();
|
|
|
|
|
if (save.size())
|
|
|
|
|
dest->push_back(df_path + "/save/" + save + "/scripts");
|
|
|
|
|
}
|
|
|
|
@ -481,13 +478,13 @@ void Core::getScriptPaths(std::vector<std::string> *dest)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string Core::findScript(string name)
|
|
|
|
|
std::string Core::findScript(std::string name)
|
|
|
|
|
{
|
|
|
|
|
vector<string> paths;
|
|
|
|
|
std::vector<std::string> paths;
|
|
|
|
|
getScriptPaths(&paths);
|
|
|
|
|
for (auto it = paths.begin(); it != paths.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
string path = *it + "/" + name;
|
|
|
|
|
std::string path = *it + "/" + name;
|
|
|
|
|
if (Filesystem::isfile(path))
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
@ -497,7 +494,7 @@ string Core::findScript(string name)
|
|
|
|
|
bool loadScriptPaths(color_ostream &out, bool silent = false)
|
|
|
|
|
{
|
|
|
|
|
using namespace std;
|
|
|
|
|
string filename(CONFIG_PATH + "script-paths.txt");
|
|
|
|
|
std::string filename(CONFIG_PATH + "script-paths.txt");
|
|
|
|
|
ifstream file(filename);
|
|
|
|
|
if (!file)
|
|
|
|
|
{
|
|
|
|
@ -505,7 +502,7 @@ bool loadScriptPaths(color_ostream &out, bool silent = false)
|
|
|
|
|
out.printerr("Could not load %s\n", filename.c_str());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
string raw;
|
|
|
|
|
std::string raw;
|
|
|
|
|
int line = 0;
|
|
|
|
|
while (getline(file, raw))
|
|
|
|
|
{
|
|
|
|
@ -516,7 +513,7 @@ bool loadScriptPaths(color_ostream &out, bool silent = false)
|
|
|
|
|
if (!(ss >> ch) || ch == '#')
|
|
|
|
|
continue;
|
|
|
|
|
ss >> ws; // discard whitespace
|
|
|
|
|
string path;
|
|
|
|
|
std::string path;
|
|
|
|
|
getline(ss, path);
|
|
|
|
|
if (ch == '+' || ch == '-')
|
|
|
|
|
{
|
|
|
|
@ -565,7 +562,7 @@ static std::string sc_event_name (state_change_event id) {
|
|
|
|
|
return "SC_UNKNOWN";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void help_helper(color_ostream &con, const string &entry_name) {
|
|
|
|
|
void help_helper(color_ostream &con, const std::string &entry_name) {
|
|
|
|
|
CoreSuspender suspend;
|
|
|
|
|
auto L = Lua::Core::State;
|
|
|
|
|
Lua::StackUnwinder top(L);
|
|
|
|
@ -583,7 +580,7 @@ void help_helper(color_ostream &con, const string &entry_name) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tags_helper(color_ostream &con, const string &tag) {
|
|
|
|
|
void tags_helper(color_ostream &con, const std::string &tag) {
|
|
|
|
|
CoreSuspender suspend;
|
|
|
|
|
auto L = Lua::Core::State;
|
|
|
|
|
Lua::StackUnwinder top(L);
|
|
|
|
@ -601,11 +598,11 @@ void tags_helper(color_ostream &con, const string &tag) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ls_helper(color_ostream &con, const vector<string> ¶ms) {
|
|
|
|
|
vector<string> filter;
|
|
|
|
|
void ls_helper(color_ostream &con, const std::vector<std::string> ¶ms) {
|
|
|
|
|
std::vector<std::string> filter;
|
|
|
|
|
bool skip_tags = false;
|
|
|
|
|
bool show_dev_commands = false;
|
|
|
|
|
string exclude_strs = "";
|
|
|
|
|
std::string exclude_strs = "";
|
|
|
|
|
|
|
|
|
|
bool in_exclude = false;
|
|
|
|
|
for (auto str : params) {
|
|
|
|
@ -641,7 +638,7 @@ void ls_helper(color_ostream &con, const vector<string> ¶ms) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
command_result Core::runCommand(color_ostream &con, const std::string &first_, vector<string> &parts)
|
|
|
|
|
command_result Core::runCommand(color_ostream &con, const std::string &first_, std::vector<std::string> &parts)
|
|
|
|
|
{
|
|
|
|
|
std::string first = first_;
|
|
|
|
|
CommandDepthCounter counter;
|
|
|
|
@ -717,7 +714,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
{
|
|
|
|
|
if (p->size() && (*p)[0] == '-')
|
|
|
|
|
{
|
|
|
|
|
if (p->find('a') != string::npos)
|
|
|
|
|
if (p->find('a') != std::string::npos)
|
|
|
|
|
all = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -876,7 +873,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
}
|
|
|
|
|
con << parts[0];
|
|
|
|
|
bool builtin = is_builtin(con, parts[0]);
|
|
|
|
|
string lua_path = findScript(parts[0] + ".lua");
|
|
|
|
|
std::string lua_path = findScript(parts[0] + ".lua");
|
|
|
|
|
Plugin *plug = plug_mgr->getPluginByCommand(parts[0]);
|
|
|
|
|
if (builtin)
|
|
|
|
|
{
|
|
|
|
@ -933,31 +930,31 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::string> list = ListKeyBindings(parts[1]);
|
|
|
|
|
if (list.empty())
|
|
|
|
|
con << "No bindings." << endl;
|
|
|
|
|
con << "No bindings." << std::endl;
|
|
|
|
|
for (size_t i = 0; i < list.size(); i++)
|
|
|
|
|
con << " " << list[i] << endl;
|
|
|
|
|
con << " " << list[i] << std::endl;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
con << "Usage:" << endl
|
|
|
|
|
<< " keybinding list <key>" << endl
|
|
|
|
|
<< " keybinding clear <key>[@context]..." << endl
|
|
|
|
|
<< " keybinding set <key>[@context] \"cmdline\" \"cmdline\"..." << endl
|
|
|
|
|
<< " keybinding add <key>[@context] \"cmdline\" \"cmdline\"..." << endl
|
|
|
|
|
<< "Later adds, and earlier items within one command have priority." << endl
|
|
|
|
|
<< "Supported keys: [Ctrl-][Alt-][Shift-](A-Z, 0-9, F1-F12, `, or Enter)." << endl
|
|
|
|
|
<< "Context may be used to limit the scope of the binding, by" << endl
|
|
|
|
|
<< "requiring the current context to have a certain prefix." << endl
|
|
|
|
|
<< "Current UI context is: " << endl
|
|
|
|
|
<< join_strings("\n", Gui::getCurFocus(true)) << endl;
|
|
|
|
|
con << "Usage:" << std::endl
|
|
|
|
|
<< " keybinding list <key>" << std::endl
|
|
|
|
|
<< " keybinding clear <key>[@context]..." << std::endl
|
|
|
|
|
<< " keybinding set <key>[@context] \"cmdline\" \"cmdline\"..." << std::endl
|
|
|
|
|
<< " keybinding add <key>[@context] \"cmdline\" \"cmdline\"..." << std::endl
|
|
|
|
|
<< "Later adds, and earlier items within one command have priority." << std::endl
|
|
|
|
|
<< "Supported keys: [Ctrl-][Alt-][Shift-](A-Z, 0-9, F1-F12, `, or Enter)." << std::endl
|
|
|
|
|
<< "Context may be used to limit the scope of the binding, by" << std::endl
|
|
|
|
|
<< "requiring the current context to have a certain prefix." << std::endl
|
|
|
|
|
<< "Current UI context is: " << std::endl
|
|
|
|
|
<< join_strings("\n", Gui::getCurFocus(true)) << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (first == "alias")
|
|
|
|
|
{
|
|
|
|
|
if (parts.size() >= 3 && (parts[0] == "add" || parts[0] == "replace"))
|
|
|
|
|
{
|
|
|
|
|
const string &name = parts[1];
|
|
|
|
|
vector<string> cmd(parts.begin() + 2, parts.end());
|
|
|
|
|
const std::string &name = parts[1];
|
|
|
|
|
std::vector<std::string> cmd(parts.begin() + 2, parts.end());
|
|
|
|
|
if (!AddAlias(name, cmd, parts[0] == "replace"))
|
|
|
|
|
{
|
|
|
|
|
con.printerr("Could not add alias %s - already exists\n", name.c_str());
|
|
|
|
@ -977,15 +974,15 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
auto aliases = ListAliases();
|
|
|
|
|
for (auto p : aliases)
|
|
|
|
|
{
|
|
|
|
|
con << p.first << ": " << join_strings(" ", p.second) << endl;
|
|
|
|
|
con << p.first << ": " << join_strings(" ", p.second) << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
con << "Usage: " << endl
|
|
|
|
|
<< " alias add|replace <name> <command...>" << endl
|
|
|
|
|
<< " alias delete|clear <name> <command...>" << endl
|
|
|
|
|
<< " alias list" << endl;
|
|
|
|
|
con << "Usage: " << std::endl
|
|
|
|
|
<< " alias add|replace <name> <command...>" << std::endl
|
|
|
|
|
<< " alias delete|clear <name> <command...>" << std::endl
|
|
|
|
|
<< " alias list" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (first == "fpause")
|
|
|
|
@ -1038,8 +1035,8 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
con << "Usage:" << endl
|
|
|
|
|
<< " script <filename>" << endl;
|
|
|
|
|
con << "Usage:" << std::endl
|
|
|
|
|
<< " script <filename>" << std::endl;
|
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1065,13 +1062,13 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
{
|
|
|
|
|
if (parts.empty() || parts[0] == "help" || parts[0] == "?")
|
|
|
|
|
{
|
|
|
|
|
con << "Usage: sc-script add|remove|list|help SC_EVENT [path-to-script] [...]" << endl;
|
|
|
|
|
con << "Valid event names (SC_ prefix is optional):" << endl;
|
|
|
|
|
con << "Usage: sc-script add|remove|list|help SC_EVENT [path-to-script] [...]" << std::endl;
|
|
|
|
|
con << "Valid event names (SC_ prefix is optional):" << std::endl;
|
|
|
|
|
for (int i = SC_WORLD_LOADED; i <= SC_UNPAUSED; i++)
|
|
|
|
|
{
|
|
|
|
|
std::string name = sc_event_name((state_change_event)i);
|
|
|
|
|
if (name != "SC_UNKNOWN")
|
|
|
|
|
con << " " << name << endl;
|
|
|
|
|
con << " " << name << std::endl;
|
|
|
|
|
}
|
|
|
|
|
return CR_OK;
|
|
|
|
|
}
|
|
|
|
@ -1081,7 +1078,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
parts.push_back("");
|
|
|
|
|
if (parts[1].size() && sc_event_id(parts[1]) == SC_UNKNOWN)
|
|
|
|
|
{
|
|
|
|
|
con << "Unrecognized event name: " << parts[1] << endl;
|
|
|
|
|
con << "Unrecognized event name: " << parts[1] << std::endl;
|
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
}
|
|
|
|
|
for (auto it = state_change_scripts.begin(); it != state_change_scripts.end(); ++it)
|
|
|
|
@ -1100,13 +1097,13 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
{
|
|
|
|
|
if (parts.size() < 3 || (parts.size() >= 4 && parts[3] != "-save"))
|
|
|
|
|
{
|
|
|
|
|
con << "Usage: sc-script add EVENT path-to-script [-save]" << endl;
|
|
|
|
|
con << "Usage: sc-script add EVENT path-to-script [-save]" << std::endl;
|
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
}
|
|
|
|
|
state_change_event evt = sc_event_id(parts[1]);
|
|
|
|
|
if (evt == SC_UNKNOWN)
|
|
|
|
|
{
|
|
|
|
|
con << "Unrecognized event: " << parts[1] << endl;
|
|
|
|
|
con << "Unrecognized event: " << parts[1] << std::endl;
|
|
|
|
|
return CR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
bool save_specific = (parts.size() >= 4 && parts[3] == "-save");
|
|
|
|
@ -1115,7 +1112,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
{
|
|
|
|
|
if (script == *it)
|
|
|
|
|
{
|
|
|
|
|
con << "Script already registered" << endl;
|
|
|
|
|
con << "Script already registered" << std::endl;
|
|
|
|
|
return CR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1126,13 +1123,13 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
{
|
|
|
|
|
if (parts.size() < 3 || (parts.size() >= 4 && parts[3] != "-save"))
|
|
|
|
|
{
|
|
|
|
|
con << "Usage: sc-script remove EVENT path-to-script [-save]" << endl;
|
|
|
|
|
con << "Usage: sc-script remove EVENT path-to-script [-save]" << std::endl;
|
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
}
|
|
|
|
|
state_change_event evt = sc_event_id(parts[1]);
|
|
|
|
|
if (evt == SC_UNKNOWN)
|
|
|
|
|
{
|
|
|
|
|
con << "Unrecognized event: " << parts[1] << endl;
|
|
|
|
|
con << "Unrecognized event: " << parts[1] << std::endl;
|
|
|
|
|
return CR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
bool save_specific = (parts.size() >= 4 && parts[3] == "-save");
|
|
|
|
@ -1145,13 +1142,13 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
con << "Unrecognized script" << endl;
|
|
|
|
|
con << "Unrecognized script" << std::endl;
|
|
|
|
|
return CR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
con << "Usage: sc-script add|remove|list|help SC_EVENT [path-to-script] [...]" << endl;
|
|
|
|
|
con << "Usage: sc-script add|remove|list|help SC_EVENT [path-to-script] [...]" << std::endl;
|
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1173,13 +1170,13 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
if (!svc)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
file << "// Plugin: " << plug->getName() << endl;
|
|
|
|
|
file << "// Plugin: " << plug->getName() << std::endl;
|
|
|
|
|
svc->dumpMethods(file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
con << "Usage: devel/dump-rpc \"filename\"" << endl;
|
|
|
|
|
con << "Usage: devel/dump-rpc \"filename\"" << std::endl;
|
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1196,8 +1193,8 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
}
|
|
|
|
|
else if (res == CR_NOT_IMPLEMENTED)
|
|
|
|
|
{
|
|
|
|
|
string completed;
|
|
|
|
|
string filename = findScript(first + ".lua");
|
|
|
|
|
std::string completed;
|
|
|
|
|
std::string filename = findScript(first + ".lua");
|
|
|
|
|
bool lua = filename != "";
|
|
|
|
|
if ( !lua ) {
|
|
|
|
|
filename = findScript(first + ".rb");
|
|
|
|
@ -1234,22 +1231,22 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
|
|
|
|
|
return CR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Core::loadScriptFile(color_ostream &out, string fname, bool silent)
|
|
|
|
|
bool Core::loadScriptFile(color_ostream &out, std::string fname, bool silent)
|
|
|
|
|
{
|
|
|
|
|
if(!silent) {
|
|
|
|
|
INFO(script,out) << "Loading script: " << fname << std::endl;
|
|
|
|
|
cerr << "Loading script: " << fname << std::endl;
|
|
|
|
|
std::cerr << "Loading script: " << fname << std::endl;
|
|
|
|
|
}
|
|
|
|
|
ifstream script(fname.c_str());
|
|
|
|
|
std::ifstream script(fname.c_str());
|
|
|
|
|
if ( !script.good() )
|
|
|
|
|
{
|
|
|
|
|
if(!silent)
|
|
|
|
|
out.printerr("Error loading script: %s\n", fname.c_str());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
string command;
|
|
|
|
|
std::string command;
|
|
|
|
|
while(script.good()) {
|
|
|
|
|
string temp;
|
|
|
|
|
std::string temp;
|
|
|
|
|
getline(script,temp);
|
|
|
|
|
bool doMore = false;
|
|
|
|
|
if ( temp.length() > 0 ) {
|
|
|
|
@ -1333,18 +1330,18 @@ void fIOthread(void * iodata)
|
|
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
string command = "";
|
|
|
|
|
std::string command = "";
|
|
|
|
|
int ret;
|
|
|
|
|
while ((ret = con.lineedit("[DFHack]# ",command, main_history))
|
|
|
|
|
== Console::RETRY);
|
|
|
|
|
if(ret == Console::SHUTDOWN)
|
|
|
|
|
{
|
|
|
|
|
cerr << "Console is shutting down properly." << endl;
|
|
|
|
|
std::cerr << "Console is shutting down properly." << std::endl;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if(ret == Console::FAILURE)
|
|
|
|
|
{
|
|
|
|
|
cerr << "Console caught an unspecified error." << endl;
|
|
|
|
|
std::cerr << "Console caught an unspecified error." << std::endl;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if(ret)
|
|
|
|
@ -1405,7 +1402,7 @@ Core::Core() :
|
|
|
|
|
void Core::fatal (std::string output)
|
|
|
|
|
{
|
|
|
|
|
errorstate = true;
|
|
|
|
|
stringstream out;
|
|
|
|
|
std::stringstream out;
|
|
|
|
|
out << output ;
|
|
|
|
|
if (output[output.size() - 1] != '\n')
|
|
|
|
|
out << '\n';
|
|
|
|
@ -1421,7 +1418,7 @@ void Core::fatal (std::string output)
|
|
|
|
|
out << "Check file stderr.log for details\n";
|
|
|
|
|
MessageBox(0,out.str().c_str(),"DFHack error!", MB_OK | MB_ICONERROR);
|
|
|
|
|
#else
|
|
|
|
|
cout << "DFHack fatal error: " << out.str() << std::endl;
|
|
|
|
|
std::cout << "DFHack fatal error: " << out.str() << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bool is_headless = bool(getenv("DFHACK_HEADLESS"));
|
|
|
|
@ -1459,16 +1456,16 @@ bool Core::Init()
|
|
|
|
|
// this is handled as appropriate in Console-posix.cpp
|
|
|
|
|
fprintf(stdout, "dfhack: redirecting stdout to stdout.log (again)\n");
|
|
|
|
|
if (!freopen("stdout.log", "w", stdout))
|
|
|
|
|
cerr << "Could not redirect stdout to stdout.log" << endl;
|
|
|
|
|
std::cerr << "Could not redirect stdout to stdout.log" << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
fprintf(stderr, "dfhack: redirecting stderr to stderr.log\n");
|
|
|
|
|
if (!freopen("stderr.log", "w", stderr))
|
|
|
|
|
cerr << "Could not redirect stderr to stderr.log" << endl;
|
|
|
|
|
std::cerr << "Could not redirect stderr to stderr.log" << std::endl;
|
|
|
|
|
|
|
|
|
|
Filesystem::init();
|
|
|
|
|
|
|
|
|
|
cerr << "DFHack build: " << Version::git_description() << "\n"
|
|
|
|
|
<< "Starting with working directory: " << Filesystem::getcwd() << endl;
|
|
|
|
|
std::cerr << "DFHack build: " << Version::git_description() << "\n"
|
|
|
|
|
<< "Starting with working directory: " << Filesystem::getcwd() << std::endl;
|
|
|
|
|
|
|
|
|
|
// find out what we are...
|
|
|
|
|
#ifdef LINUX_BUILD
|
|
|
|
@ -1477,7 +1474,7 @@ bool Core::Init()
|
|
|
|
|
const char * path = "hack\\symbols.xml";
|
|
|
|
|
#endif
|
|
|
|
|
auto local_vif = dts::make_unique<DFHack::VersionInfoFactory>();
|
|
|
|
|
cerr << "Identifying DF version.\n";
|
|
|
|
|
std::cerr << "Identifying DF version.\n";
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
local_vif->loadFile(path);
|
|
|
|
@ -1518,8 +1515,8 @@ bool Core::Init()
|
|
|
|
|
"recompile.\n"
|
|
|
|
|
"More details can be found in stderr.log in this folder.\n"
|
|
|
|
|
);
|
|
|
|
|
cout << msg << endl;
|
|
|
|
|
cerr << msg << endl;
|
|
|
|
|
std::cout << msg << std::endl;
|
|
|
|
|
std::cerr << msg << std::endl;
|
|
|
|
|
fatal("Not a known DF version - XML version mismatch (see console or stderr.log)");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@ -1529,13 +1526,13 @@ bool Core::Init()
|
|
|
|
|
errorstate = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
cerr << "Version: " << vinfo->getVersion() << endl;
|
|
|
|
|
std::cerr << "Version: " << vinfo->getVersion() << std::endl;
|
|
|
|
|
p = std::move(local_p);
|
|
|
|
|
|
|
|
|
|
// Init global object pointers
|
|
|
|
|
df::global::InitGlobals();
|
|
|
|
|
|
|
|
|
|
cerr << "Initializing Console.\n";
|
|
|
|
|
std::cerr << "Initializing Console.\n";
|
|
|
|
|
// init the console.
|
|
|
|
|
bool is_text_mode = (init && init->display.flag.is_set(init_display_flags::TEXT));
|
|
|
|
|
bool is_headless = bool(getenv("DFHACK_HEADLESS"));
|
|
|
|
@ -1551,29 +1548,29 @@ bool Core::Init()
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cerr << "endwin(): bind failed" << endl;
|
|
|
|
|
std::cerr << "endwin(): bind failed" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cerr << "Headless mode requires PRINT_MODE:TEXT" << endl;
|
|
|
|
|
std::cerr << "Headless mode requires PRINT_MODE:TEXT" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
cerr << "Headless mode not supported on Windows" << endl;
|
|
|
|
|
std::cerr << "Headless mode not supported on Windows" << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
if (is_text_mode && !is_headless)
|
|
|
|
|
{
|
|
|
|
|
cerr << "Console is not available. Use dfhack-run to send commands.\n";
|
|
|
|
|
std::cerr << "Console is not available. Use dfhack-run to send commands.\n";
|
|
|
|
|
if (!is_text_mode)
|
|
|
|
|
{
|
|
|
|
|
cout << "Console disabled.\n";
|
|
|
|
|
std::cout << "Console disabled.\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(con.init(false))
|
|
|
|
|
cerr << "Console is running.\n";
|
|
|
|
|
std::cerr << "Console is running.\n";
|
|
|
|
|
else
|
|
|
|
|
cerr << "Console has failed to initialize!\n";
|
|
|
|
|
std::cerr << "Console has failed to initialize!\n";
|
|
|
|
|
/*
|
|
|
|
|
// dump offsets to a file
|
|
|
|
|
std::ofstream dump("offsets.log");
|
|
|
|
@ -1642,19 +1639,19 @@ bool Core::Init()
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cerr << "Binding to SDL.\n";
|
|
|
|
|
std::cerr << "Binding to SDL.\n";
|
|
|
|
|
if (!DFSDL::init(con)) {
|
|
|
|
|
fatal("cannot bind SDL libraries");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
cerr << "Initializing textures.\n";
|
|
|
|
|
std::cerr << "Initializing textures.\n";
|
|
|
|
|
Textures::init(con);
|
|
|
|
|
// create mutex for syncing with interactive tasks
|
|
|
|
|
cerr << "Initializing plugins.\n";
|
|
|
|
|
std::cerr << "Initializing plugins.\n";
|
|
|
|
|
// create plugin manager
|
|
|
|
|
plug_mgr = new PluginManager(this);
|
|
|
|
|
plug_mgr->init();
|
|
|
|
|
cerr << "Starting the TCP listener.\n";
|
|
|
|
|
std::cerr << "Starting the TCP listener.\n";
|
|
|
|
|
auto listen = ServerMain::listen(RemoteClient::GetDefaultPort());
|
|
|
|
|
IODATA *temp = new IODATA;
|
|
|
|
|
temp->core = this;
|
|
|
|
@ -1662,7 +1659,7 @@ bool Core::Init()
|
|
|
|
|
|
|
|
|
|
if (!is_text_mode || is_headless)
|
|
|
|
|
{
|
|
|
|
|
cerr << "Starting IO thread.\n";
|
|
|
|
|
std::cerr << "Starting IO thread.\n";
|
|
|
|
|
// create IO thread
|
|
|
|
|
d->iothread = std::thread{fIOthread, (void*)temp};
|
|
|
|
|
}
|
|
|
|
@ -1672,19 +1669,19 @@ bool Core::Init()
|
|
|
|
|
d->iothread = std::thread{fInitthread, (void*)temp};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cerr << "Starting DF input capture thread.\n";
|
|
|
|
|
std::cerr << "Starting DF input capture thread.\n";
|
|
|
|
|
// set up hotkey capture
|
|
|
|
|
d->hotkeythread = std::thread(fHKthread, (void *) temp);
|
|
|
|
|
started = true;
|
|
|
|
|
modstate = 0;
|
|
|
|
|
|
|
|
|
|
if (!listen.get())
|
|
|
|
|
cerr << "TCP listen failed.\n";
|
|
|
|
|
std::cerr << "TCP listen failed.\n";
|
|
|
|
|
|
|
|
|
|
if (df::global::game)
|
|
|
|
|
{
|
|
|
|
|
vector<string> args;
|
|
|
|
|
const string & raw = df::global::game->command_line.original;
|
|
|
|
|
std::vector<std::string> args;
|
|
|
|
|
const std::string & raw = df::global::game->command_line.original;
|
|
|
|
|
size_t offset = 0;
|
|
|
|
|
while (offset < raw.size())
|
|
|
|
|
{
|
|
|
|
@ -1698,7 +1695,7 @@ bool Core::Init()
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size_t next = raw.find(" ", offset);
|
|
|
|
|
if (next == string::npos)
|
|
|
|
|
if (next == std::string::npos)
|
|
|
|
|
{
|
|
|
|
|
args.push_back(raw.substr(offset));
|
|
|
|
|
offset = raw.size();
|
|
|
|
@ -1712,12 +1709,12 @@ bool Core::Init()
|
|
|
|
|
}
|
|
|
|
|
for (auto it = args.begin(); it != args.end(); )
|
|
|
|
|
{
|
|
|
|
|
const string & first = *it;
|
|
|
|
|
const std::string & first = *it;
|
|
|
|
|
if (first.length() > 0 && first[0] == '+')
|
|
|
|
|
{
|
|
|
|
|
vector<string> cmd;
|
|
|
|
|
std::vector<std::string> cmd;
|
|
|
|
|
for (it++; it != args.end(); it++) {
|
|
|
|
|
const string & arg = *it;
|
|
|
|
|
const std::string & arg = *it;
|
|
|
|
|
if (arg.length() > 0 && arg[0] == '+')
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
@ -1727,12 +1724,12 @@ bool Core::Init()
|
|
|
|
|
|
|
|
|
|
if (runCommand(con, first.substr(1), cmd) != CR_OK)
|
|
|
|
|
{
|
|
|
|
|
cerr << "Error running command: " << first.substr(1);
|
|
|
|
|
std::cerr << "Error running command: " << first.substr(1);
|
|
|
|
|
for (auto it2 = cmd.begin(); it2 != cmd.end(); it2++)
|
|
|
|
|
{
|
|
|
|
|
cerr << " \"" << *it2 << "\"";
|
|
|
|
|
std::cerr << " \"" << *it2 << "\"";
|
|
|
|
|
}
|
|
|
|
|
cerr << "\n";
|
|
|
|
|
std::cerr << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@ -1742,7 +1739,7 @@ bool Core::Init()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cerr << "DFHack is running.\n";
|
|
|
|
|
std::cerr << "DFHack is running.\n";
|
|
|
|
|
|
|
|
|
|
onStateChange(con, SC_CORE_INITIALIZED);
|
|
|
|
|
|
|
|
|
@ -1761,7 +1758,7 @@ bool Core::setHotkeyCmd( std::string cmd )
|
|
|
|
|
/// removes the hotkey command and gives it to the caller thread
|
|
|
|
|
std::string Core::getHotkeyCmd( bool &keep_going )
|
|
|
|
|
{
|
|
|
|
|
string returner;
|
|
|
|
|
std::string returner;
|
|
|
|
|
std::unique_lock<std::mutex> lock(HotkeyMutex);
|
|
|
|
|
HotkeyCond.wait(lock, [this]() -> bool {return this->hotkey_set;});
|
|
|
|
|
if (hotkey_set == SHUTDOWN) {
|
|
|
|
@ -1986,22 +1983,22 @@ void getFilesWithPrefixAndSuffix(const std::string& folder, const std::string& p
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t loadScriptFiles(Core* core, color_ostream& out, const vector<std::string>& prefix, const std::string& folder) {
|
|
|
|
|
static const string suffix = ".init";
|
|
|
|
|
vector<string> scriptFiles;
|
|
|
|
|
size_t loadScriptFiles(Core* core, color_ostream& out, const std::vector<std::string>& prefix, const std::string& folder) {
|
|
|
|
|
static const std::string suffix = ".init";
|
|
|
|
|
std::vector<std::string> scriptFiles;
|
|
|
|
|
for ( size_t a = 0; a < prefix.size(); a++ ) {
|
|
|
|
|
getFilesWithPrefixAndSuffix(folder, prefix[a], ".init", scriptFiles);
|
|
|
|
|
}
|
|
|
|
|
std::sort(scriptFiles.begin(), scriptFiles.end(),
|
|
|
|
|
[&](const string &a, const string &b) {
|
|
|
|
|
string a_base = a.substr(0, a.size() - suffix.size());
|
|
|
|
|
string b_base = b.substr(0, b.size() - suffix.size());
|
|
|
|
|
[&](const std::string &a, const std::string &b) {
|
|
|
|
|
std::string a_base = a.substr(0, a.size() - suffix.size());
|
|
|
|
|
std::string b_base = b.substr(0, b.size() - suffix.size());
|
|
|
|
|
return a_base < b_base;
|
|
|
|
|
});
|
|
|
|
|
size_t result = 0;
|
|
|
|
|
for ( size_t a = 0; a < scriptFiles.size(); a++ ) {
|
|
|
|
|
result++;
|
|
|
|
|
string path = "";
|
|
|
|
|
std::string path = "";
|
|
|
|
|
if (folder != ".")
|
|
|
|
|
path = folder + "/";
|
|
|
|
|
core->loadScriptFile(out, path + scriptFiles[a], false);
|
|
|
|
@ -2012,10 +2009,10 @@ size_t loadScriptFiles(Core* core, color_ostream& out, const vector<std::string>
|
|
|
|
|
namespace DFHack {
|
|
|
|
|
namespace X {
|
|
|
|
|
typedef state_change_event Key;
|
|
|
|
|
typedef vector<string> Val;
|
|
|
|
|
typedef pair<Key,Val> Entry;
|
|
|
|
|
typedef vector<Entry> EntryVector;
|
|
|
|
|
typedef map<Key,Val> InitVariationTable;
|
|
|
|
|
typedef std::vector<std::string> Val;
|
|
|
|
|
typedef std::pair<Key,Val> Entry;
|
|
|
|
|
typedef std::vector<Entry> EntryVector;
|
|
|
|
|
typedef std::map<Key,Val> InitVariationTable;
|
|
|
|
|
|
|
|
|
|
EntryVector computeInitVariationTable(void* none, ...) {
|
|
|
|
|
va_list list;
|
|
|
|
@ -2030,7 +2027,7 @@ namespace DFHack {
|
|
|
|
|
const char *v = va_arg(list, const char *);
|
|
|
|
|
if (!v || !v[0])
|
|
|
|
|
break;
|
|
|
|
|
val.push_back(string(v));
|
|
|
|
|
val.emplace_back(v);
|
|
|
|
|
}
|
|
|
|
|
result.push_back(Entry(key,val));
|
|
|
|
|
}
|
|
|
|
@ -2647,8 +2644,8 @@ bool Core::RunAlias(color_ostream &out, const std::string &name,
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const string &first = aliases[name][0];
|
|
|
|
|
vector<string> parts(aliases[name].begin() + 1, aliases[name].end());
|
|
|
|
|
const std::string &first = aliases[name][0];
|
|
|
|
|
std::vector<std::string> parts(aliases[name].begin() + 1, aliases[name].end());
|
|
|
|
|
parts.insert(parts.end(), parameters.begin(), parameters.end());
|
|
|
|
|
result = runCommand(out, first, parts);
|
|
|
|
|
return true;
|
|
|
|
|