429 lines
14 KiB
C++
429 lines
14 KiB
C++
// Copyright 2016 Mookie. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Components/SceneComponent.h"
|
|
#include "Engine/EngineTypes.h"
|
|
#include "EBGun.h"
|
|
#include "EBWeaponData.h"
|
|
#include "EBBulletProperties.h"
|
|
#include "NiagaraComponent.h"
|
|
#include "NiagaraFunctionLibrary.h"
|
|
#include "EBPlayerWeaponController.generated.h"
|
|
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWeaponChanged, UEBWeaponData*, NewWeapon);
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWeaponFired, UEBWeaponData*, WeaponData);
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWeaponReloaded, UEBWeaponData*, WeaponData);
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWeaponEmpty, UEBWeaponData*, WeaponData);
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnAmmoChanged, int32, CurrentAmmo, int32, ReserveAmmo);
|
|
|
|
/**
|
|
* Player Weapon Controller - AAA Game Industry Standard Scene Component
|
|
*
|
|
* This follows the pattern used in games like Call of Duty:
|
|
* - Single persistent weapon actor (never destroyed)
|
|
* - Weapon data assets for all variations
|
|
* - Hot-swap meshes, stats, and behavior
|
|
* - No actor spawning/despawning
|
|
* - Inventory is just array of weapon data
|
|
*
|
|
* Benefits:
|
|
* - Zero GC pressure from spawning/destroying
|
|
* - Instant weapon switching (just data swap)
|
|
* - Memory efficient
|
|
* - Network friendly
|
|
* - Scales to hundreds of weapons
|
|
* - Direct positioning control as scene component
|
|
* - Gun spawns directly on this component's transform
|
|
*/
|
|
UCLASS(Blueprintable, BlueprintType, ClassGroup=(EasyBallistics), meta=(BlueprintSpawnableComponent, DisplayName = "EB Player Weapon Controller", ToolTip = "Player weapon controller scene component for managing weapon inventory and interactions with direct positioning"))
|
|
class EASYBALLISTICS_API UEBPlayerWeaponController : public USceneComponent
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
UEBPlayerWeaponController();
|
|
|
|
// ========================================
|
|
// WEAPON SYSTEM
|
|
// ========================================
|
|
|
|
/** Single persistent weapon actor */
|
|
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_WeaponActor, Category = "Weapon System")
|
|
AEBGun* WeaponActor;
|
|
|
|
/** Current weapon data */
|
|
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CurrentWeaponData, Category = "Weapon System")
|
|
UEBWeaponData* CurrentWeaponData;
|
|
|
|
/** Player's weapon inventory (just data assets) */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, ReplicatedUsing = OnRep_WeaponInventory, Category = "Weapon System", meta = (AllowedClasses = "EBWeaponData", DisplayName = "Weapon Inventory", ToolTip = "Array of weapon data assets available to the player"))
|
|
TArray<UEBWeaponData*> WeaponInventory;
|
|
|
|
/** Current weapon index in inventory */
|
|
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CurrentWeaponIndex, Category = "Weapon System")
|
|
int32 CurrentWeaponIndex = 0;
|
|
|
|
/** Default weapon to spawn with */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Weapon System", meta = (AllowedClasses = "EBWeaponData", DisplayName = "Default Weapon", ToolTip = "The default weapon data asset to equip on spawn"))
|
|
UEBWeaponData* DefaultWeapon;
|
|
|
|
/** Auto-equip first weapon on begin play */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Weapon System")
|
|
bool bAutoEquipOnBeginPlay = true;
|
|
|
|
// ========================================
|
|
// AMMO SYSTEM
|
|
// ========================================
|
|
|
|
/** Current ammo in magazine */
|
|
UPROPERTY(BlueprintReadOnly, Replicated, Category = "Ammo System")
|
|
int32 CurrentAmmo = 0;
|
|
|
|
/** Reserve ammo */
|
|
UPROPERTY(BlueprintReadOnly, Replicated, Category = "Ammo System")
|
|
int32 ReserveAmmo = 0;
|
|
|
|
/** Infinite ammo cheat */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ammo System")
|
|
bool bInfiniteAmmo = false;
|
|
|
|
// ========================================
|
|
// WEAPON SPAWN SETTINGS
|
|
// ========================================
|
|
|
|
/** Spawn transform offset relative to this component */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Weapon Spawn", meta = (DisplayName = "Weapon Spawn Offset", ToolTip = "Transform offset for spawning the weapon relative to this component"))
|
|
FTransform WeaponSpawnOffset = FTransform::Identity;
|
|
|
|
// ========================================
|
|
// NIAGARA VFX SYSTEM
|
|
// ========================================
|
|
|
|
/** Persistent Niagara components for weapon effects */
|
|
UPROPERTY(BlueprintReadOnly, Category = "Niagara VFX")
|
|
UNiagaraComponent* MuzzleFlashComponent;
|
|
|
|
UPROPERTY(BlueprintReadOnly, Category = "Niagara VFX")
|
|
UNiagaraComponent* MuzzleSmokeComponent;
|
|
|
|
UPROPERTY(BlueprintReadOnly, Category = "Niagara VFX")
|
|
UNiagaraComponent* BarrelHeatComponent;
|
|
|
|
UPROPERTY(BlueprintReadOnly, Category = "Niagara VFX")
|
|
UNiagaraComponent* AttachmentGlowComponent;
|
|
|
|
/** Current weapon heat level (0-1) */
|
|
UPROPERTY(BlueprintReadOnly, Replicated, Category = "Niagara VFX")
|
|
float CurrentHeatLevel = 0.0f;
|
|
|
|
/** Enable advanced VFX features */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Niagara VFX")
|
|
bool bEnableAdvancedVFX = true;
|
|
|
|
// ========================================
|
|
// INPUT ACTIONS
|
|
// ========================================
|
|
|
|
/** Primary fire */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Input")
|
|
void Fire();
|
|
|
|
/** Stop firing */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Input")
|
|
void StopFire();
|
|
|
|
/** Reload weapon */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Input")
|
|
void Reload();
|
|
|
|
/** Switch to next weapon */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Input")
|
|
void NextWeapon();
|
|
|
|
/** Switch to previous weapon */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Input")
|
|
void PreviousWeapon();
|
|
|
|
/** Switch to specific weapon by index */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Input")
|
|
void SwitchToWeapon(int32 WeaponIndex);
|
|
|
|
/** Switch to specific weapon by data */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Input")
|
|
void SwitchToWeaponData(UEBWeaponData* WeaponData);
|
|
|
|
/** Toggle fire mode */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Input")
|
|
void ToggleFireMode();
|
|
|
|
/** Toggle safety */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Input")
|
|
void ToggleSafety();
|
|
|
|
// ========================================
|
|
// WEAPON MANAGEMENT
|
|
// ========================================
|
|
|
|
/** Add weapon to inventory */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Management")
|
|
void AddWeapon(UEBWeaponData* WeaponData);
|
|
|
|
/** Remove weapon from inventory */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Management")
|
|
void RemoveWeapon(UEBWeaponData* WeaponData);
|
|
|
|
/** Clear all weapons */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Management")
|
|
void ClearWeapons();
|
|
|
|
/** Set entire weapon inventory */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Management")
|
|
void SetWeaponInventory(const TArray<UEBWeaponData*>& NewInventory);
|
|
|
|
/** Apply weapon data to actor */
|
|
UFUNCTION(BlueprintCallable, Category = "Weapon Management")
|
|
void ApplyWeaponData(UEBWeaponData* WeaponData);
|
|
|
|
// ========================================
|
|
// AMMO MANAGEMENT
|
|
// ========================================
|
|
|
|
/** Add ammo to reserve */
|
|
UFUNCTION(BlueprintCallable, Category = "Ammo Management")
|
|
void AddAmmo(int32 Amount);
|
|
|
|
/** Set current ammo */
|
|
UFUNCTION(BlueprintCallable, Category = "Ammo Management")
|
|
void SetCurrentAmmo(int32 Amount);
|
|
|
|
/** Set reserve ammo */
|
|
UFUNCTION(BlueprintCallable, Category = "Ammo Management")
|
|
void SetReserveAmmo(int32 Amount);
|
|
|
|
/** Refill all ammo */
|
|
UFUNCTION(BlueprintCallable, Category = "Ammo Management")
|
|
void RefillAmmo();
|
|
|
|
// ========================================
|
|
// STATUS QUERIES
|
|
// ========================================
|
|
|
|
/** Can weapon fire */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
bool CanFire() const;
|
|
|
|
/** Is weapon equipped */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
bool HasWeapon() const;
|
|
|
|
/** Get current weapon data */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
UEBWeaponData* GetCurrentWeaponData() const { return CurrentWeaponData; }
|
|
|
|
/** Get weapon count */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
int32 GetWeaponCount() const { return WeaponInventory.Num(); }
|
|
|
|
/** Get weapon at index */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
UEBWeaponData* GetWeaponAtIndex(int32 Index) const;
|
|
|
|
/** Find weapon index */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
int32 FindWeaponIndex(UEBWeaponData* WeaponData) const;
|
|
|
|
/** Has weapon in inventory */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
bool HasWeaponInInventory(UEBWeaponData* WeaponData) const;
|
|
|
|
/** Get current fire mode */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
EFireMode GetFireMode() const;
|
|
|
|
/** Is safety on */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
bool IsSafetyOn() const;
|
|
|
|
/** Get muzzle transform */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
FTransform GetMuzzleTransform() const;
|
|
|
|
/** Get current heat level */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
float GetHeatLevel() const { return CurrentHeatLevel; }
|
|
|
|
/** Is weapon overheated */
|
|
UFUNCTION(BlueprintPure, Category = "Weapon Status")
|
|
bool IsOverheated() const;
|
|
|
|
// ========================================
|
|
// DEBUG FUNCTIONS
|
|
// ========================================
|
|
|
|
/** Print comprehensive weapon debug information to log */
|
|
UFUNCTION(BlueprintCallable, Category = "Debug")
|
|
void PrintWeaponDebugInfo() const;
|
|
|
|
// ========================================
|
|
// NIAGARA VFX CONTROL
|
|
// ========================================
|
|
|
|
/** Trigger muzzle flash effect */
|
|
UFUNCTION(BlueprintCallable, Category = "Niagara VFX")
|
|
void TriggerMuzzleFlash();
|
|
|
|
/** Trigger shell ejection effect */
|
|
UFUNCTION(BlueprintCallable, Category = "Niagara VFX")
|
|
void TriggerShellEjection();
|
|
|
|
/** Spawn tracer effect */
|
|
UFUNCTION(BlueprintCallable, Category = "Niagara VFX")
|
|
void SpawnTracerEffect(const FVector& StartLocation, const FVector& EndLocation);
|
|
|
|
/** Spawn impact effect */
|
|
UFUNCTION(BlueprintCallable, Category = "Niagara VFX")
|
|
void SpawnImpactEffect(const FVector& ImpactLocation, const FVector& ImpactNormal, UPhysicalMaterial* SurfaceMaterial = nullptr);
|
|
|
|
/** Update weapon heat effects */
|
|
UFUNCTION(BlueprintCallable, Category = "Niagara VFX")
|
|
void UpdateHeatEffects();
|
|
|
|
/** Set Niagara parameter on all weapon effects */
|
|
UFUNCTION(BlueprintCallable, Category = "Niagara VFX")
|
|
void SetNiagaraFloatParameter(const FString& ParameterName, float Value);
|
|
|
|
/** Set Niagara vector parameter on all weapon effects */
|
|
UFUNCTION(BlueprintCallable, Category = "Niagara VFX")
|
|
void SetNiagaraVectorParameter(const FString& ParameterName, const FVector& Value);
|
|
|
|
/** Set Niagara color parameter on all weapon effects */
|
|
UFUNCTION(BlueprintCallable, Category = "Niagara VFX")
|
|
void SetNiagaraColorParameter(const FString& ParameterName, const FLinearColor& Value);
|
|
|
|
// ========================================
|
|
// EVENTS
|
|
// ========================================
|
|
|
|
/** Called when weapon changes */
|
|
UPROPERTY(BlueprintAssignable, Category = "Weapon Events")
|
|
FOnWeaponChanged OnWeaponChanged;
|
|
|
|
/** Called when weapon fires */
|
|
UPROPERTY(BlueprintAssignable, Category = "Weapon Events")
|
|
FOnWeaponFired OnWeaponFired;
|
|
|
|
/** Called when weapon reloads */
|
|
UPROPERTY(BlueprintAssignable, Category = "Weapon Events")
|
|
FOnWeaponReloaded OnWeaponReloaded;
|
|
|
|
/** Called when weapon is empty */
|
|
UPROPERTY(BlueprintAssignable, Category = "Weapon Events")
|
|
FOnWeaponEmpty OnWeaponEmpty;
|
|
|
|
/** Called when ammo changes */
|
|
UPROPERTY(BlueprintAssignable, Category = "Weapon Events")
|
|
FOnAmmoChanged OnAmmoChanged;
|
|
|
|
/** Called when WeaponActor is replicated */
|
|
UFUNCTION()
|
|
void OnRep_WeaponActor();
|
|
|
|
// ========================================
|
|
// OVERRIDES
|
|
// ========================================
|
|
|
|
virtual void BeginPlay() override;
|
|
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
|
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
|
|
|
#if WITH_EDITOR
|
|
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
|
|
#endif
|
|
|
|
protected:
|
|
// ========================================
|
|
// INTERNAL FUNCTIONS
|
|
// ========================================
|
|
|
|
/** Create weapon actor */
|
|
void CreateWeaponActor();
|
|
|
|
/** Apply weapon data to gun actor */
|
|
void InternalApplyWeaponData(UEBWeaponData* WeaponData);
|
|
|
|
/** Update ammo from weapon data */
|
|
void UpdateAmmoFromWeaponData();
|
|
|
|
/** Handle weapon fired */
|
|
UFUNCTION()
|
|
void HandleWeaponFired(UEBBulletPropertiesAsset* BulletType);
|
|
|
|
/** Handle magazine empty */
|
|
UFUNCTION()
|
|
void HandleMagazineEmpty();
|
|
|
|
/** Bind weapon events */
|
|
void BindWeaponEvents();
|
|
|
|
/** Unbind weapon events */
|
|
void UnbindWeaponEvents();
|
|
|
|
/** Check authority */
|
|
bool HasAuthority() const;
|
|
|
|
/** Create Niagara components */
|
|
void CreateNiagaraComponents();
|
|
|
|
/** Update Niagara components with weapon data */
|
|
void UpdateNiagaraComponents();
|
|
|
|
/** Apply Niagara parameters from weapon data */
|
|
void ApplyNiagaraParameters(UNiagaraComponent* Component, const FNiagaraEffectParams& Params);
|
|
|
|
/** Update heat level and effects */
|
|
void UpdateWeaponHeat(float DeltaTime);
|
|
|
|
private:
|
|
// ========================================
|
|
// SERVER RPCS
|
|
// ========================================
|
|
|
|
UFUNCTION(Server, Reliable)
|
|
void ServerSwitchToWeapon(int32 WeaponIndex);
|
|
|
|
UFUNCTION(Server, Reliable)
|
|
void ServerSwitchToWeaponData(UEBWeaponData* WeaponData);
|
|
|
|
UFUNCTION(Server, Reliable)
|
|
void ServerAddWeapon(UEBWeaponData* WeaponData);
|
|
|
|
UFUNCTION(Server, Reliable)
|
|
void ServerRemoveWeapon(UEBWeaponData* WeaponData);
|
|
|
|
UFUNCTION(Server, Reliable)
|
|
void ServerSetCurrentAmmo(int32 Amount);
|
|
|
|
UFUNCTION(Server, Reliable)
|
|
void ServerSetReserveAmmo(int32 Amount);
|
|
|
|
UFUNCTION(Server, Reliable)
|
|
void ServerToggleFireMode();
|
|
|
|
UFUNCTION(Server, Reliable)
|
|
void ServerToggleSafety();
|
|
|
|
// ========================================
|
|
// REPLICATION
|
|
// ========================================
|
|
|
|
UFUNCTION()
|
|
void OnRep_CurrentWeaponData();
|
|
|
|
UFUNCTION()
|
|
void OnRep_WeaponInventory();
|
|
|
|
UFUNCTION()
|
|
void OnRep_CurrentWeaponIndex();
|
|
}; |