|  |  |  | @ -106,6 +106,9 @@ namespace DFHack { | 
		
	
		
			
				|  |  |  |  | DBG_DECLARE(core,keybinding,DebugCategory::LINFO); | 
		
	
		
			
				|  |  |  |  | DBG_DECLARE(core,script,DebugCategory::LINFO); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | static const std::string CONFIG_PATH = "dfhack-config/"; | 
		
	
		
			
				|  |  |  |  | static const std::string CONFIG_DEFAULTS_PATH = "hack/data/dfhack-config-defaults/"; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | class MainThread { | 
		
	
		
			
				|  |  |  |  | public: | 
		
	
		
			
				|  |  |  |  |     //! MainThread::suspend keeps the main DF thread suspended from Core::Init to
 | 
		
	
	
		
			
				
					|  |  |  | @ -486,10 +489,10 @@ void Core::getScriptPaths(std::vector<std::string> *dest) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     lock_guard<mutex> lock(script_path_mutex); | 
		
	
		
			
				|  |  |  |  |     dest->clear(); | 
		
	
		
			
				|  |  |  |  |     string df_path = this->p->getPath(); | 
		
	
		
			
				|  |  |  |  |     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 + "/dfhack-config/scripts"); | 
		
	
		
			
				|  |  |  |  |     dest->push_back(df_path + CONFIG_PATH + "scripts"); | 
		
	
		
			
				|  |  |  |  |     if (df::global::world && isWorldLoaded()) { | 
		
	
		
			
				|  |  |  |  |         string save = World::ReadWorldFolder(); | 
		
	
		
			
				|  |  |  |  |         if (save.size()) | 
		
	
	
		
			
				
					|  |  |  | @ -518,7 +521,7 @@ string Core::findScript(string name) | 
		
	
		
			
				|  |  |  |  | bool loadScriptPaths(color_ostream &out, bool silent = false) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     using namespace std; | 
		
	
		
			
				|  |  |  |  |     string filename("dfhack-config/script-paths.txt"); | 
		
	
		
			
				|  |  |  |  |     string filename(CONFIG_PATH + "script-paths.txt"); | 
		
	
		
			
				|  |  |  |  |     ifstream file(filename); | 
		
	
		
			
				|  |  |  |  |     if (!file) | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
	
		
			
				
					|  |  |  | @ -1311,11 +1314,11 @@ static void run_dfhack_init(color_ostream &out, Core *core) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // load baseline defaults
 | 
		
	
		
			
				|  |  |  |  |     core->loadScriptFile(out, "dfhack-config/init/default.dfhack.init", false); | 
		
	
		
			
				|  |  |  |  |     core->loadScriptFile(out, CONFIG_PATH + "init/default.dfhack.init", false); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // load user overrides
 | 
		
	
		
			
				|  |  |  |  |     std::vector<std::string> prefixes(1, "dfhack"); | 
		
	
		
			
				|  |  |  |  |     loadScriptFiles(core, out, prefixes, "dfhack-config/init"); | 
		
	
		
			
				|  |  |  |  |     loadScriptFiles(core, out, prefixes, CONFIG_PATH + "init"); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | // Load dfhack.init in a dedicated thread (non-interactive console mode)
 | 
		
	
	
		
			
				
					|  |  |  | @ -1331,14 +1334,14 @@ void fInitthread(void * iodata) | 
		
	
		
			
				|  |  |  |  | // A thread function... for the interactive console.
 | 
		
	
		
			
				|  |  |  |  | void fIOthread(void * iodata) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     static const char * HISTORY_FILE = "dfhack-config/dfhack.history"; | 
		
	
		
			
				|  |  |  |  |     static const std::string HISTORY_FILE = CONFIG_PATH + "dfhack.history"; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     IODATA * iod = ((IODATA*) iodata); | 
		
	
		
			
				|  |  |  |  |     Core * core = iod->core; | 
		
	
		
			
				|  |  |  |  |     PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     CommandHistory main_history; | 
		
	
		
			
				|  |  |  |  |     main_history.load(HISTORY_FILE); | 
		
	
		
			
				|  |  |  |  |     main_history.load(HISTORY_FILE.c_str()); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     Console & con = core->getConsole(); | 
		
	
		
			
				|  |  |  |  |     if (plug_mgr == 0) | 
		
	
	
		
			
				
					|  |  |  | @ -1379,7 +1382,7 @@ void fIOthread(void * iodata) | 
		
	
		
			
				|  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |             // a proper, non-empty command was entered
 | 
		
	
		
			
				|  |  |  |  |             main_history.add(command); | 
		
	
		
			
				|  |  |  |  |             main_history.save(HISTORY_FILE); | 
		
	
		
			
				|  |  |  |  |             main_history.save(HISTORY_FILE.c_str()); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         auto rv = core->runCommand(con, command); | 
		
	
	
		
			
				
					|  |  |  | @ -1614,46 +1617,44 @@ bool Core::Init() | 
		
	
		
			
				|  |  |  |  |     // initialize data defs
 | 
		
	
		
			
				|  |  |  |  |     virtual_identity::Init(this); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // create config directory if it doesn't already exist
 | 
		
	
		
			
				|  |  |  |  |     if (!Filesystem::mkdir_recursive(CONFIG_PATH)) | 
		
	
		
			
				|  |  |  |  |         con.printerr("Failed to create config directory: '%s'\n", CONFIG_PATH.c_str()); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // copy over default config files if necessary
 | 
		
	
		
			
				|  |  |  |  |     std::map<std::string, bool> config_files; | 
		
	
		
			
				|  |  |  |  |     std::map<std::string, bool> default_config_files; | 
		
	
		
			
				|  |  |  |  |     if (Filesystem::listdir_recursive("dfhack-config", config_files, 10, false) != 0) | 
		
	
		
			
				|  |  |  |  |         con.printerr("Failed to list directory: dfhack-config"); | 
		
	
		
			
				|  |  |  |  |     else if (Filesystem::listdir_recursive("dfhack-config/default", default_config_files, 10, false) != 0) | 
		
	
		
			
				|  |  |  |  |         con.printerr("Failed to list directory: dfhack-config/default"); | 
		
	
		
			
				|  |  |  |  |     if (Filesystem::listdir_recursive(CONFIG_PATH, config_files, 10, false) != 0) | 
		
	
		
			
				|  |  |  |  |         con.printerr("Failed to list directory: '%s'\n", CONFIG_PATH.c_str()); | 
		
	
		
			
				|  |  |  |  |     else if (Filesystem::listdir_recursive(CONFIG_DEFAULTS_PATH, default_config_files, 10, false) != 0) | 
		
	
		
			
				|  |  |  |  |         con.printerr("Failed to list directory: '%s'\n", CONFIG_DEFAULTS_PATH.c_str()); | 
		
	
		
			
				|  |  |  |  |     else | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |         // ensure all config file directories exist before we start copying files
 | 
		
	
		
			
				|  |  |  |  |         for (auto it = default_config_files.begin(); it != default_config_files.end(); ++it) | 
		
	
		
			
				|  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |         for (auto &entry : default_config_files) { | 
		
	
		
			
				|  |  |  |  |             // skip over files
 | 
		
	
		
			
				|  |  |  |  |             if (!it->second) | 
		
	
		
			
				|  |  |  |  |             if (!entry.second) | 
		
	
		
			
				|  |  |  |  |                 continue; | 
		
	
		
			
				|  |  |  |  |             std::string dirname = "dfhack-config/" + it->first; | 
		
	
		
			
				|  |  |  |  |             std::string dirname = CONFIG_PATH + entry.first; | 
		
	
		
			
				|  |  |  |  |             if (!Filesystem::mkdir_recursive(dirname)) | 
		
	
		
			
				|  |  |  |  |             { | 
		
	
		
			
				|  |  |  |  |                 con.printerr("Failed to create config directory: '%s'\n", dirname.c_str()); | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         // copy files from the default tree that don't already exist in the config tree
 | 
		
	
		
			
				|  |  |  |  |         for (auto it = default_config_files.begin(); it != default_config_files.end(); ++it) | 
		
	
		
			
				|  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |         for (auto &entry : default_config_files) { | 
		
	
		
			
				|  |  |  |  |             // skip over directories
 | 
		
	
		
			
				|  |  |  |  |             if (it->second) | 
		
	
		
			
				|  |  |  |  |             if (entry.second) | 
		
	
		
			
				|  |  |  |  |                 continue; | 
		
	
		
			
				|  |  |  |  |             std::string filename = it->first; | 
		
	
		
			
				|  |  |  |  |             if (config_files.find(filename) == config_files.end()) | 
		
	
		
			
				|  |  |  |  |             { | 
		
	
		
			
				|  |  |  |  |                 std::string src_file = std::string("dfhack-config/default/") + filename; | 
		
	
		
			
				|  |  |  |  |             std::string filename = entry.first; | 
		
	
		
			
				|  |  |  |  |             if (!config_files.count(filename)) { | 
		
	
		
			
				|  |  |  |  |                 std::string src_file = CONFIG_DEFAULTS_PATH + filename; | 
		
	
		
			
				|  |  |  |  |                 if (!Filesystem::isfile(src_file)) | 
		
	
		
			
				|  |  |  |  |                     continue; | 
		
	
		
			
				|  |  |  |  |                 std::string dest_file = std::string("dfhack-config/") + filename; | 
		
	
		
			
				|  |  |  |  |                 std::string dest_file = CONFIG_PATH + filename; | 
		
	
		
			
				|  |  |  |  |                 std::ifstream src(src_file, std::ios::binary); | 
		
	
		
			
				|  |  |  |  |                 std::ofstream dest(dest_file, std::ios::binary); | 
		
	
		
			
				|  |  |  |  |                 if (!src.good() || !dest.good()) | 
		
	
		
			
				|  |  |  |  |                 { | 
		
	
		
			
				|  |  |  |  |                     con.printerr("Copy failed: %s\n", filename.c_str()); | 
		
	
		
			
				|  |  |  |  |                 if (!src.good() || !dest.good()) { | 
		
	
		
			
				|  |  |  |  |                     con.printerr("Copy failed: '%s'\n", filename.c_str()); | 
		
	
		
			
				|  |  |  |  |                     continue; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 dest << src.rdbuf(); | 
		
	
	
		
			
				
					|  |  |  | @ -2090,9 +2091,9 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve | 
		
	
		
			
				|  |  |  |  |         const std::vector<std::string>& set = i->second; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         // load baseline defaults
 | 
		
	
		
			
				|  |  |  |  |         this->loadScriptFile(out, "dfhack-config/init/default." + set[0] + ".init", false); | 
		
	
		
			
				|  |  |  |  |         this->loadScriptFile(out, CONFIG_PATH + "init/default." + set[0] + ".init", false); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         loadScriptFiles(this, out, set, "dfhack-config/init"); | 
		
	
		
			
				|  |  |  |  |         loadScriptFiles(this, out, set, CONFIG_PATH + "init"); | 
		
	
		
			
				|  |  |  |  |         loadScriptFiles(this, out, set, rawFolder); | 
		
	
		
			
				|  |  |  |  |         loadScriptFiles(this, out, set, rawFolder + "objects/"); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					|  |  |  | 
 |