- Updated `CONTEXT.md` to reference the new Manual Implementation Guide and Build Checklist in blueprint spec files. - Added a detailed Manual Implementation Guide to `01_GI_GameTagRegistry.md`, including class setup, variable initialization, function implementations, and a build checklist. - Introduced a Manual Implementation Guide section in `22_BPC_PhysicsDragSystem.md` with step-by-step instructions for setup and function logic. - Expanded `28_BPC_ConsumableSystem.md` with a comprehensive Manual Implementation Guide detailing class setup, variable initialization, function implementations, and networking. - Enhanced `69_BP_WeaponBase.md` with a Manual Implementation Guide covering class setup, variable defaults, function implementations, and networking. - Added a Manual Implementation Guide to `84_AI_BaseAgentController.md`, outlining class setup, variable initialization, function implementations, and networking. - Updated `TEMPLATE.md` to version 2.0, incorporating the Manual Implementation Guide and Build Checklist for human implementers. - Revised `INDEX.md` to reflect the new purpose and content of blueprint specifications, emphasizing the inclusion of the Manual Implementation Guide.
350 lines
14 KiB
Markdown
350 lines
14 KiB
Markdown
# 49 — BP_WeaponBase
|
||
|
||
## Blueprint Spec — UE 5.5–5.7
|
||
|
||
---
|
||
|
||
### Parent Class
|
||
`Actor` (attached to character via `AttachToComponent`)
|
||
|
||
### Dependencies
|
||
- [`BPC_InventoryComponent`](../04-inventory/25_BPC_InventoryComponent.md)
|
||
- [`BPC_EquipmentSystem`](../04-inventory/28_BPC_EquipmentSystem.md)
|
||
- [`BPC_PlayerCameraManager`](../02-player/14_BPC_PlayerCameraManager.md)
|
||
- [`BPC_DamageHandler`](53_BPC_DamageHandlerComponent.md)
|
||
- [`DA_WeaponData`](../12-content/60_DA_WeaponDataAsset.md)
|
||
- [`I_Damageable`](../01-core/03_I_Damageable.md)
|
||
- [`BPC_CombatFeedbackComponent`](54_BPC_CombatFeedbackComponent.md)
|
||
|
||
### Purpose
|
||
Base class for all weapon actors (ranged and melee). Provides common weapon lifecycle: equip, unequip, fire input, ammo tracking integration, aim-down-sights, and weapon state machine. Designed to be extended by [`BP_RangedWeapon`](50_BP_RangedWeapon.md) and [`BP_MeleeWeapon`](51_BP_MeleeWeapon.md).
|
||
|
||
### Responsibilities
|
||
- Attach/detach from character socket on equip/unequip
|
||
- Manage weapon state (holstered / equipping / ready / firing / reloading)
|
||
- Handle fire input (start / stop) — base delegates to subclass
|
||
- Track aim-down-sights state and apply camera FOV transition
|
||
- Fire event dispatchers for UI state changes
|
||
- Communicate with [`BPC_EquipmentSystem`](../04-inventory/28_BPC_EquipmentSystem.md) for weapon selection
|
||
- Communicate with inventory for ammo consumption
|
||
|
||
### Does NOT Handle
|
||
- Specific fire logic (raycast / projectile / melee hitbox) — that is subclass
|
||
- Ammo math (that is [`BPC_AmmoComponent`](52_BPC_AmmoComponent.md))
|
||
- Damage calculation (that is [`BPC_DamageHandler`](53_BPC_DamageHandlerComponent.md))
|
||
- Visual / audio feedback (that is [`BPC_CombatFeedbackComponent`](54_BPC_CombatFeedbackComponent.md))
|
||
- UI display (that is HUD widget)
|
||
|
||
### Variables
|
||
|
||
| Name | Type | Description |
|
||
|------|------|-------------|
|
||
| `WeaponData` | DA_WeaponData | Weapon definition asset |
|
||
| `WeaponState` | EWeaponState | Current state machine |
|
||
| `SkeletalMesh` | USkeletalMeshComponent | Weapon visual |
|
||
| `WeaponRoot` | USceneComponent | Attachment root |
|
||
| `HolsterSocket` | FName | Socket name for holstered |
|
||
| `EquipSocket` | FName | Socket name for ready |
|
||
| `AimDownSightsFOV` | Float | FOV when ADS (e.g. 60.0) |
|
||
| `DefaultFOV` | Float | Normal FOV |
|
||
| `ADSInterpSpeed` | Float | Camera blend speed |
|
||
| `bIsAiming` | Bool | Currently ADS |
|
||
| `FireRateTimer` | FTimerHandle | Fire rate control |
|
||
| `bCanFire` | Bool | Not on cooldown |
|
||
| `EquipDuration` | Float | Seconds for equip animation |
|
||
| `HolsterDuration` | Float | Seconds for holster animation |
|
||
| `RecoilPitch` | Float | Camera pitch per shot |
|
||
| `RecoilYaw` | Float | Camera yaw per shot |
|
||
|
||
### Enums
|
||
|
||
| Enum | Values | Description |
|
||
|------|--------|-------------|
|
||
| `EWeaponState` | Holstered, Equipping, Ready, Firing, Reloading, Holstering, Broken | Weapon lifecycle |
|
||
| `EWeaponFireMode` | SemiAutomatic, FullAutomatic, BurstFire, ChargeAndRelease, MeleeSwing | Fire type |
|
||
|
||
### Functions / Events
|
||
|
||
| Name | Inputs | Outputs | Description |
|
||
|------|--------|---------|-------------|
|
||
| `Equip` | — | — | Play equip anim, attach to EquipSocket, set state to Ready |
|
||
| `Holster` | — | — | Play holster anim, attach to HolsterSocket, set state to Holstered |
|
||
| `StartFire` | — | — | Begin fire loop (if auto) or single fire (semi) |
|
||
| `StopFire` | — | — | End fire loop |
|
||
| `CanFire` | — | Bool | Check state, ammo, cooldown |
|
||
| `OnFire` | — | — | Virtual: subclass implements actual fire logic |
|
||
| `StartReload` | — | — | Begin reload sequence |
|
||
| `FinishReload` | — | — | Called after reload anim |
|
||
| `StartAim` | — | — | Blend camera to ADS FOV |
|
||
| `StopAim` | — | — | Blend camera back to DefaultFOV |
|
||
| `SetWeaponState` | NewState: EWeaponState | — | Change state and broadcast |
|
||
| `GetWeaponTag` | — | GameplayTag | Return weapon identifier |
|
||
| `OnWeaponBroken` | — | — | Weapon disabled (durability zero) |
|
||
|
||
### Event Dispatchers
|
||
|
||
| Name | Parameters | Fired When |
|
||
|------|-----------|-----------|
|
||
| `OnWeaponStateChanged` | NewState: EWeaponState, OldState: EWeaponState | State machine change |
|
||
| `OnWeaponEquipped` | WeaponRef: BP_WeaponBase | Ready to use |
|
||
| `OnWeaponHolstered` | WeaponRef: BP_WeaponBase | Stored away |
|
||
| `OnFireStarted` | — | Fire input received and valid |
|
||
| `OnFireStopped` | — | Fire input released |
|
||
| `OnAimStarted` | — | ADS enter |
|
||
| `OnAimStopped` | — | ADS exit |
|
||
| `OnReloadStarted` | — | Reload begin |
|
||
| `OnReloadCompleted` | — | Reload finish |
|
||
| `OnWeaponBroken` | — | Durability depleted |
|
||
|
||
### Blueprint Flow
|
||
|
||
```
|
||
[StartFire]
|
||
└─► If !CanFire → return
|
||
└─► Set WeaponState = Firing
|
||
└─► Broadcast OnFireStarted
|
||
└─► Call OnFire (subclass override)
|
||
└─► If FireMode == FullAutomatic → start FireRateTimer loop
|
||
└─► If FireMode == SemiAutomatic → block until timer clears
|
||
|
||
[StopFire]
|
||
└─► Clear FireRateTimer
|
||
└─► If FireMode == BurstFire → let burst complete, then stop
|
||
└─► Set WeaponState = Ready
|
||
└─► Broadcast OnFireStopped
|
||
|
||
[StartReload]
|
||
└─► If WeaponState != Ready → return
|
||
└─► Set WeaponState = Reloading
|
||
└─► Broadcast OnReloadStarted
|
||
└─► Start animation or timer for reload duration
|
||
└─► On completion → FinishReload
|
||
|
||
[FinishReload]
|
||
└─► BPC_AmmoComponent.RefillAmmo(WeaponData.MagazineSize)
|
||
└─► Set WeaponState = Ready
|
||
└─► Broadcast OnReloadCompleted
|
||
|
||
[StartAim / StopAim]
|
||
└─► Set bIsAiming
|
||
└─► Get BPC_PlayerCameraManager from owner
|
||
└─► Set FOV with interp speed
|
||
└─► Broadcast OnAimStarted / OnAimStopped
|
||
```
|
||
|
||
### Communications With
|
||
|
||
| Target System | Method | Why |
|
||
|---------------|--------|-----|
|
||
| [`BPC_EquipmentSystem`](../04-inventory/28_BPC_EquipmentSystem.md) | Direct | Get/return weapon socket assignment |
|
||
| [`BPC_AmmoComponent`](52_BPC_AmmoComponent.md) | Get Component | Check / consume / refill ammo |
|
||
| [`BPC_DamageHandler`](53_BPC_DamageHandlerComponent.md) | Get Component | Delegate damage processing |
|
||
| [`BPC_CombatFeedbackComponent`](54_BPC_CombatFeedbackComponent.md) | Get Component | Play muzzle flash, hit FX, sounds |
|
||
| [`BPC_PlayerCameraManager`](../02-player/14_BPC_PlayerCameraManager.md) | Get from Owner | ADS FOV blend |
|
||
| [`BPC_InventoryComponent`](../04-inventory/25_BPC_InventoryComponent.md) | Get from Owner | Check ammo inventory |
|
||
| HUD Widget | Dispatcher (via GM) | Update crosshair, ammo display |
|
||
| Owner (Player Character) | Direct | Animation blueprint queries weapon state |
|
||
|
||
### Reuse Notes
|
||
Subclass for ranged or melee specific fire implementations. The state machine prevents firing during reload, equip, or holster sequences. Weapons are data-driven via `DA_WeaponData` — design changes never require blueprint edits.
|
||
|
||
---
|
||
|
||
## Manual Implementation Guide
|
||
|
||
### Class Setup
|
||
1. Create Blueprint Class: Parent = `Actor`, Name = `BP_WeaponBase`
|
||
2. Save to: `Content/Framework/Weapons/`
|
||
3. Add components in Construction Script:
|
||
- `WeaponRoot` (SceneComponent) — root
|
||
- `SkeletalMesh` (SkeletalMeshComponent) — attached to root
|
||
4. Set `Replicates` = true in Class Defaults
|
||
|
||
### Variable Defaults (Class Defaults)
|
||
| Variable | Type | Default |
|
||
|----------|------|---------|
|
||
| `WeaponState` | `EWeaponState` | `Holstered` |
|
||
| `HolsterSocket` | `Name` | `weapon_holster` |
|
||
| `EquipSocket` | `Name` | `weapon_equip` |
|
||
| `AimDownSightsFOV` | `Float` | `55.0` |
|
||
| `DefaultFOV` | `Float` | `90.0` |
|
||
| `ADSInterpSpeed` | `Float` | `10.0` |
|
||
| `bIsAiming` | `Boolean` | `false` |
|
||
| `bCanFire` | `Boolean` | `true` |
|
||
| `EquipDuration` | `Float` | `0.5` |
|
||
| `HolsterDuration` | `Float` | `0.5` |
|
||
| `RecoilPitch` | `Float` | `2.0` |
|
||
| `RecoilYaw` | `Float` | `0.5` |
|
||
|
||
### Function Implementations
|
||
|
||
#### `Equip(CharacterOwner: Character)` → `void`
|
||
|
||
```
|
||
[Function: Equip]
|
||
Step 1: Branch on WeaponState == Holstered → If not, return (can't equip twice)
|
||
Step 2: SetWeaponState(Equipping)
|
||
Step 3: AttachToComponent(CharacterOwner.Mesh, EquipSocket)
|
||
- Set Relative Location = (0,0,0)
|
||
- Set Relative Rotation = (0,0,0)
|
||
Step 4: Set Actor Hidden In Game = false
|
||
Step 5: Play equip animation on SkeletalMesh (if montage exists)
|
||
Step 6: Start timer for EquipDuration:
|
||
└─ On timer complete:
|
||
- SetWeaponState(Ready)
|
||
- Set bCanFire = true
|
||
- Fire OnWeaponEquipped(Self)
|
||
```
|
||
|
||
**Nodes:** `Switch on EWeaponState`, `Attach Actor to Component`, `Set Actor Hidden In Game`, `Play Animation`, `Set Timer by Event`
|
||
|
||
#### `Holster()` → `void`
|
||
|
||
```
|
||
[Function: Holster]
|
||
Step 1: Branch on WeaponState == Ready OR Firing → If not, return
|
||
Step 2: If WeaponState == Firing: StopFire first
|
||
Step 3: SetWeaponState(Holstering)
|
||
Step 4: Play holster animation on SkeletalMesh
|
||
Step 5: Start timer for HolsterDuration:
|
||
└─ On timer complete:
|
||
- AttachToComponent(CharacterOwner.Mesh, HolsterSocket)
|
||
- SetWeaponState(Holstered)
|
||
- Fire OnWeaponHolstered(Self)
|
||
```
|
||
|
||
#### `StartFire()` → `void`
|
||
|
||
```
|
||
[Function: StartFire]
|
||
Step 1: Branch on WeaponState == Ready (only fire from Ready state):
|
||
False → Return
|
||
Step 2: Call CanFire() → Branch on result:
|
||
False → Return
|
||
Step 3: SetWeaponState(Firing)
|
||
Step 4: Fire OnFireStarted
|
||
Step 5: Call OnFire() — this is the subclass override point (virtual function)
|
||
Step 6: Switch on WeaponData.FireMode:
|
||
Case SemiAutomatic:
|
||
- Set bCanFire = false
|
||
- Set timer by WeaponData.FireRate → on complete: Set bCanFire = true
|
||
Case FullAutomatic:
|
||
- Start looping timer (interval = WeaponData.FireRate)
|
||
- Each tick: Call OnFire()
|
||
Case BurstFire:
|
||
- Loop 3 times with WeaponData.FireRate delay between each
|
||
- On burst complete: SetWeaponState(Ready)
|
||
```
|
||
|
||
**Important:** `OnFire()` is a **BlueprintImplementableEvent** — it has NO body in BP_WeaponBase. Subclasses (BP_RangedWeapon, BP_MeleeWeapon) override it with their own fire logic.
|
||
|
||
#### `StopFire()` → `void`
|
||
|
||
```
|
||
[Function: StopFire]
|
||
Step 1: Branch on WeaponState == Firing:
|
||
False → Return
|
||
Step 2: If FireMode == FullAutomatic OR BurstFire:
|
||
- Clear all FireRate timers
|
||
Step 3: SetWeaponState(Ready)
|
||
Step 4: Fire OnFireStopped
|
||
```
|
||
|
||
#### `CanFire()` → `Boolean`
|
||
|
||
```
|
||
[Function: CanFire] (Pure)
|
||
Step 1: Branch on WeaponState == Ready → If not, return false
|
||
Step 2: Branch on bCanFire → If not, return false (on cooldown)
|
||
Step 3: Get AmmoComponent from Owner → Call HasAmmo()
|
||
- If no ammo: return false (subclass may trigger auto-reload)
|
||
Step 4: Get Owner → Get BPC_StateManager → Call IsActionPermitted(GameplayTag: "Action.Fire")
|
||
- If not permitted: return false
|
||
Step 5: Return true
|
||
```
|
||
|
||
#### `StartReload()` → `void`
|
||
|
||
```
|
||
[Function: StartReload]
|
||
Step 1: Branch on WeaponState == Ready:
|
||
False → Return (can't reload while firing/holstered)
|
||
Step 2: Branch on AmmoComponent.IsMagazineFull():
|
||
True → Return (no need to reload)
|
||
Step 3: Branch on AmmoComponent.HasReserveAmmo():
|
||
False → Return (no ammo to load)
|
||
Step 4: SetWeaponState(Reloading)
|
||
Step 5: Fire OnReloadStarted
|
||
Step 6: Play reload animation montage:
|
||
- Use AnimNotify "OnReloadComplete" at the ammo-insert frame
|
||
- AnimNotify handler: call FinishReload()
|
||
```
|
||
|
||
#### `FinishReload()` → `void`
|
||
|
||
```
|
||
[Function: FinishReload]
|
||
Step 1: Get AmmoComponent → Call RefillAmmo(MagazineSize from WeaponData)
|
||
Step 2: SetWeaponState(Ready)
|
||
Step 3: Fire OnReloadCompleted
|
||
```
|
||
|
||
#### `StartAim()` → `void`
|
||
|
||
```
|
||
[Function: StartAim]
|
||
Step 1: Set bIsAiming = true
|
||
Step 2: Get Owner → Get PlayerController → Get PlayerCameraManager
|
||
Step 3: Set PlayerCameraManager Field of View to AimDownSightsFOV with interp speed
|
||
Step 4: Fire OnAimStarted
|
||
```
|
||
|
||
#### `StopAim()` → `void`
|
||
|
||
```
|
||
[Function: StopAim]
|
||
Step 1: Set bIsAiming = false
|
||
Step 2: Get PlayerCameraManager → Set FOV to DefaultFOV with interp
|
||
Step 3: Fire OnAimStopped
|
||
```
|
||
|
||
#### `SetWeaponState(NewState: EWeaponState)` → `void`
|
||
|
||
```
|
||
[Function: SetWeaponState]
|
||
Step 1: OldState = WeaponState
|
||
Step 2: If NewState == OldState → Return
|
||
Step 3: WeaponState = NewState
|
||
Step 4: Mark variable dirty (for replication)
|
||
Step 5: Fire OnWeaponStateChanged(NewState, OldState)
|
||
```
|
||
|
||
### Event Dispatcher Bindings
|
||
|
||
| Bind to Dispatcher | Custom Event | Logic |
|
||
|-------------------|-------------|-------|
|
||
| `IA_Fire` (Pressed) | `OnFirePressed` | Call StartFire() |
|
||
| `IA_Fire` (Released) | `OnFireReleased` | Call StopFire() |
|
||
| `IA_Reload` (Pressed) | `OnReloadPressed` | Call StartReload() |
|
||
| `IA_Aim` (Pressed) | `OnAimPressed` | Call StartAim() |
|
||
| `IA_Aim` (Released) | `OnAimReleased` | Call StopAim() |
|
||
|
||
### Networking
|
||
- **WeaponState** replicated with `OnRep_WeaponState` → plays matching animation on remote clients
|
||
- **All state transitions** are server-authoritative via `Server_StartFire`, `Server_StartReload`, etc.
|
||
- Client predicts: fire animation, muzzle flash, recoil (cosmetic only)
|
||
- Server validates: ammo count, fire rate cooldown, state machine transitions
|
||
|
||
### Blueprint Build Checklist
|
||
- [ ] Create BP_WeaponBase actor with WeaponRoot + SkeletalMesh components
|
||
- [ ] Add EquipmentSocket component on Player Character (weapon_equip, weapon_holster)
|
||
- [ ] Add all variables with correct types and defaults
|
||
- [ ] Implement Equip/Holster with attach/detach and animation timers
|
||
- [ ] Implement StartFire/StopFire with fire rate timer loop
|
||
- [ ] Create OnFire as BlueprintImplementableEvent (empty — subclasses override)
|
||
- [ ] Implement CanFire checks: state, cooldown, ammo, StateManager permission
|
||
- [ ] Implement StartReload/FinishReload with animation notify
|
||
- [ ] Implement StartAim/StopAim with FOV interpolation
|
||
- [ ] Implement SetWeaponState with old state tracking and dispatcher
|
||
- [ ] Bind all input actions (Fire, Reload, Aim)
|
||
- [ ] Add networking: replicated WeaponState, Server_ RPCs for all mutators |