├── .gitignore ├── GenericStorages ├── GenericStorages.uplugin └── Source │ └── GenericStorages │ ├── GenericStorages.Build.cs │ ├── Private │ ├── ComponentPicker.cpp │ ├── DeferredComponentRegistry.cpp │ ├── Editor │ │ ├── ComponentPickerCustomization.cpp │ │ ├── ComponentPickerCustomization.h │ │ ├── DataTablePickerCustomization.cpp │ │ ├── DataTablePickerCustomization.h │ │ ├── GenericSystemConfigCustomization.cpp │ │ ├── GenericSystemConfigCustomization.h │ │ ├── SClassPickerGraphPin.cpp │ │ ├── SClassPickerGraphPin.h │ │ ├── TypeTableBinddingCustomization.cpp │ │ └── TypeTableBinddingCustomization.h │ ├── GenericSingletons.cpp │ ├── GenericStoragesModule.cpp │ ├── GenericStoragesModule.h │ ├── GenericSystems.cpp │ ├── MIO.cpp │ ├── MemberDataRegistry.cpp │ ├── ObjectDataRegistry.cpp │ ├── ObjectPattern.cpp │ └── TypeTableBindding.cpp │ ├── Public │ ├── ClassDataStorage.h │ ├── ComponentPattern.h │ ├── ComponentPicker.h │ ├── DataTablePicker.h │ ├── DeferredComponentConfig.h │ ├── DeferredComponentRegistry.h │ ├── Editor │ │ ├── UnrealEditorUtils.cpp │ │ └── UnrealEditorUtils.h │ ├── GMPPropertyPath.h │ ├── GenericSingletons.h │ ├── GenericStorages.h │ ├── GenericStoragesLog.h │ ├── GenericSystems.h │ ├── MIO.h │ ├── MemberDataRegistry.h │ ├── ObjectDataRegistry.h │ ├── ObjectPattern.h │ └── WorldLocalStorages.h │ └── Template │ ├── AttributeCompatibility.h │ ├── ComponentCompatibility.h │ ├── MACRO_FOR_EACH.h │ ├── PrivateFieldAccessor.h │ ├── PropertyCompatibility.include │ ├── ProtectFieldAccessor.h │ ├── TypeTableBindding.h │ ├── UnrealCompatibility.h │ └── mio │ ├── detail │ ├── mmap.ipp │ └── string_util.hpp │ ├── mmap.hpp │ └── page.hpp ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | /GenericStorages/Intermediate 34 | /GenericStorages/Binaries 35 | -------------------------------------------------------------------------------- /GenericStorages/GenericStorages.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "0.9", 5 | "FriendlyName": "GenericStorages", 6 | "Description": "GenericStorages Utilities", 7 | "Category": "Core", 8 | "CreatedBy": "wangjieest", 9 | "CreatedByURL": "", 10 | "MarketplaceURL": "", 11 | "DocsURL": "", 12 | "SupportURL": "", 13 | "EnabledByDefault": true, 14 | "CanContainContent": false, 15 | "IsBetaVersion": false, 16 | "Installed": false, 17 | "Modules": [ 18 | { 19 | "Name": "GenericStorages", 20 | "Type": "Runtime", 21 | "LoadingPhase": "PreDefault", 22 | "BlacklistPlatforms": [] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/GenericStorages.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class GenericStorages : ModuleRules 6 | { 7 | public GenericStorages(ReadOnlyTargetRules Target) 8 | : base(Target) 9 | { 10 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 11 | PublicIncludePaths.AddRange(new string[]{ 12 | ModuleDirectory + "/Public", 13 | ModuleDirectory + "/Template", 14 | ModuleDirectory, 15 | // ... add public include paths required here ... 16 | }); 17 | 18 | PublicDependencyModuleNames.AddRange(new string[]{ 19 | "Core", 20 | "CoreUObject", 21 | "Engine", 22 | }); 23 | 24 | PrivateDependencyModuleNames.AddRange(new string[]{ 25 | // ... add private dependencies that you statically link with here ... 26 | }); 27 | 28 | DynamicallyLoadedModuleNames.AddRange(new string[]{ 29 | // ... add any modules that your module loads dynamically here ... 30 | }); 31 | 32 | if (Target.Type != TargetRules.TargetType.Server) 33 | { 34 | PrivateDependencyModuleNames.AddRange(new string[]{ 35 | "UMG", 36 | }); 37 | } 38 | 39 | if (Target.Type == TargetRules.TargetType.Editor) 40 | { 41 | PrivateDependencyModuleNames.AddRange(new string[]{ 42 | "UnrealEd", 43 | "SlateCore", 44 | "Slate", 45 | "InputCore", 46 | "GraphEditor", 47 | "EditorStyle", 48 | "BlueprintGraph", 49 | "KismetWidgets", 50 | "ClassViewer", 51 | "PropertyEditor", 52 | "Settings", 53 | }); 54 | } 55 | BuildVersion Version; 56 | if (BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out Version)) 57 | { 58 | bool bUE_USE_FPROPERTY = (Version.MajorVersion > 4 || (Version.MajorVersion == 4 && Version.MinorVersion >= 25)); 59 | if (bUE_USE_FPROPERTY) 60 | PublicDefinitions.Add("UE_USE_UPROPERTY=0"); 61 | else 62 | PublicDefinitions.Add("UE_USE_UPROPERTY=1"); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/ComponentPicker.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #include "ComponentPicker.h" 4 | 5 | #include "Engine/Blueprint.h" 6 | #include "Engine/BlueprintGeneratedClass.h" 7 | #include "Engine/SCS_Node.h" 8 | #include "Engine/SimpleConstructionScript.h" 9 | #include "GameFramework/Actor.h" 10 | #include "UObject/UnrealType.h" 11 | #include "Template/UnrealCompatibility.h" 12 | 13 | UActorComponent* FComponentPicker::FindComponentByName(AActor* InActor) const 14 | { 15 | return FindComponentByName(InActor, ComponentName); 16 | } 17 | 18 | UActorComponent* FComponentPicker::FindComponentByName(AActor* InActor, FName CompName, TSubclassOf InClass) 19 | { 20 | if (!InActor || !CompName.IsValid() || CompName.IsNone()) 21 | return nullptr; 22 | 23 | auto ActorClass = InActor->GetClass(); 24 | if (InActor->HasAnyFlags(RF_ClassDefaultObject)) 25 | { 26 | if (UBlueprintGeneratedClass* BBGClass = Cast(ActorClass)) 27 | { 28 | const TArray& ActorBlueprintNodes = BBGClass->SimpleConstructionScript->GetAllNodes(); 29 | for (USCS_Node* Node : ActorBlueprintNodes) 30 | { 31 | if (Node->GetVariableName() == CompName && (!InClass || Node->ComponentClass->IsChildOf(InClass))) 32 | { 33 | return Node->GetActualComponentTemplate(BBGClass); 34 | } 35 | } 36 | } 37 | } 38 | 39 | FObjectPropertyBase* ObjProp = FindFProperty(ActorClass, CompName); 40 | if (ObjProp) 41 | { 42 | return Cast(ObjProp->GetObjectPropertyValue_InContainer(InActor)); 43 | } 44 | 45 | for (auto& Comp : InActor->GetComponents()) 46 | { 47 | if (Comp->GetFName() == CompName && !(InClass || Comp->IsA(InClass.Get()))) 48 | { 49 | return Comp; 50 | } 51 | } 52 | 53 | return nullptr; 54 | } 55 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/DeferredComponentRegistry.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #include "DeferredComponentRegistry.h" 4 | 5 | #include "ClassDataStorage.h" 6 | #include "DeferredComponentConfig.h" 7 | #include "Engine/Engine.h" 8 | #include "Engine/NetConnection.h" 9 | #include "Engine/World.h" 10 | #include "GameFramework/PlayerController.h" 11 | #include "GenericSingletons.h" 12 | #include "GenericStoragesLog.h" 13 | #include "Misc/MessageDialog.h" 14 | #include "Stats/Stats2.h" 15 | #include "Templates/SharedPointer.h" 16 | #include "UObject/ObjectMacros.h" 17 | #include "UObject/PropertyPortFlags.h" 18 | #include "UObject/UObjectGlobals.h" 19 | 20 | #if WITH_EDITOR 21 | #include "Editor.h" 22 | #endif 23 | 24 | ////////////////////////////////////////////////////////////////////////// 25 | namespace DeferredComponentRegistry 26 | { 27 | struct ClassDataStorage : public ClassStorage::TClassStorageImpl 28 | { 29 | void AddDeferredComponents(TSubclassOf Class, const TSet>& RegDatas, bool bPersistent, uint8 Mode) 30 | { 31 | if (!RegDatas.Num()) 32 | return; 33 | check(Class.Get()); 34 | 35 | ModifyData(Class, bPersistent, [&](auto&& Arr) { 36 | for (auto& RegClass : RegDatas) 37 | { 38 | if (RegClass) 39 | { 40 | Arr.AddUnique(FRegClassData{RegClass, UDeferredComponentRegistry::GetMode(Mode, RegClass)}); 41 | } 42 | } 43 | }); 44 | } 45 | 46 | void AddDeferredComponent(TSubclassOf Class, TSubclassOf RegClass, bool bPersistent, uint8 Mode) 47 | { 48 | if (ensureAlways(Class.Get() && RegClass)) 49 | { 50 | ModifyData(Class, bPersistent, [&](auto&& Arr) { 51 | auto TmpFlags = Mode; 52 | Arr.AddUnique(FRegClassData{RegClass, UDeferredComponentRegistry::GetMode(Mode, RegClass)}); 53 | }); 54 | } 55 | } 56 | }; 57 | 58 | ClassDataStorage Storage; 59 | 60 | void AppendDeferredComponents(AActor& Actor) 61 | { 62 | #if WITH_EDITOR 63 | auto World = Actor.GetWorld(); 64 | if (!(World->WorldType == EWorldType::PIE || World->WorldType == EWorldType::Game)) 65 | return; 66 | #endif 67 | auto CurClass = Actor.GetClass(); 68 | auto It = Storage.CreateIterator(CurClass); 69 | if (!It) 70 | return; 71 | 72 | static auto PrefixName = TEXT("`"); 73 | #if WITH_EDITOR 74 | // check names 75 | TArray Names; 76 | for (auto& a : Actor.GetComponents()) 77 | { 78 | if (a->GetName().StartsWith(PrefixName)) 79 | Names.Add(a->GetName()); 80 | } 81 | if (Names.Num()) 82 | { 83 | FString Desc = FString::Printf(TEXT("component name conflicted:%s."), *Actor.GetClass()->GetName()); 84 | 85 | for (auto& a : Names) 86 | { 87 | Desc += TEXT("\n\t-->") + a; 88 | } 89 | if (FPlatformMisc::IsDebuggerPresent()) 90 | { 91 | ensureAlwaysMsgf(false, TEXT("%s"), *Desc); 92 | } 93 | else 94 | { 95 | FMessageDialog::Debugf(FText::FromString(Desc)); 96 | } 97 | } 98 | #endif 99 | 100 | QUICK_SCOPE_CYCLE_COUNTER(STAT_DeferredComponentRegistry_AppendDeferredComponents); 101 | do 102 | { 103 | auto& CurData = *It; 104 | for (auto& RegData : CurData.Data) 105 | { 106 | if (!ensure(IsValid(RegData.RegClass))) 107 | continue; 108 | 109 | const bool bIsClient = (Actor.GetNetMode() != NM_DedicatedServer); 110 | // 111 | if ((RegData.RegFlags & (bIsClient ? EComponentDeferredMode::ClientSide : EComponentDeferredMode::ServerSide)) == 0) 112 | continue; 113 | 114 | auto CDO = RegData.RegClass.GetDefaultObject(); 115 | const bool bIsReplicated = CDO->GetIsReplicated(); 116 | const bool bSetReplicated = EComponentDeferredMode::HasAnyFlags(RegData.RegFlags, EComponentDeferredMode::Replicated); 117 | 118 | const bool bIsNameStable = CDO->IsNameStableForNetworking(); 119 | const bool bSetNameStable = EComponentDeferredMode::HasAnyFlags(RegData.RegFlags, EComponentDeferredMode::NameStable); 120 | 121 | if (bIsClient) 122 | { 123 | if (EComponentDeferredMode::HasAnyFlags(RegData.RegFlags, EComponentDeferredMode::ServerSide) && (bIsReplicated || bSetReplicated) && !bSetNameStable && !bIsNameStable) 124 | { 125 | continue; 126 | } 127 | } 128 | 129 | // check existing deferred component 130 | if (!ensure(!Actor.FindComponentByClass(CurClass))) 131 | { 132 | UE_LOG(LogGenericStorages, Warning, TEXT("DeferredComponentRegistry::AppendDeferComponents Skip ActorComponent %s For Actor %s"), *GetNameSafe(RegData.RegClass), *GetNameSafe(&Actor)); 133 | } 134 | else 135 | { 136 | UE_LOG(LogGenericStorages, Log, TEXT("DeferredComponentRegistry::AppendDeferredComponents %s : %s"), *Actor.GetName(), *RegData.RegClass->GetName()); 137 | QUICK_SCOPE_CYCLE_COUNTER(STAT_DeferredComponentRegistry_SpawnComponents); 138 | FName CompName = *FString::Printf(TEXT("%s_%s"), PrefixName, *RegData.RegClass->GetName()); 139 | // no need AddOwnedComponent as NewObject does 140 | UActorComponent* ActorComp = NewObject(&Actor, RegData.RegClass, *CompName.ToString(), RF_Transient); 141 | if (bSetNameStable) 142 | ActorComp->SetNetAddressable(); 143 | if (bSetReplicated) 144 | ActorComp->SetIsReplicated(true); 145 | ActorComp->RegisterComponent(); 146 | 147 | if (TOnComponentInitialized::bNeedInit) 148 | { 149 | Actor.AddInstanceComponent(ActorComp); 150 | 151 | if (ActorComp->bAutoActivate && !ActorComp->IsActive()) 152 | { 153 | ActorComp->Activate(true); 154 | } 155 | if (ActorComp->bWantsInitializeComponent && !ActorComp->HasBeenInitialized()) 156 | { 157 | ActorComp->InitializeComponent(); 158 | } 159 | } 160 | } 161 | } 162 | } while (++It); 163 | } 164 | 165 | static FDelayedAutoRegisterHelper DelayInnerInitUDeferredComponentRegistry(EDelayedRegisterRunPhase::EndOfEngineInit, [] { 166 | #if WITH_EDITOR 167 | if (GIsEditor) 168 | { 169 | FEditorDelegates::PreBeginPIE.AddLambda([](bool bIsSimulating) { Storage.Cleanup(); }); 170 | } 171 | else 172 | #endif 173 | { 174 | // cleanup 175 | // Register for PreloadMap so cleanup can occur on map transitions 176 | FCoreUObjectDelegates::PreLoadMap.AddLambda([](const FString& MapName) { Storage.Cleanup(); }); 177 | // FWorldDelegates::OnPreWorldFinishDestroy.AddLambda([](UWorld*) { Storage.Cleanup(); }); 178 | } 179 | 180 | // Bind 181 | TOnComponentInitialized::Bind(); 182 | }); 183 | } // namespace DeferredComponentRegistry 184 | 185 | void UDeferredComponentRegistry::AddDeferredComponents(TSubclassOf Class, const TSet>& RegDatas, bool bPersistent, uint8 Mode) 186 | { 187 | QUICK_SCOPE_CYCLE_COUNTER(STAT_DeferredComponentRegistry_Registers); 188 | DeferredComponentRegistry::Storage.AddDeferredComponents(Class, RegDatas, bPersistent, Mode); 189 | } 190 | 191 | void UDeferredComponentRegistry::ModifyDeferredComponents(TSubclassOf Class, TFunctionRef Cb, bool bPersistent) 192 | { 193 | DeferredComponentRegistry::Storage.ModifyData(Class, bPersistent, Cb); 194 | } 195 | 196 | void UDeferredComponentRegistry::AddDeferredComponent(TSubclassOf Class, TSubclassOf RegClass, bool bPersistent, uint8 Mode) 197 | { 198 | QUICK_SCOPE_CYCLE_COUNTER(STAT_DeferredComponentRegistry_Register); 199 | DeferredComponentRegistry::Storage.AddDeferredComponent(Class, RegClass, bPersistent, Mode); 200 | } 201 | 202 | void UDeferredComponentRegistry::EnableAdd(bool bNewEnabled) 203 | { 204 | DeferredComponentRegistry::Storage.SetEnableState(bNewEnabled); 205 | } 206 | 207 | uint8 UDeferredComponentRegistry::GetMode(uint8 InFlags, TSubclassOf InClass) 208 | { 209 | auto TmpFlags = InFlags; 210 | auto CDO = InClass.GetDefaultObject(); 211 | if (!TmpFlags) 212 | { 213 | if (CDO->GetIsReplicated()) 214 | { 215 | const bool bIsNameStable = CDO->IsNameStableForNetworking(); 216 | TmpFlags = EComponentDeferredMode::ServerSide | EComponentDeferredMode::Replicated; 217 | if (bIsNameStable) 218 | TmpFlags |= EComponentDeferredMode::NameStable | EComponentDeferredMode::ClientSide; 219 | } 220 | else 221 | { 222 | TmpFlags = EComponentDeferredMode::BothSide; 223 | } 224 | } 225 | else if (EComponentDeferredMode::HasAnyFlags(InFlags, EComponentDeferredMode::ServerSide)) 226 | { 227 | bool bSetReplicated = EComponentDeferredMode::HasAnyFlags(InFlags, EComponentDeferredMode::Replicated); 228 | const bool bSetNameStable = EComponentDeferredMode::HasAnyFlags(InFlags, EComponentDeferredMode::NameStable); 229 | if (!bSetReplicated && CDO->GetIsReplicated()) 230 | { 231 | TmpFlags |= EComponentDeferredMode::Replicated; 232 | bSetReplicated = true; 233 | } 234 | 235 | if (bSetReplicated) 236 | { 237 | if (bSetNameStable || CDO->IsNameStableForNetworking()) 238 | TmpFlags |= EComponentDeferredMode::ClientSide | EComponentDeferredMode::NameStable; 239 | else 240 | TmpFlags &= ~EComponentDeferredMode::ClientSide | EComponentDeferredMode::NameStable; 241 | } 242 | } 243 | return TmpFlags; 244 | } 245 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/Editor/ComponentPickerCustomization.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #include "ComponentPickerCustomization.h" 4 | #if WITH_EDITOR 5 | #include "Slate.h" 6 | 7 | #include "DetailCategoryBuilder.h" 8 | #include "DetailLayoutBuilder.h" 9 | #include "Editor.h" 10 | #include "Engine/BlueprintGeneratedClass.h" 11 | #include "Engine/SCS_Node.h" 12 | #include "Engine/SimpleConstructionScript.h" 13 | #include "GameFramework/Actor.h" 14 | #include "IDetailChildrenBuilder.h" 15 | #include "IPropertyTypeCustomization.h" 16 | #include "IPropertyUtilities.h" 17 | #include "Internationalization/Text.h" 18 | #include "Misc/AssertionMacros.h" 19 | #include "Modules/ModuleManager.h" 20 | #include "PropertyCustomizationHelpers.h" 21 | #include "PropertyEditorModule.h" 22 | #include "PropertyHandle.h" 23 | #include "UObject/UnrealType.h" 24 | #include "Editor/UnrealEditorUtils.h" 25 | #include "Widgets/Text/STextBlock.h" 26 | #include "AssetRegistry/AssetRegistryModule.h" 27 | namespace ComponentPicker 28 | { 29 | static const FName NameComponent = TEXT("ComponentName"); 30 | static const FName NameComponentClass = TEXT("ComponentClass"); 31 | } // namespace ComponentPicker 32 | 33 | TSharedRef FComponentPickerCustomization::MakeInstance() 34 | { 35 | return MakeShareable(new FComponentPickerCustomization); 36 | } 37 | 38 | void FComponentPickerCustomization::CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) 39 | { 40 | TArray OuterObjects; 41 | PropertyHandle->GetOuterObjects(OuterObjects); 42 | if (OuterObjects.Num() == 1) 43 | { 44 | RootPropertyHandle = PropertyHandle; 45 | auto Outer = OuterObjects[0]; 46 | AActor* Actor = nullptr; 47 | auto ComponentHandle = PropertyHandle->GetChildHandle(ComponentPicker::NameComponent, false); 48 | check(ComponentHandle.IsValid()); 49 | ComponentHandle->MarkHiddenByCustomization(); 50 | 51 | auto FilterHandle = PropertyHandle->GetChildHandle(ComponentPicker::NameComponentClass, false); 52 | check(FilterHandle.IsValid()); 53 | 54 | FName SelfComponentName; 55 | auto TestOuter = Outer; 56 | while (TestOuter) 57 | { 58 | Actor = Cast(TestOuter); 59 | if (Actor) 60 | break; 61 | if (SelfComponentName.IsNone()) 62 | { 63 | if (auto SelfComp = Cast(TestOuter)) 64 | { 65 | SelfComponentName = SelfComp->GetFName(); 66 | } 67 | } 68 | TestOuter = TestOuter->GetOuter(); 69 | } 70 | 71 | FilterClass = UActorComponent::StaticClass(); 72 | const FString& ClassName = PropertyHandle->GetMetaData("MetaClass"); 73 | if (!ClassName.IsEmpty()) 74 | { 75 | #if UE_5_00_OR_LATER 76 | UClass* Class = UClass::TryFindTypeSlowSafe(ClassName); 77 | #else 78 | UClass* Class = FindObject(ANY_PACKAGE_COMPATIABLE, *ClassName); 79 | #endif 80 | if (!Class) 81 | { 82 | Class = LoadObject(nullptr, *ClassName); 83 | } 84 | if (Class && Class->IsChildOf()) 85 | { 86 | FilterClass = Class; 87 | } 88 | } 89 | else 90 | { 91 | if (auto Class = UnrealEditorUtils::GetPropertyMemberPtr>(PropertyHandle, ComponentPicker::NameComponentClass)) 92 | { 93 | if (Class->Get()) 94 | { 95 | FilterClass = *Class; 96 | } 97 | } 98 | } 99 | 100 | TSubclassOf CDOActorClass = nullptr; 101 | if (!Actor || !Actor->GetLevel()) 102 | { 103 | TestOuter = Outer; 104 | while (TestOuter) 105 | { 106 | UBlueprintGeneratedClass* RootBlueprintGeneratedClass = Cast(TestOuter->GetClass()); 107 | if (RootBlueprintGeneratedClass && RootBlueprintGeneratedClass->IsChildOf(AActor::StaticClass())) 108 | { 109 | CDOActorClass = static_cast>(RootBlueprintGeneratedClass); 110 | break; 111 | } 112 | TestOuter = TestOuter->GetOuter(); 113 | } 114 | } 115 | 116 | if (!CDOActorClass && !Actor) 117 | { 118 | FilterHandle->MarkHiddenByCustomization(); 119 | auto ComponentNameHandle = PropertyHandle->GetChildHandle(ComponentPicker::NameComponent, false); 120 | if (ComponentNameHandle.IsValid()) 121 | { 122 | HeaderRow 123 | .NameContent() 124 | [ 125 | ComponentNameHandle->CreatePropertyNameWidget() 126 | ] 127 | .ValueContent() 128 | [ 129 | ComponentNameHandle->CreatePropertyValueWidget() 130 | ]; 131 | } 132 | return; 133 | } 134 | 135 | if (!Outer->HasAnyFlags(RF_ClassDefaultObject)) 136 | FilterHandle->MarkHiddenByCustomization(); 137 | 138 | Names.Reset(); 139 | FName* MyValue = UnrealEditorUtils::GetPropertyMemberPtr(PropertyHandle, ComponentPicker::NameComponent); 140 | CurText = FText::FromName(*MyValue); 141 | if (*MyValue != NAME_None) 142 | Names.Add(MakeShared(NAME_None)); 143 | auto SharedMyValue = MakeShared(*MyValue); 144 | Names.Add(SharedMyValue); 145 | for (auto& a : FComponentPickerCustomization::GetNames(Actor, CDOActorClass, FilterClass, SelfComponentName)) 146 | { 147 | Names.Add(MakeShared(a)); 148 | } 149 | TSharedPtr ValueWidget; 150 | HeaderRow 151 | .IsEnabled(!PropertyHandle->IsEditConst()) 152 | .NameContent() 153 | [ 154 | PropertyHandle->CreatePropertyNameWidget() 155 | ] 156 | .ValueContent() 157 | .MinDesiredWidth(260.f) 158 | .MaxDesiredWidth(0.f) 159 | [ 160 | SNew(SHorizontalBox) 161 | + SHorizontalBox::Slot() 162 | .AutoWidth() 163 | [ 164 | SAssignNew(ValueWidget, SComboBox>) 165 | .OptionsSource(&Names) 166 | .InitiallySelectedItem(SharedMyValue) 167 | .OnGenerateWidget_Lambda([](TSharedPtr InName) { 168 | return SNew(STextBlock) 169 | .Text(FText::FromName(*InName)); 170 | }) 171 | .OnSelectionChanged_Lambda([this](TSharedPtr InName, ESelectInfo::Type SelectInfo) { 172 | if (SelectInfo == ESelectInfo::OnNavigation) 173 | { 174 | return; 175 | } 176 | auto ThisProperty = RootPropertyHandle.Pin(); 177 | if (ThisProperty.IsValid()) 178 | { 179 | if (auto CurName = UnrealEditorUtils::GetPropertyMemberPtr(ThisProperty, ComponentPicker::NameComponent)) 180 | { 181 | CurText = FText::FromName(*InName); 182 | if (*InName != *CurName) 183 | { 184 | GEditor->BeginTransaction(TEXT("PropertyEditor"), NSLOCTEXT("LeveledPicker", "EditPropertyTransaction", "Edit LeveledPicker"), GetPropertyOwnerUObject(ThisProperty->GetProperty())); 185 | ThisProperty->NotifyPreChange(); 186 | *CurName = *InName; 187 | ThisProperty->NotifyPostChange(EPropertyChangeType::ValueSet); 188 | ThisProperty->NotifyFinishedChangingProperties(); 189 | GEditor->EndTransaction(); 190 | } 191 | } 192 | } 193 | }) 194 | .Content() 195 | [ 196 | SNew(STextBlock) 197 | .Text_Lambda([this] { 198 | auto ThisProperty = RootPropertyHandle.Pin(); 199 | if (ThisProperty.IsValid()) 200 | { 201 | if (FName* MyValue = UnrealEditorUtils::GetPropertyMemberPtr(ThisProperty, ComponentPicker::NameComponent)) 202 | { 203 | return FText::FromName(*MyValue); 204 | } 205 | } 206 | return FText::FromName(NAME_None); 207 | }) 208 | ] 209 | ] 210 | ]; 211 | ValueWidget->SetEnabled(!PropertyHandle->IsEditConst()); 212 | } 213 | } 214 | 215 | void FComponentPickerCustomization::CustomizeChildren(TSharedRef PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils) 216 | { 217 | PropertyHandle->MarkHiddenByCustomization(); 218 | // if (!CDOActorClass.Get()) 219 | // return; 220 | // 221 | // TArray OuterObjects; 222 | // PropertyHandle->GetOuterObjects(OuterObjects); 223 | // if (OuterObjects.Num() == 1) 224 | // { 225 | // if (auto ComponentNameHandle = PropertyHandle->GetChildHandle(ComponentPicker::NameComponent, false)) 226 | // { 227 | // ChildBuilder.AddProperty(ComponentNameHandle.ToSharedRef()); 228 | // auto Utilities = CustomizationUtils.GetPropertyUtilities(); 229 | // ComponentNameHandle->SetOnPropertyValueChanged( 230 | // FSimpleDelegate::CreateLambda([Utilities] { Utilities->ForceRefresh(); })); 231 | // } 232 | // // if (auto ComponentClassHandle = PropertyHandle->GetChildHandle(ComponentPicker::NameComponentClass, false)) 233 | // // { 234 | // // ChildBuilder.AddProperty(ComponentClassHandle.ToSharedRef()); 235 | // // } 236 | // } 237 | } 238 | 239 | TArray FComponentPickerCustomization::GetNames(AActor* Actor, TSubclassOf InActorClass, TSubclassOf InClass, FName ExInclueName) 240 | { 241 | TArray Ret; 242 | if (!InClass) 243 | InClass = UActorComponent::StaticClass(); 244 | if (Actor) 245 | { 246 | for (auto& a : Actor->GetComponents()) 247 | { 248 | if (a->IsA(InClass) && ExInclueName != a->GetFName()) 249 | Ret.AddUnique(a->GetFName()); 250 | } 251 | } 252 | else 253 | { 254 | // AActor* ActorCDO = InActorClass->GetDefaultObject(); 255 | // FObjectPropertyBase* ObjProp = FindFProperty(ActorCDO->GetClass(), CompnentName); 256 | // if (ObjProp) 257 | // { 258 | // if (auto Comp = Cast(ObjProp->GetObjectPropertyValue_InContainer(ActorCDO))) 259 | // Ret.AddUnique(Comp->GetFName()); 260 | // } 261 | 262 | // Check blueprint nodes. Components added in blueprint editor only (and not in code) are not available from 263 | // CDO. 264 | UBlueprintGeneratedClass* RootBlueprintGeneratedClass = Cast(InActorClass); 265 | UClass* ActorClass = InActorClass; 266 | 267 | // Go down the inheritance tree to find nodes that were added to parent blueprints of our blueprint graph. 268 | do 269 | { 270 | if (!IsValid(ActorClass)) 271 | { 272 | return Ret; 273 | } 274 | 275 | UBlueprintGeneratedClass* ActorBlueprintGeneratedClass = Cast(ActorClass); 276 | if (!ActorBlueprintGeneratedClass) 277 | { 278 | break; 279 | } 280 | 281 | const TArray& ActorBlueprintNodes = ActorBlueprintGeneratedClass->SimpleConstructionScript->GetAllNodes(); 282 | 283 | for (USCS_Node* Node : ActorBlueprintNodes) 284 | { 285 | if (Node->ComponentClass->IsChildOf(InClass)) 286 | { 287 | if (ExInclueName != Node->GetVariableName()) 288 | Ret.AddUnique(Node->GetVariableName()); 289 | } 290 | } 291 | ActorClass = Cast(ActorClass->GetSuperStruct()); 292 | } while (ActorClass != AActor::StaticClass()); 293 | } 294 | return Ret; 295 | } 296 | #endif 297 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/Editor/ComponentPickerCustomization.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #if WITH_EDITOR 7 | #include "CoreUObject.h" 8 | 9 | #include "Components/ActorComponent.h" 10 | #include "IDetailCustomization.h" 11 | #include "IPropertyTypeCustomization.h" 12 | #include "Templates/SubclassOf.h" 13 | 14 | class FComponentPickerCustomization : public IPropertyTypeCustomization 15 | { 16 | public: 17 | static TSharedRef MakeInstance(); 18 | 19 | protected: 20 | virtual void CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) override; 21 | virtual void CustomizeChildren(TSharedRef PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils) override; 22 | 23 | TArray> Names; 24 | TWeakPtr RootPropertyHandle; 25 | TSubclassOf FilterClass; 26 | FText CurText; 27 | static TArray GetNames(AActor* Actor, TSubclassOf InActorClass, TSubclassOf InClass, FName ExInclueName = NAME_None); 28 | 29 | template 30 | static TArray GetNames(const TSubclassOf InActorClass, FName ExInclueName = NAME_None) 31 | { 32 | return GetNames(InActorClass, T::StaticClass(), ExInclueName); 33 | } 34 | }; 35 | #endif 36 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/Editor/DataTablePickerCustomization.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #include "DataTablePickerCustomization.h" 4 | 5 | #if WITH_EDITOR 6 | #include "Slate.h" 7 | 8 | #include "DataTableEditorUtils.h" 9 | #include "DataTablePicker.h" 10 | #include "DetailCategoryBuilder.h" 11 | #include "DetailLayoutBuilder.h" 12 | #include "Editor.h" 13 | #include "Engine/BlueprintGeneratedClass.h" 14 | #include "Engine/Level.h" 15 | #include "Engine/Selection.h" 16 | #include "Engine/SimpleConstructionScript.h" 17 | #include "Engine/World.h" 18 | #include "EngineUtils.h" 19 | #include "GameFramework/Actor.h" 20 | #include "IDetailChildrenBuilder.h" 21 | #include "IPropertyTypeCustomization.h" 22 | #include "IPropertyUtilities.h" 23 | #include "Internationalization/Text.h" 24 | #include "PropertyCustomizationHelpers.h" 25 | #include "PropertyHandle.h" 26 | #include "SNameComboBox.h" 27 | #include "UObject/LinkerLoad.h" 28 | #include "UObject/ObjectMacros.h" 29 | #include "UObject/UnrealType.h" 30 | 31 | namespace DataTablePickerCustomization 32 | { 33 | #if UE_4_20_OR_LATER 34 | using SNameComboBox = ::SNameComboBox; 35 | #else 36 | class SNameComboBox : public SCompoundWidget 37 | { 38 | public: 39 | DECLARE_DELEGATE_RetVal_OneParam(FString, FGetNameComboLabel, TSharedPtr); 40 | typedef TSlateDelegates>::FOnSelectionChanged FOnNameSelectionChanged; 41 | 42 | SLATE_BEGIN_ARGS(SNameComboBox) 43 | : _ColorAndOpacity(FSlateColor::UseForeground()) 44 | , _ContentPadding(FMargin(4.0, 2.0)) 45 | , _OnGetNameLabelForItem() 46 | {} 47 | SLATE_ARGUMENT(TArray>*, OptionsSource) 48 | SLATE_ATTRIBUTE(FSlateColor, ColorAndOpacity) 49 | SLATE_ATTRIBUTE(FMargin, ContentPadding) 50 | SLATE_EVENT(FOnNameSelectionChanged, OnSelectionChanged) 51 | SLATE_EVENT(FOnComboBoxOpening, OnComboBoxOpening) 52 | SLATE_ARGUMENT(TSharedPtr, InitiallySelectedItem) 53 | SLATE_EVENT(FGetNameComboLabel, OnGetNameLabelForItem) 54 | SLATE_END_ARGS() 55 | 56 | void Construct(const FArguments& InArgs) 57 | { 58 | SelectionChanged = InArgs._OnSelectionChanged; 59 | GetTextLabelForItem = InArgs._OnGetNameLabelForItem; 60 | 61 | // Then make widget 62 | this->ChildSlot 63 | [ 64 | SAssignNew(NameCombo, SComboBox>) 65 | .OptionsSource(InArgs._OptionsSource) 66 | .OnGenerateWidget(this, &SNameComboBox::MakeItemWidget) 67 | .OnSelectionChanged(this, &SNameComboBox::OnSelectionChanged) 68 | .OnComboBoxOpening(InArgs._OnComboBoxOpening) 69 | .InitiallySelectedItem(InArgs._InitiallySelectedItem) 70 | .ContentPadding(InArgs._ContentPadding) 71 | [ 72 | SNew(STextBlock) 73 | .ColorAndOpacity(InArgs._ColorAndOpacity) 74 | .Text(this, &SNameComboBox::GetSelectedNameLabel) 75 | ] 76 | ]; 77 | SelectedItem = NameCombo->GetSelectedItem(); 78 | } 79 | 80 | TSharedRef MakeItemWidget(TSharedPtr NameItem) 81 | { 82 | check(NameItem.IsValid()); 83 | 84 | return SNew(STextBlock) 85 | .Text(this, &SNameComboBox::GetItemNameLabel, NameItem); 86 | } 87 | 88 | void SetSelectedItem(TSharedPtr NewSelection) { NameCombo->SetSelectedItem(NewSelection); } 89 | TSharedPtr GetSelectedItem() { return SelectedItem; } 90 | void RefreshOptions() { NameCombo->RefreshOptions(); } 91 | void ClearSelection() { NameCombo->ClearSelection(); } 92 | 93 | private: 94 | TSharedPtr OnGetSelection() const { return SelectedItem; } 95 | void OnSelectionChanged(TSharedPtr Selection, ESelectInfo::Type SelectInfo) 96 | { 97 | if (Selection.IsValid()) 98 | { 99 | SelectedItem = Selection; 100 | } 101 | SelectionChanged.ExecuteIfBound(Selection, SelectInfo); 102 | } 103 | FText GetSelectedNameLabel() const 104 | { 105 | TSharedPtr StringItem = NameCombo->GetSelectedItem(); 106 | return GetItemNameLabel(StringItem); 107 | } 108 | 109 | FText GetItemNameLabel(TSharedPtr NameItem) const 110 | { 111 | if (!NameItem.IsValid()) 112 | { 113 | return FText::GetEmpty(); 114 | } 115 | 116 | return (GetTextLabelForItem.IsBound()) ? FText::FromString(GetTextLabelForItem.Execute(NameItem)) : FText::FromName(*NameItem); 117 | } 118 | 119 | private: 120 | FGetNameComboLabel GetTextLabelForItem; 121 | TSharedPtr SelectedItem; 122 | TArray> Names; 123 | TSharedPtr>> NameCombo; 124 | FOnNameSelectionChanged SelectionChanged; 125 | }; 126 | #endif 127 | } // namespace DataTablePickerCustomization 128 | 129 | TSharedRef FDataTablePickerCustomization::MakeInstance() 130 | { 131 | return MakeShareable(new FDataTablePickerCustomization); 132 | } 133 | 134 | void FDataTablePickerCustomization::CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) 135 | { 136 | TArray OuterObjects; 137 | PropertyHandle->GetOuterObjects(OuterObjects); 138 | if (OuterObjects.Num() == 1) 139 | { 140 | RootPropertyHandle = PropertyHandle; 141 | 142 | auto OrignalPtr = UnrealEditorUtils::GetPropertyAddress(PropertyHandle); 143 | check(OrignalPtr); 144 | 145 | StructTypePicker.Init(PropertyHandle); 146 | auto Utilities = CustomizationUtils.GetPropertyUtilities(); 147 | auto DataPropertyHandle = PropertyHandle->GetChildHandle("DataTable", false); 148 | 149 | HeaderRow 150 | .NameContent() 151 | [ 152 | PropertyHandle->CreatePropertyNameWidget() 153 | ] 154 | .ValueContent() 155 | .MinDesiredWidth(250.f) 156 | .MaxDesiredWidth(0.f) 157 | [ 158 | SNew(SHorizontalBox) 159 | + SHorizontalBox::Slot() 160 | .FillWidth(120) 161 | [ 162 | StructTypePicker.MakePropertyWidget(DataPropertyHandle) 163 | ] 164 | ]; 165 | } 166 | } 167 | 168 | ////////////////////////////////////////////////////////////////////////// 169 | TSharedRef FDataTablePathPickerCustomization::MakeInstance() 170 | { 171 | return MakeShareable(new FDataTablePathPickerCustomization()); 172 | } 173 | 174 | void FDataTablePathPickerCustomization::CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) 175 | { 176 | TArray OuterObjects; 177 | PropertyHandle->GetOuterObjects(OuterObjects); 178 | if (OuterObjects.Num() == 1) 179 | { 180 | RootPropertyHandle = PropertyHandle; 181 | 182 | auto OrignalPtr = UnrealEditorUtils::GetPropertyAddress(PropertyHandle); 183 | check(OrignalPtr); 184 | 185 | StructTypePicker.Init(PropertyHandle); 186 | 187 | auto Utilities = CustomizationUtils.GetPropertyUtilities(); 188 | 189 | auto DataPropertyHandle = PropertyHandle->GetChildHandle("DataTablePath", false); 190 | HeaderRow 191 | .NameContent() 192 | [ 193 | PropertyHandle->CreatePropertyNameWidget() 194 | ] 195 | .ValueContent() 196 | .MinDesiredWidth(250.f) 197 | .MaxDesiredWidth(0.f) 198 | 199 | [ 200 | SNew(SHorizontalBox) 201 | + SHorizontalBox::Slot() 202 | .FillWidth(120) 203 | 204 | [ 205 | StructTypePicker.MakePropertyWidget(DataPropertyHandle) 206 | ] 207 | ]; 208 | } 209 | } 210 | 211 | ////////////////////////////////////////////////////////////////////////// 212 | TSharedRef FDataTableRowNamePickerCustomization::MakeInstance() 213 | { 214 | return MakeShareable(new FDataTableRowNamePickerCustomization); 215 | } 216 | 217 | inline void FDataTableRowNamePickerCustomization::PostChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info) 218 | { 219 | #if WITH_EDITORONLY_DATA 220 | auto ThisProperty = RootPropertyHandle.Pin(); 221 | if (ThisProperty.IsValid()) 222 | { 223 | if (auto Ptr = UnrealEditorUtils::GetPropertyAddress(ThisProperty)) 224 | { 225 | if (Changed && (Changed == Ptr->DataTablePath.Get()) && (FDataTableEditorUtils::EDataTableChangeInfo::RowList == Info)) 226 | { 227 | auto R = Utilities.Pin(); 228 | if (R.IsValid()) 229 | R->RequestRefresh(); 230 | } 231 | } 232 | } 233 | #endif 234 | } 235 | 236 | void FDataTableRowNamePickerCustomization::CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) 237 | { 238 | TArray OuterObjects; 239 | PropertyHandle->GetOuterObjects(OuterObjects); 240 | if (OuterObjects.Num() == 1) 241 | { 242 | RootPropertyHandle = PropertyHandle; 243 | auto* OrignalPtr = UnrealEditorUtils::GetPropertyAddress(PropertyHandle); 244 | check(OrignalPtr); 245 | TSharedPtr CurrentlySelectedName; 246 | if (auto Table = OrignalPtr->DataTablePath.Get()) 247 | { 248 | PreloadObject(Table); 249 | NameList.Empty(); 250 | for (auto a : Table->GetRowNames()) 251 | { 252 | auto Ptr = MakeShared(a); 253 | NameList.Add(Ptr); 254 | if (OrignalPtr->RowName == a) 255 | CurrentlySelectedName = Ptr; 256 | } 257 | } 258 | 259 | StructTypePicker.Init(PropertyHandle); 260 | 261 | Utilities = CustomizationUtils.GetPropertyUtilities(); 262 | StructTypePicker.OnChanged.BindLambda([this] { 263 | auto ThisProperty = RootPropertyHandle.Pin(); 264 | if (ThisProperty.IsValid()) 265 | { 266 | if (auto Ptr = UnrealEditorUtils::GetPropertyAddress(ThisProperty)) 267 | { 268 | { 269 | UnrealEditorUtils::FScopedPropertyTransaction Scoped(ThisProperty); 270 | Ptr->RowName = NAME_None; 271 | #if WITH_EDITORONLY_DATA 272 | Ptr->DataTablePath = nullptr; 273 | #endif 274 | } 275 | TArray OuterObjects; 276 | ThisProperty->GetOuterObjects(OuterObjects); 277 | for (auto& a : OuterObjects) 278 | a->MarkPackageDirty(); 279 | } 280 | } 281 | }); 282 | 283 | auto SoftPropertyHandle = PropertyHandle->GetChildHandle("DataTablePath", false); 284 | HeaderRow 285 | .NameContent() 286 | [ 287 | PropertyHandle->CreatePropertyNameWidget() 288 | ] 289 | .ValueContent() 290 | .MinDesiredWidth(250.f) 291 | .MaxDesiredWidth(0.f) 292 | [ 293 | SNew(SHorizontalBox) 294 | + SHorizontalBox::Slot() 295 | .FillWidth(60) 296 | [ 297 | SNew(DataTablePickerCustomization::SNameComboBox) 298 | .ContentPadding(FMargin(6.0f, 2.0f)) 299 | .OptionsSource(&NameList) 300 | .InitiallySelectedItem(CurrentlySelectedName) 301 | .OnSelectionChanged(this, &FDataTableRowNamePickerCustomization::ComboBoxSelectionChanged) 302 | ] 303 | + SHorizontalBox::Slot() 304 | .FillWidth(160) 305 | [ 306 | StructTypePicker.MakePropertyWidget(SoftPropertyHandle) 307 | ] 308 | + SHorizontalBox::Slot() 309 | .FillWidth(120) 310 | [ 311 | StructTypePicker.MakeWidget() 312 | ] 313 | ]; 314 | } 315 | } 316 | 317 | void FDataTableRowNamePickerCustomization::ComboBoxSelectionChanged(TSharedPtr NameItem, ESelectInfo::Type SelectInfo) 318 | { 319 | FName Name = NameItem.IsValid() ? *NameItem : NAME_None; 320 | auto ThisProperty = RootPropertyHandle.Pin(); 321 | if (ThisProperty.IsValid()) 322 | { 323 | if (auto Ptr = UnrealEditorUtils::GetPropertyAddress(ThisProperty)) 324 | { 325 | if (Ptr->RowName != Name) 326 | { 327 | UnrealEditorUtils::FScopedPropertyTransaction Scoped(ThisProperty); 328 | Ptr->RowName = Name; 329 | TArray OuterObjects; 330 | ThisProperty->GetOuterObjects(OuterObjects); 331 | for (auto& a : OuterObjects) 332 | a->MarkPackageDirty(); 333 | } 334 | } 335 | } 336 | } 337 | 338 | void FDataTableRowNamePickerCustomization::PreloadObject(UObject* ReferencedObject) 339 | { 340 | if ((ReferencedObject != NULL) && ReferencedObject->HasAnyFlags(RF_NeedLoad)) 341 | { 342 | ReferencedObject->GetLinker()->Preload(ReferencedObject); 343 | } 344 | } 345 | 346 | ////////////////////////////////////////////////////////////////////////// 347 | TSharedRef FDataTableRowPickerCustomization::MakeInstance() 348 | { 349 | return MakeShareable(new FDataTableRowPickerCustomization); 350 | } 351 | 352 | inline void FDataTableRowPickerCustomization::PostChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info) 353 | { 354 | auto ThisProperty = RootPropertyHandle.Pin(); 355 | if (ThisProperty.IsValid()) 356 | { 357 | if (auto Ptr = UnrealEditorUtils::GetPropertyAddress(ThisProperty)) 358 | { 359 | if (Changed && (Changed == Ptr->DataTable) && (FDataTableEditorUtils::EDataTableChangeInfo::RowList == Info)) 360 | { 361 | auto R = Utilities.Pin(); 362 | if (R.IsValid()) 363 | R->RequestRefresh(); 364 | } 365 | } 366 | } 367 | } 368 | 369 | void FDataTableRowPickerCustomization::CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) 370 | { 371 | TArray OuterObjects; 372 | PropertyHandle->GetOuterObjects(OuterObjects); 373 | if (OuterObjects.Num() == 1) 374 | { 375 | RootPropertyHandle = PropertyHandle; 376 | FDataTableRowPicker* OrignalPtr = UnrealEditorUtils::GetPropertyAddress(PropertyHandle); 377 | check(OrignalPtr); 378 | TSharedPtr CurrentlySelectedName; 379 | if (auto Table = OrignalPtr->DataTable) 380 | { 381 | PreloadObject(Table); 382 | NameList.Empty(); 383 | for (auto a : Table->GetRowNames()) 384 | { 385 | auto Ptr = MakeShared(a); 386 | NameList.Add(Ptr); 387 | if (OrignalPtr->RowName == a) 388 | CurrentlySelectedName = Ptr; 389 | } 390 | } 391 | 392 | StructTypePicker.Init(PropertyHandle); 393 | 394 | Utilities = CustomizationUtils.GetPropertyUtilities(); 395 | StructTypePicker.OnChanged.BindLambda([this] { 396 | auto ThisProperty = RootPropertyHandle.Pin(); 397 | if (ThisProperty.IsValid()) 398 | { 399 | if (auto Ptr = UnrealEditorUtils::GetPropertyAddress(ThisProperty)) 400 | { 401 | { 402 | UnrealEditorUtils::FScopedPropertyTransaction Scoped(ThisProperty); 403 | Ptr->DataTable = nullptr; 404 | Ptr->RowName = NAME_None; 405 | } 406 | // Utilities->ForceRefresh(); 407 | TArray OuterObjects; 408 | ThisProperty->GetOuterObjects(OuterObjects); 409 | for (auto& a : OuterObjects) 410 | a->MarkPackageDirty(); 411 | } 412 | } 413 | }); 414 | 415 | auto TablePropertyHandle = PropertyHandle->GetChildHandle("DataTable", false); 416 | HeaderRow 417 | .NameContent() 418 | [ 419 | PropertyHandle->CreatePropertyNameWidget() 420 | ] 421 | .ValueContent() 422 | .MinDesiredWidth(250.f) 423 | .MaxDesiredWidth(0.f) 424 | [ 425 | SNew(SHorizontalBox) 426 | + SHorizontalBox::Slot() 427 | .FillWidth(60) 428 | [ 429 | SNew(DataTablePickerCustomization::SNameComboBox) 430 | .ContentPadding(FMargin(6.0f, 2.0f)) 431 | .OptionsSource(&NameList) 432 | .InitiallySelectedItem(CurrentlySelectedName) 433 | .OnSelectionChanged(this, &FDataTableRowPickerCustomization::ComboBoxSelectionChanged) 434 | ] 435 | + SHorizontalBox::Slot() 436 | .FillWidth(160) 437 | [ 438 | StructTypePicker.MakePropertyWidget(TablePropertyHandle) 439 | ] 440 | + SHorizontalBox::Slot() 441 | .FillWidth(120) 442 | [ 443 | StructTypePicker.MakeWidget() 444 | ] 445 | ]; 446 | } 447 | } 448 | 449 | void FDataTableRowPickerCustomization::ComboBoxSelectionChanged(TSharedPtr NameItem, ESelectInfo::Type SelectInfo) 450 | { 451 | FName Name = NameItem.IsValid() ? *NameItem : NAME_None; 452 | auto ThisProperty = RootPropertyHandle.Pin(); 453 | if (ThisProperty.IsValid()) 454 | { 455 | if (auto Ptr = UnrealEditorUtils::GetPropertyAddress(ThisProperty)) 456 | { 457 | if (Ptr->RowName != Name) 458 | { 459 | UnrealEditorUtils::FScopedPropertyTransaction Scoped(ThisProperty); 460 | Ptr->RowName = Name; 461 | TArray OuterObjects; 462 | ThisProperty->GetOuterObjects(OuterObjects); 463 | for (auto& a : OuterObjects) 464 | a->MarkPackageDirty(); 465 | } 466 | } 467 | } 468 | } 469 | 470 | void FDataTableRowPickerCustomization::PreloadObject(UObject* ReferencedObject) 471 | { 472 | if ((ReferencedObject != NULL) && ReferencedObject->HasAnyFlags(RF_NeedLoad)) 473 | { 474 | ReferencedObject->GetLinker()->Preload(ReferencedObject); 475 | } 476 | } 477 | #endif 478 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/Editor/DataTablePickerCustomization.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | #include "CoreMinimal.h" 5 | 6 | #if WITH_EDITOR 7 | #include "CoreUObject.h" 8 | 9 | #include "DataTableEditorUtils.h" 10 | #include "Editor/UnrealEditorUtils.h" 11 | #include "IDetailCustomization.h" 12 | #include "IPropertyTypeCustomization.h" 13 | #include "Templates/SubclassOf.h" 14 | #include "UnrealCompatibility.h" 15 | 16 | class UScriptStruct; 17 | class FDataTablePickerCustomization : public IPropertyTypeCustomization 18 | { 19 | public: 20 | static TSharedRef MakeInstance(); 21 | 22 | protected: 23 | virtual void CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) override; 24 | virtual void CustomizeChildren(TSharedRef PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils) override {} 25 | 26 | TWeakPtr RootPropertyHandle; 27 | UnrealEditorUtils::FDatatableTypePicker StructTypePicker; 28 | }; 29 | 30 | class FDataTablePathPickerCustomization : public IPropertyTypeCustomization 31 | { 32 | public: 33 | static TSharedRef MakeInstance(); 34 | 35 | protected: 36 | virtual void CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) override; 37 | virtual void CustomizeChildren(TSharedRef PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils) override {} 38 | 39 | TWeakPtr RootPropertyHandle; 40 | UnrealEditorUtils::FDatatableTypePicker StructTypePicker; 41 | }; 42 | 43 | class FDataTableRowNamePickerCustomization 44 | : public IPropertyTypeCustomization 45 | , public FDataTableEditorUtils::INotifyOnDataTableChanged 46 | { 47 | public: 48 | static TSharedRef MakeInstance(); 49 | 50 | protected: 51 | void PreChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info) {} 52 | 53 | void PostChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info); 54 | virtual void CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) override; 55 | virtual void CustomizeChildren(TSharedRef PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils) override {} 56 | void ComboBoxSelectionChanged(TSharedPtr StringItem, ESelectInfo::Type SelectInfo); 57 | TWeakPtr Utilities; 58 | TArray> NameList; 59 | // Ensures the specified object is preloaded. ReferencedObject can be NULL. 60 | void PreloadObject(UObject* ReferencedObject); 61 | FString ObjectPath; 62 | TWeakPtr RootPropertyHandle; 63 | UnrealEditorUtils::FDatatableTypePicker StructTypePicker; 64 | }; 65 | 66 | class FDataTableRowPickerCustomization 67 | : public IPropertyTypeCustomization 68 | , public FDataTableEditorUtils::INotifyOnDataTableChanged 69 | 70 | { 71 | public: 72 | static TSharedRef MakeInstance(); 73 | 74 | protected: 75 | void PreChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info) {} 76 | 77 | void PostChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info); 78 | virtual void CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) override; 79 | virtual void CustomizeChildren(TSharedRef PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils) override {} 80 | 81 | TWeakPtr Utilities; 82 | void ComboBoxSelectionChanged(TSharedPtr StringItem, ESelectInfo::Type SelectInfo); 83 | TArray> NameList; 84 | // Ensures the specified object is preloaded. ReferencedObject can be NULL. 85 | void PreloadObject(UObject* ReferencedObject); 86 | FString ObjectPath; 87 | TWeakPtr RootPropertyHandle; 88 | UnrealEditorUtils::FDatatableTypePicker StructTypePicker; 89 | }; 90 | #endif 91 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/Editor/GenericSystemConfigCustomization.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #include "GenericSystemConfigCustomization.h" 4 | 5 | #if WITH_EDITOR 6 | #include "Slate.h" 7 | 8 | #include "DetailCategoryBuilder.h" 9 | #include "DetailLayoutBuilder.h" 10 | #include "Editor.h" 11 | #include "Editor/UnrealEditorUtils.h" 12 | #include "Engine/BlueprintGeneratedClass.h" 13 | #include "Engine/Level.h" 14 | #include "Engine/Selection.h" 15 | #include "Engine/SimpleConstructionScript.h" 16 | #include "Engine/World.h" 17 | #include "EngineUtils.h" 18 | #include "GameFramework/Actor.h" 19 | #include "GenericSystems.h" 20 | #include "IDetailChildrenBuilder.h" 21 | #include "IPropertyTypeCustomization.h" 22 | #include "IPropertyUtilities.h" 23 | #include "Internationalization/Text.h" 24 | #include "PropertyCustomizationHelpers.h" 25 | #include "PropertyHandle.h" 26 | #include "SNameComboBox.h" 27 | #include "UObject/LinkerLoad.h" 28 | #include "UObject/ObjectMacros.h" 29 | #include "UObject/UnrealType.h" 30 | 31 | TSharedRef FGenericSystemConfigCustomization::MakeInstance() 32 | { 33 | return MakeShareable(new FGenericSystemConfigCustomization); 34 | } 35 | 36 | void FGenericSystemConfigCustomization::CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) 37 | { 38 | TArray OuterObjects; 39 | PropertyHandle->GetOuterObjects(OuterObjects); 40 | if (OuterObjects.Num() == 1) 41 | { 42 | RootPropertyHandle = PropertyHandle; 43 | PropertyHandle->MarkResetToDefaultCustomized(); 44 | auto ClassHandle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FGenericSystemConfig, SystemClass), false); 45 | check(ClassHandle.IsValid()); 46 | 47 | SystemClass = UnrealEditorUtils::GetPropertyAddress(PropertyHandle)->SystemClass; 48 | HeaderRow 49 | .NameContent() 50 | [ 51 | PropertyHandle->CreatePropertyNameWidget() 52 | ] 53 | .ValueContent() 54 | .MinDesiredWidth(160.f) 55 | [ 56 | SNew(SHorizontalBox) 57 | + SHorizontalBox::Slot() 58 | .AutoWidth() 59 | [ 60 | SNew(SClassPropertyEntryBox) 61 | .MetaClass(AGenericSystemBase::StaticClass()) 62 | .AllowAbstract(false) 63 | .AllowNone(false) 64 | .SelectedClass(SystemClass) 65 | .OnSetClass_Lambda([this](const UClass* Class) { 66 | auto ThisProperty = RootPropertyHandle.Pin(); 67 | if (ThisProperty.IsValid()) 68 | { 69 | auto ClassHandle = ThisProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FGenericSystemConfig, SystemClass), false); 70 | if (ClassHandle.IsValid()) 71 | { 72 | SystemClass = const_cast(Class); 73 | ClassHandle->SetValue(SystemClass); 74 | } 75 | } 76 | }) 77 | ] 78 | // Use button 79 | + SHorizontalBox::Slot() 80 | .AutoWidth() 81 | [ 82 | PropertyCustomizationHelpers::MakeBrowseButton(FSimpleDelegate::CreateSP(this, &FGenericSystemConfigCustomization::BrowseTo), NSLOCTEXT("GenericSystems", "SelectInstance", "Select Instance")) 83 | ] 84 | 85 | ]; 86 | } 87 | } 88 | 89 | void FGenericSystemConfigCustomization::BrowseTo() 90 | { 91 | auto ThisProperty = RootPropertyHandle.Pin(); 92 | if (!ThisProperty.IsValid()) 93 | return; 94 | 95 | FGenericSystemConfig* OrignalPtr = UnrealEditorUtils::GetPropertyAddress(ThisProperty); 96 | check(OrignalPtr); 97 | 98 | if (AActor* Actor = OrignalPtr->SystemIns.Get()) 99 | { 100 | if (USelection* Selection = GEditor->GetSelectedActors()) 101 | { 102 | if (Selection->Num() == 1 && Selection->GetSelectedObject(0) == Actor) 103 | { 104 | GEditor->MoveViewportCamerasToActor(*Actor, false); 105 | } 106 | else 107 | { 108 | Selection->BeginBatchSelectOperation(); 109 | GEditor->SelectNone(false, true, false); 110 | GEditor->SelectActor(Actor, true, true); 111 | Selection->EndBatchSelectOperation(); 112 | } 113 | } 114 | else 115 | { 116 | GEditor->SelectActor(Actor, true, true); 117 | } 118 | } 119 | } 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/Editor/GenericSystemConfigCustomization.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #if WITH_EDITOR 6 | #include "CoreMinimal.h" 7 | #include "CoreUObject.h" 8 | 9 | #include "IDetailCustomization.h" 10 | #include "IPropertyTypeCustomization.h" 11 | #include "Templates/SubclassOf.h" 12 | 13 | class UScriptStruct; 14 | class FGenericSystemConfigCustomization : public IPropertyTypeCustomization 15 | { 16 | public: 17 | static TSharedRef MakeInstance(); 18 | 19 | protected: 20 | virtual void CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) override; 21 | virtual void CustomizeChildren(TSharedRef PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils) override {} 22 | void BrowseTo(); 23 | TWeakPtr RootPropertyHandle; 24 | UClass* SystemClass = nullptr; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/Editor/SClassPickerGraphPin.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #if WITH_EDITOR 6 | #include "CoreMinimal.h" 7 | 8 | #include "Input/Reply.h" 9 | #include "KismetPins/SGraphPinObject.h" 10 | #include "SGraphPin.h" 11 | #include "UnrealCompatibility.h" 12 | #include "Widgets/DeclarativeSyntaxSupport.h" 13 | #include "Widgets/SWidget.h" 14 | 15 | class GENERICSTORAGES_API SGraphPinObjectExtra : public SGraphPinObject 16 | { 17 | public: 18 | SLATE_BEGIN_ARGS(SGraphPinObjectExtra) {} 19 | SLATE_END_ARGS() 20 | 21 | protected: 22 | virtual bool AllowSelfPinWidget() const override { return false; } 23 | static bool HasCustomMeta(UEdGraphPin* InGraphPinObj, const TCHAR* MetaName, TSet* Out = nullptr); 24 | virtual FReply OnClickUse() override; 25 | virtual bool OnCanUseAssetData(const FAssetData& AssetData); 26 | }; 27 | 28 | // CustomClassPinPicker with MetaClass [AllowedClasses DisallowedClasses AllowAbstract MustImplement NotConnectable WithinMetaKey WithoutMetaKey] 29 | class CustomClassPinPicker; 30 | class GENERICSTORAGES_API SClassPickerGraphPin : public SGraphPinObjectExtra 31 | { 32 | public: 33 | SLATE_BEGIN_ARGS(SClassPickerGraphPin) {} 34 | SLATE_ARGUMENT_DEFAULT(bool, bRequiredMatch){true}; 35 | SLATE_END_ARGS() 36 | 37 | void Construct(const FArguments& InArgs, UEdGraphPin* InGraphPinObj, FProperty* InBindProp = nullptr); 38 | 39 | static bool IsMatchedPinType(UEdGraphPin* InGraphPinObj); 40 | static bool IsMatchedToCreate(UEdGraphPin* InGraphPinObj); 41 | static UClass* GetChoosenClass(UEdGraphPin* InGraphPinObj); 42 | 43 | protected: 44 | friend struct FClassPickerGraphPinUtils; 45 | bool SetMetaInfo(UEdGraphPin* InGraphPinObj); 46 | 47 | // Called when a new class was picked via the asset picker 48 | void OnPickedNewClass(UClass* ChosenClass); 49 | 50 | //~ Begin SGraphPinObject Interface 51 | virtual FReply OnClickUse() override; 52 | virtual TSharedRef GenerateAssetPicker() override; 53 | virtual FText GetDefaultComboText() const override; 54 | virtual const FAssetData& GetAssetData(bool bRuntimePath) const override; 55 | //~ End SGraphPinObject Interface 56 | 57 | /** Cached AssetData without the _C */ 58 | mutable FAssetData CachedEditorAssetData; 59 | FProperty* BindProp = nullptr; 60 | TOptional bNotConnectable; 61 | TSharedPtr ClassFilter; 62 | bool bRequiredMatch = true; 63 | }; 64 | 65 | // CustomObjectPinPicker with [MetaClass, NotConnectable RequrieConnection] 66 | class CustomObjectPinPicker; 67 | class GENERICSTORAGES_API SObjectFilterGraphPin : public SGraphPinObjectExtra 68 | { 69 | public: 70 | SLATE_BEGIN_ARGS(SObjectFilterGraphPin) {} 71 | SLATE_END_ARGS() 72 | 73 | void Construct(const FArguments& InArgs, UEdGraphPin* InGraphPinObj); 74 | 75 | static bool IsMatchedPinType(UEdGraphPin* InGraphPinObj); 76 | static bool IsMatchedToCreate(UEdGraphPin* InGraphPinObj); 77 | 78 | protected: 79 | bool SetMetaInfo(UEdGraphPin* InGraphPinObj); 80 | TWeakObjectPtr WeakMetaClass; 81 | }; 82 | 83 | // CustomDatatableFilter with [DataTableMetaStruct DisableNoneSelection NotConnectable RequrieConnection] 84 | class CustomDataTableFilter; 85 | class GENERICSTORAGES_API SDataTableFilterGraphPin : public SGraphPinObjectExtra 86 | { 87 | public: 88 | SLATE_BEGIN_ARGS(SDataTableFilterGraphPin) {} 89 | SLATE_END_ARGS() 90 | 91 | void Construct(const FArguments& InArgs, UEdGraphPin* InGraphPinObj); 92 | 93 | static bool IsMatchedPinType(UEdGraphPin* InGraphPinObj); 94 | static bool IsMatchedToCreate(UEdGraphPin* InGraphPinObj); 95 | 96 | protected: 97 | virtual bool OnCanUseAssetData(const FAssetData& AssetData) override; 98 | 99 | bool SetMetaInfo(UEdGraphPin* InGraphPinObj); 100 | virtual TSharedRef GenerateAssetPicker() override; 101 | TSet StructNames; 102 | bool bDisableNoneSelection = false; 103 | bool bRequrieConnection = false; 104 | }; 105 | 106 | namespace CustomGraphPinPicker 107 | { 108 | void RegInterfaceClassSelectorFactory(); 109 | void RegInterfaceObjectFilterFactory(); 110 | void RegInterfaceDataTableFilterFactory(); 111 | } // namespace CustomGraphPinPicker 112 | #endif 113 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/Editor/TypeTableBinddingCustomization.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericAbilities, Inc. All Rights Reserved. 2 | #if WITH_EDITOR 3 | #include "TypeTableBinddingCustomization.h" 4 | 5 | #include "Slate.h" 6 | 7 | #include "DetailCategoryBuilder.h" 8 | #include "DetailLayoutBuilder.h" 9 | #include "Editor.h" 10 | #include "Editor/UnrealEditorUtils.h" 11 | #include "Engine/SimpleConstructionScript.h" 12 | #include "Framework/Notifications/NotificationManager.h" 13 | #include "GameFramework/Actor.h" 14 | #include "GenericSingletons.h" 15 | #include "IDetailChildrenBuilder.h" 16 | #include "IPropertyTypeCustomization.h" 17 | #include "IPropertyUtilities.h" 18 | #include "Misc/AssertionMacros.h" 19 | #include "Modules/ModuleManager.h" 20 | #include "PropertyCustomizationHelpers.h" 21 | #include "PropertyHandle.h" 22 | #include "TypeTableBindding.h" 23 | #include "UObject/UnrealType.h" 24 | 25 | TSharedRef FTypeToTableCustomization::MakeInstance() 26 | { 27 | return MakeShareable(new FTypeToTableCustomization); 28 | } 29 | 30 | void FTypeToTableCustomization::CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) 31 | { 32 | TArray OuterObjects; 33 | PropertyHandle->GetOuterObjects(OuterObjects); 34 | if (OuterObjects.Num() == 1) 35 | { 36 | auto OuterObject = OuterObjects[0]; 37 | RootPropertyHandle = PropertyHandle; 38 | auto WeakProperyHandle = RootPropertyHandle; 39 | 40 | auto OrignalPtr = UnrealEditorUtils::GetPropertyAddress(PropertyHandle, OuterObject); 41 | check(OrignalPtr); 42 | ScriptStruct = FTypeTableBindding::FindType(OrignalPtr->Type); 43 | 44 | TWeakPtr Utilities = CustomizationUtils.GetPropertyUtilities(); 45 | FWeakObjectPtr WeakObject = OuterObject; 46 | 47 | TWeakPtr WeakSelf = StaticCastSharedRef(AsShared()); 48 | auto Cb = FSimpleDelegate::CreateLambda([Utilities, WeakProperyHandle, WeakObject, WeakSelf] { 49 | auto Prop = WeakProperyHandle.Pin(); 50 | auto This = WeakSelf.Pin(); 51 | if (!Prop || !WeakObject.IsValid() || !This.IsValid()) 52 | return; 53 | 54 | auto OrignalPtr = UnrealEditorUtils::GetPropertyAddress(Prop, WeakObject.Get()); 55 | auto FoundScriptStruct = FTypeTableBindding::FindType(OrignalPtr->Type); 56 | if (FoundScriptStruct && OrignalPtr->Table && (!FoundScriptStruct->IsChildOf(OrignalPtr->Table->RowStruct))) 57 | { 58 | if (auto TablePropertyHandle = Prop->GetChildHandle("Table", false)) 59 | { 60 | TablePropertyHandle->SetValue((UObject*)nullptr, EPropertyValueSetFlags::NotTransactable); 61 | UnrealEditorUtils::ShowNotification(TEXT("Table Type MisMatch")); 62 | } 63 | } 64 | This->StructTypePicker.ScriptStruct = FoundScriptStruct; 65 | 66 | if (auto Util = Utilities.Pin()) 67 | Util->RequestRefresh(); 68 | }); 69 | 70 | Cb.Execute(); 71 | auto TypePropertyHandle = PropertyHandle->GetChildHandle("Type", false); 72 | TypePropertyHandle->SetOnPropertyValueChanged(Cb); 73 | 74 | auto TablePropertyHandle = PropertyHandle->GetChildHandle("Table", false); 75 | 76 | InitValue = MakeShared(NAME_None); 77 | { 78 | Names.Reset(); 79 | Names.Add(InitValue); 80 | TArray Classes; 81 | FTypeTableBindding::Get().Binddings.GetKeys(Classes); 82 | for (auto& a : Classes) 83 | { 84 | if (auto Class = DynamicClass(a)) 85 | { 86 | Names.Add(MakeShareable(new FName(*a))); 87 | if (OrignalPtr->Type && OrignalPtr->Type->GetName() == a) 88 | InitValue = Names.Last(); 89 | } 90 | } 91 | } 92 | 93 | HeaderRow 94 | .NameContent() 95 | [ 96 | SNew(SHorizontalBox) 97 | + SHorizontalBox::Slot() 98 | .FillWidth(120) 99 | [ 100 | SNew(SComboBox>) 101 | .OptionsSource(&Names) 102 | .InitiallySelectedItem(InitValue) 103 | .OnGenerateWidget_Lambda([](TSharedPtr InName) { 104 | return SNew(STextBlock) 105 | .Text(FText::FromName(*InName)); 106 | }) 107 | .OnSelectionChanged_Lambda([this, Utilities](TSharedPtr InName, ESelectInfo::Type SelectInfo) { 108 | if (SelectInfo == ESelectInfo::OnNavigation) 109 | { 110 | return; 111 | } 112 | auto Class = DynamicClass(InName->ToString()); 113 | if (!Class) 114 | return; 115 | 116 | if (auto ThisProperty = RootPropertyHandle.Pin()) 117 | { 118 | auto CurType = UnrealEditorUtils::GetPropertyMemberPtr(ThisProperty, TEXT("Type")); 119 | if (CurType) 120 | { 121 | auto& CurClass = *CurType; 122 | if (!CurClass || *InName != CurClass->GetFName()) 123 | { 124 | GEditor->BeginTransaction(TEXT("PropertyEditor"), NSLOCTEXT("ExecutionConfig", "EditPropertyTransaction", "Edit ExecutionConfig"), GetPropertyOwnerUObject(ThisProperty->GetProperty())); 125 | InitValue = InName; 126 | CurClass = Class; 127 | ThisProperty->NotifyPreChange(); 128 | ThisProperty->NotifyPostChange(EPropertyChangeType::ValueSet); 129 | ThisProperty->NotifyFinishedChangingProperties(); 130 | GEditor->EndTransaction(); 131 | } 132 | } 133 | StructTypePicker.ScriptStruct = FTypeTableBindding::FindType(Class); 134 | 135 | if (auto Util = Utilities.Pin()) 136 | Util->RequestRefresh(); 137 | } 138 | }) 139 | .Content() 140 | [ 141 | SNew(STextBlock) 142 | .Text_Lambda([this] { return FText::FromName(*InitValue); }) 143 | ] 144 | ] 145 | + SHorizontalBox::Slot() 146 | .AutoWidth() 147 | [ 148 | PropertyCustomizationHelpers::MakeBrowseButton(FSimpleDelegate::CreateLambda([InitVal{this->InitValue}] { 149 | if (InitVal && !InitVal->IsNone()) 150 | { 151 | auto Class = DynamicClass(InitVal->ToString()); 152 | if (GEditor && Class) 153 | { 154 | TArray Objects; 155 | Objects.Add(Class); 156 | GEditor->SyncBrowserToObjects(Objects); 157 | } 158 | } 159 | })) 160 | ] 161 | ] 162 | .ValueContent() 163 | .MinDesiredWidth(250.f) 164 | .MaxDesiredWidth(0.f) 165 | [ 166 | SNew(SHorizontalBox) 167 | + SHorizontalBox::Slot() 168 | .FillWidth(120) 169 | [ 170 | StructTypePicker.MakeDynamicPropertyWidget(TablePropertyHandle, false) 171 | ] 172 | ]; 173 | } 174 | } 175 | #endif 176 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/Editor/TypeTableBinddingCustomization.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericAbilities, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | #if WITH_EDITOR 5 | #include "CoreMinimal.h" 6 | 7 | #include "Editor/UnrealEditorUtils.h" 8 | #include "Kismet2/BlueprintEditorUtils.h" 9 | #include "IPropertyTypeCustomization.h" 10 | #include "Templates/SubclassOf.h" 11 | #include "UObject/Class.h" 12 | 13 | class FTypeToTableCustomization : public IPropertyTypeCustomization 14 | { 15 | public: 16 | static TSharedRef MakeInstance(); 17 | 18 | protected: 19 | virtual void CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) override; 20 | virtual void CustomizeChildren(TSharedRef PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils) override {} 21 | TWeakObjectPtr ScriptStruct; 22 | TWeakPtr RootPropertyHandle; 23 | TArray> Names; 24 | TSharedPtr InitValue; 25 | UnrealEditorUtils::FDatatableTypePicker StructTypePicker; 26 | }; 27 | #endif -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/GenericStoragesModule.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | #include "GenericStoragesModule.h" 3 | 4 | #if WITH_EDITOR 5 | #include "Editor/ComponentPickerCustomization.h" 6 | #include "Editor/DataTablePickerCustomization.h" 7 | #include "Editor/GenericSystemConfigCustomization.h" 8 | #include "Editor/SClassPickerGraphPin.h" 9 | #include "PropertyEditorDelegates.h" 10 | #include "PropertyEditorModule.h" 11 | 12 | #if UE_4_25_OR_LATER 13 | #include "Slate.h" 14 | 15 | #include "LevelEditor.h" 16 | #include "Settings/LevelEditorPlaySettings.h" 17 | #endif 18 | #endif 19 | 20 | #include "Engine/Engine.h" 21 | #include "Engine/World.h" 22 | #include "GenericSingletons.h" 23 | #include "GenericStoragesLog.h" 24 | #include "Misc/CoreDelegates.h" 25 | #include "Misc/DelayedAutoRegister.h" 26 | #include "Modules/ModuleInterface.h" 27 | #include "Modules/ModuleManager.h" 28 | #include "TimerManager.h" 29 | #include "WorldLocalStorages.h" 30 | 31 | #define LOCTEXT_NAMESPACE "GenericStoragesPlugin" 32 | 33 | DEFINE_LOG_CATEGORY(LogGenericStorages) 34 | 35 | namespace GenericStorages 36 | { 37 | static bool bModuleReady = false; 38 | static FSimpleMulticastDelegate OnModuleStarted; 39 | bool CallOnPluginReady(FSimpleDelegate Delegate) 40 | { 41 | if (bModuleReady) 42 | { 43 | Delegate.Execute(); 44 | return true; 45 | } 46 | else 47 | { 48 | OnModuleStarted.Add(MoveTemp(Delegate)); 49 | return false; 50 | } 51 | } 52 | 53 | static bool bIsEngineLoopInitCompleted = false; 54 | static FSimpleMulticastDelegate OnFEngineLoopInitCompleted; 55 | void CallOnEngineInitCompletedImpl(FSimpleDelegate& Lambda) 56 | { 57 | if (bIsEngineLoopInitCompleted) 58 | { 59 | Lambda.Execute(); 60 | } 61 | else 62 | { 63 | check(IsInGameThread()); 64 | OnFEngineLoopInitCompleted.Add(MoveTemp(Lambda)); 65 | } 66 | } 67 | static FDelayedAutoRegisterHelper DelayOnEngineInitCompleted(EDelayedRegisterRunPhase::EndOfEngineInit, [] { 68 | bIsEngineLoopInitCompleted = true; 69 | OnFEngineLoopInitCompleted.Broadcast(); 70 | OnFEngineLoopInitCompleted.Clear(); 71 | }); 72 | 73 | bool DelayExec(const UObject* InObj, FTimerDelegate Delegate, float InDelay, bool bEnsureExec) 74 | { 75 | InDelay = FMath::Max(InDelay, 0.00001f); 76 | auto World = GEngine->GetWorldFromContextObject(InObj, InObj ? EGetWorldErrorMode::LogAndReturnNull : EGetWorldErrorMode::ReturnNull); 77 | #if WITH_EDITOR 78 | if (bEnsureExec && (!World || !World->IsGameWorld())) 79 | { 80 | if (GEditor && GEditor->IsTimerManagerValid()) 81 | { 82 | FTimerHandle TimerHandle; 83 | GEditor->GetTimerManager()->SetTimer(TimerHandle, MoveTemp(Delegate), InDelay, false); 84 | } 85 | else 86 | { 87 | auto Holder = World ? NewObject(World) : NewObject(); 88 | Holder->SetFlags(RF_Standalone); 89 | if (World) 90 | World->PerModuleDataObjects.Add(Holder); 91 | else 92 | Holder->AddToRoot(); 93 | 94 | GEditor->OnPostEditorTick().AddWeakLambda(Holder, [Holder, WeakWorld{MakeWeakObjectPtr(World)}, Delegate(MoveTemp(Delegate)), InDelay](float Delta) mutable { 95 | InDelay -= Delta; 96 | if (InDelay <= 0.f) 97 | { 98 | if (auto OwnerWorld = WeakWorld.Get()) 99 | OwnerWorld->PerModuleDataObjects.Remove(Holder); 100 | Holder->RemoveFromRoot(); 101 | 102 | Delegate.ExecuteIfBound(); 103 | Holder->ClearFlags(RF_Standalone); 104 | Holder->MarkAsGarbage(); 105 | } 106 | }); 107 | } 108 | return true; 109 | } 110 | else 111 | #endif 112 | { 113 | World = World ? World : GWorld; 114 | ensure(!bEnsureExec || World); 115 | if (World) 116 | { 117 | FTimerHandle TimerHandle; 118 | World->GetTimerManager().SetTimer(TimerHandle, MoveTemp(Delegate), InDelay, false); 119 | return true; 120 | } 121 | } 122 | return false; 123 | } 124 | 125 | TWeakObjectPtr WeakPieObj; 126 | #if WITH_EDITOR 127 | void InitWeakPieObj() 128 | { 129 | if (IsInGameThread() && TrueOnFirstCall([] {})) 130 | { 131 | FEditorDelegates::PreBeginPIE.AddLambda([](bool) { 132 | auto Obj = NewObject(); 133 | Obj->AddToRoot(); 134 | GenericStorages::WeakPieObj = Obj; 135 | }); 136 | FEditorDelegates::EndPIE.AddLambda([](bool) { 137 | auto Obj = GenericStorages::WeakPieObj.Get(); 138 | Obj->RemoveFromRoot(); 139 | GenericStorages::WeakPieObj = nullptr; 140 | }); 141 | } 142 | } 143 | #endif 144 | } // namespace GenericStorages 145 | 146 | UObject* UGenericLocalStore::GetPieObject(const UWorld* InCtx) 147 | { 148 | checkSlow(InCtx); 149 | #if WITH_EDITOR 150 | if (GIsEditor) 151 | { 152 | return GenericStorages::WeakPieObj.Get(); 153 | } 154 | else 155 | #endif 156 | { 157 | return InCtx->GetGameInstance(); 158 | } 159 | } 160 | 161 | class FGenericStoragesPlugin final : public IModuleInterface 162 | { 163 | public: 164 | // IModuleInterface implementation 165 | virtual void StartupModule() override 166 | { 167 | GenericStorages::bModuleReady = true; 168 | GenericStorages::OnModuleStarted.Broadcast(); 169 | GenericStorages::OnModuleStarted.Clear(); 170 | 171 | #if WITH_EDITOR 172 | GenericStorages::InitWeakPieObj(); 173 | CustomGraphPinPicker::RegInterfaceClassSelectorFactory(); 174 | CustomGraphPinPicker::RegInterfaceObjectFilterFactory(); 175 | CustomGraphPinPicker::RegInterfaceDataTableFilterFactory(); 176 | 177 | auto PropertyModule = FModuleManager::GetModulePtr("PropertyEditor"); 178 | if (PropertyModule) 179 | { 180 | PropertyModule->RegisterCustomPropertyTypeLayout("DataTablePicker", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FDataTablePickerCustomization::MakeInstance)); 181 | PropertyModule->RegisterCustomPropertyTypeLayout("DataTablePathPicker", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FDataTablePathPickerCustomization::MakeInstance)); 182 | PropertyModule->RegisterCustomPropertyTypeLayout("DataTableRowNamePicker", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FDataTableRowNamePickerCustomization::MakeInstance)); 183 | PropertyModule->RegisterCustomPropertyTypeLayout("DataTableRowPicker", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FDataTableRowPickerCustomization::MakeInstance)); 184 | PropertyModule->RegisterCustomPropertyTypeLayout("ComponentPicker", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FComponentPickerCustomization::MakeInstance)); 185 | PropertyModule->RegisterCustomPropertyTypeLayout("GenericSystemConfig", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGenericSystemConfigCustomization::MakeInstance)); 186 | PropertyModule->NotifyCustomizationModuleChanged(); 187 | } 188 | 189 | #if UE_4_25_OR_LATER 190 | FLevelEditorModule* LevelEditorModule = (GIsEditor && !IsRunningCommandlet()) ? FModuleManager::GetModulePtr(TEXT("LevelEditor")) : nullptr; 191 | if (LevelEditorModule) 192 | { 193 | // a handy place to quick set RunUnderOneProcess 194 | LevelEditorModule->GetAllLevelEditorToolbarPlayMenuExtenders().Add(FLevelEditorModule::FLevelEditorMenuExtender::CreateLambda([](const TSharedRef List) { 195 | auto Extender = MakeShared(); 196 | Extender->AddMenuExtension(TEXT("LevelEditorPlayInWindowNetwork"), EExtensionHook::After, nullptr, FMenuExtensionDelegate::CreateLambda([](FMenuBuilder& MenuBuilder) { 197 | ULevelEditorPlaySettings* PlayInSettings = GetMutableDefault(); 198 | auto CheckBox = SNew(SCheckBox) 199 | .IsChecked_Lambda([PlayInSettings] { 200 | bool bRunUnderOneProcess = false; 201 | PlayInSettings->GetRunUnderOneProcess(bRunUnderOneProcess); 202 | return bRunUnderOneProcess ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; 203 | }) 204 | .OnCheckStateChanged_Lambda([PlayInSettings](ECheckBoxState State) { 205 | PlayInSettings->SetRunUnderOneProcess(State == ECheckBoxState::Checked); 206 | PlayInSettings->PostEditChange(); 207 | PlayInSettings->SaveConfig(); 208 | }) 209 | .ToolTipText(LOCTEXT("RunUnderOneProcessTip", "a handy place to quick set RunUnderOneProcess")) 210 | .IsFocusable(false); 211 | 212 | MenuBuilder.AddWidget(CheckBox, LOCTEXT("RunUnderOneProcess", "RunUnderOneProcess")); 213 | })); 214 | return Extender; 215 | })); 216 | } 217 | #endif 218 | 219 | #if PLATFORM_DESKTOP 220 | // auto quit ds process 221 | static const auto Key = TEXT("WatchParentProcess"); 222 | if (!IsRunningCommandlet() && (FParse::Param(FCommandLine::Get(), TEXT("server")) || FParse::Param(FCommandLine::Get(), Key))) 223 | { 224 | auto CurProcId = FPlatformProcess::GetCurrentProcessId(); 225 | FPlatformProcess::FProcEnumerator CurProcIt; 226 | while (CurProcIt.MoveNext()) 227 | { 228 | auto CurProc = CurProcIt.GetCurrent(); 229 | if (CurProc.GetPID() == CurProcId) 230 | { 231 | #if UE_5_00_OR_LATER 232 | if (!CurProc.GetName().StartsWith(TEXT("UnrealEditor-"))) 233 | break; 234 | #else 235 | if (!CurProc.GetName().StartsWith(TEXT("UE4Editor-"))) 236 | break; 237 | #endif 238 | auto ParentProcHandle = FPlatformProcess::OpenProcess(CurProc.GetParentPID()); 239 | struct FMyRunnable : public FRunnable 240 | { 241 | virtual uint32 Run() override 242 | { 243 | while (FPlatformProcess::IsProcRunning(ParentProcHandle) && !IsEngineExitRequested()) 244 | FPlatformProcess::Sleep(1.f); 245 | 246 | RequestEngineExit(Key); 247 | return 0; 248 | } 249 | FMyRunnable(FProcHandle InHandle) 250 | : ParentProcHandle(InHandle) 251 | { 252 | } 253 | ~FMyRunnable() 254 | { 255 | FPlatformProcess::CloseProc(ParentProcHandle); 256 | delete this; 257 | } 258 | FProcHandle ParentProcHandle; 259 | }; 260 | 261 | if (FPlatformProcess::IsProcRunning(ParentProcHandle)) 262 | FRunnableThread::Create(new FMyRunnable(ParentProcHandle), Key); 263 | break; 264 | } 265 | } 266 | } 267 | #endif 268 | 269 | #endif 270 | } 271 | 272 | virtual void ShutdownModule() override {} 273 | // End of IModuleInterface implementation 274 | }; 275 | 276 | #if WITH_LOCALSTORAGE_MULTIMODULE_SUPPORT 277 | namespace WorldLocalStorages 278 | { 279 | namespace Internal 280 | { 281 | struct FStoredPair 282 | { 283 | TWeakObjectPtr WeakCtx; 284 | TMap> Value; 285 | }; 286 | static TArray> Storages; 287 | 288 | void BindWorldLifetime() 289 | { 290 | if (TrueOnFirstCall([] {})) 291 | { 292 | #if WITH_EDITOR 293 | FWorldDelegates::OnWorldCleanup.AddStatic([](UWorld* InWorld, bool, bool) { Storages.RemoveAllSwap([&](auto& Cell) { return Cell.WeakCtx == InWorld; }); }); 294 | FEditorDelegates::EndPIE.AddStatic([](const bool) { Storages.Reset(); }); 295 | #else 296 | FWorldDelegates::OnWorldCleanup.AddStatic([](UWorld* InWorld, bool, bool) { Storages.RemoveAllSwap([&](auto& Cell) { return Cell.WeakCtx == InWorld; }); }); 297 | #endif 298 | } 299 | } 300 | } // namespace Internal 301 | 302 | struct FStorageUtils 303 | { 304 | template 305 | static void* GetStorage(const U* ContextObj, const char* TypeName, const TFunctionRef& InCtor, void (*InDtor)(void*)) 306 | { 307 | Internal::BindWorldLifetime(); 308 | check(!ContextObj || IsValid(ContextObj)); 309 | auto& ValRef = FLocalStorageOps::FindOrAdd(Internal::Storages, ContextObj, [&]() -> TMap>& { 310 | auto& Pair = Add_GetRef(Internal::Storages); 311 | Pair.WeakCtx = ContextObj; 312 | return Pair.Value; 313 | }); 314 | auto& Ref = ValRef.FindOrAdd(TypeName); 315 | if (!Ref) 316 | Ref = MakeShareable(InCtor(), [InDtor](void* p) { InDtor(p); }); 317 | return Ref.Get(); 318 | } 319 | }; 320 | 321 | void* FLocalStorageOps::GetStorageImpl(const UWorld* ContextObj, const char* TypeName, TFunctionRef InCtor, void (*InDtor)(void*)) 322 | { 323 | return FStorageUtils::GetStorage(ContextObj, TypeName, InCtor, InDtor); 324 | } 325 | void* FLocalStorageOps::GetStorageImpl(const UGameInstance* ContextObj, const char* TypeName, TFunctionRef InCtor, void (*InDtor)(void*)) 326 | { 327 | return FStorageUtils::GetStorage(ContextObj, TypeName, InCtor, InDtor); 328 | } 329 | void* FLocalStorageOps::GetStorageImpl(const UObject* ContextObj, const char* TypeName, TFunctionRef InCtor, void (*InDtor)(void*)) 330 | { 331 | return FStorageUtils::GetStorage(ContextObj, TypeName, InCtor, InDtor); 332 | } 333 | 334 | } // namespace WorldLocalStorages 335 | #endif 336 | 337 | #undef LOCTEXT_NAMESPACE 338 | 339 | IMPLEMENT_MODULE(FGenericStoragesPlugin, GenericStorages) 340 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/GenericStoragesModule.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "GenericStoragesModule.generated.h" 8 | 9 | UCLASS() 10 | class UGenericPlaceHolder : public UObject 11 | { 12 | GENERATED_BODY() 13 | public: 14 | }; 15 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/MIO.cpp: -------------------------------------------------------------------------------- 1 | #include "MIO.h" 2 | 3 | #include "Containers/UnrealString.h" 4 | 5 | #if PLATFORM_ANDROID 6 | #include "Android/AndroidPlatformMisc.h" 7 | #endif 8 | 9 | #include "GenericStoragesLog.h" 10 | #include "HAL/FileManager.h" 11 | #include "mio/mmap.hpp" 12 | #include "WorldLocalStorages.h" 13 | #include "UnrealCompatibility.h" 14 | 15 | #if PLATFORM_ANDROID 16 | extern FString AndroidRelativeToAbsolutePath(bool bUseInternalBasePath, FString RelPath); 17 | #endif 18 | 19 | namespace GenericStorages 20 | { 21 | UGameInstance* FindGameInstance(UObject* InObj); 22 | } 23 | namespace MIO 24 | { 25 | template::value, mio::ummap_source, mio::ummap_sink>> 26 | class FMappedFileRegionImpl final 27 | : public IMappedFileRegion 28 | , private MapType 29 | { 30 | static_assert(sizeof(ByteT) == sizeof(char), "err"); 31 | FString FileInfo; 32 | 33 | public: 34 | virtual FString& GetInfo() override { return FileInfo; } 35 | virtual ByteT* GetMappedPtr() override { return MapType::data(); } 36 | virtual int64 GetMappedSize() override { return MapType::mapped_length(); } 37 | 38 | ~FMappedFileRegionImpl() = default; 39 | FMappedFileRegionImpl(const TCHAR* Filename, int64 Offset = 0, int64 BytesToMap = MAX_int64, bool bPreloadHint = false) 40 | { 41 | std::error_code ErrCode; 42 | FileInfo = Filename; 43 | MapType::map(Filename, Offset, BytesToMap, ErrCode); 44 | 45 | if (ErrCode) 46 | { 47 | UE_LOG(LogGenericStorages, Error, TEXT("OpenMapped Error : [%s] %d(%s)"), Filename, ErrCode.value(), ANSI_TO_TCHAR(ErrCode.message().c_str())); 48 | } 49 | } 50 | }; 51 | 52 | TUniquePtr> OpenMappedRead(const TCHAR* Filename, int64 Offset /*= 0*/, int64 BytesToMap /*= 0*/, bool bPreloadHint /*= false*/) 53 | { 54 | return MakeUnique>(Filename, Offset, BytesToMap, bPreloadHint); 55 | } 56 | 57 | TUniquePtr> OpenMappedWrite(const TCHAR* Filename, int64 Offset /*= 0*/, int64 BytesToMap /*= MAX_int64*/, bool bPreloadHint /*= false*/) 58 | { 59 | return MakeUnique>(Filename, Offset, BytesToMap, bPreloadHint); 60 | } 61 | 62 | int32 ReadLines(const TCHAR* Filename, const TFunctionRef&)>& Lambda, char Dim /*= '\n'*/) 63 | { 64 | FMappedFileRegionImpl MapFile{Filename}; 65 | auto Lines = 0; 66 | if (!MapFile.GetMappedPtr()) 67 | return 0; 68 | 69 | TArray Buffer; 70 | Buffer.Reserve(2048); 71 | auto Ptr = MapFile.GetMappedPtr(); 72 | auto Size = MapFile.GetMappedSize(); 73 | int64 i = 0u; 74 | while (i < Size) 75 | { 76 | auto Ch = Ptr[i]; 77 | if (Ch == Dim) 78 | { 79 | if (Buffer.Num() > 0) 80 | { 81 | ++Lines; 82 | Lambda(Buffer); 83 | Buffer.Reset(); 84 | } 85 | continue; 86 | } 87 | Buffer.Add(Ptr[i]); 88 | } 89 | 90 | if (Buffer.Num() > 0) 91 | { 92 | ++Lines; 93 | Lambda(Buffer); 94 | } 95 | return Lines; 96 | } 97 | 98 | int32 WriteLines(const TCHAR* Filename, const TArray>& Lines, char Dim /*= '\n'*/) 99 | { 100 | int32 LineCount = 0; 101 | TUniquePtr Writer(IFileManager::Get().CreateFileWriter(Filename)); 102 | if (Writer) 103 | { 104 | for (int64 i = 0; i < Lines.Num(); ++i) 105 | { 106 | auto& Buffer = Lines[i]; 107 | if (Buffer.Num() > 0) 108 | { 109 | ++LineCount; 110 | Writer->Serialize((void*)Buffer.GetData(), Buffer.Num()); 111 | Writer->Serialize(&Dim, 1); 112 | } 113 | } 114 | } 115 | return LineCount; 116 | } 117 | 118 | bool ChunkingFile(const TCHAR* Filename, TArray64& Buffer, const TFunctionRef&)>& Lambda) 119 | { 120 | check(Filename); 121 | if (!Buffer.Num()) 122 | Buffer.SetNumUninitialized(2048); 123 | 124 | TUniquePtr Reader(IFileManager::Get().CreateFileReader(Filename)); 125 | if (ensure(Reader)) 126 | { 127 | int64 LeftSize = Reader->TotalSize(); 128 | while (LeftSize > 0) 129 | { 130 | auto ActualSize = LeftSize > Buffer.Num() ? Buffer.Num() : LeftSize; 131 | Buffer.SetNumUninitialized(ActualSize, false); 132 | Reader->Serialize(Buffer.GetData(), ActualSize); 133 | Lambda(Buffer); 134 | LeftSize -= ActualSize; 135 | } 136 | return true; 137 | } 138 | return false; 139 | } 140 | 141 | void* OpenLockHandle(const TCHAR* Path, FString& ErrorCategory) 142 | { 143 | ensure(FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FPaths::GetPath(Path))); 144 | return mio::OpenLockHandle(Path, ErrorCategory); 145 | } 146 | void CloseLockHandle(void* InHandle) 147 | { 148 | if (InHandle) 149 | mio::CloseLockHandle(InHandle); 150 | } 151 | 152 | struct FProcessLockIndexImpl : public FProcessLockIndex 153 | { 154 | void* Handle = nullptr; 155 | FProcessLockIndexImpl(void* InHandle, int32 Idx, int32 PIEInstance = 0) 156 | : Handle(InHandle) 157 | { 158 | PIEIndex = PIEInstance; 159 | Index = Idx; 160 | } 161 | ~FProcessLockIndexImpl() 162 | { 163 | if (Handle) 164 | CloseLockHandle(Handle); 165 | } 166 | }; 167 | 168 | template 169 | bool GetGlobalSystemIndexHandleImpl(void*& OutHandle, int32& OutIndex, const TCHAR* Key, int32 MaxTries = 1024) 170 | { 171 | int64 StartIndex = 0; 172 | if constexpr (bFromCmd) 173 | { 174 | if (FCommandLine::IsInitialized()) 175 | { 176 | FParse::Value(FCommandLine::Get(), TEXT("-GlobalSystemIndex="), StartIndex); 177 | StartIndex = FMath::Max(int64(0), StartIndex); 178 | } 179 | } 180 | 181 | auto LockDir = FPaths::ConvertRelativePathToFull(FPaths::Combine(FPaths::ProjectSavedDir(), FString::Printf(TEXT(".indexlock")))); 182 | for (int32 Index = StartIndex; Index < MaxTries; ++Index) 183 | { 184 | FString ErrorMsg; 185 | FString TestFileName = FString::Printf(TEXT("%s%s"), Key ? Key : TEXT("_GlobalIndex_"), *LexToString(Index)); 186 | if (auto Handle = MIO::OpenLockHandle(*FPaths::Combine(LockDir, FString::Printf(TEXT("%s.lock"), *TestFileName)), ErrorMsg)) 187 | { 188 | OutIndex = Index; 189 | OutHandle = Handle; 190 | return true; 191 | } 192 | } 193 | ensureMsgf(false, TEXT("Failed for GetGlobalSystemIndexHandle(%s, %s)"), Key ? Key : TEXT("_GlobalIndex_"), *LexToString(MaxTries)); 194 | return false; 195 | } 196 | 197 | int32 GetProcessUniqueIndex() 198 | { 199 | static TSharedPtr ProcessUniqueLock; 200 | if (ProcessUniqueLock) 201 | return ProcessUniqueLock->Index; 202 | 203 | void* Handle = nullptr; 204 | int32 Index = 0; 205 | if (GetGlobalSystemIndexHandleImpl(Handle, Index, TEXT("_ProcessUniqueIndex_"))) 206 | { 207 | ProcessUniqueLock = MakeShared(Handle, Index); 208 | } 209 | return Index; 210 | } 211 | 212 | TSharedPtr GetGlobalSystemIndexHandle(const TCHAR* Key, int32 MaxTries) 213 | { 214 | void* Handle = nullptr; 215 | int32 Index = 0; 216 | if (GetGlobalSystemIndexHandleImpl(Handle, Index, Key, MaxTries)) 217 | { 218 | return MakeShared(Handle, Index); 219 | } 220 | return nullptr; 221 | } 222 | FProcessLockIndex* GetGameInstanceIndexHandle(const UObject* InCtx, const TCHAR* Key, int32 MaxTries /*= 1024*/) 223 | { 224 | static WorldLocalStorages::TGenericGameLocalStorage Containers; 225 | UGameInstance* Ins = GenericStorages::FindGameInstance((UObject*)InCtx); 226 | void* Handle = nullptr; 227 | int32 Index = 0; 228 | if (Key) 229 | { 230 | GetGlobalSystemIndexHandleImpl(Handle, Index, Key, MaxTries); 231 | } 232 | else 233 | { 234 | Index = GetProcessUniqueIndex(); 235 | } 236 | auto Lambda = [&] { return new FProcessLockIndexImpl(Handle, Index, Ins ? Ins->GetWorldContext()->PIEInstance : UE::GetPlayInEditorID()); }; 237 | return &Containers.GetLocalValue(Ins, Lambda); 238 | } 239 | 240 | FString ConvertToAbsolutePath(FString InPath) 241 | { 242 | #if PLATFORM_IOS 243 | InPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(*InPath); 244 | #elif PLATFORM_ANDROID 245 | InPath = AndroidRelativeToAbsolutePath(false, InPath); 246 | #elif PLATFORM_WINDOWS 247 | #else 248 | #endif 249 | InPath = FPaths::ConvertRelativePathToFull(InPath); 250 | return InPath; 251 | } 252 | 253 | const FString& FullProjectSavedDir() 254 | { 255 | static FString FullSavedDirPath = [] { 256 | #if UE_BUILD_SHIPPING 257 | FString ProjSavedDir = FPaths::ProjectDir() / TEXT("Saved/"); 258 | #else 259 | FString ProjSavedDir = FPaths::ProjectSavedDir(); 260 | #endif 261 | return ConvertToAbsolutePath(ProjSavedDir); 262 | }(); 263 | return FullSavedDirPath; 264 | } 265 | 266 | FMappedBuffer::FMappedBuffer(FGuid InId, uint32 InCapacity, const TCHAR* SubDir) 267 | : ReadIdx(0) 268 | , WriteIdx(0) 269 | { 270 | auto RegionSize = FMath::RoundUpToPowerOfTwo(FMath::Max(PLATFORM_IOS ? 4096u * 4 : 4096u, InCapacity)); 271 | FString SaveDir = FPaths::Combine(FullProjectSavedDir(), SubDir ? SubDir : TEXT("Mapped")); 272 | FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*SaveDir); 273 | Region = MIO::OpenMappedWrite(*FPaths::Combine(SaveDir, InId.IsValid() ? InId.ToString() : FGuid::NewGuid().ToString()), 0, RegionSize); 274 | } 275 | 276 | bool FMappedBuffer::IsValid() const 277 | { 278 | return Region.IsValid(); 279 | } 280 | 281 | bool FMappedBuffer::WillWrap(uint32 InSize) const 282 | { 283 | return ensure(InSize < GetRegionSize()) && (WriteIdx + InSize >= GetRegionSize()); 284 | } 285 | 286 | bool FMappedBuffer::WillFull(uint32 InSize, bool bContinuous) const 287 | { 288 | return (!ensure(InSize < GetRegionSize())) || (Num() + InSize < GetRegionSize()) || (bContinuous && InSize >= ReadIdx); 289 | } 290 | 291 | uint8* FMappedBuffer::Write(const void* InVal, uint32 InSize, bool bContinuous) 292 | { 293 | auto RegionSize = GetRegionSize(); 294 | if (!ensure(RegionSize > 0)) 295 | return nullptr; 296 | 297 | bool bTestFull = WillFull(InSize, bContinuous); 298 | auto AddrToWrite = &GetBuffer(WriteIdx); 299 | if (!WillWrap(InSize)) 300 | { 301 | if (InVal) 302 | { 303 | FMemory::Memcpy(AddrToWrite, InVal, InSize); 304 | } 305 | WriteIdx += InSize; 306 | } 307 | else if (bContinuous) 308 | { 309 | AddrToWrite = &GetBuffer(0); 310 | WriteIdx = InSize % FMath::Max(RegionSize, 1u) + 1; 311 | if (InVal) 312 | { 313 | FMemory::Memcpy(AddrToWrite, InVal, WriteIdx - 1); 314 | } 315 | } 316 | else 317 | { 318 | auto FirstPart = RegionSize - WriteIdx; 319 | auto LeftSize = InSize - FirstPart; 320 | if (InVal) 321 | { 322 | FMemory::Memcpy(AddrToWrite, InVal, FirstPart); 323 | FMemory::Memcpy(&GetBuffer(0), (uint8*)InVal + FirstPart, LeftSize); 324 | } 325 | WriteIdx = LeftSize; 326 | } 327 | 328 | if (bTestFull) 329 | ReadIdx = (WriteIdx + 1) % FMath::Max(RegionSize, 1u); 330 | return AddrToWrite; 331 | } 332 | 333 | uint32 FMappedBuffer::ReadUntil(uint8 TestChar, TFunctionRef Op) 334 | { 335 | if (!IsWrap()) 336 | { 337 | for (auto i = ReadIdx; i < WriteIdx; ++i) 338 | { 339 | auto Char = GetBuffer(i); 340 | if (Char == TestChar) 341 | return i - ReadIdx; 342 | Op(Char); 343 | } 344 | } 345 | else 346 | { 347 | for (auto i = ReadIdx; i < GetRegionSize(); ++i) 348 | { 349 | auto Char = GetBuffer(i); 350 | if (GetBuffer(i) == TestChar) 351 | return i - ReadIdx; 352 | Op(Char); 353 | } 354 | for (auto i = 0u; i < WriteIdx; ++i) 355 | { 356 | auto Char = GetBuffer(i); 357 | if (GetBuffer(i) == TestChar) 358 | return i + (GetRegionSize() - ReadIdx); 359 | Op(Char); 360 | } 361 | } 362 | return 0u; 363 | } 364 | 365 | uint32 FMappedBuffer::ReadUntil(uint8 TestChar) 366 | { 367 | return ReadUntil(TestChar, [](auto) {}); 368 | } 369 | 370 | uint32 FMappedBuffer::WriteImpl(uint32 InLen, const void* InBuf) 371 | { 372 | const bool bIsEmplty = IsEmpty(); 373 | if (bIsEmplty) 374 | { 375 | *reinterpret_cast(GetPtr() + WriteIdx) = InLen; 376 | WriteIdx += sizeof(InLen); 377 | FMemory::Memcpy(&GetBuffer(WriteIdx), InBuf, InLen); 378 | WriteIdx += InLen; 379 | } 380 | return 0u; 381 | } 382 | 383 | uint8& FMappedBuffer::GetBuffer(int32 Idx) const 384 | { 385 | return *(GetPtr() + Idx); 386 | } 387 | 388 | uint32 FMappedBuffer::GetRegionSize() const 389 | { 390 | return Region ? Region->GetMappedSize() : 0u; 391 | } 392 | 393 | uint8* FMappedBuffer::GetPtr() const 394 | { 395 | check(IsValid()); 396 | return Region->GetMappedPtr(); 397 | } 398 | 399 | } // namespace MIO 400 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/MemberDataRegistry.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #include "MemberDataRegistry.h" 4 | #if WITH_EDITOR 5 | #include "Engine/Engine.h" 6 | #include "Engine/GameEngine.h" 7 | #include "Engine/World.h" 8 | #include "GenericSingletons.h" 9 | #include "UObject/UObjectThreadContext.h" 10 | #endif 11 | 12 | FWeakMemberDataTag::FWeakMemberDataTag() 13 | { 14 | #if WITH_EDITOR 15 | FUObjectThreadContext& ThreadContext = FUObjectThreadContext::Get(); 16 | UObject* Initializer = ThreadContext.IsInConstructor ? ThreadContext.TopInitializer()->GetObj() : nullptr; 17 | if (!Outer.IsValid()) 18 | Outer = Initializer; 19 | #endif 20 | } 21 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/ObjectDataRegistry.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #include "ObjectDataRegistry.h" 4 | 5 | #include "GameFramework/Actor.h" 6 | #include "GenericSingletons.h" 7 | #include "Misc/CoreDelegates.h" 8 | #include "PrivateFieldAccessor.h" 9 | #include "Templates/SharedPointer.h" 10 | #include "UnrealCompatibility.h" 11 | #include "WorldLocalStorages.h" 12 | 13 | namespace ObjectDataRegistry 14 | { 15 | using DataType = TSharedPtr; 16 | using KeyType = FName; 17 | 18 | struct FObjectDataStorage : public FUObjectArray::FUObjectDeleteListener 19 | { 20 | virtual ~FObjectDataStorage() 21 | { 22 | if (bListened && UObjectInitialized()) 23 | DisableListener(); 24 | } 25 | 26 | TMap> ObjectDataStorage; 27 | TMap> KeyCache; 28 | bool bListened = false; 29 | 30 | virtual void NotifyUObjectDeleted(const UObjectBase* ObjectBase, int32 Index) override 31 | { 32 | auto Object = static_cast(ObjectBase); 33 | OnObjectRemoved(Object); 34 | } 35 | 36 | void OnObjectRemoved(const UObject* Object) 37 | { 38 | #if UE_4_23_OR_LATER 39 | // TODO IsInGarbageCollectorThread() 40 | static TLockFreePointerListUnordered GameThreadObjects; 41 | if (IsInGameThread()) 42 | #else 43 | check(IsInGameThread()); 44 | #endif 45 | { 46 | #if UE_4_23_OR_LATER 47 | if (!GameThreadObjects.IsEmpty()) 48 | { 49 | TArray Objs; 50 | GameThreadObjects.PopAll(Objs); 51 | for (auto Ptr : Objs) 52 | { 53 | RemoveObject(*Ptr); 54 | delete Ptr; 55 | } 56 | } 57 | #endif 58 | RemoveObject(Object); 59 | 60 | if (ObjectDataStorage.Num() == 0) 61 | DisableListener(); 62 | } 63 | #if UE_4_23_OR_LATER 64 | else 65 | { 66 | GameThreadObjects.Push(new FWeakObjectPtr(Object)); 67 | } 68 | #endif 69 | } 70 | void OnUObjectArrayShutdown() { DisableListener(); } 71 | void DisableListener() 72 | { 73 | if (bListened) 74 | { 75 | bListened = false; 76 | GUObjectArray.RemoveUObjectDeleteListener(this); 77 | } 78 | } 79 | void EnableListener() 80 | { 81 | if (!bListened) 82 | { 83 | bListened = true; 84 | GUObjectArray.AddUObjectDeleteListener(this); 85 | } 86 | } 87 | bool RemoveObject(const FWeakObjectPtr& Object) 88 | { 89 | if (auto Find = ObjectDataStorage.Find(Object)) 90 | { 91 | for (auto& a : *Find) 92 | KeyCache.Remove(a.Key); 93 | ObjectDataStorage.Remove(Object); 94 | return true; 95 | } 96 | return false; 97 | } 98 | bool RemoveKey(const KeyType& Key) 99 | { 100 | if (auto Find = KeyCache.Find(Key)) 101 | { 102 | for (auto& Obj : *Find) 103 | { 104 | if (auto Found = ObjectDataStorage.Find(Obj)) 105 | Found->Remove(Key); 106 | } 107 | KeyCache.Remove(Key); 108 | return true; 109 | } 110 | return false; 111 | } 112 | 113 | public: 114 | void AddObjectData(const FWeakObjectPtr& Object, const KeyType& Key, DataType Data) 115 | { 116 | check(Object.IsValid() && Key.IsValid()); 117 | if (ObjectDataStorage.Num() == 0) 118 | EnableListener(); 119 | ObjectDataStorage.FindOrAdd(Object).Add(Key, Data); 120 | KeyCache.FindOrAdd(Key).Add(Object); 121 | } 122 | 123 | void* GetObjectData(const FWeakObjectPtr& Object, const KeyType& Key) 124 | { 125 | if (auto Find = ObjectDataStorage.Find(Object)) 126 | { 127 | if (auto Found = Find->Find(Key)) 128 | { 129 | return Found->Get(); 130 | } 131 | } 132 | return nullptr; 133 | } 134 | bool RemoveObjectData(const FWeakObjectPtr& Object, const KeyType& Key) 135 | { 136 | check(Object.IsValid() && Key.IsValid()); 137 | if (auto Find = ObjectDataStorage.Find(Object)) 138 | { 139 | if (auto Found = Find->Find(Key)) 140 | { 141 | Find->Remove(Key); 142 | if (auto Cache = KeyCache.Find(Key)) 143 | Cache->Remove(Object); 144 | if (ObjectDataStorage.Num() == 0) 145 | DisableListener(); 146 | return true; 147 | } 148 | } 149 | return false; 150 | } 151 | }; 152 | 153 | TUniquePtr GlobalMgr; 154 | 155 | TUniquePtr& GetStorage(bool bCreate = false) 156 | { 157 | if (bCreate && !GlobalMgr) 158 | { 159 | GlobalMgr = MakeUnique(); 160 | FCoreDelegates::OnPreExit.AddLambda([] { 161 | if (ensureAlways(GlobalMgr)) 162 | { 163 | GlobalMgr.Reset(); 164 | } 165 | }); 166 | } 167 | return GlobalMgr; 168 | } 169 | } // namespace ObjectDataRegistry 170 | 171 | void* FObjectDataRegistry::FindDataPtr(const UObject* Obj, FName Key) 172 | { 173 | if (auto& Mgr = ObjectDataRegistry::GetStorage()) 174 | { 175 | return Mgr->GetObjectData(Obj, Key); 176 | } 177 | return nullptr; 178 | } 179 | 180 | bool FObjectDataRegistry::DelDataPtr(const UObject* Obj, FName Key) 181 | { 182 | if (auto& Mgr = ObjectDataRegistry::GetStorage()) 183 | { 184 | return Mgr->RemoveObjectData(Obj, Key); 185 | } 186 | return false; 187 | } 188 | 189 | ////////////////////////////////////////////////////////////////////////// 190 | 191 | void UObjectDataRegistryHelper::OnActorDestroyed(AActor* InActor) 192 | { 193 | if (auto& Mgr = ObjectDataRegistry::GetStorage()) 194 | Mgr->RemoveObject(FWeakObjectPtr(InActor)); 195 | } 196 | 197 | DEFINE_FUNCTION(UObjectDataRegistryHelper::execGetObjectData) 198 | { 199 | P_GET_OBJECT(UObject, Obj); 200 | P_GET_UBOOL(bWriteData); 201 | P_GET_UBOOL_REF(bSucc); 202 | Stack.MostRecentProperty = nullptr; 203 | Stack.StepCompiledIn(nullptr); 204 | if (auto Prop = CastField(Stack.MostRecentProperty)) 205 | { 206 | auto& Mgr = ObjectDataRegistry::GetStorage(true); 207 | void* Ptr = Mgr->GetObjectData(Obj, Prop->Struct->GetFName()); 208 | if (Ptr) 209 | { 210 | if (!bWriteData) 211 | Prop->CopyCompleteValueToScriptVM(Stack.MostRecentPropertyAddress, Ptr); 212 | else 213 | Prop->CopyCompleteValueFromScriptVM(Ptr, Stack.MostRecentPropertyAddress); 214 | bSucc = true; 215 | } 216 | else if (auto Ops = Prop->Struct->GetCppStructOps()) 217 | { 218 | Ptr = FMemory::Malloc(Ops->GetSize(), Ops->GetAlignment()); 219 | Ops->Construct(Ptr); 220 | auto SPtr = TSharedPtr(Ptr, [Ops](void* p) { 221 | if (Ops->HasDestructor()) 222 | Ops->Destruct(p); 223 | FMemory::Free(p); 224 | }); 225 | Prop->CopyCompleteValueFromScriptVM(Ptr, Stack.MostRecentPropertyAddress); 226 | Mgr->AddObjectData(Obj, Prop->Struct->GetFName(), SPtr); 227 | bSucc = true; 228 | } 229 | else 230 | { 231 | bSucc = false; 232 | } 233 | } 234 | else 235 | { 236 | bSucc = false; 237 | } 238 | } 239 | 240 | DEFINE_FUNCTION(UObjectDataRegistryHelper::execDelObjectData) 241 | { 242 | P_GET_OBJECT(UObject, Obj); 243 | Stack.MostRecentProperty = nullptr; 244 | Stack.StepCompiledIn(nullptr); 245 | if (auto Prop = CastField(Stack.MostRecentProperty)) 246 | { 247 | if (auto& Mgr = ObjectDataRegistry::GetStorage()) 248 | Mgr->RemoveObjectData(Obj, Prop->Struct->GetFName()); 249 | } 250 | } 251 | 252 | void UObjectDataRegistryHelper::DeleteObjectDataByName(const UObject* KeyObj, FName Name) 253 | { 254 | FObjectDataRegistry::DelDataPtr(KeyObj, Name); 255 | } 256 | 257 | GS_PRIVATEACCESS_FUNCTION_NAME(UObjectDataRegistryHelper, OnActorDestroyed, void(AActor*)) 258 | void* FObjectDataRegistry::GetDataPtr(const UObject* Obj, FName Key, const TFunctionRef()>& Func) 259 | { 260 | void* Ret = nullptr; 261 | if (auto& Mgr = ObjectDataRegistry::GetStorage(true)) 262 | { 263 | Ret = Mgr->GetObjectData(Obj, Key); 264 | if (!Ret) 265 | { 266 | auto Data = Func(); 267 | Ret = Data.Get(); 268 | if (auto Actor = Cast(Obj)) 269 | { 270 | static FName OnActorDestroyedName = PrivateAccess::UObjectDataRegistryHelper::OnActorDestroyed; 271 | auto Helper = UGenericSingletons::GetSingleton(Obj); 272 | auto& OnDestroyed = const_cast(Actor)->OnDestroyed; 273 | if (OnDestroyed.Contains(Helper, OnActorDestroyedName)) 274 | { 275 | #if UE_5_03_OR_LATER 276 | TBaseDynamicDelegate Delegate; 277 | #else 278 | TBaseDynamicDelegate Delegate; 279 | #endif 280 | Delegate.BindUFunction(Helper, OnActorDestroyedName); 281 | OnDestroyed.Add(Delegate); 282 | } 283 | } 284 | Mgr->AddObjectData(Obj, Key, MoveTemp(Data)); 285 | } 286 | } 287 | return Ret; 288 | } 289 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/ObjectPattern.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #include "ObjectPattern.h" 4 | 5 | #include "Engine/Engine.h" 6 | #include "Engine/World.h" 7 | #include "GenericSingletons.h" 8 | #include "UnrealCompatibility.h" 9 | 10 | FCriticalSection UObjectPattern::Critical; 11 | 12 | UObjectPattern::FCSLock423::FCSLock423() 13 | { 14 | #if UE_4_23_OR_LATER 15 | UObjectPattern::Critical.Lock(); 16 | #endif 17 | } 18 | 19 | UObjectPattern::FCSLock423::~FCSLock423() 20 | { 21 | #if UE_4_23_OR_LATER 22 | UObjectPattern::Critical.Unlock(); 23 | #endif 24 | } 25 | 26 | namespace ObjectPattern 27 | { 28 | template 29 | void EachClass(UObject* Object, UClass* StopClass, const F& f) 30 | { 31 | check(StopClass); 32 | auto ObjectClass = Object->GetClass(); 33 | for (auto CurClass = ObjectClass; CurClass; CurClass = CurClass->GetSuperClass()) 34 | { 35 | #if WITH_EDITOR 36 | if (CurClass->GetName().StartsWith(TEXT("SKEL_"))) 37 | continue; 38 | #endif 39 | if (CurClass == StopClass) 40 | break; 41 | f(CurClass); 42 | } 43 | } 44 | template 45 | void EachClass(UObject* Object, const F& f) 46 | { 47 | auto ObjectClass = Object->GetClass(); 48 | for (auto CurClass = ObjectClass; CurClass; CurClass = CurClass->GetSuperClass()) 49 | { 50 | #if WITH_EDITOR 51 | if (CurClass->GetName().StartsWith(TEXT("SKEL_"))) 52 | continue; 53 | #endif 54 | f(CurClass); 55 | if (CurClass->IsNative()) 56 | break; 57 | } 58 | } 59 | 60 | TArray Storage; 61 | auto AllocNewStorage(int32& Index) 62 | { 63 | if (Index == 0) 64 | { 65 | Index = Storage.Add(FObjectPatternType{MakeShared()}); 66 | } 67 | return Index; 68 | } 69 | TMap, int32> ClassToID; 70 | } // namespace ObjectPattern 71 | 72 | UClass* UObjectPattern::FindFirstNativeClass(UClass* Class) 73 | { 74 | for (; Class; Class = Class->GetSuperClass()) 75 | { 76 | if (0 != (Class->ClassFlags & CLASS_Native)) 77 | { 78 | break; 79 | } 80 | } 81 | return Class; 82 | } 83 | 84 | #if WITH_EDITOR 85 | bool UObjectPattern::EditorIsGameWorld(const UObject* WorldContextObj) 86 | { 87 | if (IsRunningCommandlet() || !UObjectInitialized() || IsEngineExitRequested()) 88 | return false; 89 | 90 | check(WorldContextObj); 91 | // auto Class = WorldContextObj->GetClass(); 92 | // if (IsValid(Class)) 93 | // { 94 | // if (Class->IsChildOf(UActorComponent::StaticClass())) 95 | // { 96 | // auto Comp = static_cast(WorldContextObj); 97 | // if (!IsValid(Comp->GetOuter()) || Comp->GetOuter()->GetFName().IsNone()) 98 | // return false; 99 | // if (!IsValid(Comp->GetOwner()) || Comp->GetOwner()->GetFName().IsNone()) 100 | // return false; 101 | // } 102 | // } 103 | 104 | auto World = GEngine->GetWorldFromContextObject(WorldContextObj, EGetWorldErrorMode::ReturnNull); 105 | return IsValid(World) && World->IsGameWorld(); 106 | } 107 | #endif 108 | 109 | FObjectPatternType::FWeakObjectArray::TIterator FObjectPatternType::CreateIterator() 110 | { 111 | check(IsValid()); 112 | return Objects->CreateIterator(); 113 | } 114 | 115 | void UObjectPattern::SetObject(UObject* Object, UClass* StopClass) 116 | { 117 | if (!EditorIsGameWorld(Object)) 118 | return; 119 | 120 | auto& RefObjects = Get(Object)->TypeObjects; 121 | if (StopClass) 122 | { 123 | check(Object->IsA(StopClass)); 124 | ObjectPattern::EachClass(Object, StopClass->GetSuperClass(), [&](auto CurClass) { 125 | auto& Ref = RefObjects.FindOrAdd(CurClass); 126 | ensureMsgf(!Ref.IsValid(), TEXT("%s"), *GetNameSafe(Object)); 127 | Ref = Object; 128 | }); 129 | } 130 | else 131 | { 132 | ObjectPattern::EachClass(Object, [&](auto CurClass) { 133 | auto& Ref = RefObjects.FindOrAdd(CurClass); 134 | ensureMsgf(!Ref.IsValid(), TEXT("%s"), *GetNameSafe(Object)); 135 | Ref = Object; 136 | }); 137 | } 138 | } 139 | 140 | FObjectPatternType::FWeakObjectArray::TIterator UObjectPattern::NativeIterator(int32 Index) 141 | { 142 | if (ensure(Index > 0 && Index < ObjectPattern::Storage.Num())) 143 | { 144 | return ObjectPattern::Storage[Index].CreateIterator(); 145 | } 146 | else 147 | { 148 | static FObjectPatternType::FWeakObjectArray NullObjects; 149 | return NullObjects.CreateIterator(); 150 | } 151 | } 152 | 153 | UObjectPattern::UObjectPattern() 154 | { 155 | static bool bListened = false; 156 | if (!bListened) 157 | { 158 | bListened = true; 159 | FWorldDelegates::OnWorldCleanup.AddLambda([](UWorld* World, bool /*bSessionEnded*/, bool /*bCleanupResources*/) { 160 | for (auto It = ObjectPattern::ClassToID.CreateIterator(); It;) 161 | { 162 | if (!It->Key.IsValid()) 163 | It.RemoveCurrent(); 164 | else 165 | ++It; 166 | } 167 | #if !WITH_EDITOR 168 | FCSLock423 Lock; 169 | 170 | if (auto Mgr = Get(World)) 171 | Mgr->Binddings.Empty(); 172 | #endif 173 | }); 174 | } 175 | } 176 | 177 | UObjectPattern* UObjectPattern::Get(const UObject* Obj) 178 | { 179 | if (!UObjectInitialized() || IsEngineExitRequested()) 180 | return nullptr; 181 | 182 | #if WITH_EDITOR 183 | if (GIsEditor) 184 | { 185 | return UGenericSingletons::GetSingleton(Obj); 186 | } 187 | else 188 | #endif 189 | { 190 | return UGenericSingletons::GetSingleton((UObject*)nullptr); 191 | } 192 | } 193 | 194 | TArray UObjectPattern::AllObject(const UObject* WorldContextObj, UClass* Class) 195 | { 196 | TArray Ret; 197 | EachObject(WorldContextObj, Class, [&](UObject* Obj) { Ret.Add(Obj); }); 198 | return Ret; 199 | } 200 | 201 | void UObjectPattern::EachObject(const UObject* WorldContextObj, UClass* Class, const TFunctionRef& f) 202 | { 203 | if (!EditorIsGameWorld(WorldContextObj)) 204 | return; 205 | 206 | if (auto Found = Get(WorldContextObj)->Binddings.Find(Class)) 207 | { 208 | for (auto It = Found->CreateIterator(); It;) 209 | { 210 | if (auto a = It->Get()) 211 | { 212 | f(a); 213 | ++It; 214 | } 215 | else 216 | { 217 | It.RemoveCurrent(); 218 | } 219 | } 220 | } 221 | } 222 | 223 | int32 UObjectPattern::GetTypeID(UClass* Class) 224 | { 225 | if (ensure(Class && ObjectPattern::ClassToID.Contains(Class))) 226 | { 227 | return ObjectPattern::ClassToID[Class]; 228 | } 229 | return 0; 230 | } 231 | 232 | UObject* UObjectPattern::GetObject(const UObject* WorldContextObj, UClass* Class) 233 | { 234 | if (!EditorIsGameWorld(WorldContextObj)) 235 | return nullptr; 236 | 237 | if (auto Find = Get(WorldContextObj)->TypeObjects.Find(Class)) 238 | return Find->Get(); 239 | return nullptr; 240 | } 241 | 242 | bool UObjectPattern::AddClassToRegistry(UObject* Object, UClass* StopClass, int32& ID) 243 | { 244 | if (Object->GetClass() == StopClass) 245 | { 246 | ID = ObjectPattern::AllocNewStorage(ObjectPattern::ClassToID.FindOrAdd(StopClass)); 247 | return true; 248 | } 249 | { 250 | FCSLock423 Lock; 251 | ObjectPattern::EachClass(Object, StopClass, [&](auto CurClass) { ObjectPattern::AllocNewStorage(ObjectPattern::ClassToID.FindOrAdd(CurClass)); }); 252 | return false; 253 | } 254 | } 255 | 256 | bool UObjectPattern::RemoveClassFromRegistry(UObject* Object, UClass* StopClass) 257 | { 258 | if (!EditorIsGameWorld(Object)) 259 | return true; 260 | 261 | FCSLock423 Lock; 262 | auto Class = Object->GetClass(); 263 | #if WITH_EDITOR 264 | if (!IsValid(Class) || Class->GetFName().IsNone() || Class->GetName().StartsWith(TEXT("SKEL_"))) 265 | return true; 266 | #endif 267 | auto Count = ObjectPattern::ClassToID.Remove(Class); 268 | return ensure(Count > 0); 269 | } 270 | 271 | void UObjectPattern::AddObjectToRegistry(UObject* Object, UClass* StopClass) 272 | { 273 | // if (!EditorIsGameWorld(Object)) 274 | // return; 275 | 276 | FCSLock423 Lock; 277 | check(!Object->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)); 278 | 279 | ObjectPattern::EachClass(Object, StopClass->GetSuperClass(), [&](auto CurClass) { 280 | #if WITH_EDITOR 281 | check(ObjectPattern::ClassToID.Contains(CurClass)); 282 | check(ObjectPattern::Storage.IsValidIndex(ObjectPattern::ClassToID[CurClass])); 283 | #endif 284 | FObjectPatternType& Found = Binddings.FindOrAdd(CurClass); 285 | if (!Found.Objects.IsValid()) 286 | { 287 | Found.Objects = ObjectPattern::Storage[ObjectPattern::ClassToID.FindChecked(CurClass)].Objects; 288 | } 289 | #if WITH_EDITOR 290 | ensure(Found.Objects.IsValid() && !Found.Objects->Contains(Object)); 291 | #endif 292 | Found.Add(Object); 293 | }); 294 | } 295 | 296 | void UObjectPattern::RemoveObjectFromRegistry(UObject* Object, UClass* StopClass) 297 | { 298 | // if (!EditorIsGameWorld(Object)) 299 | // return; 300 | 301 | FCSLock423 Lock; 302 | 303 | check(!Object->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)); 304 | 305 | auto ObjectClass = Object->GetClass(); 306 | ObjectPattern::EachClass(Object, StopClass->GetSuperClass(), [&](auto CurClass) { 307 | if (auto Found = Binddings.Find(CurClass)) 308 | { 309 | Found->Remove(Object); 310 | } 311 | }); 312 | } 313 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Private/TypeTableBindding.cpp: -------------------------------------------------------------------------------- 1 | // Copyright GenericAbilities, Inc. All Rights Reserved. 2 | 3 | #include "TypeTableBindding.h" 4 | 5 | #include "GenericSingletons.h" 6 | 7 | FTypeTableBindding& FTypeTableBindding::Get() 8 | { 9 | static FTypeTableBindding Singleton; 10 | 11 | if (TrueOnFirstCall([] {})) 12 | { 13 | GenericSingletons::DeferredWorldCleanup(TEXT("TypeTableBindding"), [] { 14 | auto It = Singleton.Binddings.CreateIterator(); 15 | while (It) 16 | { 17 | if (!It->Key.IsEmpty() && It->Value.IsValid()) 18 | { 19 | ++It; 20 | } 21 | else 22 | { 23 | It.RemoveCurrent(); 24 | } 25 | } 26 | }); 27 | } 28 | return Singleton; 29 | } 30 | 31 | UScriptStruct* FTypeTableBindding::FindType(UClass* Class) 32 | { 33 | UScriptStruct* Ret = nullptr; 34 | if (Class) 35 | { 36 | if (auto Find = Get().Binddings.Find(Class->GetName())) 37 | { 38 | //ensure(*Find == S::StaticStruct()) 39 | Ret = Find->Get(); 40 | } 41 | } 42 | return Ret; 43 | } 44 | 45 | namespace TypeTableBindding 46 | { 47 | struct FKeyCache 48 | { 49 | FName Base; 50 | FName Sub; 51 | 52 | FKeyCache(const FString& InBase, const FString& InSub) 53 | : Base(*InBase, InBase.Len()) 54 | , Sub(*InSub, InSub.Len()) 55 | { 56 | } 57 | FKeyCache(const FKeyCache&) = default; 58 | FKeyCache& operator=(const FKeyCache&) = default; 59 | FORCEINLINE friend bool operator==(const FKeyCache& Lhs, const FKeyCache& Rhs) { return (Lhs.Base == Rhs.Base) && (Lhs.Sub == Rhs.Sub); } 60 | }; 61 | 62 | FORCEINLINE uint32 GetTypeHash(const FKeyCache& Key) 63 | { 64 | return HashCombine(GetTypeHash(Key.Base), GetTypeHash(Key.Sub)); 65 | } 66 | 67 | static TMap, TMap>> Lookup; 68 | } // namespace TypeTableBindding 69 | 70 | UDataTable* FTableBinddingDeclaration::GetTableFromType(UClass* Class) 71 | { 72 | return nullptr; 73 | } 74 | 75 | FName FTableBinddingDeclaration::GetRowName(UDataTable& Table, const TCHAR* InCategory, const TCHAR* InSubCategory) 76 | { 77 | return NAME_None; 78 | } 79 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/ClassDataStorage.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | #include "CoreMinimal.h" 5 | 6 | #include "Misc/CoreDelegates.h" 7 | #include "GenericStoragesLog.h" 8 | #include "Misc/CoreDelegates.h" 9 | 10 | namespace ClassStorage 11 | { 12 | // each type (USTRUCT or UCLASS) would has a storage place in the type-tree for fast lookup 13 | template 14 | struct TClassStorageImpl 15 | { 16 | protected: 17 | using StorageDataType = T; 18 | struct StorageContainerType; 19 | 20 | using DataPtrType = TSharedPtr; 21 | static auto* GetRaw(const DataPtrType& Ptr) { return Ptr.Get(); } 22 | template 23 | static DataPtrType AllocShared(Args&&... args) 24 | { 25 | return MakeShared(Forward(args)...); 26 | } 27 | struct ClassIterator 28 | { 29 | explicit ClassIterator(const DataPtrType& InPtr) 30 | : Ptr(InPtr) 31 | { 32 | } 33 | // we do not return sharedptr type. 34 | FORCEINLINE const StorageContainerType& operator*() const { return *GetRaw(Ptr); } 35 | FORCEINLINE const StorageContainerType* operator->() const { return GetRaw(Ptr); } 36 | FORCEINLINE explicit operator bool() { return Ptr != nullptr; } 37 | FORCEINLINE ClassIterator& operator++() 38 | { 39 | Ptr = Ptr->Super; 40 | return *this; 41 | } 42 | 43 | private: 44 | DataPtrType Ptr; 45 | }; 46 | 47 | ////////////////////////////////////////////////////////////////////////// 48 | struct StorageContainerType 49 | { 50 | TWeakObjectPtr KeyClass; 51 | DataPtrType Super; 52 | StorageDataType Data; 53 | 54 | const StorageContainerType* GetSuper() const { return GetRaw(Super); } 55 | }; 56 | TMap, DataPtrType> PersistentData; 57 | TMap, DataPtrType> RegisteredData; 58 | mutable TMap, DataPtrType> FastLookupTable; 59 | mutable bool bEnableAdd = true; 60 | 61 | ////////////////////////////////////////////////////////////////////////// 62 | DataPtrType* Add(TMap, DataPtrType>& Regs, const UStruct* Class, bool bEnsure, bool* bNewCreated = nullptr) 63 | { 64 | if (bEnsure && !ensureAlwaysMsgf(bEnableAdd, TEXT("TClassDataStorage cannot add data anymore"))) 65 | return nullptr; 66 | 67 | auto& Ptr = Regs.FindOrAdd(Class); 68 | if (!Ptr) 69 | { 70 | Ptr = AllocShared(); 71 | if (bNewCreated) 72 | *bNewCreated = true; 73 | Ptr->KeyClass = Class; 74 | for (auto& a : Regs) 75 | { 76 | if (a.Key.IsValid() && a.Key->IsChildOf(Class) && a.Key.Get() != Class) 77 | { 78 | for (auto CurPtr = a.Value; CurPtr; CurPtr = CurPtr->Super) 79 | { 80 | auto SuperPtr = CurPtr->Super; 81 | if (!SuperPtr) 82 | { 83 | #if !UE_BUILD_SHIPPING 84 | UE_LOG(LogGenericStorages, Log, TEXT("TClassDataStorage::AddParent %s -> %s"), *CurPtr->KeyClass->GetName(), *Class->GetName()); 85 | #endif 86 | CurPtr->Super = Ptr; 87 | break; 88 | } 89 | else if (Class == SuperPtr->KeyClass) 90 | { 91 | #if !UE_BUILD_SHIPPING 92 | UE_LOG(LogGenericStorages, Log, TEXT("TClassDataStorage::AlreadyAdded %s -> %s"), *CurPtr->KeyClass->GetName(), *Class->GetName()); 93 | #endif 94 | break; 95 | } 96 | else if (SuperPtr->KeyClass.IsValid() && Class->IsChildOf(SuperPtr->KeyClass.Get())) 97 | { 98 | #if !UE_BUILD_SHIPPING 99 | UE_LOG(LogGenericStorages, Log, TEXT("TClassDataStorage::Inserted %s-> -> %s"), *CurPtr->KeyClass->GetName(), *Class->GetName(), *SuperPtr->KeyClass->GetName()); 100 | #endif 101 | Ptr->Super = CurPtr->Super; 102 | CurPtr->Super = Ptr; 103 | break; 104 | } 105 | } 106 | } 107 | } 108 | if (!Ptr->Super) 109 | { 110 | for (auto ParentClass = Class->GetSuperStruct(); ParentClass != nullptr; ParentClass = ParentClass->GetSuperStruct()) 111 | { 112 | if (auto InnerPtr = Regs.Find(ParentClass)) 113 | { 114 | #if !UE_BUILD_SHIPPING 115 | UE_LOG(LogGenericStorages, Log, TEXT("TClassDataStorage::AddedChild %s -> %s"), *Class->GetName(), *ParentClass->GetName()); 116 | #endif 117 | Ptr->Super = *InnerPtr; 118 | break; 119 | } 120 | } 121 | } 122 | } 123 | return &Ptr; 124 | }; 125 | 126 | DataPtrType Find(const UStruct* Class, bool bNewDisable = true) const 127 | { 128 | // auto lock : at first query, no more data needed 129 | if (bAutoLock && bNewDisable) 130 | SetEnableState(false); 131 | 132 | checkSlow(Class); 133 | 134 | if (auto FindPtr = FastLookupTable.Find(Class)) 135 | return *FindPtr; 136 | 137 | DataPtrType& Ptr = FastLookupTable.Add(Class); 138 | #if !UE_BUILD_SHIPPING 139 | UE_LOG(LogGenericStorages, Log, TEXT("TClassDataStorage::FastLookupTable Add %s"), *Class->GetName()); 140 | #endif 141 | for (auto CurrentClass = Class; CurrentClass != nullptr; CurrentClass = CurrentClass->GetSuperStruct()) 142 | { 143 | if (auto InnerPtr = RegisteredData.Find(CurrentClass)) 144 | { 145 | #if !UE_BUILD_SHIPPING 146 | UE_LOG(LogGenericStorages, Log, TEXT("TClassDataStorage::FastLookupTable %s -> %s"), *Class->GetName(), *CurrentClass->GetName()); 147 | #endif 148 | Ptr = *InnerPtr; 149 | break; 150 | } 151 | } 152 | return Ptr; 153 | } 154 | void Clean() 155 | { 156 | UE_LOG(LogGenericStorages, Log, TEXT("TClassDataStorage::Clean")); 157 | #if 0 158 | FastLookupTable.Reset(); 159 | RegisteredData.Reset(); 160 | PersistentData.Reset(); 161 | SetEnableState(true); 162 | #endif 163 | } 164 | 165 | void Clear() 166 | { 167 | UE_LOG(LogGenericStorages, Log, TEXT("TClassDataStorage::Clear")); 168 | FastLookupTable.Reset(); 169 | RegisteredData.Reset(); 170 | SetEnableState(true); 171 | 172 | for (const auto& a : PersistentData) 173 | { 174 | if (a.Key.IsValid()) 175 | RegisteredData.Add(a.Key.Get(), AllocShared(*a.Value)); 176 | } 177 | 178 | for (auto& Pair : RegisteredData) 179 | { 180 | DataPtrType& Value = Pair.Value; 181 | if (Value && Value->Super) 182 | { 183 | auto SuperClass = Value->Super->KeyClass; 184 | Value->Super = nullptr; 185 | if (auto Ptr = RegisteredData.Find(SuperClass)) 186 | Value->Super = *Ptr; 187 | } 188 | } 189 | } 190 | 191 | public: 192 | TClassStorageImpl() 193 | { 194 | static_assert(std::is_copy_assignable::value, "err"); 195 | FCoreDelegates::OnEnginePreExit.AddRaw(this, &TClassStorageImpl::Clean); 196 | } 197 | 198 | void Cleanup() { Clear(); } 199 | 200 | void SetEnableState(bool bNewEanbled) const { bEnableAdd = bNewEanbled; } 201 | 202 | StorageDataType* FindData(const UStruct* Class) const 203 | { 204 | DataPtrType Ptr = Class ? Find(Class) : nullptr; 205 | return Ptr ? &Ptr->Data : (StorageDataType*)nullptr; 206 | } 207 | auto CreateIterator(const UStruct* Class) const { return ClassIterator(Find(Class)); } 208 | auto CreateIterator() const { return RegisteredData.CreateConstIterator(); } 209 | auto GetKeys() 210 | { 211 | TArray> Keys; 212 | RegisteredData.GetKeys(Keys); 213 | return Keys; 214 | } 215 | template 216 | void ModifyData(const UStruct* Class, bool bPersistent, const F& Fun, bool bPrompt = true) 217 | { 218 | if (ensureAlways(Class)) 219 | { 220 | #if !UE_BUILD_SHIPPING 221 | UE_LOG(LogGenericStorages, Log, TEXT("TClassDataStorage::Modify%s %s"), bPersistent ? TEXT("All") : TEXT("Cur"), *Class->GetName()); 222 | #endif 223 | if (bPersistent) 224 | { 225 | if (auto DataPtr = Add(PersistentData, Class, bPrompt)) 226 | { 227 | Fun((*DataPtr)->Data); 228 | } 229 | } 230 | 231 | if (auto DataPtr = Add(RegisteredData, Class, bPrompt)) 232 | { 233 | Fun((*DataPtr)->Data); 234 | FastLookupTable.FindOrAdd(Class) = *DataPtr; 235 | } 236 | } 237 | } 238 | template 239 | void ModifyCurrent(const UStruct* Class, const F& Fun, bool bEnable = false) 240 | { 241 | if (ensureAlways(Class)) 242 | { 243 | #if !UE_BUILD_SHIPPING 244 | UE_LOG(LogGenericStorages, Log, TEXT("TClassDataStorage::Modify Current %s"), *Class->GetName()); 245 | #endif 246 | if (auto ClassPtr = Find(Class)) 247 | { 248 | Fun(ClassPtr->Data, true); 249 | FastLookupTable.FindOrAdd(Class) = ClassPtr; 250 | } 251 | else 252 | { 253 | if (bEnable) 254 | SetEnableState(true); 255 | if (auto DataPtr = Add(RegisteredData, Class, true)) 256 | { 257 | Fun((*DataPtr)->Data, false); 258 | FastLookupTable.FindOrAdd(Class) = *DataPtr; 259 | } 260 | } 261 | } 262 | } 263 | }; 264 | 265 | } // namespace ClassStorage 266 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/ComponentPattern.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "Components/ActorComponent.h" 8 | #include "Kismet/BlueprintFunctionLibrary.h" 9 | #include "ObjectPattern.h" 10 | 11 | #include "ComponentPattern.generated.h" 12 | 13 | UCLASS(Transient, meta = (NeuronAction)) 14 | class GENERICSTORAGES_API UComponentPattern final : public UBlueprintFunctionLibrary 15 | { 16 | GENERATED_BODY() 17 | public: 18 | template 19 | static void EachComponent(const UObject* WorldContextObj, const F& f) 20 | { 21 | static_assert(TIsDerivedFrom::IsDerived && !TIsSame::Value, "err"); 22 | UObjectPattern::EachObject(WorldContextObj, f); 23 | } 24 | 25 | DECLARE_DYNAMIC_DELEGATE_OneParam(FOnEachComponentAction, UActorComponent*, Comp); 26 | UFUNCTION(BlueprintCallable, BlueprintInternalUseOnly, Category = "Game", meta = (NeuronAction, DisplayName = "EachComponent", WorldContext = "WorldContextObj", HidePin = "WorldContextObj")) 27 | static void EachComponent(const UObject* WorldContextObj, TSubclassOf Class, UPARAM(meta = (DeterminesOutputType = "Class", DynamicOutputParam = "Comp")) FOnEachComponentAction OnEachComp) 28 | { 29 | if (ensure(Class)) 30 | { 31 | UObjectPattern::EachObject(WorldContextObj, Class, [&](auto a) { OnEachComp.ExecuteIfBound(static_cast(a)); }); 32 | } 33 | } 34 | 35 | template 36 | static T* GetComponent(const UObject* WorldContextObject) 37 | { 38 | static_assert(TIsDerivedFrom::IsDerived && !TIsSame::Value, "err"); 39 | return UObjectPattern::GetObject(WorldContextObject); 40 | } 41 | 42 | protected: 43 | UFUNCTION(BlueprintCallable, Category = "Game", meta = (DisplayName = "GetComponents", WorldContext = "WorldContextObj", HidePin = "WorldContextObj", DeterminesOutputType = "Class", DynamicOutputParam)) 44 | static TArray AllComponent(const UObject* WorldContextObj, TSubclassOf Class) 45 | { 46 | TArray Ret; 47 | UObjectPattern::EachObject(WorldContextObj, Class, [&](auto a) { Ret.Add(static_cast(a)); }); 48 | return Ret; 49 | } 50 | 51 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "GetComponent", WorldContext = "WorldContextObj", HidePin = "WorldContextObj", DeterminesOutputType = "Class", DynamicOutputParam)) 52 | static UActorComponent* GetComponent(const UObject* WorldContextObj, TSubclassOf Class) { return static_cast(UObjectPattern::GetObject(WorldContextObj, Class)); } 53 | }; 54 | 55 | template 56 | struct TEachComponentPattern : public TEachObjectPattern 57 | { 58 | TEachComponentPattern() 59 | { 60 | static_assert(TIsDerivedFrom::IsDerived && !TIsSame::Value, "err"); 61 | Ctor(static_cast(this)); 62 | } 63 | ~TEachComponentPattern() { Dtor(static_cast(this)); } 64 | 65 | protected: 66 | using TEachObjectPattern::Ctor; 67 | using TEachObjectPattern::Dtor; 68 | }; 69 | 70 | template 71 | struct TSingleComponentPattern : public TSingleObjectPattern 72 | { 73 | TSingleComponentPattern() 74 | { 75 | static_assert(TIsDerivedFrom::IsDerived && !TIsSame::Value, "err"); 76 | Ctor(static_cast(this)); 77 | } 78 | ~TSingleComponentPattern() { Dtor(static_cast(this)); } 79 | }; 80 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/ComponentPicker.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "CoreUObject.h" 7 | 8 | #include "Components/ActorComponent.h" 9 | 10 | #include "ComponentPicker.generated.h" 11 | 12 | USTRUCT(BlueprintType) 13 | struct GENERICSTORAGES_API FComponentPicker 14 | { 15 | GENERATED_BODY() 16 | public: 17 | UPROPERTY(EditAnywhere, Category = "ComponentPicker") 18 | FName ComponentName; 19 | 20 | #if WITH_EDITORONLY_DATA 21 | UPROPERTY(EditDefaultsOnly, Category = "ComponentPicker") 22 | TSubclassOf ComponentClass; 23 | #endif 24 | operator FName() const { return ComponentName; } 25 | 26 | UActorComponent* FindComponentByName(AActor* InActor) const; 27 | template 28 | T* FindComponentByName(AActor* InActor) const 29 | { 30 | return FindComponentByName(InActor, ComponentName); 31 | } 32 | 33 | public: 34 | static UActorComponent* FindComponentByName(AActor* InActor, FName CompName, TSubclassOf InClass = {}); 35 | 36 | template 37 | static T* FindComponentByName(AActor* InActor, FName CompName) 38 | { 39 | static_assert(TIsDerivedFrom::IsDerived, "err"); 40 | return Cast(FindComponentByName(InActor, CompName, T::StaticClass())); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/DataTablePicker.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "Engine/DataTable.h" 8 | #include "Templates/SubclassOf.h" 9 | #include "UObject/WeakObjectPtr.h" 10 | #include "UObject/WeakObjectPtrTemplates.h" 11 | 12 | #include "DataTablePicker.generated.h" 13 | 14 | ////////////////////////////////////////////////////////////////////////// 15 | // meta=(DataTableType="RowSructType") 16 | USTRUCT(BlueprintType) 17 | struct GENERICSTORAGES_API FDataTablePicker 18 | { 19 | GENERATED_BODY() 20 | public: 21 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "DataTablePicker") 22 | UDataTable* DataTable = nullptr; 23 | }; 24 | 25 | // Table+Row 26 | USTRUCT(BlueprintType) 27 | struct GENERICSTORAGES_API FDataTableRowPicker 28 | { 29 | GENERATED_BODY() 30 | public: 31 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "DataTablePicker") 32 | UDataTable* DataTable = nullptr; 33 | 34 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "DataTablePicker") 35 | FName RowName; 36 | }; 37 | 38 | USTRUCT(BlueprintType) 39 | struct GENERICSTORAGES_API FDataTablePathPicker 40 | { 41 | GENERATED_BODY() 42 | public: 43 | // SoftPath 44 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "DataTablePicker") 45 | TSoftObjectPtr DataTablePath; 46 | }; 47 | 48 | USTRUCT(BlueprintType) 49 | struct GENERICSTORAGES_API FDataTableRowNamePicker 50 | { 51 | GENERATED_BODY() 52 | public: 53 | // RowName 54 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "DataTablePicker") 55 | FName RowName; 56 | 57 | #if WITH_EDITORONLY_DATA 58 | // EditorOnly,Limit DataTable type 59 | UPROPERTY(EditAnywhere, Category = "DataTablePicker") 60 | TSoftObjectPtr DataTablePath; 61 | #endif 62 | }; 63 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/DeferredComponentConfig.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "Engine/World.h" 8 | #include "Templates/SubclassOf.h" 9 | #include "UnrealCompatibility.h" 10 | 11 | #if UE_4_20_OR_LATER 12 | #include "AI/NavigationSystemBase.h" 13 | #endif 14 | 15 | class AActor; 16 | class UActorComponent; 17 | 18 | namespace DeferredComponentRegistry 19 | { 20 | GENERICSTORAGES_API void AppendDeferredComponents(AActor& Actor); 21 | 22 | // Default Hook On PostInitializeComponents or OnActorSpawned 23 | template 24 | struct TOnComponentInitialized 25 | { 26 | static constexpr bool bNeedInit = true; 27 | static void Bind() 28 | { 29 | //#if WITH_DELEGATE_ON_ACTOR_COMPONENTS_INITIALIZED 30 | #if 0 31 | // Modify Actor.cpp in Engine Source 32 | #if WITH_DELEGATE_ON_ACTOR_COMPONENTS_INITIALIZED 33 | DECLARE_DELEGATE_OneParam(FOnActorComponentsInitializedDelegate, AActor&) 34 | static FOnActorComponentsInitializedDelegate OnActorComponentsInitialized; 35 | ENGINE_API void SetOnActorComponentsInitializedDelegate(FOnActorComponentsInitializedDelegate Delegate) { OnActorComponentsInitialized = MoveTemp(Delegate); } 36 | #endif 37 | 38 | // add below to last of AActor::InitializeComponents 39 | #if WITH_DELEGATE_ON_ACTOR_COMPONENTS_INITIALIZED 40 | OnActorComponentsInitialized.ExecuteIfBound(*this); 41 | #endif 42 | //#endif 43 | extern ENGINE_API void SetOnActorComponentsInitializedDelegate(TDelegate); 44 | SetOnActorComponentsInitializedDelegate(TDelegate::CreateStatic(&AppendDeferredComponents)); 45 | #elif UE_4_20_OR_LATER 46 | class UHackNavigationSystemBase : public UNavigationSystemBase 47 | { 48 | public: 49 | using UNavigationSystemBase::OnActorRegisteredDelegate; 50 | }; 51 | 52 | if (UHackNavigationSystemBase::OnActorRegisteredDelegate().IsBound()) 53 | { 54 | // PostInitializeComponents 55 | static auto Delegate = MoveTemp(UHackNavigationSystemBase::OnActorRegisteredDelegate()); 56 | UHackNavigationSystemBase::OnActorRegisteredDelegate().BindLambda([](AActor& Actor) { 57 | AppendDeferredComponents(Actor); 58 | Delegate.Execute(Actor); 59 | }); 60 | } 61 | else 62 | #endif 63 | { 64 | // OnActorSpawned 65 | FCoreUObjectDelegates::PostLoadMapWithWorld.AddLambda([](UWorld* World) { 66 | if (World->WorldType == EWorldType::PIE || World->WorldType == EWorldType::Game) 67 | World->AddOnActorSpawnedHandler(FOnActorSpawned::FDelegate::CreateLambda([](AActor* a) { AppendDeferredComponents(*a); })); 68 | }); 69 | } 70 | } 71 | }; // namespace DeferredComponentRegistry 72 | 73 | #if 0 74 | /* 75 | Modify Actor in Engine Source 76 | 77 | //declare static delegate in AActor 78 | AActor 79 | { 80 | DECLARE_DELEGATE_OneParam(FOnActorComponentsInitializedDelegate,AActor&) 81 | static FOnActorComponentsInitializedDelegate OnActorComponentsInitialized; 82 | static void SetOnActorComponentsInitializedDelegate(FOnActorComponentsInitializedDelegate Delegate) 83 | { 84 | OnActorComponentsInitialized = MoveTemp(Delegate); 85 | } 86 | } 87 | 88 | // add below to last of AActor::InitializeComponents 89 | OnActorComponentsInitialized.ExecuteIfBound(*this) 90 | */ 91 | 92 | template 93 | struct TOnComponentInitialized> 94 | { 95 | static constexpr bool bNeedInit = false; 96 | static void Bind() 97 | { 98 | // add notify code in engine source in :InitializeComponents 99 | T::SetOnActorComponentsInitializedDelegate(TDelegate::CreateStatic(&AppendDeferredComponents)); 100 | } 101 | }; 102 | #endif 103 | } // namespace DeferredComponentRegistry 104 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/DeferredComponentRegistry.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "Engine/World.h" 8 | #include "Kismet/BlueprintFunctionLibrary.h" 9 | #include "Templates/SubclassOf.h" 10 | 11 | #include "DeferredComponentRegistry.generated.h" 12 | 13 | class AActor; 14 | class UActorComponent; 15 | class APlayerController; 16 | 17 | UENUM(BlueprintType, meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = true)) 18 | namespace EComponentDeferredMode 19 | { 20 | enum Type 21 | { 22 | None, 23 | ServerSide = 0x1 UMETA(DisplayName = "CreateOnServer", ToolTip = "CreateOnServer"), 24 | ClientSide = 0x2 UMETA(DisplayName = "CreateOnClient", ToolTip = "CreateOnClient"), 25 | Replicated = 0x4 UMETA(DisplayName = "SetReplicate", ToolTip = "SetReplicate"), 26 | NameStable = 0x8 UMETA(DisplayName = "NameStable", ToolTip = "Component,NameStable"), 27 | 28 | // means that it will create on bothside, and has a statble name path for repliction 29 | Instanced = 0xF UMETA(Hidden), 30 | 31 | BothSide = ServerSide | ClientSide UMETA(Hidden), 32 | }; 33 | } // namespace EComponentDeferredMode 34 | 35 | namespace EComponentDeferredMode 36 | { 37 | FORCEINLINE bool HasAnyFlags(uint8 Test, uint8 Flags) 38 | { 39 | return (Test & Flags) != 0; 40 | } 41 | FORCEINLINE bool HasAllFlags(uint8 Test, uint8 Flags) 42 | { 43 | return (Test & Flags) == Flags; 44 | } 45 | } // namespace EComponentDeferredMode 46 | 47 | namespace DeferredComponentRegistry 48 | { 49 | struct FRegClassData 50 | { 51 | TSubclassOf RegClass; 52 | uint8 RegFlags; 53 | 54 | // AddUnique 55 | inline bool operator==(const FRegClassData& Ohter) const { return Ohter.RegClass == RegClass; } 56 | }; 57 | using FRegClassDataArray = TArray; 58 | } // namespace DeferredComponentRegistry 59 | 60 | UCLASS() 61 | class GENERICSTORAGES_API UDeferredComponentRegistry final : public UBlueprintFunctionLibrary 62 | { 63 | GENERATED_BODY() 64 | public: 65 | UFUNCTION(BlueprintCallable, Category = "Game", meta = (CallableWithoutWorldContext = true)) 66 | static void AddDeferredComponents(TSubclassOf Class, 67 | const TSet>& RegDatas, 68 | bool bPersistent = true, 69 | UPARAM(DisplayName = "CreateMode", meta = (Bitmask, BitmaskEnum = "EComponentDeferredMode")) uint8 Mode = 0); 70 | 71 | UFUNCTION(BlueprintCallable, Category = "Game", meta = (CallableWithoutWorldContext = true)) 72 | static void AddDeferredComponent(TSubclassOf Class, 73 | TSubclassOf ComponentClass, 74 | bool bPersistent = true, 75 | UPARAM(DisplayName = "CreateMode", meta = (Bitmask, BitmaskEnum = "EComponentDeferredMode")) uint8 Mode = 0); 76 | 77 | UFUNCTION(BlueprintCallable, Category = "Game", meta = (CallableWithoutWorldContext = true)) 78 | static void EnableAdd(bool bNewEnabled); 79 | 80 | static uint8 GetMode(uint8 InFlags, TSubclassOf InClass); 81 | static void ModifyDeferredComponents(TSubclassOf Class, TFunctionRef Cb, bool bPersistent = false); 82 | }; 83 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/Editor/UnrealEditorUtils.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | #if WITH_EDITOR 5 | #include "CoreMinimal.h" 6 | 7 | #include "Components/ActorComponent.h" 8 | #include "DataTableEditorUtils.h" 9 | #include "DetailCategoryBuilder.h" 10 | #include "DetailLayoutBuilder.h" 11 | #include "Editor.h" 12 | #include "GameFramework/Actor.h" 13 | #include "IDetailChildrenBuilder.h" 14 | #include "IDetailCustomization.h" 15 | #include "IPropertyTypeCustomization.h" 16 | #include "IPropertyUtilities.h" 17 | #include "Internationalization/Text.h" 18 | #include "Misc/AssertionMacros.h" 19 | #include "Modules/ModuleManager.h" 20 | #include "PropertyCustomizationHelpers.h" 21 | #include "PropertyEditorModule.h" 22 | #include "PropertyHandle.h" 23 | #include "ScopedTransaction.h" 24 | #include "Templates/SubclassOf.h" 25 | #include "UObject/WeakObjectPtrTemplates.h" 26 | #include "UnrealCompatibility.h" 27 | #include "Widgets/DeclarativeSyntaxSupport.h" 28 | #include "EdGraph/EdGraphPin.h" 29 | #include "AssetRegistry/AssetRegistryModule.h" 30 | #if defined(GMP_API) 31 | #include "GMPCore.h" 32 | #endif 33 | 34 | class AActor; 35 | class UObject; 36 | class UDataTable; 37 | class ISettingsModule; 38 | class SWidget; 39 | 40 | namespace UnrealEditorUtils 41 | { 42 | template 43 | bool VerifyPropName(FProperty* Property) 44 | { 45 | #if defined(GMP_API) 46 | return Property && GMPReflection::EqualPropertyType(Property); 47 | #else 48 | return !!Property; 49 | #endif 50 | } 51 | 52 | template 53 | T* GetPropertyHandleUObjectValue(TSharedPtr PropertyHandle) 54 | { 55 | T* Ret = nullptr; 56 | UObject* Obj = nullptr; 57 | if (FPropertyAccess::Success == PropertyHandle->GetValue(Obj)) 58 | Ret = Cast(Obj); 59 | return Ret; 60 | } 61 | 62 | GENERICSTORAGES_API void* AccessPropertyAddress(const TSharedPtr& PropertyHandle); 63 | 64 | template 65 | ValueType* AccessPropertyAddress(const TSharedPtr& PropertyHandle, bool bEnsure = true) 66 | { 67 | FProperty* Property = PropertyHandle.IsValid() ? PropertyHandle->GetProperty() : nullptr; 68 | if (!VerifyPropName(Property)) 69 | { 70 | ensureAlways(!bEnsure); 71 | return nullptr; 72 | } 73 | return static_cast(AccessPropertyAddress(PropertyHandle)); 74 | } 75 | 76 | // TArray/TSet/TMap/Element 77 | GENERICSTORAGES_API void* GetPropertyAddress(const TSharedPtr& PropertyHandle, UObject* Outer = nullptr, void** ContainerAddr = nullptr); 78 | template 79 | StructType* GetPropertyAddress(const TSharedPtr& PropertyHandle, UObject* Outer = nullptr, void** ContainerAddr = nullptr, bool bEnsure = true) 80 | { 81 | FStructProperty* StructProperty = PropertyHandle.IsValid() ? CastField(PropertyHandle->GetProperty()) : nullptr; 82 | if (!VerifyPropName(StructProperty)) 83 | { 84 | ensureAlways(!bEnsure); 85 | return nullptr; 86 | } 87 | return static_cast(GetPropertyAddress(PropertyHandle, Outer, ContainerAddr)); 88 | } 89 | 90 | // Get Property Member In Struct 91 | GENERICSTORAGES_API void* GetPropertyMemberPtr(const TSharedPtr& PropertyHandle, FName MemberName); 92 | 93 | template 94 | ValueType* GetPropertyMemberPtr(const TSharedPtr& PropertyHandle, FName MemberName, bool bEnsure = true) 95 | { 96 | FStructProperty* StructProperty = PropertyHandle.IsValid() ? CastField(PropertyHandle->GetProperty()) : nullptr; 97 | FProperty* MemberProerty = StructProperty ? FindFProperty(StructProperty->Struct, MemberName) : nullptr; 98 | if (!VerifyPropName(MemberProerty)) 99 | { 100 | ensureAlways(!bEnsure); 101 | return nullptr; 102 | } 103 | return static_cast(GetPropertyMemberPtr(PropertyHandle, MemberName)); 104 | } 105 | 106 | ////////////////////////////////////////////////////////////////////////// 107 | 108 | struct GENERICSTORAGES_API FDatatableTypePicker 109 | { 110 | public: 111 | FDatatableTypePicker(TSharedPtr RootHandle = nullptr); 112 | 113 | TSharedPtr MyWidget; 114 | TDelegate OnChanged; 115 | TArray RowStructs; 116 | TWeakObjectPtr ScriptStruct; 117 | FString FilterPath; 118 | bool bValidate = false; 119 | 120 | void Init(TSharedPtr RootHandle); 121 | 122 | TSharedRef MakeWidget(); 123 | TSharedRef MakePropertyWidget(TSharedPtr SoftHandle, bool bAllowClear = true); 124 | TSharedRef MakeDynamicPropertyWidget(TSharedPtr SoftHandle, bool bAllowClear = true); 125 | 126 | static TWeakObjectPtr FindTableType(UDataTable* Table); 127 | static TWeakObjectPtr FindTableType(TSoftObjectPtr Table); 128 | static bool UpdateTableType(UDataTable* Table); 129 | static bool UpdateTableType(TSoftObjectPtr Table); 130 | }; 131 | 132 | ////////////////////////////////////////////////////////////////////////// 133 | 134 | class GENERICSTORAGES_API FScopedPropertyTransaction 135 | { 136 | public: 137 | FScopedPropertyTransaction(const TSharedPtr& InPropertyHandle, 138 | const FText& SessionName = NSLOCTEXT("UnrealEditorUtils", "ScopedTransaction", "ScopedTransaction"), 139 | const TCHAR* TransactionContext = TEXT("UnrealEditorUtils")); 140 | ~FScopedPropertyTransaction(); 141 | 142 | protected: 143 | IPropertyHandle* const PropertyHandle; 144 | FScopedTransaction Scoped; 145 | }; 146 | 147 | GENERICSTORAGES_API void ShowNotification(const FText& Tip, bool bSucc = false, float FadeInDuration = 1.0f, float FadeOutDuration = 2.0f, float ExpireDuration = 3.0f); 148 | inline void ShowNotification(const FString& Tip, bool bSucc = false, float FadeInDuration = 1.0f, float FadeOutDuration = 2.0f, float ExpireDuration = 3.0f) 149 | { 150 | ShowNotification(FText::FromString(Tip), bSucc, FadeInDuration, FadeOutDuration, ExpireDuration); 151 | } 152 | GENERICSTORAGES_API bool UpdatePropertyViews(const TArray& Objects); 153 | GENERICSTORAGES_API void ReplaceViewedObjects(const TMap& OldToNewObjectMap); 154 | GENERICSTORAGES_API void RemoveDeletedObjects(TArray DeletedObjects); 155 | 156 | GENERICSTORAGES_API TArray EditorSyncScan(UClass* Type, const FString& Dir = TEXT("/Game")); 157 | GENERICSTORAGES_API bool EditorAsyncLoad(UClass* Type, const FString& Dir = TEXT("/Game"), bool bOnce = true); 158 | 159 | GENERICSTORAGES_API bool IdentifyPinValueOnProperty(UEdGraphPin* GraphPinObj, UObject* Obj, FProperty* Prop, bool bReset = false); 160 | 161 | GENERICSTORAGES_API bool ShouldUseStructReference(UEdGraphPin* TestPin); 162 | 163 | GENERICSTORAGES_API ISettingsModule* GetSettingsModule(); 164 | GENERICSTORAGES_API bool RegisterSettings(const FName& ContainerName, 165 | const FName& CategoryName, 166 | const FName& SectionName, 167 | const FText& DisplayText, 168 | const FText& DescriptionText, 169 | const TWeakObjectPtr& SettingsObject, 170 | ISettingsModule* InSettingsModule = nullptr); 171 | 172 | struct FConfigurationPos 173 | { 174 | FName SectionName; 175 | FName CategoryName; 176 | FName ContainerName; 177 | 178 | FConfigurationPos(FName InSectionName = NAME_None, FName InCategoryName = "ExtraConfiguration", FName InContainerName = "Project") 179 | : SectionName(InSectionName) 180 | , CategoryName(InCategoryName) 181 | , ContainerName(InContainerName) 182 | { 183 | } 184 | }; 185 | 186 | GENERICSTORAGES_API bool AddConfigurationOnProject(UObject* Obj, const FConfigurationPos& NameCfg = {}, bool bOnlyCDO = true, bool bOnlyNative = true, bool bAllowAbstract = false); 187 | GENERICSTORAGES_API bool ShouldEndPlayMap(); 188 | } // namespace UnrealEditorUtils 189 | #else 190 | namespace UnrealEditorUtils 191 | { 192 | struct FConfigurationPos 193 | { 194 | FName SectionName; 195 | FName CategoryName; 196 | FName ContainerName; 197 | 198 | FConfigurationPos(FName InSectionName = NAME_None, FName InCategoryName = "ExtraConfiguration", FName InContainerName = "Project") 199 | : SectionName(InSectionName) 200 | , CategoryName(InCategoryName) 201 | , ContainerName(InContainerName) 202 | { 203 | } 204 | }; 205 | 206 | template 207 | GENERICSTORAGES_API bool AddConfigurationOnProject(UObject* Obj, const T&, bool bOnlyCDO = true, bool bOnlyNative = true, bool bAllowAbstract = false) 208 | { 209 | return false; 210 | } 211 | FORCEINLINE bool ShouldEndPlayMap() 212 | { 213 | return false; 214 | } 215 | } // namespace UnrealEditorUtils 216 | #endif 217 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/GMPPropertyPath.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "UnrealCompatibility.h" 5 | #if UE_4_25_OR_LATER 6 | #include "UObject/UnrealType.h" 7 | #include "UObject/WeakFieldPtr.h" 8 | 9 | struct FGMPPropertyInfo 10 | { 11 | public: 12 | FGMPPropertyInfo() 13 | : Property() 14 | , ArrayIndex(INDEX_NONE) 15 | { 16 | } 17 | 18 | FGMPPropertyInfo(TWeakFieldPtr InProperty, int32 InArrayIndex = INDEX_NONE) 19 | : Property(InProperty) 20 | , ArrayIndex(InArrayIndex) 21 | { 22 | } 23 | 24 | bool operator==(const FGMPPropertyInfo& Other) const { return Property == Other.Property && ArrayIndex == Other.ArrayIndex; } 25 | 26 | bool operator!=(const FGMPPropertyInfo& Other) const { return !(*this == Other); } 27 | 28 | TWeakFieldPtr Property; 29 | int32 ArrayIndex; 30 | }; 31 | 32 | class FGMPPropertyPath 33 | { 34 | public: 35 | static TSharedRef CreateEmpty() { return MakeShareable(new FGMPPropertyPath()); } 36 | 37 | static TSharedRef Create(const TWeakFieldPtr Property) 38 | { 39 | TSharedRef NewPath = MakeShareable(new FGMPPropertyPath()); 40 | 41 | FGMPPropertyInfo NewPropInfo; 42 | NewPropInfo.Property = Property; 43 | NewPropInfo.ArrayIndex = INDEX_NONE; 44 | 45 | NewPath->Properties.Add(NewPropInfo); 46 | 47 | return NewPath; 48 | } 49 | 50 | int32 GetNumProperties() const { return Properties.Num(); } 51 | 52 | const FGMPPropertyInfo& GetPropertyInfo(int32 index) const { return Properties[index]; } 53 | 54 | const FGMPPropertyInfo& GetLeafMostProperty() const { return Properties[Properties.Num() - 1]; } 55 | 56 | const FGMPPropertyInfo& GetRootProperty() const { return Properties[0]; } 57 | 58 | TSharedRef ExtendPath(const FGMPPropertyInfo& NewLeaf) 59 | { 60 | TSharedRef NewPath = MakeShareable(new FGMPPropertyPath()); 61 | 62 | NewPath->Properties = Properties; 63 | NewPath->Properties.Add(NewLeaf); 64 | 65 | return NewPath; 66 | } 67 | 68 | TSharedRef ExtendPath(const TSharedRef& Extension) 69 | { 70 | TSharedRef NewPath = MakeShareable(new FGMPPropertyPath()); 71 | 72 | NewPath->Properties = Properties; 73 | 74 | for (int Index = Extension->GetNumProperties() - 1; Index >= 0; Index--) 75 | { 76 | NewPath->Properties.Add(Extension->GetPropertyInfo(Index)); 77 | } 78 | 79 | return NewPath; 80 | } 81 | 82 | TSharedRef TrimPath(const int32 AmountToTrim) 83 | { 84 | TSharedRef NewPath = MakeShareable(new FGMPPropertyPath()); 85 | 86 | NewPath->Properties = Properties; 87 | 88 | for (int Count = 0; Count < AmountToTrim; Count++) 89 | { 90 | NewPath->Properties.Pop(); 91 | } 92 | 93 | return NewPath; 94 | } 95 | 96 | TSharedRef TrimRoot(const int32 AmountToTrim) 97 | { 98 | TSharedRef NewPath = CreateEmpty(); 99 | 100 | for (int Count = AmountToTrim; Count < Properties.Num(); Count++) 101 | { 102 | NewPath->Properties.Add(Properties[Count]); 103 | } 104 | 105 | return NewPath; 106 | } 107 | 108 | FString ToString(const TCHAR* Separator = TEXT("->")) const 109 | { 110 | FString NewDisplayName; 111 | bool FirstAddition = true; 112 | for (int PropertyIndex = 0; PropertyIndex < Properties.Num(); PropertyIndex++) 113 | { 114 | const FGMPPropertyInfo& PropInfo = Properties[PropertyIndex]; 115 | if (!(PropInfo.Property->IsA(FArrayProperty::StaticClass()) && PropertyIndex != Properties.Num() - 1)) 116 | { 117 | if (!FirstAddition) 118 | { 119 | NewDisplayName += Separator; 120 | } 121 | 122 | NewDisplayName += PropInfo.Property->GetFName().ToString(); 123 | 124 | if (PropInfo.ArrayIndex != INDEX_NONE) 125 | { 126 | NewDisplayName += FString::Printf(TEXT("[%d]"), PropInfo.ArrayIndex); 127 | } 128 | 129 | FirstAddition = false; 130 | } 131 | } 132 | 133 | return NewDisplayName; 134 | } 135 | 136 | /** 137 | * Add another property to be associated with this path 138 | */ 139 | void AddProperty(const FGMPPropertyInfo& InProperty) { Properties.Add(InProperty); } 140 | 141 | static bool AreEqual(const TSharedRef& PathLhs, const TSharedRef& PathRhs) 142 | { 143 | bool Result = false; 144 | 145 | if (PathLhs->GetNumProperties() == PathRhs->GetNumProperties()) 146 | { 147 | bool FoundMatch = true; 148 | for (int Index = PathLhs->GetNumProperties() - 1; Index >= 0; --Index) 149 | { 150 | const FGMPPropertyInfo& LhsPropInfo = PathLhs->GetPropertyInfo(Index); 151 | const FGMPPropertyInfo& RhsPropInfo = PathRhs->GetPropertyInfo(Index); 152 | 153 | if (LhsPropInfo.Property != RhsPropInfo.Property || LhsPropInfo.ArrayIndex != RhsPropInfo.ArrayIndex) 154 | { 155 | FoundMatch = false; 156 | break; 157 | } 158 | } 159 | 160 | if (FoundMatch) 161 | { 162 | Result = true; 163 | } 164 | } 165 | 166 | return Result; 167 | } 168 | 169 | private: 170 | TArray Properties; 171 | }; 172 | 173 | FORCEINLINE bool operator==(const FGMPPropertyPath& LHS, const FGMPPropertyPath& RHS) 174 | { 175 | if (LHS.GetNumProperties() != RHS.GetNumProperties()) 176 | { 177 | return false; 178 | } 179 | 180 | for (int32 i = 0, end = RHS.GetNumProperties(); i != end; ++i) 181 | { 182 | if (LHS.GetPropertyInfo(i) != RHS.GetPropertyInfo(i)) 183 | { 184 | return false; 185 | } 186 | } 187 | 188 | return true; 189 | } 190 | 191 | FORCEINLINE bool operator!=(const FGMPPropertyPath& LHS, const FGMPPropertyPath& RHS) 192 | { 193 | return !(LHS == RHS); 194 | } 195 | 196 | FORCEINLINE uint32 GetTypeHash(FGMPPropertyPath const& Path) 197 | { 198 | //lets concat the name and just hash the string 199 | uint32 Ret = 0; 200 | for (int32 i = 0, end = Path.GetNumProperties(); i != end; ++i) 201 | { 202 | if (Path.GetPropertyInfo(i).Property.IsValid()) 203 | { 204 | Ret = Ret ^ GetTypeHash(Path.GetPropertyInfo(i).Property->GetFName()); 205 | } 206 | } 207 | return Ret; 208 | } 209 | #endif 210 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/GenericStorages.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ClassDataStorage.h" 4 | #include "ComponentPattern.h" 5 | #include "DeferredComponentRegistry.h" 6 | #include "GenericSingletons.h" 7 | #include "GenericSystems.h" 8 | #include "MIO.h" 9 | #include "MemberDataRegistry.h" 10 | #include "ObjectDataRegistry.h" 11 | #include "ObjectPattern.h" 12 | #include "WorldLocalStorages.h" 13 | #include "DataTablePicker.h" 14 | #include "ComponentPicker.h" 15 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/GenericStoragesLog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | GENERICSTORAGES_API DECLARE_LOG_CATEGORY_EXTERN(LogGenericStorages, Log, All); 6 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/GenericSystems.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "Engine/DataTable.h" 8 | #include "Engine/EngineTypes.h" 9 | #include "GameFramework/Info.h" 10 | #include "GenericSingletons.h" 11 | #include "Misc/MessageDialog.h" 12 | #include "Templates/SubclassOf.h" 13 | #include "UObject/WeakObjectPtr.h" 14 | #include "UObject/WeakObjectPtrTemplates.h" 15 | 16 | #include "GenericSystems.generated.h" 17 | 18 | class UActorComponent; 19 | class AGenericSystemBase; 20 | 21 | UENUM(BlueprintType, meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = true)) 22 | enum class EDeferredFlag : uint8 23 | { 24 | None UMETA(Hidden), 25 | CreateOnServer = 0x1, 26 | CreateOnClient = 0x2, 27 | SetReplicated = 0x4, 28 | SetNameStable = 0x8 UMETA(Hidden), 29 | }; 30 | 31 | USTRUCT(BlueprintType) 32 | struct GENERICSTORAGES_API FSystemDeferredCompoent 33 | { 34 | GENERATED_BODY() 35 | public: 36 | UPROPERTY(EditAnywhere, Category = "SystemDependcy", meta = (AllowAbstract = "true", AllowNone = "false")) 37 | TSubclassOf ActorClass; 38 | 39 | UPROPERTY(EditAnywhere, Category = "SystemDependcy") 40 | TSubclassOf DeferredComponent; 41 | 42 | UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "SystemDependcy", meta = (Bitmask, BitmaskEnum = "/Script/GenericStorages.EDeferredFlag")) 43 | uint8 DeferredFlag = 0x3; 44 | 45 | bool operator==(const FSystemDeferredCompoent& Other) const { return ActorClass == Other.ActorClass && DeferredComponent == Other.DeferredComponent; } 46 | }; 47 | 48 | USTRUCT(BlueprintType, BlueprintInternalUseOnly) 49 | struct GENERICSTORAGES_API FGenericSystemConfig 50 | { 51 | GENERATED_BODY() 52 | public: 53 | UPROPERTY(EditAnywhere, Category = "GenericSystems") 54 | TSubclassOf SystemClass; 55 | 56 | TWeakObjectPtr SystemIns; 57 | 58 | bool operator==(const FGenericSystemConfig& rhs) const; 59 | bool operator==(const UClass* rhs) const; 60 | }; 61 | 62 | UCLASS(Transient, hidedropdown, hideCategories = (ActorTick, Rendering, Replication, Collision, Input, LOD, Cooking)) 63 | class GENERICSTORAGES_API AGenericSystemMgr : public AActor 64 | { 65 | GENERATED_BODY() 66 | public: 67 | static AGenericSystemMgr* Get(class ULevel* Level, bool bCreate = true); 68 | AGenericSystemMgr(); 69 | 70 | #if WITH_EDITOR 71 | void AddSystemInstance(AGenericSystemBase* Ins); 72 | void DelSystemInstance(AGenericSystemBase* Ins); 73 | #endif 74 | 75 | protected: 76 | UPROPERTY(EditInstanceOnly, Category = "GenericSystems", meta = (ShowOnlyInnerProperties, NoElementDuplicate)) 77 | TArray SystemSettings; 78 | 79 | virtual bool IsEditorOnly() const override { return true; } 80 | #if WITH_EDITOR 81 | virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; 82 | virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) override; 83 | 84 | UFUNCTION(CallInEditor, Category = "GenericSystems") 85 | void Refresh(); 86 | void RefreshImpl(uint32 ChangeType, bool bNotify = false); 87 | 88 | UFUNCTION(CallInEditor, Category = "GenericSystems") 89 | void ClearUseless(); 90 | 91 | virtual void PostLoad() override; 92 | virtual void PostActorCreated() override; 93 | #endif 94 | }; 95 | 96 | UCLASS(Abstract, hideCategories = (ActorTick, Rendering, Collision, Input, LOD, Cooking)) 97 | class GENERICSTORAGES_API AGenericSystemBase : public AInfo 98 | { 99 | GENERATED_BODY() 100 | 101 | public: 102 | AGenericSystemBase(); 103 | 104 | protected: 105 | enum class ESystemSource : uint8 106 | { 107 | LevelLoad, 108 | Duplicate, 109 | DynamicSpawn, 110 | }; 111 | 112 | virtual void PostDuplicate(bool bDuplicateForPIE) override; 113 | virtual void PostLoad() override; 114 | virtual void PostActorCreated() override; 115 | virtual void PostInitProperties() override; 116 | virtual bool IsNameStableForNetworking() const override; 117 | virtual void Destroyed() override; 118 | 119 | protected: 120 | virtual void PostRegistered() {} 121 | virtual void RegisterToWorld(ESystemSource Src); 122 | 123 | UPROPERTY(EditAnywhere, Category = "GenericSystems", meta = (ShowOnlyInnerProperties)) 124 | TArray DeferredComponents; 125 | }; 126 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/MIO.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreTypes.h" 4 | 5 | #include "Math/NumericLimits.h" 6 | #include "Templates/UniquePtr.h" 7 | #include "Templates/Function.h" 8 | #include "Containers/ContainersFwd.h" 9 | 10 | namespace MIO 11 | { 12 | template 13 | class IMappedFileRegion 14 | { 15 | public: 16 | static_assert(sizeof(ByteT) == sizeof(char), "err"); 17 | 18 | virtual ~IMappedFileRegion() {} 19 | virtual ByteT* GetMappedPtr() = 0; 20 | virtual int64 GetMappedSize() = 0; 21 | virtual FString& GetInfo() = 0; 22 | }; 23 | 24 | GENERICSTORAGES_API TUniquePtr> OpenMappedWrite(const TCHAR* Filename, int64 Offset = 0, int64 BytesToMap = MAX_int64, bool bPreloadHint = false); 25 | GENERICSTORAGES_API TUniquePtr> OpenMappedRead(const TCHAR* Filename, int64 Offset = 0, int64 BytesToMap = 0, bool bPreloadHint = false); 26 | GENERICSTORAGES_API bool ChunkingFile(const TCHAR* Filename, TArray64& Buffer, const TFunctionRef&)>& Lambda); 27 | GENERICSTORAGES_API FString ConvertToAbsolutePath(FString InOutPath); 28 | GENERICSTORAGES_API int32 ReadLines(const TCHAR* Filename, const TFunctionRef&)>& Lambda, char Dim = '\n'); 29 | GENERICSTORAGES_API int32 WriteLines(const TCHAR* Filename, const TArray>& Lines, char Dim = '\n'); 30 | 31 | inline bool ChunkingFile(const TCHAR* Filename, const TFunctionRef&)>& Lambda, int32 InSize = 2048) 32 | { 33 | TArray64 Buffer; 34 | Buffer.SetNumUninitialized(InSize); 35 | return ChunkingFile(Filename, Buffer, Lambda); 36 | } 37 | 38 | class GENERICSTORAGES_API FMappedBuffer 39 | { 40 | public: 41 | FMappedBuffer(FGuid InId, uint32 InCapacity, const TCHAR* SubDir = nullptr); 42 | 43 | bool IsValid() const; 44 | bool IsEmpty() const { return ReadIdx == WriteIdx; } 45 | FORCEINLINE uint32 Num() const { return IsWrap() ? (GetRegionSize() - WriteIdx + ReadIdx) : (WriteIdx - ReadIdx); } 46 | FORCEINLINE uint32 Capacity() const { return GetRegionSize(); } 47 | uint32 GetBufferLength() const { return IsWrap() ? GetRegionSize() : GetRegionSize() - WriteIdx; } 48 | FString GetFilePath() { return Region ? Region->GetInfo() : TEXT(""); } 49 | 50 | public: 51 | uint32 ReadUntil(uint8 TestChar, TFunctionRef Op); 52 | uint32 ReadUntil(uint8 TestChar); 53 | 54 | FORCEINLINE const uint8& Peek(uint32 Index) const 55 | { 56 | if (Index >= Capacity()) 57 | { 58 | Index = Capacity() - 1; 59 | } 60 | return GetBuffer((ReadIdx + Index) % (Capacity() > 0 ? Capacity() : 1)); 61 | } 62 | FORCEINLINE const uint8& operator[](uint32 Index) const { return Peek(Index); } 63 | 64 | public: 65 | bool WillWrap(uint32 InSize) const; 66 | bool WillFull(uint32 InSize, bool bContinuous = false) const; 67 | uint8* Write(const void* Value, uint32 InSize, bool bContinuous = false); 68 | FORCEINLINE uint32 GetWirteIdx() const { return WriteIdx; } 69 | FORCEINLINE uint8* GetAddr(uint32 Idx = 0) const { return &GetBuffer(Idx); } 70 | 71 | protected: 72 | uint32 WriteImpl(uint32 InLen, const void* InBuf); 73 | bool IsWrap() const { return WriteIdx < ReadIdx; } 74 | uint8& GetBuffer(int32 Idx) const; 75 | uint32 GetRegionSize() const; 76 | uint8* GetPtr() const; 77 | TUniquePtr> Region; 78 | uint32 ReadIdx; 79 | uint32 WriteIdx; 80 | }; 81 | 82 | GENERICSTORAGES_API void* OpenLockHandle(const TCHAR* Path, FString& ErrorCategory); 83 | GENERICSTORAGES_API void CloseLockHandle(void* InHandle); 84 | 85 | struct FProcessLockIndex 86 | { 87 | int32 Index; 88 | int32 PIEIndex; 89 | FString AsSuffix(const FString& Prefix = TEXT("_")) const 90 | { 91 | if (!Index) 92 | return TEXT(""); 93 | return Prefix + LexToString(Index); 94 | } 95 | }; 96 | GENERICSTORAGES_API int32 GetProcessUniqueIndex(); 97 | GENERICSTORAGES_API TSharedPtr GetGlobalSystemIndexHandle(const TCHAR* Key, int32 MaxTries = 1024); 98 | GENERICSTORAGES_API FProcessLockIndex* GetGameInstanceIndexHandle(const UObject* InCtx, const TCHAR* Key = nullptr, int32 MaxTries = 1024); 99 | } // namespace MIO 100 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/MemberDataRegistry.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "WorldLocalStorages.h" 8 | 9 | struct GENERICSTORAGES_API FWeakMemberDataTag 10 | { 11 | #if WITH_EDITOR 12 | protected: 13 | FWeakObjectPtr Outer; 14 | 15 | public: 16 | UObject* GetOuter() const { return Outer.Get(); } 17 | #endif 18 | 19 | public: 20 | FWeakMemberDataTag(); 21 | }; 22 | 23 | ////////////////////////////////////////////////////////////////////////// 24 | struct GENERICSTORAGES_API FWeakMemberData 25 | { 26 | protected: 27 | TWeakObjectPtr Obj; 28 | void* Ptr = nullptr; 29 | #if WITH_EDITOR 30 | FStructProperty* Prop = nullptr; 31 | #endif 32 | bool IsValid() const { return (Obj.IsValid() && Ptr); } 33 | }; 34 | 35 | template 36 | struct TWeakMemberData : public FWeakMemberData 37 | { 38 | protected: 39 | friend struct FMemberDataRegistry; 40 | static_assert(TIsDerivedFrom::IsDerived, "err"); 41 | 42 | T* GetMemberPtr() const 43 | { 44 | #if WITH_EDITOR 45 | checkSlow(!Prop || (Prop->Struct && Prop->Struct->IsA())); 46 | auto Ret = ensure(FWeakMemberData::IsValid()) ? Prop->ContainerPtrToValuePtr(Obj.Get()) : nullptr; 47 | ensure(!Ret || Ret == Ptr); 48 | return Ret; 49 | #else 50 | return IsValid() ? reinterpret_cast(Ptr) : nullptr; 51 | #endif 52 | } 53 | 54 | #if WITH_EDITOR 55 | template 56 | static FStructProperty* FindStructProperty(FName PropName) 57 | { 58 | FStructProperty* Prop = FindFieldChecked(C::StaticClass(), PropName); 59 | checkSlow(Prop->Struct == T::StaticStruct()); 60 | return Prop; 61 | } 62 | #endif 63 | 64 | static T* GetStorage(const UObject* WorldContextObj) { return WorldLocalStorages::GetLocalValue>(WorldContextObj, false); } 65 | 66 | static T& GetStorage(T& Default, const UObject* WorldContextObj) 67 | { 68 | auto* Data = GetStorage(WorldContextObj); 69 | return Data ? *Data : Default; 70 | } 71 | 72 | template>::value>* = nullptr> 73 | static bool RegisterStorage(C* This, T(C::*Data), FName DataName) 74 | { 75 | #if WITH_EDITOR 76 | static FName TypeMemberName = DataName; 77 | ensure(TypeMemberName == DataName); 78 | static auto Prop = TWeakMemberData::template FindStructProperty(DataName); 79 | check(This && Prop); 80 | checkSlow(T::StaticStruct() == Prop->Struct); 81 | checkSlow(C::StaticClass() == Prop->GetOuter()); 82 | #endif 83 | if (!This->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject) && ensure(C::StaticClass() == This->GetClass())) 84 | { 85 | auto& WeakStore = WorldLocalStorages::GetLocalValue>(This); 86 | WeakStore.Obj = This; 87 | WeakStore.Ptr = &(This->*Data); 88 | #if WITH_EDITOR 89 | WeakStore.Prop = Prop; 90 | ensureAlways(WeakStore.GetMemberPtr()->GetOuter() == This); 91 | #endif 92 | return true; 93 | } 94 | return false; 95 | } 96 | }; 97 | 98 | struct FMemberDataRegistry 99 | { 100 | template 101 | static T* GetStorage(const UObject* WorldContextObj) 102 | { 103 | return TWeakMemberData::GetStorage(WorldContextObj); 104 | } 105 | 106 | template 107 | static T& GetStorage(T& Default, const UObject* WorldContextObj) 108 | { 109 | return TWeakMemberData::GetStorage(Default, WorldContextObj); 110 | } 111 | 112 | template 113 | static bool RegisterStorage(C* This, T(C::*Data), FName DataName) 114 | { 115 | return TWeakMemberData::RegisterStorage(This, Data, DataName); 116 | } 117 | }; 118 | 119 | #define MEMBER_DATA_REGISTER(Class, Member) FMemberDataRegistry::RegisterStorage(this, &Class::Member, GET_MEMBER_NAME_CHECKED(Class, Member), true) 120 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/ObjectDataRegistry.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "UObject/Object.h" 8 | 9 | #include "ObjectDataRegistry.generated.h" 10 | 11 | namespace ObjectDataRegistry 12 | { 13 | template 14 | struct TObjectDataTypeName 15 | { 16 | static auto GetFName() { return T::StaticStruct()->GetFName(); } 17 | template 18 | static TSharedPtr Create(TArgs&&... Args) 19 | { 20 | using DT = TDecay; 21 | return TSharedPtr(new DT(Forward(Args)...), [](void* Ptr) { delete static_cast(Ptr); }); 22 | } 23 | }; 24 | } // namespace ObjectDataRegistry 25 | 26 | #define OBJECT_DATA_DEF(T) \ 27 | namespace ObjectDataRegistry \ 28 | { \ 29 | template<> \ 30 | struct TObjectDataTypeName \ 31 | { \ 32 | static auto GetFName() { return TEXT(#T); } \ 33 | template \ 34 | static TSharedPtr Create(TArgs&&... Args) \ 35 | { \ 36 | using DT = TDecay; \ 37 | return TSharedPtr(new DT(Forward(Args)...), [](void* Ptr) { delete static_cast(Ptr); }); \ 38 | } \ 39 | }; \ 40 | } 41 | 42 | // currently it does not support the object refs in ustruct. use weakobjectptr instead! 43 | struct FObjectDataRegistry 44 | { 45 | public: 46 | template 47 | static T* FindStorageData(const UObject* Obj) 48 | { 49 | check(IsValid(Obj)); 50 | return (T*)FindDataPtr(Obj, ObjectDataRegistry::TObjectDataTypeName::GetFName()); 51 | } 52 | 53 | template 54 | static T* GetStorageData(const UObject* Obj, TArgs&&... Args) 55 | { 56 | check(IsValid(Obj)); 57 | return (T*)GetDataPtr(Obj, ObjectDataRegistry::TObjectDataTypeName::GetFName(), ObjectDataRegistry::TObjectDataTypeName::Create(Forward(Args)...)); 58 | } 59 | 60 | template 61 | static bool RemoveStorageData(UObject* Obj) 62 | { 63 | check(IsValid(Obj)); 64 | return DelDataPtr(Obj, ObjectDataRegistry::TObjectDataTypeName::GetFName()); 65 | } 66 | 67 | protected: 68 | friend class UObjectDataRegistryHelper; 69 | GENERICSTORAGES_API static void* GetDataPtr(const UObject* Obj, FName Key, const TFunctionRef()>& Func); 70 | GENERICSTORAGES_API static void* FindDataPtr(const UObject* Obj, FName Key); 71 | GENERICSTORAGES_API static bool DelDataPtr(const UObject* Obj, FName Key); 72 | }; 73 | 74 | // For Blueprint 75 | UCLASS() 76 | class UObjectDataRegistryHelper final : public UBlueprintFunctionLibrary 77 | { 78 | GENERATED_BODY() 79 | 80 | protected: 81 | UFUNCTION(BlueprintCallable, Category = "ObjectDataRegistryHelper", CustomThunk, meta = (CallableWithoutWorldContext, DefaultToSelf = "KeObj", CustomStructureParam = "Data", bWriteData = true)) 82 | static void GetObjectData(const UObject* KeyObj, bool bWriteData, bool& bSucc, UPARAM(Ref) int32& Data); 83 | DECLARE_FUNCTION(execGetObjectData); 84 | UFUNCTION(BlueprintCallable, Category = "ObjectDataRegistryHelper", CustomThunk, meta = (CallableWithoutWorldContext, DefaultToSelf = "KeObj", CustomStructureParam = "Data")) 85 | static void DelObjectData(const UObject* KeyObj, UPARAM(Ref) int32& Data); 86 | DECLARE_FUNCTION(execDelObjectData); 87 | 88 | UFUNCTION(BlueprintCallable, Category = "ObjectDataRegistryHelper", meta = (CallableWithoutWorldContext, DefaultToSelf = "KeObj")) 89 | static void DeleteObjectDataByName(const UObject* KeyObj, FName Name); 90 | 91 | private: 92 | UFUNCTION() 93 | void OnActorDestroyed(class AActor* InActor); 94 | }; 95 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Public/ObjectPattern.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "Engine/EngineTypes.h" 8 | #include "Templates/SubclassOf.h" 9 | 10 | #include "ObjectPattern.generated.h" 11 | 12 | template 13 | struct TEachObjectPattern; 14 | 15 | USTRUCT() 16 | struct GENERICSTORAGES_API FObjectPatternType 17 | { 18 | GENERATED_BODY() 19 | public: 20 | using FWeakObjectArray = TArray; 21 | TSharedPtr Objects; 22 | bool IsValid() const { return Objects.IsValid(); } 23 | UObject* FirstObject() const 24 | { 25 | check(IsValid()); 26 | return Objects->Num() > 0 ? (*Objects)[0].Get() : nullptr; 27 | } 28 | 29 | void Add(UObject* Obj) { Objects->Add(Obj); } 30 | void Remove(UObject* Obj) { Objects->Remove(Obj); } 31 | auto Find(UObject* Obj) { return Objects->Find(FWeakObjectPtr(Obj)); } 32 | 33 | FWeakObjectArray::TIterator CreateIterator(); 34 | }; 35 | 36 | ////////////////////////////////////////////////////////////////////////// 37 | 38 | UCLASS(Transient, meta = (NeuronAction)) 39 | class GENERICSTORAGES_API UObjectPattern : public UBlueprintFunctionLibrary 40 | { 41 | GENERATED_BODY() 42 | protected: 43 | UObjectPattern(); 44 | static UObjectPattern* Get(const UObject* Obj); 45 | 46 | static UClass* FindFirstNativeClass(UClass* Class); 47 | 48 | public: 49 | UFUNCTION(meta = (DisplayName = "GetObjects", WorldContext = "WorldContextObj", HidePin = "WorldContextObj", DeterminesOutputType = "Class", DynamicOutputParam)) 50 | static TArray AllObject(const UObject* WorldContextObj, UClass* Class); 51 | 52 | public: 53 | template 54 | static void EachObject(const UObject* WorldContextObj, const F& f); 55 | 56 | static void EachObject(const UObject* WorldContextObj, UClass* Class, const TFunctionRef& f); 57 | 58 | DECLARE_DYNAMIC_DELEGATE_OneParam(FOnEachObjectAction, UObject*, Obj); 59 | UFUNCTION(BlueprintCallable, BlueprintInternalUseOnly, Category = "Game", meta = (NeuronAction, DisplayName = "EachObject", WorldContext = "WorldContextObj", HidePin = "WorldContextObj")) 60 | static void EachObject(const UObject* WorldContextObj, UClass* Class, UPARAM(meta = (DeterminesOutputType = "Class", DynamicOutputParam = "Obj")) FOnEachObjectAction OnEachObj) 61 | { 62 | if (ensure(Class)) 63 | { 64 | UObjectPattern::EachObject(WorldContextObj, Class, [&](auto a) { OnEachObj.ExecuteIfBound(a); }); 65 | } 66 | } 67 | template 68 | static T* GetObject(const UObject* WorldContextObj) 69 | { 70 | static_assert(TIsDerivedFrom::IsDerived && !TIsSame::Value, "err"); 71 | if (!EditorIsGameWorld(WorldContextObj)) 72 | return nullptr; 73 | 74 | #if WITH_EDITOR 75 | if (auto Object = static_cast(GetObject(WorldContextObj, T::StaticClass()))) 76 | { 77 | ensure(GIsEditor || TypeObject == Object); 78 | return Object; 79 | } 80 | #else 81 | if (ensure(TypeObject.IsValid())) 82 | return TypeObject.Get(); 83 | #endif 84 | return nullptr; 85 | } 86 | 87 | public: 88 | #if WITH_EDITOR 89 | static bool EditorIsGameWorld(const UObject* WorldContextObj); 90 | #else 91 | static bool EditorIsGameWorld(const UObject* WorldContextObj) { return true; } 92 | #endif 93 | 94 | template 95 | static void SetObject(T* Obj) 96 | { 97 | if (!EditorIsGameWorld(Obj)) 98 | return; 99 | 100 | if (!Obj->HasAnyFlags(RF_ArchetypeObject)) 101 | { 102 | #if WITH_EDITOR 103 | static_assert(TIsDerivedFrom::IsDerived && !TIsSame::Value, "err"); 104 | check(IsValid(Obj)); 105 | check(Obj->IsA(T::StaticClass())); 106 | #if 0 107 | static_assert(std::is_final::value, "err"); 108 | check(FindFirstNativeClass(Obj->GetClass()) == T::StaticClass()); 109 | #endif 110 | #endif 111 | ensure(GIsEditor || !TypeObject.IsValid()); 112 | TypeObject = Obj; 113 | 114 | SetObject(Obj, T::StaticClass()); 115 | } 116 | } 117 | 118 | protected: 119 | friend class UComponentPattern; 120 | UFUNCTION(BlueprintCallable, Category = "Game", meta = (DisplayName = "GetObject", WorldContext = "WorldContextObj", HidePin = "WorldContextObj", DeterminesOutputType = "Class", DynamicOutputParam)) 121 | static UObject* GetObject(const UObject* WorldContextObj, UClass* Class); 122 | 123 | UFUNCTION(BlueprintCallable, meta = (DisplayName = "SetObject", WorldContext = "Object", HidePin = "StopClass"), Category = "Game") 124 | static void SetObject(UObject* Object, UClass* StopClass = nullptr); 125 | 126 | template 127 | static int32 GetTypeID() 128 | { 129 | #if WITH_EDITOR 130 | ensure(TypeID != 0 && GetTypeID(T::StaticClass()) == TypeID); 131 | #endif 132 | return TypeID; 133 | } 134 | 135 | static int32 GetTypeID(UClass* Class); 136 | 137 | template 138 | static auto NativeIterator() 139 | { 140 | auto Index = GetTypeID(); 141 | static_assert(TIsDerivedFrom>::IsDerived, "err"); 142 | static_assert(TIsDerivedFrom::IsDerived && !TIsSame::Value, "err"); 143 | check(Index); 144 | return NativeIterator(Index); 145 | } 146 | static FObjectPatternType::FWeakObjectArray::TIterator NativeIterator(int32 Index); 147 | 148 | ////////////////////////////////////////////////////////////////////////// 149 | template 150 | friend struct TEachObjectPattern; 151 | template 152 | friend struct TSingleObjectPattern; 153 | template 154 | static void Register(T* Obj) 155 | { 156 | #if WITH_EDITOR 157 | static_assert(TIsDerivedFrom::IsDerived && !TIsSame::Value, "err"); 158 | check(IsValid(Obj)); 159 | check(Obj->IsA(T::StaticClass())); 160 | if (Obj->HasAnyFlags(RF_Transactional)) 161 | return; 162 | #if 0 163 | static_assert(std::is_final::value, "err"); 164 | check(FindFirstNativeClass(Obj->GetClass()) == T::StaticClass()); 165 | #endif 166 | #endif 167 | 168 | if (Obj->HasAnyFlags(RF_ArchetypeObject | RF_DefaultSubObject)) 169 | { 170 | AddClassToRegistry(Obj, T::StaticClass(), TypeID); 171 | ensure(TypeID != 0); 172 | } 173 | else if (EditorIsGameWorld(Obj)) 174 | { 175 | if (auto Mgr = Get(Obj)) 176 | Mgr->AddObjectToRegistry(Obj, T::StaticClass()); 177 | } 178 | } 179 | 180 | template 181 | static void Unregister(T* Obj) 182 | { 183 | if (UObjectInitialized()) 184 | { 185 | #if WITH_EDITOR 186 | if (Obj->HasAnyFlags(RF_Transactional)) 187 | return; 188 | #endif 189 | if (Obj->HasAnyFlags(RF_ArchetypeObject | RF_DefaultSubObject)) 190 | { 191 | if (!Obj->GetClass()->IsNative()) 192 | RemoveClassFromRegistry(Obj, T::StaticClass()); 193 | } 194 | else if (EditorIsGameWorld(Obj)) 195 | { 196 | if (auto Mgr = Get(Obj)) 197 | Mgr->RemoveObjectFromRegistry(Obj, T::StaticClass()); 198 | } 199 | } 200 | } 201 | 202 | template 203 | static void UnsetObject(T* Obj) 204 | { 205 | if (!EditorIsGameWorld(Obj)) 206 | return; 207 | 208 | if (!Obj->HasAnyFlags(RF_ArchetypeObject)) 209 | { 210 | #if WITH_EDITOR 211 | static_assert(TIsDerivedFrom::IsDerived && !TIsSame::Value, "err"); 212 | check(Obj->IsA(T::StaticClass())); 213 | 214 | #if 0 215 | static_assert(std::is_final::value, "err"); 216 | check(FindFirstNativeClass(Obj->GetClass()) == T::StaticClass()); 217 | #endif 218 | if (GIsEditor) 219 | { 220 | if (auto Mgr = Get(Obj)) 221 | { 222 | auto& Ref = Mgr->TypeObjects.FindOrAdd(T::StaticClass()); 223 | ensure(Obj == Ref.Get()); 224 | Ref = nullptr; 225 | } 226 | } 227 | else 228 | #endif 229 | { 230 | ensure(Obj == TypeObject); 231 | TypeObject = nullptr; 232 | } 233 | } 234 | } 235 | 236 | private: 237 | void AddObjectToRegistry(UObject* Object, UClass* InNativeClass); 238 | void RemoveObjectFromRegistry(UObject* Object, UClass* InNativeClass); 239 | UPROPERTY() 240 | TMap Binddings; 241 | 242 | private: 243 | static bool AddClassToRegistry(UObject* Object, UClass* InNativeClass, int32& ID); 244 | static bool RemoveClassFromRegistry(UObject* Object, UClass* InNativeClass); 245 | 246 | static FCriticalSection Critical; 247 | class FCSLock423 final 248 | { 249 | public: 250 | FCSLock423(); 251 | ~FCSLock423(); 252 | }; 253 | 254 | template 255 | static int32 TypeID; 256 | 257 | TMap, FWeakObjectPtr> TypeObjects; 258 | template 259 | static TWeakObjectPtr TypeObject; 260 | }; 261 | 262 | template 263 | void UObjectPattern::EachObject(const UObject* WorldContextObj, const F& f) 264 | { 265 | if (!EditorIsGameWorld(WorldContextObj)) 266 | return; 267 | 268 | FCSLock423 Lock; 269 | 270 | #if WITH_EDITOR 271 | if (GIsEditor) 272 | { 273 | EachObject(WorldContextObj, T::StaticClass(), [&](auto a) { f(static_cast(a)); }); 274 | } 275 | else 276 | #endif 277 | { 278 | for (auto It = NativeIterator(); It;) 279 | { 280 | if (auto a = It->Get()) 281 | { 282 | f(static_cast(a)); 283 | ++It; 284 | } 285 | else 286 | { 287 | It.RemoveCurrent(); 288 | } 289 | } 290 | } 291 | } 292 | 293 | template 294 | int32 UObjectPattern::TypeID; 295 | template 296 | TWeakObjectPtr UObjectPattern::TypeObject; 297 | 298 | ////////////////////////////////////////////////////////////////////////// 299 | template 300 | struct TEachObjectPattern 301 | { 302 | protected: 303 | static auto Ctor(T* This) { return UObjectPattern::Register(This); } 304 | static auto Dtor(T* This) { return UObjectPattern::Unregister(This); } 305 | }; 306 | 307 | template 308 | struct TSingleObjectPattern 309 | { 310 | protected: 311 | static auto Ctor(T* This) { return UObjectPattern::SetObject(This); } 312 | static auto Dtor(T* This) 313 | { 314 | #if WITH_EDITOR 315 | return UObjectPattern::UnsetObject(This); 316 | #endif 317 | } 318 | }; 319 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Template/AttributeCompatibility.h: -------------------------------------------------------------------------------- 1 | // Copyright UnrealCompatibility, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #if !defined(ATTRIBUTECOMPATIBILITY_GUARD_H) 6 | #define ATTRIBUTECOMPATIBILITY_GUARD_H 7 | 8 | #include "Misc/Attribute.h" 9 | #include "UnrealCompatibility.h" 10 | 11 | #if !UE_4_20_OR_LATER 12 | template 13 | FORCEINLINE TAttribute MakeAttributeRaw(SourceType* InObject, T (SourceTypeOrBase::*InMethod)(PayloadTypes...), typename TDecay::Type... InputPayload) 14 | { 15 | return TAttribute::Create(TAttribute::FGetter::CreateRaw(InObject, InMethod, MoveTemp(InputPayload)...)); 16 | } 17 | template 18 | FORCEINLINE TAttribute MakeAttributeRaw(const SourceType* InObject, T (SourceTypeOrBase::*InMethod)(PayloadTypes...) const, typename TDecay::Type... InputPayload) 19 | { 20 | return TAttribute::Create(TAttribute::FGetter::CreateRaw(InObject, InMethod, MoveTemp(InputPayload)...)); 21 | } 22 | template 23 | FORCEINLINE TAttribute MakeAttributeSP(SourceType* InObject, T (SourceTypeOrBase::*InMethod)(PayloadTypes...), typename TDecay::Type... InputPayload) 24 | { 25 | return TAttribute::Create(TAttribute::FGetter::CreateSP(InObject, InMethod, MoveTemp(InputPayload)...)); 26 | } 27 | template 28 | FORCEINLINE TAttribute MakeAttributeSP(const SourceType* InObject, T (SourceTypeOrBase::*InMethod)(PayloadTypes...) const, typename TDecay::Type... InputPayload) 29 | { 30 | return TAttribute::Create(TAttribute::FGetter::CreateSP(InObject, InMethod, MoveTemp(InputPayload)...)); 31 | } 32 | template 33 | decltype(auto) MakeAttributeLambda(LambdaType&& InCallable, PayloadTypes&&... InputPayload) 34 | { 35 | typedef decltype(InCallable(DeclVal()...)) T; 36 | 37 | return TAttribute::Create(TAttribute::FGetter::CreateLambda(InCallable, Forward(InputPayload)...)); 38 | } 39 | #endif 40 | 41 | template 42 | inline auto MakeAttributeWeakLambda(const TSharedRef& InUserObject, LambdaType&& InCallable, PayloadTypes&&... InputPayload) 43 | { 44 | using T = decltype(InCallable(DeclVal()...)); 45 | return TAttribute::Create(CreateSPLambda(InUserObject, Forward(InCallable)), Forward(InputPayload)...); 46 | } 47 | 48 | template 49 | inline auto MakeAttributeWeakLambda(const UserObject* InUserObject, LambdaType&& InCallable, PayloadTypes&&... InputPayload) 50 | { 51 | using T = decltype(InCallable(DeclVal()...)); 52 | return TAttribute::Create(CreateWeakLambda(InUserObject, Forward(InCallable)), Forward(InputPayload)...); 53 | } 54 | 55 | #endif // !defined(ATTRIBUTECOMPATIBILITY_GUARD_H) 56 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Template/ComponentCompatibility.h: -------------------------------------------------------------------------------- 1 | // Copyright UnrealCompatibility, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #if !defined(UNREAL_COMPONENT_COMPATIBILITY_GUARD_H) 6 | #define UNREAL_COMPONENT_COMPATIBILITY_GUARD_H 7 | 8 | #include "Launch/Resources/Version.h" 9 | #include "PrivateFieldAccessor.h" 10 | #include "UObject/UnrealType.h" 11 | // 12 | #include "Components/ActorComponent.h" 13 | #include "GameFramework/Actor.h" 14 | 15 | #if UE_4_24_OR_LATER 16 | inline void SetIsReplicatedByDefault(UActorComponent* Comp, const bool bNewReplicates) 17 | { 18 | if (LIKELY(Comp->HasAnyFlags(RF_NeedInitialization))) 19 | { 20 | Comp->bReplicates = bNewReplicates; 21 | } 22 | else 23 | { 24 | ensureMsgf(false, TEXT("SetIsReplicatedByDefault should only be called during Component Construction. Class=%s"), *GetPathNameSafe(Comp->GetClass())); 25 | SetIsReplicated(bNewReplicates); 26 | } 27 | } 28 | 29 | inline void SetHidden(AActor* Actor, bool bInHidden) 30 | { 31 | Actor->bHidden = bInHidden; 32 | } 33 | 34 | inline void SetReplicatingMovement(AActor* Actor, bool bInReplicateMovement) 35 | { 36 | Actor->bReplicateMovement = bInReplicateMovement; 37 | } 38 | 39 | inline void SetCanBeDamaged(AActor* Actor, bool bInCanBeDamaged) 40 | { 41 | Actor->bCanBeDamaged = bInCanBeDamaged; 42 | } 43 | 44 | inline void SetRole(AActor* Actor, ENetRole InRole) 45 | { 46 | Actor->Role = InRole; 47 | } 48 | 49 | inline FRepMovement& GetReplicatedMovement_Mutable(AActor* Actor) 50 | { 51 | return Actor->ReplicatedMovement; 52 | } 53 | 54 | inline void SetReplicatedMovement(AActor* Actor, const FRepMovement& InReplicatedMovement) 55 | { 56 | GetReplicatedMovement_Mutable(Actor) = InReplicatedMovement; 57 | } 58 | 59 | inline void SetInstigator(AActor* Actor, APawn* InInstigator) 60 | { 61 | Actor->Instigator = InInstigator; 62 | } 63 | inline APawn* GetInstigator(const AActor* Actor) 64 | { 65 | return Actor->Instigator; 66 | } 67 | 68 | inline AController* GetInstigatorController(const AActor* Actor) 69 | { 70 | return Actor->Instigator ? Actor->Instigator->Controller : nullptr; 71 | } 72 | 73 | #else // NGINE_MINOR_VERSION >= 24 74 | 75 | inline void SetIsReplicatedByDefault(UActorComponent* Comp, const bool bNewReplicates) 76 | { 77 | struct UHookActorComponent : public UActorComponent 78 | { 79 | using UActorComponent::SetIsReplicatedByDefault; 80 | }; 81 | static_cast(Comp)->SetIsReplicatedByDefault(bNewReplicates); 82 | } 83 | 84 | inline void SetHidden(AActor* Actor, bool bInHidden) 85 | { 86 | Actor->SetHidden(bInHidden); 87 | } 88 | 89 | inline void SetReplicatingMovement(AActor* Actor, bool bInReplicateMovement) 90 | { 91 | Actor->SetReplicatingMovement(bInReplicateMovement); 92 | } 93 | 94 | inline void SetCanBeDamaged(AActor* Actor, bool bInCanBeDamaged) 95 | { 96 | Actor->SetCanBeDamaged(bInCanBeDamaged); 97 | } 98 | 99 | inline void SetRole(AActor* Actor, ENetRole InRole) 100 | { 101 | Actor->SetRole(InRole); 102 | } 103 | 104 | inline FRepMovement& GetReplicatedMovement_Mutable(AActor* Actor) 105 | { 106 | return Actor->GetReplicatedMovement_Mutable(); 107 | } 108 | 109 | inline void SetReplicatedMovement(AActor* Actor, const FRepMovement& InReplicatedMovement) 110 | { 111 | Actor->SetReplicatedMovement(InReplicatedMovement); 112 | } 113 | 114 | inline void SetInstigator(AActor* Actor, APawn* InInstigator) 115 | { 116 | Actor->SetInstigator(InInstigator); 117 | } 118 | inline APawn* GetInstigator(const AActor* Actor) 119 | { 120 | return Actor->GetInstigator(); 121 | } 122 | 123 | inline AController* GetInstigatorController(const AActor* Actor) 124 | { 125 | return Actor->GetInstigatorController(); 126 | } 127 | #endif 128 | 129 | #endif // !defined(UNREAL_COMPONENT_COMPATIBILITY_GUARD_H) 130 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Template/PrivateFieldAccessor.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | #define GS_PRIVATEACCESS_MEMBER(Class, Member, ...) \ 9 | namespace PrivateAccess \ 10 | { \ 11 | using Z_##MemberPtr##Class##Member##M##Type = __VA_ARGS__; \ 12 | using Z_##MemberPtr##Class##Member = Z_##MemberPtr##Class##Member##M##Type Class::*; \ 13 | template \ 14 | struct Z_Get##Class##Member \ 15 | { \ 16 | friend Z_##MemberPtr##Class##Member Access##Class##Member() { return MemPtr; } \ 17 | }; \ 18 | Z_##MemberPtr##Class##Member Access##Class##Member(); \ 19 | template struct Z_Get##Class##Member<&Class::Member>; \ 20 | auto& Member(const Class& Ref) { return const_cast(Ref).*Access##Class##Member(); } \ 21 | } 22 | 23 | #define GS_PRIVATEACCESS_FUNCTION(Class, FuncName, ...) \ 24 | namespace PrivateAccess \ 25 | { \ 26 | using Z_##FuncPtr##Class##FuncName##F##Type = __VA_ARGS__; \ 27 | using Z_##FuncPtr##Class##FuncName = Z_##FuncPtr##Class##FuncName##F##Type Class::*; \ 28 | template \ 29 | struct Z_Get##Class##FuncName \ 30 | { \ 31 | friend Z_##FuncPtr##Class##FuncName Access##Class##FuncName() { return MemPtr; } \ 32 | }; \ 33 | Z_##FuncPtr##Class##FuncName Access##Class##FuncName(); \ 34 | template struct Z_Get##Class##FuncName<&Class::FuncName>; \ 35 | template, Class>::value>* = nullptr, typename... Args> \ 36 | decltype(auto) FuncName(T&& Ref, Args&&... args) \ 37 | { \ 38 | return (std::forward(Ref).*Access##Class##FuncName())(std::forward(args)...); \ 39 | } \ 40 | } 41 | 42 | #define GS_PRIVATEACCESS_STATIC_MEMBER(Class, Member, ...) \ 43 | namespace PrivateAccessStatic \ 44 | { \ 45 | using ZZ_##MemberPtr##Class##Member##Type = __VA_ARGS__; \ 46 | using ZZ_##MemberPtr##Class##Member = ZZ_##MemberPtr##Class##Member##Type*; \ 47 | template \ 48 | struct ZZ_Get##Class##Member \ 49 | { \ 50 | friend ZZ_##MemberPtr##Class##Member Access##Class##Member() { return MemPtr; } \ 51 | }; \ 52 | ZZ_##MemberPtr##Class##Member Access##Class##Member(); \ 53 | template struct ZZ_Get##Class##Member<&Class::Member>; \ 54 | auto& Member() { return *Access##Class##Member(); } \ 55 | } 56 | 57 | #define GS_PRIVATEACCESS_STATIC_FUNCTION(Class, FuncName, ...) \ 58 | namespace PrivateAccessStatic \ 59 | { \ 60 | using ZZ_##FuncPtr##Class##FuncName##Type = __VA_ARGS__; \ 61 | using ZZ_##FuncPtr##Class##FuncName = ZZ_##FuncPtr##Class##FuncName##Type*; \ 62 | template \ 63 | struct ZZ_Get##Class##FuncName \ 64 | { \ 65 | friend ZZ_##FuncPtr##Class##FuncName Access##Class##FuncName() { return MemPtr; } \ 66 | }; \ 67 | ZZ_##FuncPtr##Class##FuncName Access##Class##FuncName(); \ 68 | template struct ZZ_Get##Class##FuncName<&Class::FuncName>; \ 69 | template \ 70 | decltype(auto) FuncName(Args&&... args) \ 71 | { \ 72 | return (*Access##Class##FuncName())(std::forward(args)...); \ 73 | } \ 74 | } 75 | 76 | #define GS_PRIVATEACCESS_FUNCTION_NAME(Class, FuncName, ...) \ 77 | GS_PRIVATEACCESS_FUNCTION(Class, FuncName, __VA_ARGS__) \ 78 | namespace PrivateAccess \ 79 | { \ 80 | namespace Class \ 81 | { \ 82 | constexpr auto FuncName = TEXT(#FuncName); \ 83 | } \ 84 | } 85 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Template/PropertyCompatibility.include: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #if !defined(UNREAL_COMPONENT_COMPATIBILITY_INL_GUARD_H) 3 | #define UNREAL_COMPONENT_COMPATIBILITY_INL_GUARD_H 4 | 5 | #include "Runtime/Launch/Resources/Version.h" 6 | 7 | #if UE_USE_UPROPERTY && !(ENGINE_MAJOR_VERSION > 4 || (ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 25)) 8 | #define DOREPLIFETIME_WITH_PARAMS_FAST DOREPLIFETIME_WITH_PARAMS 9 | #define DOREPLIFETIME_WITH_PARAMS_FAST_STATIC_ARRAY DOREPLIFETIME_WITH_PARAMS 10 | 11 | #define DOREPLIFETIME_ACTIVE_OVERRIDE_FAST DOREPLIFETIME_ACTIVE_OVERRIDE 12 | #define DOREPLIFETIME_ACTIVE_OVERRIDE_FAST_STATIC_ARRAY DOREPLIFETIME_ACTIVE_OVERRIDE 13 | 14 | #define RESET_REPLIFETIME_FAST RESET_REPLIFETIME 15 | #define RESET_REPLIFETIME_FAST_STATIC_ARRAY RESET_REPLIFETIME 16 | 17 | #define RESET_REPLIFETIME_CONDITION_FAST RESET_REPLIFETIME_CONDITION 18 | #define RESET_REPLIFETIME_CONDITION_FAST_STATIC_ARRAY RESET_REPLIFETIME_CONDITION 19 | 20 | using FFieldPropertyType = UObject; 21 | using FFieldClass = UClass; 22 | using FField = UField; 23 | 24 | using FProperty = UProperty; 25 | #define CASTCLASS_FProperty CASTCLASS_UProperty 26 | 27 | using FBoolProperty = UBoolProperty; 28 | #define CASTCLASS_FBoolProperty CASTCLASS_UBoolProperty 29 | 30 | using FNumericProperty = UNumericProperty; 31 | #define CASTCLASS_FNumericProperty CASTCLASS_UNumericProperty 32 | using FInt8Property = UInt8Property; 33 | #define CASTCLASS_FInt8Property CASTCLASS_UInt8Property 34 | using FByteProperty = UByteProperty; 35 | #define CASTCLASS_FByteProperty CASTCLASS_UByteProperty 36 | 37 | using FInt16Property = UInt16Property; 38 | #define CASTCLASS_FInt16Property CASTCLASS_UInt16Property 39 | using FUInt16Property = UUInt16Property; 40 | #define CASTCLASS_FUInt16Property CASTCLASS_UUInt16Property 41 | 42 | using FIntProperty = UIntProperty; 43 | #define CASTCLASS_FIntProperty CASTCLASS_UIntProperty 44 | using FUInt32Property = UUInt32Property; 45 | #define CASTCLASS_FUInt32Property CASTCLASS_UUInt32Property 46 | 47 | using FInt64Property = UInt64Property; 48 | #define CASTCLASS_FInt64Property CASTCLASS_UInt64Property 49 | using FUInt64Property = UUInt64Property; 50 | #define CASTCLASS_FUInt64Property CASTCLASS_UUInt64Property 51 | 52 | using FEnumProperty = UEnumProperty; 53 | #define CASTCLASS_FEnumProperty CASTCLASS_UEnumProperty 54 | 55 | using FFloatProperty = UFloatProperty; 56 | #define CASTCLASS_FFloatProperty CASTCLASS_UFloatProperty 57 | using FDoubleProperty = UDoubleProperty; 58 | #define CASTCLASS_FDoubleProperty CASTCLASS_UDoubleProperty 59 | 60 | using FStructProperty = UStructProperty; 61 | #define CASTCLASS_FStructProperty CASTCLASS_UStructProperty 62 | 63 | using FStrProperty = UStrProperty; 64 | #define CASTCLASS_FStrProperty CASTCLASS_UStrProperty 65 | using FNameProperty = UNameProperty; 66 | #define CASTCLASS_FNameProperty CASTCLASS_UNameProperty 67 | using FTextProperty = UTextProperty; 68 | #define CASTCLASS_FTextProperty CASTCLASS_UTextProperty 69 | 70 | using FArrayProperty = UArrayProperty; 71 | #define CASTCLASS_FArrayProperty CASTCLASS_UArrayProperty 72 | using FMapProperty = UMapProperty; 73 | #define CASTCLASS_FMapProperty CASTCLASS_UMapProperty 74 | using FSetProperty = USetProperty; 75 | #define CASTCLASS_FSetProperty CASTCLASS_USetProperty 76 | 77 | using FObjectPropertyBase = UObjectPropertyBase; 78 | #define CASTCLASS_FObjectPropertyBase CASTCLASS_UObjectPropertyBase 79 | using FObjectProperty = UObjectProperty; 80 | #define CASTCLASS_FObjectProperty CASTCLASS_UObjectProperty 81 | using FClassProperty = UClassProperty; 82 | #define CASTCLASS_FClassProperty CASTCLASS_UClassProperty 83 | using FWeakObjectProperty = UWeakObjectProperty; 84 | #define CASTCLASS_FWeakObjectProperty CASTCLASS_UWeakObjectProperty 85 | using FSoftObjectProperty = USoftObjectProperty; 86 | #define CASTCLASS_FSoftObjectProperty CASTCLASS_USoftObjectProperty 87 | using FSoftClassProperty = USoftClassProperty; 88 | #define CASTCLASS_FSoftClassProperty CASTCLASS_USoftClassProperty 89 | using FLazyObjectProperty = ULazyObjectProperty; 90 | #define CASTCLASS_FLazyObjectProperty CASTCLASS_ULazyObjectProperty 91 | using FInterfaceProperty = UInterfaceProperty; 92 | #define CASTCLASS_FInterfaceProperty CASTCLASS_UInterfaceProperty 93 | 94 | using FDelegateProperty = UDelegateProperty; 95 | #define CASTCLASS_FDelegateProperty CASTCLASS_UDelegateProperty 96 | using FMulticastDelegateProperty = UMulticastDelegateProperty; 97 | #define CASTCLASS_FMulticastDelegateProperty CASTCLASS_UMulticastDelegateProperty 98 | 99 | #define CASTCLASS_FMulticastInlineDelegateProperty CASTCLASS_UMulticastInlineDelegateProperty 100 | #define CASTCLASS_FMulticastSparseDelegateProperty CASTCLASS_UMulticastSparseDelegateProperty 101 | 102 | ////////////////////////////////////////////////////////////////////////// 103 | 104 | template 105 | FORCEINLINE auto CastField(From* Prop) 106 | { 107 | return Cast(Prop); 108 | } 109 | template 110 | FORCEINLINE auto CastFieldChecked(From* Prop) 111 | { 112 | return CastChecked(Prop); 113 | } 114 | 115 | template 116 | FORCEINLINE T* FindFProperty(const UStruct* Owner, FName FieldName) 117 | { 118 | return FindField(Owner, FieldName); 119 | } 120 | 121 | template 122 | FORCEINLINE T* FindUField(const UStruct* Owner, FName FieldName) 123 | { 124 | return FindField(Owner, FieldName); 125 | } 126 | 127 | template 128 | struct TFieldPath 129 | { 130 | public: 131 | TFieldPath(const T* InProp = nullptr) 132 | : Prop(const_cast(InProp)) 133 | { 134 | } 135 | TFieldPath(const T& InProp) 136 | : Prop(const_cast(&InProp)) 137 | { 138 | } 139 | TFieldPath(TYPE_OF_NULLPTR) 140 | : TFieldPath() 141 | { 142 | static_assert(TIsDerivedFrom::IsDerived, "err"); 143 | } 144 | 145 | void operator=(const T* InProp) { Prop = const_cast(InProp); } 146 | 147 | T* operator*() const { return Prop; } 148 | T* operator->() const { return Prop; } 149 | 150 | T* Get() const { return Prop; } 151 | 152 | inline bool IsUObject() const { return true; } 153 | inline bool IsValid() const { return !!Prop; } 154 | inline bool IsValidLowLevel() const { return Prop->IsValidLowLevel(); } 155 | explicit operator bool() const { return !!Prop; } 156 | 157 | bool IsA(const UClass* InClass) const { return Prop && Prop->IsA(InClass); } 158 | template 159 | bool IsA() const 160 | { 161 | static_assert(sizeof(U) > 0, "T must not be an incomplete type"); 162 | return IsA(U::StaticClass()); 163 | } 164 | 165 | FField* ToField() const { return Prop; } 166 | UObject* ToUObject() const { return Prop; } 167 | FORCEINLINE FField* ToFieldUnsafe() const { return Prop; } 168 | FORCEINLINE UObject* ToUObjectUnsafe() const { return Prop; } 169 | 170 | void* GetRawPointer() const { return Prop; } 171 | UClass* GetOwnerClass() const { return GetPropertyOwnerClass(Prop); } 172 | FString GetFullName() const { return Prop->GetFullName(); } 173 | FString GetPathName() const { return Prop->GetPathName(); } 174 | FString GetName() const { return Prop->GetName(); } 175 | FString GetClassName() const { return Prop->GetClassName(); } 176 | FName GetFName() const { return Prop->GetFName(); } 177 | bool IsNative() const { return Prop->IsNative(); } 178 | UPackage* GetOutermost() const { return Prop->GetOutermost(); } 179 | 180 | bool operator==(const TFieldPath& Other) const { return Prop == Other.Prop; } 181 | bool operator!=(const TFieldPath& Other) const { return Prop != Other.Prop; } 182 | 183 | friend uint32 GetTypeHash(const TFieldPath& InFieldpath) { return GetTypeHash(InFieldpath.Prop); } 184 | #if WITH_METADATA 185 | bool HasMetaData(const FName& Key) const { return Prop->HasMetaData(Key); } 186 | // FString GetMetaData(const FName& Key) const { return Prop->GetMetaData(Key); } 187 | #endif 188 | 189 | protected: 190 | mutable T* Prop; 191 | }; 192 | 193 | using FFieldVariant = TFieldPath<>; 194 | 195 | template 196 | using TFieldPathCompatible = T*; 197 | 198 | ////////////////////////////////////////////////////////////////////////// 199 | FORCEINLINE EClassCastFlags GetPropertyCastFlags(const FProperty* Prop) 200 | { 201 | return (EClassCastFlags)Prop->GetClass()->ClassCastFlags; 202 | } 203 | 204 | FORCEINLINE UObject* GetPropertyOwnerUObject(const FProperty* Prop) 205 | { 206 | return Prop->GetOuter(); 207 | } 208 | template 209 | FORCEINLINE T* GetPropertyOwnerUObject(const FProperty* Prop) 210 | { 211 | return Cast(Prop->GetOuter()); 212 | } 213 | template 214 | UClass* GetPropertyOwnerClass(const T* Prop) 215 | { 216 | return CastChecked(Prop->GetOuter()); 217 | } 218 | 219 | FORCEINLINE FString GetPropertyOwnerName(const FProperty* Prop) 220 | { 221 | return Prop->GetOuter()->GetName(); 222 | } 223 | #endif 224 | #endif // !defined(UNREAL_COMPONENT_COMPATIBILITY_INL_GUARD_H) 225 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Template/ProtectFieldAccessor.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericStorages, Inc. All Rights Reserved. 2 | #pragma once 3 | #include "CoreMinimal.h" 4 | #include "Runtime/Launch/Resources/Version.h" 5 | #include "MACRO_FOR_EACH.h" 6 | 7 | #include 8 | 9 | namespace transcribe 10 | { 11 | template 12 | using const_t = std::conditional_t::value, Dst const, Dst>; 13 | template 14 | using volatile_t = std::conditional_t::value, Dst volatile, Dst>; 15 | template 16 | using point_t = std::conditional_t::value, Dst*, Dst>; 17 | template 18 | using refernece_t = std::conditional_t::value, Dst*, Dst>; 19 | template 20 | using cv_t = const_t>; 21 | template 22 | using cvp_t = cv_t>; 23 | template 24 | using cvrp_t = refernece_t>; 25 | 26 | template 27 | T* ToRawPtr(T* Ptr) 28 | { 29 | return Ptr; 30 | } 31 | template 32 | auto ToRawPtr(const TSharedPtr& Ptr) 33 | { 34 | return Ptr.Get(); 35 | } 36 | template 37 | auto ToRawPtr(const TSharedRef& Ptr) 38 | { 39 | return &Ptr.Get(); 40 | } 41 | #if ENGINE_MAJOR_VERSION >= 5 42 | template 43 | auto ToRawPtr(const TObjectPtr& Ptr) 44 | { 45 | return Ptr.Get(); 46 | } 47 | #endif 48 | } // namespace transcribe 49 | 50 | #define Z_GS_USING_MEMBER_(Member) using Z_SuperType::Member 51 | #define Z_GS_USING_MEMBER(...) MACRO_FOR_EACH(Z_GS_USING_MEMBER_, ;, ##__VA_ARGS__) 52 | 53 | #define GS_DECLARE_PROTECT(Type, ...) \ 54 | struct Type##Friend : public Type \ 55 | { \ 56 | using Z_SuperType = Type; \ 57 | Z_GS_USING_MEMBER(__VA_ARGS__); \ 58 | }; 59 | 60 | #define GS_ACCESS_PROTECT(Inst, Type, ...) \ 61 | [](auto C) { \ 62 | using Z_InstType = decltype(C); \ 63 | using Z_DecayType = std::decay_t>; \ 64 | static_assert(std::is_base_of::value, "err"); \ 65 | struct Type##Friend : public Type \ 66 | { \ 67 | using Z_SuperType = std::common_type_t; \ 68 | Z_GS_USING_MEMBER(__VA_ARGS__); \ 69 | }; \ 70 | return static_cast>(C); \ 71 | }(transcribe::ToRawPtr(Inst)) 72 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Template/TypeTableBindding.h: -------------------------------------------------------------------------------- 1 | // Copyright GenericAbilities, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | #include "CoreMinimal.h" 5 | 6 | #include "Engine/DataTable.h" 7 | #include "UObject/WeakObjectPtrTemplates.h" 8 | 9 | #include "TypeTableBindding.generated.h" 10 | 11 | USTRUCT() 12 | struct FTypeTableConfig 13 | { 14 | GENERATED_BODY() 15 | public: 16 | // FindBy 17 | bool operator==(UClass* Class) const { return Class && Class == Type; } 18 | 19 | UPROPERTY(EditDefaultsOnly, Category = "TypeTableConfig") 20 | UClass* Type = nullptr; 21 | 22 | UPROPERTY(EditDefaultsOnly, Category = "TypeTableConfig") 23 | UDataTable* Table = nullptr; 24 | }; 25 | 26 | struct GENERICSTORAGES_API FTypeTableBindding 27 | { 28 | public: 29 | static UScriptStruct* FindType(UClass* Class); 30 | 31 | protected: 32 | static FTypeTableBindding& Get(); 33 | 34 | ////////////////////////////////////////////////////////////////////////// 35 | template 36 | static bool AddType(TSubclassOf Class) 37 | { 38 | static_assert(TIsDerivedFrom::IsDerived, "err"); 39 | if (ensure(Class)) 40 | { 41 | auto ClassName = Class->GetName(); 42 | if (!(ClassName.StartsWith(TEXT("SKEL_")) && ClassName.EndsWith(TEXT("_C")))) 43 | { 44 | auto& Value = Get().Binddings.FindOrAdd(Class->GetName()); 45 | auto SrciptStruct = T::StaticStruct(); 46 | if (!Value.IsValid() || Value.Get() == SrciptStruct) 47 | { 48 | Value = SrciptStruct; 49 | return true; 50 | } 51 | } 52 | } 53 | return false; 54 | } 55 | 56 | protected: 57 | friend class FTypeToTableCustomization; 58 | TMap> Binddings; 59 | }; 60 | 61 | struct FTableBinddingDeclaration 62 | { 63 | static UDataTable* GetTableFromType(UClass* Class); 64 | static FName GetRowName(UDataTable& Table, const TCHAR* Category, const TCHAR* SubCategory); 65 | }; 66 | 67 | template 68 | struct GENERICSTORAGES_API TTableBinddingDeclaration : public FTableBinddingDeclaration 69 | { 70 | protected: 71 | using FTableBinddingDeclaration::GetRowName; 72 | using FTableBinddingDeclaration::GetTableFromType; 73 | 74 | template 75 | static const T* FindTableRow(const UObject* TypeObject, const TCHAR* Category, const TCHAR* SubCategory) 76 | { 77 | check(TypeObject); 78 | if (auto Table = D::GetTableFromType(TypeObject->GetClass())) 79 | { 80 | auto RowName = D::GetRowName(*Table, Category, SubCategory); 81 | return Table->template FindRow(RowName, *TypeObject->GetName()); 82 | } 83 | return nullptr; 84 | } 85 | 86 | template 87 | static bool BindDeclaration(UObject* This) 88 | { 89 | #if WITH_EDITOR 90 | static auto FindFirstNativeClass = [](UClass* Class) { 91 | for (; Class; Class = Class->GetSuperClass()) 92 | { 93 | if (0 != (Class->ClassFlags & CLASS_Native)) 94 | { 95 | break; 96 | } 97 | } 98 | return Class; 99 | }; 100 | check(IsValid(This)); 101 | check(FindFirstNativeClass(This->GetClass()) == C::StaticClass()); 102 | return FTypeTableBindding::AddType(This->GetClass()); 103 | #else 104 | return true; 105 | #endif 106 | } 107 | }; 108 | 109 | ////////////////////////////////////////////////////////////////////////// 110 | #if 0 111 | // Decl Binddings 112 | template 113 | class TExecutionBaseBindding : public TableBinddingDeclaration 114 | { 115 | public: 116 | #if WITH_EDITOR 117 | TExecutionBaseBindding() { TableBinddingDeclaration::BindDeclaration(static_cast(this)); } 118 | #endif 119 | 120 | protected: 121 | const UDataTable* FindTable() const { return TableBinddingDeclaration::GetTableFromTypeImpl(static_cast(this)->GetClass()); } 122 | const T* FindRowData(const TCHAR* SubCategory = nullptr) const { return TableBinddingDeclaration::GetRowForExecution(static_cast(this), *static_cast(this)->GetClass()->GetName(), SubCategory); } 123 | }; 124 | 125 | // Decl Binddings 126 | template 127 | class TExecutionPhaseBindding : public TableBinddingDeclaration 128 | { 129 | public: 130 | #if WITH_EDITOR 131 | TExecutionPhaseBindding() { TableBinddingDeclaration::BindDeclaration(static_cast(this)); } 132 | #endif 133 | 134 | protected: 135 | const UDataTable* FindTable() const { return TableBinddingDeclaration::GetTableFromTypeImpl(static_cast(this)->GetClass()); } 136 | const T* FindRowData(const UGameplayEffectExecutionCalculation* ExectuionBase = nullptr) const 137 | { 138 | return TableBinddingDeclaration::GetRowForExecution(static_cast(this), ExectuionBase ? *ExectuionBase->GetClass()->GetName() : nullptr, *static_cast(this)->GetClass()->GetName()); 139 | } 140 | }; 141 | #endif 142 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Template/mio/detail/string_util.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 https://github.com/mandreyel 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 4 | * software and associated documentation files (the "Software"), to deal in the Software 5 | * without restriction, including without limitation the rights to use, copy, modify, 6 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 7 | * permit persons to whom the Software is furnished to do so, subject to the following 8 | * conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies 11 | * or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 14 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 15 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 16 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 17 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 18 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | */ 20 | 21 | #ifndef MIO_STRING_UTIL_HEADER 22 | #define MIO_STRING_UTIL_HEADER 23 | 24 | #include 25 | #include "Containers/StringConv.h" 26 | 27 | namespace mio { 28 | namespace detail { 29 | 30 | template< 31 | typename S, 32 | typename C = typename std::decay::type, 33 | typename = decltype(std::declval().data()), 34 | typename = typename std::enable_if< 35 | std::is_same::value 36 | || std::is_same::value 37 | >::type 38 | > struct char_type_helper { 39 | using type = typename C::value_type; 40 | }; 41 | 42 | template 43 | struct char_type { 44 | using type = typename char_type_helper::type; 45 | }; 46 | 47 | template<> 48 | struct char_type { 49 | using type = char; 50 | }; 51 | 52 | template<> 53 | struct char_type { 54 | using type = char; 55 | }; 56 | 57 | template 58 | struct char_type { 59 | using type = char; 60 | }; 61 | 62 | template 63 | struct char_type { 64 | using type = char; 65 | }; 66 | 67 | template<> 68 | struct char_type { 69 | using type = TCHAR; 70 | }; 71 | 72 | template<> 73 | struct char_type { 74 | using type = TCHAR; 75 | }; 76 | 77 | template 78 | struct char_type { 79 | using type = TCHAR; 80 | }; 81 | 82 | template 83 | struct char_type { 84 | using type = TCHAR; 85 | }; 86 | 87 | template 88 | struct is_c_str_helper 89 | { 90 | static constexpr bool value = std::is_same< 91 | CharT*, 92 | // TODO: I'm so sorry for this... Can this be made cleaner? 93 | typename std::add_pointer< 94 | typename std::remove_cv< 95 | typename std::remove_pointer< 96 | typename std::decay< 97 | S 98 | >::type 99 | >::type 100 | >::type 101 | >::type 102 | >::value; 103 | }; 104 | 105 | template 106 | struct is_c_str 107 | { 108 | static constexpr bool value = is_c_str_helper::value; 109 | }; 110 | 111 | template 112 | struct is_c_wstr 113 | { 114 | static constexpr bool value = is_c_str_helper::value; 115 | }; 116 | 117 | template 118 | struct is_c_str_or_c_wstr 119 | { 120 | static constexpr bool value = is_c_str::value 121 | || is_c_wstr::value 122 | ; 123 | }; 124 | 125 | template< 126 | typename String, 127 | typename = decltype(std::declval().data()), 128 | typename = typename std::enable_if::value>::type 129 | > const typename char_type::type* c_str(const String& path) 130 | { 131 | return path.data(); 132 | } 133 | 134 | template< 135 | typename String, 136 | typename = decltype(std::declval().empty()), 137 | typename = typename std::enable_if::value>::type 138 | > bool empty(const String& path) 139 | { 140 | return path.empty(); 141 | } 142 | 143 | template< 144 | typename String, 145 | typename = typename std::enable_if::value>::type 146 | > const typename char_type::type* c_str(String path) 147 | { 148 | return path; 149 | } 150 | 151 | template< 152 | typename String, 153 | typename = typename std::enable_if::value>::type 154 | > bool empty(String path) 155 | { 156 | return !path || (*path == 0); 157 | } 158 | 159 | struct FPlatformStrFromW 160 | { 161 | #ifdef _WIN32 162 | FPlatformStrFromW(const TCHAR* From) 163 | : Str(From) 164 | { 165 | } 166 | const TCHAR* Data() const { return Str; } 167 | const TCHAR* Str; 168 | #else 169 | FPlatformStrFromW(const TCHAR* From) 170 | : Conv(From) 171 | { 172 | } 173 | const ANSICHAR* Data() const { return Conv.Get(); } 174 | FTCHARToUTF8 Conv; 175 | #endif 176 | }; 177 | 178 | struct FPlatformStrFromA 179 | { 180 | #ifdef _WIN32 181 | FPlatformStrFromA(const ANSICHAR* From) 182 | : Conv(From) 183 | { 184 | } 185 | const TCHAR* Data() const { return Conv.Get(); } 186 | FUTF8ToTCHAR Conv; 187 | #else 188 | FPlatformStrFromA(const ANSICHAR* From) 189 | : Str(From) 190 | { 191 | } 192 | const ANSICHAR* Data() const { return Str; } 193 | const ANSICHAR* Str; 194 | #endif 195 | }; 196 | FPlatformStrFromA ToPlatformStrImpl(const ANSICHAR* From) { return {From}; } 197 | FPlatformStrFromW ToPlatformStrImpl(const TCHAR* From) { return {From}; } 198 | template 199 | auto ToPlatformStr(const String& From) 200 | { 201 | return ToPlatformStrImpl(c_str(From)); 202 | } 203 | } // namespace detail 204 | } // namespace mio 205 | 206 | #endif // MIO_STRING_UTIL_HEADER 207 | 208 | -------------------------------------------------------------------------------- /GenericStorages/Source/GenericStorages/Template/mio/page.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 https://github.com/mandreyel 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 4 | * software and associated documentation files (the "Software"), to deal in the Software 5 | * without restriction, including without limitation the rights to use, copy, modify, 6 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 7 | * permit persons to whom the Software is furnished to do so, subject to the following 8 | * conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies 11 | * or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 14 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 15 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 16 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 17 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 18 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | */ 20 | 21 | #ifndef MIO_PAGE_HEADER 22 | #define MIO_PAGE_HEADER 23 | 24 | #ifdef _WIN32 25 | #include "Windows/AllowWindowsPlatformTypes.h" // IWYU pragma: keep 26 | #include "Windows/AllowWindowsPlatformAtomics.h" // IWYU pragma: keep 27 | #include // IWYU pragma: keep 28 | #include "Windows/HideWindowsPlatformAtomics.h" // IWYU pragma: keep 29 | #include "Windows/WindowsHWrapper.h" // IWYU pragma: keep 30 | #include "Windows/HideWindowsPlatformTypes.h" // IWYU pragma: keep 31 | #else 32 | # include 33 | #endif 34 | 35 | namespace mio { 36 | 37 | /** 38 | * This is used by `basic_mmap` to determine whether to create a read-only or 39 | * a read-write memory mapping. 40 | */ 41 | enum class access_mode 42 | { 43 | read, 44 | write 45 | }; 46 | 47 | /** 48 | * Determines the operating system's page allocation granularity. 49 | * 50 | * On the first call to this function, it invokes the operating system specific syscall 51 | * to determine the page size, caches the value, and returns it. Any subsequent call to 52 | * this function serves the cached value, so no further syscalls are made. 53 | */ 54 | inline size_t page_size() 55 | { 56 | static const size_t page_size = [] 57 | { 58 | #ifdef _WIN32 59 | SYSTEM_INFO SystemInfo; 60 | GetSystemInfo(&SystemInfo); 61 | return SystemInfo.dwAllocationGranularity; 62 | #else 63 | return sysconf(_SC_PAGE_SIZE); 64 | #endif 65 | }(); 66 | return page_size; 67 | } 68 | 69 | /** 70 | * Alligns `offset` to the operating's system page size such that it subtracts the 71 | * difference until the nearest page boundary before `offset`, or does nothing if 72 | * `offset` is already page aligned. 73 | */ 74 | inline size_t make_offset_page_aligned(size_t offset) noexcept 75 | { 76 | const size_t page_size_ = page_size(); 77 | // Use integer division to round down to the nearest page alignment. 78 | return offset / page_size_ * page_size_; 79 | } 80 | 81 | } // namespace mio 82 | 83 | #endif // MIO_PAGE_HEADER 84 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jeffry 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GenericStorages 2 | GenericStorages For Unreal 3 | --------------------------------------------------------------------------------