diff --git a/Content/Blueprints/Weapons/Common/Blueprints/NewBlueprint.uasset b/Content/Blueprints/Weapons/Common/Blueprints/NewBlueprint.uasset new file mode 100644 index 000000000..f65bebd8f Binary files /dev/null and b/Content/Blueprints/Weapons/Common/Blueprints/NewBlueprint.uasset differ diff --git a/Content/Blueprints/Weapons/FirearmWeaponsTable.uasset b/Content/Blueprints/Weapons/FirearmWeaponsTable.uasset index 796280219..7eb7ff303 100644 Binary files a/Content/Blueprints/Weapons/FirearmWeaponsTable.uasset and b/Content/Blueprints/Weapons/FirearmWeaponsTable.uasset differ diff --git a/Content/Blueprints/Weapons/GrenadeWeaponTable.uasset b/Content/Blueprints/Weapons/GrenadeWeaponTable.uasset index 9ce98c901..6c34389e6 100644 Binary files a/Content/Blueprints/Weapons/GrenadeWeaponTable.uasset and b/Content/Blueprints/Weapons/GrenadeWeaponTable.uasset differ diff --git a/Content/Blueprints/Weapons/Knives/Stiletto/Textures/knife_stiletto.uasset b/Content/Blueprints/Weapons/Knives/Stiletto/Textures/knife_stiletto.uasset new file mode 100644 index 000000000..80a5cdb19 Binary files /dev/null and b/Content/Blueprints/Weapons/Knives/Stiletto/Textures/knife_stiletto.uasset differ diff --git a/Content/Blueprints/Weapons/Knives/butterfly/Textures/knife_butterfly.uasset b/Content/Blueprints/Weapons/Knives/butterfly/Textures/knife_butterfly.uasset new file mode 100644 index 000000000..b218fb614 Binary files /dev/null and b/Content/Blueprints/Weapons/Knives/butterfly/Textures/knife_butterfly.uasset differ diff --git a/Content/Blueprints/Weapons/MeleeWeaponTable.uasset b/Content/Blueprints/Weapons/MeleeWeaponTable.uasset index 779cd43a3..99e66da92 100644 Binary files a/Content/Blueprints/Weapons/MeleeWeaponTable.uasset and b/Content/Blueprints/Weapons/MeleeWeaponTable.uasset differ diff --git a/Content/Panorama/Icons/Equipment/ak47.uasset b/Content/Panorama/Icons/Equipment/ak47.uasset new file mode 100644 index 000000000..ccfdb7b2e Binary files /dev/null and b/Content/Panorama/Icons/Equipment/ak47.uasset differ diff --git a/Content/Panorama/Icons/Equipment/armor.uasset b/Content/Panorama/Icons/Equipment/armor.uasset new file mode 100644 index 000000000..e27cbde02 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/armor.uasset differ diff --git a/Content/Panorama/Icons/Equipment/armor_helmet.uasset b/Content/Panorama/Icons/Equipment/armor_helmet.uasset new file mode 100644 index 000000000..3b90e1401 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/armor_helmet.uasset differ diff --git a/Content/Panorama/Icons/Equipment/awp.uasset b/Content/Panorama/Icons/Equipment/awp.uasset new file mode 100644 index 000000000..5e78c3f66 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/awp.uasset differ diff --git a/Content/Panorama/Icons/Equipment/c4.uasset b/Content/Panorama/Icons/Equipment/c4.uasset new file mode 100644 index 000000000..62c874ce8 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/c4.uasset differ diff --git a/Content/Panorama/Icons/Equipment/deagle.uasset b/Content/Panorama/Icons/Equipment/deagle.uasset new file mode 100644 index 000000000..1a4495697 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/deagle.uasset differ diff --git a/Content/Panorama/Icons/Equipment/flashbang.uasset b/Content/Panorama/Icons/Equipment/flashbang.uasset new file mode 100644 index 000000000..ba71a7e38 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/flashbang.uasset differ diff --git a/Content/Panorama/Icons/Equipment/hegrenade.uasset b/Content/Panorama/Icons/Equipment/hegrenade.uasset new file mode 100644 index 000000000..9f19ebd75 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/hegrenade.uasset differ diff --git a/Content/Panorama/Icons/Equipment/helmet.uasset b/Content/Panorama/Icons/Equipment/helmet.uasset new file mode 100644 index 000000000..c28bcf470 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/helmet.uasset differ diff --git a/Content/Panorama/Icons/Equipment/hkp2000.uasset b/Content/Panorama/Icons/Equipment/hkp2000.uasset new file mode 100644 index 000000000..dc5660e31 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/hkp2000.uasset differ diff --git a/Content/Panorama/Icons/Equipment/incgrenade.uasset b/Content/Panorama/Icons/Equipment/incgrenade.uasset new file mode 100644 index 000000000..d299e1779 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/incgrenade.uasset differ diff --git a/Content/Panorama/Icons/Equipment/inferno.uasset b/Content/Panorama/Icons/Equipment/inferno.uasset new file mode 100644 index 000000000..115ca2b07 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/inferno.uasset differ diff --git a/Content/Panorama/Icons/Equipment/m4a1_silencer.uasset b/Content/Panorama/Icons/Equipment/m4a1_silencer.uasset new file mode 100644 index 000000000..d82039c64 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/m4a1_silencer.uasset differ diff --git a/Content/Panorama/Icons/Equipment/m4a1_silencer_off.uasset b/Content/Panorama/Icons/Equipment/m4a1_silencer_off.uasset new file mode 100644 index 000000000..9911ec42b Binary files /dev/null and b/Content/Panorama/Icons/Equipment/m4a1_silencer_off.uasset differ diff --git a/Content/Panorama/Icons/Equipment/mp9.uasset b/Content/Panorama/Icons/Equipment/mp9.uasset new file mode 100644 index 000000000..264f23540 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/mp9.uasset differ diff --git a/Content/Panorama/Icons/Equipment/nova.uasset b/Content/Panorama/Icons/Equipment/nova.uasset new file mode 100644 index 000000000..516879a8a Binary files /dev/null and b/Content/Panorama/Icons/Equipment/nova.uasset differ diff --git a/Content/Panorama/Icons/Equipment/smokegrenade.uasset b/Content/Panorama/Icons/Equipment/smokegrenade.uasset new file mode 100644 index 000000000..61aab95e3 Binary files /dev/null and b/Content/Panorama/Icons/Equipment/smokegrenade.uasset differ diff --git a/Source/Cloud9/Game/Cloud9AssetManager.cpp b/Source/Cloud9/Game/Cloud9AssetManager.cpp index 0aed5a6b7..5bba44591 100644 --- a/Source/Cloud9/Game/Cloud9AssetManager.cpp +++ b/Source/Cloud9/Game/Cloud9AssetManager.cpp @@ -23,7 +23,31 @@ #include "Cloud9AssetManager.h" -UObject* UCloud9AssetManager::GetOrLoadAssetSync(FPrimaryAssetId PrimaryAssetId) +#include "Cloud9/Weapon/Assets/WeaponDefinitionsAsset.h" + +UObject* UCloud9AssetManager::GetOrLoadAssetSync( + FPrimaryAssetId PrimaryAssetId, + const FString& Path, + UClass* BaseClass, + bool bHasBlueprintClasses, + bool bIsEditorOnly) +{ + static var& Manager = Get(); + + // Required to scan when using in OnConstruction method + Manager.ScanPathForPrimaryAssets( + PrimaryAssetId.PrimaryAssetType, + Path, + BaseClass, + bHasBlueprintClasses, + bIsEditorOnly, + true + ); + + return GetOrLoadScannedAssetSync(PrimaryAssetId); +} + +UObject* UCloud9AssetManager::GetOrLoadScannedAssetSync(FPrimaryAssetId PrimaryAssetId) { static var& Manager = Get(); diff --git a/Source/Cloud9/Game/Cloud9AssetManager.h b/Source/Cloud9/Game/Cloud9AssetManager.h index 16c43f859..aed6027b9 100644 --- a/Source/Cloud9/Game/Cloud9AssetManager.h +++ b/Source/Cloud9/Game/Cloud9AssetManager.h @@ -37,12 +37,71 @@ class CLOUD9_API UCloud9AssetManager : public UAssetManager GENERATED_BODY() public: + /** + * Scans a path and reads asset data for all primary assets of a specific type. + * If done in the editor it will load the data off disk, in cooked games it will + * load out of the asset registry cache. + * + * Then loads primary asset and adds loaded asset to root (AddToRoot) to prevent it from destroy by GC. + * + * @param PrimaryAssetId Asset Id to load + * @param Path Path to scan of assets + * @param BaseClass + * @param bHasBlueprintClasses + * @param bIsEditorOnly + * @return + */ UFUNCTION(BlueprintCallable) - static UObject* GetOrLoadAssetSync(FPrimaryAssetId PrimaryAssetId); + static UObject* GetOrLoadAssetSync( + FPrimaryAssetId PrimaryAssetId, + const FString& Path, + UClass* BaseClass, + bool bHasBlueprintClasses = false, + bool bIsEditorOnly = false); + /** + * Template functions wrapper for GetOrLoadAssetSync + * + * @tparam ClassType Class type of asset to look for + * @param bHasBlueprintClasses If true, the assets are blueprints that subclass BaseClass. + * If false they are base UObject assets + * @param bIsEditorOnly If true, assets will only be scanned in editor builds, + * and will not be stored into the asset registry + * @return Object of loaded asset + */ template - static ClassType* GetOrLoadAssetSync(FPrimaryAssetId PrimaryAssetId = ClassType::PrimaryAssetId) + static ClassType* GetOrLoadAssetSync(bool bHasBlueprintClasses = false, bool bIsEditorOnly = false) { - return Cast(GetOrLoadAssetSync(PrimaryAssetId)); + let Asset = GetOrLoadAssetSync( + ClassType::PrimaryAssetId, + ClassType::Path, + ClassType::StaticClass(), + bHasBlueprintClasses, + bIsEditorOnly + ); + + return Cast(Asset); + } + + /** + * Functions loads primary asset only if it was scanned (e.g. won't work for PIE start OnConstruction method). + * Also function adds loaded asset to root (AddToRoot) to prevent it from destroy by GC. + * + * @param PrimaryAssetId Asset Id to load + * @return Object of loaded asset + */ + UFUNCTION(BlueprintCallable) + static UObject* GetOrLoadScannedAssetSync(FPrimaryAssetId PrimaryAssetId); + + /** + * Template functions wrapper for GetOrLoadScannedAssetSync + * + * @param PrimaryAssetId Asset Id to load + * @return Object of loaded asset + */ + template + static ClassType* GetOrLoadScannedAssetSync(FPrimaryAssetId PrimaryAssetId = ClassType::PrimaryAssetId) + { + return Cast(GetOrLoadScannedAssetSync(PrimaryAssetId)); } }; diff --git a/Source/Cloud9/Weapon/Assets/WeaponDefinitionsAsset.cpp b/Source/Cloud9/Weapon/Assets/WeaponDefinitionsAsset.cpp index 443af4ddd..ede73d522 100644 --- a/Source/Cloud9/Weapon/Assets/WeaponDefinitionsAsset.cpp +++ b/Source/Cloud9/Weapon/Assets/WeaponDefinitionsAsset.cpp @@ -29,6 +29,7 @@ #include "Cloud9/Weapon/Extensions/EWeaponId.h" const FPrimaryAssetId UWeaponDefinitionsAsset::PrimaryAssetId = FPrimaryAssetId("Weapon:Definitions"); +const FString UWeaponDefinitionsAsset::Path = TEXT("/Game/Blueprints/Weapons"); template FWeaponDefinition UWeaponDefinitionsAsset::GetWeaponDefinition( diff --git a/Source/Cloud9/Weapon/Assets/WeaponDefinitionsAsset.h b/Source/Cloud9/Weapon/Assets/WeaponDefinitionsAsset.h index 5435face2..fb939e4c2 100644 --- a/Source/Cloud9/Weapon/Assets/WeaponDefinitionsAsset.h +++ b/Source/Cloud9/Weapon/Assets/WeaponDefinitionsAsset.h @@ -40,6 +40,7 @@ class CLOUD9_API UWeaponDefinitionsAsset : public UPrimaryDataAsset public: static const FPrimaryAssetId PrimaryAssetId; + static const FString Path; public: // functions bool GetWeaponDefinition(const FWeaponId& WeaponId, FWeaponDefinition& WeaponDefinition) const; diff --git a/Source/Cloud9/Weapon/Classes/Cloud9WeaponBase.h b/Source/Cloud9/Weapon/Classes/Cloud9WeaponBase.h index 87c18b2b3..e9b1816c0 100644 --- a/Source/Cloud9/Weapon/Classes/Cloud9WeaponBase.h +++ b/Source/Cloud9/Weapon/Classes/Cloud9WeaponBase.h @@ -66,6 +66,9 @@ class CLOUD9_API ACloud9WeaponBase : public AActor static const FName MuzzleFlashSocketName; static const FName CaseEjectSocketName; +public: + static UWeaponDefinitionsAsset* GetWeaponDefinitionsAsset(); + public: ACloud9WeaponBase(); @@ -165,6 +168,9 @@ class CLOUD9_API ACloud9WeaponBase : public AActor virtual void SecondaryAction(bool IsReleased); virtual void Reload(bool IsReleased); +protected: + static void ChangeMeshCollisionState(UStaticMeshComponent* Mesh, bool bIsEnabled); + protected: // functions virtual bool OnInitialize(const FWeaponId& NewWeaponId, FName NewWeaponSkin); virtual void Deinitialize(); @@ -181,10 +187,6 @@ class CLOUD9_API ACloud9WeaponBase : public AActor */ virtual void OnWeaponRemovedFromInventory(); - static UWeaponDefinitionsAsset* GetWeaponDefinitionsAsset(); - - static void ChangeMeshCollisionState(UStaticMeshComponent* Mesh, bool bIsEnabled); - UStaticMeshComponent* CreateMeshComponent(FName ComponentName, FName SocketName = NAME_None); UNiagaraComponent* CreateEffectComponent(FName ComponentName, FName SocketName = NAME_None); URadialForceComponent* CreateDetonateComponent(FName ComponentName); diff --git a/Source/Cloud9/Weapon/Notifiers/Cloud9AnimNotifyWeapon.h b/Source/Cloud9/Weapon/Notifiers/Cloud9AnimNotifyWeapon.h index b547cf0a8..8601a4b37 100644 --- a/Source/Cloud9/Weapon/Notifiers/Cloud9AnimNotifyWeapon.h +++ b/Source/Cloud9/Weapon/Notifiers/Cloud9AnimNotifyWeapon.h @@ -34,7 +34,7 @@ class CLOUD9_API UCloud9AnimNotifyWeapon : public UAnimNotify if (not IsValid(Inventory)) { - log(Error, "Invenotry is invalid"); + log(Error, "Inventory is invalid"); return nullptr; } diff --git a/Source/Cloud9/Weapon/Tables/WeaponTableBase.h b/Source/Cloud9/Weapon/Tables/WeaponTableBase.h index 6660d4ae2..eaa82ad78 100644 --- a/Source/Cloud9/Weapon/Tables/WeaponTableBase.h +++ b/Source/Cloud9/Weapon/Tables/WeaponTableBase.h @@ -85,6 +85,12 @@ struct FBaseWeaponInfo : public FTableRowBase */ UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category=Base, AdvancedDisplay) FText Description; + + /** + * Weapon icon + */ + UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category=Icon) + UTexture2D* Icon; }; namespace EFWeaponInfo diff --git a/Source/Cloud9/Weapon/Utils/WeaponSpawner.cpp b/Source/Cloud9/Weapon/Utils/WeaponSpawner.cpp new file mode 100644 index 000000000..a6196c6b4 --- /dev/null +++ b/Source/Cloud9/Weapon/Utils/WeaponSpawner.cpp @@ -0,0 +1,151 @@ +// Copyright (c) 2023 Alexei Gladkikh + + +#include "WeaponSpawner.h" + +#include "NiagaraComponent.h" +#include "Components/BoxComponent.h" + +#include "Cloud9/Character/Cloud9Character.h" +#include "Cloud9/Weapon/Classes/Cloud9WeaponBase.h" +#include "Components/BillboardComponent.h" + +FName AWeaponSpawner::RootComponentName = "RootComponent"; +FName AWeaponSpawner::TriggerBoxComponentName = "TriggerBox"; +FName AWeaponSpawner::WeaponSampleComponentName = "WeaponInitializer"; +FName AWeaponSpawner::GlowingEffectComponentName = "GlowingEffect"; +FName AWeaponSpawner::SpriteComponentName = "Sprite"; + +AWeaponSpawner::AWeaponSpawner() +{ + PrimaryActorTick.bCanEverTick = true; + + RootComponent = CreateDefaultSubobject(RootComponentName); + + TriggerBoxComponent = CreateDefaultSubobject(TriggerBoxComponentName); + WeaponSampleComponent = CreateDefaultSubobject(WeaponSampleComponentName); + GlowingEffectComponent = CreateDefaultSubobject(GlowingEffectComponentName); + + TriggerBoxComponent->SetupAttachment(RootComponent); + WeaponSampleComponent->SetupAttachment(RootComponent); + GlowingEffectComponent->SetupAttachment(RootComponent); + + GlowingEffect = nullptr; + SampleScale = 1.0f; + RotationSpeedInDegree = 0.0f; + bIsRandomInitialRotation = false; + ZoneSize = {20.0f, 20.0f, 20.0f}; + + TriggerBoxComponent->OnComponentBeginOverlap.AddDynamic(this, &AWeaponSpawner::OnBeginOverlap); + +#if WITH_EDITORONLY_DATA + // SpriteComponent = CreateEditorOnlyDefaultSubobject(SpriteComponentName); + // SpriteComponent->SetupAttachment(RootComponent); + // + // static ConstructorHelpers::FObjectFinderOptional + // TriggerTextureObject(TEXT("/Engine/EditorResources/S_Trigger")); + // + // SpriteComponent->Sprite = TriggerTextureObject.Get(); + // SpriteComponent->SetRelativeScale3D(FVector(0.5f, 0.5f, 0.5f)); + // SpriteComponent->bHiddenInGame = true; + // SpriteComponent->bIsScreenSizeScaled = true; +#endif +} + +void AWeaponSpawner::OnConstruction(const FTransform& Transform) +{ + Super::OnConstruction(Transform); + + TriggerBoxComponent->SetBoxExtent(ZoneSize); + + if (IsValid(GlowingEffect)) + { + GlowingEffectComponent->SetAsset(GlowingEffect); + } + + if (IsValid(WeaponConfig)) + { + WeaponSampleComponent->SetChildActorClass(WeaponConfig.GetWeaponStaticClass()); + + var WeaponSample = WeaponSampleComponent->GetChildActor(); + + if (not IsValid(WeaponSample)) + { + WeaponSampleComponent->CreateChildActor(); + WeaponSample = WeaponSampleComponent->GetChildActor(); + } + + if (not WeaponConfig.Initialize(WeaponSample)) + { + // WeaponSampleComponent->DestroyChildActor(); + SetActorTickEnabled(false); + return; + } + + if (not IsValid(WeaponSample)) + { + log(Error, "WeaponSampleComponent child actor is invalid"); + return; + } + + WeaponSample->UpdateComponentTransforms(); + WeaponSample->SetActorEnableCollision(false); + WeaponSample->SetActorScale3D({SampleScale, SampleScale, SampleScale}); + + if (bIsRandomInitialRotation) + { + var Rotation = WeaponSample->GetActorRotation(); + Rotation.Yaw = FMath::RandRange(0.0f, 360.0f); + WeaponSample->SetActorRotation(Rotation); + } + } +} + +void AWeaponSpawner::BeginPlay() +{ + Super::BeginPlay(); +} + +void AWeaponSpawner::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + + if (IsValid(WeaponConfig)) + { + let Actor = WeaponSampleComponent->GetChildActor(); + + if (not IsValid(Actor)) + { + log(Error, "WeaponSampleComponent child actor is invalid"); + return; + } + + var Rotation = Actor->GetActorRotation(); + Rotation.Yaw += DeltaTime * RotationSpeedInDegree; + Actor->SetActorRotation(Rotation); + } +} + +void AWeaponSpawner::OnBeginOverlap( + UPrimitiveComponent* OverlappedComponent, + AActor* OtherActor, + UPrimitiveComponent* OtherComponent, + int32 OtherBodyIndex, + bool bFromSweep, + const FHitResult& Hit) +{ + if (let Character = Cast(OtherActor); IsValid(Character) and IsValid(WeaponConfig)) + { + let Inventory = Character->GetInventory(); + + if (not IsValid(Inventory)) + { + log(Error, "Inventory is invalid"); + return; + } + + Inventory->AddWeapon(WeaponConfig, true, true); + } +} + +void AWeaponSpawner::Initialize() {} diff --git a/Source/Cloud9/Weapon/Utils/WeaponSpawner.h b/Source/Cloud9/Weapon/Utils/WeaponSpawner.h new file mode 100644 index 000000000..4ed5b3766 --- /dev/null +++ b/Source/Cloud9/Weapon/Utils/WeaponSpawner.h @@ -0,0 +1,81 @@ +// Copyright (c) 2024 Alexei Gladkikh + +#pragma once + +#include "CoreMinimal.h" +#include "Cloud9/Weapon/Structures/WeaponConfig.h" +#include "GameFramework/Actor.h" +#include "WeaponSpawner.generated.h" + +class UBoxComponent; +class UNiagaraSystem; +class UNiagaraComponent; + +UCLASS() +class CLOUD9_API AWeaponSpawner : public AActor +{ + GENERATED_BODY() + +public: + static FName RootComponentName; + static FName TriggerBoxComponentName; + static FName WeaponSampleComponentName; + static FName GlowingEffectComponentName; + static FName SpriteComponentName; + +public: + AWeaponSpawner(); + +protected: + virtual void OnConstruction(const FTransform& Transform) override; + + virtual void BeginPlay() override; + + virtual void Tick(float DeltaTime) override; + + UFUNCTION() + void OnBeginOverlap( + UPrimitiveComponent* OverlappedComponent, + AActor* OtherActor, + UPrimitiveComponent* OtherComponent, + int32 OtherBodyIndex, + bool bFromSweep, + const FHitResult& Hit); + + void Initialize(); + +protected: + UPROPERTY(BlueprintReadOnly, Category=Implementation) + UBoxComponent* TriggerBoxComponent; + + UPROPERTY(BlueprintReadOnly, Category=Implementation) + UChildActorComponent* WeaponSampleComponent; + + UPROPERTY(BlueprintReadOnly, Category=Implementation) + UNiagaraComponent* GlowingEffectComponent; + + UPROPERTY(EditAnywhere, Category=Config) + FWeaponConfig WeaponConfig; + + UPROPERTY(EditAnywhere, Category=Glowing) + UNiagaraSystem* GlowingEffect; + + UPROPERTY(EditAnywhere, Category=WeaponSample) + float SampleScale; + + UPROPERTY(EditAnywhere, Category=WeaponSample) + float RotationSpeedInDegree; + + UPROPERTY(EditAnywhere, Category=WeaponSample) + bool bIsRandomInitialRotation; + + UPROPERTY(EditAnywhere, Category=Zone) + FVector ZoneSize; + +private: +#if WITH_EDITORONLY_DATA + /** Billboard used to see the trigger in the editor */ + UPROPERTY() + UBillboardComponent* SpriteComponent; +#endif +};