第一次提交

This commit is contained in:
不明不惑
2026-03-03 01:23:02 +08:00
commit 3e434877e8
1053 changed files with 102411 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Drops/GIS_CurrencyDropper.h"
#include "GIS_CurrencySystemComponent.h"
#include "GIS_LogChannels.h"
#include "Misc/DataValidation.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GIS_CurrencyDropper)
void UGIS_CurrencyDropper::BeginPlay()
{
MyCurrency = UGIS_CurrencySystemComponent::GetCurrencySystemComponent(GetOwner());
if (MyCurrency == nullptr)
{
GIS_CLOG(Warning, "Mising currency system component!");
}
Super::BeginPlay();
}
void UGIS_CurrencyDropper::Drop()
{
if (AActor* PickupActor = CreatePickupActorInstance())
{
if (UGIS_CurrencySystemComponent* CurrencySys = UGIS_CurrencySystemComponent::GetCurrencySystemComponent(PickupActor))
{
CurrencySys->SetCurrencies(MyCurrency->GetAllCurrencies());
}
}
}
#if WITH_EDITOR
EDataValidationResult UGIS_CurrencyDropper::IsDataValid(FDataValidationContext& Context) const
{
if (PickupActorClass.IsNull())
{
Context.AddError(FText::FromString(FString::Format(TEXT("%s has no pickup actor class.!"), {*GetName()})));
return EDataValidationResult::Invalid;
}
return Super::IsDataValid(Context);
}
#endif

View File

@@ -0,0 +1,78 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Drops/GIS_DropperComponent.h"
#include "Engine/World.h"
#include "GIS_LogChannels.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/Character.h"
#include "Kismet/KismetMathLibrary.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GIS_DropperComponent)
UGIS_DropperComponent::UGIS_DropperComponent()
{
PrimaryComponentTick.bStartWithTickEnabled = false;
PrimaryComponentTick.bCanEverTick = false;
SetIsReplicatedByDefault(true);
}
void UGIS_DropperComponent::Drop()
{
}
AActor* UGIS_DropperComponent::CreatePickupActorInstance_Implementation()
{
UWorld* World = GetWorld();
check(World);
if (PickupActorClass.IsNull())
{
GIS_CLOG(Error, "missing PickupActorClass!");
return nullptr;
}
UClass* PickupClass = PickupActorClass.LoadSynchronous();
if (PickupClass == nullptr)
{
GIS_CLOG(Error, "failed to load PickupActorClass!");
return nullptr;
}
FVector Origin = CalcDropOrigin();
AActor* Pickup = World->SpawnActor<AActor>(PickupClass, FTransform(Origin + CalcDropOffset()));
if (Pickup == nullptr)
{
GIS_CLOG(Error, "failed to spawn pickup actor from PickupActorClass(%s)!", *PickupClass->GetName());
return nullptr;
}
return Pickup;
}
FVector UGIS_DropperComponent::CalcDropOrigin_Implementation() const
{
if (IsValid(DropTransform))
{
return DropTransform->GetActorLocation();
}
FVector OriginLocation = GetOwner()->GetActorLocation();
if (const ACharacter* Character = Cast<ACharacter>(GetOwner()))
{
OriginLocation.Z -= Character->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
}
else if (const UCapsuleComponent* CapsuleComponent = Cast<UCapsuleComponent>(GetOwner()->GetRootComponent()))
{
OriginLocation.Z -= CapsuleComponent->GetScaledCapsuleHalfHeight();
}
return OriginLocation;
}
FVector UGIS_DropperComponent::CalcDropOffset_Implementation() const
{
const float RandomX = UKismetMathLibrary::RandomFloatInRange(-DropRadius, DropRadius);
const float RandomY = UKismetMathLibrary::RandomFloatInRange(-DropRadius, DropRadius);
return FVector(RandomX, RandomY, 0);
}

View File

