Diagrams
Overview
Visual diagrams illustrating the internal architecture and runtime behavior of CCHARUMODULE.
1. Class Hierarchy & Component Composition
Base class inheritance tree showing which components each level adds. All base classes implement IGenericTeamAgentInterface (via UCInteractionComponent) and ICCommonActor.
classDiagram
direction TB
class AActor {
<<UE Base>>
}
class APawn {
<<UE Base>>
}
class ACharacter {
<<UE Base>>
}
class ACActor {
+USceneComponent* cdryxRootComponent
+UCInitializerComponent* initializerComponent
+UCDebugComponent* debugComponent
+UCStaticMeshComponent* meshComponent
+UCInteractionComponent* interactionComponent
+UCSelectComponent* selectComponent
+UCSkillComponent* skillComponent
}
class ACPawn {
+UCCapsuleComponent* cdryxRootComponent
+UCSkeletalMeshComponent* meshComponent
+UCLifeComponent* lifeComponent
+UCCombotterComponent* combotterComponent
+UCFloatingMovementComponent* floatingMovement
+UCNavigationInvokerComponent* navInvoker
+UCAIPerceptionStimuliSourceComponent* aiPerception
+UCAutomationComponent* automationComponent
}
class ACCharacter {
+UCCapsuleComponent* cCapsuleComponent
+UCSkeletalMeshComponent* cSkeletalMeshComponent
+UCCharacterMovementComponent* cCharMovement
}
class ACPlayer1STCharacter {
+UCSpringArmComponent* springArm
+UCCameraComponent* camera
+UCActionMappingComponent* actionMapping
+UCTurnByTurnComponent* turnByTurn
+UCFOWComponent* fow
+UCMinimapComponent* minimap
+UCCompassComponent* compass
}
class ACPlayerFLYPawn {
+UCSpringArmComponent* springArm
+UCCameraComponent* camera
+UCActionMappingComponent* actionMapping
+UCFOWComponent* fow
}
class ACProjectile {
+USphereComponent* cdryxRootComponent
+UCStaticMeshComponent* meshComponent
+UCProjectileMovementComponent* projectileMvt
}
class ACSun {
+UDirectionalLightComponent* directionalLight
}
class ACPortrait {
+USkeletalMeshComponent* skeletalMesh
+USceneCaptureComponent2D* sceneCapture2D
}
AActor <|-- ACActor
APawn <|-- ACPawn
ACharacter <|-- ACCharacter
ACCharacter <|-- ACPlayer1STCharacter
ACPawn <|-- ACPlayerFLYPawn : via ACPlayerBaseFLYPawn
AActor <|-- ACProjectile
ACActor <|-- ACSun
AActor <|-- ACPortrait
note for ACCharacter "Replaces default UE capsule, mesh\nand movement via ObjectInitializer"
note for ACPlayer1STCharacter "complete_CSTR_CPLAYER_FIRST_PERSON_ONLY\nadds player-specific components"2. Actor Lifecycle Pipeline
Full sequence from DataTable configuration to runtime actor management: spawn, initialization, AI possession, and deactivation.
sequenceDiagram
participant DT as DataTable
participant AS as ACActorSpawner
participant AM as UCActormaker
participant Q as dataQueue
participant GT as Game Thread
participant A as Actor
participant IC as UCInitializerComponent
participant W as World Tiles
DT->>AS: FCNPCMaker row
AS->>AM: instantiate(actorMakerStruct)
Note over AM: initActorMap() on first call
AM->>AM: iterateOnClusterRoom()
AM->>AM: countCreateActor() per maker per room
AM->>AM: buildInformation() creates UCActorInformation
AM->>AM: assignToCells() populates actorCellMap
loop Every Tick
AS->>AM: buildASync(x, y)
AM->>AM: wantDraw(x, y)
Note over AM: Guard: queue empty?<br/>pawn moved cell?
AM->>AM: drawActor(x, y)
Note over AM: Compute activate/deactivate sets<br/>Batch into pools
AM->>Q: Enqueue FActorDataQueue batches
GT->>Q: Dequeue 1 batch per frame
GT->>AM: updateActor_sync()
end
AM->>A: popOn(advIdx)
Note over A: spawnActorAtRuntime if no actor
A->>IC: init(advIdx)
IC->>IC: Cascade init to all components
AM->>W: worldTileReadyAt(x, y)?
alt Tile ready with fullLOD
AM->>A: possessIt() with AI controller
else Tile not ready
AM->>AM: waitForTileMap.Add(uvIndex, advIdx)
W-->>AM: onTileReady(uvIndex)
AM->>A: possessIt()
end
Note over AM: When pawn moves away
AM->>A: popOff(advIdx)
Note over A: resetAll() then disable ticks
alt killed or consumed
AM->>A: Destroy()
end3. Cell-Based Spatial Pooling (Lazy Loading)
How UCActormaker manages actor activation/deactivation based on pawn proximity using a cell grid, wakeUpDistance protection, and batched pooling.
3a. Spatial Grid
Actors are pre-assigned to cells via CellUtility::assignToCells using their spawn position and wakeUpDistance. When the pawn enters a cell, all actors assigned to that cell become activation candidates.
3b. Decision Flow
How buildASync decides whether to redraw actors based on pawn movement, then computes activation/deactivation sets with wakeUpDistance protection and batched pooling.
flowchart TB
START["buildASync(x, y)"] --> WANT{"wantDraw(x, y)?"}
WANT -->|"queue not empty"| SKIP[Skip draw]
WANT -->|"pawn same cell"| SKIP
WANT -->|"pawn moved cell<br/>or forceDraw"| DRAW["drawActor(x, y)"]
DRAW --> NEWCELL["Lookup actorCellMap<br/>for new pawn cell"]
NEWCELL --> ACTIVATE["advToActivate =<br/>actors in pawn cell"]
DRAW --> OLDACTIVE["Previous<br/>activatedAdversaryArray"]
OLDACTIVE --> DEACT_CHECK{"Actor still<br/>in new cell?"}
DEACT_CHECK -->|Yes| KEEP[Keep active]
DEACT_CHECK -->|No| DIST_CHECK{"dist actor pawn<br/>< wakeUpDistance?"}
DIST_CHECK -->|Yes| PROTECT["Protected:<br/>stay active"]
DIST_CHECK -->|No| ORIGIN_CHECK{"Actor far from<br/>spawn origin?"}
ORIGIN_CHECK -->|Yes| TELEPORT["teleportBack<br/>+ deactivate"]
ORIGIN_CHECK -->|No| DEACTIVATE["deactivate<br/>popOff"]
ACTIVATE --> BATCH["Split into batches<br/>poolSizeStart / poolSizeRun"]
DEACTIVATE --> BATCH
TELEPORT --> BATCH
BATCH --> ENQUEUE["Enqueue<br/>FActorDataQueue"]
ENQUEUE --> FRAME["Game thread:<br/>dequeue 1 batch per frame"]
FRAME --> POPON["popOn: spawn + init<br/>+ wait tile + possess AI"]
FRAME --> POPOFF["popOff: disable ticks<br/>+ reset components"]
FRAME --> TPBACK["teleportBack:<br/>return to origin"]3c. Configuration Parameters
| Parameter | Default | Description |
|---|---|---|
cellSize |
20000 | Size of each spatial cell in world units |
wakeUpDistance |
10000 | Distance from pawn within which actors are protected from despawn |
poolSizeStart |
8 | Batch size for the first spawn pass |
poolSizeRun |
4 | Batch size for subsequent spawn/despawn passes |
4. Combat State Machines
The three CSimpleStateMachine instances inside UCCombotterComponent, driven by AnimNotify events from CMontageNotifier.
stateDiagram-v2
state "Melee Attack" as MELEE {
[*] --> S_NOT_ATTACKING
S_NOT_ATTACKING --> S_ATTACKING : user click (proceedAttack)
S_ATTACKING --> S_COMBO_WINDOW : C_CANCOMBO_AN
S_ATTACKING --> S_ATTACK_FINISHED : montage end or C_NOMORECOMBO_AN
S_COMBO_WINDOW --> S_ATTACKING : user click (next combo)
S_COMBO_WINDOW --> S_ATTACK_FINISHED : C_NOMORECOMBO_AN or timeout
S_ATTACK_FINISHED --> S_NOT_ATTACKING : reset
}
state "Range Attack" as RANGE {
[*] --> S_BOW_NOT_DRAWING
S_BOW_NOT_DRAWING --> S_PREPARE_BOW_DRAW : proceedStartRangeAttack
S_PREPARE_BOW_DRAW --> S_BOW_DRAWING : C_STARTRANGE_AN
S_BOW_DRAWING --> S_BOW_SHOT : proceedEndRangeAttack + C_SHOTRANGE_AN
S_BOW_SHOT --> S_RANGE_FINISHED : C_ENDRANGE_AN
S_RANGE_FINISHED --> S_BOW_NOT_DRAWING : reset
}
state "Block" as BLOCK {
[*] --> S_NOT_BLOCKING
S_NOT_BLOCKING --> S_PREPARE_BLOCKING : proceedStartBlock
S_PREPARE_BLOCKING --> S_BLOCKING : C_STARTBLOCK_AN
S_BLOCKING --> S_BLOCK_END : proceedEndBlock + C_ENDBLOCK_AN
S_BLOCK_END --> S_NOT_BLOCKING : reset
}5. Damage & Death Flow
How UCLifeComponent processes incoming damage, applies armor, triggers skills and animations, and handles the death sequence.
flowchart TB
DMG["OnTakeAnyDamage fires"] --> CONTAINER["Create UCDamageReceptionContainer<br/>(damage, armor, causer, instigator)"]
CONTAINER --> SKILL["Execute executeDamagedSkill"]
SKILL --> ANIM{"damage > 0?"}
ANIM -->|Yes| PLAY["Play damagedAnimMontage"]
ANIM -->|No| REDUCE
PLAY --> REDUCE["currentLife -= (damage - armor)"]
REDUCE --> CHECK{"currentLife <= 0?"}
CHECK -->|No| DONE[Continue]
CHECK -->|Yes| DEATH_SKILL["Execute executeDeathSkill"]
DEATH_SKILL --> KILLED_MONTAGE["Play killedAnimMontage"]
KILLED_MONTAGE --> HALF["After 50% anim duration:<br/>disable collision + enable ragdoll"]
HALF --> DOUBLE["After 200% anim duration:<br/>disable physics + freeze skeleton"]
DOUBLE --> DEFINITIVE["definitiveDeath()<br/>killedOrConsumed = true"]
DEFINITIVE --> BROADCAST["Broadcast onKilled"]6. Player Creation & Switching
How ACPlayerSpawner creates players via UCPlayermaker and handles player switching with teleportation and possession.
sequenceDiagram
participant User as Game Code
participant PS as ACPlayerSpawner
participant PM as UCPlayermaker
participant PI as UCPlayerInitializer
participant Room as Room and Tile System
participant Pawn as Player Pawn
User->>PS: switchPlayer(tag, location, blend)
PS->>PS: playermakerMap.Find(tag)
alt Player not yet created
PS->>PM: createPlayerMaker()
PM->>Pawn: spawnActorAtRuntime()
Pawn->>Pawn: UCInitializerComponent::init(-1)
end
PS->>PM: finishSpawning(location, callback, blend)
PM->>PI: Create UCPlayerInitializer (tickable)
loop Tick until ready
PI->>Room: Room ready?
PI->>Room: Tile ready at location?
end
PI->>Pawn: TeleportTo(location)
PI->>Pawn: SetViewTargetWithBlend(blend)
PI->>Pawn: PlayerController Possess(pawn)
PI-->>User: Ready callback7. Input System Flow
How UCActionMappingComponent creates input bindings at runtime and dispatches events to the pawn via ICInputReceiver.
flowchart TB
subgraph SETUP["Setup (UCActionMappingComponent)"]
direction TB
CREATE["createDefaultInputAction()<br/>Create UInputMappingContext"] --> BIND["setup()<br/>Bind all ECInputActionType<br/>to UEnhancedInputComponent"]
BIND --> REGISTER["Add mapping context<br/>to EnhancedInputLocalPlayerSubsystem"]
end
subgraph RUNTIME["Runtime Event Flow"]
direction TB
UE["UEnhancedInputComponent<br/>fires action"] --> DISPATCH["UCActionMappingComponent<br/>dispatches to ICInputReceiver"]
DISPATCH --> STRUCT["FCInputStruct callbacks"]
STRUCT --> T["onTriggered"]
STRUCT --> S["onStarted"]
STRUCT --> G["onGoing"]
STRUCT --> C["onCanceled"]
STRUCT --> CO["onCompleted"]
end
subgraph ACTIONS["ECInputActionType"]
direction LR
MOVE["MOVE<br/>ZQSD Arrows Gamepad"]
ROTATE["ROTATE<br/>Mouse XY Gamepad R"]
JUMP["JUMP<br/>SpaceBar"]
COMBAT["LMB_CLICK BLOCK<br/>INTERACT"]
VIEW["CHANGE_VIEW<br/>SCROLL"]
UI["DISPLAY_RESOURCE<br/>DISPLAY_MAP"]
end
SETUP --> RUNTIME
ACTIONS -.-> DISPATCH8. Fight Mode State Flow
How ACPlayer1STCharacter transitions between normal and fight mode, and how AddControllerYawInput handles turn-in-place with montage animations.
8a. Fight Mode Transition
How the player character toggles between normal mode and fight mode, updating rotation settings and broadcasting the fight state to turnByTurnComponent.
flowchart TB
subgraph NORMAL["Normal Mode"]
N["bOrientRotationToMovement = true\nRotationRate = 540\nCDRYX_FIGHTING = false"]
end
subgraph FIGHT["Fight Mode"]
F["bOrientRotationToMovement = false\nRotationRate = 270\nCDRYX_FIGHTING = true"]
end
NORMAL -->|"updateFightReason with advIdx ON"| FIGHT
FIGHT -->|"fightReasonSet empty\nor cleanFightReason"| NORMAL
FIGHT -->|"always"| TBT["turnByTurnComponent\nfightReasonUpdated"]
NORMAL -->|"always"| TBT8b. Turn-in-Place Logic in AddControllerYawInput
How the overridden AddControllerYawInput handles rotation in fight mode: blocking suppression, montage-based turn at 66° threshold when stationary, and snap rotation at 25° when moving.
flowchart TB
START["AddControllerYawInput"] --> FIGHTING{"isFighting?"}
FIGHTING -->|"No"| PASS["Super only"]
FIGHTING -->|"Yes"| BLOCKING{"blocking\n+ speed near 0?"}
BLOCKING -->|"Yes"| SUPPRESS["Suppress rotation\nreturn"]
BLOCKING -->|"No"| YAWDIFF{"yawDiff?"}
YAWDIFF -->|"near 0"| LOCK["DesiredRotation = false"]
YAWDIFF -->|"speed near 0\nyawDiff > 66 deg"| MONTAGE["Play turnLeft or turnRight\nmontage stops if speed > 0\nDesiredRotation = true\nafter 0.45s delay"]
YAWDIFF -->|"speed > 0\nyawDiff > 25 deg"| SNAP["DesiredRotation = true\nafter 0.22s delay"]9. Perspective Toggle Flow
How ACPlayer1STCharacter::changeView() switches between first-person and top-view camera modes, triggered by key press (V) or 3-finger touch on mobile.
flowchart LR
subgraph FIRST["First Person View"]
FP["bUsePawnControlRotation = true\nbInheritPitch = not mobile\nbInheritYaw = true\nHideCursorDuringCapture = true"]
end
subgraph TOP["Top View"]
TV["bUsePawnControlRotation = false\nbInheritPitch = false\nbInheritYaw = false\nHideCursorDuringCapture = false"]
end
FIRST -->|"changeView\nor 3-finger touch"| TOP
TOP -->|"changeView\nor 3-finger touch"| FIRST
TOP --> T_ACT["cleanFightReason\ncustomReset"]
FIRST --> F_ACT["SetControlRotation = ActorRotation\ninitSpeedFactor\ncustomReset"]
TOP --> BC1["broadcast TOP_VIEW"]
FIRST --> BC2["broadcast FIRT_VIEW"]10. Input System — UCActionMappingComponent to ICInputReceiver to ACPlayer1STCharacter
How the Enhanced Input system routes physical key events through UCActionMappingComponent, the ICInputReceiver interface slots, and into ACPlayer1STCharacter::initActionEvent() game logic.
10a. Routing Pipeline
How createDefaultInputAction maps physical keys to UInputAction, setup binds them via the AMC_BIND_ACTION macro, and the macro dispatches to ICInputReceiver slots that initActionEvent fills with game logic.
flowchart TB
subgraph COMP["UCActionMappingComponent"]
CREATE["createDefaultInputAction\nCreates UInputMappingContext\nMaps ECInputActionType to UInputAction + keys"]
SETUP["setup\nBinds via AMC_BIND_ACTION macro\n5 ETriggerEvent per action"]
CREATE --> SETUP
end
subgraph MACRO["AMC_BIND_ACTION macro"]
CAST["Cast owner to ICInputReceiver\nCall matching FCInputStruct callback\nwith value + elapsedSec + triggeredSec"]
end
subgraph IFACE["ICInputReceiver interface"]
SLOTS["15 FCInputStruct fields\nEach has 5 TFunction callbacks\nonTriggered / onStarted / onGoing\nonCanceled / onCompleted\nAll default to no-op lambdas"]
end
subgraph PLAYER["ACPlayer1STCharacter"]
INIT["initActionEvent\nOverrides no-op lambdas\nwith game logic"]
end
SETUP --> MACRO
MACRO --> IFACE
PLAYER -.->|"fills slots"| IFACE10b. Input Action Mapping
The 15 input actions grouped by category (Movement, Combat, Camera, UI) with their physical key bindings and behavior descriptions.
flowchart TB
subgraph MOVEMENT["Movement"]
MOVE["moveEvent / FVector2D\nZQSD Arrows Gamepad L\nforward + strafe or 1-stick mobile"]
ROTATE["rotateEvent / FVector2D\nMouse XY Gamepad R\nyaw + pitch"]
JUMP["jumpEvent / bool\nSpaceBar\nstart/end jump"]
end
subgraph COMBAT["Combat"]
LMB["LMBEvent / bool\nLeft Click\ntop view with click-to-move or attack\n1st view with melee"]
CTRL_LMB["ctrlLMBEvent / bool\nCtrl + Left Click\nrange attack hold"]
BLOCK_EV["blockEvent / bool\nTab\nstart/end block"]
end
subgraph CAMERA["Camera"]
SCROLL["scrollEvent / float\nMouse Wheel\narm length zoom 10% step"]
PINCH["pinchEvent / float\nGesture_Pinch mobile\nratio-based zoom"]
ALT_SCROLL["alternativeScrollEvent / float\nCtrl + Mouse Wheel\nFOV 1-180 degrees"]
RMB["RMBEvent / bool\nRight Click\ncamera rotation"]
CHANGE["changeViewEvent / bool\nV key\nchangeView toggle"]
end
subgraph UI["Interaction and UI"]
INTERACT["interactEvent / bool\nF key\nexecuteInteraction on target"]
TOUCH["touchEvent / bool\nTouch mobile\n3 fingers with changeView"]
RESOURCE["displayResourceEvent / bool\nI key\nspawnResourceWidget"]
MAP["displayMapEvent / bool\nM key\nshowOrHideMap"]
end11. UCPlayerInitializer Teleport and Possess Workflow
How UCPlayermaker::finishSpawning() creates a UCPlayerInitializer tickable that waits for room and tile readiness before teleporting and possessing the player pawn.
sequenceDiagram
participant PM as UCPlayermaker
participant PI as UCPlayerInitializer
participant RU as RoomUtility
participant WU as WorldUtility
participant P as Player Pawn
PM ->> PI: doForever creates UCPlayerInitializer
PM ->> PI: set pawn, mainTag, tagArray,<br/>whereToTeleport, whatToDoWhenReady
PI ->> RU: bind onRoomBuilt
PI ->> WU: bind onTileReady
alt rooms already built
PM ->> PI: call onRoomBuilt immediately
else rooms not built yet
RU -->> PI: onRoomBuilt event
end
alt whereToTeleport already set
PI ->> PI: skip room search
else whereToTeleport not set
PI ->> RU: iterateOnClusterRoom
RU -->> PI: find eligible room by mainTag and tagArray
PI ->> PI: whereToTeleport = room.center
end
PI ->> WU: worldTileReadyAt x y
alt tile fullLOD
PI ->> P: teleport Z = zCalculate + capsuleHalfHeight
PI ->> P: setActivated and resetAll
PI ->> P: SetViewTargetWithBlend
PI ->> P: Possess
PI ->> PI: stop and unbind
else tile not ready or not fullLOD
PI ->> P: teleport only
WU -->> PI: onTileReady event
alt fullLOD and matching uvIndex
PI ->> P: teleport
PI ->> P: setActivated and resetAll
PI ->> P: SetViewTargetWithBlend
PI ->> P: Possess
PI ->> PI: stop and unbind
else not fullLOD
PI ->> P: teleport only
end
end