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 — creates USLPrimaryGameLayout + USLHUDWidget on BeginPlay

#Weapon System

  • ASLWeaponActor — persistent world actor; owns WeaponData (config) and CurrentAmmo (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 + FP Local Only)
  • SetPendingEquipWeapon — server-only, finalizes all state immediately; ability handles animation only
  • Anim notify (SLAnimNotify_SendGameplayEvent) fires Equip_Attach tag at the correct montage frame
  • OnRep_EquippedWeapon — broadcasts OnEquippedWeaponChanged on all clients; drives simulated proxy mesh attach + anim layer link automatically
  • Per-weapon equip Gameplay Cue support (EquipCueTag)

#Fire System

  • USLGameplayAbility_FireLocal Predicted; handles full shot loop: timing, tracing, damage, recoil, cue dispatch
  • Full-auto (RPM timer) and single-shot modes
  • Client-predicted shot validation — QueueShotsForValidationServer_ProcessShotsMulticast_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

  • USLAmmoAttributeSetCurrentAmmo + MaxAmmo GAS attributes, replicated to all clients
  • Per-shot decrement via GE_SL_AmmoDecrement (Instant GE, -1 Add on authority)
  • On equip: weapon actor's CurrentAmmo pushed into the attribute set
  • On unequip: attribute value written back to the weapon actor — each weapon retains its own ammo independently
  • OnAmmoChanged(CurrentAmmo, MaxAmmo)BlueprintAssignable delegate on USLWeaponsComponent, 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 — USLPrimaryGameLayout with HUD, Game, Menu, Modal layers
  • USLHUDWidget — persistent overlay; hosts ReticleContainer, NotificationContainer, and AmmoStrip; exposes ShowWeaponPickupPrompt / HideWeaponPickupPrompt BP events; ShowTimedNotification(WidgetClass, Data, Duration) / HideTimedNotification() for transient HUD messages
  • USLReticle — per-weapon crosshair; swapped via SwapReticle() on equip; driven by OnSpreadChanged + OnTargetDetected
  • USLAmmoWidget — per-weapon ammo display (C++ base); implements OnAmmoChanged(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_AmmoStrip BP subclass); equipped weapon always on top, secondaries below; driven by OnCarriedWeaponsChanged + OnEquippedWeaponChanged; initialized from InitializeLocalPlayerHUD on every possession
  • USLNotificationWidget — base class for timed HUD notifications; FSLNotificationData struct (Message, SubMessage, WeaponData, Icon, Sound); OnShow(Data) BlueprintImplementableEvent
  • Spread calculation — GetCurrentSpread(PlayerSpeed) on USLWeaponsComponent
  • Target detection — CheckForEnemyTarget(...) on USLWeaponsComponent

#Notifications

  • USLNotificationWidget (Public/UI/SLNotificationWidget.h) — abstract base; FSLNotificationData struct carries message, sub-message, weapon data ref, icon, and optional sound
  • ShowTimedNotification / HideTimedNotification on USLHUDWidget — auto-dismiss timer, replaces previous notification immediately
  • MakeNotificationDataFromWeapon on USL_BlueprintLibrary — pre-populates FSLNotificationData from a USLWeaponDataAsset (icon from WeaponIcon, sub-message defaults to WeaponDisplayName)
  • Client_ShowAmmoPickupNotification(WeaponData) RPC + OnAmmoPickupNotification BlueprintImplementableEvent on ASLCharacterBase — routes server ammo pickup events to the owning client's HUD

#Editor Utilities

  • Weapon Icon Generator — editor utility BP + USLWeaponIconGenerator C++ library; two-pass transparent background with adjustable BackgroundAlphaTolerance, auto-fit camera, optional background plane (bBackgroundPlane, BackgroundPlaneColor, BackgroundPlaneSizeMultiplier), mesh overlay material, outline dilation pass, full mip chain generation; outputs UTexture2D assets for use in the ammo HUD widget

#Weapon Pickup — Full Flow ✅

  • IA_SL_Interact input action wired → Server_AcceptPickup
  • OnShowPickupPrompt / OnHidePickupPrompt → HUD widget events
  • ShowWeaponPickupPrompt / HideWeaponPickupPrompt implemented in WBP_SL_HUD
  • Drop on death — Server_DropWeapon called for all carried weapons on death event

