3. Core concepts
In short: A handful of ideas explain how the whole plugin works: content is data, rules are settings, state is plain serializable data, logic is separate from presentation, and everything is checked by validation. Learn them once here and every other chapter will read the same way.
3.1 Basics
3.1.1 Content is data
Everything a player meets in an RPG Saga Engine game (a class, a character, an ability, an item, an enemy group, a dialog, a quest) is a data asset you create in the Content Browser or with a Studio wizard. New content means new data, not new code or new Blueprints.
Data assets derive from URSEPrimaryDataAsset. They share a few fields:
- Display Name: the player-facing, localizable name. While it is empty, the asset name is shown, so placeholder content still reads.
- Dev Notes: design notes for your team (editor only, stripped from packaged builds).
- Balance Locked: tells the balance tools never to change this asset.
- Archetype link (editor only): the template the asset follows. See Game foundation and archetypes.
Data assets refer to each other by reference (a class lists abilities, a character names its class). Saved games never store those references as pointers: they store IDs (see below), so content can be renamed, moved or removed between versions without breaking old saves.
3.1.2 IDs and the Asset Manager
Every data asset has a Primary Asset Id: its type (the first native class name, for example RSEAbilityData) plus its asset name. Save files, runtime state and the tools use this stable ID. Two practical consequences:
- Give assets clear, stable names (
DA_Ability_Fireball,DA_Char_Hero) and avoid renaming them after players have saves. If you must, add a redirect: the save system applies Unreal's core redirects and the Asset Manager's redirects when it loads old content references. - The folders are scanned by the Asset Manager. The plugin registers its own folders (for example
/RPGSagaEngine/Data/Abilities) through its default config. The Set up the project wizard registers your content root the same way, so your assets are found at run time.
3.1.3 Gameplay tags
Gameplay Tags name the things that content and rules share: stats, resources, elements, statuses, classes, equipment kinds and story flags. The plugin uses tag families with a fixed root:
| Root | Examples of what lives there |
|---|---|
Stat.* | Stat.MaxHP, Stat.Attack, Stat.Speed, Stat.ActionPoints |
Resource.* | Resource.HP, Resource.MP, Resource.Resonance |
Element.* | damage types: fire, ice, and your own |
Class.* | one tag per class |
Trait.* | movement traits, status immunities and other granted abilities |
Equip.Type.*, Equip.Slot.* | kinds of equipment and slot types |
Ability.Type.* | ability categories (attack, skill, magic...), used to sort the battle menu |
Battle.Mode.* | Battle.Mode.Tactics, ATB, Turn, FreeTactics, Action |
Progression.Points.* | growth point currencies |
Tags are edited in Project Settings → Gameplay Tags. The plugin's own tags are in its Config/Tags files. Your tags go in your project's tag sources. Only the tags that C++ code references directly are native (RSEGameplayTags::Battle_Mode_Tactics and so on). All content tags are plain data, so you can add your own stats, elements and statuses without code.
3.1.4 Settings: the rules of your game
Global rules live in Project Settings → RPG Saga Engine, one page per system (Battle, Grid, Items, Economy, Party, Progression and more). Each page is a subclass of URSEDeveloperSettings, saved to your project's Config/DefaultGame.ini. You can edit them in three places:
- Project Settings → RPG Saga Engine → <page>;
- the Configurator (RPG Saga Engine → Configurator): every settings page in one window, grouped by domain, searchable, with validation, a Reset section to defaults button and quick test launch buttons;
- the Studio's wizards, which write settings for you and show what they will change first.
There are no tunable numbers hardcoded in the plugin. If a rule has a number, it has a setting or a field on a data asset.
3.1.5 Rules profiles
A Rules Profile (URSERulesProfile) overrides some settings for one place: a boss, a chapter, a "story mode", a genre. A profile holds one override per settings page (a section) and only stores what differs from the global settings. Everything else follows the global values.
Lookup order for a setting, in the first match wins:
- the encounter's own profile (an encounter can name one);
- the game's active profile (chosen by the story with the Set Rules Profile effect, saved with the game, default from Project Settings → RPG Saga Engine → Rules Profiles → Default Profile);
- the profile's parent, then its parent's parent, and so on;
- the global settings.
A running battle copies the profile it started with, so switching the game's profile never changes a battle in progress. Some fields are global only because they must match your content (for example the tile size of the grid, the maximum level, the starting party). A profile's value for them is ignored and validation warns when it differs.
To make a profile in the Configurator, open Rules Profiles → New profile, then Add override on the sections you want to change. Debug commands: RSE.Rules.Dump logs the active profile and its overridden sections; RSE.Rules.SetProfile <AssetName | None> switches it.
3.1.6 Feature toggles
Project Settings → RPG Saga Engine → Features has one checkbox per system (Grid Tactics, Live Tactics, ATB / Turn-Based, Action Combat, Dialog, Quests, Story Scenes, Inventory, Economy, Growth / Progression, Living NPCs, Time and Weather, Map and Minimap, Stealth, Puzzles, Cards, Bestiary, Tutorials, Adaptive Difficulty, Online and Co-op). All are on by default. A switched-off system is not created at all: its subsystems do not exist, so it costs no memory or time, and its menu pages, option rows and HUD widgets disappear.
Never switched off: the party, the save system, the story state (flags and variables), the rules and the command bus.
The Configurator's Validate button warns about combinations that leave something half-working (for example Quests on, Dialog off). For one test run only, -RSEDisableFeatures=Quests,Cards on the command line turns features off without touching your settings.
3.1.7 Validation
Data is checked in the editor with Unreal's standard Data Validation (IsDataValid), so problems appear when you save, in the Message Log and in the Content Browser. RPG Saga Engine → Validate All Data checks every setting, rules profile and data asset at once and opens the results in the Message Log under RPG Saga Engine Validation. The Studio's wizards keep Create disabled until every problem is fixed, and say why at the bottom of the window.
Run Validate All Data before you package and whenever something behaves strangely.
3.2 How it works
3.2.1 Data → rules → presentation
The plugin has three layers, and information flows one way:
data assets + settings -> rules and state (RSECore) -> presentation (RSE)
(what you author) (what happens) (what the player sees)
- Data is authored by you.
- Rules (
RSECore) read the data and compute what happens: damage, turn order, pathfinding, conditions, effects, story state. They use no actors, no widgets, no input and no rendering. - Presentation (
RSE) reads the rules' state and events and shows them: actors in the world, animation, camera, HUDs and menus.
Because rules never include presentation, a battle can run headless. The battle simulator, Test in battle, the difficulty estimates and the automated tests all play real battles with no window. Presentation reacts to what rules report through events (delegates), and sends player actions back as commands.
3.2.2 State is plain data
All runtime state (the party, inventory, story flags, quests, progression) is stored in plain structs whose saved fields are marked SaveGame. Content is referenced by soft path or ID, never by pointer. Three properties follow:
- Saving is serializing those structs. A system that wants to be saved registers a save participant with the save system, which owns one named section of the save file (
Party,Narrative,Quests...). Each section has a version number, so old saves are converted by the system that owns the section, and fields added later load as their defaults. - Missing content never crashes a load. Content removed since the save was made is dropped with a warning.
- State is the unit of networking. The same sections are what co-op replicates (see Co-op and online).
The Blueprint nodes of the Save Interop group (Export Sections To Bytes, Import Sections From Bytes and friends) let you keep plugin state inside your own SaveGame. See Save and load.
3.2.3 Commands: one path for player actions
Player actions that change shared state go through the command bus (URSECommandSubsystem). A command is a small struct (Add Party Member, Equip Item, Bind Pact, Unlock Growth Node) with a handler that validates it and then applies it:
Submit(command) -> validate -> apply -> result (Applied / Rejected / ...)
In single player it runs locally, on the spot. In a co-op session a guest's command travels to the host, which validates and applies it and sends the result back. There is one code path for every mode, so your own systems become network-ready by using it. Menus, input and Blueprint nodes all send commands; the authority's own systems (battle results, loads, story effects) write state directly.
3.2.4 Conditions and effects: one language for content
Dialogs, quests, puzzles, encounters, interactions and abilities all use the same primitives:
- a condition is a question about the game state: has the item, a flag has a value, a member is in the party, a puzzle is solved (
URSEConditionsubclasses such as Flag Is, Has Item, Member In Party, Puzzle Solved, combined with All Of, Any Of and Not); - an effect is a change: set a flag, give or take an item, add a member, give experience, start a battle, start a dialog, unlock an area (
URSEWorldEffectsubclasses such as Set Flag, Give Item, Add Member, Start Battle, Start Dialog, Unlock Area).
You add them inline in any data asset's list. Every effect also has an Only If gate. Story, dialog and quests covers the full list. Your own conditions and effects can be Blueprint classes (Extending the plugin).
3.2.5 Formulas as data
Derived stats, combat damage, hit chance and resource gains are small formulas written in data (FRSEExpression), compiled once when the project loads and evaluated without allocations. The language has numbers, + - * / % ^, comparisons, && and ||, and the functions min, max, clamp, floor, ceil, round, abs, sqrt, pow and if. Names refer to stats by short name (Stamina), to the unit with a scope (Attacker.Attack, Target.Defense) and to context variables (Level, Power). See Game foundation and archetypes.
3.3 Key classes and assets
| Class / asset | Module | Role |
|---|---|---|
URSEPrimaryDataAsset | RSECore | Base of all content definitions: name, notes, archetype link, validation. |
URSEDeveloperSettings | RSECore | Base of every settings page; subclasses appear under Project Settings → RPG Saga Engine. |
URSERulesProfile | RSECore | A set of per-section rule overrides, with an optional parent. |
URSERulesSettings | RSECore | Rules Profiles page: the default profile and session rule options. |
URSERulesSubsystem | RSECore | Holds the game's active profile and resolves the profile of a battle. |
URSEFeatureSettings | RSECore | Features page: one switch per system. |
URSECommandSubsystem | RSECore | The command bus. |
URSEWorldEffect, URSECondition | RSECore | Base classes of effects and conditions. |
FRSEExpression | RSECore | A formula written in data. |
IRSESaveParticipant | RSECore | A system's save section. |
URSESaveSubsystem | RSECore | Collects the sections, writes and reads save files. |
3.4 Settings
| Where | What |
|---|---|
| Project Settings → RPG Saga Engine → Features | One checkbox per system. All on by default. |
| Project Settings → RPG Saga Engine → Rules Profiles | Default Profile (a new game's profile) and Session Rule Options (option rows whose values are the host's in co-op). |
| Project Settings → RPG Saga Engine → Commands | Handler classes for the command bus (Blueprint or C++). |
Configurator (RPG Saga Engine → Configurator) | All pages in one window, with the Rules Profiles panel and the tools. |
Every page is documented in Appendix B.
3.4.1 Console variables and commands
Debug switches are console variables and commands under RSE.*; no debug behaviour is hardcoded. A few you will use early:
| Name | What it does |
|---|---|
RSE.Rules.Dump | Logs the active rules profile and its overridden sections. |
RSE.Rules.SetProfile <name or None> | Switches the game's rules profile. |
RSE.Party.List | Logs each party member's HP, MP, KO state and lasting statuses. |
RSE.Items.Give <Item> [Count] | Adds an item to the party inventory. |
RSE.Encounter.Debug, RSE.NPC.Debug, RSE.Camera.FramingDebug | Debug drawing and logging for encounters, NPCs and the battle camera. |
The full list is in Appendix C.
3.5 Blueprint usage
All Blueprint nodes are under the category RPG Saga. Systems that need the game's state take a hidden World Context Object, so you can call them from any actor, widget or game instance.
Reading the game's rules and state:
- Event BeginPlay
- Is Feature Enabled (Feature = Dialog)
- Branch on the result, then create your dialog button only on True.
Switching the rules profile from a graph:
- In data, prefer the story effect Set Rules Profile. In a graph, use Get Game Instance Subsystem (class
RSERulesSubsystem), then call Set Active Profile on it and pass your profile asset. - Bind to On Rules Profile Changed on the same object to refresh your UI.
Sending a command from Blueprint:
- Make Instanced Struct with the command type, for example Add Party Member.
- Fill its fields (Character = your character asset).
- Get Game Instance Subsystem (class
RSECommandSubsystem) → Submit Command. - Read the result's Status.
Most systems also have convenience nodes that do the same in one call. For example, Add Party Member in the party library sends that command for you. See Appendix A.
3.6 C++ usage
Read a rule through the active profile instead of the raw settings, so profiles keep working:
#include "Core/RSERulesSubsystem.h"
#include "Battle/Common/RSEBattleSettings.h"
int32 GetATBPartySize(const UObject* WorldContext)
{
const URSERulesProfile* Profile = URSERulesSubsystem::GetActiveProfileFor(WorldContext);
const URSEBattleSettings* Battle = RSERules::Get<URSEBattleSettings>(Profile);
return Battle->ATBPartySize;
}
Never call GetDefault<T>() for a settings class that is a rules profile section in rule code. RSERules::GetGlobal<T>() states the intent when you do want the global value.
A new settings page is a subclass of URSEDeveloperSettings:
UCLASS(Config = Game, DefaultConfig, EditInlineNew, meta = (DisplayName = "My Rules"))
class UMyRulesSettings : public URSEDeveloperSettings
{
GENERATED_BODY()
public:
// A rules profile may override this page.
virtual bool IsProfileSection() const override { return true; }
UPROPERTY(Config, EditAnywhere, Category = "Combat", meta = (ClampMin = "0"))
float MyBonus = 1.f;
};
It appears under Project Settings → RPG Saga Engine and in the Configurator automatically. Add EditInlineNew and IsProfileSection only if a profile may override it.
A system that stores its own save section registers a struct:
// In a UGameInstanceSubsystem::Initialize
URSESaveSubsystem* Save = Collection.InitializeDependency<URSESaveSubsystem>();
Save->RegisterStruct<FMyState>(TEXT("MyState"), /*Version*/ 1, this, [this] { return &State; });
// After changing State at run time (the authority only):
Save->MarkSectionChanged(TEXT("MyState"));
Gate a subsystem on a feature toggle with RSE_FEATURE_GATE(ERSEFeature::Cards) right after GENERATED_BODY(), or by calling RSEFeatures::IsEnabled from ShouldCreateSubsystem.
3.7 Advanced
- Profile sections. Only settings classes that return
truefromIsProfileSection()can be overridden. A profile's section is created inline (EditInlineNew), initialised from the global values the first time, and stores a value only if it differs. UseGetGlobalOnlyProperties()for fields that must always come from the global settings. - Writing rules code. Rule code reads settings through
RSERules::Get<T>(Profile)and never through the class default object. Battles read through their own copy of the profile (URSEBattle::GetRules<T>()). - Subsystem lookup in tests. Headless tests create subsystems with
NewObjectwithout a subsystem collection.RSESubsystemLookup::FindFor<T>(Object)finds either kind, so write rule code with it when it must run in tests. - No Tick by default. Systems use events, timers and one-shot tickers. If you add a system, do the same.
- Heavy references are soft. Mesh, texture and animation references on data assets are
TSoftObjectPtr, so loading a data asset never pulls its art in. - Save versions. Never rename a section id once saves exist. Bump the version and convert old bytes in
ReadSaveSection. - Extending the language. New conditions and effects are subclasses of
URSEConditionandURSEWorldEffect, or Blueprint classes of Custom (Blueprint). Both areEditInlineNew, so they appear in every list at once. - Plugin defaults. The plugin's
Config/Defaults/Game.iniis applied under your config at load. A key you set in yourDefaultGame.iniwins. A list you set (any+Key=or!Key=ClearArray) replaces the plugin's list.
3.8 Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| A setting you changed has no effect in a boss fight | The boss's encounter or the active rules profile overrides it | Run RSE.Rules.Dump, then edit the setting in the profile (Configurator → Rules Profiles) instead of the global page. |
| A profile's value is ignored | The field is global only | The Configurator hides global-only fields in profiles and lists them in a note. Edit the global page. |
| A system's menu page or HUD is missing | Its feature is switched off | Project Settings → RPG Saga Engine → Features. Check -RSEDisableFeatures in the command line. |
| Old saves lose a character or item after a rename | The content ID changed | Add a core redirect or an Asset Manager redirect for the old name. |
| Create is disabled in a wizard | A validation problem | Read the reason at the bottom of the window; fix it, or run Validate All Data. |
| A new settings page is under Other in the Configurator | It is not in a group | Project Settings → Editor → RPG Saga Engine Configurator → Groups: add the class to a group. |
| A guest in co-op cannot change something | The command is host-only | Host-only commands (saves, session rules, giving characters) are refused for guests by design. |
3.9 See also
- Game foundation and archetypes
- Story, dialog and quests
- Save and load
- Co-op and online
- Extending the plugin
- Product pages:
docs/product/modularity.md,docs/product/glossary.md; design notesdocs/design/rules-profiles.md,docs/design/configurator.md,docs/design/attributes.md.