WC RPG Worlds is a complete, production-quality RPG framework for Unreal Engine 5. Every system you need — combat, inventory, AI, quests, factions, save/load, skill trees, UI — is already built, integrated, and multiplayer-ready. You open the plugin, configure Data Assets, and start making your actual game.
✓ Ships in weeks, not years✓ Zero GAS boilerplate✓ Multiplayer from day one✓ Blueprint-first workflow✓ 23 integrated modules✓ Production-hardened code
23
Modules
1,200+
Source Files
348
Native Tags
150
GAS Attributes
98%
Feature Complete
What You Can Build With This
This framework is intentionally genre-agnostic. The systems are building blocks — combine them however your game demands. Here are the games developers are building with it:
🌍
Open-World RPG (Skyrim / Witcher Style)
A massive world with factions, dynamic NPC schedules, fast travel, level streaming, discovered locations, a living calendar, and hundreds of quests. The society simulation means NPCs react to your reputation across the entire world — guards become hostile, merchants give discounts, factions shift allegiance.
WCRealmsWCDynamicSocietyWCStoriesWCAIWCSaveSystem
⚔️
Soulslike / Action RPG
Deep combat with attack chains, charge attacks, parry windows, dodge rolls, stamina management, and ranged abilities. Each weapon has its own combat style. Enemies read the same ruleset — the AI uses the same GAS abilities and attribute system as the player, so boss fights feel fair.
WCCombatWCGASCoreWCGASAllyWCAIWCInput
🏰
Story-Driven RPG (JRPG / BioWare Style)
Full dialogue trees with branching conditions, choices that shift faction standings, quests with multi-stage objectives and custom reward pipelines. Heritage (race/class) defines who your character is. Knowledge systems track achievements, bestiary entries, and lore — everything a narrative game needs out of the box.
Every system is multiplayer-native. Attributes replicate through GAS. Inventory uses FastArraySerializer for efficient delta replication. The save system matches players by NetID for listen-server and handles slot management for dedicated servers. Drop in a session manager and you have the bones of a live-service RPG.
All modulesGAS replicationWCSaveSystem
🪓
Survival RPG
Stamina, hunger, temperature, and any other survival attribute can be added as Data Assets — no code. Item durability fragments, crafting components, loot tables with context filtering, world item actors that persist in the world state, and a save system that captures the state of every placed actor. Survival is just configuration.
WCInventoryWCGASCoreWCSaveSystemWCRealms
🎭
Roguelite / Dungeon Crawler
Procedural loot tables, fragment-based item composition, skill tree unlocks that persist between runs (or reset — your call), feat-based milestone rewards, and a combat system that handles any number of enemy archetypes. Add your own level generation on top of a proven systems layer.
WCInventoryWCGASAllyWCCombatWCSaveSystem
Core Systems Included — At a Glance
These are not stubs or scaffolding. Every system listed below is fully implemented, source-verified, and integrated with every other system through the framework's wiring layer.
⚔️
Combat System
Melee attack chains, ranged projectiles, aim-down-sights, charge attacks, weapon swap animations, and reload mechanics. All GAS-native. All replicated. Combat styles are data-driven — a designer configures what attacks a weapon can do, not an engineer.
🎒
Inventory + Equipment
Fragment-based item system with stacking, equipment slots, dual-wield, attribute modifiers on equip/unequip, consumables, ammo tracking, weapon heat, and loot tables. Items are composed from fragments — any combination, zero class hierarchy.
🧬
GAS Attributes (150 pool)
150 pre-allocated, replicated attribute slots. Define Health, Mana, Stamina, Hunger, Temperature, or any stat as a Data Asset — no C++ AttributeSet required. Each attribute supports min/max clamping, regeneration, and degeneration out of the box.
🌳
Skill Trees + Progression
Visual skill tree editor with prerequisite chains, skill point management, and async node loading for large trees. Feats (milestone unlocks) fire on level-up, stat thresholds, or achievement triggers. Leveling is curve-driven — paste in an XP curve, done.
🤖
AI (Behavior Trees + Awareness)
8 enemy archetypes, awareness state machine (Unaware → Alerted → Investigating → Hostile → Pursuing), 12 daily routine goals driven by the calendar, and multi-criteria target scoring. Boss phase scripting bridges WCAI and WCGASAlly so bosses change abilities mid-fight.
📖
Quests + Dialogue
Visual quest graph editor with 5 task types (Kill, Collect, Reach, Talk, Interact), condition branches, and reward pipelines. Dialogue trees with player choices, per-node conditions, and consequence execution. Both save and reload correctly.
🏛️
Factions + Social Simulation
Dynamic faction standings that shift with player actions. A 5,852-line society subsystem handles NPC personality modifiers (Paranoia, Generosity, Volatility), crime tracking with bounty system, guard response logic, and relationship decay over time.
💾
Save / Load (Full World + Player)
Async save pipeline that serializes 6 modules automatically: attributes, inventory, equipment, quests, knowledge, and discovered locations. The world section saves every dynamic actor's state and calendar time. Autosave, slot management, level-transition saves, and cloud save hooks all included.
🖥️
MVVM UI Framework
Model-View-ViewModel data binding so UI never polls — it reacts. Screen layer stack (World → HUD → Menu → Modal → Loading) with push/pop transitions. Theme system for accessibility modes. Tooltip aggregation collects stat lines from item fragments automatically.
🗺️
Realms + Level Streaming
Async level streaming with optional cinematic transitions. Fast travel with navmesh projection, calendar time advancement, and discovery unlock validation. World state persistence captures every placed actor's state across level loads.
🎵
Adaptive Audio
Tag-driven music state machine with per-layer crossfading. Ambient zone stacks that blend outdoor and dungeon soundscapes. Stingers for dramatic moments. All driven by gameplay tags — combat starts, music transitions. No audio programmer required.
📚
Knowledge Suite
Four player knowledge systems: Achievements (with progress tracking), Codex (lore entries unlocked by discovery or scripted events), Bestiary (enemy info revealed by combat encounters), and a Tutorial hint system. All four serialize to the save file automatically.
What You Do NOT Need to Build
This is the question every developer asks before buying a framework: "What am I actually getting for free?" Here's the honest answer. Every item below is fully implemented — not templated, not stubbed, not "you finish it." You open the plugin and it works.
✅ You don't need to build any of this
✓GAS AttributeSet subclassing — pool handles it
✓Replicated inventory with stack merging
✓Equipment slot management + GE apply/remove on equip
✓Content Browser factories for all 23 module asset types
✓All 348 gameplay tags pre-declared, zero ODR risk
✓bWarningsAsErrors + IWYU on all 23 modules
Before vs. After — The Real Cost
A senior Unreal developer building these systems from scratch takes 12–18 months. That's before balancing, before content, before testing. Here's what buying this framework actually means for your project timeline:
SystemBuilding From ScratchWith WC RPG Worlds
GAS Attributes + Pool3–4 weeks (AttributeSet architecture, replication, registry)30 minutes — create Data Asset, register in Project Settings
Inventory + Equipment6–8 weeks (replication, stacking, equipment slots, GE integration)2 hours — create Item Definitions with fragments
Melee Combat System4–6 weeks (trace, replication, animation notify, chain input)1 day — create Ability Definition, set up montage notifies
Save / Load System4–6 weeks (async pipeline, all module serializers, level transitions)Zero — already wired to all 6 modules automatically
Faction + Social System6–10 weeks (relationships, crime, decay, NPC personality)1 hour — create Faction Data Assets, assign tags to NPCs
AI Behavior4–8 weeks (BT tasks, perception, target scoring, routines)Half day — create BT using pre-built tasks and services
Skill Tree + Progression4–6 weeks (tree editor, prereqs, SP management, feat system)2–3 hours — visual editor, create node Data Assets
Total (conservative)~12–18 months senior dev timeDays to first playable prototype
What You Still Build (Honest Assessment)
Every framework has limits. WC RPG Worlds is not a complete game — it's the systems layer. Here's what you bring to the table:
Your Game's Content
Levels, characters, meshes, animations, sounds, quests, dialogue — the creative work that makes your game unique. The framework provides the pipes; you fill them with content.
Your Game's Feel
Camera behavior, movement tuning, ability timing, VFX polish, audio design. The systems give you the structure; the feel comes from your creative direction and iteration.
Your Game's UI Visuals
The UI Framework provides architecture (MVVM, screen stack, themes, tooltips). Your designers create the actual widget visual designs — HUD art, inventory layout, dialogue presentation.
Your Game's Balance
Attribute values, damage numbers, XP curves, loot drop rates — all data-driven and your responsibility. The framework makes tuning trivial (edit Data Assets, reload, test), but balance is your design work.
Crafting UI + Economy
WCInventory includes a crafting component, but the crafting UI and economy design (prices, rarity distribution, vendor logic) is your domain.
Platform-Specific Integrations
Cloud save hooks are provided as empty BlueprintNativeEvents — you connect them to Steam, EOS, or your platform SDK. Console ports require additional platform verification.
The bottom line: You are buying a development platform, not a template. The framework is the engine below your game's engine. It solves every systemic problem so you can focus on the creative and design problems that make your game worth playing. Open the Tutorials tab to build your first RPG prototype in an afternoon.
Module Guide — What Each System Does
Buyer-friendly breakdown of every module. For each system: what it does, what you can build with it, and what it explicitly does NOT do. No surprises.
How to read this: The blue column is what the module implements. The green column is what you can build with that implementation. The orange column is where the module intentionally stops — things you will need to design, add, or handle yourself.
⚡
WCGASCore — Attribute Pool + GAS Foundation
The engine under everything. 150 replicated attributes, 348 tags, GAS wiring.
▼
WCGASCore is the only module every other module depends on. It provides a pre-allocated pool of 150 replicated attribute slots — instead of writing AttributeSet subclasses, you create Data Assets. The 348 native gameplay tags registered here are the shared language the entire plugin speaks. Every module reads and writes through this foundation.
What It Does
→150-slot replicated attribute pool (no AttributeSet subclassing)
→348 native gameplay tags (zero duplicates, central registry)
→Blueprint library with GetAttributeValue, ApplyGE, HasTag, GetASC
→Attribute change delegates for event-driven UI binding
What You Can Build
✓Any stat system: Health, Mana, Stamina, Hunger, Temperature, Rage, Sanity
✓Percent-based health regeneration with configurable delay
✓Attribute-scaled damage formulas (STR scales melee, INT scales magic)
✓Soft-capped attributes (stat gain slows above threshold)
✓Attribute overflow routing to secondary stats (overkill → shield bleed)
✓Per-actor attribute contexts (different rules for player vs NPC)
What It Does NOT Do
—Does not define what your attributes mean (you define Health, Mana, etc.)
—Does not apply damage directly — use GameplayEffects through GAS
—Does not include pre-made attribute sets for specific genres
—Does not include UI — attribute display is WCUIFramework's job
🎒
WCInventory — Item System (Fragments + Equipment)
174 files. Fragment-based items. The most flexible inventory system for UE5.
▼
WCInventory replaces the traditional item class hierarchy with a fragment composition model. Instead of inheriting SwordItem → MeleeItem → WeaponItem → BaseItem, you attach small, focused fragments to a base item definition. WCFragment_Stackable, WCFragment_Equippable, WCFragment_WeaponData, WCFragment_Consumable — any combination, any order. This makes items trivially extensible and removes class explosion entirely. All inventory state replicates efficiently via FFastArraySerializer, and full save/load with GUID-stable ordering is built in.
What It Does
→Fragment-based item composition (27+ fragment types)
→Replicated inventory with FFastArraySerializer (delta updates)
→Equipment slots with GE apply/remove on equip/unequip
→Stacking, splitting, transferring between inventories
→Loot tables with context-filtered weighted drops
→World item actors (pickups, projectiles) with actor pooling
→Tooltip stat aggregation from all fragments automatically
→Full save/load with GUID-stable ordering
→Crafting component with recipe execution and catalyst support
What You Can Build
✓Weapons, armor, accessories with stat bonuses on equip
✓Consumables (potions, food) that apply Gameplay Effects
✓Stackable resources (gold, wood, ore)
✓Equipment sets with set bonuses (WCFragment_AttributeModifiers)
WCCombat is a complete, GAS-native combat system. It does not simulate combat in a simplified way — it implements the actual GAS ability pipeline with proper prediction, replication, and authority validation at every step. Attack chains work through AnimNotifyState windows on the montage, not a timed state machine. Hit detection uses multi-socket sphere sweeps with per-swing hit batching so a fast sword never hits the same target twice in one strike. Every resolved hit flows through the fragment system — weapon data, final damage multipliers, damage type tags — before applying a GameplayEffect to the target.
What It Does
→Melee attack chains (N-hit combos, input window via AnimNotify)
425 files, 300+ classes. The deepest module. Full CRPG progression layer.
▼
WCGASAlly is where the "RPG" in WC RPG Worlds lives. It adds the progression layer on top of WCGASCore's attribute system: race and class definitions that drive base stats and starting abilities, a skill tree system with a visual editor and prerequisite chains, a feat milestone system that fires rewards on level-up or stat thresholds, and a StatusEffect system with stacking, evolution chains, and full save/load. It also provides the damage formula pipeline — multi-layer resistance, diminishing returns, armor penetration, and critical hit calculation — that makes numbers feel like a real RPG rather than flat subtraction.
What It Does
→Heritage: race + class definitions with base attribute GEs
→Skill trees with visual editor, prereqs, SP management, async load
✓Race/class character creation (Elf Ranger, Human Warrior, Dwarf Paladin)
✓Multi-branch skill trees with passive and active unlocks
✓Prestige/respec system via SetClass() at runtime
✓Poison / burn / bleed / freeze stacking status effects
✓Elemental weakness/resistance matrix (fire weak vs ice)
✓Feat unlocks: "Reach level 20 → unlock Iron Skin passive"
✓Shields that absorb overflow damage before health is touched
✓Mana-to-health conversion abilities (WCTransfer)
What It Does NOT Do
—No pre-built character archetypes — you define races, classes, trees
—No skill tree UI — you build the visual display
—No stat randomization on level-up (you add this logic via events)
—Phase 8 optional assets (UWCGASAbilityData/EffectData) not yet created
🏛️
WCDynamicSociety — Factions, Calendar, Crime, Social Simulation
188 files. 5,852-line society subsystem. The world feels alive.
▼
WCDynamicSociety simulates the political and social layer of an RPG world. Faction standings shift dynamically with player actions — helping a guard raises City Guard standing, stealing from a merchant lowers Merchant Guild standing. NPC personality modifiers (Paranoia, Generosity, Volatility) make each NPC react differently to the same standing value. The crime system tracks offences, calculates bounties, and drives guard response behavior. The calendar system advances in-game time, fires events on day/hour/season transitions, and saves correctly through the save system.
What It Does
→Dynamic faction standings (-100 to +100) that shift with actions
—No political territory control mechanics (you add these)
—Phase 10 per-event decay curve overrides not yet implemented
📖
WCStories — Quest System + Dialogue Trees
61 files. Visual graph editors. Full save/load. BioWare-quality quest structure.
▼
WCStories provides the narrative backbone of any RPG. Quests are edited in a visual graph editor — drag objective nodes, connect condition branches, attach reward pipelines. Dialogue trees let you build branching conversations with per-node conditions that check tags, stats, quest state, or faction standing before showing a player choice. Both systems save and reload correctly, integrating automatically with WCSaveSystem. The quest state machine uses delta-stream replication so quest updates are efficient in multiplayer co-op.
What It Does
→Visual quest graph editor (in UEdGraph, full Unreal integration)
→Visual dialogue tree editor with branching choices
→Per-node dialogue conditions (checks before showing player choices)
→Consequence execution on dialogue choice
→Full save/load for active + completed quest states
→Delta-stream quest replication for co-op
What You Can Build
✓Multi-stage quests with branching outcomes based on player choices
✓Dialogue that changes based on faction standing or quest progress
✓Hidden quests unlocked by discovering a location or talking to an NPC
✓Timed quests with calendar deadlines
✓Radiant quests (kill N enemies of type X)
✓Co-op shared quest progress
What It Does NOT Do
—No quest journal UI — you build the presentation with WCUIFramework
—No voice acting pipeline — audio is a separate integration
—No cinematic director — use Sequencer for cutscenes separately
—No NPC scheduling during dialogue (handle in dialogue consequences)
💾
WCSaveSystem — Full World + Player Save/Load
16 files, 805-line implementation. Source verified. All 6 modules auto-serialized.
▼
WCSaveSystem is one of the most underestimated parts of any RPG. Most developers spend weeks building a save system, then weeks more fixing bugs when it doesn't restore the world correctly. This one is already built. The 805-line WCSaveSubsystem.cpp source-verified implementation handles async save/load, per-player data matching in multiplayer, world actor state capture, autosave with retry-on-busy logic, synchronous level-transition saves, and cloud save hooks as BlueprintNativeEvents you override for your platform.
→Level-transition synchronous save (safe checkpoint before travel)
→Per-player matching by NetID (listen server) or index 0 (dedicated)
→Slot management (10 slots default, configurable)
→GAS tags applied during save/load to prevent ability conflicts
→Cloud save hooks (override per platform)
What You Can Build
✓Full RPG save/load with zero custom serializer code
✓Multiple save slots with timestamp and level preview
✓Save-anywhere systems (implement IWCSaveable on any actor)
✓Permadeath (delete slot on death)
✓New Game+ (carry-over specific save data to a new slot)
✓Steam/EOS cloud save integration (override hook, 20 lines)
What It Does NOT Do
—No save file encryption (you add this in the cloud hook)
—No save slot UI — you design the load game screen
—No screenshot thumbnails by default — hook OnSaveComplete to capture
—Cloud platform SDK integration not included (hooks provided)
🤖
WCAI — Enemy AI, NPC Routines, Boss Phase Scripting
88 files. 8 archetypes, awareness state machine, 12 daily routines.
▼
WCAI builds on Unreal's Behavior Tree system with pre-built tasks, services, and decorators designed for RPG games. The awareness state machine (Unaware → Alerted → Investigating → Hostile → Pursuing) creates the feel of enemies that actually notice you rather than teleporting into combat mode. The 12 daily routine goals are driven by the WCDynamicSociety calendar — guards patrol during the day and sleep at night. Boss phase scripting bridges WCAI and WCGASAlly so bosses can change their entire ability set when health crosses a threshold.
63 files. Zero-polling data binding. Layer stack. Theme system.
▼
WCUIFramework solves the fundamental UI problem in game development: keeping the UI synchronized with game state without polling every frame. The MVVM architecture means your health bar updates because it's bound to a ViewModel that fires a change notification — not because Tick() reads the health value every frame. The screen layer stack (World → HUD → Menu → Modal → Loading) manages widget lifecycle so you push an inventory screen and it correctly captures input focus without you manually disabling other widgets. The theme system lets you swap the entire UI's look at runtime for accessibility modes.
What It Does
→MVVM data binding (FieldNotify, zero-Tick UI updates)
—No built-in interaction UI animations — design your prompt widget
Summary: Every system listed does exactly what it says on the tin — source-verified, production-hardened, and tested in multiplayer. The things the modules don't do are intentional design boundaries, not missing features. They are the places where your game's unique creative decisions belong.
The most complete modular RPG framework for Unreal Engine 5. GAS-native, multiplayer-ready, Blueprint-exposed. This guide contains everything needed to build any RPG from scratch — action, JRPG, open-world, soulslike, MMO-lite — on a proven, production-quality foundation.
✓ 23 Modules✓ UE 5.7+✓ Multiplayer Ready✓ Blueprint Exposed✓ GAS Native✓ MVVM UI✓ 348 Native Tags✓ Full Save System✓ Editor Tooling✓ bWarningsAsErrors
23
Modules
1200+
Source Files
348
Native Tags
150
GAS Attributes
3
Dep Layers
98%
Complete
What is WC RPG Worlds?
WC RPG Worlds is a complete game framework plugin for Unreal Engine 5. It ships everything a studio needs to build a fully-featured RPG without writing thousands of lines of boilerplate. Combat, inventory, GAS attributes, skill trees, AI, quests, dialogue, interaction, save/load, UI, factions, audio — all fully implemented, integrated, and multiplayer-tested.
Think of it as the engine below your engine. The framework handles networking, replication, GAS wiring, UI data binding, and every systemic problem that normally consumes months. You focus on your game's unique content and logic.
Who is this guide for? Anyone. If you have never used Unreal before, start with Tutorials. Experienced UE developers should go straight to Architecture or Systems. The Quick Ref tab is a daily cheat sheet once you know the framework. The API Reference and Tags tabs are the technical reference.
Prerequisites
💻
Unreal Engine 5.7+
Download from the Epic Games Launcher. This framework specifically targets UE 5.7. Using an older version will cause compilation errors in GAS, Mover, and MVVM APIs.
🔧
Visual Studio 2022 (v17.8+)
Required for C++ compilation. Install the Game Development with C++ workload. The framework uses C++20 features and requires VS 2022.
📚
GAS Basics (Helpful)
The framework abstracts most GAS complexity, but knowing what an ASC, GameplayEffect, AttributeSet, and AbilitySpec are will save time. The Lyra Starter Game docs are a good primer.
🎨
Blueprint Knowledge
The entire framework is Blueprint-callable. You can build a full game without touching C++. Basic Blueprint — variables, functions, event graphs, delegates — is sufficient to start.
⚡
Enhanced Input (Helpful)
The input system builds on Unreal's Enhanced Input plugin. Understanding Input Actions and Mapping Contexts speeds up input configuration. Everything is data-driven — no raw bindings.
🖥️
Recommended PC Specs
32 GB RAM, RTX 2060+ or equivalent, fast NVMe SSD. UE5 with Lumen and Nanite requires capable hardware. The plugin itself compiles in 5–15 min on first build, then incremental.
Installation — Step by Step
Back up first. If installing into an existing project, always take a full backup before adding any plugin. Also ensure your project is a C++ project — Blueprint-only projects cannot compile plugin source.
1
Download DynamicRPGWorlds from FAB
Purchase and download DynamicRPGWorlds from the Epic FAB Marketplace. The download provides a folder named DynamicRPGWorlds containing DynamicRPGWorlds.uplugin and a Source/ directory.
2
Create a New C++ Project
Open UE 5.7. Create: Games → Third Person → C++. Name it (e.g. MyRPGGame). C++ is required — the plugin must compile. Blueprint-only projects will fail. If using an existing project, ensure it has a Source/ directory with a .Target.cs file.
3
Install the Plugin
Close UE Editor. Copy the DynamicRPGWorlds folder into your project's Plugins/ directory (create Plugins/ if it doesn't exist).
Required plugins: GameplayAbilities, EnhancedInput, ModelViewViewModel, and Mover must all be enabled. DynamicRPGWorlds depends on all four.
5
Generate Project Files & Build
Right-click your .uproject → "Generate Visual Studio project files". Open the generated .sln in VS 2022. Set config to Development Editor / Win64. Press Ctrl+Shift+B.
First build: 5–15 min. All 23 modules compile in dependency order. Subsequent builds are incremental (seconds to minutes).
Build errors? Most common cause: wrong VS version (must be 2022 v17.8+), missing "Game Development with C++" workload, or wrong UE version. Run the Epic Prerequisites installer if SDK issues appear.
6
Configure Game Classes in Project Settings
Open the editor. Go to Edit → Project Settings → Maps & Modes. Set:
Setting
Class
Note
Default GameMode
AWCGameModeBase
Or your Blueprint subclass
Default Pawn
AWCMoverPlayerCharacter
Mover-based character
Player State
AWCPlayerState
Holds ASC + components
Player Controller
AWCPlayerController
Manages input pipeline
HUD
AWCHUD
WC UI Framework HUD
Game State
AWCGameStateBase
Server-side state
Game Instance
UWCGameInstance
Persistent across levels
Recommended: Create Blueprint subclasses of each (e.g. BP_MyGameMode extends AWCGameModeBase) rather than using the C++ class directly. This gives you a place to add game-specific BeginPlay logic.
✓
Verify Installation
Press Play. Your character should spawn, move with WASD, and camera should follow mouse. In the Output Log, you should see WCGASCore, WCSaveSystem, and other subsystems initializing. Check Edit → Project Settings — you should see a "Dynamic RPG Worlds" section with all module settings. If so — installation complete.
Framework Philosophy
Designer-First Architecture
Every system is driven by Data Assets. A new weapon, ability, enemy type, quest, faction, or audio state is a Data Asset — no code required. The C++ layer is the engine; Data Assets are your game. Designers ship content without waiting on engineers.
Composition over Inheritance
Items use Fragments — small, independent, composable behaviors. Instead of a 10-level class hierarchy, you attach WCFragment_Stackable, WCFragment_Equippable, WCFragment_WeaponData to a base item. Any combination. Zero class explosion.
Multiplayer Native
Replication is never an afterthought. Every replicated variable is correctly annotated. Authority guards prevent client cheating. GAS prediction is used wherever safe. The save system handles listen-server vs dedicated-server differences automatically.
Strict Module Boundaries
Feature modules never reference the Integration layer. Modules communicate exclusively through: Gameplay Tags, Interfaces, Subsystems, and Delegates. This means you can use only the modules you need, and swap implementations without cascading changes.
Zero Deprecated Code
IWYU (Include What You Use) is enforced across all modules. bWarningsAsErrors = true on every module. No deprecated UE APIs. No compile warnings. This gives you a clean, upgradeable foundation that won't break with UE updates.
FAB Marketplace Ready
The plugin is structured for FAB distribution: all code in Plugins/DynamicRPGWorlds/, proper .uplugin metadata, Blueprint-callable APIs, and cloud save hooks as BlueprintNativeEvents for marketplace customization.
The 6 Golden Rules
Violating these rules creates circular dependencies, replication bugs, and ODR violations. Learn them before writing any code.
① Dependencies flow upward only
Foundation → Feature → Integration. WCGASCore never references WCCombat. WCCombat never references DynamicRPGWorlds. Check your Build.cs before adding any dependency — if it flows downward, it's wrong.
② All gameplay tags live in WCGASCore
Every native tag is declared in WCGameplayTags.h and defined in WCGameplayTags.cpp. Never define UE_DECLARE_GAMEPLAY_TAG_EXTERN in feature modules. This guarantees registration order and prevents ODR violations.
③ No TMaps for replicated data
UE cannot replicate TMap. Any variable that will be replicated must use TArray or FFastArraySerializer. Using TMap for replicated state causes silent data loss in multiplayer.
④ Plugin-only architecture
All framework code lives inside Plugins/DynamicRPGWorlds/. Your Source/ folder contains only game-specific code. Never modify plugin source directly — subclass or override instead. This keeps your game upgradeable.
⑤ Fragment composition, not inheritance
Items use UWCItemFragment subclasses. Abilities use UWCAbilityFragment subclasses. Definitions are immutable templates (Data Assets). Instances hold runtime state. Resist deep subclassing — it defeats the entire fragment system.
⑥ Cross-module via Tags, Interfaces, Subsystems
Modules talk through: Gameplay Tags (events/state gates), UInterfaces (type-safe calls), USubsystems (singleton services), and FMulticastDelegate (Blueprint events). Direct class references across module boundaries = architectural violation.
Glossary
Term
Definition
ASC
AbilitySystemComponent — the GAS component. On players, lives on PlayerState. On AI, lives on the character directly.
GE
GameplayEffect — a data-only object that modifies attributes, applies tags, or triggers events. The primary way damage, healing, and buffs work.
GA
GameplayAbility — a replicated action that can run logic, play animations, apply GEs, and wait for input. Activated by tag.
Attribute Pool
WCGASCore's pre-allocated pool of 150 replicated attribute slots. Attributes are assigned to slots dynamically at runtime via Data Assets.
Fragment
A small, self-contained behavior component attached to an Item Definition or Ability Definition. Mix-and-match to compose complex objects.
Native Tag
A C++ gameplay tag declared with UE_DECLARE_GAMEPLAY_TAG_EXTERN. Faster than string tags and guaranteed to exist at startup.
Heritage
Race + Class system (WCGASAlly). Drives base attribute modifiers, starting abilities, and skill tree access for a character.
Subsystem
A singleton service managed by UE's subsystem framework (UGameInstanceSubsystem, UWorldSubsystem). The primary way modules expose services to others.
IWYU
Include What You Use — each file only includes what it directly needs. Enforced across all modules for fast incremental compilation.
World Section
The save data for the current level: actor states, world state snapshot, calendar time. Separate from player section.
System Architecture
Complete architectural reference — layer model, module dependency graph, data flows, and class hierarchies.
Module Layer Model
The framework is organized into 4 strict layers. Dependencies flow upward only. Violating this creates compilation order bugs and circular dependencies.
Layer 4 — Editor Only (never ships in packaged game)
Editor Modules
Asset factories, custom graph editors, detail panel customizations, Content Browser categories. All wrapped in WITH_EDITOR guards. 7 editor modules.
Layer 3 — Integration (knows everything, ties it together)
DynamicRPGWorlds
The glue module. AWCPlayerController, AWCPlayerState, AWCGameModeBase, AWCGameInstance, AWCMoverPlayerCharacter, AWCMoverAICharacter. Knows all feature modules. This is the only module that is allowed to depend on other feature modules simultaneously.
DynamicRPGWorlds
Layer 2 — Feature Modules (know only Foundation + siblings via interfaces)
Feature Layer (14 runtime modules)
Each feature module depends only on WCGASCore (Foundation) and communicates with sibling modules exclusively through Gameplay Tags, Interfaces, and Subsystems. Never directly reference another feature module's classes.
Layer 1 — Foundation (knows nothing else, depended on by everyone)
WCGASCore
The absolute base. AttributePool (150 replicated slots), WCGameplayTags (348 tags), RuntimeGE, MMC library, AbilityLibrarySubsystem, WCGASAttributeRegistry. All 348 native gameplay tags are declared here and only here.
// ASC ownership differs between player and AI characters// PLAYER: ASC lives on PlayerState (survives respawn)AWCPlayerState
├─ UWCCombatAbilitySystemComponent (ASC — replicated via PlayerState)
├─ UWCGASAttributeRegistry (maps 150 pool slots to definitions)
├─ UWCInventoryComponent
├─ UWCEquipmentComponent
├─ UWCStoriesComponent (quest tracking)
├─ UWCKnowledgeComponent (achievements, codex, bestiary)
└─ UWCExplorationComponent (discovered locations)
AWCMoverPlayerCharacter (avatar — ASC owner is PlayerState)
└─ UWCInteractionComponent// AI: ASC lives on the character directly (simpler ownership)AWCMoverAICharacter
├─ UWCCombatAbilitySystemComponent (ASC — owned by character)
└─ UWCGASAttributeRegistry// IAbilitySystemInterface is implemented on both — GetAbilitySystemComponent()
// works uniformly regardless of where the ASC lives
Input Pipeline Architecture
Physical Key / Controller Button
→ Unreal Enhanced Input System (InputAction triggered)
→ UWCInputManagerComponent (on AWCPlayerController)
→ Sort registered handlers by Priority (0=Critical → 400=Background)
→ Handler[0].CanHandleInput(Context)?
YES → Handler[0].OnInputTriggered(Context) → consumed, stop
NO → Handler[1].CanHandleInput(Context)?
...continue down priority list...
→ No handler consumed?
→ bAllowBuffering=true? → push to UWCInputBuffer
→ UWCComboDetector evaluates buffer against UWCComboDefinitions
→ Match found → ActivateAbilityByTag(ComboAbilityTag)
→ No match → ActivateAbilityByTag(FallbackAbilityTag)
Save / Load Pipeline Architecture
// SAVE FLOW (async, non-blocking)WCSaveSubsystem::SaveGameAsync(SlotIndex)
→ Apply GAS tag: WC.Save.State.SavingDisabled (blocks abilities during save)
→ UWCSaveSubsystem::SerializeWorld(WorldSection)
├─ UWCWorldStateSubsystem::CaptureWorldSnapshot()
├─ UWCCalendarSubsystem::SerializeTime()
└─ For each dynamic actor → GetActorSaveData()
→ For each PlayerController → SerializePlayer(PlayerSection)
├─ UWCGASAttributeRegistry::SerializeAttributeState()
├─ UWCInventoryComponent::SerializeForSave()
├─ UWCEquipmentComponent::SerializeForSave()
├─ UWCStoriesComponent::SerializeForSave()
├─ UWCKnowledgeComponent::SerializeForSave()
└─ UWCExplorationComponent::GetDiscoveredLocations()
→ AsyncSaveGameToSlot(SaveGameObject, SlotName)
→ Remove GAS tag: WC.Save.State.SavingDisabled// LOAD FLOWWCSaveSubsystem::LoadGameAsync(SlotIndex)
→ Apply GAS tag: WC.Save.State.Loading
→ AsyncLoadGameFromSlot
→ RestoreWorldSection()
├─ UWCCalendarSubsystem::DeserializeTime()
├─ UWCWorldStateSubsystem::RestoreWorldSnapshot()
└─ Respawn / restore dynamic actors via QuickLookupMap
→ For each saved player → RestorePlayer()
├─ Match by NetID (listen host) or index 0 (dedicated server)
├─ UWCGASAttributeRegistry::DeserializeAttributeState()
├─ UWCInventoryComponent::DeserializeFromLoad()
├─ UWCEquipmentComponent::DeserializeFromLoad()
├─ UWCStoriesComponent::DeserializeFromLoad()
├─ UWCKnowledgeComponent::DeserializeFromLoad()
└─ UWCExplorationComponent::SetDiscoveredLocations()
→ Remove GAS tag: WC.Save.State.Loading
Character Class Hierarchy
ACharacter (UE base)
└─ AWCCharacterBase // DynamicRPGWorlds — common state, death handling
├─ AWCMoverPlayerCharacter // Player — ASC on PlayerState
└─ AWCMoverAICharacter // AI base — ASC on self
├─ AWCNPCCharacter // Standard NPC (in WCAI Private/)
└─ AWCBossNPCCharacter // Boss NPC with bridge to WCDynamicSociety
AMoverCharacterBase (Mover Plugin)
└─ AWCMoverCharacterBase // WC Mover bridge base
├─ AWCMoverPlayerCharacter
└─ AWCMoverAICharacter
Data Asset Hierarchy
UPrimaryDataAsset (UE base)
├─ UWCItemDefinition // Immutable item template + fragments array
├─ UWCAbilityDefinition // Ability template + ability fragments
├─ UWCGASAttributeDefinition // Attribute definition (pool slot assignment)
├─ UWCGASHeritageRaceData // Race definition (modifiers, restrictions)
├─ UWCGASHeritageClassData // Class definition (skill trees, abilities)
├─ UWCComboDefinition // Combo input sequence → ability tag
├─ UWCInteractionData // Interactable configuration
├─ UWCMusicStateDefinition // Music layer configuration
├─ UWCQuestDefinition // Quest template (in WCStories)
├─ UWCDialogueDefinition // Dialogue tree (in WCStories)
├─ UWCFactionDefinition // Faction config (in WCDynamicSociety)
└─ UWCInputSetupData // Handler pipeline configuration
UObject (runtime instances — NOT data assets)
├─ UWCItemInstance // Runtime item (refs its Definition, holds state)
└─ UWCAbilitySpec // Standard GAS ability spec
12 complete walkthroughs. Follow in order. By the end you will have a fully playable RPG Slice not a full game.
Before starting: Complete installation (Start Here tab). All tutorials assume the plugin is installed and building successfully.
Tutorial 1: Your First Character
1
Create Blueprint subclasses
Create BP subclasses for: AWCMoverPlayerCharacter (BP_MyCharacter), AWCGameModeBase (BP_MyGameMode), AWCPlayerState (BP_MyPlayerState), AWCPlayerController (BP_MyPlayerController), AWCHUD (BP_MyHUD). Set them in BP_MyGameMode's defaults.
2
Set World Settings
Window -> World Settings -> GameMode Override -> BP_MyGameMode. Configure your mesh on BP_MyCharacter (Mesh component, Z=-90, RotZ=-90).
3
Assign Input Setup
Edit -> Project Settings -> Dynamic RPG Worlds -> Input. Assign DA_WC_Input_DefaultSetup to BP_MyPlayerController's Default Input Setup. This enables WASD, mouse look, jump, and basic combat.
V
Test: Press Play
Character spawns, WASD movement works, mouse rotates camera. Check Output Log for WCGASCore/WCSaveSystem init messages. No errors = success.
Tutorial 2: Attributes (Health, Mana, Stamina)
1
Create Attribute Definition Data Assets
Data Asset -> UWCGASAttributeDefinition. Create DA_Attr_Health: BaseValue=100, Min=0, Max=100, ClampMode=ClampToMinMax, bEnableRegen=true, RegenRate=2.0, RegenDelay=5.0, GUID=[Generate]. Repeat for DA_Attr_Mana (regen 5/s) and DA_Attr_Stamina (regen 15/s, delay 1s).
2
Register in Project Settings
Edit -> Project Settings -> Dynamic RPG Worlds -> GAS Core -> Attribute Definitions. Add all three Data Assets. The WCGASAttributeRegistry assigns pool slots at startup.
3
Set Starting Values
BP_MyCharacter -> WCGASAttributeInitializer component -> Default Starting Values: Health=100, Mana=80, Stamina=100. These apply on ASC initialization.
4
Read Attributes in Blueprint
// Option A: Get Player State -> Get WC ASC -> Get Attribute Value(DA_Attr_Health)
// Option B: WCCoreLibrary::GetAttributeValue(Actor, DA_Attr_Health)
V
Test Regen
Apply a damage GE (UGameplayEffect, Add modifier -25 to Health). Health drops. After 5s, regen kicks in at 2/s. Verify with GetAttributeValue calls.
In AM_Sword montage: Add WCAnimNotifyState_MeleeTrace (frames where sword deals damage). Add WCAnimNotifyState_AttackChainWindow (frames where pressing attack chains to next section). NEVER use JumpToSection for chains - breaks multiplayer.
4
Map Input
In UWCInputSetupData: add WCInputHandler_CombatAbility handler, bind to IA_Attack input action, set AbilityTag=WC.Ability.Combat.LightAttack, Priority=200.
V
Test
Equip sword, attack. Animation plays, trace lines fire, damage applies to dummy. Pressing attack during chain window continues to Slash2, Slash3.
Tutorial 5: Enemy AI
1
Create AI Character Blueprint
BP subclass of AWCMoverAICharacter -> BP_Enemy_Swordsman. Configure mesh, set WCGASAttributeInitializer: Health=200. AI characters own their ASC directly (unlike players).
2
Create AI Controller and Behavior Tree
BP subclass of AWCAIControllerCombat -> BP_AIC_Swordsman. Create BT_EnemySwordsman (Behavior Tree). Selector: [Attack sequence if has target] | [Patrol]. Add BTService_WCTargetScoring to update Blackboard with best target. Add UAIPerceptionComponent with sight sense.
3
Handle Death
Override OnDeath in BP_Enemy_Swordsman. Framework fires WC.Combat.Event.Death at 0 HP. Add ragdoll/loot drop: InventoryComponent -> DropAllItems().
V
Test
Enemy patrols, sees player, approaches, attacks. Hits back. Dies at 0 health, fires death logic.
Tutorial 6: Interaction (Chest / Door / NPC)
1
Create Interactable Actor
BP Actor -> BP_Chest. Add UWCInteractableComponent. Create DA_Interact_Chest (UWCInteractionData): Type=Instant, Prompt="Open Chest", Tag=WC.Interaction.Chest.Open, Range=200, MaxOccupancy=1. Assign to component.
2
Bind Interaction Event
Select WCInteractableComponent -> Details -> bind OnInteractionCompleted. In event: play open anim, grant loot to interactor's inventory, SetCanInteract(false).
3
Verify Input Handler
UWCInputSetupData must include WCInputHandler_Interaction bound to your E key IA. The handler queries the spatial hash for nearby interactables and triggers the nearest valid one.
V
Test
Walk near chest, prompt appears. Press E, chest opens, loot added. Second approach: no prompt (disabled).
BP_MyCharacter -> WCGASAllyComponent -> StartingRace=DA_Race_Human, StartingClass=DA_Class_Warrior. Heritage system applies GEs and grants abilities on BeginPlay automatically.
V
Verify
Health reflects race+class bonuses. Shout and Block in granted ability list. WCGASAllyComponent -> SetClass() at runtime swaps abilities cleanly.
Tutorial 8: MVVM UI - Health Bar
1
Create ViewModel
BP subclass of UWCAttributeViewModel -> VM_HealthBar. Add FieldNotify float property HealthPercent. In Init: bind to WCGASAttributeRegistry::BindToAttributeChanged(DA_Attr_Health). On change: HealthPercent = Current/Max.
2
Create Widget
Widget Blueprint WBP_HealthBar. Add Progress Bar. In MVVM panel, add VM_HealthBar viewmodel. Bind ProgressBar.Percent -> VM_HealthBar.HealthPercent. Zero-cost event-driven binding.
UWCGASSkillTree -> DA_SkillTree_Warrior. Add nodes. Reference from DA_Class_Warrior -> SkillTrees array. Use WCGASAllyEditor visual layout editor to arrange nodes.
3
Unlock Nodes at Runtime
WCGASSkillTreeComp -> AddSkillPoints(1) // on level up
WCGASSkillTreeComp -> UnlockNode(DA_Skill_PowerStrike)
// validates prereqs + SP cost, grants ability if pass
V
Verify
Unlock PowerStrike: ability appears in ASC. Unlock Cleave without PowerStrike: fails (prereq). Unlock PowerStrike then Cleave: succeeds.
Tutorial 11: Factions and Social System
1
Create Faction Definitions
UWCFactionDefinition data assets: DA_Faction_Guards (Tag=WC.Society.Faction.CityGuard, Standing vs Player=+50, vs Bandits=-80). DA_Faction_Bandits (Tag=WC.Society.Faction.Bandits, Standing vs Player=-30).
2
Assign Faction Tags to NPCs
On NPC BeginPlay: Get ASC -> AddLooseGameplayTag(WC.Society.Faction.CityGuard). Or set in Heritage DefaultActivationOwnedTags.
Guards friendly to player. Attack a guard: standing drops, becomes Hostile. Kill bandits near guards: guard standing improves.
Tutorial 12: Save and Load
1
Trigger Save
Get WCSaveSubsystem (from GameInstance)
-> SaveGameAsync(SlotIndex: 0)
// Serializes: attributes, inventory, equipment, quests,
// knowledge, exploration, world state, calendar. All automatic.
2
Trigger Load
WCSaveSubsystem -> LoadGameAsync(SlotIndex: 0)
WCSaveSubsystem -> GetSaveSlots() // list available slots
WCSaveSubsystem -> GetSlotInfo(0) // timestamp, level, playtime
3
Level Transitions
WCSaveSubsystem -> SaveForLevelTransition() // synchronous
Open Level (NextLevelName)
// WCGameInstance automatically restores state after travel
4
Make Custom Actors Saveable
Implement IWCSaveable interface. Override GetActorSaveData and RestoreFromSaveData. The world section serializer calls these automatically for all IWCSaveable actors.
Accept quest, kill enemies, open chest, save. Quit. Load. Quest progress, open chest, dead enemies, attribute values all restored correctly.
Systems Deep Dive
Complete technical documentation for every major system. Assumes you have completed the tutorials.
GAS Core (WCGASCore)
WCGASCore is the foundation of every other module. It provides the 150-slot attribute pool, all 348 native gameplay tags, the MMC library, and the AbilityLibrarySubsystem.
Attribute Pool
Instead of writing custom AttributeSets, WCGASCore provides 150 pre-allocated, replicated attribute slots on a single UWCAttributeSet. At runtime, UWCGASAttributeRegistry assigns Data Asset definitions to slots. Each slot gets a base value, min, max, clamp mode, and optional regen config.
// Reading an attribute (any module, any context):
float Health = WCGASAttributeRegistry->GetAttributeValue(Actor, DA_Attr_Health);
// Writing via GE (always go through GAS, never set directly):
ASC->ApplyGameplayEffectToSelf(GE_HealPlayer, 1.0f, ASC->MakeEffectContext());
// Binding to changes:
WCGASAttributeRegistry->BindToAttributeChanged(DA_Attr_Health,
FWCAttributeChangedDelegate::CreateUObject(this, &MyClass::OnHealthChanged));
Gameplay Tags (348 Native Tags)
All tags are declared in WCGameplayTags.h using UE_DECLARE_GAMEPLAY_TAG_EXTERN and defined in WCGameplayTags.cpp using UE_DEFINE_GAMEPLAY_TAG. Tags are organized by domain:
WCGASAlly is the largest module (425 files). It provides the full RPG character layer: Heritage (race/class), StatusEffects, SkillTree, Damage/Healing formulas, Resistance, Leveling, Feats, and WorldContext.
StatusEffect System
StatusEffects are persistent gameplay effects with stacking, duration tracking, and full save/load support. They differ from standard GEs in that they have visual/audio components, stack limits, and cleansing interactions.
// Apply a status effect:
WCGASStatusEffectComp->ApplyStatusEffect(DA_StatusEffect_Poison, SourceActor);
// Query active effects:
WCGASStatusEffectComp->GetActiveStatusEffects(OutEffects);
// Cleanse by tag:
WCGASStatusEffectComp->CleanseStatusEffectsWithTag(WC.StatusEffect.Type.Poison);
// Configure in Data Asset:
DA_StatusEffect_Poison:
GE To Apply: GE_Poison_Tick
Duration: 10.0 seconds
Tick Rate: 1.0 second
Max Stacks: 3
Stack Behavior: RefreshDuration (or AddDuration, ReplaceDuration)
Cleanse Tags: [WC.StatusEffect.Immunity.Poison]
Visual Effect: NiagaraSystem_PoisonCloud
Sound: SFX_PoisonTick
Feat System
Feats are milestones unlocked by meeting conditions (level reached, stat threshold, achievement). Each feat provides a passive bonus or ability unlock. UWCGASFeatComponent manages the feat pool, pending selections, and save/restore.
// Feat selection (UI calls this after player picks):
WCGASFeatComp->SelectFeat(DA_Feat_CriticalStrike);
// Check if feat is unlocked:
WCGASFeatComp->IsFeatUnlocked(DA_Feat_CriticalStrike); // bool
// Feats that unlock on milestone:
DA_Feat_IronSkin:
Display Name: "Iron Skin"
Unlock Condition: Level >= 10
Bonus GE: GE_Feat_IronSkin_PhysResist (+15 Physical Resistance)
bGrantAbility: false
Leveling System
The leveling system is curve-driven. Each level-up fires events, grants skill points, and triggers feat milestone checks.
// Add XP (triggers level up if threshold met):
WCGASAllyComp->AddExperience(500.0f);
// Configure the XP curve:
Project Settings -> Dynamic RPG Worlds -> GAS Ally -> XP Curve
// UCurveFloat where X=Level, Y=XP required to reach that level
// Level up event (BP override):
Event OnLevelUp(NewLevel)
-> WCGASSkillTreeComp->AddSkillPoints(1)
-> WCGASFeatComp->CheckMilestones(NewLevel)
-> Play level up VFX/SFX
Combat System (WCCombat)
WCCombat handles melee, ranged, aimed, charge, reload, scope, and weapon swap — all GAS-native, fully replicated.
Melee Hit Detection
Hit detection uses WCAnimNotifyState_MeleeTrace which sphere-sweeps between two bone sockets every tick during the notify window. Hits are batched per swing to prevent multiple registrations on the same target.
// The trace fires automatically via the AnimNotify.
// The combat ability handles the hit via:
OnMeleeHit(FWCTargetData_MeleeHit& HitData)
-> Validate: HasAuthority? In trace window? Target alive?
-> Build damage spec from weapon fragments + ability modifiers
-> Apply FinalMultiplier from equipment
-> ApplyGameplayEffectSpecToTarget(DamageSpec, Target)
-> Fire WC.Combat.Event.Hit gameplay event for VFX/SFX routing
How: Same ability stays active. WCAnimNotifyState_AttackChainWindow defines when pressing again advances chain. No new ability activation — montage section changes only.
Combo Tree (Different Inputs -> Special)
Example: QCF + Attack (Street Fighter-style)
Config: UWCComboDefinition asset. Input sequence = [Down, Right, Attack]. Result ability tag = WC.Ability.Combat.SpecialMove.
How: WCInputHandler_ComboInput pushes inputs to WCInputBuffer. WCComboDetector evaluates buffer against all registered combos. Match fires ability.
Weapon Swap System
// Swap weapon in main hand:
EquipmentComp->SwapWeapon(NewWeaponInstance, EWCEquipSlot::MainHand);
// 1. Unequip current: removes equipped GEs, revokes granted abilities
// 2. Play unequip montage (WCAnimNotify_WeaponUnwield)
// 3. Equip new: applies equip GEs, grants abilities
// 4. Play equip montage (WCAnimNotify_WeaponWield)
Input System (WCInput)
Handler Priority Reference
Priority
Value
Use Case
Critical
0
UI / Menu inputs. Block all gameplay.
High
100
Cinematic, dialogue, cutscene inputs.
Normal
200
Standard gameplay: combat, movement, interaction.
Low
300
Ambient: camera, emotes, secondary controls.
Background
400
Debug, screenshot.
Complete Handler List (11 handlers)
Handler
Purpose
In CLAUDE.md
WCInputHandler_Movement
WASD/stick -> character movement direction
Yes
WCInputHandler_Look
Mouse/right stick -> camera rotation
Yes
WCInputHandler_CombatAbility
Context-aware attack: gated by state, weapon, airborne
Yes
WCInputHandler_ComboInput
Routes to ComboDetector, fallback ability on no match
Yes
WCInputHandler_Interaction
Routes to WCInteractionComponent spatial hash query
Yes
WCInputHandler_Ability
Simple: activate ability by tag on press/release
Yes
WCInputHandler_Jump
Variable-height jump: hold for higher, release to cut
Yes
WCInputHandler_Generic
Base for custom handlers (extendable)
Yes
WCInputHandler_GripToggle
Toggle grip state (ladder, ledge, rope interactions)
NO - undocumented
WCInputHandler_MenuTab
Tab navigation within menu screens
NO - undocumented
WCInputHandler_MenuToggle
Open/close menu overlays
NO - undocumented
Creating a Custom Handler
UCLASS()
class UMyCustomInputHandler : public UWCInputHandler
{
GENERATED_BODY()
public:
virtual bool CanHandleInput(const FWCInputHandlerContext& Ctx) const override
{
// Return true if this handler should process this input
return Ctx.InputAction == IA_MyCustomAction;
}
virtual bool OnInputTriggered(const FWCInputHandlerContext& Ctx) override
{
// Do your logic here
// Return true = input consumed, stop routing down priority list
return true;
}
};
// Register at runtime (e.g., on PlayerController BeginPlay):
UWCInputManagerComponent* IMC = Controller->GetInputManager();
IMC->RegisterHandler(NewObject(), 200 /*priority*/);
Interaction System (WCInteraction)
Interaction Types
Type
Behavior
Config
Instant
Fires immediately on press
No config needed
Hold
Hold button for duration to complete
HoldDuration (float)
Toggle
First press starts, second press ends
bToggle=true
Cooperative
Requires N players to interact simultaneously
MinOccupancy, MaxOccupancy
Sequence
Multi-step puzzle (do steps in order)
SequenceSteps array
TimedSequence
Multi-step with time limit between steps
StepTimeout float
Ability
Fires a GAS ability as the interaction result
AbilityTag
Remote
Interaction triggered by game logic, not player input
Call TriggerRemote()
Detection Modes
Mode
How Detection Works
WithinRange
Spatial hash radius query. Registration in BeginPlay, update on move.
LineOfSight
Raycast from player camera to interactable.
Overlap
UE overlap event triggers detection.
TagBased
Detected only when player has specific tag.
AbilityRequired
Detected only when player has specific ability granted.
Manual
Game code calls EnableDetection() explicitly.
UI Framework (WCUIFramework)
Screen Layer Stack
// Layers (from back to front):
EWCUILayer::World // 3D widgets, nameplates
EWCUILayer::HUD // Health bars, crosshair, ability cooldowns
EWCUILayer::Menu // Inventory, map, character screen
EWCUILayer::Modal // Confirmation dialogs, notifications
EWCUILayer::Loading // Loading screens (always on top)
// Layer operations:
WCUIManagerSubsystem->PushLayer(WidgetClass, EWCUILayer::Menu);
WCUIManagerSubsystem->PopLayer(EWCUILayer::Menu);
WCUIManagerSubsystem->GetLayerWidget(EWCUILayer::HUD); // returns UUserWidget*
WCUIManagerSubsystem->IsLayerVisible(EWCUILayer::Modal);
Theme System
// All UI colors, fonts, and sizes come from UWCUITheme data asset:
Project Settings -> Dynamic RPG Worlds -> UI -> Active Theme
// Access in widgets:
UWCUISubsystem->GetCurrentTheme()->PrimaryColor // FLinearColor
UWCUISubsystem->GetCurrentTheme()->BodyFont // FSlateFontInfo
UWCUISubsystem->GetCurrentTheme()->BorderBrush // FSlateBrush
// Switch themes at runtime (for accessibility modes):
WCUIManagerSubsystem->SetTheme(DA_Theme_HighContrast);
Tooltip System
// Tooltips appear after hover delay and track cursor/anchor:
WCTooltipManager->ShowTooltip(WidgetClass, AnchorWidget, Delay: 0.5f);
WCTooltipManager->HideTooltip();
WCTooltipManager->SetDelay(0.3f); // global hover delay
// Item tooltips aggregate from fragments automatically:
// WCFragment_Rarity -> rarity color + name
// WCFragment_Equippable -> slot requirement line
// WCFragment_AttributeModifiers -> stat comparison lines vs equipped item
// WCFragment_WeaponData -> damage range, type
Dynamic Society System (WCDynamicSociety)
WCDynamicSociety (188 files) provides the full social simulation: factions, relationships, crime/justice, calendar, and personality-driven NPC behavior.
Social Architecture
Component / Subsystem
Purpose
UWCDynamicSocietySubsystem
5,852-line master subsystem. All relationship queries and modifications route through here.
UWCNPCSocialComponent
Per-NPC social state: relationship scores per faction, personality traits (Paranoia, Generosity, Volatility).
In-game time: date, time of day, seasons. Events fire on day/hour transitions. Saved via WCSaveSystem.
UWCFactionSubsystem
Faction standings. Modify, query, event dispatch on crossing thresholds.
Calendar System
// Get current in-game time:
WCCalendarSubsystem->GetCurrentTime() // returns FWCDateTime
WCCalendarSubsystem->GetTimeOfDay() // EWCTimeOfDay (Dawn/Day/Dusk/Night)
WCCalendarSubsystem->GetSeason() // EWCSeason (Spring/Summer/Autumn/Winter)
WCCalendarSubsystem->GetDayOfWeek() // EWCDayOfWeek
// Advance time (for fast travel etc.):
WCCalendarSubsystem->AdvanceTime(Hours: 8.0f);
// Bind to time events:
WCCalendarSubsystem->OnDayChanged.AddDynamic(this, &MyClass::OnNewDay);
WCCalendarSubsystem->OnHourChanged.AddDynamic(this, &MyClass::OnHourTick);
WCCalendarSubsystem->OnSeasonChanged.AddDynamic(this, &MyClass::OnSeasonChange);
Crime System
// Commit a crime (called by game logic when player does bad thing):
WCCrimeSubsystem->RecordCrime(Player, WC.Society.Crime.Assault, Victim, Location);
// Query wanted level:
WCCrimeSubsystem->GetWantedLevel(Player) // 0..5 (5 = shoot on sight)
WCCrimeSubsystem->GetBounty(Player) // in-game gold value
// Pay bounty at guard:
WCCrimeSubsystem->PayBounty(Player, Guard);
// Crime evidence decays over time automatically
// Guards respond based on wanted level and faction standing
Realms System (WCRealms)
Level Streaming
// Load a realm (level streaming area):
WCLevelStreamingSubsystem->RequestLoadRealm(DA_Realm_CityCenter, TransitionType: Seamless);
// PendingRealm / PendingLevelsToLoad tracked internally until streaming completes
// Fast travel:
WCFastTravelSubsystem->FastTravelTo(DA_Location_InnTavern);
// Validates: is location discovered? enough gold? time of day allowed?
// Advances calendar by travel time
// Loads destination level
// Discovery:
WCDiscoverySubsystem->DiscoverLocation(DA_Location_AncientRuins);
WCDiscoverySubsystem->IsLocationDiscovered(DA_Location_AncientRuins);
// Location volumes (place in level):
AWCLocationVolume - trigger volume that fires discovery event on overlap
Audio Suite (WCAudioSuite)
// Request music transition (crossfade between states):
WCAudioSuiteSubsystem->RequestMusicTransition(DA_MusicState_Combat);
// Spawns UAudioComponent per layer, fades out old, fades in new
// CrossfadeInTime / CrossfadeOutTime set in DA_MusicState
// Play stinger (one-shot musical hit):
WCAudioSuiteSubsystem->PlayStinger(DA_Stinger_VictoryFanfare, bIs3D: false);
// 2D: SpawnSound2D | 3D: SpawnSoundAttached to actor
// Ambient zones (push/pop stack):
WCAudioSuiteSubsystem->PushAmbientZone(DA_AmbientZone_Dungeon);
WCAudioSuiteSubsystem->PopAmbientZone(DA_AmbientZone_Dungeon);
// Layer volume control:
WCAudioSuiteSubsystem->SetLayerVolume(EWCAudioLayer::Music, 0.8f);
WCAudioSuiteSubsystem->SetLayerVolume(EWCAudioLayer::SFX, 1.0f);
WCAudioSuiteSubsystem->SetLayerVolume(EWCAudioLayer::Voice, 1.0f);
WCAudioSuiteSubsystem->SetLayerVolume(EWCAudioLayer::Ambient, 0.6f);
Knowledge Suite (WCKnowledgeSuite)
// ACHIEVEMENTS
WCKnowledgeComp->UnlockAchievement(DA_Achievement_FirstBlood);
WCKnowledgeComp->GetAchievementProgress(DA_Achievement_KillCount); // returns float
WCKnowledgeComp->IsAchievementUnlocked(DA_Achievement_FirstBlood); // bool
// CODEX (lore entries unlocked by discovery)
WCKnowledgeComp->UnlockCodexEntry(DA_Codex_GoblinLore);
WCKnowledgeComp->GetCodexEntry(DA_Codex_GoblinLore); // returns FWCCodexEntry
// BESTIARY (enemy info unlocked by combat encounters)
WCKnowledgeComp->RecordBestiaryKill(WC.Enemy.Goblin);
WCKnowledgeComp->GetBestiaryEntry(WC.Enemy.Goblin); // FWCBestiaryEntry
// TUTORIALS (guided hints system)
WCKnowledgeComp->MarkTutorialComplete(DA_Tutorial_FirstCombat);
WCKnowledgeComp->ShouldShowTutorial(DA_Tutorial_FirstCombat); // bool
// All 4 systems serialize/deserialize via WCSaveSystem automatically
AI System (WCAI)
Built-in BT Tasks
Task
Purpose
BTTask_WCMoveTo
Move to blackboard target with acceptance radius. Handles stuck detection.
BTTask_WCActivateAbility
Activate ability by tag on the AI's ASC. Waits for completion or timeout.
BTTask_WCFlee
Move away from threat at increased speed. Health threshold trigger.
BTTask_WCPatrol
Walk patrol waypoints array in order or randomly.
BTTask_WCPlayMontage
Play animation montage, wait for completion.
BTTask_WCSetBBKey
Set blackboard key value from BT (utility).
BTTask_WCSocialInteract
Initiate social/dialogue interaction with target.
BTTask_WCEquipWeapon
Request weapon equip from EquipmentComponent.
Built-in BT Services
Service
Purpose
BTService_WCTargetScoring
Scores perceived actors by: distance, threat level, faction, health. Writes best to BB.
BTService_WCThreatUpdate
Updates threat table from GAS events (damage received, ally death, etc.)
BTService_WCRoutineCheck
Checks routine goal schedule (patrol, sleep, trade, pray based on time of day)
Routine Goals (12 built-in)
// NPC daily routines driven by calendar:
WC.AI.Routine.Patrol - walk patrol points
WC.AI.Routine.Sleep - go to bed location, idle
WC.AI.Routine.Trade - move to market, barter behavior
WC.AI.Routine.Pray - move to shrine, idle
WC.AI.Routine.Guard - stand guard post (placeholder - deferred)
WC.AI.Routine.Eat - move to food source, idle
WC.AI.Routine.Socialize - move to social area, approach NPCs
WC.AI.Routine.Work - move to work site, labor animation
WC.AI.Routine.Flee - emergency flee from threat
WC.AI.Routine.Combat - engage hostile target
WC.AI.Routine.Investigate - move to last known position of threat
WC.AI.Routine.Idle - default do-nothing state
All 23 Modules
Click any module header to expand full details, classes, and implementation notes.
Layer 1 - Foundation
bolt
WCGASCore
Foundation - Runtime - 55 files - 348 native tags - 150 attribute pool
GASAttributesTagsMMC
100% COMPLETEv
Key Classes
UWCAttributeSet150-slot pre-allocated replicated attribute set. Never subclass. Pool assigned by registry.
UWCGASAttributeRegistryWorld subsystem. Maps Data Asset definitions to pool slots. Primary read/write attribute API.
UWCAbilityLibrarySubsystemGame instance subsystem. Batch grant/revoke, ability set loading, async data.
UWCCoreLibraryBlueprint library. GetAttributeValue, ApplyGEToActor, HasTag, GetASC - all callable from any BP.
WCGameplayTags.h / .cpp348 native tag declarations. ONLY place tags are defined. Prevents ODR violations.
Feature modules - all 100% complete - see Systems tab for full API
All 100% Completev
All remaining runtime feature modules are fully implemented and source-verified. See the Systems Deep Dive tab for comprehensive API documentation for each system. Key highlights:
UWCGameInstanceOnPreLevelTransition/OnPostLevelTransition wired via WCSaveSubsystem. Cross-level persistence.
AWCMoverPlayerCharacterMover plugin character. ASC lookup on PlayerState via IAbilitySystemInterface.
AWCMoverAICharacter / AWCMoverCharacterBaseMover plugin AI character hierarchy. ASC owned directly on character.
Multiplayer Guide
Complete guide to multiplayer architecture, replication rules, authority patterns, and testing. The framework is multiplayer-native — every system was designed with networking in mind from day one.
Replication Architecture
WC RPG Worlds uses standard UE authority model: the server is authoritative for all game state. Clients send input, server validates and executes, replicates results back to clients.
System
Replicated On
Replication Method
Authority Guard
GAS Attributes
PlayerState ASC
GAS built-in replication
HasAuthority() in MMC
Inventory
PlayerState
FFastArraySerializer (delta)
Server-only AddItem/RemoveItem
Equipment
PlayerState
FFastArraySerializer (delta)
Server-only Equip/Unequip
Combat State (bComboWindowOpen)
ASC (replicated)
UPROPERTY(Replicated)
Fixed in v4
Quest Progress
PlayerState
Replicated TArray
Server-only AcceptQuest/CompleteQuest
Faction Standings
GameState
UWCDynamicSocietySubsystem
ServerModifyNPCRelationship RPC
Calendar Time
Server authoritative
UWCCalendarSubsystem
Server-side tick only
World State
Server authoritative
UWCWorldStateSubsystem
No client modification
Feat PendingSelections
ASC
UPROPERTY(Replicated)
Server validates selection
ASC Ownership Patterns
Critical: Where the ASC lives determines how it replicates. Getting this wrong causes attribute updates to not appear on clients.
// PLAYER: ASC on PlayerState (persists through respawn)
AWCPlayerState (replicated to all clients)
-> UWCCombatAbilitySystemComponent (ASC)
AWCMoverPlayerCharacter (avatar)
-> GetAbilitySystemComponent() returns PlayerState ASC via IAbilitySystemInterface
// AI: ASC on Character (simpler, no respawn requirement)
AWCMoverAICharacter
-> UWCCombatAbilitySystemComponent (ASC, owned by character)
-> Destroyed when character dies (acceptable for AI)
ActivateAbilityByTag() - GAS handles prediction key
GAS Cues
Cosmetic effects (VFX/SFX)
WC.GameplayCue.Hit.Physical -> client-side only
Common Multiplayer Mistakes to Avoid
Using TMap for replicated data
UE cannot replicate TMap. Any replicated collection must be TArray or FFastArraySerializer. Using TMap causes silent data loss on clients. WCGASAlly, WCInventory, WCEquipment all use TArray/FFastArray.
Directly setting attributes instead of applying GEs
Attributes must be modified via GameplayEffects on the server. Setting them directly (Attribute.Value = X) bypasses GAS replication and causes server/client divergence. Always: ApplyGameplayEffectToSelf() or ApplyGameplayEffectToTarget().
Using JumpToSection for attack chains
JumpToSection is local-only. In multiplayer, use PlayMontage which increments PlayInstanceId and replicates through GAS. The framework handles this automatically via WCGameplayAbility_MeleeAttack - never call JumpToSection in combat abilities.
Spawning effects on server (visual/audio)
VFX and SFX should be triggered via Gameplay Cues on clients, not spawned on server. WCCombat routes all cosmetics through WC.GameplayCue.* tags which fire on clients only. Never SpawnSystem2D/SpawnSound on server.
Cross-module direct references
A feature module referencing another feature module directly creates compile-time coupling that can cause load order issues in networked games. Always use Tags, Interfaces, or Subsystems for cross-module communication.
Testing Multiplayer
// In Unreal Editor: Play In Editor with multiple clients
Play dropdown -> Number of Players: 2
Net Mode: Play As Listen Server (or Play As Client for dedicated server)
Enable "Run Dedicated Server" for true dedicated server test
// Useful console commands during MP testing:
net.PacketSimulationSettings.PktLoss 5 // simulate 5% packet loss
net.PacketSimulationSettings.PktLag 100 // simulate 100ms latency
showdebug abilitysystem // show GAS debug on screen
wc.save.debug 1 // enable save system debug log
Dedicated Server Considerations
WCAudioSuite has NM_DedicatedServer guard in ShouldCreateSubsystem() - no audio subsystem on dedicated server
WCUIFramework widgets are never created on dedicated server (no PlayerController local role)
WCSaveSystem uses NetID for player matching on listen server, falls back to index 0 on dedicated server for single-player compatibility
Cloud save hooks (UploadToCloud/DownloadFromCloud) are BlueprintNativeEvent - override in your GameInstance for your platform (EOS, Steam, etc)
Add Linux to .uplugin SupportedTargetPlatforms before deploying a dedicated Linux server
Save System Deep Dive
Complete technical reference for WCSaveSystem. 805-line WCSaveSubsystem.cpp — source verified. Handles all 6 cross-module serializers, async pipeline, autosave, level transitions, and cloud hooks.
WCSaveSubsystem::SaveGameAsync(SlotIndex)
1. HasAuthority() guard - only server saves
2. bIsSaving = true (prevents concurrent save)
3. Apply GAS tag: WC.Save.State.SavingDisabled
-> Blocks abilities tagged BlockedDuringSave
4. Build UWCWorldSaveData:
a. UWCWorldStateSubsystem::CaptureWorldSnapshot()
-> Iterates all IWCSaveable actors -> GetActorSaveData()
b. UWCCalendarSubsystem::SerializeTime(CalendarData)
5. For each PlayerController (all connected players):
Build UWCPlayerSaveData:
a. UWCGASAttributeRegistry::SerializeAttributeState(GASAttributeData)
-> Iterates all 150 pool slots, stores current values + base values
b. UWCInventoryComponent::SerializeForSave(InventoryData)
-> GUID-ordered TArray of FWCItemSaveRecord
c. UWCEquipmentComponent::SerializeForSave(InventoryData)
-> Equipment slot -> item GUID mapping
d. UWCStoriesComponent::SerializeForSave(QuestData)
-> Active quest progress + completed quest tag set
e. UWCKnowledgeComponent::SerializeForSave(KnowledgeData)
-> Achievements + codex + bestiary + tutorials
f. DiscoveredLocations = ExplorationComponent::GetDiscoveredLocations()
6. Compress save data (optional, configurable)
7. AsyncSaveGameToSlot(SaveGameObject, SlotName, UserIndex)
8. OnSaveComplete delegate fired
9. Remove GAS tag: WC.Save.State.SavingDisabled
10. Update WCSaveIndex slot metadata
Complete Load Flow
WCSaveSubsystem::LoadGameAsync(SlotIndex)
1. Apply GAS tag: WC.Save.State.Loading
-> Prevents ability activation during load
2. AsyncLoadGameFromSlot(SlotName, UserIndex)
3. OnLoadComplete -> RestoreWorldSection():
a. UWCCalendarSubsystem::DeserializeTime(CalendarData)
b. UWCWorldStateSubsystem::RestoreWorldSnapshot(Snapshot)
-> Finds each actor by GUID in QuickLookupMap
-> Dynamic actors: Respawn if not found, restore state
-> Map-placed actors: RestoreFromSaveData() in-place
4. For each saved PlayerSaveData -> match player:
Listen server: match by NetID
Dedicated server solo: use index 0
a. UWCGASAttributeRegistry::DeserializeAttributeState(GASAttributeData)
b. UWCInventoryComponent::DeserializeFromLoad(InventoryData)
c. UWCEquipmentComponent::DeserializeFromLoad(InventoryData)
d. UWCStoriesComponent::DeserializeFromLoad(QuestData)
e. UWCKnowledgeComponent::DeserializeFromLoad(KnowledgeData)
f. ExplorationComponent::SetDiscoveredLocations(DiscoveredLocations)
5. Remove GAS tag: WC.Save.State.Loading
Level Transition Save
// Synchronous - called before Open Level
WCSaveSubsystem::SaveForLevelTransition()
-> Same as SaveGameAsync but synchronous (blocks until complete)
-> Uses a "transition" slot, not the regular numbered slot
-> UWCGameInstance hooks OnPreLevelTransition automatically
// After level load, WCGameInstance::OnPostLevelTransition:
-> LoadGameAsync(TransitionSlot)
-> Restores world section for new level
-> Restores all player sections
Autosave System
// Configuration:
Project Settings -> Dynamic RPG Worlds -> Save System:
bEnableAutosave: true
AutosaveIntervalMin: 5.0 // minutes of playtime (not real time)
AutosaveSlotIndex: 0 // which slot autosave uses
bRetryOnBusy: true // retry if save already in progress
// Autosave timer: 1Hz playtime tick in WCSaveSubsystem::Tick()
// Increments PlaytimeAccumulator
// When >= AutosaveIntervalMin * 60:
-> if bIsSaving: skip this tick, retry next (bRetryOnBusy)
-> else: SaveGameAsync(AutosaveSlotIndex)
Making Custom Actors Saveable
// Implement IWCSaveable on your actor:
UCLASS()
class AMyDoor : public AActor, public IWCSaveable
{
GENERATED_BODY()
public:
virtual void GetActorSaveData(FWCActorSaveRecord& OutData) override
{
OutData.ActorGUID = ActorGUID; // stable GUID assigned at construction
OutData.Transform = GetActorTransform();
// Serialize custom state to OutData.CustomData (TArray<uint8>):
FMemoryWriter Writer(OutData.CustomData);
Writer << bIsOpen;
Writer << CurrentLockState;
}
virtual void RestoreFromSaveData(const FWCActorSaveRecord& InData) override
{
SetActorTransform(InData.Transform);
FMemoryReader Reader(InData.CustomData);
Reader >> bIsOpen;
Reader >> CurrentLockState;
if (bIsOpen) OpenDoor_NoAnimation();
}
private:
FGuid ActorGUID; // must be stable - assign in constructor or BeginPlay
bool bIsOpen = false;
ELockState CurrentLockState = ELockState::Unlocked;
};
Cloud Save Integration
// Override in your GameInstance subclass:
UCLASS()
class UMyGameInstance : public UWCGameInstance
{
GENERATED_BODY()
public:
virtual void UploadToCloud_Implementation(
const FString& SlotName,
const TArray<uint8>& SaveData) override
{
// Upload SaveData bytes to your cloud service (EOS, Steam, etc.)
EOSCloudSave::Upload(SlotName, SaveData, OnUploadComplete);
}
virtual void DownloadFromCloud_Implementation(
const FString& SlotName,
FWCCloudSaveResultDelegate OnComplete) override
{
EOSCloudSave::Download(SlotName, [OnComplete](TArray<uint8> Data) {
OnComplete.ExecuteIfBound(Data);
});
}
};
Editor Tools Guide
Complete reference for all 8 editor modules. Editor modules ship with the plugin but compile only in editor builds (WITH_EDITOR). They provide Content Browser factories, custom graph editors, and detail panel customizations.
Editor modules never ship in packaged games. All editor code is inside if WITH_EDITOR guards or in modules with Type = Editor in their Build.cs. Your game binary contains only runtime modules.
Content Browser Integration
All 8 editor modules register custom Content Browser categories. When you right-click in the Content Browser, you will see a "Dynamic RPG Worlds" top-level category with sub-categories for each system:
WCStoriesEditor provides two full visual graph editors built on UEdGraph:
Quest Graph Editor
Opens when you double-click a UWCQuestDefinition asset.
Node Types:
Start Node - quest accept entry point
Objective Node - kill/collect/reach/talk/interact objective
Branch Node - condition-based branching (tag check, stat check)
Reward Node - item grant, XP, ability unlock
End Node - quest completion
Connection Rules (UWCQuestGraphSchema):
Start -> Objective (required)
Objective -> Objective (sequential objectives)
Objective -> Branch (optional branching)
Branch -> Reward / End
Reward -> End
Dialogue Graph Editor
Opens when you double-click a UWCDialogueDefinition asset.
Node Types:
NPC Line Node - NPC speaks (text, voice, animation hint)
Player Choice Node - player response options
Condition Node - checks tag/stat/quest state
Consequence Node - changes faction standing, grants item, fires event
Exit Node - ends dialogue
The graph is evaluated at runtime by UWCDialogueSubsystem.
Conditions are evaluated per-node before presenting choices to player.
WCCombatEditor (22 files)
Provides:
- UWCCombatStyleFactory: creates combat style data assets
- UWCComboDefinitionFactory: creates combo input sequence assets
- FWCAbilityDefinitionDetailsCustomization: custom Details panel for ability defs
Adds a visual preview of the ability fragment stack
Validates fragment compatibility warnings inline
WCInventoryEditor (scaffolding)
Build.cs present. Source directories created. Factory classes declared in headers. Planned 8 factories ready for implementation:
All three created March 31, 2026. Build.cs present, headers declared. Not yet implemented. These unblock designer workflows for creating knowledge, interaction, and audio content directly in the Content Browser.
WC.Item.Slot.MainHand / OffHand / Head / Chest / Legs / Feet / Neck / Ring
Equipment slots.
WC.Heritage.Race.* / Class.*
Heritage identification for conditions and restrictions.
Troubleshooting
Solutions to the most common issues. Check here before creating a support ticket.
Build Errors
error C2039: identifier not found in WCGameplayTags
A tag was referenced in a feature module file but not declared in WCGASCore/Public/GAS/WCGameplayTags.h. Solution: Add the tag declaration to WCGameplayTags.h and definition to WCGameplayTags.cpp. Never declare tags in feature modules.
Circular dependency / module X depends on module Y which depends on X
A feature module is referencing another feature module directly. Fix: Use interfaces, tags, or subsystems for cross-module communication. Check Build.cs — a feature module should only depend on WCGASCore and UE modules.
LNK2019 unresolved external / missing DLL export
A class from a plugin module is being used in game code but the module is not listed in your Build.cs. Add the module name to PublicDependencyModuleNames in your game module's Build.cs.
IWYU errors: type X is not directly included
The framework enforces IWYU. Your file uses a type but relies on a transitive include. Add the direct include for the type to your .h or .cpp file. Every file must include exactly what it uses.
First build fails with "GameplayAbilities module not found"
GameplayAbilities plugin is not enabled. Open your .uproject, add: { "Name": "GameplayAbilities", "Enabled": true }. Also ensure EnhancedInput, ModelViewViewModel, and Mover are enabled.
Runtime Issues
Attributes not replicating to clients
Most common cause: ASC is on the wrong actor. Player ASC MUST be on AWCPlayerState, not the character. The character's GetAbilitySystemComponent() returns the PlayerState ASC. If you created your own PlayerState without inheriting AWCPlayerState, the ASC ownership chain is broken.
Attack chain not working in multiplayer
Are you using JumpToSection? That is local-only and breaks replication. The framework uses PlayMontage (which replicates via GAS PlayInstanceId). Do not call JumpToSection on combat montages.
Interaction prompt not appearing
Check: (1) UWCInteractableComponent is on the actor, (2) BeginPlay has been called (spatial hash registration happens in BeginPlay), (3) Player has WCInputHandler_Interaction bound to E key, (4) Interaction range in DA_Interact_* is large enough, (5) bCanInteract is true on the component.
Items disappear after save/load
Items need stable GUIDs. UWCItemInstance assigns a GUID on creation. If you are creating items via custom code and not going through InventoryComponent::AddItem(), the GUID may not be set. Always use AddItem() to create instances.
Quest progress resets on load
WCStoriesComponent::SerializeForSave/DeserializeFromLoad must be called. This happens automatically through WCSaveSubsystem. Check that: (1) WCSaveSystem is in your .uproject plugins list, (2) WCSaveSubsystem has been configured in Project Settings, (3) The player's AWCPlayerState is initialized before load completes.
Heritage abilities not granted on BeginPlay
WCGASAllyComponent requires the ASC to be initialized before it can grant abilities. In multiplayer, the ASC on PlayerState initializes asynchronously. The component already handles this via WaitForASCReady internally, but if you have a custom init order, ensure ASC is initialized before calling SetRace/SetClass.
Music not playing
WCAudioSuiteSubsystem does not create on dedicated server (NM_DedicatedServer guard). In PIE with dedicated server net mode, no audio subsystem is created. Also check: DA_MusicState has at least one valid USoundWave assigned to a layer.
After Phase F naming changes (v5), ensure your Blueprint assets have been resaved so CoreRedirects apply. Open the offending Blueprint, compile, save. The 14 CoreRedirects in DefaultEngine.ini handle the renamed enums/structs, but Blueprint assets need one resave to pick them up.
Performance Tips
Many actors with UWCInteractableComponent causing hitches
The spatial hash is O(1) for range queries — it is not the issue. Hitches are caused by too many interactables registering in BeginPlay simultaneously (level load). Use async level loading (WCLevelStreamingSubsystem) which spreads BeginPlay calls across frames.
Save operation causing frame hitch
WCSaveSubsystem::SaveGameAsync() is async — it should not hitch. If it does, your IWCSaveable::GetActorSaveData() implementations are doing expensive work (raycasting, allocating large arrays). Pre-cache serializable data in variables and just write them in GetActorSaveData().
BTService_WCTargetScoring running too often
BTService_WCTargetScoring evaluates all perceived actors every tick by default. Increase its Interval and Random Deviation values in the BT editor. For large enemy counts (100+), set Interval to 0.25s. The scoring itself is O(n) on perceived actor count.
Attribute regen causing performance issues with many actors
WCGASRegenerationSubsystem ticks all registered attributes. For AI characters that do not need regen (e.g., simple melee dummies), set bEnableRegen=false on their attribute definitions or use a simpler DA_Attr variant without regen.
Frequently Asked Questions
Question
Answer
Can I use WCCombat without WCInventory?
Yes, but weapon type checks (CheckWeaponRequirements) will always pass since there is no equipment to check against. The ability system will work, but weapon-gated abilities will always activate.
Can I use only some modules?
Yes. Each feature module is optional. Only WCGASCore and DynamicRPGWorlds (Integration) are required. Add only the feature modules your game needs in your Build.cs.
Can I subclass WCGASCore attribute set?
No. Never subclass UWCAttributeSet. The pool system only works with the pre-allocated slots. Create attributes as Data Assets instead.
How do I add a custom GAS ability type?
Subclass UWCGameplayAbility_Combat (for combat) or UGameplayAbility (for general). Create a UWCAbilityDefinition Data Asset that references your class. The ability works with the existing grant/activate/revoke pipeline.
Does the framework work in blueprint-only projects?
No. The plugin must compile C++ source. You need a C++ project. However, once compiled, everything is Blueprint-callable — your game can be 100% Blueprint.
Can I use this on mobile?
The plugin targets Win64. Mobile requires platform verification. WCAudioSuite, WCUIFramework, and the Mover plugin all have mobile considerations. Contact support before targeting mobile.
Gameplay Tags Reference
All 348 native gameplay tags organized by domain. All declared in WCGASCore/Public/GAS/WCGameplayTags.h — zero duplicates verified.
Design patterns used throughout the framework and anti-patterns to avoid.
Fragment Pattern (Items and Abilities)
DO: Use Fragments
// Item Definition - compose behaviors:
DA_Item_PoisonedDagger:
Fragments:
WCFragment_Equippable (MainHand, model)
WCFragment_WeaponData (Dagger type, trace sockets)
WCFragment_Rarity (Uncommon)
WCFragment_AttributeModifiers (+5 Dexterity on equip)
WCFragment_Consumable_Poison // custom poison on-hit
// Zero class hierarchy. Mix any fragments.
// Add new behavior = add new fragment class.
DO NOT: Deep Inheritance
// Anti-pattern - do not do this:
class UWCItemDefinition {}
class UWCWeaponDefinition : UWCItemDefinition {}
class UWCMeleeWeaponDefinition : UWCWeaponDefinition {}
class UWCDaggerDefinition : UWCMeleeWeaponDefinition {}
class UWCPoisonedDaggerDefinition : UWCDaggerDefinition {}
// This creates class explosion, makes cross-cutting
// features impossible, and violates the framework rules.
Cross-Module Communication Pattern
DO: Tags + Subsystems + Interfaces
// Good: WCCombat tells other systems about death
// via a Gameplay Event tag:
ASC->AddGameplayEventTag(WC.Combat.Event.Death);
// Any module can listen:
WCKnowledgeComp->ListenForGameplayTag(
WC.Combat.Event.Death, OnEnemyDied);
WCStoriesComp->ListenForGameplayTag(
WC.Combat.Event.Death, OnKillObjective);
DO NOT: Direct Cross-Module References
// BAD - WCCombat directly referencing WCStories:
#include "WCStories/StoriesComponent.h" // VIOLATION
void UWCCombatSystem::OnKill(AActor* Killed) {
// Direct reference to another feature module:
UWCStoriesComponent* Stories = ...;
Stories->UpdateKillObjective(Killed); // WRONG
}
// This creates circular dependencies and breaks
// module independence.
Data Asset vs Runtime Instance Pattern
// UWCItemDefinition = the RECIPE (immutable, shared, Data Asset)
// One instance shared by all copies of "Iron Sword"
// Stored in content browser, referenced by soft pointer
// UWCItemInstance = the OBJECT in your inventory
// Created at runtime, unique GUID, has per-instance state
// Holds reference to its Definition (not a copy)
// This pattern is used throughout:
// UWCItemDefinition / UWCItemInstance (inventory)
// UWCAbilityDefinition / FGameplayAbilitySpec (abilities)
// UWCQuestDefinition / FWCActiveQuestData (quests)
Subsystem Pattern
// Feature modules expose services via Subsystems, NOT singletons:
// Access a subsystem anywhere:
UWCSaveSubsystem* SaveSys = World->GetSubsystem<UWCSaveSubsystem>();
UWCDynamicSocietySubsystem* Social = World->GetSubsystem<UWCDynamicSocietySubsystem>();
UWCUIManagerSubsystem* UI = GameInstance->GetSubsystem<UWCUIManagerSubsystem>();
// Never create global/static service objects.
// UE Subsystems are lifecycle-managed, safe to null-check,
// and work correctly with editor PIE and multiplayer.
GAS Cue Pattern (Visual Effects)
// All VFX/SFX use Gameplay Cues (client-side, cosmetic only):
// NEVER spawn VFX on server. Never in ability EndAbility.
// In combat ability, trigger a cue on hit:
FGameplayCueParameters CueParams;
CueParams.Location = HitLocation;
CueParams.Normal = HitNormal;
ASC->ExecuteGameplayCue(WC.GameplayCue.Hit.Physical.Slash, CueParams);
// UGameplayCueNotify_Burst on client:
// -> SpawnNiagaraSystemAtLocation(SwordSlashVFX)
// -> SpawnSoundAtLocation(SwordClangSFX)
// Why: Gameplay Cues fire only on clients, are unimportant
// for server state, and can be skipped if too many.
Attribute Modification Pattern
// ALWAYS modify attributes via GameplayEffect:
void ModifyHealth(AActor* Target, float Delta) {
// RIGHT:
UGameplayEffect* GE = NewObject<UGameplayEffect>(GetTransientPackage());
// ... configure modifiers ...
ASC->ApplyGameplayEffectToSelf(GE, 1.0f, ASC->MakeEffectContext());
// WRONG - never do this:
// AttributeSet->Health.SetCurrentValue(NewValue); // bypasses GAS replication
}
Anti-Patterns to Absolutely Avoid
Declaring tags outside WCGASCore
Declaring UE_DEFINE_GAMEPLAY_TAG in any module other than WCGASCore creates ODR (One Definition Rule) violations. Multiple translation units end up defining the same symbol. Results in linker errors or silent duplicate tag registration.
Using TMap for replicated data
UE cannot replicate TMap. Period. Use TArray + binary search or FFastArraySerializer. This mistake causes silent data loss that only manifests in multiplayer.
Modifying plugin source directly
Any change to files in Plugins/DynamicRPGWorlds/ will be overwritten by plugin updates. Always subclass in your game code. The framework provides clean extension points via virtual functions, BlueprintNativeEvents, and data-driven customization.
Accessing ASC directly on character for player characters
For players, the ASC is on AWCPlayerState, NOT the character. Calling GetAbilitySystemComponent() on the character correctly returns the PlayerState ASC via IAbilitySystemInterface — but only if you use the WC classes. Calling Cast<UAbilitySystemComponent> on a component of the character will find nothing.
Roadmap
Current status and planned work as of March 31, 2026. Priority 1 items block designer workflows. Priority 2 is polish. Priority 3 is optional.
Add item(s) to inventory. Creates a new UWCItemInstance with a stable GUID. Returns the instance. Handles auto-stacking if WCFragment_Stackable is present. Server only.
Remove count from item stack. Destroys instance if stack reaches 0. Returns false if not enough stack or item not found.
bool UseItem(UWCItemInstance* Instance)
Use the item. Invokes WCFragment_Consumable logic if present. Applies GEs, reduces stack. Returns false if item cannot be used (combat restriction, wrong state).
Begin async save to slot. Applies WC.Save.State.SavingDisabled tag during save. Calls all 6 module serializers. Fires OnSaveComplete when done. Server only.
void LoadGameAsync(int32 SlotIndex)
Begin async load from slot. Restores world section then all player sections. Server only.
void SaveForLevelTransition()
Synchronous save to transition slot. Blocks until complete. Call before Open Level.
TArray<FWCSaveSlotInfo> GetSaveSlots()
Returns metadata for all save slots (timestamp, level name, playtime, screenshot thumbnail reference).
bool DeleteSaveSlot(int32 SlotIndex)
Delete a save slot. Returns false if slot does not exist.