Проблема
LegacyWorldDataSource управляет директорией мира через chdir, а не как path-prefix. Причина — OLC-функции сохранения (redit_save_to_disk, medit_save_to_disk, oedit_save_to_disk, zedit_save_to_disk, trigedit_save_to_disk) пишут в пути, зашитые в compile-time макросы:
// src/engine/boot/boot_constants.h
#define WLD_PREFIX LIB_WORLD "wld" SLASH // "world/wld/"
#define MOB_PREFIX LIB_WORLD "mob" SLASH // "world/mob/"
#define OBJ_PREFIX LIB_WORLD "obj" SLASH
#define ZON_PREFIX LIB_WORLD "zon" SLASH
#define TRG_PREFIX LIB_WORLD "trg" SLASH
Эти пути всегда относительны cwd. Загрузка тоже идёт через них (GameLoader::BootIndex). Единственный рычаг сменить базовую директорию для legacy — chdir.
Из-за этого в LegacyWorldDataSource (см. PR #3290) пришлось:
- хранить
m_world_dir и оборачивать каждый Load*/Save* в ScopedChdir (src/engine/db/legacy_world_data_source.cpp, хелпер EnterWorldDir);
- трактовать
world_dir == "" как «текущий каталог», потому что main (src/engine/core/comm.cpp:759) уже сделал глобальный chdir(dir) по флагу -d, и повторный chdir в ту же папку упал бы (lib/lib).
Чем это плохо
- Асимметрия с YAML/SQLite. Те получают директорию как path-prefix (
CreateYamlDataSource("world"), открывают world/zones/... относительно cwd) — параметр осмысленный и обязательный. Legacy не может так, отсюда «магический» дефолт world_dir = "".
- Нельзя сделать параметр обязательным/честным. Единственное значение, которое
BootWorld мог бы передать — ".", что просто более явное "" + no-op chdir.
chdir — глобальное состояние процесса. Сейчас спасает RAII (ScopedChdir), но это хрупко: любой код, полагающийся на cwd во время Load*/Save* (в т.ч. в будущем — многопоточная загрузка), получит сюрприз.
Рекомендованное решение — выкинуть chdir
Переписать OLC *_save_to_disk (и, симметрично, legacy-загрузку) так, чтобы они принимали базовый путь к миру вместо хардкод-макросов *_PREFIX. Тогда:
LegacyWorldDataSource хранит m_world_dir как path-prefix (как YAML/SQLite), без chdir.
world_dir становится обязательным симметричным атрибутом: и load, и save относительно него.
- Глобальный
chdir(dir) в main остаётся для логов/плееров/конфигов/сокетов, но больше не связан с миром.
Объём: правки в redit.cpp/medit.cpp/oedit.cpp/zedit.cpp + trigedit_save_to_disk (заменить WLD_PREFIX-форматирование на base_path + "/wld/"), и в legacy-загрузчике (BootIndex / FilesPrefixes). Макросы можно оставить как дефолт базы.
Контекст
Всплыло при ревью PR #3290 (round-trip legacy↔yaml↔legacy). Текущая chdir-реализация рабочая и протестирована, тикет — про чистоту дизайна, не блокер.
Проблема
LegacyWorldDataSourceуправляет директорией мира через chdir, а не как path-prefix. Причина — OLC-функции сохранения (redit_save_to_disk,medit_save_to_disk,oedit_save_to_disk,zedit_save_to_disk,trigedit_save_to_disk) пишут в пути, зашитые в compile-time макросы:Эти пути всегда относительны cwd. Загрузка тоже идёт через них (
GameLoader::BootIndex). Единственный рычаг сменить базовую директорию для legacy —chdir.Из-за этого в
LegacyWorldDataSource(см. PR #3290) пришлось:m_world_dirи оборачивать каждыйLoad*/Save*вScopedChdir(src/engine/db/legacy_world_data_source.cpp, хелперEnterWorldDir);world_dir == ""как «текущий каталог», потому чтоmain(src/engine/core/comm.cpp:759) уже сделал глобальныйchdir(dir)по флагу-d, и повторный chdir в ту же папку упал бы (lib/lib).Чем это плохо
CreateYamlDataSource("world"), открываютworld/zones/...относительно cwd) — параметр осмысленный и обязательный. Legacy не может так, отсюда «магический» дефолтworld_dir = "".BootWorldмог бы передать —".", что просто более явное""+ no-op chdir.chdir— глобальное состояние процесса. Сейчас спасает RAII (ScopedChdir), но это хрупко: любой код, полагающийся на cwd во времяLoad*/Save*(в т.ч. в будущем — многопоточная загрузка), получит сюрприз.Рекомендованное решение — выкинуть chdir
Переписать OLC
*_save_to_disk(и, симметрично, legacy-загрузку) так, чтобы они принимали базовый путь к миру вместо хардкод-макросов*_PREFIX. Тогда:LegacyWorldDataSourceхранитm_world_dirкак path-prefix (как YAML/SQLite), без chdir.world_dirстановится обязательным симметричным атрибутом: и load, и save относительно него.chdir(dir)вmainостаётся для логов/плееров/конфигов/сокетов, но больше не связан с миром.Объём: правки в
redit.cpp/medit.cpp/oedit.cpp/zedit.cpp+trigedit_save_to_disk(заменитьWLD_PREFIX-форматирование наbase_path + "/wld/"), и в legacy-загрузчике (BootIndex/FilesPrefixes). Макросы можно оставить как дефолт базы.Контекст
Всплыло при ревью PR #3290 (round-trip legacy↔yaml↔legacy). Текущая chdir-реализация рабочая и протестирована, тикет — про чистоту дизайна, не блокер.