A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
DlgConfigParser.h
Go to the documentation of this file.
1// Copyright Csaba Molnar, Daniel Butum. All Rights Reserved.
2#pragma once
3
4#include <functional>
5#include "CoreTypes.h"
6#include "Logging/LogMacros.h"
7
8#include "IDlgParser.h"
10
11DECLARE_LOG_CATEGORY_EXTERN(LogDlgConfigParser, Log, All);
12
13
30class DLGSYSTEM_API FDlgConfigParser : public IDlgParser
31{
32public:
39 FDlgConfigParser(const FString InPreTag = "");
40
47 FDlgConfigParser(const FString& FilePath, const FString& InPreTag);
48
49 // IDlgParser Interface
50 void InitializeParser(const FString& FilePath) override;
51
52 void InitializeParserFromString(const FString& Text) override;
53
54 bool IsValidFile() const override
55 {
56 return HasValidWord();
57 }
58
59 void ReadAllProperty(const UStruct* ReferenceClass, void* TargetObject, UObject* DefaultObjectOuter = nullptr) override;
60
61 void ResetParser();
62
74 bool ReadProperty(const UStruct* ReferenceClass, void* TargetObject, UObject* DefaultObjectOuter = nullptr);
75
76private:
88 bool ReadPurePropertyBlock(void* TargetObject, const UStruct* ReferenceClass, bool bBlockStartAlreadyRead = false, UObject* DefaultObjectOuter = nullptr);
89
99 static FString ConstructConfigFile(const UStruct* ReferenceType, void* SourceObject);
100
101
107 bool FindNextWord();
108
110 bool IsNextWordString() const;
111
113 bool IsActualWordString() const;
114
121 bool FindNextWord(const FString& ExpectedStuff);
122
128 bool FindNextWordAndCheckIfBlockStart(const FString& BlockName);
129
135 bool FindNextWordAndCheckIfBlockEnd(const FString& BlockName);
136
142 bool CheckIfBlockEnd(const FString& BlockName);
143
150 bool CompareToActiveWord(const FString& StringToCompare) const;
151
157 int32 GetActiveLineNumber() const;
158
159 // @return false if the file could not be read or if the end of file is reached
160 bool HasValidWord() const { return bHasValidWord; }
161
166 FString GetActiveWord() const { return bHasValidWord ? String.Mid(From, Len) : ""; }
167
172 bool GetActiveWordAsFloat(float& FloatValue) const;
173
181 static void ConstructConfigFileInternal(const UStruct* ReferenceType, int32 TabCount, void* SourceObject, FString& OutString);
182
183
185 bool TryToReadPrimitiveProperty(void* Target, FNYProperty* PropertyBase);
186
187 bool TryToReadEnum(void* TargetObject, FNYProperty* PropertyBase);
188
190 bool ReadSet(void* TargetObject, FNYSetProperty& Property, UObject* DefaultObjectOuter);
191
193 bool ReadMap(void* TargetObject, FNYMapProperty& Property, UObject* DefaultObjectOuter);
194
205 template <typename Type, typename PropertyType>
206 bool ReadPrimitiveProperty(void* Target,
207 FNYProperty* PropertyBase,
208 std::function<Type()> OnGetAsValue,
209 const FString& TypeName,
210 bool bCanBeEmpty);
211
212
224 template <typename PropertyType>
225 bool ReadComplexProperty(void* Target,
226 FNYProperty* Property,
227 const UStruct* ReferenceType,
228 std::function<void*(void*, const UClass*, UObject*)> OnInitValue,
229 UObject* Outer);
230
231
232 bool GetAsBool() const;
233 float GetAsFloat() const;
234 int32 GetAsInt32() const;
235 int64 GetAsInt64() const;
236 FName GetAsName() const;
237 FString GetAsString() const;
238 FText GetAsText() const;
239
240 void OnInvalidValue(const FString& PropType) const;
241
242 void* OnInitObject(void* ValuePtr, const UClass* ChildClass, UObject* OuterInit);
243
245 const UClass* SmartGetPropertyClass(FNYProperty* Property, const FString& TypeName);
246
247private:
248
250 FString FileName = "";
252 FString String = "";
254 int32 From = 0;
256 int32 Len = 0;
257
259 const FString PreTag;
260
261 bool bHasValidWord = false;
262
263 // Nullptr value?
264 bool bHasNullptr = false;
265
267 bool bActiveIsString = false;
268};
269
270
271template <typename Type, typename PropertyType>
273 FNYProperty* PropertyBase,
274 std::function<Type()> OnGetAsValue,
275 const FString& TypeName,
276 bool bCanBeEmpty)
277{
278 // try to find a member variable with the name
279 PropertyType* Property = FNYReflectionHelper::CastProperty<PropertyType>(PropertyBase);
280 if (Property == nullptr)
281 {
282 // Array
283 // No property found, let's check if there is an array with the same name
284 auto* ArrayProp = FNYReflectionHelper::CastProperty<FNYArrayProperty>(PropertyBase);
285
286 // SmartCastProperty gets the inner type of the array and uses dynamic_cast to cast it to the proper type
287 if (ArrayProp == nullptr || FNYReflectionHelper::SmartCastProperty<PropertyType>(ArrayProp) == nullptr)
288 {
289 return false;
290 }
291
292 TArray<Type>* Array = ArrayProp->ContainerPtrToValuePtr<TArray<Type>>(Target);
293 Array->Empty();
294 if (FindNextWordAndCheckIfBlockStart(TypeName + "Array"))
295 {
296 // read values until the block ends
297 while (!FindNextWordAndCheckIfBlockEnd(TypeName + "Array"))
298 {
299 if (!bHasValidWord && !bCanBeEmpty)
300 {
301 UE_LOG(LogDlgConfigParser, Warning, TEXT("Unexpected end of file while array end was expected (config %s)"), *FileName)
302 }
303 else
304 {
305 Array->Add(OnGetAsValue());
306 }
307 }
308 }
309 }
310 else
311 {
312 // Primitive type
313 FindNextWord();
314 if (bHasValidWord || bCanBeEmpty)
315 {
316 Property->SetPropertyValue_InContainer(Target, OnGetAsValue());
317 }
318 else
319 {
320 UE_LOG(LogDlgConfigParser, Warning, TEXT("Unexpected end of file while %s value was expected (config %s)"), *TypeName, *FileName)
321 }
322 }
323
324 FindNextWord();
325 return true;
326}
327
328
329template <typename PropertyType>
331 FNYProperty* Property,
332 const UStruct* ReferenceType,
333 std::function<void*(void*, const UClass*, UObject*)> OnInitValue,
334 UObject* Outer)
335{
336 PropertyType* ElementProp = FNYReflectionHelper::CastProperty<PropertyType>(Property);
337 if (ElementProp == nullptr)
338 {
339 auto* ArrayProp = FNYReflectionHelper::CastProperty<FNYArrayProperty>(Property);
340 if (ArrayProp == nullptr || FNYReflectionHelper::SmartCastProperty<PropertyType>(ArrayProp) == nullptr)
341 {
342 return false;
343 }
344
345 // Array
346 FScriptArrayHelper Helper(ArrayProp, ArrayProp->ContainerPtrToValuePtr<uint8>(Target));
347 Helper.EmptyValues();
348 if (!FindNextWordAndCheckIfBlockStart(ReferenceType->GetName() + "Array element") || !FindNextWord("{ or }"))
349 {
350 return false;
351 }
352
353 while (!CheckIfBlockEnd(ReferenceType->GetName() + "Array element"))
354 {
355 const UClass* ReferenceClass = Cast<UClass>(ReferenceType);
356 if (ReferenceClass != nullptr)
357 {
358 if (IsActualWordString() && ArrayProp->Inner != nullptr) // UObject by reference
359 {
360 const FString Path = GetActiveWord();
361 void* TargetPtr = Helper.GetRawPtr(Helper.AddValue());
362 auto* ObjectPtrPtr = static_cast<UObject**>(TargetPtr);
363 *ObjectPtrPtr = nullptr; // reset first
364 if (!Path.TrimStartAndEnd().IsEmpty()) // null reference ?
365 {
366 *ObjectPtrPtr = StaticLoadObject(UObject::StaticClass(), Outer, *Path);
367 }
368
369 FindNextWord();
370 continue;
371 }
372
373 const FString TypeName = PreTag + GetActiveWord();
374 ReferenceClass = GetChildClassFromName(ReferenceClass, TypeName);
375 if (ReferenceClass == nullptr)
376 {
377 UE_LOG(LogDlgConfigParser, Warning, TEXT("Failed to find class %s in config %s (:%d)"),
378 *TypeName, *FileName, GetActiveLineNumber());
379 return false;
380 }
381 }
382 else if (!CompareToActiveWord("{"))
383 {
384 if (!bHasValidWord)
385 {
386 UE_LOG(LogDlgConfigParser, Warning, TEXT("Unexpected end of file while %s array element end was expected (config %s)"),
387 *ReferenceType->GetName(), *FileName)
388 }
389 else
390 {
391 UE_LOG(LogDlgConfigParser, Warning, TEXT("'{' expected but %s found for %s array element (config %s :%d)"),
392 *ReferenceType->GetName(), *GetActiveWord(), *FileName, GetActiveLineNumber());
393 }
394 return false;
395 }
396
397 void* Value = OnInitValue(Helper.GetRawPtr(Helper.AddValue()), ReferenceClass, Outer);
398 if (!ReadPurePropertyBlock(Value, ReferenceClass == nullptr ? ReferenceType : ReferenceClass, ReferenceClass == nullptr, Outer))
399 {
400 return false;
401 }
402 }
403
404 FindNextWord();
405 return true;
406 }
407
408 // Try pure block
409 void* Value = OnInitValue(ElementProp->template ContainerPtrToValuePtr<void>(Target), Cast<UClass>(ReferenceType), Outer);
410 return ReadPurePropertyBlock(Value, ReferenceType, false, Outer);
411}
DECLARE_LOG_CATEGORY_EXTERN(LogDlgConfigParser, Log, All)
UProperty FNYProperty
UMapProperty FNYMapProperty
USetProperty FNYSetProperty
bool IsActualWordString() const
bool CompareToActiveWord(const FString &StringToCompare) const
FString GetActiveWord() const
bool ReadPrimitiveProperty(void *Target, FNYProperty *PropertyBase, std::function< Type()> OnGetAsValue, const FString &TypeName, bool bCanBeEmpty)
bool FindNextWordAndCheckIfBlockEnd(const FString &BlockName)
bool CheckIfBlockEnd(const FString &BlockName)
bool ReadPurePropertyBlock(void *TargetObject, const UStruct *ReferenceClass, bool bBlockStartAlreadyRead=false, UObject *DefaultObjectOuter=nullptr)
bool FindNextWordAndCheckIfBlockStart(const FString &BlockName)
const FString PreTag
bool ReadComplexProperty(void *Target, FNYProperty *Property, const UStruct *ReferenceType, std::function< void *(void *, const UClass *, UObject *)> OnInitValue, UObject *Outer)
bool IsValidFile() const override
int32 GetActiveLineNumber() const
bool HasValidWord() const
virtual void InitializeParserFromString(const FString &Text)
Definition IDlgParser.h:18
const UClass * GetChildClassFromName(const UClass *ParentClass, const FString &Name)
Definition IDlgParser.h:45
virtual void ReadAllProperty(const UStruct *ReferenceClass, void *TargetObject, UObject *DefaultObjectOuter=nullptr)=0
virtual void InitializeParser(const FString &FilePath)=0