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

Публичный API

Публичный API входит в редакции Indie, Pro, Source и Studio (в Starter API закрыт); полный исходный код C# есть только в Source и Studio. Это руководство описывает стабильную поверхность публичного API, которую можно использовать для взаимодействия с MCE и его расширения из собственных скриптов на C#, не связывая игровой код с внутренними деталями.

Публичный API

Стабильность — это обещание об ИМЕНИ. Всё остальное может меняться между версиями.

Пространство имён SDK​

MCE предоставляет свой публичный API через пространство имён OpenMon.MCE.SDK. Оно содержит чистые интерфейсы, дающие доступ к подсистемам движка без привязки вашего кода к внутренним реализациям.

IMonsterCaptureEngine​

Главная точка входа. Все остальные интерфейсы доступны через неё:

using OpenMon.MCE.SDK;

public class MyGameManager : MonoBehaviour
{
[Inject] private IMonsterCaptureEngine engine;

private void Start()
{
Debug.Log($"MCE Version: {engine.Version}");
Debug.Log($"Monsters in DB: {engine.Database.MonsterCount}");
Debug.Log($"Player name: {engine.Player.PlayerName}");
}
}

Свойства:

СвойствоТипОписание
DatabaseIMonsterDatabaseДоступ только для чтения к базе данных монстров/приёмов/предметов
BattleIBattleSystemСостояние и события сражения
PlayerIPlayerDataКоманда, деньги, имя и значки игрока
SaveSystemISaveSystemОперации сохранения и загрузки
VersionstringСтрока версии движка MCE

IMonsterDatabase​

Запрашивайте монстров, приёмы, способности, предметы и типы:

IMonsterDatabase db = engine.Database;

// Get a monster by dex number (National Dex; the parameter is a uint)
MonsterEntry flameleon = db.GetMonster(152u);

// Get a monster by name
MonsterEntry sparkbit = db.GetMonster("Sparkbit");

// Get all monsters
IReadOnlyList<MonsterEntry> allMonsters = db.GetAllMonsters();

// Get a move
Move thunderbolt = db.GetMove("Thunderbolt");

// Get all moves
IReadOnlyList<Move> allMoves = db.GetAllMoves();

// Get type effectiveness. Types are ScriptableObjects fetched from the database
// (there is no MonsterType enum), so look them up by name first:
MonsterType electric = db.GetAllTypes().FirstOrDefault(t => t.name == "Electric");
MonsterType water = db.GetAllTypes().FirstOrDefault(t => t.name == "Water");
float effectiveness = db.GetTypeEffectiveness(electric, water);
// Returns 2.0 (super effective)

// Get all types
IReadOnlyList<MonsterType> types = db.GetAllTypes();

// Get total count
int count = db.MonsterCount;

IBattleSystem​

Контракт SDK для состояния и событий сражения:

IBattleSystem battle = engine.Battle;

// Is a battle in progress?
if (battle.IsInBattle) { /* ... */ }

// Subscribe to battle events
battle.OnBattleStarted += HandleBattleStarted;
battle.OnBattleEnded += HandleBattleEnded; // bool playerWon
Движок пока их не вызывает

IsInBattle, OnBattleStarted и OnBattleEnded питаются хуками движка (BattleSystemFacade.NotifyBattleStarted / NotifyBattleEnded), которые текущий движок не вызывает, поэтому они остаются неактивными. Наблюдайте за сражениями через лаунчер сражений — см. Паттерн 1 и заметки в IBattleSystem.

IPlayerData​

Доступ к текущему состоянию игрока:

IPlayerData player = engine.Player;

// Player's monster team
Roster roster = player.PlayerRoster;
int teamSize = roster.RosterSize;
MonsterInstance firstMonster = roster[0];

// Player's money, as of the last save (the live balance is in the bag)
int money = player.Money;

// The name of the player's CharacterData asset
string name = player.PlayerName;

// Player's badge count
int badges = player.BadgeCount;

ISaveSystem​

Контракт SDK для сохранения и загрузки:

ISaveSystem saves = engine.SaveSystem;

saves.Save(1);
saves.Load(1);
bool hasData = saves.HasSaveData(1);
saves.DeleteSave(1);

saves.OnSaved += (slot) => Debug.Log($"Saved to slot {slot}");
saves.OnLoaded += (slot) => Debug.Log($"Loaded from slot {slot}");
Пока не подключён к сохранениям движка

