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()
    end

3. 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.

Cell-Based Spatial Pooling Cell-Based Spatial Pooling

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 callback

7. 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 -.-> DISPATCH

8. 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"| TBT

8b. 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"| IFACE

10b. 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"]
    end

11. 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