ArticyXImporter
ArticyXImporter for Unreal Engine
Loading...
Searching...
No Matches
ArticyImporterHelpers.h
1//
2// Copyright (c) 2023 articy Software GmbH & Co. KG. All rights reserved.
3//
4
5#pragma once
6
7#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >0
8#include "AssetRegistry/AssetRegistryModule.h"
9#else
10#include "AssetRegistryModule.h"
11#endif
12#include "UObject/Package.h"
13#include "UObject/ConstructorHelpers.h"
14#include "Interfaces/ArticyObjectWithPosition.h"
15#include "Interfaces/ArticyNode.h"
16
25{
35 inline UPackage* FindOrCreatePackage(const FString& Name)
36 {
37 const FString PackageName = ArticyHelpers::GetArticyGeneratedFolder() / Name;
38
39 // @TODO Engine Versioning
40#if ENGINE_MAJOR_VERSION >= 5 || (ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 26)
41 UPackage* AssetPackage = CreatePackage(*PackageName);
42#else
43 UPackage* AssetPackage = CreatePackage(nullptr, *PackageName);
44#endif
45
46 AssetPackage->FullyLoad();
47
48 return AssetPackage;
49 }
50
62 inline UClass* RetrieveClass(const FString& ClassName, const FString& ModuleName = "", UClass* BaseClass = UArticyObject::StaticClass())
63 {
64 if (!ModuleName.IsEmpty())
65 {
66 auto FullClassName = FString::Printf(TEXT("/Script/%s.%s"), *ModuleName, *ClassName);
67 return ConstructorHelpersInternal::FindOrLoadClass(FullClassName, BaseClass);
68 }
69
70 FString FullClassName = FString::Printf(TEXT("/Script/%s.%s"), TEXT("ArticyRuntime"), *ClassName);
71 UClass* Result = ConstructorHelpersInternal::FindOrLoadClass(FullClassName, BaseClass);
72
73 if (Result != nullptr)
74 {
75 return Result;
76 }
77
78 FullClassName = FString::Printf(TEXT("/Script/%s.%s"), FApp::GetProjectName(), *ClassName);
79 Result = ConstructorHelpersInternal::FindOrLoadClass(FullClassName, BaseClass);
80
81 return Result;
82 }
83
99 template <typename AssetType>
100 AssetType* GenerateAsset(const TCHAR* ClassName, const TCHAR* ModuleName, const FString AssetName = "", const FString SubFolder = "", const EObjectFlags AdditionalFlags = RF_NoFlags, bool MustCreate = false)
101 {
102 const auto ActualAssetName = AssetName.IsEmpty() ? ClassName : AssetName;
103 const auto FileName = (SubFolder.IsEmpty() ? ActualAssetName : SubFolder / ActualAssetName).Replace(TEXT(" "), TEXT("_"));
104
105 //auto FullClassName = FString::Printf(TEXT("Class'/Script/%s.%s'"), ModuleName, ClassName);
106
107 if (auto UClass = RetrieveClass(ClassName, ModuleName, AssetType::StaticClass()))
108 {
109 auto AssetPackage = FindOrCreatePackage(FileName);
110 EObjectFlags Flags = RF_Public | RF_Standalone;
111
112 // If this asset is flagged as MustCreate...
113 if (MustCreate)
114 {
115 // ... Then make sure the asset doesn't already exist.
116 // If it does, throw the most helpful ensure message we can and return nullptr
117 AssetType* Existing = FindObject<AssetType>(AssetPackage, *ActualAssetName);
118 if (!ensureAlwaysMsgf(Existing == nullptr, TEXT(
119 "Warning!! Somehow you have managed to load an old Articy Asset asset (%s) when it\n"
120 "_should_ have been deleted already by DeleteGeneratedAssets() in CodeGenerator.cpp.\n"
121 "This is likely caused by your Source Control plugin in Unreal restoring deleted files\n"
122 "unexpectedly. If you're not sure what's going on, please contact support@articy.com for\n"
123 "assistance with details on how you triggered this issue.\n"
124 "Loading will be cancelled to avoid crashing Unreal."
125 ), *ActualAssetName))
126 {
127 return nullptr;
128 }
129 }
130
131 // primarily added so we can add RF_ArchetypeObject to the database and GV asset creation.
132 // It fixes a problem in which the CDO would not get refreshed after reimporting changes via Hot Reload
133 if (AdditionalFlags != RF_NoFlags)
134 {
135 Flags = Flags | AdditionalFlags;
136 }
137 AssetType* CreatedAsset = NewObject<AssetType>(AssetPackage, UClass, *ActualAssetName, Flags);;
138
139 // if we successfully created the asset, notify the asset registry and mark it dirty
140 if (CreatedAsset)
141 {
142 // Notify the asset registry
143 FAssetRegistryModule::AssetCreated(Cast<UObject>(CreatedAsset));
144
145 // Mark the package dirty...
146 AssetPackage->MarkPackageDirty();
147 }
148
149 return CreatedAsset;
150 }
151
152 //UE_LOG(LogArticyEditor, Error, TEXT("ArticyImporter: Could not find class %s!"), ClassName);
153
154 return nullptr;
155 }
156
170 template <typename AssetType>
171 AssetType* GenerateSubAsset(const TCHAR* ClassName, const TCHAR* ModuleName, const FString AssetName = "", UObject* Outer = nullptr)
172 {
173 if (!Outer)
174 {
175 //UE_LOG(LogArticyEditor, Error, TEXT("Could not generate sub-asset %s: Outer is null!"), *AssetName);
176 return nullptr;
177 }
178
179 const auto ActualAssetName = AssetName.IsEmpty() ? ClassName : AssetName;
180 const auto FileName = ActualAssetName.Replace(TEXT(" "), TEXT("_"));
181
182 auto FullClassName = FString::Printf(TEXT("Class'/Script/%s.%s'"), ModuleName, ClassName);
183 if (auto UClass = ConstructorHelpersInternal::FindOrLoadClass(FullClassName, AssetType::StaticClass()))
184 {
185 // only public, not standalone, since the assets are bound to their outers
186 EObjectFlags Flags = RF_Public;
187 AssetType* CreatedAsset = NewObject<AssetType>(Outer, UClass, FName(*ActualAssetName), Flags);
188
189 // if we successfully created the asset, notify the asset registry and mark it dirty
190 if (CreatedAsset)
191 {
192 // Notify the asset registry
193 FAssetRegistryModule::AssetCreated(Cast<UObject>(CreatedAsset));
194 }
195
196 return CreatedAsset;
197 }
198
199 //UE_LOG(LogArticyEditor, Error, TEXT("ArticyImporter: Could not find class %s!"), ClassName);
200
201 return nullptr;
202 }
203
212 static bool IsPlayInEditor()
213 {
214 for (const FWorldContext& Context : GEngine->GetWorldContexts())
215 {
216 if (Context.World()->IsPlayInEditor())
217 {
218 return true;
219 }
220 }
221 return false;
222 }
223
232 {
240 FORCEINLINE bool operator()(const FArticyId& A, const FArticyId& B) const
241 {
242 const IArticyObjectWithPosition* AObjectWithPosition = Cast<IArticyObjectWithPosition>(UArticyObject::FindAsset(A));
243 const IArticyObjectWithPosition* BObjectWithPosition = Cast<IArticyObjectWithPosition>(UArticyObject::FindAsset(B));
244
245 if (!AObjectWithPosition || !BObjectWithPosition) return true;
246
247 const FVector2D& APos = AObjectWithPosition->GetPosition();
248 const FVector2D& BPos = BObjectWithPosition->GetPosition();
249
250 if (APos.X == BPos.X)
251 {
252 return APos.Y < BPos.Y;
253 }
254
255 return APos.X < BPos.X;
256 }
257 };
258
259}
Definition ArticyObjectWithPosition.h:17
Provides utility functions for importing and managing Articy assets in Unreal Engine.
AssetType * GenerateSubAsset(const TCHAR *ClassName, const TCHAR *ModuleName, const FString AssetName="", UObject *Outer=nullptr)
Generates a sub-asset of the specified type.
Definition ArticyImporterHelpers.h:171
UPackage * FindOrCreatePackage(const FString &Name)
Finds or creates a package with the specified name.
Definition ArticyImporterHelpers.h:35
AssetType * GenerateAsset(const TCHAR *ClassName, const TCHAR *ModuleName, const FString AssetName="", const FString SubFolder="", const EObjectFlags AdditionalFlags=RF_NoFlags, bool MustCreate=false)
Generates an asset of the specified type.
Definition ArticyImporterHelpers.h:100
UClass * RetrieveClass(const FString &ClassName, const FString &ModuleName="", UClass *BaseClass=UArticyObject::StaticClass())
Retrieves a class by name, optionally within a specified module.
Definition ArticyImporterHelpers.h:62
Comparator for sorting Articy nodes based on their X position.
Definition ArticyImporterHelpers.h:232
FORCEINLINE bool operator()(const FArticyId &A, const FArticyId &B) const
Comparison operator for sorting nodes based on position.
Definition ArticyImporterHelpers.h:240
Definition ArticyBaseTypes.h:18