В текущем движке engine.SaveSystem не подключён к SavegameManager: Save и Load лишь порождают запросы, которые никто не обрабатывает, а события никогда не срабатывают. Движок сохраняет именованные папки (см. руководство Система сохранений). Чтобы хранить собственные флаги и счётчики вместе с сохранением игрока, используйте игровые переменные в GlobalGameData (см. Паттерн 3).

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

MCE использует Zenject (Extenject) для внедрения зависимостей. Чтобы получить интерфейсы SDK в ваших скриптах, используйте атрибут [Inject]:

using Zenject;
using OpenMon.MCE.SDK;

public class MyCustomFeature : MonoBehaviour
{
// IMonsterCaptureEngine is the only SDK interface bound in DI
// (see SDKInstaller). Reach the subsystems through its properties.
[Inject] private IMonsterCaptureEngine engine;

private IMonsterDatabase database;
private IBattleSystem battle;

private void Awake()
{
// engine is injected before Awake/Start runs
database = engine.Database;
battle = engine.Battle;
}
}
Нет опыта с Zenject?

Если вы новичок во внедрении зависимостей, вот простая версия: добавьте [Inject] над закрытым полем IMonsterCaptureEngine, и Zenject заполнит его автоматически. Вызывать GetComponent или FindObjectOfType не нужно. Поле будет заполнено до запуска Start(), а остальные интерфейсы SDK доступны через него (engine.Database, engine.Battle, engine.Player, engine.SaveSystem).

Если ваш скрипт не является MonoBehaviour, управляемым Zenject, можно получить зависимость вручную:

var engine = ProjectContext.Instance.Container.Resolve<IMonsterCaptureEngine>();

Настраиваемые через Inspector параметры​

Многие системы MCE предоставляют настройки через Inspector Unity, не требуя кода:

Настройка через ScriptableObject​

АссетНазначение
MCESettingsОбщие настройки игры: шанс встречи по типам (TileEncounterChance), шанс дикого шайни, правило опыта, длина игровых суток, эмоциональные шарики
BattleConfigurationFileБоевые настройки для игрока: стиль сражения и ускорение анимации
BattleLauncherСцена сражения, боевая музыка диких сражений и сражений с тренерами и ИИ сражений по умолчанию
MonsterEntryДанные вида монстра
MoveОпределения приёмов (по одному конкретному классу на приём)
WildEncountersSetТаблицы встреч, связанные из ассета SceneInfo каждой карты
BattleAIСтратегии ИИ, объединяемые через Fallback

Настройка компонентов​

Большинство компонентов MCE выводят ключевые настройки в Inspector:

  • MCECharacterController / PlayerCharacter: скорость шага в секундах на тайл, отображаемый персонаж или монстр.
  • EncounterTile: тип встречи тайла.
  • SceneInfo (и его SceneInfoAsset): название карты, музыка, регион, погода, встречи.
  • Actor и его подклассы: слоты CommandGraph (при включении, цикл, взаимодействие, по требованию).

События и обратные вызовы​

MCE не использует поля UnityEvent в своих компонентах; он вызывает обычные события и обратные вызовы C#, на которые вы подписываетесь из своих скриптов. Наиболее полезные:

ГдеСобытиеСрабатывает, когда
IBattleLauncherSubscribeToBattleLaunched, SubscribeToBattleToUnload, SubscribeToBattleEnded(Action<BattleResultParameters>)Сцена сражения запущена, вот-вот выгрузится или сражение завершилось
IBattleSystemOnBattleStarted, OnBattleEnded(bool playerWon)Зарезервировано: фасад SDK вызывает их, когда движок вызывает его хуки (пока не подключено)
RosterOnRosterUpdatedМонстры в команде изменились
QuestManagerOnQuestStarted, OnObjectiveProgressed, OnObjectiveChanged, OnQuestCompleted, OnQuestFailed, OnRewardsGrantedСоответствующее событие квеста
PlayerEmotes (статический)Played(string balloonName)Локальный игрок показывает эмоциональный шарик

Чтобы запустить собственный C# из графа, напишите пользовательский узел (следующий раздел).

Расширение MCE без исходного кода​

Паттерн 1: слушатель событий​

Создайте MonoBehaviour, который слушает события MCE и запускает вашу логику. Лаунчер сражений привязан в DI и уведомляет о завершении сражения:

using OpenMon.MCE.Battle;

