Weapons · Updated May 22, 2026
System Link — New Weapon Checklist
System Link — New Weapon Checklist
End-to-end steps for adding a new weapon to SystemLink. Follow in order — earlier steps unlock later ones (e.g. native tags must exist before the GAS ability BPs can pick them).
The Assault Rifle is the canonical reference. When in doubt about a property value or asset layout, duplicate the AR's equivalent and customize.
Naming convention: all assets use<Prefix>_SL_<WeaponName>_<Detail>(e.g.BP_GA_SL_Shotgun_PrimaryFire,DA_SL_Shotgun). Weapon-specific assets live underContent/SystemLink/Weapons/<WeaponName>/.
#1. Native Gameplay Tags
Add new tags before anything else — every later step references them.
#In Plugins/SystemLinkCore/Source/SystemLinkCore/Private/GameplayTags/SLTags.cpp
Per-weapon ability tags (paired with the equip ability BPs):
UE_DEFINE_GAMEPLAY_TAG(FirstPerson_<WeaponName>, "SLTags.Abilities.Equip.FirstPerson.<WeaponName>");
UE_DEFINE_GAMEPLAY_TAG(ThirdPerson_<WeaponName>, "SLTags.Abilities.Equip.ThirdPerson.<WeaponName>");
#In Config/DefaultGameplayTags.ini
Cue tags (used by the fire/impact gameplay cues). These don't need C++ declarations — just register them in the ini:
+GameplayTagList=(Tag="GameplayCues.Weapon.<WeaponName>.PrimaryFire")
+GameplayTagList=(Tag="GameplayCues.Weapon.<WeaponName>.Impact")
Add a StopFireCue tag too if the weapon has looping fire effects (rare — only full-auto weapons with sustained loops).
#2. Mesh Assets
#Skeletal Meshes
- FP mesh (
SK_<WeaponName>_FP) — first-person view, usually a stylized cleaner pose
- TP mesh (
SK_<WeaponName>) — third-person, full-detail, viewed by other players
Both rigged to a skeleton that supports the IK + animation conventions used elsewhere in the project. The AR's skeleton is the reference — if your weapon's anatomy is similar, share the skeleton; if not, duplicate and modify.
#Required Sockets
| Socket Name | On Mesh | Purpose |
|---|---|---|
MuzzleFlash | FP and TP mesh | Spawn location for muzzle flash, fire cue, hit traces |
AttachPoint | FP and TP mesh | Where the character hand grips the weapon (matches AttachSocketName on FSLWeaponSkeletalMeshData) |
| Left-hand IK socket (named per-weapon) | FP and TP mesh | Where the character's left hand grips for IK — LeftHandIKEffectorSocketName in mesh data |
| Left-hand IK joint target (optional) | FP and TP mesh | Pole-vector reference for the IK chain — LeftHandIKJointTargetSocketName |
ShellEjectSocket (optional) | TP mesh | Shell ejection spawn point (only weapons with visible casings) |
Verify the MuzzleFlash socket's +X axis points down the barrel — if rotated 90° off, the TP fire cue and trace origin will be wrong. (This was the shotgun bug fixed mid-shotgun-branch.)
#3. Weapon Data Asset
DA_SL_<WeaponName> (class: USLWeaponDataAsset) under Content/SystemLink/Weapons/<WeaponName>/. The single most important asset — all per-weapon config lives here.
#First/Third Person Mesh Data — FSLWeaponSkeletalMeshData (two instances)
| Field | Notes |
|---|---|
WeaponMesh | The skeletal mesh asset for this view |
AttachSocketName | Hand-bone socket on the character mesh (typically hand_r) |
RightHandBoneName | Reference bone for left-hand IK BoneSpace (typically hand_r) |
LeftHandIKEffectorSocketName | Socket on the weapon mesh used as left-hand target |
LeftHandIKJointTargetSocketName | Optional pole-vector reference socket |
LeftHandIKAlpha | 0–1, blend strength of the left-hand IK |
AnimLayerClass | Anim layer linked into the character mesh's ABP (arm pose, IK) |
WeaponMeshAnimClass | Standalone ABP set directly on the weapon mesh (bolt cycle, pump, etc.). Null for static weapons. |
EquipMontage | Animation montage played on this view's mesh during equip |
#Primary Fire Mode — FSLWeaponFireMode
| Field | Notes |
|---|---|
bEnabled | Set true |
FireType | Hitscan or Projectile |
FireMode | FullAuto or SingleShot |
RoundsPerMinute | For full-auto only |
PostFireDelay | Seconds the ability stays alive after firing — drives pump/bolt animations via bIsFiring. Single-shot only. |
BulletConeAngleDegrees | Half-angle of stationary spread |
MaxBulletConeAngleDegrees | Half-angle of max-movement spread |
MaxBulletSpreadSpeed | Player speed at which spread reaches max |
PelletCount | Shots per trigger pull (1 for normal, 8+ for shotgun) |
MaxAmmo | Total ammo capacity — no reload model, set high enough that reload isn't needed (AR=600, Shotgun=60) |
BaseDamage | Per-pellet damage |
DamageMultipliers | Per-body-part multipliers (Body/Head/Arms/Legs). Defaults: 1.0 / 2.0 / 0.75 / 0.75. Override per-weapon if a specific weapon needs different headshot/limb tuning (e.g. Head = 1.5 on shotgun to avoid one-shot kills). See Docs/DamagePipeline.md § 0. |
MaxRange | Trace distance in cm |
MuzzleSocketName | Must match a socket on the FP and TP mesh |
AmmoDecrementEffect | GE_SL_AmmoDecrement — reused across all weapons |
FireCueTag | GameplayCues.Weapon.<WeaponName>.PrimaryFire |
StopFireCueTag | Optional, for looping fire sounds |
ImpactCueTag | GameplayCues.Weapon.<WeaponName>.Impact |
RecoilPitchKick | Upward kick per shot |
RecoilYawRange | Random horizontal kick range |
RecoilRecoverySpeed | How fast recoil decays |
RecoilKickbackDistance | Positional kick on FP viewmodel (cm) |
RecoilLateralRange | Random lateral position kick (cm) |
#HUD
| Field | Notes |
|---|---|
PrimaryReticleClass | WBP_SL_Reticle_<WeaponName> |
SecondaryReticleClass | Only if the weapon has a secondary fire mode |
AmmoWidgetClass | WBP_SL_Ammo_<WeaponName> |
WeaponIcon | T_Icon_<WeaponName> texture |
WeaponDisplayName | Human-readable name shown in pickup prompts |
#Other
| Field | Notes |
|---|---|
Equip cue tag (EquipCueTag) | Per-weapon equip cue if desired |
| FP/TP equip ability classes | BP_GA_SL_FP_<WeaponName>_Equip, BP_GA_SL_TP_<WeaponName>_Equip |
| Primary fire ability class | BP_GA_SL_<WeaponName>_PrimaryFire |
#4. GAS Abilities
Duplicate the AR's abilities and customize. Always BP_GA_SL_<WeaponName>_<Detail> under Content/SystemLink/AbilitySystem/Abilities/Weapons/<WeaponName>/.
#Equip abilities (TP + FP)
BP_GA_SL_TP_<WeaponName>_Equip—Server Initiated, plays the TP equip montage, sendsEquip_Attachevent at the right anim frame
BP_GA_SL_FP_<WeaponName>_Equip—Local Only, plays the FP equip montage
Set their AbilityTags to the matching native tag from step 1.
#Primary fire ability
BP_GA_SL_<WeaponName>_PrimaryFire— duplicateBP_GA_SL_AssualtRifle_PrimaryFire(note the AR typoAssualt— content rename is deferred)
- AbilityTags →
SLTags.Abilities.PrimaryFire
- Activation Owned Tags →
SLTags.States.Weapon.Firing
- Activation Blocked Tags →
SLTags.States.Weapon.Firing(prevents re-fire duringPostFireDelay)
- Triggers[0] →
{ TriggerTag: SLTags.Events.Weapon.PrimaryFire, Source: GameplayEvent }
- Override
OnLocallyPredictedShotFiredfor FP cosmetics (sound, muzzle flash, recoil shake)
- Override
OnProjectileHitPredictedfor predicted hit feedback
#5. Gameplay Cues
Duplicate the AR cues and customize. Under Content/SystemLink/AbilitySystem/Cues/Weapons/<WeaponName>/:
GC_SL_<WeaponName>_PrimaryFire(GameplayCueNotify_Burst) → muzzle flash Niagara + fire sound, tag:GameplayCues.Weapon.<WeaponName>.PrimaryFire
GC_SL_<WeaponName>_Impact(GameplayCueNotify_Burst) → impact spark + decal + sound, tag:GameplayCues.Weapon.<WeaponName>.Impact
GameplayCue notify path is already scanned recursively from Content/SystemLink/AbilitySystem/Cues/ (config in DefaultGame.ini) — no path config needed.
Remember: the fire cue excludes the local instigator by default so the local shooter doesn't double-play their own effects. FP cosmetics come from OnLocallyPredictedShotFired in the fire ability BP.
#6. Animations
For each view (FP and TP):
- Equip montage — character + weapon mesh, plays on equip. Include an
SLAnimNotify_SendGameplayEventfiringSLTags.Events.Weapon.Equip_Attachat the frame the weapon should attach.
- Idle pose / aim offset — base pose while holding the weapon
- Fire animation / additive layer — recoil kick, pump cycle, bolt cycle as appropriate
#Anim Blueprints
Two layers of ABP per weapon:
- Character ABP (
ABP_MC_FP_<WeaponName>,ABP_MC_TP_<WeaponName>) — drives the character's hand pose, recoil layer, fire state machine. Use as anim layer viaAnimLayerClasson the mesh data.
- Weapon mesh ABP (optional, set via
WeaponMeshAnimClass) — drives bolt cycling, pump animation, or any weapon-mesh-only motion.
#State machine gotchas
- Non-looping fire animations in a state machine state need "Always Reset on Entry" enabled — otherwise the asset player gets stuck at t=end on first play and never replays. See
feedback_animbp_state_reset_on_entry.mdmemory.
- Inertial Blend transitions need an
Inertializationnode downstream in the AnimGraph — otherwise UE warns on quit.
#7. HUD Assets
#Weapon Icon
- Open the Weapon Icon Generator editor utility (
USLWeaponIconGenerator)
- Point at the TP weapon mesh, neutral gray background, transparent background off
- Export side-profile render
- Feed render + AR icon (as style reference) into Nano Banana with the prompt in
Docs/AIPrompts.md
- Import result as
T_Icon_<WeaponName>inContent/SystemLink/Weapons/<WeaponName>/UI/(orIcons/)
- Assign to
WeaponIconon the data asset
#Ammo Widget
Per the design vision: Doom Eternal-style numeric counter (icon + CurrentAmmo / MaxAmmo). Duplicate WBP_SL_Ammo_AssaultRifle, swap the icon image, save as WBP_SL_Ammo_<WeaponName> in Content/SystemLink/Weapons/<WeaponName>/UI/. No structural changes needed — OnAmmoChanged(int32 CurrentAmmo, int32 MaxAmmo) BIE handles the display.
Set on DA_SL_<WeaponName>.AmmoWidgetClass.
The multi-slot strip (WBP_SL_AmmoStrip) reads AmmoWidgetClass from the data asset and creates one instance per carried weapon slot automatically — no additional HUD wiring is needed when adding a new weapon.
#Reticle Widget
Duplicate WBP_SL_Reticle_AssaultRifle to WBP_SL_Reticle_<WeaponName> in Content/SystemLink/Weapons/<WeaponName>/UI/. Customize the crosshair to reflect the weapon's character — wider for shotgun (pellet spread), tight for precision weapons, etc.
Set on DA_SL_<WeaponName>.PrimaryReticleClass.
#8. Weapon Actor Blueprint (Optional)
If the weapon needs custom logic beyond what ASLWeaponActor provides (e.g. special attach/detach FX, custom drop behavior), create BP_SL_WeaponActor_<WeaponName> deriving from ASLWeaponActor. Otherwise the C++ base class handles everything.
#9. Weapon Pickup Blueprint
BP_SL_WeaponPickup_<WeaponName> deriving from ASLWeaponPickup (or ASLPickupBase for custom pickup logic). Place in Content/SystemLink/Pickups/Weapons/<WeaponName>/. Set WeaponActorClass to the weapon actor class.
#10. Test Checklist (per weapon)
- [ ] Pickup → carry → equip → fire works without crashes
- [ ] FP idle and fire animations look correct
- [ ] TP idle and fire animations replicate to other clients
- [ ] HUD swaps to the new ammo widget and reticle on equip
- [ ] Ammo counter decrements on fire, refills on ammo pickup
- [ ]
MaxAmmocap is respected by pickups
- [ ] Muzzle flash spawns at the
MuzzleFlashsocket with correct orientation
- [ ] Impact effects play on hit
- [ ] Recoil applies and recovers smoothly
- [ ] Drop on death works — weapon spawns as a pickup in the world
- [ ] Multiplayer correctness: see
Docs/FireAbilityNetworkTesting.md
- [ ] No
LogAnimation: Setting an additive animation ... is not allowedwarnings (check Animation Mode on any preview SkeletalMeshActors)
#Reference Pattern
Assault Rifle is the canonical reference. Every step above has a working AR counterpart:
DA_SL_AssaultRifle
BP_GA_SL_AssualtRifle_PrimaryFire(typo preserved — content rename deferred)
GC_SL_AssaultRifle_PrimaryFire,GC_SL_AssaultRifle_Impact
WBP_SL_Ammo_AssaultRifle,WBP_SL_Reticle_AssaultRifle,T_Icon_AssaultRifle
ABP_MC_FP_AssaultRifle,ABP_MC_TP_AssaultRifle
When in doubt: duplicate AR, customize the parts that differ.