#Health / Damage / Death (Core)

  • USLHealthAttributeSet — CurrentHealth, MaxHealth, CurrentShield, MaxShield; all replicated
  • USLDamageExecution — shield-first absorption; SetByCaller tag SLTags::Data::Damage
  • GE_Damage Blueprint — Instant, wired into both ExecuteFire_ListenServerHost and Server_ProcessShots
  • GE_Dead Blueprint — Infinite, grants States.Character.Dead via Target Tags
  • USLGameplayAbility_Death C++ base + BP_GA_SL_Death Blueprint — triggered by Events.Character.Death gameplay event; applies GE_Dead, cancels all abilities, executes DeathCueTag cue, disables collision/movement, calls OnDeathStarted
  • GC_Death Blueprint — GameplayCueNotify_Static; locally controlled: TP view switch; plays death montage
  • Dead tag added to ActivationBlockedTags in USLGameplayAbility constructor
  • bIsDead in FSLAnimState driven by replicated Dead gameplay tag — death animation visible on all clients
  • GE_ShieldRegenDelay Blueprint — Has Duration (3s), grants ShieldRechargingDelay, removes itself + ShieldRecharging GEs on reapplication
  • GE_ShieldRegen Blueprint — Infinite, Period 0.1s, OngoingTagRequirements.MustNotHaveTags = ShieldRechargingDelay; auto-starts when delay expires, stopped by C++ when shield is full
  • DropWeaponActor(WeaponActor*) on ASLCharacterBase — non-RPC authority-guarded drop for use in death BP loop
  • ESLHitDirection4 — 4-way enum for Anim BP; FSLAnimState.HitDirection + LastHitDirection are 4-way; 8-way → 4-way collapse in BuildAnimSnapshots
  • LastHitDirectionReplicated — replicated ESLHitDirection on character; simulated proxy fallback in BuildAnimSnapshots
  • 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() from PostGameplayEffectExecute; reads DeathAnimationTimeout from GameMode; fires RequestRespawn independently of AnimNotify; works on dedicated servers
  • Death camera — camera boom re-attached to pelvis, arm extended, lag enabled, TickDeathCamera() looks at spine_03
  • bDebug on character — gates death/respawn on-screen debug prints; Server_DebugForceRespawn() for testing (stripped in Shipping)
  • GE_Respawn Blueprint — resets CurrentHealth + CurrentShield to Max on new pawn via Instant + Attribute Based Override
  • OnPawnInitialized(bool bIsRespawn)BlueprintImplementableEvent BlueprintCallable on ASLCharacterBase; fires on owning client when controller + ASC are valid; use instead of BeginPlay for any BP init requiring a valid controller or ASC
  • Client_PawnInitialized RPC + two-flag coordination — handles both arrival orderings of RPC vs OnRep_PlayerState
  • InitializeLocalPlayerHUD(ASC) — private C++ helper on ASLPlayerCharacter; restores HUD + re-inits health/damage widgets; called from all three possession paths
  • ASLPlayerController::IsCharacterDead() + dead-checks in all input handlers (except Look) — replaces DisableInput/EnableInput entirely; no input system state to manage on death or respawn
  • USLWeaponsComponent::UnbindAllDelegates()BlueprintCallable; clears OnEquippedWeaponChanged + OnAmmoChanged BP bindings; call from OnClientDeathStarted
  • Respawn overlay on PlayerController — ShowRespawnOverlay / HideRespawnOverlay BP methods; widget stored on PC to survive pawn swap; uses Add to Player Screen (not Push to Game Stack)
  • HUD WeaponsComponent rebind pattern — unbind in OnClientDeathStarted, rebind + update character references in OnPawnInitialized

#Animation

  • FSLAnimState snapshotted 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

  • CarriedWeaponsReplicated TArray<ASLWeaponActor*> on ASLCharacterBase
  • 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), NetMulticast FX hook, OnCollected / OnOverlapEnd virtuals
  • ASLWeaponPickup — two modes: map-placed (lazy spawn from WeaponActorClass) and dropped (set via SetWeapon)
  • 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)OnShowPickupPrompt BP event on character
  • Server_AcceptPickup() RPC — player presses interact, server grants weapon via AcceptPickup()
  • Overlap exit → Client_HidePickupPrompt()OnHidePickupPrompt BP event on character
  • ASLAmmoPickup — standalone ammo-only pickup; WeaponData targets a specific weapon type; AmmoAmount (default 30); checks carried weapons by data asset, respects the equipped/unequipped ammo split, calls AddAmmo + Client_ShowAmmoPickupNotification
  • USLHUDWidget exposes ShowWeaponPickupPrompt(WeaponData) / HideWeaponPickupPrompt() BP events for the prompt UI
  • Pickup launch arcASLPickupBase has BounceCollision (root, blocks world geo) + ProjectileMovementComponent; LaunchPickup(Direction) applies random spread within LaunchSpreadAngle, bounces MaxBounces times, re-enables trigger on landing; BP_OnPickupLanded fires on all clients
  • Drop weaponServer_DropWeapon on ASLCharacterBase; spawns ASLWeaponPickup at DropSpawnOffset (default 40 fwd / 50 up), calls LaunchPickup; OnWeaponDropped BlueprintNativeEvent for per-character FX

See WeaponPickup.md for the full design.

#Shotgun (full) — complete ✅ (2026-05-20)

  • Pump-action 8-pellet hitscan, PostFireDelay driven pump animation, positional + camera recoil, MuzzleSocket alignment, GAS-replicated TP fire montage, Always Reset on Entry non-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 via USLReticle::OnWeaponFired)
  • See Docs/Shotgun.md for the full spec and Docs/CurrentFocus.md for 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 to ECC_GameTraceChannel1 in Types/SLCollisionChannels.h
  • Capsule ignores WeaponTrace; Physics Asset bodies on SK_MasterChief block it
  • ESLBoneGroup enum (Body/Head/Arms/Legs), FSLDamageMultipliers per-fire-mode struct, BoneGroupAnchors parent-chain walk on ASLCharacterBase
  • Debug prints on hit (gated on bDebug on 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.cs server)
  • Seamless travel for map transitions

#Deferred / Lower Priority

FeatureNotes
Throw empty weaponOnAmmoChanged trigger + throw GAS ability + physics launch + weapon-as-projectile. Infrastructure already in place.
Secondary fire modeTwo-phase chord (left trigger = mode, right trigger = fire). Full design in memory.
Multiple weapon typesOnly AssaultRifle and Shotgun exist. Adding a new weapon is a Blueprint-only task — pattern is established.
Infinite ammoGlobal / per-character / per-fire-mode layers. Decrement GE already skippable.