public class AchievementTracker : MonoBehaviour
{
[Inject] private IBattleLauncher battleLauncher;

private int battlesWon;

private void OnEnable() => battleLauncher.SubscribeToBattleEnded(OnBattleEnded);

private void OnDisable() => battleLauncher.UnsubscribeFromBattleEnded(OnBattleEnded);

private void OnBattleEnded(BattleResultParameters result)
{
if (!result.PlayerWon) return;

battlesWon++;
if (battlesWon >= 100)
UnlockAchievement("Battle Master");
}
}

Паттерн 2: запрос к базе данных​

Используйте API базы данных для создания собственных функций:

public class TypeMatchupHelper : MonoBehaviour
{
[Inject] private IMonsterCaptureEngine engine;

private IMonsterDatabase database;

private void Awake()
{
database = engine.Database;
}

public List<MonsterType> GetWeaknesses(MonsterType type)
{
var weaknesses = new List<MonsterType>();
foreach (var attackType in database.GetAllTypes())
{
if (database.GetTypeEffectiveness(attackType, type) > 1f)
weaknesses.Add(attackType);
}
return weaknesses;
}
}

Паттерн 3: интеграция с сохранением​

Храните собственные флаги и счётчики в сохранении игрока, записывая их как игровые переменные в GlobalGameData — то же хранилище, что использует CommandGraph. Они сохраняются, загружаются и сбрасываются вместе со всем остальным:

using OpenMon.MCE.Player;

// The marker interface IPlayerDataReceiver is what makes the player's data
// (GlobalGameData, Roster, CharacterData...) injectable into a class.
public class AchievementCounters : MonoBehaviour, IPlayerDataReceiver
{
[Inject] private GlobalGameData globalGameData;

public void CountBattleWon()
{
int won = globalGameData.GetVariable<int>("battlesWon");
globalGameData.SetVariable("battlesWon", won + 1);
}
}

Переменная должна существовать у держателя (определите её в игровых переменных ассета GlobalGameData). См. руководство Система сохранений.

Паттерн 4: пользовательский узел CommandGraph​

Чтобы запускать собственный C# из визуального скриптинга, напишите узел. Узел — это небольшой класс [Serializable] в вашей собственной сборке, наследующий SingleExecutionPathCommandNode; редактор перечисляет его в меню Create Command графа под последним сегментом его пространства имён:

using System;
using System.Collections;
using OpenMon.MCE.Actors.CommandGraph;

namespace MyGame.Events
{
[Serializable]
public class AwardAchievement : SingleExecutionPathCommandNode
{
[UnityEngine.SerializeField] private string AchievementId;

protected override IEnumerator Run(CommandParameterData parameterData,
Action<CommandParameterData> callback)
{
MyAchievements.Unlock(AchievementId);
yield break;
}
}
}

Узел затем появится как Create Command / Events / AwardAchievement. О контексте (CommandParameterData), который может читать узел, см. API CommandGraph.

Что нельзя сделать без исходного кода​

ОграничениеОбходной путь
Изменить саму формулу уронаДобавляйте множители через способности, предметы, статусы и приёмы (ScriptableObject); формула относится к редакциям Source и Studio
Добавить новые боевые модулиМодули — компоненты движка (редакции Source и Studio); реагируйте через события IBattleSystem
Изменить физику движенияНастройте скорость шага и типы тайлов в TileData
Изменить порядок выполнения цикла сраженияРедакции Source и Studio
Изменить макеты интерфейсаПереопределите префабы (если они доступны) или наложите свой интерфейс поверх
Нужно больше контроля?

Если публичный API кажется вам слишком ограниченным для вашего проекта, рассмотрите переход на редакцию Source. Он включает весь исходный код C# и документацию по архитектуре для глубокой настройки.

Ссылки на сборки​

Чтобы ссылаться на типы MCE в своих скриптах, ваше определение сборки (.asmdef) должно ссылаться на:

{
"references": [
"OpenMon.MCE.Runtime"
]
}

Если вы не используете определения сборок, типы MCE доступны глобально через DLL.

Рекомендации​

  1. Зависьте от интерфейсов, а не от реализаций. Используйте IMonsterCaptureEngine, а не конкретные классы.
  2. Отписывайтесь от событий. Всегда удаляйте обработчики событий в OnDisable или OnDestroy, чтобы избежать утечек памяти.
  3. Не кешируйте устаревшие данные. Запрашивайте SDK каждый раз, когда нужны актуальные данные, особенно для IPlayerData.
  4. Используйте внедрение Zenject. Избегайте FindObjectOfType и синглтонов для доступа к MCE.
  5. Смотрите справочник API. У интерфейсов SDK есть XML-документация на каждом члене. Ваша IDE покажет подсказки.