@@ -0,0 +1,108 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Drops/GIS_ItemDropperComponent.h"
#include "GIS_InventoryTags.h"
#include "GameFramework/Actor.h"
#include "GIS_InventorySystemComponent.h"
#include "GIS_ItemCollection.h"
#include "GIS_LogChannels.h"
#include "Pickups/GIS_InventoryPickupComponent.h"
#include "Pickups/GIS_ItemPickupComponent.h"
#include "Pickups/GIS_WorldItemComponent.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GIS_ItemDropperComponent)
void UGIS_ItemDropperComponent::Drop()
{
TArray<FGIS_ItemInfo> ItemsToDrop = GetItemsToDrop();
DropItemsInternal(ItemsToDrop);
}
void UGIS_ItemDropperComponent::BeginPlay()
{
if (!CollectionTag.IsValid())
{
CollectionTag = GIS_CollectionTags::Main;
}
Super::BeginPlay();
}
TArray<FGIS_ItemInfo> UGIS_ItemDropperComponent::GetItemsToDrop() const
{
return GetItemsToDropInternal();
}
TArray<FGIS_ItemInfo> UGIS_ItemDropperComponent::GetItemsToDropInternal() const
{
TArray<FGIS_ItemInfo> Items;
UGIS_InventorySystemComponent* Inventory = UGIS_InventorySystemComponent::FindInventorySystemComponent(GetOwner());
if (Inventory == nullptr)
{
GIS_CLOG(Error, "requires inventory system component to drop items.")
return Items;
}
UGIS_ItemCollection* Collection = Inventory->GetCollectionByTag(CollectionTag);
if (Collection == nullptr)
{
GIS_CLOG(Error, " inventory missing collection with tag:%s'", *CollectionTag.ToString())
return Items;
}
Items = Collection->GetAllItemInfos();
return Items;
}
void UGIS_ItemDropperComponent::DropItemsInternal(const TArray<FGIS_ItemInfo>& ItemInfos)
{
if (bDropAsInventory)
{
DropInventoryPickup(ItemInfos);
}
else
{
for (int32 i = 0; i < ItemInfos.Num(); i++)
{
DropItemPickup(ItemInfos[i]);
}
}
}
void UGIS_ItemDropperComponent::DropInventoryPickup(const TArray<FGIS_ItemInfo>& ItemInfos)
{
if (AActor* PickupActor = CreatePickupActorInstance())
{
UGIS_InventorySystemComponent* Inventory = PickupActor->FindComponentByClass<UGIS_InventorySystemComponent>();
UGIS_InventoryPickupComponent* Pickup = PickupActor->FindComponentByClass<UGIS_InventoryPickupComponent>();
if (Inventory == nullptr || Pickup == nullptr)
{
GIS_CLOG(Error, "Spawned pickup(%s) missing either inventory component or inventory pickup component.", *PickupActor->GetName());
return;
}
UGIS_ItemCollection* Collection = Inventory->GetDefaultCollection();
if (Collection == nullptr)
{
GIS_CLOG(Error, "Spawned pickup(%s)'s inventory doesn't have default collection.", *PickupActor->GetName());
return;
}
Collection->RemoveAll();
Collection->AddItems(ItemInfos);
}
}
void UGIS_ItemDropperComponent::DropItemPickup(const FGIS_ItemInfo& ItemInfo)
{
if (AActor* Pickup = CreatePickupActorInstance())
{
UGIS_ItemPickupComponent* ItemPickup = Pickup->FindComponentByClass<UGIS_ItemPickupComponent>();
UGIS_WorldItemComponent* WorldItem = Pickup->FindComponentByClass<UGIS_WorldItemComponent>();
if (ItemPickup == nullptr || WorldItem == nullptr)
{
GIS_CLOG(Error, "Spawned pickup(%s) missing either ItemPickup component or WorldItem component.", *Pickup->GetName());
}
WorldItem->SetItemInfo(ItemInfo.Item, ItemInfo.Amount);
}
}

View File

@@ -0,0 +1,94 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Drops/GIS_RandomItemDropperComponent.h"
#include "GameFramework/Actor.h"
#include "GIS_InventorySystemComponent.h"
#include "GIS_ItemCollection.h"
#include "GIS_LogChannels.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GIS_RandomItemDropperComponent)
TArray<FGIS_ItemInfo> UGIS_RandomItemDropperComponent::GetItemsToDropInternal() const
{
TArray<FGIS_ItemInfo> Results;
UGIS_InventorySystemComponent* Inventory = UGIS_InventorySystemComponent::FindInventorySystemComponent(GetOwner());
if (Inventory == nullptr)
{
GIS_CLOG(Error, "requires inventory system component to drop items.")
return Results;
}
UGIS_ItemCollection* Collection = Inventory->GetCollectionByTag(CollectionTag);
if (Collection == nullptr)
{
GIS_CLOG(Error, " inventory missing collection with tag:%s'", *CollectionTag.ToString())
return Results;
}
const TArray<FGIS_ItemStack>& ItemStacks = Collection->GetAllItemStacks();
TArray<FGIS_ItemInfo> ItemInfos;
ItemInfos.Reserve(ItemStacks.Num());
int32 ProbabilitySum = 0;
for (int32 i = 0; i < ItemStacks.Num(); ++i)
{
//加权
ProbabilitySum += ItemStacks[i].Amount;
ItemInfos[i] = FGIS_ItemInfo(ProbabilitySum, ItemStacks[i]);
}
int32 RandomAmount = FMath::RandRange(MinAmount, MaxAmount + 1);
Results.Empty();
for (int i = 0; i < RandomAmount; i++)
{
auto& selectedItemInfo = GetRandomItemInfo(ItemInfos, ProbabilitySum);
bool foundMatch = false;
//去重,多个栈可能指向同一个道具实例,若发现重复
for (int j = 0; j < Results.Num(); j++)
{
if (Results[j].Item == selectedItemInfo.Item)
{
Results[j] = FGIS_ItemInfo(Results[j].Amount + 1, Results[j]);
foundMatch = true;
break;
}
}
if (!foundMatch) { Results.Add(FGIS_ItemInfo(1, selectedItemInfo)); }
}
return Results;
}
const FGIS_ItemInfo& UGIS_RandomItemDropperComponent::GetRandomItemInfo(const TArray<FGIS_ItemInfo>& ItemInfos, int32 ProbabilitySum) const
{
int32 RandomProbabilityIdx = FMath::RandRange(0, ProbabilitySum);
int32 min = 0;
int32 max = ItemInfos.Num() - 1;
int32 mid = 0;
while (min <= max)
{
mid = (min + max) / 2;
if (ItemInfos[mid].Amount == RandomProbabilityIdx)
{
++mid;
break;
}
if (RandomProbabilityIdx < ItemInfos[mid].Amount
&& (mid == 0 || RandomProbabilityIdx > ItemInfos[mid - 1].Amount)) { break; }
if (RandomProbabilityIdx < ItemInfos[mid].Amount) { max = mid - 1; }
else
{
min = mid + 1;
}
}
return ItemInfos[mid];
}