diff --git a/Config/DefaultMounteaInventoryEquipment.ini b/Config/DefaultMounteaInventoryEquipment.ini new file mode 100644 index 00000000..3f10dec9 --- /dev/null +++ b/Config/DefaultMounteaInventoryEquipment.ini @@ -0,0 +1,8 @@ +[CoreRedirects] ++FunctionRedirects=(OldName="/Script/MounteaInventoryEquipment.IMounteaInventoryInterface.GetInventoryWBPClass",NewName="/Script/MounteaInventoryEquipment.IMounteaInventoryInterface.GetInventoryUIClass") ++FunctionRedirects=(OldName="/Script/MounteaInventoryEquipment.IMounteaInventoryInterface.SetInventoryWBPClass",NewName="/Script/MounteaInventoryEquipment.IMounteaInventoryInterface.SetInventoryUIClass") ++FunctionRedirects=(OldName="/Script/MounteaInventoryEquipment.IMounteaInventoryInterface.SetInventoryWBP",NewName="/Script/MounteaInventoryEquipment.IMounteaInventoryInterface.SetInventoryUI") ++FunctionRedirects=(OldName="/Script/MounteaInventoryEquipment.IMounteaInventoryInterface.GetInventoryWBP",NewName="/Script/MounteaInventoryEquipment.IMounteaInventoryInterface.GetInventoryUI") ++ClassRedirects=(OldName="/Script/MounteaInventoryEquipment.ContentThemeConfig",NewName="/Script/MounteaInventoryEquipment.ContentTheme") ++ClassRedirects=(OldName="/Script/MounteaInventoryEquipment.CategoryThemeConfig",NewName="/Script/MounteaInventoryEquipment.CategoryTheme") ++PropertyRedirects=(OldName="/Script/MounteaInventoryEquipment.CategoryThemeData.Category",NewName="/Script/MounteaInventoryEquipment.CategoryThemeData.CategoryTheme") \ No newline at end of file diff --git a/Config/Tags/MounteaInventoryEquipmentTags.ini b/Config/Tags/MounteaInventoryEquipmentTags.ini index 6f57dd67..2e261902 100644 --- a/Config/Tags/MounteaInventoryEquipmentTags.ini +++ b/Config/Tags/MounteaInventoryEquipmentTags.ini @@ -22,6 +22,8 @@ GameplayTagList=(Tag="Mountea_Inventory.Functions.Action.ActionSelected",DevComm GameplayTagList=(Tag="Mountea_Inventory.Functions.Action.HideContainer",DevComment="") GameplayTagList=(Tag="Mountea_Inventory.Functions.Action.ShowContainer",DevComment="") GameplayTagList=(Tag="Mountea_Inventory.Functions.Category.OnSelected",DevComment="") +GameplayTagList=(Tag="Mountea_Inventory.Functions.Inventory",DevComment="") +GameplayTagList=(Tag="Mountea_Inventory.Functions.Inventory.GetEquipmentRef",DevComment="") GameplayTagList=(Tag="Mountea_Inventory.Functions.Slot.OnDragEnter",DevComment="") GameplayTagList=(Tag="Mountea_Inventory.Functions.Slot.OnDragFinished",DevComment="") GameplayTagList=(Tag="Mountea_Inventory.Functions.Slot.OnDragLeave",DevComment="") diff --git a/Content/Blueprints/Actions/BPA_Equip.uasset b/Content/Blueprints/Actions/BPA_Equip.uasset index 8424c556..e6745b0f 100644 Binary files a/Content/Blueprints/Actions/BPA_Equip.uasset and b/Content/Blueprints/Actions/BPA_Equip.uasset differ diff --git a/Content/Blueprints/Categories/Weapon.uasset b/Content/Blueprints/Categories/Weapon.uasset new file mode 100644 index 00000000..0f7ca866 Binary files /dev/null and b/Content/Blueprints/Categories/Weapon.uasset differ diff --git a/Content/Blueprints/Components/BPC_MounteaEquipment.uasset b/Content/Blueprints/Components/BPC_MounteaEquipment.uasset index 648215f2..508a05cc 100644 Binary files a/Content/Blueprints/Components/BPC_MounteaEquipment.uasset and b/Content/Blueprints/Components/BPC_MounteaEquipment.uasset differ diff --git a/Content/Blueprints/Components/BPC_MounteaInventory.uasset b/Content/Blueprints/Components/BPC_MounteaInventory.uasset index 8fd7b27c..1944d4fc 100644 Binary files a/Content/Blueprints/Components/BPC_MounteaInventory.uasset and b/Content/Blueprints/Components/BPC_MounteaInventory.uasset differ diff --git a/Content/Blueprints/Items/Books/HiddenBible.uasset b/Content/Blueprints/Items/Books/HiddenBible.uasset new file mode 100644 index 00000000..00bbde8f Binary files /dev/null and b/Content/Blueprints/Items/Books/HiddenBible.uasset differ diff --git a/Content/Blueprints/Items/Weapon/Sword.uasset b/Content/Blueprints/Items/Weapon/Sword.uasset new file mode 100644 index 00000000..6e6c121f Binary files /dev/null and b/Content/Blueprints/Items/Weapon/Sword.uasset differ diff --git a/Content/Blueprints/Theme/Example01/BP_Theme01.uasset b/Content/Blueprints/Theme/Example01/BP_Theme01.uasset new file mode 100644 index 00000000..85010e84 Binary files /dev/null and b/Content/Blueprints/Theme/Example01/BP_Theme01.uasset differ diff --git a/Content/Blueprints/Theme/Example01/Theme01.uasset b/Content/Blueprints/Theme/Example01/Theme01.uasset new file mode 100644 index 00000000..4c918c27 Binary files /dev/null and b/Content/Blueprints/Theme/Example01/Theme01.uasset differ diff --git a/Content/Blueprints/Theme/MounteaThemeConfig.uasset b/Content/Blueprints/Theme/MounteaThemeConfig.uasset index 8e43146e..1004b02d 100644 Binary files a/Content/Blueprints/Theme/MounteaThemeConfig.uasset and b/Content/Blueprints/Theme/MounteaThemeConfig.uasset differ diff --git a/Content/Data/EquipmentData/MounteaEquipmentConfigData.uasset b/Content/Data/EquipmentData/MounteaEquipmentConfigData.uasset new file mode 100644 index 00000000..9d600ee5 Binary files /dev/null and b/Content/Data/EquipmentData/MounteaEquipmentConfigData.uasset differ diff --git a/Content/Data/ItemData/DataAssets/SwordData.uasset b/Content/Data/ItemData/DataAssets/SwordData.uasset new file mode 100644 index 00000000..6fee22f9 Binary files /dev/null and b/Content/Data/ItemData/DataAssets/SwordData.uasset differ diff --git a/Content/Data/ItemData/DataTables/Descriptions/DT_DefaultItemDescriptionsTable.uasset b/Content/Data/ItemData/DataTables/Descriptions/DT_DefaultItemDescriptionsTable.uasset index a1e95a22..b9978f12 100644 Binary files a/Content/Data/ItemData/DataTables/Descriptions/DT_DefaultItemDescriptionsTable.uasset and b/Content/Data/ItemData/DataTables/Descriptions/DT_DefaultItemDescriptionsTable.uasset differ diff --git a/Content/Data/ItemData/DataTables/Items/DT_DefaultItemsTable.uasset b/Content/Data/ItemData/DataTables/Items/DT_DefaultItemsTable.uasset index fb9fc217..c9867be2 100644 Binary files a/Content/Data/ItemData/DataTables/Items/DT_DefaultItemsTable.uasset and b/Content/Data/ItemData/DataTables/Items/DT_DefaultItemsTable.uasset differ diff --git a/Content/Materials/DropShadow/MI_ExampleCategory.uasset b/Content/Materials/DropShadow/MI_ExampleCategory.uasset new file mode 100644 index 00000000..c7ab6480 Binary files /dev/null and b/Content/Materials/DropShadow/MI_ExampleCategory.uasset differ diff --git a/Content/Materials/DropShadow/M_CategoryAtlas.uasset b/Content/Materials/DropShadow/M_CategoryAtlas.uasset new file mode 100644 index 00000000..88259779 Binary files /dev/null and b/Content/Materials/DropShadow/M_CategoryAtlas.uasset differ diff --git a/Content/Materials/Functions/MF_BoxBlur.uasset b/Content/Materials/Functions/MF_BoxBlur.uasset new file mode 100644 index 00000000..3ace2b96 Binary files /dev/null and b/Content/Materials/Functions/MF_BoxBlur.uasset differ diff --git a/Content/Textures/Icons/Atlas/T_Icons_Source.uasset b/Content/Textures/Icons/Atlas/T_Icons_Source.uasset new file mode 100644 index 00000000..ec616495 Binary files /dev/null and b/Content/Textures/Icons/Atlas/T_Icons_Source.uasset differ diff --git a/Content/Textures/Icons/Items/T_Weapon_Icon.uasset b/Content/Textures/Icons/Items/T_Weapon_Icon.uasset new file mode 100644 index 00000000..964f962d Binary files /dev/null and b/Content/Textures/Icons/Items/T_Weapon_Icon.uasset differ diff --git a/Content/WBP/Actions/WBP_ItemActionsContainer.uasset b/Content/WBP/Actions/WBP_ItemActionsContainer.uasset index 6f2bbd77..367cdb38 100644 Binary files a/Content/WBP/Actions/WBP_ItemActionsContainer.uasset and b/Content/WBP/Actions/WBP_ItemActionsContainer.uasset differ diff --git a/Content/WBP/Equipment/WBP_Equipment.uasset b/Content/WBP/Equipment/WBP_Equipment.uasset index 60ac03bc..74aecf4d 100644 Binary files a/Content/WBP/Equipment/WBP_Equipment.uasset and b/Content/WBP/Equipment/WBP_Equipment.uasset differ diff --git a/Content/WBP/Example01/Inventory/T_Selection.uasset b/Content/WBP/Example01/Inventory/T_Selection.uasset new file mode 100644 index 00000000..141373f6 Binary files /dev/null and b/Content/WBP/Example01/Inventory/T_Selection.uasset differ diff --git a/Content/WBP/Example01/Inventory/T_SelectionBase.uasset b/Content/WBP/Example01/Inventory/T_SelectionBase.uasset new file mode 100644 index 00000000..cf04d311 Binary files /dev/null and b/Content/WBP/Example01/Inventory/T_SelectionBase.uasset differ diff --git a/Content/WBP/Example01/Inventory/T_SelectionSimple.uasset b/Content/WBP/Example01/Inventory/T_SelectionSimple.uasset new file mode 100644 index 00000000..fba0cfbb Binary files /dev/null and b/Content/WBP/Example01/Inventory/T_SelectionSimple.uasset differ diff --git a/Content/WBP/Example01/Inventory/WBP_Container_Example01.uasset b/Content/WBP/Example01/Inventory/WBP_Container_Example01.uasset new file mode 100644 index 00000000..780ed731 Binary files /dev/null and b/Content/WBP/Example01/Inventory/WBP_Container_Example01.uasset differ diff --git a/Content/WBP/Example01/Inventory/WBP_Inventory_Example01.uasset b/Content/WBP/Example01/Inventory/WBP_Inventory_Example01.uasset new file mode 100644 index 00000000..b8d37944 Binary files /dev/null and b/Content/WBP/Example01/Inventory/WBP_Inventory_Example01.uasset differ diff --git a/Content/WBP/Example01/Inventory/WBP_Selectable_Example01.uasset b/Content/WBP/Example01/Inventory/WBP_Selectable_Example01.uasset new file mode 100644 index 00000000..ed07110b Binary files /dev/null and b/Content/WBP/Example01/Inventory/WBP_Selectable_Example01.uasset differ diff --git a/Content/WBP/Inventory/WBP_Inventory.uasset b/Content/WBP/Inventory/WBP_Inventory.uasset index d9a7e4c5..4f83e255 100644 Binary files a/Content/WBP/Inventory/WBP_Inventory.uasset and b/Content/WBP/Inventory/WBP_Inventory.uasset differ diff --git a/Content/WBP/Item/WBP_InventoryItem.uasset b/Content/WBP/Item/WBP_InventoryItem.uasset index ccc40a2d..ebb87ff3 100644 Binary files a/Content/WBP/Item/WBP_InventoryItem.uasset and b/Content/WBP/Item/WBP_InventoryItem.uasset differ diff --git a/Content/WBP/Slot/WBP_EquipmentSlot.uasset b/Content/WBP/Slot/WBP_EquipmentSlot.uasset index 7785e771..d74330ff 100644 Binary files a/Content/WBP/Slot/WBP_EquipmentSlot.uasset and b/Content/WBP/Slot/WBP_EquipmentSlot.uasset differ diff --git a/MounteaInventoryEquipment.uplugin b/MounteaInventoryEquipment.uplugin index 631db5cd..4b8ce7e9 100644 --- a/MounteaInventoryEquipment.uplugin +++ b/MounteaInventoryEquipment.uplugin @@ -20,8 +20,7 @@ "Name": "MounteaInventoryEquipment", "Type": "Runtime", "LoadingPhase": "PreDefault", - "WhitelistPlatforms": - [ + "WhitelistPlatforms": [ "Linux", "Mac", "Win64" @@ -31,8 +30,7 @@ "Name": "MounteaInventoryEquipmentEditor", "Type": "Editor", "LoadingPhase": "PostEngineInit", - "WhitelistPlatforms": - [ + "WhitelistPlatforms": [ "Linux", "Mac", "Win64" @@ -42,8 +40,17 @@ "Name": "MounteaInventoryEquipmentNotifications", "Type": "Editor", "LoadingPhase": "PostEngineInit", - "WhitelistPlatforms": - [ + "WhitelistPlatforms": [ + "Linux", + "Mac", + "Win64" + ] + }, + { + "Name": "MounteaInventoryEquipmentDeveloper", + "Type": "DeveloperTool", + "LoadingPhase": "Default", + "WhitelistPlatforms": [ "Linux", "Mac", "Win64" diff --git a/Resources/K2NodeIcons/DistinctIcon.png b/Resources/K2NodeIcons/DistinctIcon.png new file mode 100644 index 00000000..582c1c3e Binary files /dev/null and b/Resources/K2NodeIcons/DistinctIcon.png differ diff --git a/Source/MounteaInventoryEquipment/MounteaInventoryEquipment.Build.cs b/Source/MounteaInventoryEquipment/MounteaInventoryEquipment.Build.cs index 89a534b5..0a1aec92 100644 --- a/Source/MounteaInventoryEquipment/MounteaInventoryEquipment.Build.cs +++ b/Source/MounteaInventoryEquipment/MounteaInventoryEquipment.Build.cs @@ -31,7 +31,8 @@ public MounteaInventoryEquipment(ReadOnlyTargetRules Target) : base(Target) "UMG", "Projects", - "GameplayTags" + "GameplayTags", + "CommonUI" // ... add other public dependencies that you statically link with here ... } ); diff --git a/Source/MounteaInventoryEquipment/Private/Components/MounteaEquipmentComponent.cpp b/Source/MounteaInventoryEquipment/Private/Components/MounteaEquipmentComponent.cpp index 276ee185..79eccca8 100644 --- a/Source/MounteaInventoryEquipment/Private/Components/MounteaEquipmentComponent.cpp +++ b/Source/MounteaInventoryEquipment/Private/Components/MounteaEquipmentComponent.cpp @@ -4,6 +4,11 @@ #include "Components/MounteaEquipmentComponent.h" #include "Engine/ActorChannel.h" +#include "Helpers/MounteaInventoryEquipmentBPF.h" +#include "Interfaces/MounteaEquipmentWBPInterface.h" +#include "Net/UnrealNetwork.h" +#include "Settings/MounteaInventoryEquipmentSettings.h" +#include "WBP/MounteaBaseUserWidget.h" UMounteaEquipmentComponent::UMounteaEquipmentComponent() { @@ -19,6 +24,8 @@ void UMounteaEquipmentComponent::BeginPlay() void UMounteaEquipmentComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME(UMounteaEquipmentComponent, EquipmentSlotData); } bool UMounteaEquipmentComponent::ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) @@ -42,6 +49,11 @@ bool UMounteaEquipmentComponent::ReplicateSubobjects(UActorChannel* Channel, FOu return bUpdated; } +AActor* UMounteaEquipmentComponent::GetOwningActor_Implementation() const +{ + return GetOwner(); +} + FString UMounteaEquipmentComponent::FindSlotForItem_Implementation(const UMounteaInventoryItemBase* Item) const { FString SlotID; @@ -61,14 +73,37 @@ FString UMounteaEquipmentComponent::FindSlotForItem_Implementation(const UMounte return SlotID; } +UMounteaEquipmentSlot* UMounteaEquipmentComponent::FindSlotByID_Implementation(const FString& SlotID) const +{ + for (const FMounteaEquipmentSlotData& Itr : EquipmentSlotData) + { + if (Itr.Slot && Itr.Slot->GetSlotID().Equals(SlotID)) return Itr.Slot; + } + + return nullptr; +} + #pragma region EQUIP -bool UMounteaEquipmentComponent::EquipItem_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) +bool UMounteaEquipmentComponent::EquipItem_Implementation(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) { if (!ItemToEquip) return false; - if (GetOwner() && GetOwner()->HasAuthority()) + if (GetOwner() && !GetOwner()->HasAuthority()) { + // Cleanup Slot before populating new, so populated slot can return to Inventory + // Local stuff should be fine, as it will get updates once server response is received + if (const auto TempEquipmentUI = Execute_GetEquipmentUI(this)) + { + if (UMounteaEquipmentSlot* const FoundSlot = UMounteaInventoryEquipmentBPF::FindEquipmentSlot(EquipmentSlotData, SlotID)) + { + FoundSlot->UpdateItem(ItemToEquip); + + TempEquipmentUI->ProcessMounteaWidgetCommand(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::UnequipItemWidget, FoundSlot); + TempEquipmentUI->ProcessMounteaWidgetCommand(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::EquipItemWidget, FoundSlot); + } + } + EquipItem_Server(ItemToEquip, SlotID); } @@ -82,19 +117,24 @@ bool UMounteaEquipmentComponent::EquipItem_Implementation(const UMounteaInventor return false; } -void UMounteaEquipmentComponent::EquipItem_Server_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) +void UMounteaEquipmentComponent::EquipItem_Server_Implementation(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) { if (Execute_CanEquipItem(this, ItemToEquip)) { - OnSlotEquipped.Broadcast(ItemToEquip, SlotID); + if (UMounteaEquipmentSlot* Slot = UMounteaInventoryEquipmentBPF::FindEquipmentSlot(EquipmentSlotData, SlotID)) + { + Slot->UpdateItem(ItemToEquip); + + OnSlotEquipped.Broadcast(ItemToEquip, SlotID); - OnRep_Equipment(); + OnRep_Equipment(); - EquipItem_Multicast(ItemToEquip, SlotID); + EquipItem_Multicast(ItemToEquip, SlotID); + } } } -bool UMounteaEquipmentComponent::EquipItem_Server_Validate(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) +bool UMounteaEquipmentComponent::EquipItem_Server_Validate(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) { return true; } @@ -109,12 +149,18 @@ void UMounteaEquipmentComponent::EquipItem_Multicast_Implementation(const UMount #pragma region UNEQUIP -bool UMounteaEquipmentComponent::UnEquipItem_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) +bool UMounteaEquipmentComponent::UnEquipItem_Implementation(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) { if (!ItemToEquip) return false; - if (GetOwner() && GetOwner()->HasAuthority()) + if (GetOwner() && !GetOwner()->HasAuthority()) { + // Cleanup Slot and return possible slot back to Inventory + if (const auto TempEquipmentUI = Execute_GetEquipmentUI(this)) + { + TempEquipmentUI->ProcessMounteaWidgetCommand(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::UnequipItemWidget, UMounteaInventoryEquipmentBPF::FindEquipmentSlot(EquipmentSlotData, SlotID)); + } + UnEquipItem_Server(ItemToEquip, SlotID); } @@ -128,19 +174,24 @@ bool UMounteaEquipmentComponent::UnEquipItem_Implementation(const UMounteaInvent return false; } -void UMounteaEquipmentComponent::UnEquipItem_Server_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) +void UMounteaEquipmentComponent::UnEquipItem_Server_Implementation(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) { if (Execute_IsItemEquipped(this, ItemToEquip, SlotID)) { - OnSlotUnequipped.Broadcast(ItemToEquip, SlotID); - - OnRep_Equipment(); + if (UMounteaEquipmentSlot* Slot = UMounteaInventoryEquipmentBPF::FindEquipmentSlot(EquipmentSlotData, SlotID)) + { + Slot->UpdateItem(nullptr); + + OnSlotUnequipped.Broadcast(ItemToEquip, SlotID); + + OnRep_Equipment(); - UnEquipItem_Multicast(ItemToEquip, SlotID); + UnEquipItem_Multicast(ItemToEquip, SlotID); + } } } -bool UMounteaEquipmentComponent::UnEquipItem_Server_Validate(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) +bool UMounteaEquipmentComponent::UnEquipItem_Server_Validate(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) { return true; } @@ -154,11 +205,9 @@ void UMounteaEquipmentComponent::UnEquipItem_Multicast_Implementation(const UMou #pragma endregion -bool UMounteaEquipmentComponent::IsItemEquipped_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) +bool UMounteaEquipmentComponent::IsItemEquipped_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) const { return EquipmentSlotData.Contains(FMounteaEquipmentSlotDataCompare(ItemToEquip, SlotID)); - - return true; } TArray UMounteaEquipmentComponent::GetAllSlots_Implementation() const @@ -172,7 +221,25 @@ bool UMounteaEquipmentComponent::CanEquipItem_Implementation(const UMounteaInven const FString SlotID = Execute_FindSlotForItem(this, ItemToEquip); - return !SlotID.IsEmpty(); + if (SlotID.IsEmpty()) return false; + + return !Execute_IsItemEquipped(this, ItemToEquip, SlotID); +} + +UMounteaBaseUserWidget* UMounteaEquipmentComponent::GetEquipmentUI_Implementation() const +{ + return EquipmentUI; +} + +bool UMounteaEquipmentComponent::SetEquipmentUI_Implementation(UMounteaBaseUserWidget* NewUI) +{ + if(NewUI != EquipmentUI) + { + EquipmentUI = NewUI; + return true; + } + + return false; } void UMounteaEquipmentComponent::OnRep_Equipment() diff --git a/Source/MounteaInventoryEquipment/Private/Components/MounteaInventoryComponent.cpp b/Source/MounteaInventoryEquipment/Private/Components/MounteaInventoryComponent.cpp index 4577115b..75f7fcad 100644 --- a/Source/MounteaInventoryEquipment/Private/Components/MounteaInventoryComponent.cpp +++ b/Source/MounteaInventoryEquipment/Private/Components/MounteaInventoryComponent.cpp @@ -12,6 +12,7 @@ #include "Net/UnrealNetwork.h" #include "Settings/MounteaInventoryEquipmentSettings.h" +#include "WBP/MounteaBaseUserWidget.h" #define LOCTEXT_NAMESPACE "MounteaInventoryComponent" @@ -36,6 +37,11 @@ void UMounteaInventoryComponent::GetLifetimeReplicatedProps(TArray UMounteaInventoryComponent::GetInventoryWBPClass_Implementation() +TSubclassOf UMounteaInventoryComponent::GetInventoryUIClass_Implementation() const { return InventoryWBPClass; } -UMounteaBaseUserWidget* UMounteaInventoryComponent::GetInventoryWBP_Implementation() +UMounteaBaseUserWidget* UMounteaInventoryComponent::GetInventoryUI_Implementation() const { return InventoryWBP; } @@ -139,7 +145,7 @@ bool UMounteaInventoryComponent::HasItem_Simple(const FItemRetrievalFilter& Sear { for (const auto& Itr : Items) { - if (Itr && Itr->ItemData.CompatibleGameplayTags.HasAny(SearchFilter.Tags)) + if (Itr && Itr->ItemData.ItemFlags.HasAny(SearchFilter.Tags)) { return true; } @@ -166,87 +172,61 @@ bool UMounteaInventoryComponent::HasItem_Simple(const FItemRetrievalFilter& Sear bool UMounteaInventoryComponent::HasItem_Multithreading(const FItemRetrievalFilter& SearchFilter) const { - if (SearchFilter.IsValid()) + if (!SearchFilter.IsValid()) + return false; + + TAtomic ItemFound(false); + + const int32 NumChunks = FMath::CeilToInt(static_cast(Items.Num()) / ChunkSize); + + auto SearchFunction = [&](const int32 ChunkIndex) { - int32 ThreadsPerFilter = UMounteaInventoryEquipmentBPF::GetValidFiltersCount(SearchFilter); - const int32 MinThreads = UMounteaInventoryEquipmentBPF::GetSettings()->ThreadsLimit; - const int32 NumThreads = FMath::Min( FPlatformMisc::NumberOfWorkerThreadsToSpawn(), MinThreads); + if (ItemFound.Load()) + return; - ThreadsPerFilter = FMath::Max( NumThreads/ThreadsPerFilter, 1); - - TArray Threads; - TAtomic ItemFound(false); + const int32 StartIndex = ChunkIndex * ChunkSize; + const int32 EndIndex = FMath::Min(StartIndex + ChunkSize, Items.Num()); - if (SearchFilter.bSearchByClass) + for (int32 i = StartIndex; i < EndIndex; i++) { - FItemRetrievalFilter SpecificFilter = SearchFilter; - SpecificFilter.bSearchByItem = false; - SpecificFilter.bSearchByTag = false; - SpecificFilter.bSearchByGUID = false; + if (ItemFound.Load()) + return; - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) - { - FItemSearchRunnable* SearchRunnable = new FItemSearchRunnable(Items, SpecificFilter, ItemFound); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("HasItemRunnable_ClassSearch")); - Threads.Add(Thread); - } - } - if (SearchFilter.bSearchByItem) - { - FItemRetrievalFilter SpecificFilter = SearchFilter; - SpecificFilter.bSearchByClass = false; - SpecificFilter.bSearchByTag = false; - SpecificFilter.bSearchByGUID = false; + const auto& Item = Items[i]; - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) + // Search by Item + if (SearchFilter.bSearchByItem && Item == SearchFilter.Item) { - FItemSearchRunnable* SearchRunnable = new FItemSearchRunnable(Items, SpecificFilter, ItemFound); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("HasItemRunnable_ItemSearch")); - Threads.Add(Thread); + ItemFound = true; + return; } - } - if (SearchFilter.bSearchByTag) - { - FItemRetrievalFilter SpecificFilter = SearchFilter; - SpecificFilter.bSearchByClass = false; - SpecificFilter.bSearchByItem = false; - SpecificFilter.bSearchByGUID = false; - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) + // Search by Class + if (SearchFilter.bSearchByClass && Item && Item->IsA(SearchFilter.Class)) { - FItemSearchRunnable* SearchRunnable = new FItemSearchRunnable(Items, SpecificFilter, ItemFound); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("HasItemRunnable_TagSearch")); - Threads.Add(Thread); + ItemFound = true; + return; } - } - if (SearchFilter.bSearchByGUID) - { - FItemRetrievalFilter SpecificFilter = SearchFilter; - SpecificFilter.bSearchByClass = false; - SpecificFilter.bSearchByItem = false; - SpecificFilter.bSearchByTag = false; - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) + // Search by Tag + if (SearchFilter.bSearchByTag && Item && Item->ItemData.ItemFlags.HasAny(SearchFilter.Tags)) { - FItemSearchRunnable* SearchRunnable = new FItemSearchRunnable(Items, SpecificFilter, ItemFound); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("HasItemRunnable_GUIDSearch")); - Threads.Add(Thread); + ItemFound = true; + return; } - } - for (FRunnableThread* Thread : Threads) - { - if (Thread) + // Search by GUID + if (SearchFilter.bSearchByGUID && Item && Item->GetItemGuid() == SearchFilter.Guid) { - Thread->WaitForCompletion(); - delete Thread; + ItemFound = true; + return; } } + }; - return ItemFound.Load(); - } - - return false; + ParallelFor(NumChunks, SearchFunction); + + return ItemFound.Load(); } UMounteaInventoryItemBase* UMounteaInventoryComponent::FindItem_Implementation(const FItemRetrievalFilter& SearchFilter) const @@ -298,7 +278,7 @@ UMounteaInventoryItemBase* UMounteaInventoryComponent::FindItem_Simple(const FIt { for (const auto& Itr : Items) { - if (Itr && Itr->ItemData.CompatibleGameplayTags.HasAny(SearchFilter.Tags)) + if (Itr && Itr->ItemData.ItemFlags.HasAny(SearchFilter.Tags)) { return Itr; } @@ -323,87 +303,61 @@ UMounteaInventoryItemBase* UMounteaInventoryComponent::FindItem_Simple(const FIt UMounteaInventoryItemBase* UMounteaInventoryComponent::FindItem_Multithreading(const FItemRetrievalFilter& SearchFilter) const { - if (SearchFilter.IsValid()) + if (!SearchFilter.IsValid()) + return nullptr; + + TAtomic FoundItem(nullptr); + + const int32 NumChunks = FMath::CeilToInt(static_cast(Items.Num()) / ChunkSize); + + auto SearchFunction = [&](const int32 ChunkIndex) { - int32 ThreadsPerFilter = UMounteaInventoryEquipmentBPF::GetValidFiltersCount(SearchFilter); - const int32 MinThreads = UMounteaInventoryEquipmentBPF::GetSettings()->ThreadsLimit; - const int32 NumThreads = FMath::Min( FPlatformMisc::NumberOfWorkerThreadsToSpawn(), MinThreads); + if (FoundItem.Load()) + return; - ThreadsPerFilter = FMath::Max( NumThreads/ThreadsPerFilter, 1); - - TArray Threads; - TAtomic FoundItem(nullptr); + const int32 StartIndex = ChunkIndex * ChunkSize; + const int32 EndIndex = FMath::Min(StartIndex + ChunkSize, Items.Num()); - if (SearchFilter.bSearchByClass) + for (int32 i = StartIndex; i < EndIndex; i++) { - FItemRetrievalFilter SpecificFilter = SearchFilter; - SpecificFilter.bSearchByItem = false; - SpecificFilter.bSearchByTag = false; - SpecificFilter.bSearchByGUID = false; + if (FoundItem.Load()) + return; - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) - { - FItemGetRunnable* SearchRunnable = new FItemGetRunnable(Items, SpecificFilter, FoundItem); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("ItemGetRunnable_ClassSearch")); - Threads.Add(Thread); - } - } - if (SearchFilter.bSearchByItem) - { - FItemRetrievalFilter SpecificFilter = SearchFilter; - SpecificFilter.bSearchByClass = false; - SpecificFilter.bSearchByTag = false; - SpecificFilter.bSearchByGUID = false; + const auto& Item = Items[i]; - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) + // Search by Item + if (SearchFilter.bSearchByItem && Item == SearchFilter.Item) { - FItemGetRunnable* SearchRunnable = new FItemGetRunnable(Items, SpecificFilter, FoundItem); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("ItemGetRunnable_ItemSearch")); - Threads.Add(Thread); + FoundItem = Item; + return; } - } - if (SearchFilter.bSearchByTag) - { - FItemRetrievalFilter SpecificFilter = SearchFilter; - SpecificFilter.bSearchByClass = false; - SpecificFilter.bSearchByItem = false; - SpecificFilter.bSearchByGUID = false; - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) + // Search by Class + if (SearchFilter.bSearchByClass && Item && Item->IsA(SearchFilter.Class)) { - FItemGetRunnable* SearchRunnable = new FItemGetRunnable(Items, SpecificFilter, FoundItem); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("ItemGetRunnable_TagSearch")); - Threads.Add(Thread); + FoundItem = Item; + return; } - } - if (SearchFilter.bSearchByGUID) - { - FItemRetrievalFilter SpecificFilter = SearchFilter; - SpecificFilter.bSearchByClass = false; - SpecificFilter.bSearchByItem = false; - SpecificFilter.bSearchByTag = false; - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) + // Search by Tag + if (SearchFilter.bSearchByTag && Item && Item->ItemData.ItemFlags.HasAny(SearchFilter.Tags)) { - FItemGetRunnable* SearchRunnable = new FItemGetRunnable(Items, SpecificFilter, FoundItem); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("ItemGetRunnable_GUIDSearch")); - Threads.Add(Thread); + FoundItem = Item; + return; } - } - for (FRunnableThread* Thread : Threads) - { - if (Thread) + // Search by GUID + if (SearchFilter.bSearchByGUID && Item && Item->GetItemGuid() == SearchFilter.Guid) { - Thread->WaitForCompletion(); - delete Thread; + FoundItem = Item; + return; } } + }; - return FoundItem.Load(); - } + ParallelFor(NumChunks, SearchFunction); - return nullptr; + return FoundItem.Load(); } TArray UMounteaInventoryComponent::GetItems_Simple(const FItemRetrievalFilter OptionalFilter) const @@ -441,7 +395,7 @@ TArray UMounteaInventoryComponent::GetItems_Simple(c { for (const auto& Item : Items) { - if (Item && Item->ItemData.CompatibleGameplayTags.HasAny(OptionalFilter.Tags)) + if (Item && Item->ItemData.ItemFlags.HasAny(OptionalFilter.Tags)) { FoundItems.Add(Item); } @@ -468,88 +422,58 @@ TArray UMounteaInventoryComponent::GetItems_Simple(c TArray UMounteaInventoryComponent::GetItems_Multithreading(const FItemRetrievalFilter OptionalFilter) const { - int32 ThreadsPerFilter = UMounteaInventoryEquipmentBPF::GetValidFiltersCount(OptionalFilter); - const int32 MinThreads = UMounteaInventoryEquipmentBPF::GetSettings()->ThreadsLimit; - const int32 NumThreads = FMath::Min( FPlatformMisc::NumberOfWorkerThreadsToSpawn(), MinThreads); + if (!OptionalFilter.IsValid()) + return TArray(); + + const int32 NumChunks = FMath::CeilToInt(static_cast(Items.Num()) / ChunkSize); - ThreadsPerFilter = FMath::Max( NumThreads/ThreadsPerFilter, 1); - - TArray Threads; + // Thread-safe container to collect items from each thread/chunk + FCriticalSection CriticalSection; TArray ReturnValues; - // Make runnable for each filter task. Each thread will iterate over only 1 filter. - if (OptionalFilter.bSearchByClass) + auto SearchFunction = [&](const int32 ChunkIndex) { - // Create and run the search runnables on separate threads - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) - { - FItemRetrievalFilter SpecificFilter = OptionalFilter; - SpecificFilter.bSearchByItem = false; - SpecificFilter.bSearchByTag = false; - SpecificFilter.bSearchByGUID = false; - - FItemsGetRunnable* SearchRunnable = new FItemsGetRunnable(Items, SpecificFilter, ReturnValues); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("ItemsGetRunnable_ClassSearch"), 0, TPri_BelowNormal); - Threads.Add(Thread); - } - } - if (OptionalFilter.bSearchByItem) - { - // Create and run the search runnables on separate threads - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) - { - FItemRetrievalFilter SpecificFilter = OptionalFilter; - SpecificFilter.bSearchByClass = false; - SpecificFilter.bSearchByTag = false; - SpecificFilter.bSearchByGUID = false; - - FItemsGetRunnable* SearchRunnable = new FItemsGetRunnable(Items, SpecificFilter, ReturnValues); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("ItemsGetRunnable_ItemSearch"), 0, TPri_BelowNormal); - Threads.Add(Thread); - } - } - if (OptionalFilter.bSearchByTag) - { - // Create and run the search runnables on separate threads - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) - { - FItemRetrievalFilter SpecificFilter = OptionalFilter; - SpecificFilter.bSearchByClass = false; - SpecificFilter.bSearchByItem = false; - SpecificFilter.bSearchByGUID = false; - - FItemsGetRunnable* SearchRunnable = new FItemsGetRunnable(Items, SpecificFilter, ReturnValues); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("ItemsGetRunnable_TagSearch"), 0, TPri_BelowNormal); - Threads.Add(Thread); - } - } - if (OptionalFilter.bSearchByGUID) - { - // Create and run the search runnables on separate threads - for (int32 ThreadIndex = 0; ThreadIndex < ThreadsPerFilter; ++ThreadIndex) - { - FItemRetrievalFilter SpecificFilter = OptionalFilter; - SpecificFilter.bSearchByClass = false; - SpecificFilter.bSearchByItem = false; - SpecificFilter.bSearchByTag = false; - - FItemsGetRunnable* SearchRunnable = new FItemsGetRunnable(Items, SpecificFilter, ReturnValues); - FRunnableThread* Thread = FRunnableThread::Create(SearchRunnable, TEXT("ItemsGetRunnable_GUIDSearch"), 0, TPri_Lowest); - Threads.Add(Thread); - } - } + const int32 StartIndex = ChunkIndex * ChunkSize; + const int32 EndIndex = FMath::Min(StartIndex + ChunkSize, Items.Num()); + TArray TempList; - // Wait for the threads to complete - for (FRunnableThread* Thread : Threads) - { - if (Thread) + for (int32 i = StartIndex; i < EndIndex; i++) { - Thread->WaitForCompletion(); - delete Thread; + auto& Item = Items[i]; + + // Search by Class + if (OptionalFilter.bSearchByClass && Item && Item->IsA(OptionalFilter.Class)) + { + TempList.Add(Item); + } + + // Search by Item + else if (OptionalFilter.bSearchByItem && Item == OptionalFilter.Item) + { + TempList.Add(Item); + } + + // Search by Tag + else if (OptionalFilter.bSearchByTag && Item && Item->ItemData.ItemFlags.HasAny(OptionalFilter.Tags)) + { + TempList.Add(Item); + } + + // Search by GUID + else if (OptionalFilter.bSearchByGUID && Item && Item->GetItemGuid() == OptionalFilter.Guid) + { + TempList.Add(Item); + } } - } - // Collect the found items from the atomic variables + // Add items found in this chunk to the main list + CriticalSection.Lock(); + ReturnValues.Append(TempList); + CriticalSection.Unlock(); + }; + + ParallelFor(NumChunks, SearchFunction); + return ReturnValues; } @@ -666,12 +590,12 @@ AActor* UMounteaInventoryComponent::GetOwningActor_Implementation() const return GetOwner(); } -void UMounteaInventoryComponent::SetInventoryWBPClass_Implementation(TSubclassOf NewInventoryWBPClass) +void UMounteaInventoryComponent::SetInventoryUIClass_Implementation(TSubclassOf NewInventoryWBPClass) { InventoryWBPClass = NewInventoryWBPClass; } -void UMounteaInventoryComponent::SetInventoryWBP_Implementation(UMounteaBaseUserWidget* NewWBP) +void UMounteaInventoryComponent::SetInventoryUI_Implementation(UMounteaBaseUserWidget* NewWBP) { if (InventoryWBP && InventoryWBP != NewWBP) { @@ -792,6 +716,12 @@ bool UMounteaInventoryComponent::SetInventoryFlags_Implementation() return true; } +bool UMounteaInventoryComponent::DoesHaveAuthority_Implementation() const +{ + if (GetOwner()==nullptr) return false; + return GetOwner()->HasAuthority(); +} + void UMounteaInventoryComponent::SetOtherInventory_Server_Implementation(const TScriptInterface& NewInventory) { if (NewInventory != OtherInventory) @@ -1037,7 +967,7 @@ bool UMounteaInventoryComponent::AddItem_Internal(UMounteaInventoryItemBase* Ite return true; } - + return false; } @@ -1265,10 +1195,13 @@ bool UMounteaInventoryComponent::CanExecuteCosmetics() const void UMounteaInventoryComponent::PostItemAdded_Client_Implementation(UMounteaInventoryItemBase* Item, const FItemUpdateResult& UpdateContext) { - if (!GetOwner()) return; + if (!GetOwner()) return; if (!GetWorld()) return; - + if (!Item) return; + if (!CanExecuteCosmetics()) return; + + Item->InitializeNewItem(this); GetWorld()->GetTimerManager().ClearTimer(TimerHandle_RequestItemSyncTimerHandle); @@ -1315,6 +1248,8 @@ void UMounteaInventoryComponent::PostItemAdded_Client_RequestUpdate(UMounteaInve if (!Item) return; GetWorld()->GetTimerManager().ClearTimer(TimerHandle_RequestInventorySyncTimerHandle); + + Item->InitializeNewItem(this); if (InventoryWBP) { @@ -1354,6 +1289,8 @@ void UMounteaInventoryComponent::PostItemUpdated_Client_RequestUpdate(UMounteaIn GetWorld()->GetTimerManager().ClearTimer(TimerHandle_RequestInventorySyncTimerHandle); + Item->InitializeNewItem(this); + if (InventoryWBP) { InventoryWBP->ProcessMounteaWidgetCommand(MounteaInventoryEquipmentConsts::MounteaInventoryWidgetCommands::InventoryCommands::RefreshItemsWidgets, Item); @@ -1418,172 +1355,3 @@ void UMounteaInventoryComponent::PostEditChangeProperty(FPropertyChangedEvent& P #endif #undef LOCTEXT_NAMESPACE - -uint32 FItemSearchRunnable::Run() -{ - // Search by Item - if (SearchFilter.bSearchByItem) - { - if (Items.Contains(SearchFilter.Item)) - { - ItemFound = true; - return 1; - } - } - - // Search by Class - if (SearchFilter.bSearchByClass) - { - for (const auto& Itr : Items) - { - if (Itr && Itr->IsA(SearchFilter.Class)) - { - ItemFound = true; - return 1; - } - } - } - - // Search by Tag - if (SearchFilter.bSearchByTag) - { - for (const auto& Itr : Items) - { - if (Itr && Itr->ItemData.CompatibleGameplayTags.HasAny(SearchFilter.Tags)) - { - ItemFound = true; - return 1; - } - } - } - - // Search by GUID - if (SearchFilter.bSearchByGUID) - { - for (const auto& Itr : Items) - { - if (Itr && Itr->GetItemGuid() == SearchFilter.Guid) - { - ItemFound = true; - return 1; - } - } - } - - return 0; -} - -uint32 FItemGetRunnable::Run() -{ - // Search by Item - if (SearchFilter.bSearchByItem) - { - if (Items.Contains(SearchFilter.Item)) - { - FoundItem = SearchFilter.Item; - ItemFound = true; - return 1; - } - } - - // Search by Class - if (SearchFilter.bSearchByClass) - { - for (const auto& Itr : Items) - { - if (Itr && Itr->IsA(SearchFilter.Class)) - { - FoundItem = Itr; - ItemFound = true; - return 1; - } - } - } - - // Search by Tag - if (SearchFilter.bSearchByTag) - { - for (const auto& Itr : Items) - { - if (Itr && Itr->ItemData.CompatibleGameplayTags.HasAny(SearchFilter.Tags)) - { - FoundItem = Itr; - ItemFound = true; - return 1; - } - } - } - - // Search by GUID - if (SearchFilter.bSearchByGUID) - { - for (const auto& Itr : Items) - { - if (Itr && Itr->GetItemGuid() == SearchFilter.Guid) - { - FoundItem = Itr; - ItemFound = true; - return 1; - } - } - } - - return 0; -} - -uint32 FItemsGetRunnable::Run() -{ - // Search by Item - if (SearchFilter.bSearchByItem) - { - for (const auto& Item : Items) - { - if (Item == SearchFilter.Item) - { - FoundItems.Add(Item); - ItemFound = true; - } - } - } - - // Search by Class - if (SearchFilter.bSearchByClass) - { - for (const auto& Item : Items) - { - if (Item && Item->IsA(SearchFilter.Class)) - { - FoundItems.Add(Item); - ItemFound = true; - } - } - } - - // Search by Tag - if (SearchFilter.bSearchByTag) - { - for (const auto& Item : Items) - { - if (Item && Item->ItemData.CompatibleGameplayTags.HasAny(SearchFilter.Tags)) - { - FoundItems.Add(Item); - ItemFound = true; - } - } - } - - // Search by GUID - if (SearchFilter.bSearchByGUID) - { - for (const auto& Item : Items) - { - if (Item && Item->GetItemGuid() == SearchFilter.Guid) - { - FoundItems.Add(Item); - ItemFound = true; - } - } - } - - return ItemFound ? 1 : 0; -} diff --git a/Source/MounteaInventoryEquipment/Private/Definitions/MounteaEquipmentSlot.cpp b/Source/MounteaInventoryEquipment/Private/Definitions/MounteaEquipmentSlot.cpp index e1c76261..49626ac0 100644 --- a/Source/MounteaInventoryEquipment/Private/Definitions/MounteaEquipmentSlot.cpp +++ b/Source/MounteaInventoryEquipment/Private/Definitions/MounteaEquipmentSlot.cpp @@ -4,19 +4,33 @@ #include "Definitions/MounteaEquipmentSlot.h" #include "Net/UnrealNetwork.h" +#include "Settings/MounteaEquipmentConfigData.h" #include "Settings/MounteaInventoryEquipmentSettings.h" +void UMounteaEquipmentSlot::UpdateItem(UMounteaInventoryItemBase* NewItem) +{ + if (NewItem!=ItemInSlot) + { + ItemInSlot = NewItem; + + OnRep_Slot(); + } +} + void UMounteaEquipmentSlot::OnRep_Slot() { - RepKey = 0; + RepKey++; } -TArray UMounteaEquipmentSlot::GetSlotIDs() const +TArray UMounteaEquipmentSlot::GetSlotIDs() { TArray ReturnValues; if (const UMounteaInventoryEquipmentSettings* Settings = GetDefault()) { - Settings->EquipmentSlotIDs.GetKeys(ReturnValues); + if (const UMounteaEquipmentConfigData* EquipmentData = Settings->EquipmentConfigData.LoadSynchronous()) + { + EquipmentData->EquipmentSlotIDs.GetKeys(ReturnValues); + } } return ReturnValues; @@ -49,7 +63,13 @@ void UMounteaEquipmentSlot::PostEditChangeProperty(FPropertyChangedEvent& Proper { if (const UMounteaInventoryEquipmentSettings* Settings = GetDefault()) { - SlotCompatibleTag = *Settings->EquipmentSlotIDs.Find(SlotID); + if (const UMounteaEquipmentConfigData* EquipmentData = Settings->EquipmentConfigData.LoadSynchronous()) + { + if (EquipmentData->EquipmentSlotIDs.Contains(SlotID)) + { + SlotCompatibleTag = *EquipmentData->EquipmentSlotIDs.Find(SlotID); + } + } } } } diff --git a/Source/MounteaInventoryEquipment/Private/Definitions/MounteaInventoryItem.cpp b/Source/MounteaInventoryEquipment/Private/Definitions/MounteaInventoryItem.cpp index 2c25f4cd..ecd56ba3 100644 --- a/Source/MounteaInventoryEquipment/Private/Definitions/MounteaInventoryItem.cpp +++ b/Source/MounteaInventoryEquipment/Private/Definitions/MounteaInventoryItem.cpp @@ -3,20 +3,51 @@ #include "Definitions/MounteaInventoryItem.h" +#include "Definitions/MounteaInventoryItemCategory.h" +#include "Definitions/MounteaInventoryItemRarity.h" #include "Helpers/MounteaInventoryEquipmentConsts.h" #include "Net/UnrealNetwork.h" #include "Helpers/FMounteaTemplatesLibrary.h" #include "Helpers/MounteaInventoryEquipmentBPF.h" +#include "Settings/MounteaInventoryEquipmentSettings.h" + UMounteaInventoryItemBase::UMounteaInventoryItemBase() { RepKey = 0; + + FWorldDelegates::OnPostWorldCreation.AddUObject(this, &UMounteaInventoryItemBase::PostWorldCreated); +} + +UMounteaInventoryItemBase::~UMounteaInventoryItemBase() +{ + FWorldDelegates::OnPostWorldCreation.RemoveAll(this); +} + +void UMounteaInventoryItemBase::PostWorldCreated(UWorld* NewWorld) +{ + if (FApp::IsGame()) + { + SetWorld(NewWorld); + + OnItemAdded.AddUniqueDynamic(this, &UMounteaInventoryItemBase::ItemAdded); + OnItemInitialized.AddUniqueDynamic(this, &UMounteaInventoryItemBase::ItemInitialized); + OnItemModified.AddUniqueDynamic(this, &UMounteaInventoryItemBase::ItemModified); + OnItemRemoved.AddUniqueDynamic(this, &UMounteaInventoryItemBase::ItemRemoved); + + SetValidData(); + + EnsureValidConfig(); + InitializeItemActions(); + + OnItemBeginPlay(TEXT("Item has been initialized")); + } } void UMounteaInventoryItemBase::PostInitProperties() { - UObject::PostInitProperties(); + UDataAsset::PostInitProperties(); bool bIsEditorNoPlay = false; #if WITH_EDITOR @@ -32,17 +63,20 @@ void UMounteaInventoryItemBase::PostInitProperties() EnsureValidConfig(); } - else - { - OnItemAdded.AddUniqueDynamic(this, &UMounteaInventoryItemBase::ItemAdded); - OnItemInitialized.AddUniqueDynamic(this, &UMounteaInventoryItemBase::ItemInitialized); - OnItemModified.AddUniqueDynamic(this, &UMounteaInventoryItemBase::ItemModified); - OnItemRemoved.AddUniqueDynamic(this, &UMounteaInventoryItemBase::ItemRemoved); - - SetValidData(); +} - OnItemBeginPlay(TEXT("Item has been initialized")); +TArray UMounteaInventoryItemBase::GetItemActions() const +{ + TArray ReturnValues; + for (const auto& Itr : ItemActions) + { + if (Itr.ItemAction && !ReturnValues.Contains(Itr.ItemAction)) + { + ReturnValues.Add(Itr.ItemAction); + } } + + return ReturnValues; } bool UMounteaInventoryItemBase::IsValid(UObject* WorldContextObject) const @@ -78,6 +112,27 @@ int32 UMounteaInventoryItemBase::GetQuantity() const return ItemData.ItemQuantity.CurrentQuantity; } +bool UMounteaInventoryItemBase::OwnerHasAuthority() const +{ + if (!OwningInventory) + { + if (!GEngine) return false; + if (!World) return false; + + const FString ModeName = GetEnumValueAsString(TEXT("ENetRole"), GEngine->GetNetMode(World)); + + UE_LOG(LogTemp, Error, TEXT("%s"), *ModeName) + if (GEngine->GetNetMode(World) == NM_Client) + { + return false; + } + + return true; + } + + return OwningInventory->Execute_DoesHaveAuthority(OwningInventory.GetObject()); +} + void UMounteaInventoryItemBase::SetWorldFromLevel(ULevel* FromLevel) { if (FromLevel == nullptr) @@ -91,9 +146,23 @@ void UMounteaInventoryItemBase::SetWorldFromLevel(ULevel* FromLevel) } } +void UMounteaInventoryItemBase::InitializeItemActions() +{ + TArray Actions = GetItemActions(); + for (UMounteaInventoryItemAction* ItrAction : Actions) + { + FMounteaDynamicDelegateContext Context; + Context.Command = MounteaInventoryEquipmentConsts::MounteaInventoryWidgetCommands::ItemActionCommands::InitializeAction; + Context.Payload = this; + ItrAction->InitializeAction(this, Context); + } +} + void UMounteaInventoryItemBase::SetWorld(UWorld* NewWorld) { World = NewWorld; + + InitializeItemActions(); } void UMounteaInventoryItemBase::InitializeNewItem(const TScriptInterface& NewOwningInventory) @@ -106,20 +175,36 @@ void UMounteaInventoryItemBase::InitializeNewItem(const TScriptInterfaceExecute_GetOwningActor(NewOwningInventory.GetObject())) { World = InventoryOwner->GetWorld(); - OwningInventory = NewOwningInventory; + } + else + { + World = NewOwningInventory.GetObject()->GetWorld(); + } - MarkDirtyForReplication(); + OwningInventory = NewOwningInventory; + + MarkDirtyForReplication(); - FString Message = ItemData.ItemName.ToString(); - Message.Append(": Initialization completed."); - OnItemInitialized.Broadcast(Message); - } + FString Message = ItemData.ItemName.ToString(); + Message.Append(": Initialization completed."); + OnItemInitialized.Broadcast(Message); } void UMounteaInventoryItemBase::OnRep_Item() { + if (OwningInventory.GetObject() == nullptr) return; + FString Message = ItemData.ItemName.ToString(); Message.Append(" has been modified."); + + if (const AActor* InventoryOwner = OwningInventory->Execute_GetOwningActor(OwningInventory.GetObject())) + { + World = InventoryOwner->GetWorld(); + } + else + { + World = OwningInventory.GetObject()->GetWorld(); + } OnItemModified.Broadcast(Message); } @@ -223,12 +308,6 @@ void UMounteaInventoryItemBase::SetValidData() } } -void UMounteaInventoryItemBase::SetValidDataEditor() -{ - SetValidData(); - EnsureValidConfig(); -} - void UMounteaInventoryItemBase::ClearMappedValues() { ItemData = FMounteaInventoryItemRequiredData(); @@ -239,24 +318,15 @@ void UMounteaInventoryItemBase::CopyTagsFromTypes() { if (ItemData.ItemCategory) { - ItemData.CompatibleGameplayTags.AppendTags(ItemData.ItemCategory->CompatibleGameplayTags); + ItemData.ItemFlags.AppendTags(ItemData.ItemCategory->CompatibleGameplayTags); } if (ItemData.ItemRarity) { - ItemData.CompatibleGameplayTags.AddTag(ItemData.ItemRarity->RarityGameplayTag); + ItemData.ItemFlags.AddTag(ItemData.ItemRarity->RarityGameplayTag); } } -#if WITH_EDITOR - -void UMounteaInventoryItemBase::PostDuplicate(bool bDuplicateForPIE) -{ - UObject::PostDuplicate(bDuplicateForPIE); - - ItemGuid = FGuid::NewGuid(); -} - void UMounteaInventoryItemBase::EnsureValidConfig() { if (ItemConfig.ItemConfig == nullptr) @@ -265,6 +335,52 @@ void UMounteaInventoryItemBase::EnsureValidConfig() const TSubclassOf Class = UMounteaInventoryEquipmentBPF::GetSettings()->DefaultItemConfigClass.LoadSynchronous(); ItemConfig.ItemConfig = UMounteaInventoryEquipmentBPF::GetItemConfig(this, Class, bFound); } + + // Copy Actions Categories + { + TArray CurrentActions = GetItemActionsDefinitions(); + ItemActions.Empty(); + + if (ItemData.ItemCategory) + { + TArray CategoryActions = ItemData.ItemCategory->GetCategoryActionsDefinitions(); + + for (const FMounteaItemAction ItrCategoryAction: CategoryActions) + { + if (!ItrCategoryAction.ItemAction) continue; + if (CurrentActions.Contains(ItrCategoryAction)) continue; + + const UMounteaInventoryItemAction* SourceAction = ItrCategoryAction.ItemAction; + UMounteaInventoryItemAction* NewAction = NewObject(GetPackage(), SourceAction->GetClass()); + NewAction->CopyFromOther(ItrCategoryAction.ItemAction); + + FMounteaItemAction NewActionDefinition; + NewActionDefinition.ItemAction = NewAction; + + CurrentActions.Add(NewActionDefinition); + } + } + + ItemActions = CurrentActions; + } +} + +#if WITH_EDITOR + +void UMounteaInventoryItemBase::SetValidDataEditor() +{ + EnsureValidConfig(); + SetValidData(); +} + +void UMounteaInventoryItemBase::PostDuplicate(bool bDuplicateForPIE) +{ + UObject::PostDuplicate(bDuplicateForPIE); + + EnsureValidConfig(); + SetValidData(); + + ItemGuid = FGuid::NewGuid(); } void UMounteaInventoryItemBase::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) diff --git a/Source/MounteaInventoryEquipment/Private/Definitions/MounteaInventoryItemCategory.cpp b/Source/MounteaInventoryEquipment/Private/Definitions/MounteaInventoryItemCategory.cpp index 90847b2a..b17b45dc 100644 --- a/Source/MounteaInventoryEquipment/Private/Definitions/MounteaInventoryItemCategory.cpp +++ b/Source/MounteaInventoryEquipment/Private/Definitions/MounteaInventoryItemCategory.cpp @@ -2,4 +2,3 @@ #include "Definitions/MounteaInventoryItemCategory.h" - diff --git a/Source/MounteaInventoryEquipment/Private/Definitions/MounteaItemAction.cpp b/Source/MounteaInventoryEquipment/Private/Definitions/MounteaItemAction.cpp index 67d54d2f..f14acbb8 100644 --- a/Source/MounteaInventoryEquipment/Private/Definitions/MounteaItemAction.cpp +++ b/Source/MounteaInventoryEquipment/Private/Definitions/MounteaItemAction.cpp @@ -40,3 +40,16 @@ void UMounteaInventoryItemAction::SetWorld(UWorld* NewWorld) World = NewWorld; } +void UMounteaInventoryItemAction::CopyFromOther(const UMounteaInventoryItemAction* OtherAction) +{ + if (!OtherAction) return; + + ActionIcon = OtherAction->ActionIcon; + ActionName = OtherAction->ActionName; + ActionTag = OtherAction->ActionTag; + ActionContext = OtherAction->ActionContext; + + World = OtherAction->GetWorld(); + OwningItem = OtherAction->GetOwningItem(); +} + diff --git a/Source/MounteaInventoryEquipment/Private/Definitions/MounteaItemAdditionalData.cpp b/Source/MounteaInventoryEquipment/Private/Definitions/MounteaItemAdditionalData.cpp index c65500e9..c5037683 100644 --- a/Source/MounteaInventoryEquipment/Private/Definitions/MounteaItemAdditionalData.cpp +++ b/Source/MounteaInventoryEquipment/Private/Definitions/MounteaItemAdditionalData.cpp @@ -2,7 +2,7 @@ #include "Definitions/MounteaItemAdditionalData.h" - +#include "Helpers/FMounteaTemplatesLibrary.h" #include "Definitions/MounteaInventoryTableTypes.h" UMounteaItemAdditionalData::UMounteaItemAdditionalData() @@ -26,6 +26,18 @@ FMounteaItemDescription* UMounteaItemAdditionalData::GetRowData(const UMounteaIn return FromTable->FindRow(FromRow, Context); } +TArray UMounteaItemAdditionalData::GetSourceTableRows_ShortDescription() const +{ + { + return GetSourceRows(SourceTable_ShortDescription); + } +} + +TArray UMounteaItemAdditionalData::GetSourceTableRows_LongDescription() const +{ + return GetSourceRows(SourceTable_LongDescription); +} + #if WITH_EDITOR void UMounteaItemAdditionalData::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) diff --git a/Source/MounteaInventoryEquipment/Private/Helpers/MounteaInventoryEquipmentBPF.cpp b/Source/MounteaInventoryEquipment/Private/Helpers/MounteaInventoryEquipmentBPF.cpp index 523df6a4..6e21f304 100644 --- a/Source/MounteaInventoryEquipment/Private/Helpers/MounteaInventoryEquipmentBPF.cpp +++ b/Source/MounteaInventoryEquipment/Private/Helpers/MounteaInventoryEquipmentBPF.cpp @@ -3,6 +3,347 @@ #include "Helpers/MounteaInventoryEquipmentBPF.h" +#include "Definitions/MounteaEquipmentSlot.h" +#include "Definitions/MounteaInventoryItem.h" +#include "Definitions/MounteaInventoryItemCategory.h" +#include "Helpers/FMounteaTemplatesLibrary.h" +#include "Interfaces/MounteaInventoryItemWBPInterface.h" +#include "Interfaces/MounteaInventorySlotWBPInterface.h" +#include "Settings/MounteaInventoryEquipmentSettings.h" +#include "Settings/MounteaInventoryThemeConfig.h" +#include "Setup/MounteaInventoryConfig.h" + +TScriptInterface UMounteaInventoryEquipmentBPF::GetInventoryInterface(AActor* FromActor) +{ + return GetInterfaceFrom>(FromActor); +} + +bool UMounteaInventoryEquipmentBPF::ItemRetrievalFilter_IsValid(const FItemRetrievalFilter& Filter) +{ + return Filter.IsValid(); +} + +bool UMounteaInventoryEquipmentBPF::IsArrayValid(const TArray& Array) +{ + return Array.Num() > 0; +} + +UActorComponent* UMounteaInventoryEquipmentBPF::GetSingleComponentByInterface(const AActor* Target, TSubclassOf InterfaceFilter) +{ + if (Target == nullptr) return nullptr; + + TArray TempComps = Target->GetComponentsByInterface(InterfaceFilter); + + if (TempComps.IsEmpty()) return nullptr; + + return TempComps[0]; +} + +bool UMounteaInventoryEquipmentBPF::IsInventoryValid( const TScriptInterface& InventoryInterface) +{ + return InventoryInterface.GetObject() != nullptr; +} + +UObject* UMounteaInventoryEquipmentBPF::GetObjectByClass(UObject* Object, const TSubclassOf ClassFilter, bool& bResult) +{ + if (ClassFilter == nullptr) + { + bResult = false; + return nullptr; + } + + if (Object == nullptr) + { + bResult = false; + return nullptr; + } + + if (Object->IsA(ClassFilter)) + { + bResult = true; + return Object; + } + + bResult = false; + return nullptr; +} + +TArray UMounteaInventoryEquipmentBPF::GetThemeConfigs() +{ + TArray Result; + if (const auto Settings = GetSettings()) + { + for (auto& Itr : Settings->ThemeConfigs) + { + if (Itr.IsNull()) continue; + + Result.Add(Itr.LoadSynchronous()); + } + } + + return Result; +} + +TArray UMounteaInventoryEquipmentBPF::GetThemeConfigsNames() +{ + TArray Result; + + for (const auto& Itr : GetThemeConfigs()) + { + + if (Itr) Result.Add(Itr->GetName()); + } + return Result; +} + +UMounteaInventoryThemeConfig* UMounteaInventoryEquipmentBPF::GetThemeConfigByName(const FString& SearchName) +{ + UMounteaInventoryThemeConfig* Result = nullptr; + + for (const auto& Itr : GetThemeConfigs()) + { + if (Itr && Itr->GetName().Equals(SearchName)) + { + Result = Itr; + + return Result; + } + } + + return Result; +} + +TSubclassOf UMounteaInventoryEquipmentBPF::GetThemeConfigClass() +{ + if (GetSettings()->ThemeConfig) return GetSettings()->ThemeConfig->StaticClass(); + + return nullptr; +} + +UMounteaInventoryThemeConfig* UMounteaInventoryEquipmentBPF::GetThemeConfig(const TSubclassOf ClassFilter, bool& bResult) +{ + if (ClassFilter == nullptr) + { + bResult = false; + return nullptr; + } + + bResult = true; + const UMounteaInventoryEquipmentSettings* Settings = GetDefault(); + if (!Settings) + { + return NewObject(); + } + + if (Settings->ThemeConfig.IsNull()) + { + return NewObject(GetTransientPackage(), ClassFilter); + } + + auto const FoundTheme = Settings->ThemeConfig.LoadSynchronous(); + return FoundTheme->IsA(ClassFilter) ? FoundTheme : NewObject(GetTransientPackage(), ClassFilter); +} + +TSubclassOf UMounteaInventoryEquipmentBPF::GetItemInventoryConfigClass(const TScriptInterface Target, const TSubclassOf ClassFilter, bool& bResult) +{ + if (!Target) return nullptr; + + return Target->Execute_GetInventoryConfigClass(Target.GetObject()); +} + +TSubclassOf UMounteaInventoryEquipmentBPF::GetItemItemConfigClass( + const UMounteaInventoryItemBase* Target) +{ + if (!Target) return nullptr; + + return Target->GetItemConfigClass(); +} + +UMounteaInventoryConfig* UMounteaInventoryEquipmentBPF::GetInventoryConfig(const TScriptInterface Target, const TSubclassOf ClassFilter, bool& bResult) +{ + if (ClassFilter == nullptr) + { + bResult = false; + return nullptr; + } + + if (Target == nullptr) + { + bResult = false; + return nullptr; + } + + return Target->Execute_GetInventoryConfig(Target.GetObject(), ClassFilter, bResult); +} + +UMounteaInventoryItemConfig* UMounteaInventoryEquipmentBPF::GetItemConfig(const UMounteaInventoryItemBase* Target, const TSubclassOf ClassFilter, bool& bResult) +{ + if (ClassFilter == nullptr) + { + bResult = false; + return nullptr; + } + + if (Target == nullptr) + { + bResult = false; + return nullptr; + } + + return Target->GetItemConfig(ClassFilter, bResult); +} + +UMounteaItemAdditionalData* UMounteaInventoryEquipmentBPF::GetItemAdditionalData(const UMounteaInventoryItemBase* Target, const TSubclassOf ClassFilter, bool& bResult) +{ + if (ClassFilter == nullptr) + { + bResult = false; + return nullptr; + } + + if (Target == nullptr) + { + bResult = false; + return nullptr; + } + + return Target->GetItemAdditionalData(ClassFilter, bResult); +} + +UMounteaEquipmentSlot* UMounteaInventoryEquipmentBPF::FindEquipmentSlot(const TArray& SlotsData, const FMounteaEquipmentSlotDataCompare& Filter) +{ + for (const auto& Itr : SlotsData) + { + if (Itr == Filter) return Itr.Slot; + } + + return nullptr; +} + +UMounteaEquipmentSlot* UMounteaInventoryEquipmentBPF::FindEquipmentSlot(const TArray& SlotsData, const FString& SlotID) +{ + for (const auto& Itr : SlotsData) + { + if (Itr.Slot && Itr.Slot->GetSlotID().Equals(SlotID)) return Itr.Slot; + } + + return nullptr; +} + +bool UMounteaInventoryEquipmentBPF::IsEditor() +{ +#if WITH_EDITOR + return true; +#endif + + return false; +} + +bool UMounteaInventoryEquipmentBPF::IsEditorNoPlay() +{ + // This is to ensure we are not throwing InvalidWorld errors in Editor with no Gameplay. + bool bIsEditorCall = false; +#if WITH_EDITOR + if (GEditor != nullptr) + { + bIsEditorCall = !GEditor->GetPlayInEditorSessionInfo().IsSet(); + } +#endif + + return bIsEditorCall; +} + +bool UMounteaInventoryEquipmentBPF::IsShipping() +{ + +#if UE_BUILD_SHIPPING + return true; +#endif + + return false; +} + +const UMounteaInventoryEquipmentSettings* UMounteaInventoryEquipmentBPF::GetSettings() +{ + return GetDefault(); +} + +UMounteaInventoryItemsTable* UMounteaInventoryEquipmentBPF::GetDefaultItemsTable() +{ + return GetSettings()->DefaultInventoryItemDefinitionsTable.LoadSynchronous(); +} + +TSet UMounteaInventoryEquipmentBPF::GetAllowedCategories() +{ + TSet ReturnValues; + for (auto Itr : GetSettings()->InventoryCategories) + { + ReturnValues.Add(Itr.LoadSynchronous()); + } + + return ReturnValues; +} + +TSet UMounteaInventoryEquipmentBPF::GetAllowedRarities() +{ + TSet ReturnValues; + for (auto Itr : GetSettings()->InventoryRarities) + { + ReturnValues.Add(Itr.LoadSynchronous()); + } + + return ReturnValues; +} + +TArray UMounteaInventoryEquipmentBPF::GetDragKeys() +{ + return GetSettings()->DragKeys; +} + +TArray UMounteaInventoryEquipmentBPF::GetActionRequestKeys() +{ + return GetSettings()->ActionRequestKeys; +} + +TSoftClassPtr UMounteaInventoryEquipmentBPF::GetDefaultItemConfigClass() +{ + return GetSettings()->DefaultItemConfigClass; +} + +bool UMounteaInventoryEquipmentBPF::UIDebug() +{ + if (IsShipping()) + { + return false; + } + + if (const UMounteaInventoryEquipmentSettings* Settings = GetDefault()) + { + return Settings->bUIDebug; + } + + return false; +} + +bool UMounteaInventoryEquipmentBPF::IsDragAllowed() +{ + return GetSettings()->bDragDropAllowed; +} + +FIntPoint UMounteaInventoryEquipmentBPF::GetInventoryDimensions() +{ + bool bFound; + const auto Config = GetThemeConfig(UMounteaInventoryThemeConfig::StaticClass(), bFound); + return bFound ? Config->InventoryBaseSize : FIntPoint(6, 10); +} + +FIntPoint UMounteaInventoryEquipmentBPF::GetInventorySlotSize() +{ + bool bFound; + const auto Config = GetThemeConfig(UMounteaInventoryThemeConfig::StaticClass(), bFound); + return bFound ? Config->SlotBaseSize : FIntPoint(16, 16); +} + int UMounteaInventoryEquipmentBPF::CalculateMaxSubtractQuantity(UMounteaInventoryItemBase* Item, UMounteaInventoryItemBase* OtherItem, const int32 RequestedQuantity) { if (RequestedQuantity == 0) @@ -87,6 +428,138 @@ int32 UMounteaInventoryEquipmentBPF::RemoveItemQuantity(UMounteaInventoryItemBas return 0; } +bool UMounteaInventoryEquipmentBPF::DoesHaveTag(const UMounteaInventoryItemBase* Item, const FGameplayTag Tag) +{ + if (Item == nullptr) return false; + + return Item->GetTags().HasTag(Tag); +} + +bool UMounteaInventoryEquipmentBPF::DoesHaveAnyTag(const UMounteaInventoryItemBase* Item, + const FGameplayTagContainer Tags) +{ + if (Item == nullptr) return false; + + return Item->GetTags().HasAny(Tags); +} + +bool UMounteaInventoryEquipmentBPF::DoesHaveAllTags(const UMounteaInventoryItemBase* Item, + const FGameplayTagContainer Tags) +{ + if (Item == nullptr) return false; + + return Item->GetTags().HasAll(Tags); +} + +TArray UMounteaInventoryEquipmentBPF::CalculateItemShadow(const FIntPoint& StartCoords, + const FIntPoint& Area) +{ + TSet Results; + + int32 X = StartCoords.X; + int32 Y = StartCoords.Y; + + for (int i = 0; i < Area.X; i++) + { + for (int j = 0; j < Area.Y; j++) + { + Results.Add(FIntPoint(X, Y)); + + Y++; + } + + X++; + Y = StartCoords.Y; + } + + return Results.Array(); +} + +bool UMounteaInventoryEquipmentBPF::IsValidShadow(const TArray& SlotsCoords, + const TArray>& SlotsRefs, const TArray& Shadow, + const TScriptInterface& MovedItem) +{ + if (MovedItem.GetObject() == nullptr) + { + UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 00] Trying to move nothing!")) + return false; + } + + const FIntPoint Area = MovedItem->Execute_GetItemSize(MovedItem.GetObject()); + + + if (Shadow.Num() < FMath::Max(Area.X, Area.Y)) + { + UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 01] Trying to move outside Inventory grid!")) + return false; + } + + for (const auto& Itr : Shadow) + { + if (!SlotsCoords.Contains(Itr)) + { + UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 02] Shadow coords outsied Inventoyr grid!!")) + return false; + } + } + + TMap> Slots; + + //Collect slots under shadow + for (int i = 0; i < Shadow.Num(); i++) + { + const FIntPoint Coords = Shadow[i]; + + if (!SlotsCoords.Contains(Coords)) + { + UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 03] Shadow coords outsied Inventoyr grid!!")) + return false; + } + + if (!SlotsCoords.IsValidIndex(SlotsCoords.Find(Coords))) + { + UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 04] Shadow coords outsied Inventoyr grid!!")) + return false; + } + + const int CoordsIndex = SlotsCoords.Find(Coords); + + TScriptInterface Slot = SlotsRefs.IsValidIndex(CoordsIndex) ? SlotsRefs[CoordsIndex] : nullptr; + + Slots.Add(Coords, Slot); + } + + // Validate slot under shadow + for (const auto& Itr : Shadow) + { + if (!SlotsCoords.Contains(Itr)) + { + UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 05] Shadow coords outsied Inventoyr grid!!")) + return false; + } + + const TScriptInterface* Slot = Slots.Find(Itr); + if (!Slot->GetInterface()->Execute_IsSlotEmpty(Slot->GetObject()) ) + { + const TScriptInterface OccupyingItem = Slot->GetInterface()->Execute_GetOccupyingItem(Slot->GetObject()); + if (OccupyingItem != MovedItem) + { + UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 06] Shadow occupied by different Item!!")) + return false; + } + } + } + + return true; +} + +bool UMounteaInventoryEquipmentBPF::IsSafeSlot(const FIntPoint& StartCoords, const FIntPoint& Area) +{ + CalculateItemShadow(StartCoords, Area); + + return false; +} + TArray UMounteaInventoryEquipmentBPF::ExcludeItems(const FItemRetrievalFilter& Filter, const TArray& ItemsToFilter) { if (!Filter.IsValid()) return TArray(); diff --git a/Source/MounteaInventoryEquipment/Private/Interfaces/MounteaEquipmentSlotWBPInterface.cpp b/Source/MounteaInventoryEquipment/Private/Interfaces/MounteaEquipmentSlotWBPInterface.cpp new file mode 100644 index 00000000..f4a1a3b1 --- /dev/null +++ b/Source/MounteaInventoryEquipment/Private/Interfaces/MounteaEquipmentSlotWBPInterface.cpp @@ -0,0 +1,6 @@ +// All rights reserved Dominik Pavlicek 2023. + + +#include "Interfaces/MounteaEquipmentSlotWBPInterface.h" + +// Add default functionality here for any IMounteaEquipmentSlotWBPInterface functions that are not pure virtual. diff --git a/Source/MounteaInventoryEquipment/Private/Settings/ContentTheme.cpp b/Source/MounteaInventoryEquipment/Private/Settings/ContentTheme.cpp new file mode 100644 index 00000000..9b7f57bd --- /dev/null +++ b/Source/MounteaInventoryEquipment/Private/Settings/ContentTheme.cpp @@ -0,0 +1,5 @@ +// All rights reserved Dominik Pavlicek 2023. + + +#include "Settings/ContentTheme.h" + diff --git a/Source/MounteaInventoryEquipment/Private/Settings/MounteaEquipmentConfigData.cpp b/Source/MounteaInventoryEquipment/Private/Settings/MounteaEquipmentConfigData.cpp new file mode 100644 index 00000000..416df9b6 --- /dev/null +++ b/Source/MounteaInventoryEquipment/Private/Settings/MounteaEquipmentConfigData.cpp @@ -0,0 +1,5 @@ +// All rights reserved Dominik Pavlicek 2023. + + +#include "Settings/MounteaEquipmentConfigData.h" + diff --git a/Source/MounteaInventoryEquipment/Private/Settings/MounteaInventoryEquipmentSettings.cpp b/Source/MounteaInventoryEquipment/Private/Settings/MounteaInventoryEquipmentSettings.cpp index 7a1e4d29..c0c39f9e 100644 --- a/Source/MounteaInventoryEquipment/Private/Settings/MounteaInventoryEquipmentSettings.cpp +++ b/Source/MounteaInventoryEquipment/Private/Settings/MounteaInventoryEquipmentSettings.cpp @@ -23,6 +23,16 @@ UMounteaInventoryEquipmentSettings::UMounteaInventoryEquipmentSettings() InventoryWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaInventoryWidgetCommands::InventoryCommands::RefreshItemsWidgets); InventoryWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaInventoryWidgetCommands::InventoryCommands::RemoveItemWidget); + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::InitializeEquipmentWidget); + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::CreateEquipmentWidget); + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::ShowEquipmentWidget); + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::HideEquipmentWidget); + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::RefreshEquipmentWidget); + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::RefreshEquipmentWidget); + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::RefreshItemsWidgets); + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::UnequipItemWidget); + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::EquipItemWidget); + InventoryUpdateMessages.Add(EInventoryUpdateResult::EIUR_Success, LOCTEXT("InventoryUpdateMessages_Success", "Inventory Updated")); InventoryUpdateMessages.Add(EInventoryUpdateResult::EIUR_Failed, LOCTEXT("InventoryUpdateMessages_Failed", "Inventory Update Failed")); diff --git a/Source/MounteaInventoryEquipment/Private/Settings/MounteaInventoryThemeConfig.cpp b/Source/MounteaInventoryEquipment/Private/Settings/MounteaInventoryThemeConfig.cpp index cba3f602..f6c0171b 100644 --- a/Source/MounteaInventoryEquipment/Private/Settings/MounteaInventoryThemeConfig.cpp +++ b/Source/MounteaInventoryEquipment/Private/Settings/MounteaInventoryThemeConfig.cpp @@ -2,4 +2,145 @@ #include "Settings/MounteaInventoryThemeConfig.h" +#include "Helpers/MounteaInventoryEquipmentBPF.h" +UMounteaInventoryThemeConfig::UMounteaInventoryThemeConfig() +{ +} + +void UMounteaInventoryThemeConfig::GenerateMissingThemes() +{ + // Category Image Theme + { + if (CategoryImageTheme == nullptr) + { + UImageTheme* NewImageTheme = NewObject(GetPackage()); + + CategoryImageTheme = NewImageTheme; + } + } + + // Categories Themes + { + const TSet AllCategories = UMounteaInventoryEquipmentBPF::GetAllowedCategories(); + TSet CategoriesWithTheme; + + for (const auto& Itr : CategoryThemes) + { + if (Itr.CategoryTheme) + { + CategoriesWithTheme.Add(Itr.CategoryTheme->Category); + } + } + + TArray MissingCategories; + for (UMounteaInventoryItemCategory* Category : AllCategories) + { + if (!CategoriesWithTheme.Contains(Category)) + { + MissingCategories.Add(Category); + } + } + + for (const auto& Itr : MissingCategories) + { + UCategoryTheme* NewCategoryTheme = NewObject(GetPackage(), UCategoryTheme::StaticClass()); + + if (NewCategoryTheme == nullptr) continue; + + NewCategoryTheme->Category = Itr; + NewCategoryTheme->CategoryStyle = CategoryImageTheme; + + FCategoryThemeData NewCategoryThemeData; + NewCategoryThemeData.CategoryTheme = NewCategoryTheme; + + CategoryThemes.Add(NewCategoryThemeData); + } + } + + // Text Theme + { + if (TextTheme == nullptr) + { + UTextTheme* NewTextTheme = NewObject(GetPackage()); + + TextTheme = NewTextTheme; + } + } + + // Colours Theme + { + if (ColoursTheme == nullptr) + { + UColoursTheme* NewColoursTheme = NewObject(GetPackage()); + + ColoursTheme = NewColoursTheme; + } + } +} + + + +#if WITH_EDITOR + +void UMounteaInventoryThemeConfig::GenerateMissingThemes_Editor() +{ + GenerateMissingThemes(); +} + +void UMounteaInventoryThemeConfig::Propagate_CategoryDefaultStyle() +{ + for (const auto& Itr : CategoryThemes) + { + if (Itr.CategoryTheme) + { + Itr.CategoryTheme->CategoryStyle = CategoryImageTheme; + } + } +} + +void UMounteaInventoryThemeConfig::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + + const FString PropertyName = PropertyChangedEvent.Property->GetName(); + + // TODO: Rather than making them in-package, create a new ones in the same folder! + if (PropertyName.Equals("CategoryThemes")) + { + GenerateMissingThemes(); + } + + if (PropertyName.Equals("TextTheme")) + { + GenerateMissingThemes(); + } + + if (PropertyName.Equals("ColoursTheme")) + { + GenerateMissingThemes(); + } +} + +bool UMounteaInventoryThemeConfig::Rename(const TCHAR* NewName, UObject* NewOuter, ERenameFlags Flags) +{ + const bool bSatisfied = Super::Rename(NewName, NewOuter, Flags); + + if (bSatisfied) + { + if (TextTheme) TextTheme->Rename(nullptr, NewOuter, Flags); + + if (ColoursTheme) ColoursTheme->Rename(nullptr, NewOuter, Flags); + + if (CategoryImageTheme) CategoryImageTheme->Rename(nullptr, NewOuter, Flags); + + for (auto& Itr : CategoryThemes) + { + if (Itr.CategoryTheme) Itr.CategoryTheme->Rename(nullptr, NewOuter, Flags); + } + } + + return bSatisfied; +} + +#endif diff --git a/Source/MounteaInventoryEquipment/Private/WBP/MounteaBaseEquipmentSlotWidget.cpp b/Source/MounteaInventoryEquipment/Private/WBP/MounteaBaseEquipmentSlotWidget.cpp new file mode 100644 index 00000000..e3d9d736 --- /dev/null +++ b/Source/MounteaInventoryEquipment/Private/WBP/MounteaBaseEquipmentSlotWidget.cpp @@ -0,0 +1,23 @@ +// All rights reserved Dominik Pavlicek 2023. + + +#include "WBP/MounteaBaseEquipmentSlotWidget.h" + +#include "Helpers/MounteaInventoryEquipmentBPF.h" +#include "Settings/MounteaEquipmentConfigData.h" +#include "Settings/MounteaInventoryEquipmentSettings.h" + +TArray UMounteaBaseEquipmentSlotWidget::GetSlotIDOptions() +{ + TArray Results; + + if (const UMounteaInventoryEquipmentSettings* const Settings = UMounteaInventoryEquipmentBPF::GetSettings()) + { + if (!Settings->EquipmentConfigData.IsNull()) + { + Settings->EquipmentConfigData.LoadSynchronous()->EquipmentSlotIDs.GetKeys(Results); + } + } + + return Results; +} diff --git a/Source/MounteaInventoryEquipment/Private/WBP/MounteaBaseUserWidget.cpp b/Source/MounteaInventoryEquipment/Private/WBP/MounteaBaseUserWidget.cpp index e5b052ae..a67240f2 100644 --- a/Source/MounteaInventoryEquipment/Private/WBP/MounteaBaseUserWidget.cpp +++ b/Source/MounteaInventoryEquipment/Private/WBP/MounteaBaseUserWidget.cpp @@ -4,6 +4,7 @@ #include "WBP/MounteaBaseUserWidget.h" #include "Helpers/MounteaInventoryEquipmentBPF.h" +#include "Settings/MounteaInventoryThemeConfig.h" UMounteaBaseUserWidget::UMounteaBaseUserWidget(const FObjectInitializer& ObjectInitializer) : UUserWidget(ObjectInitializer) diff --git a/Source/MounteaInventoryEquipment/Public/Components/MounteaEquipmentComponent.h b/Source/MounteaInventoryEquipment/Public/Components/MounteaEquipmentComponent.h index 81ba74f5..7dba03d3 100644 --- a/Source/MounteaInventoryEquipment/Public/Components/MounteaEquipmentComponent.h +++ b/Source/MounteaInventoryEquipment/Public/Components/MounteaEquipmentComponent.h @@ -45,25 +45,31 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaEquipmentComponent : public UActorCo virtual bool ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) override; public: + + virtual AActor* GetOwningActor_Implementation() const override; virtual FString FindSlotForItem_Implementation(const UMounteaInventoryItemBase* Item) const override; + virtual UMounteaEquipmentSlot* FindSlotByID_Implementation(const FString& SlotID) const override; virtual TArray GetAllSlots_Implementation() const override; - virtual bool EquipItem_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) override; - virtual bool UnEquipItem_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) override; + virtual bool EquipItem_Implementation(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) override; + virtual bool UnEquipItem_Implementation(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) override; - virtual bool IsItemEquipped_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) override; + virtual bool IsItemEquipped_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) const override; virtual bool CanEquipItem_Implementation(const UMounteaInventoryItemBase* ItemToEquip) const override; + virtual UMounteaBaseUserWidget* GetEquipmentUI_Implementation() const override; + virtual bool SetEquipmentUI_Implementation(UMounteaBaseUserWidget* NewUI) override; + virtual FOnEquipmentUpdated& GetEquipmentUpdatedHandle() override { return OnEquipmentUpdated; }; virtual FOnSlotUpdated& GetSlotEquippedHandle() override { return OnSlotEquipped; }; virtual FOnSlotUpdated& GetSlotUnEquippedHandle() override { return OnSlotUnequipped; }; protected: - - UFUNCTION(Server, Reliable, WithValidation) void EquipItem_Server(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); - UFUNCTION(Server, Reliable, WithValidation) void UnEquipItem_Server(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); + + UFUNCTION(Server, Reliable, WithValidation) void EquipItem_Server(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); + UFUNCTION(Server, Reliable, WithValidation) void UnEquipItem_Server(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); UFUNCTION(NetMulticast, Unreliable) void EquipItem_Multicast(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); UFUNCTION(NetMulticast, Unreliable) void UnEquipItem_Multicast(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); UFUNCTION() void OnRep_Equipment(); @@ -77,8 +83,11 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaEquipmentComponent : public UActorCo TArray EquipmentSlotData; private: + + UPROPERTY(Transient, VisibleAnywhere, Category="2. Debug", meta=(DisplayThumbnail=false)) + UMounteaBaseUserWidget* EquipmentUI; - UPROPERTY() + UPROPERTY(Transient, VisibleAnywhere, Category="2. Debug", meta=(DisplayThumbnail=false)) int32 ReplicatedItemsKey = 0; #pragma endregion diff --git a/Source/MounteaInventoryEquipment/Public/Components/MounteaInventoryComponent.h b/Source/MounteaInventoryEquipment/Public/Components/MounteaInventoryComponent.h index 55506a3d..75aa3d06 100644 --- a/Source/MounteaInventoryEquipment/Public/Components/MounteaInventoryComponent.h +++ b/Source/MounteaInventoryEquipment/Public/Components/MounteaInventoryComponent.h @@ -53,8 +53,8 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryComponent : public UActorCo public: - virtual TSubclassOf GetInventoryWBPClass_Implementation() override; - virtual UMounteaBaseUserWidget* GetInventoryWBP_Implementation() override; + virtual TSubclassOf GetInventoryUIClass_Implementation() const override; + virtual UMounteaBaseUserWidget* GetInventoryUI_Implementation() const override; virtual bool LoadInventoryFromDataTable_Implementation(const UMounteaInventoryItemsTable* SourceTable) override; virtual void SaveInventory_Implementation() override; @@ -75,8 +75,8 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryComponent : public UActorCo virtual AActor* GetOwningActor_Implementation() const override; - virtual void SetInventoryWBPClass_Implementation(TSubclassOf NewInventoryWBPClass) override; - virtual void SetInventoryWBP_Implementation(UMounteaBaseUserWidget* NewWBP) override; + virtual void SetInventoryUIClass_Implementation(TSubclassOf NewInventoryWBPClass) override; + virtual void SetInventoryUI_Implementation(UMounteaBaseUserWidget* NewWBP) override; virtual void ProcessItemAction_Implementation(UMounteaInventoryItemAction* Action, UMounteaInventoryItemBase* Item, FMounteaDynamicDelegateContext Context) override; @@ -87,6 +87,7 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryComponent : public UActorCo virtual void SetOtherInventory_Implementation(const TScriptInterface& NewInventory) override; virtual bool SetInventoryFlags_Implementation() override; + virtual bool DoesHaveAuthority_Implementation() const override; public: @@ -243,6 +244,8 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryComponent : public UActorCo TArray RemovedItems; + //TODO: Settings? + const int32 ChunkSize = 100; #if WITH_EDITOR private: @@ -256,64 +259,4 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryComponent : public UActorCo }; -#undef LOCTEXT_NAMESPACE - -#pragma region Runnables - -class FItemSearchRunnable : public FRunnable -{ -public: - FItemSearchRunnable(const TArray& InItems, const FItemRetrievalFilter& InSearchFilter, TAtomic& InItemFound) - : Items(InItems), SearchFilter(InSearchFilter), ItemFound(InItemFound) {} - - virtual bool Init() override { return true; } - virtual uint32 Run() override; - virtual void Stop() override {} - -private: - const TArray& Items; - const FItemRetrievalFilter& SearchFilter; - TAtomic& ItemFound; -}; - -class FItemGetRunnable : public FRunnable -{ -public: - FItemGetRunnable(const TArray& InItems, const FItemRetrievalFilter& InSearchFilter, TAtomic& InFoundItem) - : Items(InItems), SearchFilter(InSearchFilter), ItemFound(false), FoundItem(InFoundItem) {} - - virtual bool Init() override { return true; } - virtual uint32 Run() override; - virtual void Stop() override {} - - bool IsItemFound() const { return ItemFound; } - UMounteaInventoryItemBase* GetFoundItem() const { return FoundItem.Load(); } - -private: - const TArray Items; - const FItemRetrievalFilter& SearchFilter; - bool ItemFound; - TAtomic& FoundItem; -}; - -class FItemsGetRunnable : public FRunnable -{ -public: - FItemsGetRunnable(const TArray& InItems, const FItemRetrievalFilter& InSearchFilter, TArray& InFoundItems) - : Items(InItems), SearchFilter(InSearchFilter), ItemFound(false), FoundItems(InFoundItems) {} - - virtual bool Init() override { return true; } - virtual uint32 Run() override; - virtual void Stop() override {} - - bool IsItemFound() const { return ItemFound; } - TArray& GetFoundItems() const { return FoundItems; } - -private: - const TArray& Items; - const FItemRetrievalFilter& SearchFilter; - bool ItemFound; - TArray& FoundItems; -}; - -#pragma endregion \ No newline at end of file +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/MounteaInventoryEquipment/Public/Definitions/MounteaEquipmentSlot.h b/Source/MounteaInventoryEquipment/Public/Definitions/MounteaEquipmentSlot.h index b5008fe1..e1f2b8be 100644 --- a/Source/MounteaInventoryEquipment/Public/Definitions/MounteaEquipmentSlot.h +++ b/Source/MounteaInventoryEquipment/Public/Definitions/MounteaEquipmentSlot.h @@ -63,6 +63,9 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaEquipmentSlot : public UObject UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|EquipmentSlot") FORCEINLINE bool IsEmpty() const { return ItemInSlot == nullptr; }; + UFUNCTION(Category="Mountea|EquipmentSlot") + void UpdateItem(UMounteaInventoryItemBase* NewItem); + FORCEINLINE int32 GetRepKey() const { return RepKey; }; protected: @@ -99,7 +102,8 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaEquipmentSlot : public UObject private: UFUNCTION() void OnRep_Slot(); - UFUNCTION() TArray GetSlotIDs() const; + UFUNCTION() + static TArray GetSlotIDs(); virtual bool IsSupportedForNetworking() const override; void MarkDirtyForReplication(); @@ -138,7 +142,7 @@ struct FMounteaEquipmentSlotData UMounteaEquipmentSlot* Slot; public: - + bool operator==(const FMounteaEquipmentSlotData& Other) const { return Slot == Other.Slot; diff --git a/Source/MounteaInventoryEquipment/Public/Definitions/MounteaInventoryItem.h b/Source/MounteaInventoryEquipment/Public/Definitions/MounteaInventoryItem.h index 9d5dc9cf..c9682712 100644 --- a/Source/MounteaInventoryEquipment/Public/Definitions/MounteaInventoryItem.h +++ b/Source/MounteaInventoryEquipment/Public/Definitions/MounteaInventoryItem.h @@ -49,8 +49,9 @@ UCLASS(BlueprintType, Blueprintable, EditInlineNew, ClassGroup="Mountea", Displa class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryItemBase : public UDataAsset, public IMounteaInventoryEquipmentItem { GENERATED_BODY() - + UMounteaInventoryItemBase(); + virtual ~UMounteaInventoryItemBase() override; private: @@ -118,18 +119,13 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryItemBase : public UDataAsse { return ItemData; } UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory") - FORCEINLINE TArray GetItemActions() const - { - TArray ReturnValues; - for (const auto& Itr : ItemActions) - { - if (Itr.ItemAction && !ReturnValues.Contains(Itr.ItemAction)) - { - ReturnValues.Add(Itr.ItemAction); - } - } + TArray GetItemActions() const; + - return ReturnValues; + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory") + FORCEINLINE TArray GetItemActionsDefinitions() const + { + return ItemActions; } UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory") @@ -204,6 +200,8 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryItemBase : public UDataAsse virtual FItemGenericEvent& GetItemRemovedHandle() { return OnItemRemoved; }; + bool OwnerHasAuthority() const; + void NetFlush() { RepKey++; @@ -214,16 +212,19 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryItemBase : public UDataAsse FGameplayTag GetFirstTag() const { - return ItemData.CompatibleGameplayTags.First(); + return ItemData.ItemFlags.First(); }; FGameplayTagContainer GetTags() const { - return ItemData.CompatibleGameplayTags; + return ItemData.ItemFlags; }; UFUNCTION(BlueprintCallable, Category="Mountea|Item") virtual void SetWorldFromLevel(ULevel* FromLevel); + UFUNCTION(BlueprintCallable, Category="Mountea|Item") + void InitializeItemActions(); + virtual void SetWorld(UWorld* NewWorld); UFUNCTION(BlueprintCallable, Category="Mountea|Item") @@ -269,6 +270,8 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryItemBase : public UDataAsse void ClearMappedValues(); void CopyTagsFromTypes(); void EnsureValidConfig(); + + void PostWorldCreated(UWorld* NewWorld); #if WITH_EDITOR diff --git a/Source/MounteaInventoryEquipment/Public/Definitions/MounteaInventoryItemCategory.h b/Source/MounteaInventoryEquipment/Public/Definitions/MounteaInventoryItemCategory.h index 8457aed7..0b2e44fd 100644 --- a/Source/MounteaInventoryEquipment/Public/Definitions/MounteaInventoryItemCategory.h +++ b/Source/MounteaInventoryEquipment/Public/Definitions/MounteaInventoryItemCategory.h @@ -12,7 +12,7 @@ /** * Mountea Inventory Category * - * Defines Category. + * Defines Category * Is Assigned to Inventory Items to sort them to Categories. */ UCLASS( BlueprintType, Blueprintable, EditInlineNew, ClassGroup="Mountea") @@ -53,6 +53,12 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryItemCategory : public UData return ReturnValues; } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory") + FORCEINLINE TArray GetCategoryActionsDefinitions() const + { + return CategoryActions.Array(); + } }; #undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/MounteaInventoryEquipment/Public/Definitions/MounteaItemAction.h b/Source/MounteaInventoryEquipment/Public/Definitions/MounteaItemAction.h index ce657a29..735b5252 100644 --- a/Source/MounteaInventoryEquipment/Public/Definitions/MounteaItemAction.h +++ b/Source/MounteaInventoryEquipment/Public/Definitions/MounteaItemAction.h @@ -48,6 +48,12 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryItemAction : public UObject FORCEINLINE UTexture2D* GetActionIcon() const { return ActionIcon; }; + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|ItemAction") + FORCEINLINE UMounteaInventoryItemBase* GetOwningItem() const + { + return OwningItem; + } + UFUNCTION(BlueprintCallable, Category="Mountea|ItemAction") virtual void SetWorldFromLevel(ULevel* FromLevel); @@ -80,6 +86,8 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryItemAction : public UObject UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|ItemAction") FORCEINLINE FMounteaDynamicDelegateContext GetActionContext() const { return ActionContext; } + + void CopyFromOther(const UMounteaInventoryItemAction* OtherAction); protected: diff --git a/Source/MounteaInventoryEquipment/Public/Definitions/MounteaItemAdditionalData.h b/Source/MounteaInventoryEquipment/Public/Definitions/MounteaItemAdditionalData.h index 88110d6c..d0c9bbfa 100644 --- a/Source/MounteaInventoryEquipment/Public/Definitions/MounteaItemAdditionalData.h +++ b/Source/MounteaInventoryEquipment/Public/Definitions/MounteaItemAdditionalData.h @@ -7,7 +7,7 @@ #include "Engine/DataAsset.h" #include "Helpers/MounteaInventoryHelpers.h" -#include "Helpers/FMounteaTemplatesLibrary.h" + #include "MounteaItemAdditionalData.generated.h" @@ -64,16 +64,10 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaItemAdditionalData : public UDataAss static FMounteaItemDescription* GetRowData(const UMounteaInventoryItemsDescriptionsTable* FromTable, FName FromRow); UFUNCTION() - TArray GetSourceTableRows_ShortDescription() const - { - return GetSourceRows(SourceTable_ShortDescription); - } + TArray GetSourceTableRows_ShortDescription() const; UFUNCTION() - TArray GetSourceTableRows_LongDescription() const - { - return GetSourceRows(SourceTable_LongDescription); - } + TArray GetSourceTableRows_LongDescription() const; #if WITH_EDITOR virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; diff --git a/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryEquipmentBPF.h b/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryEquipmentBPF.h index 64864e1c..d5df39df 100644 --- a/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryEquipmentBPF.h +++ b/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryEquipmentBPF.h @@ -8,28 +8,19 @@ #include "Kismet/BlueprintFunctionLibrary.h" #include "MounteaInventoryHelpers.h" -#include "Components/MounteaInventoryComponent.h" - -#include "Definitions/MounteaInventoryItem.h" -#include "Definitions/MounteaItemAdditionalData.h" -#include "Definitions/MounteaInventoryItemRarity.h" -#include "Definitions/MounteaInventoryItemCategory.h" - -#include "Settings/MounteaInventoryEquipmentSettings.h" - -#include "WBP/MounteaTransactionPayload.h" -#include "WBP/MounteaBaseUserWidget.h" -#include "Helpers/FMounteaTemplatesLibrary.h" - -#include "Interfaces/MounteaInventoryInterface.h" -#include "Interfaces/MounteaInventorySlotWBPInterface.h" -#include "Interfaces/MounteaInventoryItemWBPInterface.h" -#include "Setup/MounteaInventoryConfig.h" - #include "MounteaInventoryEquipmentBPF.generated.h" +class UMounteaInventoryItemsTable; +class UMounteaInventoryEquipmentSettings; +class UMounteaInventoryThemeConfig; +class UMounteaInventoryConfig; +class UMounteaInventoryItemConfig; +struct FMounteaEquipmentSlotDataCompare; +struct FMounteaEquipmentSlotData; +class UMounteaEquipmentSlot; class IMounteaInventoryInterface; + /** * */ @@ -49,334 +40,117 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryEquipmentBPF : public UBlue * @return The inventory interface as a script interface of type IMounteaInventoryInterface. */ UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static TScriptInterface GetInventoryInterface(AActor* FromActor) - { - return GetInterfaceFrom>(FromActor); - } + static TScriptInterface GetInventoryInterface(AActor* FromActor); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(CompactNodeTitle="Is Valid", DisplayName="Is Valid", NativeBreakFunc)) - static bool ItemRetrievalFilter_IsValid(const FItemRetrievalFilter& Filter) - { - return Filter.IsValid(); - } + static bool ItemRetrievalFilter_IsValid(const FItemRetrievalFilter& Filter); #pragma region Converter UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc, CompactNodeTitle="Array Valid")) - static bool IsArrayValid(const TArray& Array) - { - return Array.Num() > 0; - } + static bool IsArrayValid(const TArray& Array); #pragma endregion #pragma region HelpersFunctions UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta = (ClassFilter = "Interface"), meta=(DeterminesOutputType = "InterfaceFilter")) - static UActorComponent* GetSingleComponentByInterface(const AActor* Target, TSubclassOf InterfaceFilter) - { - if (Target == nullptr) return nullptr; - - TArray TempComps = Target->GetComponentsByInterface(InterfaceFilter); - - if (TempComps.IsEmpty()) return nullptr; - - return TempComps[0]; - } + static UActorComponent* GetSingleComponentByInterface(const AActor* Target, TSubclassOf InterfaceFilter); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc, Keywords="valid,safe,null,check"), DisplayName="Is Valid (Inventory Ref)") - static bool IsInventoryValid(const TScriptInterface& InventoryInterface) - { - return InventoryInterface.GetObject() != nullptr; - } + static bool IsInventoryValid(const TScriptInterface& InventoryInterface); - UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc, Keywords="find,all")) - static TArray GetPurifiedItemActions(const UMounteaInventoryItemBase* Target) - { - if (!Target) return TArray(); - if (!Target->GetItemData().ItemCategory) return Target->GetItemActions(); - - TArray ReturnValues = Target->GetItemData().ItemCategory->GetCategoryActions(); - - for (auto const& Itr : Target->GetItemActions()) - { - if (Itr && !ReturnValues.Contains(Itr)) - { - ReturnValues.Add(Itr); - } - } - - return ReturnValues; - } - UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta = (ClassFilter = "Object"), meta=(DeterminesOutputType = "ClassFilter")) - static UObject* GetObjectByClass(UObject* Object, const TSubclassOf ClassFilter, bool& bResult) - { - if (ClassFilter == nullptr) - { - bResult = false; - return nullptr; - } - - if (Object == nullptr) - { - bResult = false; - return nullptr; - } - - if (Object->IsA(ClassFilter)) - { - bResult = true; - return Object; - } - - bResult = false; - return nullptr; - } + static UObject* GetObjectByClass(UObject* Object, const TSubclassOf ClassFilter, bool& bResult); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory") - static TSubclassOf GetThemeConfigClass() - { - if (GetSettings()->ThemeConfig) return GetSettings()->ThemeConfig->StaticClass(); + static TArray GetThemeConfigs(); - return nullptr; - } + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory") + static TArray GetThemeConfigsNames(); + + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory") + static UMounteaInventoryThemeConfig* GetThemeConfigByName(const FString& SearchName); + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory") + static TSubclassOf GetThemeConfigClass(); + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta = (ClassFilter = "MounteaInventoryThemeConfig"), meta=(DeterminesOutputType = "ClassFilter")) - static UMounteaInventoryThemeConfig* GetThemeConfig(const TSubclassOf ClassFilter, bool& bResult) - { - if (ClassFilter == nullptr) - { - bResult = false; - return nullptr; - } - - bResult = true; - const UMounteaInventoryEquipmentSettings* Settings = GetDefault(); - if (!Settings) - { - return NewObject(); - } - - if (Settings->ThemeConfig.IsNull()) - { - return NewObject(GetTransientPackage(), ClassFilter); - } - - auto const FoundTheme = Settings->ThemeConfig.LoadSynchronous(); - return FoundTheme->IsA(ClassFilter) ? FoundTheme : NewObject(GetTransientPackage(), ClassFilter); - } + static UMounteaInventoryThemeConfig* GetThemeConfig(const TSubclassOf ClassFilter, bool& bResult); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static TSubclassOf GetItemInventoryConfigClass(const TScriptInterface Target, const TSubclassOf ClassFilter, bool& bResult) - { - if (!Target) return nullptr; + static TSubclassOf GetItemInventoryConfigClass(const TScriptInterface Target, const TSubclassOf ClassFilter, bool& bResult); - return Target->Execute_GetInventoryConfigClass(Target.GetObject()); - } - UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static TSubclassOf GetItemItemConfigClass(const UMounteaInventoryItemBase* Target) - { - if (!Target) return nullptr; - - return Target->GetItemConfigClass(); - } + static TSubclassOf GetItemItemConfigClass(const UMounteaInventoryItemBase* Target); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta = (ClassFilter = "MounteaInventoryConfig"), meta=(DeterminesOutputType = "ClassFilter")) - static UMounteaInventoryConfig* GetInventoryConfig(const TScriptInterface Target, const TSubclassOf ClassFilter, bool& bResult) - { - if (ClassFilter == nullptr) - { - bResult = false; - return nullptr; - } - - if (Target == nullptr) - { - bResult = false; - return nullptr; - } - - return Target->Execute_GetInventoryConfig(Target.GetObject(), ClassFilter, bResult); - } - + static UMounteaInventoryConfig* GetInventoryConfig(const TScriptInterface Target, const TSubclassOf ClassFilter, bool& bResult); + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta = (ClassFilter = "MounteaInventoryItemConfig"), meta=(DeterminesOutputType = "ClassFilter")) - static UMounteaInventoryItemConfig* GetItemConfig(const UMounteaInventoryItemBase* Target, const TSubclassOf ClassFilter, bool& bResult) - { - if (ClassFilter == nullptr) - { - bResult = false; - return nullptr; - } - - if (Target == nullptr) - { - bResult = false; - return nullptr; - } - - return Target->GetItemConfig(ClassFilter, bResult); - } + static UMounteaInventoryItemConfig* GetItemConfig(const UMounteaInventoryItemBase* Target, const TSubclassOf ClassFilter, bool& bResult); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta = (ClassFilter = "MounteaItemAdditionalData"), meta=(DeterminesOutputType = "ClassFilter")) - static UMounteaItemAdditionalData* GetItemAdditionalData(const UMounteaInventoryItemBase* Target, const TSubclassOf ClassFilter, bool& bResult) - { - if (ClassFilter == nullptr) - { - bResult = false; - return nullptr; - } - - if (Target == nullptr) - { - bResult = false; - return nullptr; - } - - return Target->GetItemAdditionalData(ClassFilter, bResult); - } + static UMounteaItemAdditionalData* GetItemAdditionalData(const UMounteaInventoryItemBase* Target, const TSubclassOf ClassFilter, bool& bResult); + + static UMounteaEquipmentSlot* FindEquipmentSlot(const TArray& SlotsData, const FMounteaEquipmentSlotDataCompare& Filter); + static UMounteaEquipmentSlot* FindEquipmentSlot(const TArray& SlotsData, const FString& SlotID); + #pragma endregion #pragma region EditorFunctions UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static bool IsEditor() - { -#if WITH_EDITOR - return true; -#endif - - return false; - } + static bool IsEditor(); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static bool IsEditorNoPlay() - { - // This is to ensure we are not throwing InvalidWorld errors in Editor with no Gameplay. - bool bIsEditorCall = false; -#if WITH_EDITOR - if (GEditor != nullptr) - { - bIsEditorCall = !GEditor->GetPlayInEditorSessionInfo().IsSet(); - } -#endif - - return bIsEditorCall; - } + static bool IsEditorNoPlay(); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static bool IsShipping() - { - -#if UE_BUILD_SHIPPING - return true; -#endif + static bool IsShipping(); - return false; - } - #pragma endregion #pragma region SettingsFunctions UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static const UMounteaInventoryEquipmentSettings* GetSettings() - { - return GetDefault(); - } - - UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static UMounteaInventoryItemsTable* GetDefaultItemsTable() - { - return GetSettings()->DefaultInventoryItemDefinitionsTable.LoadSynchronous(); - } - + static const UMounteaInventoryEquipmentSettings* GetSettings(); + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static TSet GetAllowedCategories() - { - TSet ReturnValues; - for (auto Itr : GetSettings()->InventoryCategories) - { - ReturnValues.Add(Itr.LoadSynchronous()); - } + static UMounteaInventoryItemsTable* GetDefaultItemsTable(); - return ReturnValues; - } + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) + static TSet GetAllowedCategories(); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static TSet GetAllowedRarities() - { - TSet ReturnValues; - for (auto Itr : GetSettings()->InventoryRarities) - { - ReturnValues.Add(Itr.LoadSynchronous()); - } + static TSet GetAllowedRarities(); - return ReturnValues; - } - UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static TArray GetDragKeys() - { - return GetSettings()->DragKeys; - } + static TArray GetDragKeys(); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static TArray GetActionRequestKeys() - { - return GetSettings()->ActionRequestKeys; - } + static TArray GetActionRequestKeys(); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static TSoftClassPtr GetDefaultItemConfigClass() - { - return GetSettings()->DefaultItemConfigClass; - } + static TSoftClassPtr GetDefaultItemConfigClass(); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static bool UIDebug() - { - if (IsShipping()) - { - return false; - } - - if (const UMounteaInventoryEquipmentSettings* Settings = GetDefault()) - { - return Settings->bUIDebug; - } - - return false; - } + static bool UIDebug(); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static bool IsDragAllowed() - { - return GetSettings()->bDragDropAllowed; - } - + static bool IsDragAllowed(); + #pragma endregion #pragma region ThemeFunctions UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static FIntPoint GetInventoryDimensions() - { - bool bFound; - const auto Config = GetThemeConfig(UMounteaInventoryThemeConfig::StaticClass(), bFound); - return bFound ? Config->InventoryBaseSize : FIntPoint(6, 10); - } + static FIntPoint GetInventoryDimensions(); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static FIntPoint GetInventorySlotSize() - { - bool bFound; - const auto Config = GetThemeConfig(UMounteaInventoryThemeConfig::StaticClass(), bFound); - return bFound ? Config->SlotBaseSize : FIntPoint(16, 16); - } - + static FIntPoint GetInventorySlotSize(); + #pragma endregion #pragma region QuantityFunctions @@ -407,140 +181,26 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryEquipmentBPF : public UBlue #pragma region ItemFunctions UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc, Keywords="has,have,contain")) - static bool DoesHaveTag(const UMounteaInventoryItemBase* Item, const FGameplayTag Tag) - { - if (Item == nullptr) return false; - - return Item->GetTags().HasTag(Tag); - } + static bool DoesHaveTag(const UMounteaInventoryItemBase* Item, const FGameplayTag Tag); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory",meta=(NativeBreakFunc, Keywords="has,have,contain")) - static bool DoesHaveAnyTag(const UMounteaInventoryItemBase* Item, const FGameplayTagContainer Tags) - { - if (Item == nullptr) return false; - - return Item->GetTags().HasAny(Tags); - } + static bool DoesHaveAnyTag(const UMounteaInventoryItemBase* Item, const FGameplayTagContainer Tags); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc, Keywords="has,have,contain")) - static bool DoesHaveAllTags(const UMounteaInventoryItemBase* Item, const FGameplayTagContainer Tags) - { - if (Item == nullptr) return false; + static bool DoesHaveAllTags(const UMounteaInventoryItemBase* Item, const FGameplayTagContainer Tags); - return Item->GetTags().HasAll(Tags); - } - UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static TArray CalculateItemShadow(const FIntPoint& StartCoords, const FIntPoint& Area) - { - TSet Results; - - int32 X = StartCoords.X; - int32 Y = StartCoords.Y; - - for (int i = 0; i < Area.X; i++) - { - for (int j = 0; j < Area.Y; j++) - { - Results.Add(FIntPoint(X, Y)); - - Y++; - } - - X++; - Y = StartCoords.Y; - } - - return Results.Array(); - } + static TArray CalculateItemShadow(const FIntPoint& StartCoords, const FIntPoint& Area); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static bool IsValidShadow(const TArray& SlotsCoords, const TArray>& SlotsRefs, const TArray& Shadow, const TScriptInterface& MovedItem) - { - if (MovedItem.GetObject() == nullptr) - { - UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 00] Trying to move nothing!")) - return false; - } - - const FIntPoint Area = MovedItem->Execute_GetItemSize(MovedItem.GetObject()); - - - if (Shadow.Num() < FMath::Max(Area.X, Area.Y)) - { - UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 01] Trying to move outside Inventory grid!")) - return false; - } - - for (const auto& Itr : Shadow) - { - if (!SlotsCoords.Contains(Itr)) - { - UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 02] Shadow coords outsied Inventoyr grid!!")) - return false; - } - } - - TMap> Slots; - - //Collect slots under shadow - for (int i = 0; i < Shadow.Num(); i++) - { - const FIntPoint Coords = Shadow[i]; - - if (!SlotsCoords.Contains(Coords)) - { - UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 03] Shadow coords outsied Inventoyr grid!!")) - return false; - } - - if (!SlotsCoords.IsValidIndex(SlotsCoords.Find(Coords))) - { - UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 04] Shadow coords outsied Inventoyr grid!!")) - return false; - } - - const int CoordsIndex = SlotsCoords.Find(Coords); - - TScriptInterface Slot = SlotsRefs.IsValidIndex(CoordsIndex) ? SlotsRefs[CoordsIndex] : nullptr; - - Slots.Add(Coords, Slot); - } - - // Validate slot under shadow - for (const auto& Itr : Shadow) - { - if (!SlotsCoords.Contains(Itr)) - { - UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 05] Shadow coords outsied Inventoyr grid!!")) - return false; - } - - const TScriptInterface* Slot = Slots.Find(Itr); - if (!Slot->GetInterface()->Execute_IsSlotEmpty(Slot->GetObject()) ) - { - const TScriptInterface OccupyingItem = Slot->GetInterface()->Execute_GetOccupyingItem(Slot->GetObject()); - if (OccupyingItem != MovedItem) - { - UE_LOG(LogTemp, Warning, TEXT("[IsValidShadow - 06] Shadow occupied by different Item!!")) - return false; - } - } - } - - return true; - } + static bool IsValidShadow(const TArray& SlotsCoords, const TArray>& SlotsRefs, const TArray& Shadow, const TScriptInterface& MovedItem); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) - static bool IsSafeSlot(const FIntPoint& StartCoords, const FIntPoint& Area) - { - CalculateItemShadow(StartCoords, Area); - - return false; - } + static bool IsSafeSlot(const FIntPoint& StartCoords, const FIntPoint& Area); UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|Inventory", meta=(NativeBreakFunc)) static TArray ExcludeItems(const FItemRetrievalFilter& Filter, const TArray& ItemsToFilter); + #pragma endregion }; diff --git a/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryEquipmentConsts.h b/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryEquipmentConsts.h index bdaf6dec..740492c6 100644 --- a/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryEquipmentConsts.h +++ b/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryEquipmentConsts.h @@ -15,7 +15,7 @@ namespace MounteaInventoryEquipmentConsts const FString RefreshInventoryWidget (TEXT("RefreshInventoryWidget")); const FString RefreshItemsWidgets (TEXT("RefreshItemsWidgets")); - const FString RemoveItemWidget (TEXT("RemoveItemWidget")); + const FString RemoveItemWidget (TEXT("UnequipItemWidget")); } namespace ItemCommands @@ -31,8 +31,30 @@ namespace MounteaInventoryEquipmentConsts const FString ShowTooltip (TEXT("ShowTooltip")); const FString HideTooltip (TEXT("HideTooltip")); } + + namespace ItemActionCommands + { + const FString InitializeAction (TEXT("InitializeAction")); + } + + } + namespace MounteaEquipmentWidgetCommands + { + namespace EquipmentCommands + { + const FString InitializeEquipmentWidget (TEXT("InitializeEquipmentWidget")); + const FString CreateEquipmentWidget (TEXT("CreateEquipmentWidget")); + const FString ShowEquipmentWidget (TEXT("ShowEquipmentWidget")); + const FString HideEquipmentWidget (TEXT("HideEquipmentWidget")); + const FString RefreshEquipmentWidget (TEXT("RefreshEquipmentWidget")); + const FString RefreshItemsWidgets (TEXT("RefreshItemsWidgets")); + + const FString UnequipItemWidget (TEXT("UnequipItemWidget")); + const FString EquipItemWidget (TEXT("EquipItemWidget")); + } + } namespace MounteaInventoryNotifications { namespace InventoryNotifications diff --git a/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryHelpers.h b/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryHelpers.h index 498409cd..0dfe6343 100644 --- a/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryHelpers.h +++ b/Source/MounteaInventoryEquipment/Public/Helpers/MounteaInventoryHelpers.h @@ -148,8 +148,8 @@ struct FMounteaInventoryItemRequiredData { GENERATED_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(NoResetToDefault)) - FGameplayTagContainer CompatibleGameplayTags; + UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(NoResetToDefault), DisplayName="Item Flags (Gameplay Tags)") + FGameplayTagContainer ItemFlags; UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(NoResetToDefault)) FText ItemName = LOCTEXT("MounteaInventoryItem_ItemName", "New Item"); @@ -170,12 +170,12 @@ struct FMounteaInventoryItemRequiredData bool operator==(const FMounteaInventoryItemRequiredData& Other) const { - if (CompatibleGameplayTags.IsEmpty()) + if (ItemFlags.IsEmpty()) { return ItemName.EqualTo(Other.ItemName); } - return ItemName.EqualTo(Other.ItemName) && CompatibleGameplayTags == Other.CompatibleGameplayTags; + return ItemName.EqualTo(Other.ItemName) && ItemFlags == Other.ItemFlags; } bool operator!=(const FMounteaInventoryItemRequiredData& Other) const diff --git a/Source/MounteaInventoryEquipment/Public/Helpers/MounteaThemeConfigHelpers.cpp b/Source/MounteaInventoryEquipment/Public/Helpers/MounteaThemeConfigHelpers.cpp new file mode 100644 index 00000000..0e1a3eb5 --- /dev/null +++ b/Source/MounteaInventoryEquipment/Public/Helpers/MounteaThemeConfigHelpers.cpp @@ -0,0 +1 @@ +#include "MounteaThemeConfigHelpers.h" diff --git a/Source/MounteaInventoryEquipment/Public/Helpers/MounteaThemeConfigHelpers.h b/Source/MounteaInventoryEquipment/Public/Helpers/MounteaThemeConfigHelpers.h new file mode 100644 index 00000000..998d7c60 --- /dev/null +++ b/Source/MounteaInventoryEquipment/Public/Helpers/MounteaThemeConfigHelpers.h @@ -0,0 +1,77 @@ +// All rights reserved Dominik Pavlicek 2023. + +#pragma once + +#include "CoreMinimal.h" +#include "MounteaThemeConfigHelpers.generated.h" + +/** + * Helper structure exposing Widget text settings to set them globally in Dialogue Settings. + */ +USTRUCT(BlueprintType) +struct FTextSettings +{ + GENERATED_BODY() + + /** + * Slate Color Settings. + * Defines color of the Font for UI. + * Default: + * * Color: White + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Text Settings", meta=(DisplayName="Color and Oppacity")) + FSlateColor FontColor; + /** + * Slate Font Info settings. + * Should be filled by default with: + * * Font: Roboot + * * Size 16 + * * Typeface: 'Regular' + * * Outline: 1 + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Text Settings", meta=(ForceShowEngineContent)) + FSlateFontInfo SubtitlesFont; + /** + * Shadow Offset Settings. + * Defines shadow offset on X and Y axis. + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Text Settings") + FVector2D ShadowOffset; + /** + * Shadow Color Settings. + * Default: + * * Color: Black + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Text Settings") + FLinearColor ShadowColor; + + /** + * Settings GUID. + * Defines whether settings are valid or not. + * Invalid settings are: + * * With no Font + * + * Invalid settings are ignored! + */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Text Settings") + FGuid SettingsGUID; + +public: + + FTextSettings() : FontColor(FLinearColor::White), ShadowOffset(1.5f, 1.25f), ShadowColor(FLinearColor::Black) + { + SubtitlesFont = FCoreStyle::GetDefaultFontStyle("Regular", 16, FFontOutlineSettings(1)); + }; +}; + +USTRUCT(BlueprintType) +struct FMounteaThemeConfigRow : public FTableRowBase +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, Category="Text Brush") + FTextSettings CategoryTextBrush; + + UPROPERTY(EditAnywhere, Category="Icon Brush") + FSlateBrush CategoryIconsBrush; +}; \ No newline at end of file diff --git a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentInterface.h b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentInterface.h index 09c9d5a4..10014994 100644 --- a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentInterface.h +++ b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentInterface.h @@ -7,6 +7,7 @@ #include "UObject/Interface.h" #include "MounteaEquipmentInterface.generated.h" +class UMounteaEquipmentSlot; struct FMounteaEquipmentSlotData; struct FMounteaEquipmentSlots; class UMounteaInventoryItemBase; @@ -40,29 +41,46 @@ class MOUNTEAINVENTORYEQUIPMENT_API IMounteaEquipmentInterface public: - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Equipment") + AActor* GetOwningActor() const; + virtual AActor* GetOwningActor_Implementation() const = 0; + + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Equipment") FString FindSlotForItem(const UMounteaInventoryItemBase* Item) const; virtual FString FindSlotForItem_Implementation(const UMounteaInventoryItemBase* Item) const = 0; - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") - bool EquipItem(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); - virtual bool EquipItem_Implementation(const UMounteaInventoryItemBase* ItemToEquip,const FString& SlotID) = 0; + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Equipment") + UMounteaEquipmentSlot* FindSlotByID(const FString& SlotID) const; + virtual UMounteaEquipmentSlot* FindSlotByID_Implementation(const FString& SlotID) const = 0; + + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Equipment") + bool EquipItem(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); + virtual bool EquipItem_Implementation(UMounteaInventoryItemBase* ItemToEquip,const FString& SlotID) = 0; - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") - bool UnEquipItem(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); - virtual bool UnEquipItem_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) = 0; + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Equipment") + bool UnEquipItem(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); + virtual bool UnEquipItem_Implementation(UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) = 0; - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") - bool IsItemEquipped(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID); - virtual bool IsItemEquipped_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) = 0; + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Equipment") + bool IsItemEquipped(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) const; + virtual bool IsItemEquipped_Implementation(const UMounteaInventoryItemBase* ItemToEquip, const FString& SlotID) const = 0; - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Equipment") TArray GetAllSlots() const; virtual TArray GetAllSlots_Implementation() const = 0; - UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Equipment") bool CanEquipItem(const UMounteaInventoryItemBase* ItemToEquip) const; virtual bool CanEquipItem_Implementation(const UMounteaInventoryItemBase* ItemToEquip) const = 0; + + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Equipment") + UMounteaBaseUserWidget* GetEquipmentUI() const; + virtual UMounteaBaseUserWidget* GetEquipmentUI_Implementation() const = 0; + + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Equipment") + bool SetEquipmentUI(UMounteaBaseUserWidget* NewUI); + virtual bool SetEquipmentUI_Implementation(UMounteaBaseUserWidget* NewUI) = 0; + public: virtual FOnEquipmentUpdated& GetEquipmentUpdatedHandle() = 0; diff --git a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentSlotWBPInterface.h b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentSlotWBPInterface.h new file mode 100644 index 00000000..828d0942 --- /dev/null +++ b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentSlotWBPInterface.h @@ -0,0 +1,25 @@ +// All rights reserved Dominik Pavlicek 2023. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Interface.h" +#include "MounteaEquipmentSlotWBPInterface.generated.h" + +// This class does not need to be modified. +UINTERFACE(MinimalAPI, BlueprintType, Blueprintable) +class UMounteaEquipmentSlotWBPInterface : public UInterface +{ + GENERATED_BODY() +}; + +/** + * + */ +class MOUNTEAINVENTORYEQUIPMENT_API IMounteaEquipmentSlotWBPInterface +{ + GENERATED_BODY() + + // Add interface functions to this class. This is the class that will be inherited to implement this interface. +public: +}; diff --git a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentWBPInterface.h b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentWBPInterface.h index 228700c2..ec43d4e1 100644 --- a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentWBPInterface.h +++ b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaEquipmentWBPInterface.h @@ -6,6 +6,9 @@ #include "UObject/Interface.h" #include "MounteaEquipmentWBPInterface.generated.h" +class UMounteaEquipmentSlot; +class IMounteaEquipmentInterface; + // This class does not need to be modified. UINTERFACE(MinimalAPI, BlueprintType, Blueprintable) class UMounteaEquipmentWBPInterface : public UInterface @@ -22,4 +25,12 @@ class MOUNTEAINVENTORYEQUIPMENT_API IMounteaEquipmentWBPInterface // Add interface functions to this class. This is the class that will be inherited to implement this interface. public: + + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Mountea|Equipment") + TScriptInterface GetOwningEquipment() const; + virtual TScriptInterface GetOwningEquipment_Implementation() const = 0; + + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Mountea|Equipment") + void SetOwningEquipment(const TScriptInterface& OwningEquipment); + virtual void SetOwningEquipment_Implementation(const TScriptInterface& OwningEquipment) = 0; }; diff --git a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryInterface.h b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryInterface.h index 551d44f9..91dbcb69 100644 --- a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryInterface.h +++ b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryInterface.h @@ -43,20 +43,20 @@ class MOUNTEAINVENTORYEQUIPMENT_API IMounteaInventoryInterface public: UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") - TSubclassOf GetInventoryWBPClass(); - virtual TSubclassOf GetInventoryWBPClass_Implementation() = 0; + TSubclassOf GetInventoryUIClass() const; + virtual TSubclassOf GetInventoryUIClass_Implementation() const = 0; UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") - void SetInventoryWBPClass(TSubclassOf NewInventoryWBPClass); - virtual void SetInventoryWBPClass_Implementation(TSubclassOf NewInventoryWBPClass) = 0; + void SetInventoryUIClass(TSubclassOf NewInventoryUIClass); + virtual void SetInventoryUIClass_Implementation(TSubclassOf NewInventoryUIClass) = 0; UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") - void SetInventoryWBP(UMounteaBaseUserWidget* NewWBP); - virtual void SetInventoryWBP_Implementation(UMounteaBaseUserWidget* NewWBP) = 0; + void SetInventoryUI(UMounteaBaseUserWidget* NewUI); + virtual void SetInventoryUI_Implementation(UMounteaBaseUserWidget* NewUI) = 0; UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") - UMounteaBaseUserWidget* GetInventoryWBP(); - virtual UMounteaBaseUserWidget* GetInventoryWBP_Implementation() = 0; + UMounteaBaseUserWidget* GetInventoryUI() const; + virtual UMounteaBaseUserWidget* GetInventoryUI_Implementation() const = 0; UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") bool LoadInventoryFromDataTable(const class UMounteaInventoryItemsTable* SourceTable); @@ -149,6 +149,10 @@ class MOUNTEAINVENTORYEQUIPMENT_API IMounteaInventoryInterface UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") bool SetInventoryFlags(); virtual bool SetInventoryFlags_Implementation() = 0; + + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Mountea|Inventory") + bool DoesHaveAuthority() const; + virtual bool DoesHaveAuthority_Implementation() const = 0; public: diff --git a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryItemWBPInterface.h b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryItemWBPInterface.h index c125e08d..581e9977 100644 --- a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryItemWBPInterface.h +++ b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryItemWBPInterface.h @@ -6,6 +6,7 @@ #include "UObject/Interface.h" #include "MounteaInventoryItemWBPInterface.generated.h" +class UMounteaBaseUserWidget; class UMounteaInventoryItemBase; // This class does not need to be modified. UINTERFACE(MinimalAPI, BlueprintType, Blueprintable) @@ -25,6 +26,9 @@ class MOUNTEAINVENTORYEQUIPMENT_API IMounteaInventoryItemWBPInterface UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="Mountea|Inventory") UMounteaInventoryItemBase* GetItem() const; + + UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="Mountea|Inventory") + UMounteaBaseUserWidget* GetItemUI() const; UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="Mountea|Inventory") FIntPoint GetRootCoords(); diff --git a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryWBPInterface.h b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryWBPInterface.h index d5c63249..2b4e4f16 100644 --- a/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryWBPInterface.h +++ b/Source/MounteaInventoryEquipment/Public/Interfaces/MounteaInventoryWBPInterface.h @@ -9,6 +9,7 @@ #include "MounteaInventoryWBPInterface.generated.h" +class IMounteaInventoryItemWBPInterface; class IMounteaInventoryInterface; struct FInventoryNotificationData; @@ -33,14 +34,18 @@ class MOUNTEAINVENTORYEQUIPMENT_API IMounteaInventoryWBPInterface virtual void CreateInventoryNotification_Implementation(const FInventoryNotificationData& NotificationData) = 0; UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Mountea|Inventory") - bool GetInventoryVisibility(); - virtual bool GetInventoryVisibility_Implementation() = 0; + bool GetInventoryVisibility() const; + virtual bool GetInventoryVisibility_Implementation() const = 0; UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Mountea|Inventory") - TScriptInterface GetOwningInventory(); - virtual TScriptInterface GetOwningInventory_Implementation() = 0; + TScriptInterface GetOwningInventory() const; + virtual TScriptInterface GetOwningInventory_Implementation() const = 0; UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Mountea|Inventory") void SetOwningInventory(const TScriptInterface& OwningInventory); virtual void SetOwningInventory_Implementation(const TScriptInterface& OwningInventory) = 0; + + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Mountea|Inventory") + TScriptInterface FindItemUI(const UMounteaInventoryItemBase* ForItem, bool& bFound) const; + virtual TScriptInterface FindItemUI_Implementation(const UMounteaInventoryItemBase* ForItem, bool& bFound) const = 0; }; diff --git a/Source/MounteaInventoryEquipment/Public/Settings/ContentTheme.h b/Source/MounteaInventoryEquipment/Public/Settings/ContentTheme.h new file mode 100644 index 00000000..4445e6d2 --- /dev/null +++ b/Source/MounteaInventoryEquipment/Public/Settings/ContentTheme.h @@ -0,0 +1,371 @@ +// All rights reserved Dominik Pavlicek 2023. + +#pragma once + +#include "CoreMinimal.h" + +#include "Definitions/MounteaInventoryItemCategory.h" +#include "Engine/DataAsset.h" +#include "Helpers/MounteaThemeConfigHelpers.h" +#include "ContentTheme.generated.h" + +#define LOCTEXT_NAMESPACE "ContentTheme" + +USTRUCT(BlueprintType) +struct FContentThemeData +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Instanced, Category = "Inventory", meta=(NoResetToDefault, AllowAbstract=false, BlueprintBaseOnly=true)) + class UContentTheme* ContentTheme = nullptr; + +public: + + bool operator==(const FContentThemeData& Other) const + { + return ContentTheme == Other.ContentTheme; + } + + friend uint32 GetTypeHash(const FContentThemeData& Data) + { + return Data.ContentTheme ? GetTypeHash(Data.ContentTheme) : 0; + } +}; + +USTRUCT(BlueprintType) +struct FCategoryThemeData +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Instanced, Category = "Inventory", meta=(NoResetToDefault, AllowAbstract=false, BlueprintBaseOnly=true)) + class UCategoryTheme* CategoryTheme = nullptr; + +public: + + bool operator==(const FCategoryThemeData& Other) const + { + return CategoryTheme == Other.CategoryTheme; + } + + friend uint32 GetTypeHash(const FCategoryThemeData& Data) + { + return Data.CategoryTheme ? GetTypeHash(Data.CategoryTheme) : 0; + } +}; + +USTRUCT(BlueprintType) +struct FTextThemeData +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Instanced, Category = "Inventory", meta=(NoResetToDefault, AllowAbstract=false, BlueprintBaseOnly=true)) + class UTextTheme* TextTheme = nullptr; + +public: + + bool operator==(const FTextThemeData& Other) const + { + return TextTheme == Other.TextTheme; + } + + friend uint32 GetTypeHash(const FTextThemeData& Data) + { + return Data.TextTheme ? GetTypeHash(Data.TextTheme) : 0; + } +}; + +USTRUCT(BlueprintType) +struct FColoursThemeData +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Instanced, Category = "Inventory", meta=(NoResetToDefault, AllowAbstract=false, BlueprintBaseOnly=true)) + class UColoursTheme* ColoursTheme = nullptr; + +public: + + bool operator==(const FColoursThemeData& Other) const + { + return ColoursTheme == Other.ColoursTheme; + } + + friend uint32 GetTypeHash(const FColoursThemeData& Data) + { + return Data.ColoursTheme ? GetTypeHash(Data.ColoursTheme) : 0; + } +}; + +/** + * UContentTheme + * + * This class acts as a foundational DataAsset, designed to encapsulate various theme settings + * that pertain to content styling and presentation. Given its role as a base class, UContentTheme establishes + * a standard structure and provides a common set of properties that all themed configurations should possess. + * + * The primary motivation behind UContentTheme is to offer a unified and consistent approach to theming across + * different areas of our application, ensuring a harmonized visual and functional experience for the end-users. + * + * Key Features: + * 1. **Extensibility**: Derived classes can augment and specialize the base properties, tailoring theme configurations + * to specific needs. This allows for rich, diverse theming capabilities without deviating from the established core structure. + * 2. **Blueprint-friendly**: Not just limited to C++, UContentThemeConfig is designed to be extended via Blueprints. This + * empowers designers and other non-programming team members to create and experiment with new theme variations with ease. + * 3. **Centralized Theme Management**: By using UInventoryThemeConfig, container for UContentThemeConfigs, we ensure that + * theme configurations for inventory and related UI elements are maintained centrally, promoting consistency and ease of updates. + * + * Usage: + * - Create a new C++ or Blueprint class derived from UContentThemeConfig. + * - Expand upon the base properties or create new ones to cater to the specific theme requirements. + * - Use the derived class within the application, ensuring a consistent and theme-adherent presentation. + * + * Note: As this class is intended to store static data, any dynamic theming or real-time adjustments should be handled + * externally, with the results then applied in accordance with the configurations defined in the relevant UContentTheme derivative. + */ +UCLASS( Abstract, Blueprintable, EditInlineNew, BlueprintType, ClassGroup=("Mountea"), AutoExpandCategories=("Mountea, Inventory"), DisplayName="Content Theme Config") +class MOUNTEAINVENTORYEQUIPMENT_API UContentTheme : public UDataAsset +{ + GENERATED_BODY() + +}; + +/** + * UCategoryThemeConfig + * + * A specialized theme configuration tailored for category-specific content presentation within the inventory system. + * This class extends the base UContentThemeConfig to provide further customization and theming options specific to inventory categories. + * It allows designers and developers to define the visual and interactive characteristics of category elements, ensuring consistent and theme-driven user experiences. + * + * This configuration includes settings for: + * - Category Text: Defines the font, color, and other text-related settings for displaying category names or descriptions. + * - Category Style: Determines the visual appearance, including images and material effects, for category backgrounds, borders, or icons. + * + * By being Blueprintable, users can create unique instances of this theme configuration through Blueprints, allowing easy and flexible customization without diving into C++. + * + * Usage: + * Attach an instance of this configuration to the UInventoryThemeConfig or any relevant class to apply theme settings. + * + * @see UContentThemeConfig + * @see UInventoryThemeConfig + */ +UCLASS( DisplayName="Category Theme Config") +class MOUNTEAINVENTORYEQUIPMENT_API UCategoryTheme : public UContentTheme +{ + GENERATED_BODY() + +public: + + /** The specific inventory item category this theme config pertains to. */ + UPROPERTY(EditAnywhere, Category="Theme Config") + UMounteaInventoryItemCategory* Category = nullptr; + + /** Defines the appearance settings for the category, such as backgrounds, borders, or icons. */ + UPROPERTY(EditAnywhere, Category="Theme Config") + class UImageTheme* CategoryStyle = nullptr; + + /** Adjusts the position of the category's icon. Used only for specific UImageStyle with Texture Atlas. */ + UPROPERTY(EditAnywhere, Category="Theme Config") + FVector2D CategoryIconOffset; + + /** Allows for overriding the default text theme for this specific category. */ + UPROPERTY(EditAnywhere, Category="Theme Config|Override") + FTextThemeData TextThemeOverride; +}; + +/** + * UTextTheme + * + * A theme configuration dedicated specifically for styling text elements within the application. + * UTextTheme provides detailed customization options for both primary and secondary text styles, + * allowing developers and designers to ensure consistency and thematic coherence in text presentations. + * + * This configuration encapsulates: + * - Primary Text: Settings related to the font, color, and other visual attributes for main or headline text. + * - Secondary Text: Settings for text that might act as subtitles, descriptions, or any secondary information. + * + * Given its Blueprintable nature, users can effortlessly spawn unique instances of this theme configuration directly from the Blueprint Editor. + * This promotes rapid iterations and experiments with text themes without the necessity of C++ involvement. + * + * Usage: + * Integrate an instance of this theme configuration into the relevant classes, like UInventoryThemeConfig, to enforce the defined text styles. + * + * @see UContentTheme + * @see UInventoryThemeConfig + */ +UCLASS( DisplayName="Text Theme Config") +class MOUNTEAINVENTORYEQUIPMENT_API UTextTheme : public UContentTheme +{ + GENERATED_BODY() + +public: + + /** Styling settings for primary text elements. */ + UPROPERTY(EditAnywhere, Category="Primary Text Theme") + FTextSettings PrimaryTextTheme; + + /** Styling settings for secondary or less emphasized text elements. */ + UPROPERTY(EditAnywhere, Category="Secondary Text Theme") + FTextSettings SecondaryTextTheme; +}; + +/** + * UImageTheme + * + * A dedicated theme configuration focused on the visual styling of image elements within the application. + * UImageTheme provides a centralized setting to dictate the appearance and presentation of images, + * ensuring consistent visual treatment and thematic alignment across various UI and content elements. + * + * The key configuration encapsulated within this class includes: + * - Image Style: Governs the visual attributes like texture, tint, and material effects for the images. + * This primary setting ensures that all images adhere to the established visual guidelines and thematic constraints. + * + * With its Blueprintable attribute, users can create unique variations of this theme configuration directly from the Blueprint Editor, + * facilitating quick iterations and visual tweaks without delving into C++. + * + * Usage: + * Integrate an instance of this theme configuration into the relevant classes to apply the defined image style consistently across the application. + * + * @see UContentTheme + * @see UInventoryThemeConfig + */ +UCLASS( DisplayName="Image Theme Config") +class MOUNTEAINVENTORYEQUIPMENT_API UImageTheme : public UContentTheme +{ + GENERATED_BODY() + +public: + + /** The primary appearance settings for images. */ + UPROPERTY(EditAnywhere, Category="Text Brush") + FSlateBrush ImageStyle; +}; + +/** + * UColoursTheme + * + * A specialized theme configuration centered on defining a color palette for the application. The UColoursTheme + * provides a comprehensive set of colors, from primary to quaternary, ensuring that designers and developers + * have a consistent and harmonious color set to work with throughout the UI and content spaces. + * + * Each color within this configuration serves a distinct purpose: + * - Primary Color: The mainstay of the UI. It represents primary actions, elements in focus, and main highlights. + * - Secondary Color: A backdrop shade, typically used for background fills, secondary components, or elements in a passive state. + * - Tertiary Color: A supplementary hue for elements like hover states, accents, or any intermediate UI component that requires differentiation. + * - Quaternary Color: An auxiliary color that can be utilized for specific theming needs, such as borders, outlines, or unique accents. + * + * Being Blueprintable, this configuration can be tweaked and iterated upon directly from the Blueprint Editor. This flexibility ensures + * that UI/UX designers can experiment and finalize the color theme without the need to modify C++ code. + * + * Usage: + * Integrate an instance of this theme configuration into the relevant classes to apply the defined color palette consistently + * across various UI and content sections of the application. + * + * @see UContentTheme + * @see UInventoryThemeConfig + */ +UCLASS( DisplayName="Colours Theme Config") +class MOUNTEAINVENTORYEQUIPMENT_API UColoursTheme : public UContentTheme +{ + GENERATED_BODY() + +public: + + /** The primary color typically used for primary UI elements and highlights. */ + UPROPERTY(EditAnywhere, Category="Colours", meta=(DisplayPriority=-100)) + FLinearColor PrimaryColor = FLinearColor(1,0.863157,0.502886); + + /** A secondary color used for background fills, secondary UI elements, or passive elements. */ + UPROPERTY(EditAnywhere, Category="Colours", meta=(DisplayPriority=-50)) + FLinearColor SecondaryColor = FLinearColor(0.230740,0.187821,0.122139); + + /** Used for tertiary purposes, such as hover states, accents, or other intermediate UI elements. */ + UPROPERTY(EditAnywhere, Category="Colours", meta=(DisplayPriority=-10)) + FLinearColor TertiaryColor = FLinearColor(1,1,1); + + /** A fourth-tier color that can be used for additional UI theming, like borders, outlines, or specific accents. */ + UPROPERTY(EditAnywhere, Category="Colours", meta=(DisplayPriority=-1)) + FLinearColor QuaternaryColor = FLinearColor(0.693872,0.351533,0.008568); +}; + +/** + * UButtonTheme + * + * A dedicated theme configuration tailored for button elements within the application. The UButtonTheme focuses on + * providing customization settings to define the appearance, behavior, and overall style of button elements, ensuring + * a consistent and visually appealing user interaction across different areas of the application. + * + * The configuration encapsulates: + * - Button Style: This captures the visual representation of the button, including its default state, hovered state, + * pressed state, and more. It also can incorporate information like padding, font, and color settings, allowing + * for a comprehensive customization of button appearances. + * + * As with other theme configurations, UButtonTheme is Blueprintable, enabling designers to adjust and set button styles + * directly from the Blueprint Editor without the need to edit C++ code. This encourages rapid iterations and flexibility + * in UI design, allowing for easy adaptability and refinements. + * + * Usage: + * Integrate an instance of this theme configuration into the relevant classes or UI components where button styling + * needs to be applied. This ensures uniformity in button appearances and interactions across the application. + * + * @see UContentTheme + * @see UInventoryThemeConfig + */ +UCLASS( DisplayName="Button Theme Config") +class MOUNTEAINVENTORYEQUIPMENT_API UButtonTheme : public UContentTheme +{ + GENERATED_BODY() + +public: + + /** The primary appearance settings for images. */ + UPROPERTY(EditAnywhere, Category="Button Brush") + FButtonStyle ButtonStyle; +}; + +/** + * USlotTheme + * + * This theme configuration is specifically crafted for inventory slots, enabling customization of various layers + * within each slot. A slot in inventory or UI systems often has multiple visual elements layered together to create + * a rich and interactive appearance. The USlotTheme offers a structured way to theme these layers, ensuring visual + * consistency across all slots in the application. + * + * The configuration covers the following layers: + * - Primary Slot Layer: This forms the base or background layer of the slot, often used for the main appearance. + * - Secondary Slot Layer: This sits atop the primary layer, possibly representing additional design elements or subtle details. + * - Tertiary Slot Layer: Another layer for decorative or functional purposes, such as hover effects or highlight states. + * - Quaternary Slot Layer: The top-most layer which can be used for special accents, borders, or additional overlays. + * + * Given its Blueprintable nature, designers can easily customize the look and feel of slots directly within the + * Blueprint Editor, facilitating quick iterations and real-time visual feedback. This level of customization ensures + * that slots in the application can be themed to match any desired aesthetic or design language. + * + * Usage: + * For any UI component or system that utilizes slots, apply an instance of this theme configuration to achieve the + * desired slot appearance. Combining multiple layers provides depth and richness to the slot design, enhancing + * user experience. + * + * @see UContentTheme + * @see UInventoryThemeConfig + */ +UCLASS( DisplayName="Slot Theme Config") +class MOUNTEAINVENTORYEQUIPMENT_API USlotTheme : public UContentTheme +{ + GENERATED_BODY() + +public: + + + UPROPERTY(EditAnywhere, Category="Slot Brush") + FSlateBrush PrimarySlotLayer; + + UPROPERTY(EditAnywhere, Category="Slot Brush") + FSlateBrush SecondarySlotLayer; + + UPROPERTY(EditAnywhere, Category="Slot Brush") + FSlateBrush TertiarySlotLayer; + + UPROPERTY(EditAnywhere, Category="Slot Brush") + FSlateBrush QuaternarySlotLayer; +}; + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/MounteaInventoryEquipment/Public/Settings/MounteaEquipmentConfigData.h b/Source/MounteaInventoryEquipment/Public/Settings/MounteaEquipmentConfigData.h new file mode 100644 index 00000000..2bdb2d90 --- /dev/null +++ b/Source/MounteaInventoryEquipment/Public/Settings/MounteaEquipmentConfigData.h @@ -0,0 +1,25 @@ +// All rights reserved Dominik Pavlicek 2023. + +#pragma once + +#include "CoreMinimal.h" +#include "GameplayTagContainer.h" +#include "Engine/DataAsset.h" +#include "MounteaEquipmentConfigData.generated.h" + +/** + * + */ +UCLASS( Blueprintable, BlueprintType, EditInlineNew, ClassGroup=("Mountea"), AutoExpandCategories=("Mountea, Inventory"), DisplayName="Mountea Equipment Data") +class MOUNTEAINVENTORYEQUIPMENT_API UMounteaEquipmentConfigData : public UDataAsset +{ + GENERATED_BODY() + +public: + + UPROPERTY(EditDefaultsOnly, Category = "1. Required", meta=(AllowAbstract=false, NoResetToDefault, DisplayThumbnail=false)) + TMap CompatibleInventoryFlags; + + UPROPERTY(EditDefaultsOnly, Category = "1. Required", meta=(AllowAbstract=false, NoResetToDefault, DisplayThumbnail=false)) + TMap EquipmentSlotIDs; +}; diff --git a/Source/MounteaInventoryEquipment/Public/Settings/MounteaInventoryEquipmentSettings.h b/Source/MounteaInventoryEquipment/Public/Settings/MounteaInventoryEquipmentSettings.h index bda89af5..1cb4d11d 100644 --- a/Source/MounteaInventoryEquipment/Public/Settings/MounteaInventoryEquipmentSettings.h +++ b/Source/MounteaInventoryEquipment/Public/Settings/MounteaInventoryEquipmentSettings.h @@ -14,6 +14,7 @@ #define LOCTEXT_NAMESPACE "MounteaInventoryEquipmentSettings" +class UMounteaEquipmentConfigData; class UMounteaInventoryConfig; class UMounteaInventoryItemsTable; class UMounteaInventoryItemConfig; @@ -23,7 +24,7 @@ struct FItemUpdateResult; /** * */ -UCLASS(config = MounteaSettings, DisplayName="Mountea Inventory & Equipment Settings") +UCLASS(config = MounteaSettings, DefaultConfig, DisplayName="Mountea Inventory & Equipment Settings") class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryEquipmentSettings : public UDeveloperSettings { GENERATED_BODY() @@ -32,6 +33,9 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryEquipmentSettings : public public: + UPROPERTY(config, EditDefaultsOnly, Category = "1. Required", meta=(AllowAbstract=false, NoResetToDefault, DisplayThumbnail=false)) + TSet> ThemeConfigs; + UPROPERTY(config, EditDefaultsOnly, Category = "1. Required", meta=(AllowAbstract=false, NoResetToDefault, DisplayThumbnail=false)) TSoftObjectPtr ThemeConfig; @@ -55,12 +59,9 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryEquipmentSettings : public UPROPERTY(config, EditDefaultsOnly, Category = "1. Required", meta=(AllowAbstract=false, NoResetToDefault, DisplayThumbnail=false)) TSet> InventoryRarities; - - UPROPERTY(config, EditDefaultsOnly, Category = "1. Required", meta=(AllowAbstract=false, NoResetToDefault, DisplayThumbnail=false)) - TMap CompatibleInventoryFlags; - + UPROPERTY(config, EditDefaultsOnly, Category = "1. Required", meta=(AllowAbstract=false, NoResetToDefault, DisplayThumbnail=false)) - TMap EquipmentSlotIDs; + TSoftObjectPtr EquipmentConfigData; UPROPERTY(config, EditDefaultsOnly, Category = "2. Optional") uint8 bUIDebug : 1; @@ -70,6 +71,9 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryEquipmentSettings : public UPROPERTY(config, EditDefaultsOnly, Category = "2. User Interface") TSet InventoryWidgetCommands; + + UPROPERTY(config, EditDefaultsOnly, Category = "2. User Interface") + TSet EquipmentWidgetCommands; UPROPERTY(config, EditDefaultsOnly, Category = "2. User Interface") TMap InventoryUpdateMessages; @@ -176,6 +180,42 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryEquipmentSettings : public } } + if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UMounteaInventoryEquipmentSettings, EquipmentWidgetCommands)) + { + if (!EquipmentWidgetCommands.Contains(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::InitializeEquipmentWidget)) + { + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::InitializeEquipmentWidget); + } + if (!EquipmentWidgetCommands.Contains(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::CreateEquipmentWidget)) + { + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::CreateEquipmentWidget); + } + if (!EquipmentWidgetCommands.Contains(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::ShowEquipmentWidget)) + { + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::ShowEquipmentWidget); + } + if (!EquipmentWidgetCommands.Contains(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::HideEquipmentWidget)) + { + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::HideEquipmentWidget); + } + if (!EquipmentWidgetCommands.Contains(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::RefreshEquipmentWidget)) + { + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::RefreshEquipmentWidget); + } + if (!EquipmentWidgetCommands.Contains(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::RefreshItemsWidgets)) + { + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::RefreshItemsWidgets); + } + if (!EquipmentWidgetCommands.Contains(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::UnequipItemWidget)) + { + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::UnequipItemWidget); + } + if (!EquipmentWidgetCommands.Contains(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::EquipItemWidget)) + { + EquipmentWidgetCommands.Add(MounteaInventoryEquipmentConsts::MounteaEquipmentWidgetCommands::EquipmentCommands::EquipItemWidget); + } + } + if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UMounteaInventoryEquipmentSettings, ItemsWidgetCommands)) { if (!ItemsWidgetCommands.Contains(MounteaInventoryEquipmentConsts::MounteaInventoryWidgetCommands::ItemCommands::AddNewItem)) diff --git a/Source/MounteaInventoryEquipment/Public/Settings/MounteaInventoryThemeConfig.h b/Source/MounteaInventoryEquipment/Public/Settings/MounteaInventoryThemeConfig.h index 20a9fcec..413ee0f0 100644 --- a/Source/MounteaInventoryEquipment/Public/Settings/MounteaInventoryThemeConfig.h +++ b/Source/MounteaInventoryEquipment/Public/Settings/MounteaInventoryThemeConfig.h @@ -3,9 +3,12 @@ #pragma once #include "CoreMinimal.h" +#include "ContentTheme.h" #include "UObject/NoExportTypes.h" #include "MounteaInventoryThemeConfig.generated.h" +class UCategoryTheme; +class UMounteaBaseEquipmentSlotWidget; class UMounteaBaseUserWidget; /** @@ -22,9 +25,33 @@ UCLASS( Blueprintable, BlueprintType, EditInlineNew, ClassGroup=("Mountea"), Aut class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryThemeConfig : public UDataAsset { GENERATED_BODY() + + UMounteaInventoryThemeConfig(); public: + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Theme", meta=(ShowOnlyInnerProperties)) + class UTextTheme* TextTheme = nullptr; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Theme", meta=(ShowOnlyInnerProperties)) + class UColoursTheme* ColoursTheme = nullptr; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Theme|Categories", meta=(ShowOnlyInnerProperties)) + class UImageTheme* CategoryImageTheme = nullptr; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Theme|Categories", meta=(ShowOnlyInnerProperties)) + TSet CategoryThemes; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Theme|Buttons", meta=(ShowOnlyInnerProperties)) + TMap, UButtonTheme*> ButtonStyleThemes; + + // ---------------------------------------------------------------------------- // + // ---------------------------------------------------------------------------- // + // BELOW CODE IS OUTDATED AND WILL BE REMOVED // + // ---------------------------------------------------------------------------- // + // ---------------------------------------------------------------------------- // + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dimensions", meta=(ShowOnlyInnerProperties)) FIntPoint SlotBaseSize = FIntPoint(64,64); @@ -60,4 +87,25 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaInventoryThemeConfig : public UDataA UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Base Class|Actions", meta=(ShowOnlyInnerProperties, MustImplement="/Script/MounteaInventoryEquipment.MounteaItemActionWBPInterface")) TSubclassOf InventoryItemActionClass; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Base Class|Equipment", meta=(ShowOnlyInnerProperties, MustImplement="/Script/MounteaInventoryEquipment.MounteaEquipmentSlotWBPInterface")) + TSubclassOf EquipmentSlotClass; + +protected: + + void GenerateMissingThemes(); + +#if WITH_EDITOR + + virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; + virtual bool Rename(const TCHAR* NewName, UObject* NewOuter, ERenameFlags Flags) override; + +public: + virtual void GenerateMissingThemes_Editor(); + + UFUNCTION() + void Propagate_CategoryDefaultStyle(); + +#endif + }; \ No newline at end of file diff --git a/Source/MounteaInventoryEquipment/Public/WBP/MounteaBaseEquipmentSlotWidget.h b/Source/MounteaInventoryEquipment/Public/WBP/MounteaBaseEquipmentSlotWidget.h new file mode 100644 index 00000000..b485443e --- /dev/null +++ b/Source/MounteaInventoryEquipment/Public/WBP/MounteaBaseEquipmentSlotWidget.h @@ -0,0 +1,32 @@ +// All rights reserved Dominik Pavlicek 2023. + +#pragma once + +#include "CoreMinimal.h" +#include "Interfaces/MounteaEquipmentSlotWBPInterface.h" +#include "WBP/MounteaBaseUserWidget.h" +#include "MounteaBaseEquipmentSlotWidget.generated.h" + +/** + * + */ +UCLASS() +class MOUNTEAINVENTORYEQUIPMENT_API UMounteaBaseEquipmentSlotWidget : public UMounteaBaseUserWidget, public IMounteaEquipmentSlotWBPInterface +{ + GENERATED_BODY() + +public: + + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Mountea|EquipmentSlot") + FORCEINLINE FString GetSlotID() const { return SlotID; }; + +protected: + + UPROPERTY(Category="2. Required", EditInstanceOnly, BlueprintReadOnly, meta=(GetOptions="GetSlotIDOptions", NoResetToDefault)) + FString SlotID; + +private: + + UFUNCTION() + static TArray GetSlotIDOptions(); +}; diff --git a/Source/MounteaInventoryEquipment/Public/WBP/MounteaBaseUserWidget.h b/Source/MounteaInventoryEquipment/Public/WBP/MounteaBaseUserWidget.h index 1c41a174..19d0286a 100644 --- a/Source/MounteaInventoryEquipment/Public/WBP/MounteaBaseUserWidget.h +++ b/Source/MounteaInventoryEquipment/Public/WBP/MounteaBaseUserWidget.h @@ -81,8 +81,12 @@ class MOUNTEAINVENTORYEQUIPMENT_API UMounteaBaseUserWidget : public UUserWidget { GENERATED_BODY() +public: + UMounteaBaseUserWidget(const FObjectInitializer& ObjectInitializer); - + +protected: + virtual void NativeConstruct() override; virtual void NativeDestruct() override; diff --git a/Source/MounteaInventoryEquipment/Public/WBP/MounteaTransactionPayload.h b/Source/MounteaInventoryEquipment/Public/WBP/MounteaTransactionPayload.h index 9b628058..135992f1 100644 --- a/Source/MounteaInventoryEquipment/Public/WBP/MounteaTransactionPayload.h +++ b/Source/MounteaInventoryEquipment/Public/WBP/MounteaTransactionPayload.h @@ -13,5 +13,4 @@ UCLASS(Abstract, Blueprintable, BlueprintType, EditInlineNew, ClassGroup=("Mount class MOUNTEAINVENTORYEQUIPMENT_API UMounteaTransactionPayload : public UObject { GENERATED_BODY() - }; diff --git a/Source/MounteaInventoryEquipmentDeveloper/MounteaInventoryEquipmentDeveloper.build.cs b/Source/MounteaInventoryEquipmentDeveloper/MounteaInventoryEquipmentDeveloper.build.cs new file mode 100644 index 00000000..a2238f8b --- /dev/null +++ b/Source/MounteaInventoryEquipmentDeveloper/MounteaInventoryEquipmentDeveloper.build.cs @@ -0,0 +1,31 @@ +using UnrealBuildTool; + +public class MounteaInventoryEquipmentDeveloper : ModuleRules +{ + public MounteaInventoryEquipmentDeveloper(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + bEnforceIWYU = true; + + PrecompileForTargets = PrecompileTargetsType.None; + bPrecompile = false; + bUsePrecompiled = false; + + PublicDependencyModuleNames.AddRange + (new string[] + { + "Core", + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + "Projects", + + "BlueprintGraph", + "KismetCompiler", + "UnrealEd", + "ToolMenus" + } + ); + } +} \ No newline at end of file diff --git a/Source/MounteaInventoryEquipmentDeveloper/Private/K2Nodes/K2Node_DistinctArray.cpp b/Source/MounteaInventoryEquipmentDeveloper/Private/K2Nodes/K2Node_DistinctArray.cpp new file mode 100644 index 00000000..1528fcc5 --- /dev/null +++ b/Source/MounteaInventoryEquipmentDeveloper/Private/K2Nodes/K2Node_DistinctArray.cpp @@ -0,0 +1,697 @@ +// All rights reserved Dominik Pavlicek 2023. + + +#include "K2Nodes/K2Node_DistinctArray.h" + +#include "BlueprintActionDatabaseRegistrar.h" +#include "BlueprintNodeSpawner.h" +#include "EdGraphUtilities.h" +#include "KismetCastingUtils.h" +#include "KismetCompiledFunctionContext.h" +#include "KismetCompilerMisc.h" +#include "ToolMenu.h" +#include "Kismet/KismetArrayLibrary.h" +#include "Kismet2/CompilerResultsLog.h" + +#define LOCTEXT_NAMESPACE "DistinctArray" + +class FKCHandler_DistinctArray : public FNodeHandlingFunctor +{ + +protected: + EKismetCompiledStatementType CompiledStatementType; + +public: + FKCHandler_DistinctArray(FKismetCompilerContext& InCompilerContext) : FNodeHandlingFunctor(InCompilerContext) + { + CompiledStatementType = KCST_CallFunction ; + } + + virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) override + { + UK2Node_DistinctArray* ContainerNode = CastChecked(Node); + UEdGraphPin* OutputPin = ContainerNode->GetOutputPin(); + + FNodeHandlingFunctor::RegisterNets(Context, Node); + + // Create a local term to drop the container into + FBPTerminal* Term = Context.CreateLocalTerminalFromPinAutoChooseScope(OutputPin, Context.NetNameMap->MakeValidName(OutputPin)); + Term->bPassedByReference = false; + Term->Source = Node; + Context.NetMap.Add(OutputPin, Term); + } + + virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override + { + // 1. Retrieve all TArray Inputs + TArray InputArrays; + + for (UEdGraphPin* Pin : Node->Pins) + { + if (Pin && Pin->Direction == EGPD_Input) + { + FBPTerminal** InputTerm = Context.NetMap.Find(FEdGraphUtilities::GetNetFromPin(Pin)); + if (InputTerm) + { + InputArrays.Add(*InputTerm); + } + } + } + + // 2. Get the empty TArray Output + UK2Node_DistinctArray* DistinctArrayNode = CastChecked(Node); + UEdGraphPin* OutputPin = DistinctArrayNode->GetOutputPin(); + FBPTerminal* OutputArrayTerm = *Context.NetMap.Find(OutputPin); + check(OutputArrayTerm); + + FArrayProperty* OuterArr = CastField(OutputArrayTerm->AssociatedVarProperty); + if (!OuterArr) return; + + void* OuterArrVal = OuterArr->GetPropertyValuePtr_InContainer(OutputArrayTerm->Source); + if (!OuterArrVal) return; + + FScriptArrayHelper OutputArrayHelper(OuterArr, OuterArrVal); + //OutputArrayHelper.EmptyValues(); // Make sure the output array is empty + + /* + // 3. Add All Intersecting Values from All Inputs to the Output + for (FBPTerminal* ArrayTerm : InputArrays) + { + FArrayProperty* Arr = CastField(ArrayTerm->AssociatedVarProperty); + if (!Arr) continue; + + void* ArrVal = Arr->GetPropertyValuePtr_InContainer(ArrayTerm->Source); + if (!ArrVal) continue; + + FScriptArrayHelper InputArrayHelper(Arr, ArrVal); + FProperty* InnerProp = CastField(ArrayTerm->AssociatedVarProperty)->Inner; + + for (int32 SourceIndex = 0; SourceIndex < InputArrayHelper.Num(); ++SourceIndex) + { + void* SourceItem = InputArrayHelper.GetRawPtr(SourceIndex); + + bool bItemExistsInAllArrays = true; + + for (FBPTerminal* OtherArrayTerm : InputArrays) + { + if (OtherArrayTerm != ArrayTerm) // Don't compare with itself + { + FArrayProperty* OtherArr = CastField(OtherArrayTerm->AssociatedVarProperty); + if (!OtherArr) continue; + + void* OtherArrVal = Arr->GetPropertyValuePtr_InContainer(OtherArrayTerm->Source); + if (!OtherArrVal) continue; + + FScriptArrayHelper OtherArrayHelper(OtherArr, OtherArrVal); + + //FScriptArrayHelper OtherArrayHelper(CastField(OtherArrayTerm->AssociatedVarProperty), OtherArrayTerm->AssociatedVarProperty); + bool bItemFound = false; + + for (int32 OtherIndex = 0; OtherIndex < OtherArrayHelper.Num(); ++OtherIndex) + { + void* OtherItem = OtherArrayHelper.GetRawPtr(OtherIndex); + if (!OtherItem) continue; + + bItemFound = true; + /* + if (InnerProp->Identical(SourceItem, OtherItem)) + { + bItemFound = true; + break; + } + + } + + if (!bItemFound) + { + bItemExistsInAllArrays = false; + break; + } + } + } + + UE_LOG(LogTemp, Error, TEXT("ItemExistsInAllArrays: %s"), *FString( bItemExistsInAllArrays ? "TRUE" : "FALSE")) + if (bItemExistsInAllArrays) + { + bool bAlreadyInOutput = false; + for (int32 OutIdx = 0; OutIdx < OutputArrayHelper.Num(); ++OutIdx) + { + void* OutputItem = OutputArrayHelper.GetRawPtr(OutIdx); + /* + if (InnerProp->Identical(SourceItem, OutputItem)) + { + bAlreadyInOutput = true; + break; + } + } + + if (!bAlreadyInOutput) + { + //int32 NewIdx = OutputArrayHelper.AddValue(); + // InnerProp->CopySingleValueToScriptVM(OutputArrayHelper.GetRawPtr(NewIdx), SourceItem); + } + } + } + } + */ + } + + +}; + +UK2Node_DistinctArray::UK2Node_DistinctArray() +{ + MinNumInputs = 2; + NumInputs = 2; + ContainerType = EPinContainerType::Array; +} + +FText UK2Node_DistinctArray::GetNodeTitle(ENodeTitleType::Type TitleType) const +{ + return LOCTEXT("DistinctArray_Title", "Distinct Array"); +} + +FText UK2Node_DistinctArray::GetTooltipText() const +{ + return LOCTEXT("DistinctArray_Tooltip", "Return distinct (intersection) result of any specified arrays."); +} + +FLinearColor UK2Node_DistinctArray::GetNodeTitleColor() const +{ + return FLinearColor::Yellow; +} + +FLinearColor UK2Node_DistinctArray::GetNodeBodyTintColor() const +{ + return FLinearColor::Yellow; +} + +FSlateIcon UK2Node_DistinctArray::GetIconAndTint(FLinearColor& OutColor) const +{ + static const FSlateIcon Icon = FSlateIcon("MIEStyleSet", "MIEStyleSet.Icon.DistinctArray"); + return Icon; +} + +void UK2Node_DistinctArray::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const +{ + UK2Node::ValidateNodeDuringCompilation(MessageLog); + + const UEdGraphSchema_K2* Schema = Cast(GetSchema()); + UEdGraphPin* OutputPin = GetOutputPin();; + if (!ensure(Schema) || !ensure(OutputPin) || Schema->IsExecPin(*OutputPin)) + { + MessageLog.Error(*NSLOCTEXT("K2Node", "DistinctArray_OutputIsExec", "Unacceptable array type in @@").ToString(), this); + } +} + +void UK2Node_DistinctArray::PostReconstructNode() +{ + // Find a pin that has connections to use to jumpstart the wildcard process + FEdGraphPinType OutputPinType; + FEdGraphTerminalType OutputPinValueType; + + const bool bMapContainer = ContainerType == EPinContainerType::Map; + bool bFoundKey = false; + bool bFoundValue = !bMapContainer; + + UEdGraphPin* OutputPin = GetOutputPin(); + if (OutputPin->LinkedTo.Num() > 0) + { + OutputPinType = OutputPin->LinkedTo[0]->PinType; + bFoundKey = true; + + if (bMapContainer) + { + OutputPinValueType = OutputPin->LinkedTo[0]->PinType.PinValueType; + bFoundValue = true; + } + } + else + { + bool bKeyPin = !bMapContainer; + UEdGraphPin* CurrentTopParent = nullptr; + + check(Pins[0] == OutputPin); + for (int32 PinIndex = 1; PinIndex < Pins.Num() && (!bFoundKey || !bFoundValue); ++PinIndex) + { + if (UEdGraphPin* CurrentPin = Pins[PinIndex]) + { + if (CurrentPin->ParentPin == nullptr) + { + CurrentTopParent = CurrentPin; + if (bMapContainer) + { + bKeyPin = !bKeyPin; + } + } + + if ((bKeyPin && !bFoundKey) || (!bKeyPin && !bFoundValue)) + { + checkSlow((CurrentPin->ParentPin == nullptr) || (CurrentTopParent != nullptr)); + if (CurrentPin->LinkedTo.Num() > 0) + { + // The pin is linked, use its type as the type for the key or value type as appropriate + + // If this is a split pin, so we want to base the pin type on the parent rather than the linked to pin + const FEdGraphPinType& PinType = (CurrentPin->ParentPin ? CurrentTopParent->PinType : CurrentPin->LinkedTo[0]->PinType); + if (bKeyPin) + { + OutputPinType = PinType; + bFoundKey = true; + } + else + { + OutputPinValueType = FEdGraphTerminalType::FromPinType(PinType); + bFoundValue = true; + } + } + else if (!Pins[PinIndex]->DoesDefaultValueMatchAutogenerated()) + { + // The pin has user data in it, continue to use its type as the type for all pins. + + // If this is a split pin, so we want to base the pin type on the parent rather than this pin + const FEdGraphPinType& PinType = (CurrentPin->ParentPin ? CurrentTopParent->PinType : CurrentPin->PinType); + + if (bKeyPin) + { + OutputPinType = PinType; + bFoundKey = true; + } + else + { + OutputPinValueType = FEdGraphTerminalType::FromPinType(PinType); + bFoundValue = true; + } + } + } + } + } + } + + if (bFoundKey) + { + OutputPin->PinType = MoveTemp(OutputPinType); + } + else + { + OutputPin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard; + OutputPin->PinType.PinSubCategory = NAME_None; + OutputPin->PinType.PinSubCategoryObject = nullptr; + } + + if (bMapContainer) + { + if (bFoundValue) + { + OutputPin->PinType.PinValueType = MoveTemp(OutputPinValueType); + } + else + { + OutputPin->PinType.PinValueType.TerminalCategory = UEdGraphSchema_K2::PC_Wildcard; + OutputPin->PinType.PinValueType.TerminalSubCategory = NAME_None; + OutputPin->PinType.PinValueType.TerminalSubCategoryObject = nullptr; + } + } + + OutputPin->PinType.ContainerType = ContainerType; + PropagatePinType(); + + UK2Node::PostReconstructNode(); +} + +FText UK2Node_DistinctArray::GetKeywords() const +{ + return GetClass()->GetMetaDataText(TEXT("Keywords"), TEXT("UObjectKeywords"), GetClass()->GetFullGroupName(false)); +} + +void UK2Node_DistinctArray::NotifyPinConnectionListChanged(UEdGraphPin* Pin) +{ + UK2Node::NotifyPinConnectionListChanged(Pin); + + // Array to cache the input pins we might want to find these if we are removing the last link + TArray KeyPins; + TArray ValuePins; + GetKeyAndValuePins(KeyPins, ValuePins); + + auto CountLinkedPins = [](const TArray PinsToCount) + { + int32 LinkedPins = 0; + for (UEdGraphPin* CurrentPin : PinsToCount) + { + if (CurrentPin->LinkedTo.Num() > 0) + { + ++LinkedPins; + } + } + return LinkedPins; + }; + + // Was this the first or last connection? + const int32 NumKeyPinsWithLinks = CountLinkedPins(KeyPins); + const int32 NumValuePinsWithLinks = CountLinkedPins(ValuePins); + + UEdGraphPin* OutputPin = GetOutputPin(); + + bool bNotifyGraphChanged = false; + if (Pin->LinkedTo.Num() > 0) + { + if (Pin->ParentPin == nullptr) + { + if (Pin == OutputPin) + { + if (NumKeyPinsWithLinks == 0 && (OutputPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard && Pin->LinkedTo[0]->PinType.PinCategory != UEdGraphSchema_K2::PC_Wildcard)) + { + FEdGraphTerminalType TerminalType = MoveTemp(OutputPin->PinType.PinValueType); + OutputPin->PinType = Pin->LinkedTo[0]->PinType; + OutputPin->PinType.PinValueType = MoveTemp(TerminalType); + OutputPin->PinType.ContainerType = ContainerType; + bNotifyGraphChanged = true; + } + if (ContainerType == EPinContainerType::Map && NumValuePinsWithLinks == 0 && (OutputPin->PinType.PinValueType.TerminalCategory == UEdGraphSchema_K2::PC_Wildcard && Pin->LinkedTo[0]->PinType.PinValueType.TerminalCategory != UEdGraphSchema_K2::PC_Wildcard)) + { + OutputPin->PinType.PinValueType = Pin->LinkedTo[0]->PinType.PinValueType; + bNotifyGraphChanged = true; + } + } + else if (ValuePins.Contains(Pin)) + { + // Just made a connection to a value pin, was it the first? + if (NumValuePinsWithLinks == 1 && (OutputPin->PinType.PinValueType.TerminalCategory == UEdGraphSchema_K2::PC_Wildcard && Pin->LinkedTo[0]->PinType.PinCategory != UEdGraphSchema_K2::PC_Wildcard)) + { + // Update the types on all the pins + OutputPin->PinType.PinValueType = FEdGraphTerminalType::FromPinType(Pin->LinkedTo[0]->PinType); + bNotifyGraphChanged = true; + } + } + else + { + // Just made a connection to a key pin, was it the first? + if (NumKeyPinsWithLinks == 1 && (OutputPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard && Pin->LinkedTo[0]->PinType.PinCategory != UEdGraphSchema_K2::PC_Wildcard)) + { + FEdGraphTerminalType TerminalType = MoveTemp(OutputPin->PinType.PinValueType); + OutputPin->PinType = Pin->LinkedTo[0]->PinType; + OutputPin->PinType.PinValueType = MoveTemp(TerminalType); + OutputPin->PinType.ContainerType = ContainerType; + bNotifyGraphChanged = true; + } + } + } + } + else if (OutputPin->LinkedTo.Num() == 0) + { + // Return to wildcard if theres nothing in any of the input pins + TFunction&)> PinsInUse = [this, &PinsInUse](TArray& PinsToConsider) + { + bool bPinInUse = false; + for (UEdGraphPin* CurrentPin : PinsToConsider) + { + // Is there something in this pin? + if (CurrentPin->SubPins.Num() > 0 || !CurrentPin->DoesDefaultValueMatchAutogenerated()) + { + bPinInUse = true; + break; + } + } + return bPinInUse; + }; + + const bool bResetOutputPinPrimary = ((NumKeyPinsWithLinks == 0) && !PinsInUse(KeyPins)); + const bool bResetOutputPinSecondary = ((NumValuePinsWithLinks == 0) && !PinsInUse(ValuePins)); + + if (bResetOutputPinPrimary) + { + OutputPin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard; + OutputPin->PinType.PinSubCategory = NAME_None; + OutputPin->PinType.PinSubCategoryObject = nullptr; + + bNotifyGraphChanged = true; + } + if (bResetOutputPinSecondary && ContainerType == EPinContainerType::Map) + { + OutputPin->PinType.PinValueType.TerminalCategory = UEdGraphSchema_K2::PC_Wildcard; + OutputPin->PinType.PinValueType.TerminalSubCategory = NAME_None; + OutputPin->PinType.PinValueType.TerminalSubCategoryObject = nullptr; + + bNotifyGraphChanged = true; + } + } + + if (bNotifyGraphChanged) + { + PropagatePinType(); + GetGraph()->NotifyGraphChanged(); + } +} + +void UK2Node_DistinctArray::GetNodeContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context) const +{ + UK2Node::GetNodeContextMenuActions(Menu, Context); + + if (!Context->bIsDebugging) + { + FToolMenuSection& Section = Menu->AddSection("K2NodeMakeArray", NSLOCTEXT("K2Nodes", "DistinctArrayHeader", "DistinctArray")); + + /* TODO + if (Context->Pin != NULL) + { + if (Context->Pin->Direction == EGPD_Input && Context->Pin->ParentPin == nullptr) + { + Section.AddMenuEntry( + "RemovePin", + LOCTEXT("RemovePin", "Remove array element pin"), + LOCTEXT("RemovePinTooltip", "Remove this array element pin"), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateUObject(const_cast(this), &UK2Node_DistinctArray::RemoveInputPin, const_cast(Context->Pin)) + ) + ); + } + } + else + { + Section.AddMenuEntry( + "AddPin", + LOCTEXT("AddPin", "Add array element pin"), + LOCTEXT("AddPinTooltip", "Add another array element pin"), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateUObject(const_cast(this), &UK2Node_DistinctArray::InteractiveAddInputPin) + ) + ); + } + + Section.AddMenuEntry( + "ResetToWildcard", + LOCTEXT("ResetToWildcard", "Reset to wildcard"), + LOCTEXT("ResetToWildcardTooltip", "Reset the node to have wildcard input/outputs. Requires no pins are connected."), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateUObject(const_cast(this), &UK2Node_DistinctArray::ClearPinTypeToWildcard), + FCanExecuteAction::CreateUObject(this, &UK2Node_DistinctArray::CanResetToWildcard) + ) + ); + + */ + } +} + +FNodeHandlingFunctor* UK2Node_DistinctArray::CreateNodeHandler(FKismetCompilerContext& CompilerContext) const +{ + return new FKCHandler_DistinctArray(CompilerContext); +} + +FText UK2Node_DistinctArray::GetMenuCategory() const +{ + return LOCTEXT("DistinctArray_MenuCategory", "Mountea Inventory & Equipment"); +} + +void UK2Node_DistinctArray::AllocateDefaultPins() +{ + // Create the output pin + UEdGraphNode::FCreatePinParams PinParams; + PinParams.ContainerType = EPinContainerType::Array; + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Wildcard, GetOutputPinName(), PinParams); + + // Create the input pins to create the container from + for (int32 i = 0; i < NumInputs; ++i) + { + UEdGraphNode::FCreatePinParams InputPinParams; + InputPinParams.ContainerType = EPinContainerType::Array; + CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, GetPinName(i), InputPinParams); + } +} + +void UK2Node_DistinctArray::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const +{ + UClass* ActionKey = GetClass(); + + if (ActionRegistrar.IsOpenForRegistration(ActionKey)) + { + UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create(GetClass()); + check(NodeSpawner != nullptr); + + ActionRegistrar.AddBlueprintAction(ActionKey, NodeSpawner); + } +} + +void UK2Node_DistinctArray::ReallocatePinsDuringReconstruction(TArray& OldPins) +{ + UK2Node::ReallocatePinsDuringReconstruction(OldPins); + + // This is necessary to retain type information after pasting or loading from disc + if (UEdGraphPin* OutputPin = GetOutputPin()) + { + // Only update the output pin if it is currently a wildcard + if (OutputPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard) + { + // Find the matching Old Pin if it exists + for (UEdGraphPin* OldPin : OldPins) + { + if (OldPin->Direction == EGPD_Output) + { + // Update our output pin with the old type information and then propagate it to our input pins + OutputPin->PinType = OldPin->PinType; + PropagatePinType(); + break; + } + } + } + } +} + +bool UK2Node_DistinctArray::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const +{ + if (!ensure(OtherPin)) + { + return true; + } + + // if MyPin has a ParentPin then we are dealing with a split pin and we should evaluate it with default behavior + if (MyPin->ParentPin == nullptr && !OtherPin->PinType.IsContainer() == true && MyPin->Direction == EGPD_Input) + { + OutReason = NSLOCTEXT("K2Node", "DistinctArray_InputIsContainer", "Cannot make a container with an input of a container!").ToString(); + return true; + } + + if (UEdGraphSchema_K2::IsExecPin(*OtherPin)) + { + OutReason = NSLOCTEXT("K2Node", "DistinctArray_InputIsExec", "Cannot make a container with an execution input!").ToString(); + return true; + } + + return false; +} + +FName UK2Node_DistinctArray::GetPinName(const int32 PinIndex) const +{ + return *FString::Printf(TEXT("Array [%d]"), PinIndex); +} + +FName UK2Node_DistinctArray::GetOutputPinName() const +{ + return FName("Distinct Array"); +} + +UEdGraphPin* UK2Node_DistinctArray::GetOutputPin() const +{ + return FindPin(GetOutputPinName()); +} + +void UK2Node_DistinctArray::GetKeyAndValuePins(TArray& KeyPins, TArray& ValuePins) const +{ + for (UEdGraphPin* CurrentPin : Pins) + { + if (CurrentPin->Direction == EGPD_Input && CurrentPin->ParentPin == nullptr) + { + KeyPins.Add(CurrentPin); + } + } +} + +void UK2Node_DistinctArray::PropagatePinType() +{ + const UEdGraphPin* OutputPin = GetOutputPin(); + + if (OutputPin) + { + UClass const* CallingContext = nullptr; + if (UBlueprint const* Blueprint = GetBlueprint()) + { + CallingContext = Blueprint->GeneratedClass; + if (CallingContext == nullptr) + { + CallingContext = Blueprint->ParentClass; + } + } + + TArray KeyPins; + TArray ValuePins; + GetKeyAndValuePins(KeyPins, ValuePins); + + // Propagate pin type info (except for array info!) to pins with dependent types + const UEdGraphSchema_K2* Schema = GetDefault(); + auto PropagateToPin = [Schema](UEdGraphPin* CurrentPin, const FEdGraphPinType& PinType) + { + // if we've reset to wild card or the parent pin no longer matches we need to collapse the split pin(s) + // otherwise everything should be OK: + if (CurrentPin->SubPins.Num() != 0 && + (CurrentPin->PinType.PinCategory != PinType.PinCategory || + CurrentPin->PinType.PinSubCategory != PinType.PinSubCategory || + CurrentPin->PinType.PinSubCategoryObject != PinType.PinSubCategoryObject) + ) + { + Schema->RecombinePin(CurrentPin->SubPins[0]); + } + + CurrentPin->PinType.PinCategory = PinType.PinCategory; + CurrentPin->PinType.PinSubCategory = PinType.PinSubCategory; + CurrentPin->PinType.PinSubCategoryObject = PinType.PinSubCategoryObject; + }; + + for (UEdGraphPin* CurrentKeyPin : KeyPins) + { + PropagateToPin(CurrentKeyPin, OutputPin->PinType); + } + + if (ValuePins.Num() > 0) + { + const FEdGraphPinType ValuePinType = FEdGraphPinType::GetPinTypeForTerminalType(OutputPin->PinType.PinValueType); + for (UEdGraphPin* CurrentValuePin : ValuePins) + { + PropagateToPin(CurrentValuePin, ValuePinType); + } + } + + for (UEdGraphPin* CurrentPin : Pins) + { + if (CurrentPin && CurrentPin != OutputPin) + { + if (CurrentPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard || CurrentPin->GetDefaultAsString().IsEmpty() == true) + { + // Only reset default value if there isn't one set or it is a wildcard. Otherwise this deletes data! + Schema->SetPinAutogeneratedDefaultValueBasedOnType(CurrentPin); + } + + // Verify that all previous connections to this pin are still valid with the new type + TArray LinkedToCopy = CurrentPin->LinkedTo; + for (UEdGraphPin* ConnectedPin : LinkedToCopy) + { + if (!Schema->ArePinsCompatible(CurrentPin, ConnectedPin, CallingContext)) + { + CurrentPin->BreakLinkTo(ConnectedPin); + } + } + } + } + // If we have a valid graph we should refresh it now to refelect any changes we made + if (UEdGraphNode* OwningNode = OutputPin->GetOwningNode()) + { + if (UEdGraph* Graph = OwningNode->GetGraph()) + { + Graph->NotifyGraphChanged(); + } + } + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/MounteaInventoryEquipmentDeveloper/Private/MounteaInventoryEquipmentDeveloper.cpp b/Source/MounteaInventoryEquipmentDeveloper/Private/MounteaInventoryEquipmentDeveloper.cpp new file mode 100644 index 00000000..0bb60ddc --- /dev/null +++ b/Source/MounteaInventoryEquipmentDeveloper/Private/MounteaInventoryEquipmentDeveloper.cpp @@ -0,0 +1,19 @@ +#include "MounteaInventoryEquipmentDeveloper.h" + +DEFINE_LOG_CATEGORY(MounteaInventoryEquipmentDeveloper); + +#define LOCTEXT_NAMESPACE "FMounteaInventoryEquipmentDeveloper" + +void FMounteaInventoryEquipmentDeveloper::StartupModule() +{ + UE_LOG(MounteaInventoryEquipmentDeveloper, Warning, TEXT("MounteaInventoryEquipmentDeveloper module has been loaded")); +} + +void FMounteaInventoryEquipmentDeveloper::ShutdownModule() +{ + UE_LOG(MounteaInventoryEquipmentDeveloper, Warning, TEXT("MounteaInventoryEquipmentDeveloper module has been unloaded")); +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FMounteaInventoryEquipmentDeveloper, MounteaInventoryEquipmentDeveloper) \ No newline at end of file diff --git a/Source/MounteaInventoryEquipmentDeveloper/Public/K2Nodes/K2Node_DistinctArray.h b/Source/MounteaInventoryEquipmentDeveloper/Public/K2Nodes/K2Node_DistinctArray.h new file mode 100644 index 00000000..245cda0d --- /dev/null +++ b/Source/MounteaInventoryEquipmentDeveloper/Public/K2Nodes/K2Node_DistinctArray.h @@ -0,0 +1,73 @@ +// All rights reserved Dominik Pavlicek 2023. + +#pragma once + +#include "CoreMinimal.h" + +#include "K2Node.h" + +#include "K2Node_DistinctArray.generated.h" + +/** + * + */ +UCLASS(MinimalAPI, meta=(Keywords = "Distinct,Intersection,Mountea")) +class UK2Node_DistinctArray : public UK2Node +{ + GENERATED_BODY() + +public: + + UK2Node_DistinctArray(); + +public: + + // UEdGraphNode interface + virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; + virtual FText GetTooltipText() const override; + virtual FLinearColor GetNodeTitleColor() const override; + virtual FLinearColor GetNodeBodyTintColor() const override; + virtual FSlateIcon GetIconAndTint(FLinearColor& OutColor) const override; + virtual void ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const override; + virtual void PostReconstructNode() override; + virtual FText GetKeywords() const override; + // End of UEdGraphNode interface + +public: + + // UK2Node interface + virtual void NotifyPinConnectionListChanged(UEdGraphPin* Pin) override; + virtual void GetNodeContextMenuActions(class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const override; + virtual bool IncludeParentNodeContextMenu() const override { return true; } + virtual class FNodeHandlingFunctor* CreateNodeHandler(class FKismetCompilerContext& CompilerContext) const override; + virtual FText GetMenuCategory() const override; + virtual bool IsNodePure() const override {return true;}; + virtual void AllocateDefaultPins() override; + virtual void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override; + virtual int32 GetNodeRefreshPriority() const override { return EBaseNodeRefreshPriority::Low_UsesDependentWildcard; } + virtual void ReallocatePinsDuringReconstruction(TArray& OldPins) override; + virtual bool IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const override; + // End of UK2Node interface + +public: + + // UK2Node_DistinctArray + virtual FName GetPinName(int32 PinIndex) const; + virtual FName GetOutputPinName() const ; + virtual UEdGraphPin* GetOutputPin() const; + virtual void GetKeyAndValuePins(TArray& KeyPins, TArray& ValuePins) const; + virtual void PropagatePinType(); + // End of UK2Node_DistinctArray + +protected: + + /** The number of input pins to generate for this node */ + UPROPERTY() + int32 NumInputs; + + /** The number of input pins which is required for the node to exist */ + UPROPERTY() + int32 MinNumInputs; + + EPinContainerType ContainerType; +}; diff --git a/Source/MounteaInventoryEquipmentDeveloper/Public/MounteaInventoryEquipmentDeveloper.h b/Source/MounteaInventoryEquipmentDeveloper/Public/MounteaInventoryEquipmentDeveloper.h new file mode 100644 index 00000000..560eae28 --- /dev/null +++ b/Source/MounteaInventoryEquipmentDeveloper/Public/MounteaInventoryEquipmentDeveloper.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Modules/ModuleManager.h" + +DECLARE_LOG_CATEGORY_EXTERN(MounteaInventoryEquipmentDeveloper, All, All); + +class FMounteaInventoryEquipmentDeveloper : public IModuleInterface +{ + public: + + /* Called when the module is loaded */ + virtual void StartupModule() override; + + /* Called when the module is unloaded */ + virtual void ShutdownModule() override; +}; \ No newline at end of file diff --git a/Source/MounteaInventoryEquipmentEditor/MounteaInventoryEquipmentEditor.build.cs b/Source/MounteaInventoryEquipmentEditor/MounteaInventoryEquipmentEditor.build.cs index 3356b9f6..2b959f39 100644 --- a/Source/MounteaInventoryEquipmentEditor/MounteaInventoryEquipmentEditor.build.cs +++ b/Source/MounteaInventoryEquipmentEditor/MounteaInventoryEquipmentEditor.build.cs @@ -59,7 +59,8 @@ public MounteaInventoryEquipmentEditor(ReadOnlyTargetRules Target) : base(Target "DataTableEditor", "DesktopPlatform", - "GameplayTags" + "GameplayTags", + "KismetCompiler" } ); diff --git a/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryContentThemeAssetAction.cpp b/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryContentThemeAssetAction.cpp new file mode 100644 index 00000000..4bdf6741 --- /dev/null +++ b/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryContentThemeAssetAction.cpp @@ -0,0 +1,68 @@ +// All rights reserved Dominik Pavlicek 2023. + +#include "FMounteaInventoryContentThemeAssetAction.h" + +#include "Helpers/FMounteaInventoryEquipmentEditorConsts.h" +#include "Settings/ContentTheme.h" + + +#define LOCTEXT_NAMESPACE "MounteaInventoryContentThemeAssetAction" + +FMounteaInventoryContentThemeAssetAction::FMounteaInventoryContentThemeAssetAction() +{} + +FText FMounteaInventoryContentThemeAssetAction::GetName() const +{ + return LOCTEXT("MounteaInventoryThemeAssetAction_Name", "Inventory Content Theme"); +} + +FColor FMounteaInventoryContentThemeAssetAction::GetTypeColor() const +{ + return FColor::Red; +} + +UClass* FMounteaInventoryContentThemeAssetAction::GetSupportedClass() const +{ + return UContentTheme::StaticClass(); +} + +uint32 FMounteaInventoryContentThemeAssetAction::GetCategories() +{ + if (FModuleManager::Get().IsModuleLoaded("AssetTools")) + { + return FAssetToolsModule::GetModule().Get().FindAdvancedAssetCategory(AdvancedMenuCategoryName); + } + + return EAssetTypeCategories::Misc; +} + +const TArray& FMounteaInventoryContentThemeAssetAction::GetSubMenus() const +{ + static const TArray AssetTypeActionSubMenu + { + AdvancedMenuSubCategoryName_05 + }; + return AssetTypeActionSubMenu; +} + +FText FTextThemeAssetActions::GetName() const +{ + return LOCTEXT("TextThemeAssetAction_Name", "Text Theme"); +} + +UClass* FTextThemeAssetActions::GetSupportedClass() const +{ + return UTextTheme::StaticClass(); +} + +FText FCategoryThemeAssetActions::GetName() const +{ + return LOCTEXT("CategoryThemeAssetAction_Name", "Category Theme"); +} + +UClass* FCategoryThemeAssetActions::GetSupportedClass() const +{ + return UCategoryTheme::StaticClass(); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryContentThemeAssetAction.h b/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryContentThemeAssetAction.h new file mode 100644 index 00000000..47a84c74 --- /dev/null +++ b/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryContentThemeAssetAction.h @@ -0,0 +1,73 @@ +// All rights reserved Dominik Pavlicek 2023. + +#pragma once + +#include "CoreMinimal.h" +#include "AssetTypeActions_Base.h" +#include "Utils/MounteaInventoryEquipmentEditorUtilities.h" + +class FMounteaInventoryContentThemeAssetAction : public FAssetTypeActions_Base +{ + +public: + + FMounteaInventoryContentThemeAssetAction(); + + virtual FText GetName() const override; + virtual FColor GetTypeColor() const override; + virtual UClass* GetSupportedClass() const override; + virtual uint32 GetCategories() override; + + virtual const TArray& GetSubMenus() const override; + + virtual bool CanFilter() override + { return true; }; + + virtual void BuildBackendFilter(FARFilter& InFilter) override + { + FilterAddNativeParentClassPath(InFilter, GetSupportedClass()); + + // Add to filter all native children classes of our supported class + TArray NativeChildClasses; + TArray BlueprintChildClasses; + FMounteaInventoryEquipmentEditorUtilities::GetAllChildClassesOf(GetSupportedClass(), NativeChildClasses, BlueprintChildClasses); + for (const UClass* ChildNativeClass : NativeChildClasses) + { + FilterAddNativeParentClassPath(InFilter, ChildNativeClass); + } + + InFilter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); + InFilter.bRecursiveClasses = true; + }; + + static void FilterAddNativeParentClassPath(FARFilter& InFilter, const UClass* Class) + { + if (Class == nullptr) + { + return; + } + + const FString Value = FString::Printf( + TEXT("%s'%s'"), + *UClass::StaticClass()->GetName(), + *Class->GetPathName() + ); + InFilter.TagsAndValues.Add(FBlueprintTags::NativeParentClassPath, Value); + }; +}; + +class FTextThemeAssetActions : public FMounteaInventoryContentThemeAssetAction +{ +public: + + virtual FText GetName() const override; + virtual UClass* GetSupportedClass() const override; +}; + +class FCategoryThemeAssetActions : public FMounteaInventoryContentThemeAssetAction +{ +public: + + virtual FText GetName() const override; + virtual UClass* GetSupportedClass() const override; +}; \ No newline at end of file diff --git a/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryThemeAssetAction.cpp b/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryThemeAssetAction.cpp index 20e4bdf1..6b4d645e 100644 --- a/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryThemeAssetAction.cpp +++ b/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryThemeAssetAction.cpp @@ -45,4 +45,9 @@ const TArray& FMounteaInventoryThemeAssetAction::GetSubMenus() const return AssetTypeActionSubMenu; } +void FMounteaInventoryThemeAssetAction::GenerateDefaultThemes(TArray> Objects) +{ + +} + #undef LOCTEXT_NAMESPACE diff --git a/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryThemeAssetAction.h b/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryThemeAssetAction.h index c5c3d98a..b57b93bd 100644 --- a/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryThemeAssetAction.h +++ b/Source/MounteaInventoryEquipmentEditor/Private/AssetActions/FMounteaInventoryThemeAssetAction.h @@ -54,4 +54,7 @@ class FMounteaInventoryThemeAssetAction : public FAssetTypeActions_Base ); InFilter.TagsAndValues.Add(FBlueprintTags::NativeParentClassPath, Value); }; + + /** Handler for when generate request is selected*/ + void GenerateDefaultThemes(TArray< TWeakObjectPtr > Objects); }; \ No newline at end of file diff --git a/Source/MounteaInventoryEquipmentEditor/Private/DetailsPanel/MounteaInventoryItemBase_Details.cpp b/Source/MounteaInventoryEquipmentEditor/Private/DetailsPanel/MounteaInventoryItemBase_Details.cpp index 1299ec1a..5995a956 100644 --- a/Source/MounteaInventoryEquipmentEditor/Private/DetailsPanel/MounteaInventoryItemBase_Details.cpp +++ b/Source/MounteaInventoryEquipmentEditor/Private/DetailsPanel/MounteaInventoryItemBase_Details.cpp @@ -201,6 +201,8 @@ void FMounteaInventoryItem_Details::CustomizeDetails(IDetailLayoutBuilder& Detai ] ] ]; + + if (EditingItem) EditingItem->SetValidDataEditor(); } #undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/MounteaInventoryEquipmentEditor/Private/Factories/MounteaContentThemeAssetFactory.cpp b/Source/MounteaInventoryEquipmentEditor/Private/Factories/MounteaContentThemeAssetFactory.cpp new file mode 100644 index 00000000..4149874c --- /dev/null +++ b/Source/MounteaInventoryEquipmentEditor/Private/Factories/MounteaContentThemeAssetFactory.cpp @@ -0,0 +1,130 @@ +// All rights reserved Dominik Pavlicek 2022. + + +#include "MounteaContentThemeAssetFactory.h" + +#include "Settings/ContentTheme.h" +#include "Utils/MounteaInventoryEquipmentEditorUtilities.h" + + +UMounteaContentThemeAssetFactory::UMounteaContentThemeAssetFactory() +{ + bCreateNew = false; + bEditAfterNew = true; + + SupportedClass = UContentTheme::StaticClass(); +} + + +UObject* UMounteaContentThemeAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) +{ + UContentTheme* NewTheme = NewObject(InParent, ParentClass, Name, Flags, Context); + + return NewTheme; +} + + +bool UMounteaContentThemeAssetFactory::ConfigureProperties() +{ + static const FText TitleText = FText::FromString(TEXT("Pick Parent Class for new Mountea Inventory Content Theme")); + + UClass* ChosenClass = nullptr; + const bool bPressedOk = FMounteaInventoryEquipmentEditorUtilities::PickChildrenOfClass(TitleText, ChosenClass, UContentTheme::StaticClass()); + + if ( bPressedOk ) + { + ParentClass = ChosenClass; + } + + return bPressedOk; +} + +UTextThemeAssetFactory::UTextThemeAssetFactory() +{ + bCreateNew = true; + bEditAfterNew = true; + + SupportedClass = UTextTheme::StaticClass(); +} + +UObject* UTextThemeAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) +{ + UTextTheme* NewTheme = NewObject(InParent, ParentClass, Name, Flags, Context); + + return NewTheme; +} + +bool UTextThemeAssetFactory::ConfigureProperties() +{ + static const FText TitleText = FText::FromString(TEXT("Pick Parent Class for new Mountea Inventory Text Theme")); + + UClass* ChosenClass = nullptr; + const bool bPressedOk = FMounteaInventoryEquipmentEditorUtilities::PickChildrenOfClass(TitleText, ChosenClass, UTextTheme::StaticClass()); + + if ( bPressedOk ) + { + ParentClass = ChosenClass; + } + + return bPressedOk; +} + +UCategoryThemeAssetFactory::UCategoryThemeAssetFactory() +{ + bCreateNew = true; + bEditAfterNew = true; + + SupportedClass = UCategoryTheme::StaticClass(); +} + +UObject* UCategoryThemeAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) +{ + UCategoryTheme* NewTheme = NewObject(InParent, ParentClass, Name, Flags, Context); + + return NewTheme; +} + +bool UCategoryThemeAssetFactory::ConfigureProperties() +{ + static const FText TitleText = FText::FromString(TEXT("Pick Parent Class for new Mountea Inventory Category Theme")); + + UClass* ChosenClass = nullptr; + const bool bPressedOk = FMounteaInventoryEquipmentEditorUtilities::PickChildrenOfClass(TitleText, ChosenClass, UCategoryTheme::StaticClass()); + + if ( bPressedOk ) + { + ParentClass = ChosenClass; + } + + return bPressedOk; +} + +USlotThemeAssetFactory::USlotThemeAssetFactory() +{ + bCreateNew = true; + bEditAfterNew = true; + + SupportedClass = USlotTheme::StaticClass(); +} + +UObject* USlotThemeAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) +{ + USlotTheme* NewTheme = NewObject(InParent, ParentClass, Name, Flags, Context); + + return NewTheme; +} + +bool USlotThemeAssetFactory::ConfigureProperties() +{ + static const FText TitleText = FText::FromString(TEXT("Pick Parent Class for new Mountea Inventory Slot Theme")); + + UClass* ChosenClass = nullptr; + const bool bPressedOk = FMounteaInventoryEquipmentEditorUtilities::PickChildrenOfClass(TitleText, ChosenClass, USlotTheme::StaticClass()); + + if ( bPressedOk ) + { + ParentClass = ChosenClass; + } + + return bPressedOk; +} diff --git a/Source/MounteaInventoryEquipmentEditor/Private/Factories/MounteaContentThemeAssetFactory.h b/Source/MounteaInventoryEquipmentEditor/Private/Factories/MounteaContentThemeAssetFactory.h new file mode 100644 index 00000000..ff840e41 --- /dev/null +++ b/Source/MounteaInventoryEquipmentEditor/Private/Factories/MounteaContentThemeAssetFactory.h @@ -0,0 +1,69 @@ +// All rights reserved Dominik Pavlicek 2022. + +#pragma once + +#include "CoreMinimal.h" +#include "Factories/Factory.h" +#include "MounteaContentThemeAssetFactory.generated.h" + +class UContentTheme; + +/** + * + */ +UCLASS() +class MOUNTEAINVENTORYEQUIPMENTEDITOR_API UMounteaContentThemeAssetFactory : public UFactory +{ + GENERATED_BODY() + +public: + + UMounteaContentThemeAssetFactory(); + + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; + virtual bool ConfigureProperties() override; + +protected: + // Holds the template of the class we are building + UPROPERTY() + TSubclassOf ParentClass; +}; + +UCLASS() +class MOUNTEAINVENTORYEQUIPMENTEDITOR_API UTextThemeAssetFactory : public UMounteaContentThemeAssetFactory +{ + GENERATED_BODY() + +public: + + UTextThemeAssetFactory(); + + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; + virtual bool ConfigureProperties() override; +}; + +UCLASS() +class MOUNTEAINVENTORYEQUIPMENTEDITOR_API UCategoryThemeAssetFactory : public UMounteaContentThemeAssetFactory +{ + GENERATED_BODY() + +public: + + UCategoryThemeAssetFactory(); + + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; + virtual bool ConfigureProperties() override; +}; + +UCLASS() +class MOUNTEAINVENTORYEQUIPMENTEDITOR_API USlotThemeAssetFactory : public UMounteaContentThemeAssetFactory +{ + GENERATED_BODY() + +public: + + USlotThemeAssetFactory(); + + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; + virtual bool ConfigureProperties() override; +}; \ No newline at end of file diff --git a/Source/MounteaInventoryEquipmentEditor/Private/Factories/MounteaThemeAssetFactory.cpp b/Source/MounteaInventoryEquipmentEditor/Private/Factories/MounteaThemeAssetFactory.cpp index 306c93b8..1feea106 100644 --- a/Source/MounteaInventoryEquipmentEditor/Private/Factories/MounteaThemeAssetFactory.cpp +++ b/Source/MounteaInventoryEquipmentEditor/Private/Factories/MounteaThemeAssetFactory.cpp @@ -21,7 +21,14 @@ UMounteaThemeAssetFactory::UMounteaThemeAssetFactory() UObject* UMounteaThemeAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) { - return NewObject(InParent, ParentClass, Name, Flags, Context); + UMounteaInventoryThemeConfig* NewTheme = NewObject(InParent, ParentClass, Name, Flags, Context); + + if (NewTheme) + { + NewTheme->GenerateMissingThemes_Editor(); + } + + return NewTheme; } diff --git a/Source/MounteaInventoryEquipmentEditor/Private/Helpers/FMounteaInventoryEquipmentEditorConsts.h b/Source/MounteaInventoryEquipmentEditor/Private/Helpers/FMounteaInventoryEquipmentEditorConsts.h index 89dcc707..09cb9c9b 100644 --- a/Source/MounteaInventoryEquipmentEditor/Private/Helpers/FMounteaInventoryEquipmentEditorConsts.h +++ b/Source/MounteaInventoryEquipmentEditor/Private/Helpers/FMounteaInventoryEquipmentEditorConsts.h @@ -28,5 +28,6 @@ const FText AdvancedMenuSubCategoryName_01 = LOCTEXT("AdvancedMenuSubCategoryNam const FText AdvancedMenuSubCategoryName_02 = LOCTEXT("AdvancedMenuSubCategoryName_02", "2. Data"); const FText AdvancedMenuSubCategoryName_03 = LOCTEXT("AdvancedMenuSubCategoryName_03", "3. Definitions"); const FText AdvancedMenuSubCategoryName_04 = LOCTEXT("AdvancedMenuSubCategoryName_04", "4. Components"); +const FText AdvancedMenuSubCategoryName_05 = LOCTEXT("AdvancedMenuSubCategoryName_05", "5. Content Themes"); #undef LOCTEXT_NAMESPACE diff --git a/Source/MounteaInventoryEquipmentEditor/Private/Helpers/MIEEditorStyle.cpp b/Source/MounteaInventoryEquipmentEditor/Private/Helpers/MIEEditorStyle.cpp index 783b983b..bb10e125 100644 --- a/Source/MounteaInventoryEquipmentEditor/Private/Helpers/MIEEditorStyle.cpp +++ b/Source/MounteaInventoryEquipmentEditor/Private/Helpers/MIEEditorStyle.cpp @@ -65,6 +65,8 @@ TSharedRef FMIEEditorStyle::Create() Style->Set("MIEStyleSet.Icon.Browse", new IMAGE_BRUSH(TEXT("BrowseIcon"), Icon12x12)); Style->Set("MIEStyleSet.Icon.Edit", new IMAGE_BRUSH(TEXT("EditIcon"), Icon12x12)); + Style->Set("MIEStyleSet.Icon.DistinctArray", new IMAGE_BRUSH(TEXT("K2NodeIcons/DistinctIcon"), Icon12x12)); + const FButtonStyle MounteaButtonStyle = FButtonStyle() .SetNormal(BOX_BRUSH("RoundedSelection_16x", 4.0f / 16.0f, FLinearColor(1, 1, 1, 0.1f))) .SetHovered(BOX_BRUSH("RoundedSelection_16x", 4.0f / 16.0f, FLinearColor(1, .55f, 0, 0.2f))) diff --git a/Source/MounteaInventoryEquipmentEditor/Private/MounteaInventoryEquipmentEditor.cpp b/Source/MounteaInventoryEquipmentEditor/Private/MounteaInventoryEquipmentEditor.cpp index 1443a519..df710c3a 100644 --- a/Source/MounteaInventoryEquipmentEditor/Private/MounteaInventoryEquipmentEditor.cpp +++ b/Source/MounteaInventoryEquipmentEditor/Private/MounteaInventoryEquipmentEditor.cpp @@ -10,6 +10,7 @@ #include "AssetActions/FMounteaInventoryCategoryAssetAction.h" #include "AssetActions/FMounteaInventoryComponentAssetAction.h" +#include "AssetActions/FMounteaInventoryContentThemeAssetAction.h" #include "AssetActions/FMounteaInventoryItemActionAssetAction.h" #include "AssetActions/FMounteaInventoryItemAdditionalDataAssetAction.h" #include "AssetActions/FMounteaInventoryItemAssetAction.h" @@ -79,8 +80,11 @@ void FMounteaInventoryEquipmentEditor::StartupModule() RegisterAssetTypeAction(FAssetToolsModule::GetModule().Get(), MakeShared()); RegisterAssetTypeAction(FAssetToolsModule::GetModule().Get(), MakeShared()); RegisterAssetTypeAction(FAssetToolsModule::GetModule().Get(), MakeShared()); - - RegisterAssetTypeAction(FAssetToolsModule::GetModule().Get(), MakeShared()); + RegisterAssetTypeAction(FAssetToolsModule::GetModule().Get(), MakeShared()); + RegisterAssetTypeAction(FAssetToolsModule::GetModule().Get(), MakeShared()); + + RegisterAssetTypeAction(FAssetToolsModule::GetModule().Get(), MakeShared()); + RegisterAssetTypeAction(FAssetToolsModule::GetModule().Get(), MakeShared()); } // Register Styles and Commands