Перейти к основному содержимому

Обзор архитектуры

Это руководство предназначено для пользователей редакций Source и Studio, имеющих доступ ко всему исходному коду MCE на C#.

Модульная архитектура

Стрелки намеренно направлены только в одну сторону. Core никогда не зависит от Online или от импортёра, и именно это делает онлайн-слой по-настоящему необязательным, а не необязательным только в README.

Этот документ охватывает иерархию модулей, структуру сборок, паттерны внедрения зависимостей и ключевые системы времени выполнения, из которых состоит Monster Capture Engine.

Иерархия модулей​

MCE организован в модули, следующие слоистой архитектуре:

Assets/
OpenMon/
Core/
Runtime/ # Core engine (REQUIRED)
Initialization/ # Engine startup, first-time wizard
Monster/ # MonsterInstance, Roster, evolution, breeding
MonsterDatabase/ # ScriptableObject definitions (species, moves, items, abilities)
Battle/ # BattleManager, 15 modules, state machine, AI
Characters/ # MCECharacterController, PlayerCharacter, followers
Actors/ # Actor system, CommandGraph visual scripting
World/ # GridController, GlobalGridManager, tiles, encounters
Saves/ # SavegameManager, SavableObject, GameVariables
Player/ # GlobalGameData, player state
UI/ # All UI controllers and views
Quests/ # Quest system (objectives, rewards, tracking)
SDK/ # Public API interfaces
GameFlow/ # Game state management
Configuration/ # ScriptableObject configs
Rendering/ # URP shaders, time-of-day, weather
Audio/ # AudioSettingsManager, AudioConfiguration (the playback engine is in Foundation)
Localization/ # Multi-language support
Badges/ # Badge tracking
Input/ # Input abstraction
MonsterDex/ # Dex tracking (seen/caught)
Animation/ # Animation utilities
WorldGenerator/ # Procedural region generator
Licensing/ # Tier and license checks
Shaders/ # Shader source files
Editor/ # Editor-only tooling
MonsterCreator/ # Monster creation wizard
Tools/ # Database Browser, Type Chart Editor, validators
Followers/ # Follower spritesheet tools
Actors/ # CommandGraph editor
Hub/ # The OpenMon Hub window
MapEditor/ # Scene View map painting overlays
Callbacks/ # Editor callback utilities

Правила зависимостей​

  1. У Core Runtime нет внешних зависимостей от модулей Online или Importer.
  2. Онлайн-функции подключаются по желанию через символ define скриптинга MCE_ONLINE.
  3. Код редактора строго отделён от рантайма границами .asmdef.
  4. Интерфейсы SDK в Runtime/SDK/ — поверхность публичного API для пользователей скомпилированных (DLL) редакций.

Структура сборок​

MCE использует Assembly Definitions Unity для соблюдения границ компиляции:

СборкаРасположениеНазначениеСсылки
OpenMon.Foundation.RuntimeFoundation/Runtime/Общий фреймворк: DI, аудио, локализация, управление сценами, твинингZenject и пакеты Unity
OpenMon.Foundation.EditorFoundation/Editor/Инструменты редактора FoundationFoundation Runtime + UnityEditor
OpenMon.MCE.RuntimeCore/Runtime/Основные игровые системыТолько библиотеки Foundation
OpenMon.MCE.EditorCore/Editor/Инструменты редактораRuntime + UnityEditor
OpenMon.Hub.EditorCore/Editor/Hub/Окно OpenMon Hub (вызывает инструменты импортёра и онлайн-слоя по имени, поэтому не зависит ни от одного из них)Foundation Runtime
MCE.Online.RuntimeOnline/Runtime/Сетевая часть на NakamaRuntime + SDK Nakama
MCE.Online.EditorOnline/Editor/Инструменты редактора онлайн-слояOnline Runtime + UnityEditor
MCE.EssentialsImporter.RuntimeImporter/Runtime/Парсеры PBS/rxdata и валидатор импортаRuntime + KaitaiStruct
MCE.EssentialsImporter.EditorImporter/Editor/Конвейер импортаRuntime + KaitaiStruct
OpenMon.SetupSetup/Установщик зависимостей пакетов и быстрая настройканет (намеренно изолирован)
MCE.Runtime.TestsCore/Tests/Runtime/Тесты режима игры для CoreRuntime + NUnit
MCE.Editor.TestsCore/Tests/Editor/Тесты режима редактора для CoreRuntime + Editor + NUnit

Почему важны Assembly Definitions​

  • Изоляция компиляции: изменения в коде редактора не перекомпилируют рантайм.
  • Соблюдение зависимостей: компилятор не позволяет рантайму ссылаться на API редактора.
  • Исключение из сборки: сборки редактора исключаются из сборок игрока.
  • Изоляция тестов: тестовые сборки могут ссылаться на внутренние элементы, не раскрывая их в продакшене.

Внедрение зависимостей (Zenject)​

MCE использует Zenject (Extenject) с паттерном установщиков для внедрения зависимостей.

Паттерн установщиков​

У каждой подсистемы есть собственный установщик, регистрирующий привязки. Большинство — установщики ScriptableObject; установщик лаунчера сражений типичен:

[CreateAssetMenu(menuName = "MCE/Dependency Injection/Battle Launcher Installer",
fileName = "BattleLauncherInstaller")]
public class BattleLauncherInstaller : LazySingletonScriptableInstaller<BattleLauncher>
{
public override void InstallBindings()
{
Reference.Reset();

Container.QueueForInject(Reference);

Container.Bind<IBattleLauncher>().FromInstance(Reference).AsSingle().Lazy();
}
}

BattleLauncher сам является ScriptableObject (ассетом), а ассет установщика указывает на него. Страница Внедрение зависимостей перечисляет все установщики.

