Public API
The public API ships with the Indie, Pro, Source and Studio editions (the Starter keeps it closed); the full C# source is only in Source and Studio. This guide explains the stable public API surface you can use to interact with and extend MCE from your own C# scripts without coupling gameplay code to internals.
Stability is a promise about a NAME. Everything else can move between versions.
The SDK Namespace
MCE exposes its public API through the OpenMon.MCE.SDK namespace. This contains clean interfaces that provide access to the engine's subsystems without coupling your code to internal implementations.
IMonsterCaptureEngine
The main entry point. All other interfaces are accessed through this:
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}");
}
}
Properties:
| Property | Type | Description |
|---|---|---|
Database | IMonsterDatabase | Read-only access to the monster/move/item database |
Battle | IBattleSystem | Battle state and events |
Player | IPlayerData | Player's roster, money, name, badges |
SaveSystem | ISaveSystem | Save and load operations |
Version | string | MCE engine version string |
IMonsterDatabase
Query monsters, moves, abilities, items, and types:
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
The SDK contract for battle state and events:
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 and OnBattleEnded are fed by engine hooks (BattleSystemFacade.NotifyBattleStarted / NotifyBattleEnded) that the current engine does not call, so they stay idle. Observe battles through the battle launcher instead -- see Pattern 1 and the notes in IBattleSystem.
IPlayerData
Access the player's current state:
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
The SDK contract for save and load:
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}");
In the current engine engine.SaveSystem is not connected to SavegameManager: Save and Load only raise requests that nothing handles, and the events never fire. The engine saves named folders (see the Save System guide). To persist your own flags and counters with the player's save, use game variables on GlobalGameData (see Pattern 3).
Dependency Injection
MCE uses Zenject (Extenject) for dependency injection. To access SDK interfaces in your scripts, use the [Inject] attribute:
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;
}
}
If you are new to dependency injection, here is the simple version: add [Inject] above a private IMonsterCaptureEngine field, and Zenject will fill it in automatically. You do not need to call GetComponent or FindObjectOfType. The field will be populated before Start() runs, and the other SDK interfaces hang off it (engine.Database, engine.Battle, engine.Player, engine.SaveSystem).
If your script is not a MonoBehaviour managed by Zenject, you can resolve manually:
var engine = ProjectContext.Instance.Container.Resolve<IMonsterCaptureEngine>();
Inspector-Configurable Options
Many MCE systems expose configuration through the Unity Inspector without requiring code:
ScriptableObject Configuration
| Asset | Purpose |
|---|---|
MCESettings | Game-wide settings: the chance of an encounter per type (TileEncounterChance), the wild shiny chance, the experience rule, the length of a game day, the emotion balloons |
BattleConfigurationFile | The player-facing battle settings: battle style and animation speed-up |
BattleLauncher | The battle scene, the wild and trainer battle music and the default battle AI |
MonsterEntry | Monster species data |
Move | Move definitions (one concrete class per move) |
WildEncountersSet | Encounter tables, linked from each map's SceneInfo asset |
BattleAI | AI strategies, chained through their Fallback |
Component Configuration
Most MCE components expose key settings in the Inspector:
- MCECharacterController / PlayerCharacter: the speed of a step in seconds per tile, the character or monster to display.
- EncounterTile: the encounter type of the tile.
- SceneInfo (and its
SceneInfoAsset): map name, music, region, weather, encounters. - Actor and its subclasses: the CommandGraph slots (on enable, loop, interact, on demand).
Events and Callbacks
MCE does not use UnityEvent fields on its components; it raises plain C# events and callbacks that you subscribe to from your scripts. The most useful ones:
| Where | Event | Fires when |
|---|---|---|
IBattleLauncher | SubscribeToBattleLaunched, SubscribeToBattleToUnload, SubscribeToBattleEnded(Action<BattleResultParameters>) | A battle scene is launched, is about to unload, or the battle ends |
IBattleSystem | OnBattleStarted, OnBattleEnded(bool playerWon) | Reserved: the SDK facade raises them when the engine calls its hooks (not yet connected) |
Roster | OnRosterUpdated | The monsters of a roster change |
QuestManager | OnQuestStarted, OnObjectiveProgressed, OnObjectiveChanged, OnQuestCompleted, OnQuestFailed, OnRewardsGranted | The matching quest event |
PlayerEmotes (static) | Played(string balloonName) | The local player shows an emotion balloon |
To run your own C# from a graph, write a custom node (next section).
Extending MCE Without Source Code
Pattern 1: Event Listener
Create a MonoBehaviour that listens to MCE events and triggers your own logic. The battle launcher is bound in DI and notifies when a battle ends:
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");
}
}
Pattern 2: Database Query
Use the database API to build custom features:
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;
}
}
Pattern 3: Save Integration
Keep your own flags and counters in the player's save by storing them as game variables on GlobalGameData, the same store CommandGraph uses. They are saved, loaded and reset with everything else:
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);
}
}
The variable has to exist on the holder (define it in the GlobalGameData asset's game variables). See the Save System guide.
Pattern 4: A Custom CommandGraph Node
To trigger your own C# from visual scripting, write a node. A node is a small [Serializable] class in your own assembly that derives from SingleExecutionPathCommandNode; the editor lists it in the graph's Create Command menu under the last segment of its namespace:
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;
}
}
}
The node then appears as Create Command / Events / AwardAchievement. See the CommandGraph API for the context (CommandParameterData) a node can read.
What You Cannot Do Without Source Code
| Limitation | Workaround |
|---|---|
| Change the damage formula itself | Add factors through abilities, items, statuses and moves (ScriptableObjects); the formula is in the Source and Studio editions |
| Add new battle modules | The modules are engine components (Source and Studio editions); react through the IBattleSystem events |
| Change movement physics | Adjust the step speed and the tile types in TileData |
| Change how the battle loop is sequenced | Source and Studio editions |
| Modify UI layouts | Override prefabs (if exposed) or layer your own UI on top |
If you find the public API too limiting for your project, consider upgrading to the Source edition. It includes the full C# source code and architecture documentation for deep customization.
Assembly References
To reference MCE types in your scripts, your assembly definition (.asmdef) must reference:
{
"references": [
"OpenMon.MCE.Runtime"
]
}
If you are not using assembly definitions, MCE types are available globally through the DLL.
Best Practices
- Depend on interfaces, not implementations. Use
IMonsterCaptureEngine, not concrete classes. - Unsubscribe from events. Always remove event handlers in
OnDisableorOnDestroyto prevent memory leaks. - Do not cache stale data. Query the SDK each time you need current data, especially for
IPlayerData. - Use Zenject injection. Avoid
FindObjectOfTypeor singletons for MCE access. - Check the API reference. The SDK interfaces have XML documentation on every member. Your IDE will show tooltips.