Skip to content

Legacy world data source использует chdir вместо path-prefix #3301

@kvirund

Description

@kvirund

Проблема

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-реализация рабочая и протестирована, тикет — про чистоту дизайна, не блокер.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions