Migration
This commit is contained in:
@@ -0,0 +1,321 @@
|
||||
// Amasson
|
||||
|
||||
|
||||
#include "Components/SlotInventoryComponent.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "GameFramework/PlayerState.h"
|
||||
|
||||
USlotInventoryComponent::USlotInventoryComponent()
|
||||
{
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
|
||||
SetComponentTickEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
/** Public Content Management */
|
||||
|
||||
const FInventoryContent& USlotInventoryComponent::GetContent() const
|
||||
{
|
||||
return Content;
|
||||
}
|
||||
|
||||
int32 USlotInventoryComponent::GetContentCapacity() const
|
||||
{
|
||||
return Content.Slots.Num();
|
||||
}
|
||||
|
||||
void USlotInventoryComponent::SetContentCapacity(int32 NewCapacity)
|
||||
{
|
||||
if (NewCapacity < 0)
|
||||
NewCapacity = 0;
|
||||
|
||||
const int32 OldCapacity = GetContentCapacity();
|
||||
|
||||
Content.Slots.SetNum(NewCapacity, true);
|
||||
|
||||
if (NewCapacity > OldCapacity)
|
||||
{
|
||||
for (int32 NewSlotIndex = OldCapacity; NewSlotIndex < NewCapacity; NewSlotIndex++)
|
||||
{
|
||||
ClearSlotAtIndex(NewSlotIndex);
|
||||
}
|
||||
}
|
||||
OnInventoryCapacityChanged.Broadcast(this, NewCapacity);
|
||||
}
|
||||
|
||||
|
||||
/** Public Slot Management */
|
||||
|
||||
bool USlotInventoryComponent::GetSlotValueAtIndex(int32 Index, FInventorySlot& SlotValue) const
|
||||
{
|
||||
if (const FInventorySlot* SlotPtr = Content.GetSlotConstPtrAtIndex(Index))
|
||||
{
|
||||
SlotValue = *SlotPtr;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool USlotInventoryComponent::SetSlotValueAtIndex(int32 Index, const FInventorySlot& NewSlotValue)
|
||||
{
|
||||
if (FInventorySlot* SlotPtr = Content.GetSlotPtrAtIndex(Index))
|
||||
{
|
||||
*SlotPtr = NewSlotValue;
|
||||
MarkDirtySlot(Index);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool USlotInventoryComponent::IsEmptySlotAtIndex(int32 Index) const
|
||||
{
|
||||
if (const FInventorySlot* SlotPtr = Content.GetSlotConstPtrAtIndex(Index))
|
||||
return SlotPtr->IsEmpty();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool USlotInventoryComponent::ClearSlotAtIndex(int32 Index)
|
||||
{
|
||||
if (FInventorySlot* SlotPtr = Content.GetSlotPtrAtIndex(Index))
|
||||
{
|
||||
bool bIsEmpty = SlotPtr->IsEmpty();
|
||||
SlotPtr->Reset();
|
||||
if (!bIsEmpty)
|
||||
{
|
||||
MarkDirtySlot(Index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 USlotInventoryComponent::GetEmptySlotCounts() const
|
||||
{
|
||||
int32 Total = 0;
|
||||
|
||||
for (const FInventorySlot& Slot : Content.Slots)
|
||||
{
|
||||
if (Slot.IsEmpty())
|
||||
++Total;
|
||||
}
|
||||
return Total;
|
||||
}
|
||||
|
||||
bool USlotInventoryComponent::ContainsOnlyEmptySlots() const
|
||||
{
|
||||
for (const FInventorySlot& Slot : Content.Slots)
|
||||
{
|
||||
if (!Slot.IsEmpty())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void USlotInventoryComponent::ModifySlotCountAtIndex(int32 Index, int32 ModifyAmount, bool bAllOrNothing, int32& Overflow)
|
||||
{
|
||||
FInventorySlot* SlotPtr = Content.GetSlotPtrAtIndex(Index);
|
||||
|
||||
if (!SlotPtr || SlotPtr->IsEmpty())
|
||||
{
|
||||
Overflow = ModifyAmount;
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8 MaxStackSize = GetMaxStackSizeForID(SlotPtr->ID);
|
||||
|
||||
if (bAllOrNothing)
|
||||
{
|
||||
bool bModified = SlotPtr->TryModifyCountByExact(ModifyAmount, MaxStackSize);
|
||||
if (bModified)
|
||||
{
|
||||
Overflow = 0;
|
||||
MarkDirtySlot(Index);
|
||||
}
|
||||
else
|
||||
Overflow = ModifyAmount;
|
||||
}
|
||||
else
|
||||
{
|
||||
SlotPtr->ModifyCountWithOverflow(ModifyAmount, Overflow, MaxStackSize);
|
||||
if (Overflow != ModifyAmount)
|
||||
MarkDirtySlot(Index);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 USlotInventoryComponent::GetMaxStackSizeForID(const FName& ID) const
|
||||
{
|
||||
return 255;
|
||||
}
|
||||
|
||||
void USlotInventoryComponent::GetMaxStackSizeForIds(const TSet<FName>& Ids, TMap<FName, uint8>& MaxStackSizes) const
|
||||
{
|
||||
for (const FName& Id : Ids)
|
||||
{
|
||||
const uint8 MaxStackSize = GetMaxStackSizeForID(Id);
|
||||
MaxStackSizes.Add(Id, MaxStackSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Content Management */
|
||||
|
||||
int32 USlotInventoryComponent::GetContentIdCount(FName Id) const
|
||||
{
|
||||
int32 Total = 0;
|
||||
|
||||
for (const FInventorySlot& Slot : Content.Slots)
|
||||
{
|
||||
if (Slot.IsEmpty()) continue;
|
||||
|
||||
if (Slot.ID == Id)
|
||||
Total += Slot.Count;
|
||||
}
|
||||
return Total;
|
||||
}
|
||||
|
||||
bool USlotInventoryComponent::ModifyContentWithOverflow(const TMap<FName, int32>& IdsAndCounts, TMap<FName, int32>& Overflows)
|
||||
{
|
||||
const TMap<FName, uint8>& MaxStackSizes = GetMaxStackSizesFromIds(IdsAndCounts);
|
||||
|
||||
TSet<int32> ModifiedSlots;
|
||||
FInventoryContent::FContentModificationResult ModificationResult(&ModifiedSlots, &Overflows);
|
||||
Content.ModifyContentWithValues(IdsAndCounts, MaxStackSizes, ModificationResult);
|
||||
|
||||
for (int32 ModifiedSlotIndex : ModifiedSlots)
|
||||
{
|
||||
MarkDirtySlot(ModifiedSlotIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool USlotInventoryComponent::TryModifyContentWithoutOverflow(const TMap<FName, int32>& IdsAndCounts)
|
||||
{
|
||||
const TMap<FName, uint8>& MaxStackSizes = GetMaxStackSizesFromIds(IdsAndCounts);
|
||||
|
||||
TSet<int32> ModifiedSlots;
|
||||
|
||||
FInventoryContent TmpContent = Content;
|
||||
|
||||
TMap<FName, int32> TmpOverflows;
|
||||
FInventoryContent::FContentModificationResult ModificationResult(&ModifiedSlots, &TmpOverflows);
|
||||
|
||||
TmpContent.ModifyContentWithValues(IdsAndCounts, MaxStackSizes, ModificationResult);
|
||||
|
||||
if (!TmpOverflows.IsEmpty())
|
||||
return false;
|
||||
|
||||
Content = TmpContent;
|
||||
|
||||
for (int32 ModifiedSlotIndex : ModifiedSlots)
|
||||
MarkDirtySlot(ModifiedSlotIndex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool USlotInventoryComponent::DropSlotTowardOtherInventoryAtIndex(int32 SourceIndex, USlotInventoryComponent* DestinationInventory, int32 DestinationIndex, uint8 MaxAmount)
|
||||
{
|
||||
if (!IsValid(DestinationInventory)) return false;
|
||||
|
||||
FInventorySlot* SourceSlot = Content.GetSlotPtrAtIndex(SourceIndex);
|
||||
if (!SourceSlot)
|
||||
return false;
|
||||
|
||||
const uint8 MaxStackSize = DestinationInventory->GetMaxStackSizeForID(SourceSlot->ID);
|
||||
|
||||
if (DestinationInventory->Content.ReceiveSlotAtIndex(*SourceSlot, DestinationIndex, MaxStackSize, MaxAmount))
|
||||
{
|
||||
MarkDirtySlot(SourceIndex);
|
||||
DestinationInventory->MarkDirtySlot(DestinationIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool USlotInventoryComponent::DropSlotTowardOtherInventory(int32 SourceIndex, USlotInventoryComponent* Destination)
|
||||
{
|
||||
if (!IsValid(Destination)) return false;
|
||||
|
||||
FInventorySlot SourceSlot;
|
||||
if (!GetSlotValueAtIndex(SourceIndex, SourceSlot))
|
||||
return false;
|
||||
|
||||
if (SourceSlot.IsEmpty())
|
||||
return false;
|
||||
|
||||
TMap<FName, int32> Modifications;
|
||||
Modifications.Add(SourceSlot.ID, SourceSlot.Count);
|
||||
|
||||
TMap<FName, int32> Overflows;
|
||||
if (!Destination->ModifyContentWithOverflow(Modifications, Overflows))
|
||||
return false;
|
||||
|
||||
if (Overflows.IsEmpty())
|
||||
{
|
||||
ClearSlotAtIndex(SourceIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
checkf(Overflows.Contains(SourceSlot.ID), TEXT("Overflow is not empty but does not contains SourceSlot.ID"));
|
||||
const int32 NewCount = Overflows[SourceSlot.ID];
|
||||
|
||||
if (SourceSlot.Count == NewCount)
|
||||
return false;
|
||||
|
||||
SourceSlot.Count = NewCount;
|
||||
return SetSlotValueAtIndex(SourceIndex, SourceSlot);
|
||||
}
|
||||
|
||||
void USlotInventoryComponent::RegroupSlotAtIndexWithSimilarIds(int32 Index)
|
||||
{
|
||||
TSet<int32> ModifiedSlots;
|
||||
FInventoryContent::FContentModificationResult ModificationResult(&ModifiedSlots, nullptr);
|
||||
|
||||
FInventorySlot* Slot = Content.GetSlotPtrAtIndex(Index);
|
||||
if (!Slot) return;
|
||||
|
||||
const uint8 MaxStackSize = GetMaxStackSizeForID(Slot->ID);
|
||||
|
||||
Content.RegroupSlotsWithSimilarIdsAtIndex(Index, ModificationResult, MaxStackSize, Slot);
|
||||
|
||||
for (const int32 ModifiedSlotIndex : ModifiedSlots)
|
||||
MarkDirtySlot(ModifiedSlotIndex);
|
||||
}
|
||||
|
||||
|
||||
/** Private Content Management */
|
||||
|
||||
const TMap<FName, uint8> USlotInventoryComponent::GetMaxStackSizesFromIds(const TMap<FName, int32>& IdsAndCounts) const
|
||||
{
|
||||
TSet<FName> Ids;
|
||||
IdsAndCounts.GetKeys(Ids);
|
||||
TMap<FName, uint8> MaxStackSizes;
|
||||
GetMaxStackSizeForIds(Ids, MaxStackSizes);
|
||||
return MaxStackSizes;
|
||||
}
|
||||
|
||||
/** Slot Updating */
|
||||
|
||||
void USlotInventoryComponent::BroadcastContentUpdate()
|
||||
{
|
||||
OnInventoryContentChanged.Broadcast(this, DirtySlots.Array());
|
||||
DirtySlots.Reset();
|
||||
}
|
||||
|
||||
void USlotInventoryComponent::MarkDirtySlot(int32 SlotIndex)
|
||||
{
|
||||
DirtySlots.Add(SlotIndex);
|
||||
MarkSlotsHaveBeenModified();
|
||||
}
|
||||
|
||||
void USlotInventoryComponent::MarkSlotsHaveBeenModified()
|
||||
{
|
||||
SetComponentTickEnabled(true);
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
// Amasson
|
||||
|
||||
|
||||
#include "Components/SlotInventoryComponent_Networked.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
|
||||
USlotInventoryComponent_Networked::USlotInventoryComponent_Networked()
|
||||
{
|
||||
SetIsReplicatedByDefault(true);
|
||||
bHasAuthority = GetOwner() ? GetOwner()->HasAuthority() : false;
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
if (bHasAuthority)
|
||||
{
|
||||
OnInventoryCapacityChanged.AddDynamic(this, &ThisClass::OnCapacityChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::Server_BroadcastFullInventory_Implementation(bool bOwnerOnly)
|
||||
{
|
||||
TArray<int32> AllIndices;
|
||||
AllIndices.Reserve(GetContentCapacity() + 1); // Reserve space for N+1 elements
|
||||
for (int32 i = 0; i <= GetContentCapacity(); i++)
|
||||
AllIndices.Add(i);
|
||||
|
||||
if (bOwnerOnly)
|
||||
Client_UpdateSlotsValues_Implementation(AllIndices, Content.Slots);
|
||||
else
|
||||
NetMulticast_UpdateSlotsValues_Implementation(AllIndices, Content.Slots);
|
||||
}
|
||||
|
||||
|
||||
/** Client Request */
|
||||
|
||||
void USlotInventoryComponent_Networked::Server_RequestSetContentCapacity_Implementation(int32 NewCapacity)
|
||||
{
|
||||
SetContentCapacity(NewCapacity);
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::Server_RequestSetSlotValueAtIndex_Implementation(int32 Index, const FInventorySlot& NewSlotValue)
|
||||
{
|
||||
SetSlotValueAtIndex(Index, NewSlotValue);
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::Server_RequestClearSlotAtIndex_Implementation(int32 Index)
|
||||
{
|
||||
ClearSlotAtIndex(Index);
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::Server_RequestDropSlotTowardOtherInventoryAtIndex_Implementation(int32 SourceIndex, USlotInventoryComponent* DestinationInventory, int32 DestinationIndex, uint8 MaxAmount)
|
||||
{
|
||||
DropSlotTowardOtherInventoryAtIndex(SourceIndex, DestinationInventory, DestinationIndex, MaxAmount);
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::Server_RequestDropSlotTowardOtherInventory_Implementation(int32 SourceIndex, USlotInventoryComponent* DestinationInventory)
|
||||
{
|
||||
DropSlotTowardOtherInventory(SourceIndex, DestinationInventory);
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::Server_RequestDropSlotFromOtherInventoryAtIndex_Implementation(int32 DestinationIndex, USlotInventoryComponent* SourceInventory, int32 SourceIndex, uint8 MaxAmount)
|
||||
{
|
||||
if (IsValid(SourceInventory))
|
||||
{
|
||||
SourceInventory->DropSlotTowardOtherInventoryAtIndex(SourceIndex, this, DestinationIndex, MaxAmount);
|
||||
}
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::Server_RequestDropSlotFromOtherInventory_Implementation(USlotInventoryComponent* SourceInventory, int32 SourceIndex)
|
||||
{
|
||||
if (IsValid(SourceInventory))
|
||||
{
|
||||
SourceInventory->DropSlotTowardOtherInventory(SourceIndex, this);
|
||||
}
|
||||
}
|
||||
|
||||
static AActor* GetLastValidOwner(AActor* Actor)
|
||||
{
|
||||
if (IsValid(Actor))
|
||||
{
|
||||
AActor* Owner = Actor->GetOwner();
|
||||
AActor* ValidOwner = GetLastValidOwner(Owner);
|
||||
return IsValid(ValidOwner) ? ValidOwner : Actor;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool IsValidAndCanCallRPC(UActorComponent* Component)
|
||||
{
|
||||
if (IsValid(Component))
|
||||
{
|
||||
AActor* LastOwner = GetLastValidOwner(Component->GetOwner());
|
||||
if (IsValid(LastOwner))
|
||||
{
|
||||
ENetRole NetRole = LastOwner->GetLocalRole();
|
||||
bool bCanCallRPC = NetRole >= ENetRole::ROLE_AutonomousProxy;
|
||||
return bCanCallRPC;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::DropInventorySlotFromSourceToDestinationAtIndex(USlotInventoryComponent_Networked* SourceInventory, int32 SourceIndex, USlotInventoryComponent_Networked* DestinationInventory, int32 DestinationIndex, uint8 MaxAmount)
|
||||
{
|
||||
if (IsValidAndCanCallRPC(SourceInventory))
|
||||
{
|
||||
SourceInventory->Server_RequestDropSlotTowardOtherInventoryAtIndex(SourceIndex, DestinationInventory, DestinationIndex, MaxAmount);
|
||||
}
|
||||
else if (IsValidAndCanCallRPC(DestinationInventory))
|
||||
{
|
||||
DestinationInventory->Server_RequestDropSlotFromOtherInventoryAtIndex(DestinationIndex, SourceInventory, SourceIndex, MaxAmount);
|
||||
}
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::DropInventorySlotFromSourceToDestination(USlotInventoryComponent_Networked* SourceInventory, int32 SourceIndex, USlotInventoryComponent_Networked* DestinationInventory)
|
||||
{
|
||||
if (IsValidAndCanCallRPC(SourceInventory))
|
||||
{
|
||||
SourceInventory->Server_RequestDropSlotTowardOtherInventory(SourceIndex, DestinationInventory);
|
||||
}
|
||||
else if (IsValidAndCanCallRPC(DestinationInventory))
|
||||
{
|
||||
DestinationInventory->Server_RequestDropSlotFromOtherInventory(SourceInventory, SourceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::Server_RequestRegroupSlotAtIndexWithSimilarIds_Implementation(int32 Index)
|
||||
{
|
||||
RegroupSlotAtIndexWithSimilarIds(Index);
|
||||
}
|
||||
|
||||
|
||||
/** Slot Update */
|
||||
|
||||
void USlotInventoryComponent_Networked::NetMulticast_UpdateSlotsValues_Implementation(const TArray<int32>& Indices, const TArray<FInventorySlot>& Values)
|
||||
{
|
||||
ReceievedUpdateSlotsValues(Indices, Values);
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::Client_UpdateSlotsValues_Implementation(const TArray<int32>& Indices, const TArray<FInventorySlot>& Values)
|
||||
{
|
||||
ReceievedUpdateSlotsValues(Indices, Values);
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::ReceievedUpdateSlotsValues(const TArray<int32>& Indices, const TArray<FInventorySlot>& Values)
|
||||
{
|
||||
checkf(Indices.Num() == Values.Num(), TEXT("SlotInventoryComponent_Networked::ReceievedUpdateSlotsValues: Received miss matching arrays"));
|
||||
|
||||
if (bHasAuthority)
|
||||
return;
|
||||
|
||||
for (int32 i = 0; i < Indices.Num(); i++)
|
||||
{
|
||||
SetSlotValueAtIndex(Indices[i], Values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Capacity Update */
|
||||
|
||||
void USlotInventoryComponent_Networked::OnCapacityChanged(USlotInventoryComponent* SlotInventoryComponent, int32 NewCapacity)
|
||||
{
|
||||
if (SlotInventoryComponent == this)
|
||||
{
|
||||
NetMulticast_UpdateCapacity(NewCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::NetMulticast_UpdateCapacity_Implementation(int32 NewCapacity)
|
||||
{
|
||||
if (bHasAuthority)
|
||||
return;
|
||||
|
||||
SetContentCapacity(NewCapacity);
|
||||
}
|
||||
|
||||
|
||||
/** Content Update */
|
||||
|
||||
void USlotInventoryComponent_Networked::BroadcastContentUpdate()
|
||||
{
|
||||
if (bHasAuthority)
|
||||
BroadcastModifiedSlotsToClients();
|
||||
|
||||
Super::BroadcastContentUpdate();
|
||||
}
|
||||
|
||||
void USlotInventoryComponent_Networked::BroadcastModifiedSlotsToClients()
|
||||
{
|
||||
TArray<int32> Indices;
|
||||
TArray<FInventorySlot> Values;
|
||||
|
||||
for (int32 DirtySlotIndex : DirtySlots)
|
||||
{
|
||||
FInventorySlot SlotValue;
|
||||
if (GetSlotValueAtIndex(DirtySlotIndex, SlotValue))
|
||||
{
|
||||
Indices.Add(DirtySlotIndex);
|
||||
Values.Add(SlotValue);
|
||||
}
|
||||
}
|
||||
NetMulticast_UpdateSlotsValues(Indices, Values);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "SlotBasedInventorySystem.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FSlotBasedInventorySystemModule"
|
||||
|
||||
void FSlotBasedInventorySystemModule::StartupModule()
|
||||
{
|
||||
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
|
||||
}
|
||||
|
||||
void FSlotBasedInventorySystemModule::ShutdownModule()
|
||||
{
|
||||
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
|
||||
// we call this function before unloading the module.
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FSlotBasedInventorySystemModule, SlotBasedInventorySystem)
|
||||
@@ -0,0 +1,15 @@
|
||||
// Amasson
|
||||
|
||||
|
||||
#include "SlotInventoryBlueprintLibrary.h"
|
||||
|
||||
|
||||
bool USlotInventoryBlueprintLibrary::IsValidIndex(const FInventoryContent& Content, int32 Index)
|
||||
{
|
||||
return Content.IsValidIndex(Index);
|
||||
}
|
||||
|
||||
bool USlotInventoryBlueprintLibrary::IsEmptySlot(const FInventorySlot& Slot)
|
||||
{
|
||||
return Slot.IsEmpty();
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
// Amasson
|
||||
|
||||
|
||||
#include "Structures/SlotInventorySystemStructs.h"
|
||||
#include "Math/UnrealMathUtility.h"
|
||||
#include "Templates/UnrealTemplate.h"
|
||||
|
||||
|
||||
bool FInventorySlot::IsEmpty() const
|
||||
{
|
||||
return ID == NAME_None || Count == 0;
|
||||
}
|
||||
|
||||
void FInventorySlot::Reset()
|
||||
{
|
||||
ID = NAME_None;
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
void FInventorySlot::ModifyCountWithOverflow(int32 ModifyAmount, int32& Overflow, uint8 MaxStackSize)
|
||||
{
|
||||
int32 NewCount = Count + ModifyAmount;
|
||||
|
||||
if (NewCount < 0)
|
||||
{
|
||||
Overflow = Count + ModifyAmount;
|
||||
Count = 0;
|
||||
}
|
||||
else if (NewCount > MaxStackSize)
|
||||
{
|
||||
Overflow = Count + ModifyAmount - MaxStackSize;
|
||||
Count = MaxStackSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
Overflow = 0;
|
||||
Count = NewCount;
|
||||
}
|
||||
}
|
||||
|
||||
bool FInventorySlot::TryModifyCountByExact(int32 ModifyAmount, uint8 MaxStackSize)
|
||||
{
|
||||
int32 NewCount = Count + ModifyAmount;
|
||||
|
||||
if (NewCount < 0 || NewCount > MaxStackSize)
|
||||
return false;
|
||||
|
||||
Count = NewCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FInventorySlot::AddIdAndCount(const FName& SlotId, int32 ModifyAmount, int32& Overflow, uint8 MaxStackSize)
|
||||
{
|
||||
if (IsEmpty())
|
||||
{
|
||||
if (ModifyAmount < 0)
|
||||
{
|
||||
Overflow = ModifyAmount;
|
||||
return false;
|
||||
}
|
||||
ID = SlotId;
|
||||
Count = FMath::Min(ModifyAmount, int32(MaxStackSize));
|
||||
Overflow = ModifyAmount - Count;
|
||||
return Overflow != ModifyAmount;
|
||||
}
|
||||
|
||||
if (ID != SlotId)
|
||||
{
|
||||
Overflow = ModifyAmount;
|
||||
return false;
|
||||
}
|
||||
|
||||
ModifyCountWithOverflow(ModifyAmount, Overflow, MaxStackSize);
|
||||
return Overflow != ModifyAmount;
|
||||
}
|
||||
|
||||
|
||||
/** Inventory Content */
|
||||
|
||||
|
||||
bool FInventoryContent::IsValidIndex(int32 Index) const
|
||||
{
|
||||
return Index >= 0 && Index < Slots.Num();
|
||||
}
|
||||
|
||||
FInventorySlot* FInventoryContent::GetSlotPtrAtIndex(int32 Index)
|
||||
{
|
||||
if (!IsValidIndex(Index))
|
||||
return nullptr;
|
||||
|
||||
return &(Slots[Index]);
|
||||
}
|
||||
|
||||
const FInventorySlot* FInventoryContent::GetSlotConstPtrAtIndex(int32 Index) const
|
||||
{
|
||||
if (!IsValidIndex(Index))
|
||||
return nullptr;
|
||||
|
||||
return &(Slots[Index]);
|
||||
}
|
||||
|
||||
FInventoryContent::FContentModificationResult::FContentModificationResult(TSet<int32>* InModifiedSlots, TMap<FName, int32>* InOverflows)
|
||||
: bModifiedSomething(false), bCreatedEmptySlot(false),
|
||||
ModifiedSlots(InModifiedSlots), Overflows(InOverflows)
|
||||
{}
|
||||
|
||||
void FInventoryContent::ModifyContentWithValues(const TMap<FName, int32>& IdsAndCounts, const TMap<FName, uint8>& MaxStackSizes, FContentModificationResult& ModificationResult)
|
||||
{
|
||||
bool bModified = false;
|
||||
bool bHasPositiveOverflow = false;
|
||||
bool bHasNewEmptySlots = false;
|
||||
|
||||
for (const TPair<FName, int32>& IdAndCount : IdsAndCounts)
|
||||
{
|
||||
const FName& SlotId = IdAndCount.Key;
|
||||
int32 ModifyAmount = IdAndCount.Value;
|
||||
const uint8 MaxStackSize = MaxStackSizes[SlotId];
|
||||
|
||||
FContentModificationResult Result(ModificationResult.ModifiedSlots, nullptr);
|
||||
ReceiveSlotOverflow(SlotId, ModifyAmount, MaxStackSize, false, Result);
|
||||
ReceiveSlotOverflow(SlotId, ModifyAmount, MaxStackSize, true, Result);
|
||||
bModified = Result.bModifiedSomething;
|
||||
bHasNewEmptySlots = Result.bCreatedEmptySlot;
|
||||
|
||||
if (ModifyAmount != 0)
|
||||
{
|
||||
if (ModificationResult.Overflows)
|
||||
ModificationResult.Overflows->Add(SlotId, ModifyAmount);
|
||||
if (ModifyAmount > 0)
|
||||
bHasPositiveOverflow = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bModified && bHasPositiveOverflow && bHasNewEmptySlots && ModificationResult.Overflows)
|
||||
{
|
||||
if (ModificationResult.Overflows)
|
||||
{
|
||||
const TMap<FName, int32> NewModifications = *ModificationResult.Overflows;
|
||||
ModificationResult.Overflows->Reset();
|
||||
ModifyContentWithValues(NewModifications, MaxStackSizes, ModificationResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FInventoryContent::ReceiveSlotOverflow(const FName& SlotId, int32& InoutOverflow, uint8 MaxStackSize, bool bTargetEmptySlots, FContentModificationResult& ModificationResult)
|
||||
{
|
||||
for (int32 i = 0; i < Slots.Num() && InoutOverflow != 0; i++)
|
||||
{
|
||||
FInventorySlot& Slot(Slots[i]);
|
||||
|
||||
if (Slot.IsEmpty() != bTargetEmptySlots)
|
||||
continue;
|
||||
|
||||
if (Slot.AddIdAndCount(SlotId, InoutOverflow, InoutOverflow, MaxStackSize))
|
||||
{
|
||||
ModificationResult.bModifiedSomething = true;
|
||||
if (Slot.IsEmpty())
|
||||
ModificationResult.bCreatedEmptySlot = true;
|
||||
if (ModificationResult.ModifiedSlots)
|
||||
ModificationResult.ModifiedSlots->Add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FInventoryContent::ReceiveSlotAtIndex(FInventorySlot& InoutSlot, int32 Index, uint8 MaxStackSize, uint8 MaxTransferAmount)
|
||||
{
|
||||
FInventorySlot* LocalSlot = GetSlotPtrAtIndex(Index);
|
||||
if (!LocalSlot)
|
||||
return false;
|
||||
|
||||
if (LocalSlot->IsEmpty())
|
||||
{
|
||||
if (InoutSlot.IsEmpty())
|
||||
return false;
|
||||
|
||||
LocalSlot->ID = InoutSlot.ID;
|
||||
LocalSlot->Count = 0;
|
||||
}
|
||||
|
||||
if (LocalSlot->ID == InoutSlot.ID)
|
||||
{
|
||||
return MergeSlotsWithSimilarIds(*LocalSlot, InoutSlot, MaxStackSize, MaxTransferAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bCanReceiveSlot = InoutSlot.Count <= MaxTransferAmount && InoutSlot.Count <= MaxStackSize;
|
||||
if (!bCanReceiveSlot)
|
||||
return false;
|
||||
|
||||
SwapSlots(InoutSlot, *LocalSlot);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FInventoryContent::RegroupSlotsWithSimilarIdsAtIndex(int32 Index, FContentModificationResult& ModificationResult, uint8 MaxStackSize, FInventorySlot* CachedSlotPtr)
|
||||
{
|
||||
FInventorySlot* TargetSlot = CachedSlotPtr ? CachedSlotPtr : GetSlotPtrAtIndex(Index);
|
||||
|
||||
if (!TargetSlot)
|
||||
return;
|
||||
|
||||
if (TargetSlot->IsEmpty())
|
||||
return;
|
||||
|
||||
for (int32 SlotIndex = 0; SlotIndex < Slots.Num() && TargetSlot->Count < MaxStackSize; SlotIndex++)
|
||||
{
|
||||
if (TargetSlot->Count >= MaxStackSize)
|
||||
break;
|
||||
|
||||
if (SlotIndex == Index)
|
||||
continue;
|
||||
|
||||
FInventorySlot& Slot = Slots[SlotIndex];
|
||||
|
||||
if (!Slot.IsEmpty() && Slot.ID == TargetSlot->ID)
|
||||
{
|
||||
bool bMerged = MergeSlotsWithSimilarIds(*TargetSlot, Slot, MaxStackSize);
|
||||
if (bMerged)
|
||||
{
|
||||
ModificationResult.bModifiedSomething = true;
|
||||
if (ModificationResult.ModifiedSlots)
|
||||
ModificationResult.ModifiedSlots->Add(SlotIndex);
|
||||
if (Slot.IsEmpty())
|
||||
ModificationResult.bCreatedEmptySlot = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ModificationResult.bModifiedSomething)
|
||||
if (ModificationResult.ModifiedSlots)
|
||||
ModificationResult.ModifiedSlots->Add(Index);
|
||||
}
|
||||
|
||||
bool FInventoryContent::MergeSlotsWithSimilarIds(FInventorySlot& DestinationSlot, FInventorySlot& SourceSlot, uint8 MaxStackSize, uint8 MaxTransferAmount)
|
||||
{
|
||||
checkf(SourceSlot.ID == DestinationSlot.ID, TEXT("Tried to merge slots with different Ids (%s!=%s)"), *SourceSlot.ID.ToString(), *DestinationSlot.ID.ToString());
|
||||
|
||||
const int32 LocalCount = DestinationSlot.Count;
|
||||
const int32 ReceiveCount = SourceSlot.Count;
|
||||
|
||||
const int32 TotalCount = LocalCount + ReceiveCount;
|
||||
const int32 StackCount = FMath::Min(TotalCount, int32(MaxStackSize));
|
||||
|
||||
const int32 TotalTransferAmount = StackCount - LocalCount;
|
||||
const int32 TransferAmount = FMath::Min(TotalTransferAmount, int32(MaxTransferAmount));
|
||||
|
||||
if (TransferAmount == 0)
|
||||
return false;
|
||||
|
||||
SourceSlot.Count -= TransferAmount;
|
||||
DestinationSlot.Count += TransferAmount;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FInventoryContent::SwapSlots(FInventorySlot& FirstSlot, FInventorySlot& SecondSlot)
|
||||
{
|
||||
Swap(FirstSlot, SecondSlot);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
// Amasson
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "Structures/SlotInventorySystemStructs.h"
|
||||
#include "SlotInventoryComponent.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInventoryCapacityChangedSignature, USlotInventoryComponent*, SlotInventoryComponent, int32, NewCapacity);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInventoryContentChangedSignature, USlotInventoryComponent*, SlotInventoryComponent, const TArray<int32>&, ChangedSlots);
|
||||
|
||||
UCLASS( Blueprintable, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
|
||||
class SLOTBASEDINVENTORYSYSTEM_API USlotInventoryComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
USlotInventoryComponent();
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FOnInventoryCapacityChangedSignature OnInventoryCapacityChanged;
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FOnInventoryContentChangedSignature OnInventoryContentChanged;
|
||||
|
||||
|
||||
/** Content Management */
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content")
|
||||
const FInventoryContent& GetContent() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Capacity")
|
||||
int32 GetContentCapacity() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Capacity")
|
||||
void SetContentCapacity(int32 NewCapacity);
|
||||
|
||||
|
||||
/** Slot Management */
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Slot")
|
||||
bool GetSlotValueAtIndex(int32 Index, FInventorySlot& SlotValue) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Slot")
|
||||
bool SetSlotValueAtIndex(int32 Index, const FInventorySlot& NewSlotValue);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Slot|Count")
|
||||
bool IsEmptySlotAtIndex(int32 Index) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Slot|Count")
|
||||
bool ClearSlotAtIndex(int32 Index);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Slot|Count")
|
||||
int32 GetEmptySlotCounts() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Slot|Count")
|
||||
bool ContainsOnlyEmptySlots() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Slot|Count")
|
||||
void ModifySlotCountAtIndex(int32 Index, int32 ModifyAmount, bool bAllOrNothing, int32& Overflow);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Slot|Count")
|
||||
virtual uint8 GetMaxStackSizeForID(const FName& ID) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Slot|Count")
|
||||
void GetMaxStackSizeForIds(const TSet<FName>& Ids, TMap<FName, uint8>& MaxStackSizes) const;
|
||||
|
||||
|
||||
/** Content Management */
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Count")
|
||||
int32 GetContentIdCount(FName Id) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Modify")
|
||||
bool ModifyContentWithOverflow(const TMap<FName, int32>& IdsAndCounts, TMap<FName, int32>& Overflows);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Modify")
|
||||
bool TryModifyContentWithoutOverflow(const TMap<FName, int32>& IdsAndCounts);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Action")
|
||||
bool DropSlotTowardOtherInventoryAtIndex(int32 SourceIndex, USlotInventoryComponent* Destination, int32 DestinationIndex, uint8 MaxAmount = 255);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Action")
|
||||
bool DropSlotTowardOtherInventory(int32 SourceIndex, USlotInventoryComponent* Destination);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Content|Action")
|
||||
void RegroupSlotAtIndexWithSimilarIds(int32 Index);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/** Content Management */
|
||||
|
||||
const TMap<FName, uint8> GetMaxStackSizesFromIds(const TMap<FName, int32>& IdsAndCounts) const;
|
||||
|
||||
|
||||
/** Slot Updating */
|
||||
|
||||
virtual void BroadcastContentUpdate();
|
||||
|
||||
void MarkDirtySlot(int32 SlotIndex);
|
||||
|
||||
void MarkSlotsHaveBeenModified();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* The purpose of the tick function is to trigger an update broadcast only once.
|
||||
* We can use mark modified content multiple times in a same tick but they will
|
||||
* be cached and only broadcast in the next tick all at once.
|
||||
*/
|
||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
SetComponentTickEnabled(false);
|
||||
BroadcastContentUpdate();
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "Content", meta = (AllowPrivateAccess = true))
|
||||
FInventoryContent Content;
|
||||
|
||||
TSet<int32> DirtySlots;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
// Amasson
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/SlotInventoryComponent.h"
|
||||
#include "SlotInventoryComponent_Networked.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS( Blueprintable, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
|
||||
class SLOTBASEDINVENTORYSYSTEM_API USlotInventoryComponent_Networked : public USlotInventoryComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
USlotInventoryComponent_Networked();
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
|
||||
|
||||
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "ClientRequest|Update")
|
||||
void Server_BroadcastFullInventory(bool bOwnerOnly = true);
|
||||
|
||||
|
||||
/** Client Request */
|
||||
|
||||
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "ClientRequest|Content|Capacity")
|
||||
void Server_RequestSetContentCapacity(int32 NewCapacity);
|
||||
|
||||
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "ClientRequest|Content|Slot")
|
||||
void Server_RequestSetSlotValueAtIndex(int32 Index, const FInventorySlot& NewSlotValue);
|
||||
|
||||
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "ClientRequest|Content|Slot")
|
||||
void Server_RequestClearSlotAtIndex(int32 Index);
|
||||
|
||||
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "ClientRequest|Action|Drop")
|
||||
void Server_RequestDropSlotTowardOtherInventoryAtIndex(int32 SourceIndex, USlotInventoryComponent* DestinationInventory, int32 DestinationIndex, uint8 MaxAmount = 255);
|
||||
|
||||
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "ClientRequest|Action|Drop")
|
||||
void Server_RequestDropSlotTowardOtherInventory(int32 SourceIndex, USlotInventoryComponent* DestinationInventory);
|
||||
|
||||
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "ClientRequest|Action|Drop")
|
||||
void Server_RequestDropSlotFromOtherInventoryAtIndex(int32 DestinationIndex, USlotInventoryComponent* SourceInventory, int32 SourceIndex, uint8 MaxAmount = 255);
|
||||
|
||||
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "ClientRequest|Action|Drop")
|
||||
void Server_RequestDropSlotFromOtherInventory(USlotInventoryComponent* SourceInventory, int32 SourceIndex);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "ClientRequest|Action|Drop")
|
||||
static void DropInventorySlotFromSourceToDestinationAtIndex(USlotInventoryComponent_Networked* SourceInventory, int32 SourceIndex, USlotInventoryComponent_Networked* DestinationInventory, int32 DestinationIndex, uint8 MaxAmount = 255);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "ClientRequest|Action|Drop")
|
||||
static void DropInventorySlotFromSourceToDestination(USlotInventoryComponent_Networked* SourceInventory, int32 SourceIndex, USlotInventoryComponent_Networked* DestinationInventory);
|
||||
|
||||
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "ClientRequest|Action")
|
||||
void Server_RequestRegroupSlotAtIndexWithSimilarIds(int32 Index);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
/** Slot Update */
|
||||
|
||||
UFUNCTION(NetMulticast, Reliable)
|
||||
void NetMulticast_UpdateSlotsValues(const TArray<int32>& Indices, const TArray<FInventorySlot>& Values);
|
||||
|
||||
UFUNCTION(Client, Reliable)
|
||||
void Client_UpdateSlotsValues(const TArray<int32>& Indices, const TArray<FInventorySlot>& Values);
|
||||
|
||||
void ReceievedUpdateSlotsValues(const TArray<int32>& Indices, const TArray<FInventorySlot>& Values);
|
||||
|
||||
|
||||
/** Capacity Update */
|
||||
|
||||
UFUNCTION()
|
||||
void OnCapacityChanged(USlotInventoryComponent* SlotInventoryComponent, int32 NewCapacity);
|
||||
|
||||
UFUNCTION(NetMulticast, Reliable)
|
||||
void NetMulticast_UpdateCapacity(int32 NewCapacity);
|
||||
|
||||
|
||||
/** Content Update */
|
||||
|
||||
virtual void BroadcastContentUpdate() override;
|
||||
|
||||
void BroadcastModifiedSlotsToClients();
|
||||
|
||||
bool bHasAuthority;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
class FSlotBasedInventorySystemModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
// Amasson
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "Structures/SlotInventorySystemStructs.h"
|
||||
#include "SlotInventoryBlueprintLibrary.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class SLOTBASEDINVENTORYSYSTEM_API USlotInventoryBlueprintLibrary : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
/** Inventory Content */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SlotInventory|Content")
|
||||
static bool IsValidIndex(const FInventoryContent& Content, int32 Index);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SlotInventory|Slot")
|
||||
static bool IsEmptySlot(const FInventorySlot& Slot);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
// Amasson
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/DataTable.h"
|
||||
#include "SlotInventorySystemStructs.generated.h"
|
||||
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FInventorySlot
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame)
|
||||
FName ID;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame)
|
||||
uint8 Count = 0;
|
||||
|
||||
|
||||
bool IsEmpty() const;
|
||||
void Reset();
|
||||
void ModifyCountWithOverflow(int32 ModifyAmount, int32& Overflow, uint8 MaxStackSize = 255);
|
||||
bool TryModifyCountByExact(int32 ModifyAmount, uint8 MaxStackSize = 255);
|
||||
bool AddIdAndCount(const FName& SlotId, int32 ModifyAmount, int32& Overflow, uint8 MaxStackSize = 255);
|
||||
|
||||
};
|
||||
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct SLOTBASEDINVENTORYSYSTEM_API FInventoryContent
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, SaveGame)
|
||||
TArray<FInventorySlot> Slots;
|
||||
|
||||
|
||||
bool IsValidIndex(int32 Index) const;
|
||||
|
||||
FInventorySlot* GetSlotPtrAtIndex(int32 Index);
|
||||
const FInventorySlot* GetSlotConstPtrAtIndex(int32 Index) const;
|
||||
|
||||
struct FContentModificationResult
|
||||
{
|
||||
bool bModifiedSomething;
|
||||
bool bCreatedEmptySlot;
|
||||
TSet<int32>* ModifiedSlots;
|
||||
TMap<FName, int32>* Overflows;
|
||||
|
||||
FContentModificationResult(TSet<int32>* InModifiedSlots, TMap<FName, int32>* Overflows);
|
||||
};
|
||||
|
||||
void ModifyContentWithValues(const TMap<FName, int32>& IdsAndCounts, const TMap<FName, uint8>& MaxStackSizes, FContentModificationResult& ModificationResult);
|
||||
|
||||
void ReceiveSlotOverflow(const FName& SlotId, int32& InoutOverflow, uint8 MaxStackSize, bool bTargetEmptySlots, FContentModificationResult& ModificationResult);
|
||||
bool ReceiveSlotAtIndex(FInventorySlot& InoutSlot, int32 Index, uint8 MaxStackSize = 255, uint8 MaxTransferAmount = 255);
|
||||
|
||||
void RegroupSlotsWithSimilarIdsAtIndex(int32 Index, FContentModificationResult& ModificationResult, uint8 MaxStackSize = 255, FInventorySlot* CachedSlotPtr = nullptr);
|
||||
|
||||
static bool MergeSlotsWithSimilarIds(FInventorySlot& DestinationSlot, FInventorySlot& SourceSlot, uint8 MaxStackSize = 255, uint8 MaxTransferAmount = 255);
|
||||
|
||||
static void SwapSlots(FInventorySlot& FirstSlot, FInventorySlot& SecondSlot);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class SlotBasedInventorySystem : ModuleRules
|
||||
{
|
||||
public SlotBasedInventorySystem(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicIncludePaths.AddRange(
|
||||
new string[] {
|
||||
// ... add public include paths required here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PrivateIncludePaths.AddRange(
|
||||
new string[] {
|
||||
// ... add other private include paths required here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
// ... add other public dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
// ... add private dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
DynamicallyLoadedModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
// ... add any modules that your module loads dynamically here ...
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user