// #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(OutCollection)) { const TArray& 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()) { ItemFilterObjects.AddUnique(InFilterObject); } } void UItemStackContainer::RemoveFilterObject(UObject* InFilterObject) { if (InFilterObject && InFilterObject->Implements()) { 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 TempItemInfo = TempItemData ? TOptional(TempItemData->GetItemInfo()) : TOptional(); // 交换数据 if (TOptional TempTargetItemInfo = TargetItemData ? TOptional(TargetItemData->GetItemInfo()) : TOptional(); 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 TempItemInfo = TempItemData ? TOptional(TempItemData->GetItemInfo()) : TOptional(); if (TOptional TempTargetItemInfo = TargetItemData ? TOptional(TargetItemData->GetItemInfo()) : TOptional(); 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 UItemStackContainer::GetItemInfoArrayFromInventorySystem() { TArray 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()) { 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(this); } ItemDataRef->SetItemInfo(InInfo); } void UItemStackContainer::SyncItemInfoToItemDataArray(const TArray& InItemInfos) { if (InventorySystemComponent.IsValid() && CollectionToTrackTag.IsValid()) { // 获取集合,如果是slotted collection则根据slot来赋值 if (const UGIS_ItemSlotCollection* SlotCollection = Cast(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(Object)) { OnItemSelectionChanged.Broadcast(SelectedItemData,true); return; } OnItemSelectionChanged.Broadcast(nullptr,false); } void UItemStackContainer::HandleItemHoveredChanged(UObject* Object, bool bIsHovered) const { if (UItemData* HoveredItemData = Cast(Object)) { OnItemHoveredChanged.Broadcast(HoveredItemData,bIsHovered); } } void UItemStackContainer::HandleItemClicked(UObject* Object) const { if (UItemData* ClickedItemData = Cast(Object)) { OnItemClicked.Broadcast(ClickedItemData); } } void UItemStackContainer::HandleListViewEntryWidgetGenerated(UUserWidget& UserWidget) const { OnItemEntryGenerated.Broadcast(&UserWidget); } void UItemStackContainer::HandleItemDoubleClicked(UObject* Object) const { if (UItemData* ClickedItemData = Cast(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(); } } }