Now · Updated Jun 16, 2026
SystemLink — Development Progress
SystemLink — Development Progress
Halo + Doom Eternal hybrid FPS framework on Unreal Engine 5.7. All gameplay logic lives in Plugins/SystemLinkCore/.
#Completed
#Character
ASLCharacterBase— FP/TP mesh setup,WeaponsComponent, GAS interface,BuildAnimSnapshots()tick
ASLPlayerCharacter— FP/TP view mode toggle, camera setup
ASLPlayerState— ASC host (server-authoritative, replicated)
ASLPlayerHUD— createsUSLPrimaryGameLayout+USLHUDWidgeton BeginPlay
#Weapon System
ASLWeaponActor— persistent world actor; ownsWeaponData(config) andCurrentAmmo(replicated state); survives equip/unequip/drop cycles
USLWeaponDataAsset— per-weapon config: fire modes, meshes, montages, IK settings, sway/lag settings, equip abilities, cue tags, reticle class, ammo widget class
USLWeaponsComponent— weapon brain: equip/unequip, mesh attachment, anim layer linking, recoil, shot validation, ammo attribute management
#Equip System
- GAS-driven per-weapon equip abilities (TP
Server Initiated+ FPLocal Only)
SetPendingEquipWeapon— server-only, finalizes all state immediately; ability handles animation only
- Anim notify (
SLAnimNotify_SendGameplayEvent) firesEquip_Attachtag at the correct montage frame
OnRep_EquippedWeapon— broadcastsOnEquippedWeaponChangedon all clients; drives simulated proxy mesh attach + anim layer link automatically
- Per-weapon equip Gameplay Cue support (
EquipCueTag)
#Fire System
USLGameplayAbility_Fire—Local Predicted; handles full shot loop: timing, tracing, damage, recoil, cue dispatch
- Full-auto (RPM timer) and single-shot modes
- Client-predicted shot validation —
QueueShotsForValidation→Server_ProcessShots→Multicast_OnShotsConfirmed
- Recoil — per-shot pitch kick + random yaw, recovers over time,
GetRecoilMagnitude()for TP additive pose
- Sphere sweep fallback for hit validation latency forgiveness
#Ammo System
USLAmmoAttributeSet—CurrentAmmo+MaxAmmoGAS attributes, replicated to all clients
- Per-shot decrement via
GE_SL_AmmoDecrement(Instant GE, -1 Add on authority)
- On equip: weapon actor's
CurrentAmmopushed into the attribute set
- On unequip: attribute value written back to the weapon actor — each weapon retains its own ammo independently
OnAmmoChanged(CurrentAmmo, MaxAmmo)—BlueprintAssignabledelegate onUSLWeaponsComponent, fires on every attribute change
#Gameplay Cues
- Fire cue (
FireCueTag) — muzzle flash, fire sound, shell eject; replicated to all clients via GAS
- Stop-fire cue (
StopFireCueTag) — looping effect cleanup on all clients
- Impact cue (
ImpactCueTag) — confirmed hit VFX/SFX; owning client uses predicted path instead
- Equip cue (
EquipCueTag) — holster sounds, attach VFX; replicated
- Cue Manager scans
Content/SystemLink/AbilitySystem/Cues/recursively
#HUD
- CommonUI stack —
USLPrimaryGameLayoutwith HUD, Game, Menu, Modal layers
USLHUDWidget— persistent overlay; hostsReticleContainer,NotificationContainer, andAmmoStrip; exposesShowWeaponPickupPrompt/HideWeaponPickupPromptBP events;ShowTimedNotification(WidgetClass, Data, Duration)/HideTimedNotification()for transient HUD messages
USLReticle— per-weapon crosshair; swapped viaSwapReticle()on equip; driven byOnSpreadChanged+OnTargetDetected
USLAmmoWidget— per-weapon ammo display (C++ base); implementsOnAmmoChanged(CurrentAmmo, MaxAmmo)BIE +SetWeapon(WeaponActor)to subscribe to a specific weapon actor's ammo delegate
USLAmmoStrip— Halo 3-style multi-slot weapon strip (C++ base +WBP_SL_AmmoStripBP subclass); equipped weapon always on top, secondaries below; driven byOnCarriedWeaponsChanged+OnEquippedWeaponChanged; initialized fromInitializeLocalPlayerHUDon every possession
USLNotificationWidget— base class for timed HUD notifications;FSLNotificationDatastruct (Message, SubMessage, WeaponData, Icon, Sound);OnShow(Data)BlueprintImplementableEvent
- Spread calculation —
GetCurrentSpread(PlayerSpeed)onUSLWeaponsComponent
- Target detection —
CheckForEnemyTarget(...)onUSLWeaponsComponent
#Notifications
USLNotificationWidget(Public/UI/SLNotificationWidget.h) — abstract base;FSLNotificationDatastruct carries message, sub-message, weapon data ref, icon, and optional sound
ShowTimedNotification/HideTimedNotificationonUSLHUDWidget— auto-dismiss timer, replaces previous notification immediately
MakeNotificationDataFromWeapononUSL_BlueprintLibrary— pre-populatesFSLNotificationDatafrom aUSLWeaponDataAsset(icon fromWeaponIcon, sub-message defaults toWeaponDisplayName)
Client_ShowAmmoPickupNotification(WeaponData)RPC +OnAmmoPickupNotificationBlueprintImplementableEvent onASLCharacterBase— routes server ammo pickup events to the owning client's HUD
#Editor Utilities
- Weapon Icon Generator — editor utility BP +
USLWeaponIconGeneratorC++ library; two-pass transparent background with adjustableBackgroundAlphaTolerance, auto-fit camera, optional background plane (bBackgroundPlane,BackgroundPlaneColor,BackgroundPlaneSizeMultiplier), mesh overlay material, outline dilation pass, full mip chain generation; outputsUTexture2Dassets for use in the ammo HUD widget
#Weapon Pickup — Full Flow ✅
IA_SL_Interactinput action wired →Server_AcceptPickup
OnShowPickupPrompt/OnHidePickupPrompt→ HUD widget events
ShowWeaponPickupPrompt/HideWeaponPickupPromptimplemented inWBP_SL_HUD
- Drop on death —
Server_DropWeaponcalled for all carried weapons on death event
#Health / Damage / Death (Core)
USLHealthAttributeSet— CurrentHealth, MaxHealth, CurrentShield, MaxShield; all replicated
USLDamageExecution— shield-first absorption;SetByCallertagSLTags::Data::Damage
GE_DamageBlueprint — Instant, wired into bothExecuteFire_ListenServerHostandServer_ProcessShots
GE_DeadBlueprint — Infinite, grantsStates.Character.Deadvia Target Tags
USLGameplayAbility_DeathC++ base +BP_GA_SL_DeathBlueprint — triggered byEvents.Character.Deathgameplay event; applies GE_Dead, cancels all abilities, executes DeathCueTag cue, disables collision/movement, calls OnDeathStarted
GC_DeathBlueprint — GameplayCueNotify_Static; locally controlled: TP view switch; plays death montage
- Dead tag added to
ActivationBlockedTagsinUSLGameplayAbilityconstructor
bIsDeadinFSLAnimStatedriven by replicated Dead gameplay tag — death animation visible on all clients
GE_ShieldRegenDelayBlueprint — Has Duration (3s), grantsShieldRechargingDelay, removes itself + ShieldRecharging GEs on reapplication
GE_ShieldRegenBlueprint — Infinite, Period 0.1s,OngoingTagRequirements.MustNotHaveTags = ShieldRechargingDelay; auto-starts when delay expires, stopped by C++ when shield is full
DropWeaponActor(WeaponActor*)onASLCharacterBase— non-RPC authority-guarded drop for use in death BP loop
ESLHitDirection4— 4-way enum for Anim BP;FSLAnimState.HitDirection+LastHitDirectionare 4-way; 8-way → 4-way collapse inBuildAnimSnapshots
LastHitDirectionReplicated— replicatedESLHitDirectionon character; simulated proxy fallback inBuildAnimSnapshots
IsDead()—BlueprintPure; ragdoll latch OR Dead tag; safe on all machines
OnClientDeathStarted()—BlueprintImplementableEvent BlueprintCallable; fires on owning client; BP hides HUD, unbinds WeaponsComponent delegates, shows respawn overlay
- Server-side death timeout —
StartServerDeathTimeout()fromPostGameplayEffectExecute; readsDeathAnimationTimeoutfrom GameMode; firesRequestRespawnindependently of AnimNotify; works on dedicated servers
- Death camera — camera boom re-attached to pelvis, arm extended, lag enabled,
TickDeathCamera()looks atspine_03
bDebugon character — gates death/respawn on-screen debug prints;Server_DebugForceRespawn()for testing (stripped in Shipping)
GE_RespawnBlueprint — resets CurrentHealth + CurrentShield to Max on new pawn via Instant + Attribute Based Override
OnPawnInitialized(bool bIsRespawn)—BlueprintImplementableEvent BlueprintCallableonASLCharacterBase; fires on owning client when controller + ASC are valid; use instead of BeginPlay for any BP init requiring a valid controller or ASC
Client_PawnInitializedRPC + two-flag coordination — handles both arrival orderings of RPC vsOnRep_PlayerState
InitializeLocalPlayerHUD(ASC)— private C++ helper onASLPlayerCharacter; restores HUD + re-inits health/damage widgets; called from all three possession paths
ASLPlayerController::IsCharacterDead()+ dead-checks in all input handlers (exceptLook) — replacesDisableInput/EnableInputentirely; no input system state to manage on death or respawn
USLWeaponsComponent::UnbindAllDelegates()—BlueprintCallable; clearsOnEquippedWeaponChanged+OnAmmoChangedBP bindings; call fromOnClientDeathStarted
- Respawn overlay on PlayerController —
ShowRespawnOverlay/HideRespawnOverlayBP methods; widget stored on PC to survive pawn swap; usesAdd to Player Screen(notPush to Game Stack)
- HUD WeaponsComponent rebind pattern — unbind in
OnClientDeathStarted, rebind + update character references inOnPawnInitialized
#Animation
FSLAnimStatesnapshotted every tick — velocity, aim angles, look rates, movement flags
- LHIK FP/TP snapshots for left-hand IK
CalculateWeaponSwayTransform()— idle and movement sway
CalculateWeaponLag()— rotational lag
CheckFPWeaponObstruction()— wall-proximity viewmodel pullback
#Weapon Inventory
CarriedWeapons—Replicated TArray<ASLWeaponActor*>onASLCharacterBase
AddWeaponToInventory(WeaponActor)— authority guard, duplicate check
FindCarriedWeaponByData(DataAsset)— finds a carried weapon by its data asset pointer
GetCarriedWeapons()— BP-readable accessor
#Weapon Pickup
ASLPickupBase— abstract base; sphere overlap (server-only),NetMulticastFX hook,OnCollected/OnOverlapEndvirtuals
ASLWeaponPickup— two modes: map-placed (lazy spawn fromWeaponActorClass) and dropped (set viaSetWeapon)
- Ammo top-up path — player already carries that weapon type →
AddAmmo(),Client_ShowAmmoPickupNotification(), auto-collect, no prompt
- Pickup prompt path — new weapon →
SetPendingPickup,Client_ShowPickupPrompt(WeaponData)→OnShowPickupPromptBP event on character
Server_AcceptPickup()RPC — player presses interact, server grants weapon viaAcceptPickup()
- Overlap exit →
Client_HidePickupPrompt()→OnHidePickupPromptBP event on character
ASLAmmoPickup— standalone ammo-only pickup;WeaponDatatargets a specific weapon type;AmmoAmount(default 30); checks carried weapons by data asset, respects the equipped/unequipped ammo split, callsAddAmmo+Client_ShowAmmoPickupNotification
USLHUDWidgetexposesShowWeaponPickupPrompt(WeaponData)/HideWeaponPickupPrompt()BP events for the prompt UI
- Pickup launch arc —
ASLPickupBasehasBounceCollision(root, blocks world geo) +ProjectileMovementComponent;LaunchPickup(Direction)applies random spread withinLaunchSpreadAngle, bouncesMaxBouncestimes, re-enables trigger on landing;BP_OnPickupLandedfires on all clients
- Drop weapon —
Server_DropWeapononASLCharacterBase; spawnsASLWeaponPickupatDropSpawnOffset(default 40 fwd / 50 up), callsLaunchPickup;OnWeaponDroppedBlueprintNativeEvent for per-character FX
See WeaponPickup.md for the full design.
#Shotgun (full) — complete ✅ (2026-05-20)
- Pump-action 8-pellet hitscan,
PostFireDelaydriven pump animation, positional + camera recoil, MuzzleSocket alignment, GAS-replicated TP fire montage,Always Reset on Entrynon-looping fire state, Inertialization node in the TP ABP
- HUD:
T_Icon_Shotgun(Nano Banana + Icon Generator),WBP_SL_Ammo_Shotgun(Doom Eternal-style numeric counter, MaxAmmo = 60),WBP_SL_Reticle_Shotgun(fixed cyan ring + corner brackets, fire/ready bracket-position animation viaUSLReticle::OnWeaponFired)
- See
Docs/Shotgun.mdfor the full spec andDocs/CurrentFocus.mdfor session history
#Hit Detection Refinement — complete ✅ (2026-05-20)
Per-bone hit detection. Hit.BoneName populates from Physics Asset bodies; per-weapon damage multipliers applied at both authoritative dispatch sites. Headshots and limb damage now work.
- Custom trace channel
ECC_WeaponTrace(default response: Block) — aliased toECC_GameTraceChannel1inTypes/SLCollisionChannels.h
- Capsule ignores
WeaponTrace; Physics Asset bodies onSK_MasterChiefblock it
ESLBoneGroupenum (Body/Head/Arms/Legs),FSLDamageMultipliersper-fire-mode struct,BoneGroupAnchorsparent-chain walk onASLCharacterBase
- Debug prints on hit (gated on
bDebugon fire ability + weapons component)
- See
Docs/DamagePipeline.md§ 0 for the multiplier flow
#Backlog — Ordered by Priority
#1. Multi-Slot Weapon HUD — complete ✅ (2026-05-22)
Halo 3-style stacked weapon-slot strip. Both carried weapons show live ammo simultaneously; equipped weapon on top (active scale/opacity), secondary below (dimmed). Ammo updates instantly on shots and pickups. See Docs/WeaponsSystem.md → Ammo Display for the architecture.
#2. Shotgun fire cosmetics + shell ejection — complete ✅ (2026-05-22)
Shotgun-specific sound + muzzle flash wired in OnLocallyPredictedShotFired; shell ejection implemented.
#3. Secondary Weapon — Left-Hand Sidearm
Reframed from alt-fire to a dedicated left-hand pistol: hold LT draws a sidearm (primary lowers cosmetically), RT fires it. Dedicated always-populated, swappable, non-droppable sidearm slot (separate from the 2 main slots). Same GAS-tag chord backbone. Reuses the existing fire pipeline. Biggest cost is animation (lowered-primary + pistol-raised poses). Full design: Docs/SecondaryWeapon.md.
#4. Melee — core complete ✅ (Standalone-verified 2026-05-29), final polish remaining
Full GAS melee: backstab one-shot, timer-driven authoritative damage (notify-independent), replicated impact cue, camera shakes, wall-hit FX, weapon-clipping handling, eye-origin view sweep. AR + Shotgun ABP states done. Remaining: unarmed melee anim/state, SFX assets, camera-shake asset assignment, range tuning. See Docs/Melee.md → "Remaining polish".
#Known minor polish (non-blocking)
- GameplayCue cold-start miss — the first instance of a cue per client session can be dropped
(e.g. shield-down FX on the first melee hit) because the GameplayCueNotify async-loads on first reference. Self-heals after one load; cosmetic-only. Fix when convenient: preload cue notifies at startup (sync-load the cue manager runtime library, or warm the GC_ classes via a primary asset list).
#5. Menus / CommonUI Foundation
Pause menu, settings, and modal system built on CommonUI. Works with controller and keyboard/mouse. Design + footgun reference fully documented in Docs/UISystem.md. Layer scaffolding already in place. Comes before grenades because a working pause menu makes testing all subsequent features much easier. Remaining: UI input actions + IMC, CommonUI data assets, controller data assets, C++ base classes (USLButtonBase, USLScreenWidget, USLModalWidget, USLTabListWidget), pop/clear API on layout, pause wiring in SLPlayerController, Blueprint subclasses + visual layout. See Docs/UISystem.md § 7 for the full build order.
#6. Hand Grenades — design locked, not started
Full plan: Docs/GrenadeSystem.md. Simple throw, no cooking (struck from scope). GAS ability, projectile spawned on server (arc + bounce via ProjectileMovementComponent, reusing the BUG-019 fix), timed fuse → radial damage (sphere sweep + damage GE falloff) + explosion cue. Count = replicated int32 on ASLCharacterBase (resets on respawn, no new attribute set). Increment 1 = frag only, end-to-end playable; Increment 2 = plasma (sticky) + per-type counts + switching. (Note: this was previously slotted after #5 so a pause menu would ease testing — Beepers opted to do grenades first; testing stays PIE-based as before.)
#7. Mobility Assist Module (MMA-3) — design done, not started
Doom Eternal-style double jump + air dash, provided by an equippable Mobility Assist Module (data asset + component + GAS ability bundle). 2 dash charges with timed recharge, 1 double jump per airtime, dash directions limited to forward/left/right. Full plan in Docs/MobilityAssistModule.md.
#8. Match Structure
- Game mode — score tracking, kill feed, win condition (score limit or time limit)
- Respawn — spawn point selection, respawn timer
- End-of-match screen
#9. Online Subsystem + Dedicated Server
- EOS or Steam session creation, matchmaking, NAT traversal
- Dedicated server build target (
SystemLink.Target.csserver)
- Seamless travel for map transitions
#Deferred / Lower Priority
| Feature | Notes |
|---|---|
| Throw empty weapon | OnAmmoChanged trigger + throw GAS ability + physics launch + weapon-as-projectile. Infrastructure already in place. |
| Secondary fire mode | Two-phase chord (left trigger = mode, right trigger = fire). Full design in memory. |
| Multiple weapon types | Only AssaultRifle and Shotgun exist. Adding a new weapon is a Blueprint-only task — pattern is established. |
| Infinite ammo | Global / per-character / per-fire-mode layers. Decrement GE already skippable. |