Changes
diff --git a/cmake/build_nethack.cmake b/cmake/build_nethack.cmake
index fe73a28..a308acc 100644
--- a/cmake/build_nethack.cmake
+++ b/cmake/build_nethack.cmake
@@ -48,6 +48,22 @@ if(NOT setup_result EQUAL 0)
"${setup_output}\n${setup_error}")
endif()
+# NetHack's Linux hint embeds HACKDIR in SYSCF_FILE. MCP workers run from
+# private game directories and link sysconf there, so keep this path relative.
+set(NETHACK_MAKEFILE "${NETHACK_SOURCE_DIR}/Makefile")
+file(READ "${NETHACK_MAKEFILE}" NETHACK_MAKEFILE_CONTENT)
+string(FIND "${NETHACK_MAKEFILE_CONTENT}"
+ "$(HACKDIR)/sysconf" NETHACK_SYSCF_PATH_POSITION)
+if(NETHACK_SYSCF_PATH_POSITION EQUAL -1)
+ message(FATAL_ERROR "Could not find NetHack's compiled SYSCF_FILE path")
+endif()
+string(REPLACE
+ "$(HACKDIR)/sysconf"
+ "sysconf"
+ NETHACK_MAKEFILE_CONTENT
+ "${NETHACK_MAKEFILE_CONTENT}")
+file(WRITE "${NETHACK_MAKEFILE}" "${NETHACK_MAKEFILE_CONTENT}")
+
# Publish NetHack's native end condition before the engine tears itself down.
set(NETHACK_END_SOURCE "${NETHACK_SOURCE_DIR}/src/end.c")
file(READ "${NETHACK_END_SOURCE}" NETHACK_END_CONTENT)
diff --git a/include/game_session.hpp b/include/game_session.hpp
index 03c0dbc..28664a6 100644
--- a/include/game_session.hpp
+++ b/include/game_session.hpp
@@ -100,8 +100,8 @@ private:
ToolResult refreshAgentActivity(std::int64_t& activity_at_s);
bool persistAgentActivity(std::int64_t activity_at_s);
void handleWorkerMessage(const Json& message);
- bool copyRuntimeFiles(const std::filesystem::path& run_directory,
- std::string& error) const;
+ bool prepareRunDirectory(const std::filesystem::path& run_directory,
+ std::string& error) const;
static bool validGameId(const Json& arguments,
const Json& state,
std::string& error);
diff --git a/src/game_session.cpp b/src/game_session.cpp
index 14b6a5c..3fb2353 100644
--- a/src/game_session.cpp
+++ b/src/game_session.cpp
@@ -178,7 +178,7 @@ ToolResult GameSession::startGame(const Json& arguments)
const std::filesystem::path run_directory = data_root_ / game_id_;
std::string error;
- if(!copyRuntimeFiles(run_directory, error))
+ if(!prepareRunDirectory(run_directory, error))
{
return errorResult("ENGINE_FAILURE", error);
}
@@ -1087,7 +1087,7 @@ void GameSession::handleWorkerMessage(const Json& message)
}
}
-bool GameSession::copyRuntimeFiles(
+bool GameSession::prepareRunDirectory(
const std::filesystem::path& run_directory, std::string& error) const
{
try
@@ -1102,6 +1102,7 @@ bool GameSession::copyRuntimeFiles(
std::filesystem::permissions(run_directory / "save",
owner_permissions,
std::filesystem::perm_options::replace);
+ // Link shared immutable data into the private working directory.
for(const char* filename : {"nhdat", "symbols", "license", "sysconf"})
{
const auto source = runtime_dir_ / filename;
@@ -1110,7 +1111,9 @@ bool GameSession::copyRuntimeFiles(
error = "NetHack runtime file is missing: " + source.string();
return false;
}
- std::filesystem::copy_file(source, run_directory / filename);
+ std::filesystem::create_symlink(
+ std::filesystem::canonical(source),
+ run_directory / filename);
}
for(const char* filename : {"perm", "record", "logfile",
"xlogfile", "livelog"})