Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ Template for new versions:
## Documentation

## API
- Core: added ``getConfigPath()`` API for obtaining the path to user-specific configuration files

## Lua
- Added ``dfhack.getConfigPath()`` API, proxying ``Core::getConfigPath``

## Removed

Expand Down
12 changes: 11 additions & 1 deletion docs/dev/Lua API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,17 @@ can be omitted.

* ``dfhack.getHackPath()``

Returns the dfhack directory path, i.e., ``".../df/hack/"``.
Returns the DFHack installation directory path (the folder where DFHack is installed).
This may be the ``hack`` folder within the DF installation, but you should not rely on this.
Specifically, the installation folder is extremely likely to be somewhere else when DFHack is installed from Steam.
Always use this function to get the DFHack installation directory path instead of hardcoding it.

* ``dfhack.getConfigPath()``

Returns the DFHack config directory path (the folder where user-specific configuration files are stored).
This is currently the ``dfhack-config`` folder within the DF installation, but you should not rely on this as it is likely to change in the future.
Always use this function to get the DFHack config directory path instead of hardcoding it.
Avoid storing this value in a long-lived variable, as it's possible that in future versions of DFHack, it may be possible for the config directory to be changed at runtime.

* ``dfhack.getSavePath()``

Expand Down
23 changes: 6 additions & 17 deletions library/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,6 @@ namespace DFHack {
DBG_DECLARE(core, keybinding, DebugCategory::LINFO);
DBG_DECLARE(core, script, DebugCategory::LINFO);

static const std::filesystem::path getConfigPath()
{
return Filesystem::getInstallDir() / "dfhack-config";
};

static const std::filesystem::path getConfigDefaultsPath()
{
return Core::getInstance().getHackPath() / "data" / "dfhack-config-defaults";
};

class MainThread {
public:
//! MainThread::suspend keeps the main DF thread suspended from Core::Init to
Expand Down Expand Up @@ -538,7 +528,7 @@ std::filesystem::path Core::findScript(std::string name)
return {};
}

bool loadScriptPaths(color_ostream &out, bool silent = false)
bool Core::loadScriptPaths(color_ostream &out, bool silent)
{
std::filesystem::path filename{ getConfigPath() / "script-paths.txt" };
std::ifstream file(filename);
Expand All @@ -563,7 +553,7 @@ bool loadScriptPaths(color_ostream &out, bool silent = false)
getline(ss, path);
if (ch == '+' || ch == '-')
{
if (!Core::getInstance().addScriptPath(path, ch == '+') && !silent)
if (!addScriptPath(path, ch == '+') && !silent)
out.printerr("{}:{}: Failed to add path: {}\n", filename, line, path);
}
else if (!silent)
Expand Down Expand Up @@ -935,12 +925,11 @@ static void run_dfhack_init(color_ostream &out, Core *core)
}

// load baseline defaults
core->loadScriptFile(out, getConfigPath() / "init" / "default.dfhack.init", false);
core->loadScriptFile(out, core->getConfigPath() / "init" / "default.dfhack.init", false);

// load user overrides
std::vector<std::string> prefixes(1, "dfhack");
loadScriptFiles(core, out, prefixes, getConfigPath() / "init");

loadScriptFiles(core, out, prefixes, core->getConfigPath() / "init");
// show the terminal if requested
auto L = DFHack::Core::getInstance().getLuaState();
Lua::CallLuaModuleFunction(out, L, "dfhack", "getHideConsoleOnStartup", 0, 1,
Expand All @@ -962,9 +951,9 @@ static void fInitthread(IODATA * iod)
// A thread function... for the interactive console.
static void fIOthread(IODATA * iod)
{
static const std::filesystem::path HISTORY_FILE = getConfigPath() / "dfhack.history";

Core * core = iod->core;
std::filesystem::path HISTORY_FILE = core->getConfigPath() / "dfhack.history";

PluginManager * plug_mgr = iod->plug_mgr;

CommandHistory main_history;
Expand Down
2 changes: 2 additions & 0 deletions library/LuaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1359,6 +1359,7 @@ static uint32_t getTickCount() { return Core::getInstance().p->getTickCount(); }

static std::filesystem::path getDFPath() { return Core::getInstance().p->getPath(); }
static std::filesystem::path getHackPath() { return Core::getInstance().getHackPath(); }
static std::filesystem::path getConfigPath() { return Core::getInstance().getConfigPath(); }

static bool isWorldLoaded() { return Core::getInstance().isWorldLoaded(); }
static bool isMapLoaded() { return Core::getInstance().isMapLoaded(); }
Expand All @@ -1384,6 +1385,7 @@ static const LuaWrapper::FunctionReg dfhack_module[] = {
WRAP(getDFPath),
WRAP(getTickCount),
WRAP(getHackPath),
WRAP(getConfigPath),
Comment thread
ab9rf marked this conversation as resolved.
WRAP(isWorldLoaded),
WRAP(isMapLoaded),
WRAP(isSiteLoaded),
Expand Down
19 changes: 10 additions & 9 deletions library/LuaTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1281,29 +1281,30 @@ bool DFHack::Lua::RunCoreQueryLoop(color_ostream &out, lua_State *state, DFHack:
return (rv == LUA_OK);
}

static bool init_interpreter(color_ostream &out, lua_State *state, const char* prompt, const char* hfile)
static bool init_interpreter(color_ostream &out, lua_State *state, std::string_view prompt, const std::filesystem::path& hfile)
{
lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN);
lua_getfield(state, -1, "interpreter");
lua_remove(state, -2);
lua_pushstring(state, prompt);
lua_pushstring(state, hfile);
lua_pushlstring(state, prompt.data(), prompt.size());
lua_pushlstring(state, hfile.string().data(), hfile.string().size());
return true;
}

bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
const char *prompt, const char *hfile)
std::string_view prompt, std::filesystem::path hfile)
{
if (!out.is_console())
return false;

if (!hfile)
hfile = "dfhack-config/lua.history";
if (!prompt)
if (hfile.empty())
hfile = DFHack::Core::getInstance().getConfigPath() / "lua.history";
if (prompt.empty())
prompt = "lua";

using namespace std::placeholders;
auto init_fn = std::bind(init_interpreter, _1, _2, prompt, hfile);
auto init_fn = [&](color_ostream& out, lua_State* state) {
return init_interpreter(out, state, prompt, hfile);
};

return RunCoreQueryLoop(out, state, init_fn);
}
Expand Down
18 changes: 18 additions & 0 deletions library/include/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ distribution.
#include "Export.h"
#include "Hooks.h"

#include "modules/Filesystem.h"

#include <algorithm>
#include <atomic>
#include <chrono>
Expand Down Expand Up @@ -189,6 +191,8 @@ namespace DFHack
std::map<std::string, std::vector<std::string>> ListAliases();
std::string GetAliasCommand(const std::string &name, bool ignore_params = false);

// note that this isn't valid until after DFHack is initialized by DF calling `dfhooks_init`
// that means that it's invalid during at-init static initialization
std::filesystem::path getHackPath();

bool isWorldLoaded() { return (last_world_data_ptr != nullptr); }
Expand Down Expand Up @@ -251,6 +255,18 @@ namespace DFHack
return false;
}

// Note that this path should be treated as potentially changeable over the life of a Core instance
// Consumers should not cache this path in long-lived local variables
const std::filesystem::path getConfigPath()
{
return Filesystem::getInstallDir() / "dfhack-config";
}

const std::filesystem::path getConfigDefaultsPath()
{
return getHackPath() / "data" / "dfhack-config-defaults";
}

private:
DFHack::Console con;

Expand All @@ -275,6 +291,8 @@ namespace DFHack
void onStateChange(color_ostream &out, state_change_event event);
void handleLoadAndUnloadScripts(color_ostream &out, state_change_event event);

bool loadScriptPaths(color_ostream& out, bool silent = false);

Core(Core const&) = delete;
void operator=(Core const&) = delete;

Expand Down
11 changes: 6 additions & 5 deletions library/include/LuaTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ distribution.

#pragma once

#include <concepts>
#include <functional>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <set>
#include <string>
#include <string_view>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <concepts>
#include <vector>

Comment thread
ab9rf marked this conversation as resolved.
#include "Core.h"
#include "ColorText.h"
Expand Down Expand Up @@ -287,7 +288,7 @@ namespace DFHack::Lua {
* Uses RunCoreQueryLoop internally.
*/
DFHACK_EXPORT bool InterpreterLoop(color_ostream &out, lua_State *state,
const char *prompt = NULL, const char *hfile = NULL);
std::string_view prompt = {}, std::filesystem::path hfile = {});

