Interface System¶
Summary: Project Eternal uses interface-driven design for cross-system communication. Core interfaces enable loose coupling between combat, animation, targeting, and effects systems, allowing systems to interact through contracts rather than direct references.
Table of Contents¶
- Why Interfaces
- Core Interfaces
- Usage Patterns
- Cross-System Communication
- Source Reference
- Related Systems
- Recent Changes
Why Interfaces¶
The Coupling Problem¶
Without interfaces, systems become tightly coupled:
+------------------------------------------------------------------+
| WITHOUT INTERFACES |
+------------------------------------------------------------------+
| |
| Ability System |
| | |
| +-- Needs direct reference to UCombatComponent |
| +-- Needs direct reference to UPoiseSystemComponent |
| +-- Needs direct reference to UMontageManagerComponent |
| +-- Needs direct reference to UCombatEffectsManager |
| |
| Problem: Any change to these components breaks abilities |
| |
+------------------------------------------------------------------+
The Interface Solution¶
+------------------------------------------------------------------+
| WITH INTERFACES |
+------------------------------------------------------------------+
| |
| Ability System |
| | |
| +-- Uses ICombatInterface |
| +-- Uses IPoiseSystemInterface |
| +-- Uses IMontageManagerInterface |
| +-- Uses ICombatEffectsInterface |
| |
| Benefits: |
| - Components can change internals without breaking abilities |
| - New character types just implement interfaces |
| - Easy to mock for testing |
| - Clear contracts for network validation |
| |
+------------------------------------------------------------------+
Design Benefits¶
| Benefit | How It's Achieved |
|---|---|
| Abstraction | Systems talk via contracts, not implementations |
| Modularity | Components can be replaced without changing callers |
| Extensibility | New character types only need to implement interfaces |
| Testability | Interfaces enable mocking for unit tests |
| Multiplayer | Clear boundaries for network validation |
Core Interfaces¶
Interface Overview¶
+------------------------------------------------------------------+
| CORE INTERFACES |
+------------------------------------------------------------------+
| |
| Location: Source/ProjectEternal/Public/Interface/ |
| |
| +-------------------+ +-------------------------+ |
| | ICombatInterface | | IMontageManagerInterface| |
| | - GetCombatComp | | - GetMontageByTag | |
| | - GetHitDirection | | - GetHitReactMontage | |
| +-------------------+ +-------------------------+ |
| |
| +-------------------+ +-------------------------+ |
| | ITargetable | | IPoiseSystemInterface | |
| | - IsValid | | - ApplyPoiseDamage | |
| | - CanAttack | | - GetPoisePercentage | |
| | - IsFriendly | | - CanAct | |
| +-------------------+ +-------------------------+ |
| |
| +-------------------+ +-------------------------+ |
| | ICombatEffects | | IEquipmentOwner | |
| | - TriggerEffect | | - GetEquipmentComponent | |
| | - TriggerHitStop | +-------------------------+ |
| +-------------------+ |
| |
| +-------------------+ +-------------------------+ |
| | IPlayerInventory | | IQuestParticipant | |
| | - GetInventoryComp| | - GetPlayerQuestComp | |
| +-------------------+ +-------------------------+ |
| |
+------------------------------------------------------------------+
ICombatInterface¶
Provides access to combat state and hit direction calculations.
| Method | Return Type | Purpose |
|---|---|---|
GetCombatComponent() |
UCombatComponent* |
Access to combat component |
GetPlayerCombatComponent() |
UPlayerCombatComponent* |
Player-specific combat |
GetEnemyCombatComponent() |
UEnemyCombatComponent* |
Enemy-specific combat |
GetHitDirection() |
EHitDirection |
Direction of incoming hit |
Hit Direction Values:
| Value | Meaning |
|---|---|
Front |
Hit from character's front |
Back |
Hit from behind |
Left |
Hit from left side |
Right |
Hit from right side |
None |
No directional hit |
Implementers: AEternalCharacter
IMontageManagerInterface¶
Manages animation montage lookup by gameplay tag.
| Method | Return Type | Purpose |
|---|---|---|
GetMontageByTag() |
UAnimMontage* |
Look up montage by action tag |
GetHitReactMontage() |
UAnimMontage* |
Get hit reaction for direction |
GetDefaultMontageTable() |
UDataTable* |
Get the default montage data table |
Implementers: AEternalCharacter, UMontageManagerComponent
ITargetable¶
Targeting system validation interface.
| Method | Return Type | Purpose |
|---|---|---|
GetTarget() |
AActor* |
Get the target actor |
GetTargetsTarget() |
AActor* |
Get what this target is targeting |
IsValid() |
bool |
Can this actor be targeted? |
CanAttack() |
bool |
Is this actor able to attack? |
IsFriendly() |
bool |
Is this actor friendly to the caller? |
Implementers: AEternalCharacter
IPoiseSystemInterface¶
Poise/stagger system abstraction.
| Method | Return Type | Purpose |
|---|---|---|
ApplyPoiseDamage() |
bool |
Apply poise damage to actor |
GetPoisePercentage() |
float |
Current poise as 0-1 value |
CanAct() |
bool |
Is actor able to take actions? |
Poise States:
| State | Description |
|---|---|
Stable |
Normal operation |
Weakened |
Low poise, vulnerable |
Staggered |
Briefly stunned |
Broken |
Extended stun state |
Recovering |
Legacy — no longer entered. Retained in the enum for replication and Blueprint compatibility |
Implementers: UPoiseSystemComponent
ICombatEffectsInterface¶
Visual and audio effects trigger interface.
| Method | Return Type | Purpose |
|---|---|---|
TriggerEffectByTag() |
void |
Trigger VFX/audio by tag |
TriggerHitStop() |
void |
Freeze-frame effect on hit |
TriggerSlowMotion() |
void |
Time dilation effect |
Implementers: UCombatEffectsManager
IEquipmentOwner¶
Interface for actors that own equipment. Provides decoupled access to equipment without casting to concrete types.
| Method | Return Type | Purpose |
|---|---|---|
GetEquipmentComponent() |
UEquipmentComponent* |
Access to equipment component |
Implementers: AEternalPlayer (PlayerController)
Why this interface exists:
- Equipment lives on PlayerController (persists across death)
- Other systems (abilities, UI) need equipment access
- Avoids casting to AEternalPlayer throughout the codebase
- Enables testing with mock equipment owners
IPlayerInventory¶
Interface for actors that manage player inventory.
| Method | Return Type | Purpose |
|---|---|---|
GetInventoryComponent() |
UInventoryComponent* |
Access to inventory component |
Implementers: AEternalPlayerState
Note: PlayerState implements this interface but delegates to PlayerController, which owns the actual InventoryComponent. This allows systems to query inventory via PlayerState (which replicates) while the component lives on Controller (which persists).
IQuestParticipant¶
Interface for actors participating in the quest system.
| Method | Return Type | Purpose |
|---|---|---|
GetPlayerQuestComponent() |
UPlayerQuestComponent* |
Access to quest tracking |
Implementers: AEternalPlayerState, AEternalNPC
IDlgDialogueParticipant¶
Interface for actors participating in dialogue system interactions.
| Method | Return Type | Purpose |
|---|---|---|
GetDialogueParticipantName() |
FString |
Get actor's dialogue display name |
OnDialogueStarted() |
void |
Called when dialogue begins |
OnDialogueEnded() |
void |
Called when dialogue concludes |
Implementers: AEternalNPC
ICombatDataProvider¶
Provides combat data to sub-components (UComboComponent, UChargeComponent), replacing fragile TFunction callbacks with a stable interface contract.
| Method | Return Type | Purpose |
|---|---|---|
GetCurrentWeaponFragment() |
const FWeaponFragment* |
Current weapon fragment (or unarmed fallback) |
GetActiveWeaponMesh() |
USkeletalMeshComponent* |
Active weapon mesh (character mesh if unarmed) |
GetCombatMontagesTable() |
UDataTable* |
Combat montages table for the current weapon |
IsUnarmed() |
bool |
Is the player currently unarmed? |
GetUnarmedWeaponFragment() |
const FWeaponFragment* |
Default combat stats when no weapon equipped |
GetCurrentWeaponHand() |
FGameplayTag |
Weapon hand tag for hand-aware combo/charge/montage resolution — the charge component resolves its per-weapon config through it too |
Implementers: UPlayerCombatComponent
Note: C++-only interface (no UFUNCTIONs) because it returns pointers to non-UObject types (FWeaponFragment) which cannot be exposed to Blueprint.
IItemContainer¶
Unified contract for any container holding items in a spatial grid (inventory, stash, vendor, loot piles), so callers never need the concrete container type. All methods are BlueprintNativeEvent and called via the Execute_ pattern.
Item operations:
| Method | Return Type | Purpose |
|---|---|---|
TryAddItemToContainer() |
bool |
Primary add method — stacking, space checks, server authority |
PlaceItemAtIndex() |
bool |
Place item at a specific grid index (handles authority/replication) |
AddItemAtPosition() |
bool |
Add item at a top-left grid position |
TryPlaceItemViaRegistry() |
bool |
Centralized, registry-aware placement usable by any caller |
CanAddItemAt() |
bool |
Can the item be placed at this position? |
RemoveItemFromContainer() |
bool |
Remove an item |
FindItemInContainer() |
UItemObject* |
Find first item matching a FPrimaryAssetId |
GetAllItemsInContainer() |
TArray<UItemObject*> |
All items in the container |
HasItemInContainer() |
bool |
Does the container hold this item? |
Grid operations:
| Method | Return Type | Purpose |
|---|---|---|
GetContainerWidth() / GetContainerHeight() |
int32 |
Grid dimensions |
IndexToCoordinates() / CoordinatesToIndex() |
FIntPoint / int32 |
Flattened index <-> 2D coordinate conversion |
IsValidIndex() |
bool |
Is the index within grid bounds? |
IsSpaceAvailable() |
bool |
Is a rectangular space free (with optional ignore items for swaps)? |
FindAvailableSpace() |
bool |
Find first free space for given item dimensions |
Implementers: UItemContainerComponent (and its subclasses UInventoryComponent, UVendorContainerComponent, UCraftingContainerComponent)¶
Usage Patterns¶
Pattern 1: Cast and Execute¶
The standard pattern for interface calls:
| Step | What Happens |
|---|---|
| 1 | Check if actor implements interface |
| 2 | Use Execute_ prefix to call method |
| 3 | Pass actor as first parameter |
Pattern 2: Interface with Fallback¶
When you need to support both interface and direct component access:
Try interface cast --> If fails --> Find component directly
| |
v v
Cast<IInterface>() FindComponentByClass<T>()
Pattern 3: Interface Delegation¶
Parent class implements interface, delegates to component:
Actor implements IInterface
|
v
Interface method calls component
|
v
Component contains actual logic
Why delegate? - Actors expose component functionality - Components contain actual implementation - Clean separation of concerns
Pattern 4: Multiple Interface Composition¶
Single class implements multiple interfaces:
AEternalCharacter
|
+-- IAbilitySystemInterface (GAS integration)
+-- ICombatInterface (Combat access)
+-- IMontageManagerInterface (Animation management)
+-- ITargetable (Targeting system)
Benefits: - One class serves multiple systems - Systems interact through interfaces - Easy to extend with new interfaces
Cross-System Communication¶
Combat to Poise Flow¶
+------------------------------------------------------------------+
| COMBAT --> POISE FLOW |
+------------------------------------------------------------------+
| |
| Ability (EternalMeleeAttack) |
| | |
| v |
| Cast<IPoiseSystemInterface>(TargetActor) |
| | |
| v |
| Execute_ApplyPoiseDamage(Target, Damage, Source) |
| | |
| v |
| UPoiseSystemComponent receives damage |
| | |
| v |
| Applies GAS effect to Poise attribute |
| | |
| v |
| Updates EPoiseState (may become Staggered/Broken) |
| | |
| v |
| Broadcasts OnPoiseStateChangedDelegate |
| | |
| v |
| Ability/UI reacts to state change |
| |
+------------------------------------------------------------------+
Ability to Animation Flow¶
+------------------------------------------------------------------+
| ABILITY --> ANIMATION FLOW |
+------------------------------------------------------------------+
| |
| Ability requests montage |
| | |
| v |
| GetAvatarActor as IMontageManagerInterface |
| | |
| v |
| GetMontageByTag(ActionTag, Index, Table) |
| | |
| v |
| MontageManagerComponent looks up DataTable |
| | |
| v |
| Returns UAnimMontage* |
| | |
| v |
| Ability plays montage via ASC |
| |
+------------------------------------------------------------------+
Targeting Validation Flow¶
+------------------------------------------------------------------+
| TARGETING VALIDATION |
+------------------------------------------------------------------+
| |
| TargetingComponent finds potential targets |
| | |
| v |
| For each potential target: |
| | |
| v |
| Checks: ImplementsInterface(UTargetable) |
| | |
| v |
| Calls: Execute_IsValid(Pawn, AllowSelf, Controller) |
| | |
| v |
| Character validates itself (alive, not invisible, etc) |
| | |
| v |
| Returns true/false |
| | |
| v |
| TargetingComponent builds filtered list |
| |
+------------------------------------------------------------------+
Source Reference¶
| Topic | File | Symbol |
|---|---|---|
| Combat Interface | Source/ProjectEternal/Public/Interface/CombatInterface.h |
ICombatInterface |
| Montage Manager Interface | Source/ProjectEternal/Public/Interface/MontageManagerInterface.h |
IMontageManagerInterface |
| Targetable Interface | Source/ProjectEternal/Public/Interface/ITargetable.h |
ITargetable |
| Poise System Interface | Source/ProjectEternal/Public/Interface/PoiseSystemInterface.h |
IPoiseSystemInterface, EPoiseState |
| Combat Effects Interface | Source/ProjectEternal/Public/Interface/CombatEffectsInterface.h |
ICombatEffectsInterface |
| Equipment Owner Interface | Source/ProjectEternal/Public/Interface/EquipmentOwnerInterface.h |
IEquipmentOwner |
| Player Inventory Interface | Source/ProjectEternal/Public/Inventory/Interfaces/PlayerInventory.h |
IPlayerInventory |
| Dialogue Participant Interface | Plugins/DlgSystem/Source/DlgSystem/DlgDialogueParticipant.h |
IDlgDialogueParticipant |
| Combat Data Provider Interface | Source/ProjectEternal/Public/Interface/CombatDataProviderInterface.h |
ICombatDataProvider |
| Item Container Interface | Source/ProjectEternal/Public/Inventory/Interfaces/ItemContainer.h |
IItemContainer |
| Quest Participant Interface | Source/ProjectEternal/Public/Quest/Interfaces/QuestParticipant.h |
IQuestParticipant |
| Character Implementation | Source/ProjectEternal/Private/Character/EternalCharacter.cpp |
AEternalCharacter interface overrides |
| Poise Component | Source/ProjectEternal/Private/Combat/Components/PoiseSystemComponent.cpp |
UPoiseSystemComponent |
| Combat Effects Manager | Source/ProjectEternal/Private/Combat/Components/CombatEffectsManager.cpp |
UCombatEffectsManager |
Related Systems¶
- Character Framework - Interface implementers
- Combat Overview - ICombatInterface usage
- Poise System - IPoiseSystemInterface details
- Combat Animation - IMontageManagerInterface usage
Recent Changes¶
| Date | Change | Impact |
|---|---|---|
| 2026-08-06 | Marked EPoiseState::Recovering as legacy (no longer entered, kept for replication/Blueprint compatibility); noted that GetCurrentWeaponHand() also resolves per-weapon charge configuration; replaced the invented line ranges in the source reference table with symbol anchors |
Readers stop treating Recovering as a live state, and the reference table no longer points at line numbers that never matched the files |
| 2026-07-03 | Documented ICombatDataProvider, IItemContainer |
Complete interface reference for combat data and item container contracts |
| 2026-01-19 | Added IDlgDialogueParticipant interface; AEternalNPC now implements dialogue system | Dialogue system integration |
| 2025-12-28 | Added IEquipmentOwner interface |
Equipment access without concrete casts |
| 2025-12-28 | Documented IPlayerInventory, IQuestParticipant |
Complete interface reference |
| - | Initial documentation | - |