Ключевые установщики​

УстановщикПривязывает
GameFlowInstallerОсновные сервисы игрового процесса
PlayerCharacterInstallerPlayerCharacter, сервисы персонажей
BattleLauncherInstallerIBattleLauncher, точка входа в сражение
GridInstallerСетка сцены (MonoInstaller)
SceneInfoInstallerSceneInfo, метаданные сцены
WorldDatabaseInstallerWorldDatabase, глобальные данные карт
TileDataInstallerДанные типов тайлов
GlobalGridManagerInstallerНавигация между картами
SavegameInstallerSavegameManager, сериализация
EvolutionManagerInstallerEvolutionManager

Соглашения​

  • Привязки по соглашению имеют вид .AsSingle().Lazy() (единственный экземпляр, создаваемый при первом использовании).
  • [Inject] используется на методах Construct(), а не на конструкторах.
  • Паттерн DialogManager.Factory используется для создания интерфейса во время выполнения.
  • Установщики уровня сцены (например, GridInstaller, MonoInstaller) обслуживают сервисы каждой сцены.
  • Установщики уровня проекта (ассеты ScriptableObject на префабе ProjectContext) обслуживают глобальные сервисы.

Точки внедрения​

public class SomeManager : MonoBehaviour
{
// Field injection (for MonoBehaviours).
// Note: of the SDK interfaces, only IMonsterCaptureEngine is bound —
// take Database/Battle/Player/SaveSystem from its properties.
[Inject] private IMonsterCaptureEngine engine;

private IBattleSystem battle;

private void Awake()
{
battle = engine.Battle;
}

// Method injection (preferred for explicit dependencies on engine-internal types)
[Inject]
public void Construct(MCESettings settings, MonsterDatabaseInstance database)
{
this.settings = settings;
this.database = database;
}
}

Ключевые системы времени выполнения​

Поток MCEInitialization​

MCEInitialization — первое, что запускается при старте игры:

1. Screen setup (resolution, orientation)
2. Load databases (monsters, moves, items, abilities)
3. Download localization data (if remote)
4. Run first-time wizard (if needed)
5. Initialize subsystems (save manager, audio, input)
6. Signal ready
7. Load main menu or continue saved game

Это MonoBehaviour на постоянном GameObject, который переживает загрузки сцен.

Система монстров​

Модель данных монстров:

MonsterEntry (ScriptableObject - species definition)
├── Base stats, types, abilities
├── List<DataByFormEntry> (private per-form overrides)
├── DataByFormEntry.Evolutions: List<EvolutionData> (evolution paths)
└── Move lists (level-up, TM, egg, tutor)

MonsterInstance (runtime - individual monster)
├── Species reference (MonsterEntry)
├── Level, XP
├── IVs[6], EVs[6]
├── Nature
├── Current HP, Status
├── MoveSlot[4] (with PP)
├── Friendship, OT data
└── Form index

Roster (party of up to 6 MonsterInstances)
MonsterStorage (PC boxes)

Боевая система​

Подробности см. в разделе Внутреннее устройство сражений.

Система мира​

GlobalGridManager (cross-map navigation)
└── GridController (per-scene grid)
├── TileData grid (collision, type per tile)
├── EncounterTile zones
└── SceneInfo (metadata)

MCECharacterController (movement)
├── PlayerCharacter (input + encounters)
└── ActorCharacter (NPC AI movement)

Система сохранений​

SavegameManager
├── MCESavesSerializer (JSON read/write)
├── SavableObject[] (registered savables)
└── GameVariables (global state)

Стиль кода​

Кодовая база следует этим соглашениям:

  • Отступ в 4 пробела, фигурные скобки на новых строках.
  • PascalCase для публичных типов, методов и свойств.
  • camelCase для закрытых полей и локальных переменных.
  • [SerializeField] private вместо публичных полей.
  • Runtime/ и Editor/ разделены границами .asmdef.
  • Conventional Commits: feat:, fix:, docs:, refactor:.
Сериализованные поля

Никогда не переименовывайте сериализованные поля без плана миграции. Сцены и префабы зависят от имён сериализованных полей. Для переименований используйте [FormerlySerializedAs("oldName")].

Расширение движка​

Добавление новой системы​

  1. Создайте свои классы в Runtime/YourSystem/.
  2. Создайте установщик для внедрения зависимостей.
  3. Добавьте установщик в подходящий контекст сцены или проекта.
  4. Если нужны данные сохранения, расширьте SavableObject.
  5. Если есть инструменты редактора, создайте классы в Editor/YourSystem/.

Изменение существующей системы​

  1. Прочитайте существующий код и поймите зависимости модуля.
  2. Проверьте, нельзя ли сделать изменение через конфигурацию или расширение, а не модификацию.
  3. Если вы изменяете, следуйте существующим паттернам модуля.
  4. Обновите тесты, чтобы они покрывали изменение.
  5. Опишите изменение в сообщениях коммитов.

Вопросы производительности​

  • Запросы к базе данных через SDK (GetMonster(dexNumber), GetMonster(name)) просматривают список видов. Кешируйте запись, если вызываете их часто.
  • Боевые модули — компоненты GameObject сражения, создаваемые вместе с ним один раз за сражение, а не за ход.
  • Большие тайлмапы обходятся дороже на каждый шаг и каждый кадр. Делите очень большие карты на соединённые сцены (см. Neighbours в Движение по сетке).
  • Сериализация сохранений синхронна в основном потоке. Держите объём данных сохранения разумным.
  • Выполнение CommandGraph основано на корутинах. Сложные графы со множеством узлов подходят для скриптинга событий, но их не следует использовать для логики покадрово.