/**
* Run an interactive prompt loop. All access to the lua state
Expand Down
2 changes: 1 addition & 1 deletion library/lua/script-manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ function getModSourcePath(mod_id)
end

function getModStatePath(mod_id)
local path = ('dfhack-config/mods/%s/'):format(mod_id)
local path = (dfhack.getConfigPath() + ('/mods/%s/')):format(mod_id)
if not dfhack.filesystem.mkdir_recursive(path) then
error(('failed to create mod state directory: "%s"'):format(path))
end
Expand Down
9 changes: 4 additions & 5 deletions plugins/blueprint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#include "Console.h"
#include "Core.h"
#include "DataDefs.h"
#include "DataFuncs.h"
#include "DataIdentity.h"
Expand Down Expand Up @@ -59,8 +60,6 @@ using namespace DFHack;
DFHACK_PLUGIN("blueprint");
REQUIRE_GLOBAL(world);

static const string BLUEPRINT_USER_DIR = "dfhack-config/blueprints/";

namespace DFHack {
DBG_DECLARE(blueprint,log);
}
Expand Down Expand Up @@ -1370,9 +1369,9 @@ static const char * get_tile_zone(color_ostream &out, const df::coord &pos, cons

static bool create_output_dir(color_ostream &out,
const blueprint_options &opts) {
string basename = BLUEPRINT_USER_DIR + opts.name;
size_t last_slash = basename.find_last_of("/");
string parent_path = basename.substr(0, last_slash);
std::filesystem::path BLUEPRINT_USER_DIR = Core::getInstance().getConfigPath() / "blueprints";
std::filesystem::path basename = BLUEPRINT_USER_DIR / opts.name;
std::filesystem::path parent_path = basename.parent_path();

// create output directory if it doesn't already exist
if (!Filesystem::mkdir_recursive(parent_path)) {
Expand Down
9 changes: 6 additions & 3 deletions plugins/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ redistribute it freely, subject to the following restrictions:
distribution.
*/

#include "Core.h"
#include "PluginManager.h"
#include "DebugManager.h"
#include "Debug.h"
Expand Down Expand Up @@ -352,7 +353,9 @@ struct FilterManager : public std::map<size_t, Filter>
//! Current configuration version implemented by the code
constexpr static Json::UInt configVersion{1};
//! Path to the configuration file
constexpr static const char* configPath{"dfhack-config/runtime-debug.json"};
const inline std::filesystem::path getConfigPath() const {
return DFHack::Core::getInstance().getConfigPath() / "runtime-debug.json";
}

//! Get reference to the singleton
static FilterManager& getInstance() noexcept
Expand Down Expand Up @@ -434,15 +437,14 @@ struct FilterManager : public std::map<size_t, Filter>
DebugManager::categorySignal_t::Connection connection_;
};

constexpr const char* FilterManager::configPath;

FilterManager::~FilterManager()
{
}

