第一次提交

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,493 @@
//
#include "UI/ItemStacks/ItemStackContainer.h"
#include "CommonTabListWidgetBase.h"
#include "GIS_InventoryFunctionLibrary.h"
#include "GIS_InventorySystemComponent.h"
#include "GIS_ItemCollection.h"
#include "GIS_ItemSlotCollection.h"
#include "ItemFilterInterface.h"
#include "Async/GIS_AsyncAction_WaitInventorySystem.h"
#include "Components/ListView.h"
void UItemStackContainer::SetOwningActor_Implementation(AActor* NewOwningActor)
{
OwningActor = NewOwningActor;
}
void UItemStackContainer::OnDeactivated_Implementation()
{
IGUIS_UserWidgetInterface::OnDeactivated_Implementation();
}
void UItemStackContainer::HandleTabSelected(const FName TabId)
{
ApplyFilter(TabId);
}
void UItemStackContainer::HandleInventorySystemInitialized()
{
WaitInventorySystem = nullptr;
if (OwningActor.IsValid())
{
InventorySystemComponent = UGIS_InventorySystemComponent::GetInventorySystemComponent(OwningActor.Get());
if (InventorySystemComponent.IsValid())
{
// 订阅库存系统的消息
InventorySystemComponent.Get()->OnInventoryStackUpdate.AddDynamic(this,&UItemStackContainer::HandleInventoryStackChanged);
}
if (FilterTabsReference)
{
FilterTabsReference.Get()->OnTabSelected.AddDynamic(this,&UItemStackContainer::HandleTabSelected);
}
// 创建默认的item data槽位
CreateDefaultItemDataSlots();
// 同步数据
SyncAll();
}
}
void UItemStackContainer::CreateDefaultItemDataSlots()
{
if (!InventorySystemComponent.IsValid()) return;
UGIS_ItemCollection* OutCollection;
// 从库存系统中获取集合并添加到item data中
if (InventorySystemComponent->FindTypedCollectionByTag(CollectionToTrackTag,UGIS_ItemSlotCollection::StaticClass(),OutCollection))
{
if (UGIS_ItemSlotCollection* SlotCollection = Cast<UGIS_ItemSlotCollection>(OutCollection))
{
const TArray<FGIS_ItemSlotDefinition>& Definitions = SlotCollection->GetMyDefinition()->GetSlotDefinitions();
for (int i = 0; i < Definitions.Num(); ++i)
{
SetOrAddItemInfoToItemDataArray(FGIS_ItemInfo(),i);
}
for (int i = 0; i < ItemDataArray.Num(); ++i)
{
ItemDataArray[i]->SetItemSlotDefinition(Definitions[i]);
}
return;
}
}
// 如果没有找到slot collection则创建默认数量的item data槽位
if (bCreateDefaultItemDataSlots)
{
for (int i = 0; i < DefaultItemDataSlotCount; ++i)
{
SetOrAddItemInfoToItemDataArray(FGIS_ItemInfo(),i);
}
}
}
void UItemStackContainer::OnActivated_Implementation()
{
// 注册list view events
RegisterListViewEvents();
OwningActor = Execute_GetOwningActor(this);
if (OwningActor.IsValid())
{
WaitInventorySystem = UGIS_AsyncAction_WaitInventorySystemInitialized::WaitInventorySystemInitialized(this,OwningActor.Get());
if (WaitInventorySystem)
{
WaitInventorySystem->OnCompleted.AddDynamic(this,&UItemStackContainer::HandleInventorySystemInitialized);
}
}
}
AActor* UItemStackContainer::GetOwningActor_Implementation()
{
if (!OwningActor.IsValid())
{
if (GetOwningPlayerPawn())
{
OwningActor = GetOwningPlayerPawn();
}
else
{
OwningActor = GetOwningPlayer();
}
}
return OwningActor.Get();
}
void UItemStackContainer::AddFilterObject(UObject* InFilterObject)
{
if (InFilterObject && InFilterObject->Implements<UItemFilterInterface>())
{
ItemFilterObjects.AddUnique(InFilterObject);
}
}
void UItemStackContainer::RemoveFilterObject(UObject* InFilterObject)
{
if (InFilterObject && InFilterObject->Implements<UItemFilterInterface>())
{
ItemFilterObjects.Remove(InFilterObject);
}
}
void UItemStackContainer::SetSelectedIndexForNewItem(const int32 NewSelectedIndex)
{
SelectedIndexForNewItem = NewSelectedIndex;
}
bool UItemStackContainer::SwapItemDataSlots(const int32 IndexA, const int32 IndexB)
{
if (!CanMoveItem(IndexA,this,IndexB)) return false;
if (ItemDataArray.IsValidIndex(IndexA) && ItemDataArray.IsValidIndex(IndexB))
{
// 缓存A的数据
const UItemData* TempItemData = ItemDataArray[IndexA];
const UItemData* TargetItemData = ItemDataArray[IndexB];
// 缓存其中的数据
TOptional<FGIS_ItemInfo> TempItemInfo = TempItemData ? TOptional<FGIS_ItemInfo>(TempItemData->GetItemInfo()) : TOptional<FGIS_ItemInfo>();
// 交换数据
if (TOptional<FGIS_ItemInfo> TempTargetItemInfo = TargetItemData ? TOptional<FGIS_ItemInfo>(TargetItemData->GetItemInfo()) : TOptional<FGIS_ItemInfo>(); TempTargetItemInfo.IsSet())
{
AssignItemInfoToItemData(TempTargetItemInfo.GetValue(), IndexA);
}
if (TempItemInfo.IsSet())
{
AssignItemInfoToItemData(TempItemInfo.GetValue(), IndexB);
}
LastDropIndex = IndexB;
// 同步list view
SyncItemDataToListView();
return true;
}
return false;
}
bool UItemStackContainer::SwapItemDataToOtherContainer(const int32 SourceIndex, UItemStackContainer* TargetContainer,
const int32 TargetIndex)
{
if (!TargetContainer) return false;
if (!CanMoveItem(SourceIndex,TargetContainer,TargetIndex)) return false;
if (ItemDataArray.IsValidIndex(SourceIndex) && TargetContainer->GetItemDataArray().IsValidIndex(TargetIndex))
{
// 缓存A的数据
const UItemData* TempItemData = ItemDataArray[SourceIndex];
const UItemData* TargetItemData = TargetContainer->GetItemDataArray()[TargetIndex];
// 缓存其中的数据
TOptional<FGIS_ItemInfo> TempItemInfo = TempItemData ? TOptional<FGIS_ItemInfo>(TempItemData->GetItemInfo()) : TOptional<FGIS_ItemInfo>();
if (TOptional<FGIS_ItemInfo> TempTargetItemInfo = TargetItemData ? TOptional<FGIS_ItemInfo>(TargetItemData->GetItemInfo()) : TOptional<FGIS_ItemInfo>(); TempTargetItemInfo.IsSet())
{
AssignItemInfoToItemData(TempTargetItemInfo.GetValue(), SourceIndex);
}
if (TempItemInfo.IsSet())
{
TargetContainer->AssignItemInfoToItemData(TempItemInfo.GetValue(), TargetIndex);
}
TargetContainer->LastDropIndex = TargetIndex;
// 同步list view
SyncItemDataToListView();
TargetContainer->SyncItemDataToListView();
return true;
}
return false;
}
bool UItemStackContainer::CanMoveItem(const int32 IndexA,UItemStackContainer* TargetContainer,const int32 IndexB)
{
return true;
}
int32 UItemStackContainer::FindItemSlotIndex(const UItemData* InItemData) const
{
if (!InItemData) return INDEX_NONE;
return ItemDataArray.IndexOfByKey(InItemData);
}
void UItemStackContainer::AssignItemInfoToItemData(const FGIS_ItemInfo& InInfo, const int32 SlotIndex)
{
if (ItemDataArray.IsValidIndex(SlotIndex))
{
if (UItemData* ItemData = ItemDataArray[SlotIndex])
{
ItemData->SetItemInfo(InInfo);
}
}
}
void UItemStackContainer::UnassignItemInfoToItemData(const FGIS_ItemInfo& InInfo)
{
if (const int32 Index = FindItemIndexFromDataByStackID(InInfo.StackId); Index != INDEX_NONE)
{
const FGIS_ItemInfo EmptyInfo;
AssignItemInfoToItemData(EmptyInfo, Index);
}
}
int32 UItemStackContainer::FindItemIndexFromDataByStackID(const FGuid& StackID) const
{
for (int32 Index = 0; Index < ItemDataArray.Num(); ++Index)
{
if (const UItemData* ItemData = ItemDataArray[Index])
{
if (ItemData->GetItemInfo().StackId == StackID)
{
return Index;
}
}
}
return INDEX_NONE;
}
TArray<FGIS_ItemInfo> UItemStackContainer::GetItemInfoArrayFromInventorySystem()
{
TArray<FGIS_ItemInfo> LocalItemInfos;
if (InventorySystemComponent.IsValid())
{
if (CollectionToTrackTag.IsValid())
{
if (const UGIS_ItemCollection* ItemCollection = InventorySystemComponent.Get()->GetCollectionByTag(CollectionToTrackTag))
{
LocalItemInfos = ItemCollection->GetAllItemInfos();
}
}
}
if (LocalItemInfos.IsEmpty()) return LocalItemInfos;
// 通过配置的name和query 过滤
if (ItemFilterMap.Num() > 0 && ItemFilterName.IsValid())
{
if (const FGameplayTagQuery* Query = ItemFilterMap.Find(ItemFilterName))
{
LocalItemInfos = UGIS_InventoryFunctionLibrary::FilterItemInfosByTagQuery(LocalItemInfos,*Query);
}
}
// 通过Object过滤
if (ItemFilterObjects.Num() > 0)
{
for (UObject* FilterObject : ItemFilterObjects)
{
if (FilterObject && FilterObject->Implements<UItemFilterInterface>())
{
LocalItemInfos = IItemFilterInterface::Execute_FilterItemInfo(FilterObject,LocalItemInfos);
}
}
}
return LocalItemInfos;
}
void UItemStackContainer::ResetItemDataArray()
{
for (UItemData* ItemData : ItemDataArray)
{
ItemData->Reset();
}
}
void UItemStackContainer::SetOrAddItemInfoToItemDataArray(const FGIS_ItemInfo& InInfo, const int32 SlotIndex)
{
if (SlotIndex < 0)
{
return;
}
// 确保数组大小足够
if (ItemDataArray.Num() <= SlotIndex)
{
ItemDataArray.SetNum(SlotIndex + 1);
}
// 确保该槽位有对象
UItemData* ItemDataRef = ItemDataArray[SlotIndex];
if (!ItemDataRef)
{
ItemDataRef = NewObject<UItemData>(this);
}
ItemDataRef->SetItemInfo(InInfo);
}
void UItemStackContainer::SyncItemInfoToItemDataArray(const TArray<FGIS_ItemInfo>& InItemInfos)
{
if (InventorySystemComponent.IsValid() && CollectionToTrackTag.IsValid())
{
// 获取集合,如果是slotted collection则根据slot来赋值
if (const UGIS_ItemSlotCollection* SlotCollection = Cast<UGIS_ItemSlotCollection>(InventorySystemComponent->GetCollectionByTag(CollectionToTrackTag)))
{
for (int i = 0; i < InItemInfos.Num(); ++i)
{
const FGIS_ItemInfo& Info = InItemInfos[i];
const int32 SlotIndex = SlotCollection->GetItemSlotIndex(Info.Item);
SetOrAddItemInfoToItemDataArray(Info, SlotIndex == INDEX_NONE ? i : SlotIndex);
}
}
else
{
// 如果是普通的集合,则直接按顺序赋值
for (int i = 0; i < InItemInfos.Num(); ++i)
{
SetOrAddItemInfoToItemDataArray(InItemInfos[i], i);
}
}
}
}
void UItemStackContainer::SyncItemDataToListView()
{
if (ItemListView == nullptr) return;
ItemListView->ClearSelection();
ItemListView->ClearListItems();
ItemListView->SetListItems(ItemDataArray);
ItemListView->RegenerateAllEntries();
// 恢复上次拖拽的选中状态
if (ItemDataArray.IsValidIndex(LastDropIndex) && LastDropIndex != INDEX_NONE)
{
ItemListView->SetSelectedItem(ItemDataArray[LastDropIndex]);
LastDropIndex = INDEX_NONE;
} else
{
// 默认选中第一个
if (ItemDataArray.IsValidIndex(0) && ItemDataArray[0]->IsValidItem())
{
ItemListView->SetSelectedItem(ItemDataArray[0]);
}
}
}
int32 UItemStackContainer::FindSuitableItemDataSlotForNewItem()
{
if (SelectedIndexForNewItem == INDEX_NONE)
{
for (int i = 0; i < ItemDataArray.Num(); ++i)
{
if (const UItemData* ItemData = ItemDataArray[i])
{
if (!ItemData->IsValidItem())
{
return i;
}
}
}
return ItemDataArray.Num();
}
const int32 ReturnIndex = SelectedIndexForNewItem;
SelectedIndexForNewItem = INDEX_NONE;
return ReturnIndex;
}
void UItemStackContainer::SyncAll()
{
ResetItemDataArray();
SyncItemInfoToItemDataArray(GetItemInfoArrayFromInventorySystem());
SyncItemDataToListView();
}
void UItemStackContainer::ApplyFilter(const FName& InFilterName)
{
if (InFilterName.IsNone()) return;
if (ItemFilterMap.Contains(InFilterName))
{
ItemFilterName = InFilterName;
SyncAll();
}
}
void UItemStackContainer::HandleItemSelectionChanged(UObject* Object) const
{
if (UItemData* SelectedItemData = Cast<UItemData>(Object))
{
OnItemSelectionChanged.Broadcast(SelectedItemData,true);
return;
}
OnItemSelectionChanged.Broadcast(nullptr,false);
}
void UItemStackContainer::HandleItemHoveredChanged(UObject* Object, bool bIsHovered) const
{
if (UItemData* HoveredItemData = Cast<UItemData>(Object))
{
OnItemHoveredChanged.Broadcast(HoveredItemData,bIsHovered);
}
}
void UItemStackContainer::HandleItemClicked(UObject* Object) const
{
if (UItemData* ClickedItemData = Cast<UItemData>(Object))
{
OnItemClicked.Broadcast(ClickedItemData);
}
}
void UItemStackContainer::HandleListViewEntryWidgetGenerated(UUserWidget& UserWidget) const
{
OnItemEntryGenerated.Broadcast(&UserWidget);
}
void UItemStackContainer::HandleItemDoubleClicked(UObject* Object) const
{
if (UItemData* ClickedItemData = Cast<UItemData>(Object))
{
OnItemDoubleClicked.Broadcast(ClickedItemData);
}
}
void UItemStackContainer::RegisterListViewEvents()
{
if (ItemListView)
{
// 注册事件
ItemSelectionChangedHandle = ItemListView->OnItemSelectionChanged().AddUObject(this, &UItemStackContainer::HandleItemSelectionChanged);
ItemHoveredChangedHandle = ItemListView->OnItemIsHoveredChanged().AddUObject(this, &UItemStackContainer::HandleItemHoveredChanged);
ItemClickedHandle = ItemListView->OnItemClicked().AddUObject(this, &UItemStackContainer::HandleItemClicked);
ListViewEntryWidgetGeneratedHandle = ItemListView->OnEntryWidgetGenerated().AddUObject(this, &UItemStackContainer::HandleListViewEntryWidgetGenerated);
ItemDoubleClickedHandle = ItemListView->OnItemDoubleClicked().AddUObject(this, &UItemStackContainer::HandleItemDoubleClicked);
}
}
void UItemStackContainer::UnregisterListViewEvents() const
{
if (ItemListView)
{
// 注销事件
ItemListView->OnItemSelectionChanged().Remove(ItemSelectionChangedHandle);
ItemListView->OnItemIsHoveredChanged().Remove(ItemHoveredChangedHandle);
ItemListView->OnItemClicked().Remove(ItemClickedHandle);
ItemListView->OnEntryWidgetGenerated().Remove(ListViewEntryWidgetGeneratedHandle);
ItemListView->OnItemDoubleClicked().Remove(ItemDoubleClickedHandle);
}
}
void UItemStackContainer::HandleInventoryStackChanged(const FGIS_InventoryStackUpdateMessage& Message)
{
if (const UGIS_InventorySystemComponent* Inventory = Message.Inventory)
{
// 仅处理关联的库存系统组件的消息
if (!InventorySystemComponent.IsValid() && Inventory != InventorySystemComponent.Get()) return;
// 获取集合
if (UGIS_ItemCollection* ItemCollection = Inventory->GetCollectionById(Message.CollectionId))
{
// 仅处理配置的集合tag的消息
if (ItemCollection->GetCollectionTag() != CollectionToTrackTag) return;
FGIS_ItemInfo ChangedItemInfo = FGIS_ItemInfo(Message.Instance,Message.NewCount,ItemCollection,Message.StackId);
switch (Message.ChangeType) {
case EGIS_ItemStackChangeType::WasAdded:
// 添加
{
const int32 SlotIndex = FindSuitableItemDataSlotForNewItem();
SetOrAddItemInfoToItemDataArray(ChangedItemInfo, SlotIndex);
}
break;
case EGIS_ItemStackChangeType::WasRemoved:
// 移除
{
ChangedItemInfo.Amount = Message.NewCount - Message.Delta;
UnassignItemInfoToItemData(ChangedItemInfo);
}
break;
case EGIS_ItemStackChangeType::Changed:
// 修改
{
if (const int32 ChangedIndex = FindItemIndexFromDataByStackID(Message.StackId); ChangedIndex != INDEX_NONE)
{
SetOrAddItemInfoToItemDataArray(ChangedItemInfo, ChangedIndex);
}
}
break;
}
SyncItemDataToListView();
}
}
}