command_result FilterManager::loadConfig(DFHack::color_ostream& out) noexcept
{
nextId_ = 1;
auto configPath = getConfigPath();
if (!Filesystem::isfile(configPath))
return CR_OK;
try {
Expand All @@ -463,6 +465,7 @@ command_result FilterManager::loadConfig(DFHack::color_ostream& out) noexcept

command_result FilterManager::saveConfig(DFHack::color_ostream& out) const noexcept
{
auto configPath = getConfigPath();
try {
DEBUG(command, out) << "Save config to '" << configPath << "'" << std::endl;
JsonArchive archive;
Expand Down
7 changes: 4 additions & 3 deletions plugins/liquids.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,16 @@ using namespace df::enums;
DFHACK_PLUGIN("liquids");
REQUIRE_GLOBAL(world);

static const char * HISTORY_FILE = "dfhack-config/liquids.history";
auto constexpr HISTORY_FILE = "liquids.history";

CommandHistory liquids_hist;

command_result df_liquids (color_ostream &out, vector <string> & parameters);
command_result df_liquids_here (color_ostream &out, vector <string> & parameters);

DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
liquids_hist.load(HISTORY_FILE);
liquids_hist.load(DFHack::Core::getInstance().getConfigPath() / HISTORY_FILE);
commands.push_back(PluginCommand(
"liquids",
"Place magma, water or obsidian.",
Expand All @@ -82,7 +83,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug

DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
liquids_hist.save(HISTORY_FILE);
liquids_hist.save(DFHack::Core::getInstance().getConfigPath() / HISTORY_FILE);
return CR_OK;
}

Expand Down
2 changes: 1 addition & 1 deletion plugins/lua/blueprint.lua
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ end

-- returns the name of the output file for the given context
function get_filename(opts, phase, ordinal)
local fullname = 'dfhack-config/blueprints/' .. opts.name
local fullname = dfhack.getConfigPath() .. '/blueprints/' .. opts.name
local _,_,basename = opts.name:find('([^/]+)/*$')
if not basename then
-- should not happen since opts.name should already be validated
Expand Down
2 changes: 1 addition & 1 deletion plugins/lua/buildingplan/planneroverlay.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ local utils = require('utils')
local widgets = require('gui.widgets')
require('dfhack.buildings')

config = config or json.open('dfhack-config/buildingplan.json')
config = config or json.open(dfhack.getConfigPath() .. '/buildingplan.json')

local uibs = df.global.buildreq

Expand Down
2 changes: 1 addition & 1 deletion plugins/lua/dwarfmonitor.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ local guidm = require('gui.dwarfmode')
local overlay = require('plugins.overlay')
local utils = require('utils')

local DWARFMONITOR_CONFIG_FILE = 'dfhack-config/dwarfmonitor.json'
local DWARFMONITOR_CONFIG_FILE = dfhack.getConfigPath() .. '/dwarfmonitor.json'

-- ------------- --
-- WeatherWidget --
Expand Down
2 changes: 1 addition & 1 deletion plugins/lua/orders.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ local function do_import()
dismiss_on_select2=false,
on_select2=function(_, choice)
if choice.text:startswith('library/') then return end
local fname = 'dfhack-config/orders/'..choice.text..'.json'
local fname = dfhack.getConfigPath() .. '/orders/' .. choice.text .. '.json'
if not dfhack.filesystem.isfile(fname) then return end
dialogs.showYesNoPrompt('Delete orders file?',
'Are you sure you want to delete "' .. fname .. '"?', nil,
Expand Down
2 changes: 1 addition & 1 deletion plugins/lua/overlay.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ local scriptmanager = require('script-manager')
local utils = require('utils')
local widgets = require('gui.widgets')

local OVERLAY_CONFIG_FILE = 'dfhack-config/overlay.json'
local OVERLAY_CONFIG_FILE = dfhack.getConfigPath() .. '/overlay.json'
local OVERLAY_WIDGETS_VAR = 'OVERLAY_WIDGETS'
local GLOBAL_KEY = 'OVERLAY'

Expand Down
2 changes: 1 addition & 1 deletion plugins/lua/spectate.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ end

local function load_state()
local state = get_default_state()
local config_file = json.open('dfhack-config/spectate.json')
local config_file = json.open(dfhack.getConfigPath() .. '/spectate.json')
for key in pairs(config_file.data) do
if state[key] == nil then
config_file.data[key] = nil
Expand Down
2 changes: 1 addition & 1 deletion plugins/lua/stockpiles.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ local logistics = require('plugins.logistics')
local overlay = require('plugins.overlay')
local widgets = require('gui.widgets')

local STOCKPILES_DIR = 'dfhack-config/stockpiles'
local STOCKPILES_DIR = dfhack.getConfigPath() .. '/stockpiles'
local STOCKPILES_LIBRARY_DIR = dfhack.getHackPath() .. '/data/stockpiles'

local BAD_FILENAME_REGEX = '[^%w._]'
Expand Down
Loading
Loading