├── LICENSE ├── README.md └── src ├── EngineClasses.hpp ├── Generator.cpp ├── GenericTypes.cpp ├── IGenerator.hpp ├── Logger.cpp ├── Logger.hpp ├── Main.cpp ├── NameValidator.cpp ├── NameValidator.hpp ├── NamesStore.cpp ├── NamesStore.hpp ├── ObjectsStore.cpp ├── ObjectsStore.hpp ├── Package.cpp ├── Package.hpp ├── PatternFinder.cpp ├── PatternFinder.hpp ├── PrintHelper.cpp ├── PrintHelper.hpp ├── UE4 ├── FunctionFlags.cpp ├── FunctionFlags.hpp ├── GenericTypes.hpp ├── PropertyFlags.cpp └── PropertyFlags.hpp ├── cpplinq.hpp └── tinyformat.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 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 | # Credit 2 | @KN4CK3R created this tool, I merely adapted it to PUBG. 3 | Please check out [his repo](https://github.com/KN4CK3R) to get an SDK generator for other games. 4 | 5 | ## How to Use: 6 | 7 | * Compile all files in the src directory (x64 Release). 8 | * Inject the resultant DLL into PUBG. 9 | * Wait for the magic to happen. 10 | * Click 'OK' on the Finished message box. 11 | * Copy pasta SDK into your cheat. 12 | * Fix UTimelineComponent in AParachutePlayer_C. (PUBG_ParachutePlayer_classes.hpp) 13 | * Add AActors and AActorsForGC right before OwningWorld in ULevel. (PUBG_Engine_classes.hpp) 14 | * Add Location and Bounds to USceneComponent right after PhysicsVolume. (PUBG_Engine_classes.hpp) 15 | * Compile. 16 | 17 | ## Notes 18 | * Default Directory is D:/SDK_GEN 19 | * It is not perfectly aligned! 20 | * If you can improve the alignment, please make a pull request. -------------------------------------------------------------------------------- /src/EngineClasses.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | struct FPointer 7 | { 8 | uintptr_t Dummy; 9 | }; 10 | 11 | struct FQWord 12 | { 13 | int A; 14 | int B; 15 | }; 16 | 17 | struct FName 18 | { 19 | int32_t ComparisonIndex; 20 | int32_t Number; 21 | }; 22 | 23 | template 24 | struct TArray 25 | { 26 | TArray() 27 | { 28 | Data = nullptr; 29 | Count = Max = 0; 30 | }; 31 | 32 | size_t Num() const 33 | { 34 | return Count; 35 | }; 36 | 37 | T& operator[](size_t i) 38 | { 39 | return Data[i]; 40 | }; 41 | 42 | const T& operator[](size_t i) const 43 | { 44 | return Data[i]; 45 | }; 46 | 47 | bool IsValidIndex(size_t i) const 48 | { 49 | return i < Num(); 50 | } 51 | 52 | T* Data; 53 | int32_t Count; 54 | int32_t Max; 55 | }; 56 | 57 | template 58 | class TPair 59 | { 60 | public: 61 | KeyType Key; 62 | ValueType Value; 63 | }; 64 | 65 | struct FString : public TArray 66 | { 67 | std::string ToString() const 68 | { 69 | std::wstring wstr(Data); 70 | return std::string(wstr.begin(), wstr.end()); 71 | } 72 | }; 73 | 74 | class FScriptInterface 75 | { 76 | private: 77 | UObject* ObjectPointer; 78 | void* InterfacePointer; 79 | 80 | public: 81 | UObject* GetObject() const 82 | { 83 | return ObjectPointer; 84 | } 85 | 86 | UObject*& GetObjectRef() 87 | { 88 | return ObjectPointer; 89 | } 90 | 91 | void* GetInterface() const 92 | { 93 | return ObjectPointer != nullptr ? InterfacePointer : nullptr; 94 | } 95 | }; 96 | 97 | template 98 | class TScriptInterface : public FScriptInterface 99 | { 100 | public: 101 | InterfaceType* operator->() const 102 | { 103 | return (InterfaceType*)GetInterface(); 104 | } 105 | 106 | InterfaceType& operator*() const 107 | { 108 | return *((InterfaceType*)GetInterface()); 109 | } 110 | 111 | operator bool() const 112 | { 113 | return GetInterface() != nullptr; 114 | } 115 | }; 116 | 117 | struct FTextData 118 | { 119 | char __pad00[0x28]; 120 | wchar_t* Data; 121 | int32_t Length; 122 | }; 123 | 124 | struct FText 125 | { 126 | FTextData* Data; 127 | unsigned char UnknownData[0x10]; 128 | 129 | wchar_t* Get() 130 | { 131 | if (!Data) return nullptr; 132 | 133 | return Data->Data; 134 | } 135 | }; 136 | 137 | struct FWeakObjectPtr 138 | { 139 | int32_t ObjectIndex; 140 | int32_t ObjectSerialNumber; 141 | }; 142 | 143 | struct FStringAssetReference 144 | { 145 | FString AssetLongPathname; 146 | }; 147 | 148 | template 149 | class TPersistentObjectPtr 150 | { 151 | public: 152 | FWeakObjectPtr WeakPtr; 153 | int32_t TagAtLastTest; 154 | TObjectID ObjectID; 155 | }; 156 | 157 | class FAssetPtr : public TPersistentObjectPtr 158 | { 159 | 160 | }; 161 | 162 | struct FGuid 163 | { 164 | uint32_t A; 165 | uint32_t B; 166 | uint32_t C; 167 | uint32_t D; 168 | }; 169 | 170 | struct FUniqueObjectGuid 171 | { 172 | FGuid Guid; 173 | }; 174 | 175 | class FLazyObjectPtr : public TPersistentObjectPtr 176 | { 177 | 178 | }; 179 | 180 | struct FScriptDelegate 181 | { 182 | unsigned char UnknownData[20]; 183 | }; 184 | 185 | struct FScriptMulticastDelegate 186 | { 187 | unsigned char UnknownData[16]; 188 | }; 189 | 190 | class UClass; 191 | 192 | class UObject 193 | { 194 | public: 195 | FPointer VTableObject; 196 | int32_t ObjectFlags; 197 | int32_t InternalIndex; 198 | UClass* Class; 199 | FName Name; 200 | UObject* Outer; 201 | }; 202 | 203 | class UField : public UObject 204 | { 205 | public: 206 | UField* Next; 207 | }; 208 | 209 | class UEnum : public UField 210 | { 211 | public: 212 | FString CppType; //0x0030 213 | TArray> Names; //0x0040 214 | __int64 CppForm; //0x0050 215 | }; 216 | 217 | class UStruct : public UField 218 | { 219 | public: 220 | UStruct* SuperField; 221 | UField* Children; 222 | int32_t PropertySize; 223 | int32_t MinAlignment; 224 | char pad_0x0048[0x40]; 225 | }; 226 | 227 | class UScriptStruct : public UStruct 228 | { 229 | public: 230 | char pad_0x0088[0x10]; //0x0088 231 | }; 232 | 233 | class UFunction : public UStruct 234 | { 235 | public: 236 | __int32 FunctionFlags; //0x0088 237 | __int16 RepOffset; //0x008C 238 | __int8 NumParms; //0x008E 239 | char pad_0x008F[0x1]; //0x008F 240 | __int16 ParmsSize; //0x0090 241 | __int16 ReturnValueOffset; //0x0092 242 | __int16 RPCId; //0x0094 243 | __int16 RPCResponseId; //0x0096 244 | class UProperty* FirstPropertyToInit; //0x0098 245 | UFunction* EventGraphFunction; //0x00A0 246 | __int32 EventGraphCallOffset; //0x00A8 247 | char pad_0x00AC[0x4]; //0x00AC 248 | void* Func; //0x00B0 249 | }; 250 | 251 | class UClass : public UStruct 252 | { 253 | public: 254 | char pad_0x0088[0x198]; //0x0088 255 | }; 256 | 257 | class UProperty : public UField 258 | { 259 | public: 260 | __int32 ArrayDim; //0x0030 261 | __int32 ElementSize; //0x0034 262 | FQWord PropertyFlags; //0x0038 263 | __int32 PropertySize; //0x0040 264 | char pad_0x0044[0xC]; //0x0044 265 | __int32 Offset; //0x0050 266 | char pad_0x0054[0x24]; //0x0054 267 | }; 268 | 269 | class UNumericProperty : public UProperty 270 | { 271 | public: 272 | 273 | }; 274 | 275 | class UByteProperty : public UNumericProperty 276 | { 277 | public: 278 | UEnum* Enum; // 0x0088 (0x04) 279 | }; 280 | 281 | class UUInt16Property : public UNumericProperty 282 | { 283 | public: 284 | 285 | }; 286 | 287 | class UUInt32Property : public UNumericProperty 288 | { 289 | public: 290 | 291 | }; 292 | 293 | class UUInt64Property : public UNumericProperty 294 | { 295 | public: 296 | 297 | }; 298 | 299 | class UInt8Property : public UNumericProperty 300 | { 301 | public: 302 | 303 | }; 304 | 305 | class UInt16Property : public UNumericProperty 306 | { 307 | public: 308 | 309 | }; 310 | 311 | class UIntProperty : public UNumericProperty 312 | { 313 | public: 314 | 315 | }; 316 | 317 | class UInt64Property : public UNumericProperty 318 | { 319 | public: 320 | 321 | }; 322 | 323 | class UFloatProperty : public UNumericProperty 324 | { 325 | public: 326 | 327 | }; 328 | 329 | class UDoubleProperty : public UNumericProperty 330 | { 331 | public: 332 | 333 | }; 334 | 335 | class UBoolProperty : public UProperty 336 | { 337 | public: 338 | uint8_t FieldSize; 339 | uint8_t ByteOffset; 340 | uint8_t ByteMask; 341 | uint8_t FieldMask; 342 | }; 343 | 344 | class UObjectPropertyBase : public UProperty 345 | { 346 | public: 347 | UClass* PropertyClass; 348 | }; 349 | 350 | class UObjectProperty : public UObjectPropertyBase 351 | { 352 | public: 353 | 354 | }; 355 | 356 | class UClassProperty : public UObjectProperty 357 | { 358 | public: 359 | UClass* MetaClass; 360 | }; 361 | 362 | class UInterfaceProperty : public UProperty 363 | { 364 | public: 365 | UClass* InterfaceClass; 366 | }; 367 | 368 | class UWeakObjectProperty : public UObjectPropertyBase 369 | { 370 | public: 371 | 372 | }; 373 | 374 | class ULazyObjectProperty : public UObjectPropertyBase 375 | { 376 | public: 377 | 378 | }; 379 | 380 | class UAssetObjectProperty : public UObjectPropertyBase 381 | { 382 | public: 383 | 384 | }; 385 | 386 | class UAssetClassProperty : public UAssetObjectProperty 387 | { 388 | public: 389 | UClass* MetaClass; 390 | }; 391 | 392 | class UNameProperty : public UProperty 393 | { 394 | public: 395 | 396 | }; 397 | 398 | class UStructProperty : public UProperty 399 | { 400 | public: 401 | UScriptStruct* Struct; 402 | }; 403 | 404 | class UStrProperty : public UProperty 405 | { 406 | public: 407 | 408 | }; 409 | 410 | class UTextProperty : public UProperty 411 | { 412 | public: 413 | 414 | }; 415 | 416 | class UArrayProperty : public UProperty 417 | { 418 | public: 419 | UProperty* Inner; 420 | }; 421 | 422 | class UMapProperty : public UProperty 423 | { 424 | public: 425 | UProperty* KeyProp; 426 | UProperty* ValueProp; 427 | }; 428 | 429 | class UDelegateProperty : public UProperty 430 | { 431 | public: 432 | UFunction* SignatureFunction; 433 | }; 434 | 435 | class UMulticastDelegateProperty : public UProperty 436 | { 437 | public: 438 | UFunction* SignatureFunction; 439 | }; 440 | 441 | class UEnumProperty : public UProperty 442 | { 443 | public: 444 | class UNumericProperty* UnderlyingProp; //0x0070 445 | class UEnum* Enum; //0x0078 446 | }; //Size: 0x0080 447 | 448 | /* 449 | #pragma once 450 | 451 | #include 452 | 453 | template 454 | inline Fn GetVFunction(const void *instance, std::size_t index) { 455 | auto vtable = *reinterpret_cast(const_cast(instance)); 456 | return reinterpret_cast(vtable[index]); 457 | } 458 | 459 | // Credits to namazso <3 460 | static unsigned fnv_hash_runtime(const char* str) { 461 | static constexpr auto k_fnv_prime = 16777619u; 462 | static constexpr auto k_offset_basis = 2166136261u; 463 | 464 | auto hash = k_offset_basis; 465 | do { 466 | hash ^= *str++; 467 | hash *= k_fnv_prime; 468 | } while (*(str - 1) != 0); 469 | 470 | return hash; 471 | } 472 | 473 | class UObject; 474 | 475 | class FUObjectItem { 476 | public: 477 | UObject* Object; 478 | int32_t Flags; 479 | int32_t SerialNumber; 480 | void* unk; 481 | 482 | enum class EInternalObjectFlags : int32_t { 483 | None = 0, 484 | Native = 1 << 25, 485 | Async = 1 << 26, 486 | AsyncLoading = 1 << 27, 487 | Unreachable = 1 << 28, 488 | PendingKill = 1 << 29, 489 | RootSet = 1 << 30, 490 | NoStrongReference = 1 << 31 491 | }; 492 | 493 | inline bool IsUnreachable() const { 494 | return !!(Flags & static_cast>(EInternalObjectFlags::Unreachable)); 495 | } 496 | inline bool IsPendingKill() const { 497 | return !!(Flags & static_cast>(EInternalObjectFlags::PendingKill)); 498 | } 499 | }; 500 | 501 | class TUObjectArray { 502 | public: 503 | inline int32_t Num() const { 504 | return NumElements; 505 | } 506 | 507 | inline UObject* GetByIndex(int32_t index) const { 508 | return Objects[index].Object; 509 | } 510 | 511 | inline FUObjectItem* GetItemByIndex(int32_t index) const { 512 | if (index < NumElements) { 513 | return &Objects[index]; 514 | } 515 | return nullptr; 516 | } 517 | 518 | private: 519 | FUObjectItem* Objects; 520 | int32_t MaxElements; 521 | int32_t NumElements; 522 | }; 523 | 524 | class FUObjectArray { 525 | public: 526 | int32_t ObjFirstGCIndex; 527 | int32_t ObjLastNonGCIndex; 528 | int32_t MaxObjectsNotConsideredByGC; 529 | int32_t OpenForDisregardForGC; 530 | TUObjectArray ObjObjects; 531 | }; 532 | 533 | template 534 | struct TArray { 535 | friend struct FString; 536 | 537 | public: 538 | inline TArray() { 539 | Data = nullptr; 540 | Count = Max = 0; 541 | }; 542 | 543 | inline int Num() const { 544 | return Count; 545 | }; 546 | 547 | inline T& operator[](int i) { 548 | return Data[i]; 549 | }; 550 | 551 | inline const T& operator[](int i) const { 552 | return Data[i]; 553 | }; 554 | 555 | inline bool IsValidIndex(int i) const { 556 | return i < Num(); 557 | } 558 | 559 | private: 560 | T* Data; 561 | int32_t Count; 562 | int32_t Max; 563 | }; 564 | 565 | class FNameEntry { 566 | public: 567 | static const auto NAME_WIDE_MASK = 0x1; 568 | static const auto NAME_INDEX_SHIFT = 1; 569 | 570 | int32_t Index; 571 | char UnknownData00[0x04]; 572 | FNameEntry* HashNext; 573 | union { 574 | char AnsiName[1024]; 575 | wchar_t WideName[1024]; 576 | }; 577 | 578 | inline const int32_t GetIndex() const { 579 | return Index >> NAME_INDEX_SHIFT; 580 | } 581 | 582 | inline bool IsWide() const { 583 | return Index & NAME_WIDE_MASK; 584 | } 585 | 586 | inline const char* GetAnsiName() const { 587 | return AnsiName; 588 | } 589 | 590 | inline const wchar_t* GetWideName() const { 591 | return WideName; 592 | } 593 | }; 594 | 595 | template 596 | class TStaticIndirectArrayThreadSafeRead { 597 | public: 598 | inline size_t Num() const { 599 | return NumElements; 600 | } 601 | 602 | inline bool IsValidIndex(int32_t index) const { 603 | return index < Num() && index >= 0; 604 | } 605 | 606 | inline ElementType const* const& operator[](int32_t index) const { 607 | return *GetItemPtr(index); 608 | } 609 | 610 | private: 611 | inline ElementType const* const* GetItemPtr(int32_t Index) const { 612 | int32_t ChunkIndex = Index / ElementsPerChunk; 613 | int32_t WithinChunkIndex = Index % ElementsPerChunk; 614 | ElementType** Chunk = Chunks[ChunkIndex]; 615 | return Chunk + WithinChunkIndex; 616 | } 617 | 618 | enum { 619 | ChunkTableSize = (MaxTotalElements + ElementsPerChunk - 1) / ElementsPerChunk 620 | }; 621 | 622 | ElementType** Chunks[ChunkTableSize]; 623 | int32_t NumElements; 624 | int32_t NumChunks; 625 | }; 626 | 627 | using TNameEntryArray = TStaticIndirectArrayThreadSafeRead; 628 | 629 | struct FName { 630 | union { 631 | struct { 632 | int32_t ComparisonIndex; 633 | int32_t Number; 634 | }; 635 | 636 | // DO NOT REMOVE: needed for memory alignment! biggest member is now uint64_t 637 | uint64_t CompositeComparisonValue; 638 | }; 639 | 640 | inline FName() 641 | : ComparisonIndex(0), 642 | Number(0) { 643 | }; 644 | 645 | inline FName(int32_t i) 646 | : ComparisonIndex(i), 647 | Number(0) { 648 | }; 649 | 650 | FName(const char* nameToFind) 651 | : ComparisonIndex(0), 652 | Number(0) { 653 | static std::set cache; 654 | 655 | for (auto i : cache) { 656 | if (!std::strcmp(GetGlobalNames()[i]->GetAnsiName(), nameToFind)) { 657 | ComparisonIndex = i; 658 | 659 | return; 660 | } 661 | } 662 | 663 | for (auto i = 0; i < GetGlobalNames().Num(); ++i) { 664 | if (GetGlobalNames()[i] != nullptr) { 665 | if (!std::strcmp(GetGlobalNames()[i]->GetAnsiName(), nameToFind)) { 666 | cache.insert(i); 667 | 668 | ComparisonIndex = i; 669 | 670 | return; 671 | } 672 | } 673 | } 674 | }; 675 | 676 | static TNameEntryArray *GNames; 677 | static inline TNameEntryArray& GetGlobalNames() { 678 | return *GNames; 679 | }; 680 | 681 | inline const char* GetName() const { 682 | return GetGlobalNames()[ComparisonIndex]->GetAnsiName(); 683 | }; 684 | 685 | inline bool operator==(const FName &other) const { 686 | return ComparisonIndex == other.ComparisonIndex; 687 | }; 688 | }; 689 | 690 | struct FString : private TArray { 691 | inline FString() { 692 | }; 693 | 694 | FString(const wchar_t* other) { 695 | Max = Count = *other ? (int32_t)std::wcslen(other) + 1 : 0; 696 | 697 | if (Count) { 698 | Data = const_cast(other); 699 | } 700 | }; 701 | 702 | inline bool IsValid() const { 703 | return Data != nullptr; 704 | } 705 | 706 | inline const wchar_t* c_str() const { 707 | return Data; 708 | } 709 | 710 | std::string ToString() const { 711 | auto length = std::wcslen(Data); 712 | 713 | std::string str(length, '\0'); 714 | 715 | std::use_facet>(std::locale()).narrow(Data, Data + length, '?', &str[0]); 716 | 717 | return str; 718 | } 719 | }; 720 | 721 | template 722 | class TEnumAsByte { 723 | public: 724 | inline TEnumAsByte() { 725 | } 726 | 727 | inline TEnumAsByte(TEnum _value) 728 | : value(static_cast(_value)) { 729 | } 730 | 731 | explicit inline TEnumAsByte(int32_t _value) 732 | : value(static_cast(_value)) { 733 | } 734 | 735 | explicit inline TEnumAsByte(uint8_t _value) 736 | : value(_value) { 737 | } 738 | 739 | inline operator TEnum() const { 740 | return (TEnum)value; 741 | } 742 | 743 | inline TEnum GetValue() const { 744 | return (TEnum)value; 745 | } 746 | 747 | private: 748 | uint8_t value; 749 | }; 750 | 751 | class FScriptInterface { 752 | private: 753 | UObject* ObjectPointer; 754 | void* InterfacePointer; 755 | 756 | public: 757 | inline UObject* GetObject() const { 758 | return ObjectPointer; 759 | } 760 | 761 | inline UObject*& GetObjectRef() { 762 | return ObjectPointer; 763 | } 764 | 765 | inline void* GetInterface() const { 766 | return ObjectPointer != nullptr ? InterfacePointer : nullptr; 767 | } 768 | }; 769 | 770 | template 771 | class TScriptInterface : public FScriptInterface { 772 | public: 773 | inline InterfaceType* operator->() const { 774 | return (InterfaceType*)GetInterface(); 775 | } 776 | 777 | inline InterfaceType& operator*() const { 778 | return *((InterfaceType*)GetInterface()); 779 | } 780 | 781 | inline operator bool() const { 782 | return GetInterface() != nullptr; 783 | } 784 | }; 785 | 786 | class FTextData { 787 | public: 788 | char pad_0x0000[0x28]; //0x0000 789 | wchar_t* Name; //0x0028 790 | __int32 Length; //0x0030 791 | 792 | }; 793 | 794 | struct FText { 795 | FTextData* Data; 796 | char UnknownData[0x10]; 797 | 798 | wchar_t* Get() const { 799 | if (Data) { 800 | return Data->Name; 801 | } 802 | 803 | return nullptr; 804 | } 805 | }; 806 | 807 | struct FScriptDelegate { 808 | char UnknownData[16]; 809 | }; 810 | 811 | struct FScriptMulticastDelegate { 812 | char UnknownData[16]; 813 | }; 814 | 815 | template 816 | class TMap { 817 | char UnknownData[0x50]; 818 | }; 819 | 820 | struct FWeakObjectPtr { 821 | public: 822 | inline bool SerialNumbersMatch(FUObjectItem* ObjectItem) const { 823 | return ObjectItem->SerialNumber == ObjectSerialNumber; 824 | } 825 | 826 | bool IsValid() const; 827 | 828 | UObject* Get() const; 829 | 830 | int32_t ObjectIndex; 831 | int32_t ObjectSerialNumber; 832 | }; 833 | 834 | template 835 | struct TWeakObjectPtr : private TWeakObjectPtrBase { 836 | public: 837 | inline T* Get() const { 838 | return (T*)TWeakObjectPtrBase::Get(); 839 | } 840 | 841 | inline T& operator*() const { 842 | return *Get(); 843 | } 844 | 845 | inline T* operator->() const { 846 | return Get(); 847 | } 848 | 849 | inline bool IsValid() const { 850 | return TWeakObjectPtrBase::IsValid(); 851 | } 852 | }; 853 | 854 | template 855 | class TAutoPointer : public TBASE { 856 | public: 857 | inline operator T*() const { 858 | return TBASE::Get(); 859 | } 860 | 861 | inline operator const T*() const { 862 | return (const T*)TBASE::Get(); 863 | } 864 | 865 | explicit inline operator bool() const { 866 | return TBASE::Get() != nullptr; 867 | } 868 | }; 869 | 870 | template 871 | class TAutoWeakObjectPtr : public TAutoPointer> { 872 | public: 873 | }; 874 | 875 | template 876 | class TPersistentObjectPtr { 877 | public: 878 | FWeakObjectPtr WeakPtr; 879 | int64_t TagAtLastTest; 880 | TObjectID ObjectID; 881 | }; 882 | 883 | struct FStringAssetReference_ { 884 | char UnknownData[0x10]; 885 | }; 886 | 887 | class FAssetPtr : public TPersistentObjectPtr { 888 | 889 | }; 890 | 891 | template 892 | class TAssetPtr : FAssetPtr { 893 | 894 | }; 895 | 896 | struct FUniqueObjectGuid_ { 897 | char UnknownData[0x10]; 898 | }; 899 | 900 | class FLazyObjectPtr : public TPersistentObjectPtr { 901 | 902 | }; 903 | 904 | template 905 | class TLazyObjectPtr : FLazyObjectPtr { 906 | 907 | }; 908 | 909 | */ -------------------------------------------------------------------------------- /src/Generator.cpp: -------------------------------------------------------------------------------- 1 | #include "IGenerator.hpp" 2 | #include "ObjectsStore.hpp" 3 | #include "NamesStore.hpp" 4 | 5 | class Generator : public IGenerator 6 | { 7 | public: 8 | bool Initialize(void* module) override 9 | { 10 | alignasClasses = { 11 | { "ScriptStruct CoreUObject.Plane", 16 }, 12 | { "ScriptStruct CoreUObject.Quat", 16 }, 13 | { "ScriptStruct CoreUObject.Transform", 16 }, 14 | { "ScriptStruct CoreUObject.Vector4", 16 }, 15 | 16 | { "ScriptStruct Engine.RootMotionSourceGroup", 8 } 17 | }; 18 | 19 | virtualFunctionPattern["Class CoreUObject.Object"] = { 20 | { "\x45\x33\xF6\x3B\x05\x00\x00\x00\x00\x4D\x8B\xE0", "xxxxx????xxx", 0x200, R"( inline void ProcessEvent(class UFunction* function, void* parms) 21 | { 22 | return GetVFunction(this, %d)(this, function, parms); 23 | })" } 24 | }; 25 | virtualFunctionPattern["Class CoreUObject.Class"] = { 26 | { "\x4C\x8B\xDC\x57\x48\x81\xEC", "xxxxxxx", 0x200, R"( inline UObject* CreateDefaultObject() 27 | { 28 | return GetVFunction(this, %d)(this); 29 | })" } 30 | }; 31 | 32 | predefinedMembers["Class CoreUObject.Object"] = { 33 | { "void*", "Vtable" }, 34 | { "int32_t", "ObjectFlags" }, 35 | { "int32_t", "InternalIndex" }, 36 | { "class UClass*", "Class" }, 37 | { "FName", "Name" }, 38 | { "class UObject*", "Outer" } 39 | }; 40 | predefinedStaticMembers["Class CoreUObject.Object"] = { 41 | { "FUObjectArray*", "GObjects" } 42 | }; 43 | predefinedMembers["Class CoreUObject.Field"] = { 44 | { "class UField*", "Next" } 45 | }; 46 | predefinedMembers["Class CoreUObject.Struct"] = { 47 | { "class UStruct*", "SuperField" }, 48 | { "class UField*", "Children" }, 49 | { "int32_t", "PropertySize" }, 50 | { "int32_t", "MinAlignment" }, 51 | { "unsigned char", "UnknownData0x0048[0x40]" } 52 | }; 53 | predefinedMembers["Class CoreUObject.Function"] = { 54 | { "int32_t", "FunctionFlags" }, 55 | { "int16_t", "RepOffset" }, 56 | { "int8_t", "NumParms" }, 57 | { "int16_t", "ParmsSize" }, 58 | { "int16_t", "ReturnValueOffset" }, 59 | { "int16_t", "RPCId" }, 60 | { "int16_t", "RPCResponseId" }, 61 | { "class UProperty*", "FirstPropertyToInit" }, 62 | { "class UFunction*", "EventGraphFunction" }, 63 | { "int32_t", "EventGraphCallOffset" }, 64 | { "void*", "Func" } 65 | }; 66 | 67 | predefinedMethods["ScriptStruct CoreUObject.Vector2D"] = { 68 | PredefinedMethod::Inline(R"( inline FVector2D() 69 | : X(0), Y(0) 70 | { })"), 71 | PredefinedMethod::Inline(R"( inline FVector2D(float x, float y) 72 | : X(x), 73 | Y(y) 74 | { })") 75 | }; 76 | predefinedMethods["ScriptStruct CoreUObject.LinearColor"] = { 77 | PredefinedMethod::Inline(R"( inline FLinearColor() 78 | : R(0), G(0), B(0), A(0) 79 | { })"), 80 | PredefinedMethod::Inline(R"( inline FLinearColor(float r, float g, float b, float a) 81 | : R(r), 82 | G(g), 83 | B(b), 84 | A(a) 85 | { })") 86 | }; 87 | 88 | predefinedMethods["Class CoreUObject.Object"] = { 89 | PredefinedMethod::Inline(R"( static inline TUObjectArray& GetGlobalObjects() 90 | { 91 | return GObjects->ObjObjects; 92 | })"), 93 | PredefinedMethod::Default("std::string GetName() const", R"(std::string UObject::GetName() const 94 | { 95 | std::string name(Name.GetName()); 96 | if (Name.Number > 0) 97 | { 98 | name += '_' + std::to_string(Name.Number); 99 | } 100 | 101 | auto pos = name.rfind('/'); 102 | if (pos == std::string::npos) 103 | { 104 | return name; 105 | } 106 | 107 | return name.substr(pos + 1); 108 | })"), 109 | PredefinedMethod::Default("std::string GetFullName() const", R"(std::string UObject::GetFullName() const 110 | { 111 | std::string name; 112 | 113 | if (Class != nullptr) 114 | { 115 | std::string temp; 116 | for (auto p = Outer; p; p = p->Outer) 117 | { 118 | temp = p->GetName() + "." + temp; 119 | } 120 | 121 | name = Class->GetName(); 122 | name += " "; 123 | name += temp; 124 | name += GetName(); 125 | } 126 | 127 | return name; 128 | })"), 129 | PredefinedMethod::Inline(R"( template 130 | static T* FindObject(unsigned name) 131 | { 132 | for (int i = 0; i < GetGlobalObjects().Num(); ++i) 133 | { 134 | auto object = GetGlobalObjects().GetByIndex(i); 135 | 136 | if (object == nullptr) 137 | { 138 | continue; 139 | } 140 | 141 | if (fnv_hash_runtime(object->GetFullName().c_str()) == name) 142 | { 143 | return static_cast(object); 144 | } 145 | } 146 | return nullptr; 147 | })"), 148 | PredefinedMethod::Inline(R"( static UClass* FindClass(unsigned name) 149 | { 150 | return FindObject(name); 151 | })"), 152 | PredefinedMethod::Inline(R"( template 153 | static T* GetObjectCasted(int32_t index) 154 | { 155 | return static_cast(GetGlobalObjects().GetByIndex(index)); 156 | })"), 157 | PredefinedMethod::Default("bool IsA(UClass* cmp) const", R"(bool UObject::IsA(UClass* cmp) const 158 | { 159 | for (auto super = Class; super; super = static_cast(super->SuperField)) 160 | { 161 | if (super == cmp) 162 | { 163 | return true; 164 | } 165 | } 166 | 167 | return false; 168 | })") 169 | }; 170 | predefinedMethods["Class CoreUObject.Class"] = { 171 | PredefinedMethod::Inline(R"( template 172 | inline T* CreateDefaultObject() 173 | { 174 | return static_cast(CreateDefaultObject()); 175 | })") 176 | }; 177 | 178 | predefinedMethods["ScriptStruct CoreUObject.Vector"] = { 179 | PredefinedMethod::Inline(R"( inline FVector() 180 | : X(0), Y(0), Z(0) { 181 | })"), 182 | PredefinedMethod::Inline(R"( inline FVector(float x, float y, float z) : X(x), Y(y), Z(z) {})"), 183 | PredefinedMethod::Inline(R"( __forceinline FVector operator-(const FVector& V) { 184 | return FVector(X - V.X, Y - V.Y, Z - V.Z); 185 | })"), 186 | PredefinedMethod::Inline(R"( __forceinline FVector operator+(const FVector& V) { 187 | return FVector(X + V.X, Y + V.Y, Z + V.Z); 188 | })"), 189 | PredefinedMethod::Inline(R"( __forceinline FVector operator*(float Scale) const { 190 | return FVector(X * Scale, Y * Scale, Z * Scale); 191 | })"), 192 | PredefinedMethod::Inline(R"( __forceinline FVector operator/(float Scale) const { 193 | const float RScale = 1.f / Scale; 194 | return FVector(X * RScale, Y * RScale, Z * RScale); 195 | })"), 196 | PredefinedMethod::Inline(R"( __forceinline FVector operator+(float A) const { 197 | return FVector(X + A, Y + A, Z + A); 198 | })"), 199 | PredefinedMethod::Inline(R"( __forceinline FVector operator-(float A) const { 200 | return FVector(X - A, Y - A, Z - A); 201 | })"), 202 | PredefinedMethod::Inline(R"( __forceinline FVector operator*(const FVector& V) const { 203 | return FVector(X * V.X, Y * V.Y, Z * V.Z); 204 | })"), 205 | PredefinedMethod::Inline(R"( __forceinline FVector operator/(const FVector& V) const { 206 | return FVector(X / V.X, Y / V.Y, Z / V.Z); 207 | })"), 208 | PredefinedMethod::Inline(R"( __forceinline float operator|(const FVector& V) const { 209 | return X*V.X + Y*V.Y + Z*V.Z; 210 | })"), 211 | PredefinedMethod::Inline(R"( __forceinline float operator^(const FVector& V) const { 212 | return X*V.Y - Y*V.X - Z*V.Z; 213 | })"), 214 | PredefinedMethod::Inline(R"( __forceinline FVector& operator+=(const FVector& v) { 215 | X += v.X; 216 | Y += v.Y; 217 | Z += v.Z; 218 | return *this; 219 | })"), 220 | PredefinedMethod::Inline(R"( __forceinline FVector& operator-=(const FVector& v) { 221 | X -= v.X; 222 | Y -= v.Y; 223 | Z -= v.Z; 224 | return *this; 225 | })"), 226 | PredefinedMethod::Inline(R"( __forceinline FVector& operator*=(const FVector& v) { 227 | X *= v.X; 228 | Y *= v.Y; 229 | Z *= v.Z; 230 | return *this; 231 | })"), 232 | PredefinedMethod::Inline(R"( __forceinline FVector& operator/=(const FVector& v) { 233 | X /= v.X; 234 | Y /= v.Y; 235 | Z /= v.Z; 236 | return *this; 237 | })"), 238 | PredefinedMethod::Inline(R"( __forceinline bool operator==(const FVector& src) const { 239 | return (src.X == X) && (src.Y == Y) && (src.Z == Z); 240 | })"), 241 | PredefinedMethod::Inline(R"( __forceinline bool operator!=(const FVector& src) const { 242 | return (src.X != X) || (src.Y != Y) || (src.Z != Z); 243 | })"), 244 | PredefinedMethod::Inline(R"( __forceinline float Size() const { 245 | return sqrt(X*X + Y*Y + Z*Z); 246 | })"), 247 | PredefinedMethod::Inline(R"( __forceinline float Size2D() const { 248 | return sqrt(X*X + Y*Y); 249 | })"), 250 | PredefinedMethod::Inline(R"( __forceinline float SizeSquared() const { 251 | return X*X + Y*Y + Z*Z; 252 | })"), 253 | PredefinedMethod::Inline(R"( __forceinline float SizeSquared2D() const { 254 | return X*X + Y*Y; 255 | })"), 256 | PredefinedMethod::Inline(R"( __forceinline float Dot(const FVector& vOther) const { 257 | const FVector& a = *this; 258 | return (a.X * vOther.X + a.Y * vOther.Y + a.Z * vOther.Z); 259 | })"), 260 | PredefinedMethod::Inline(R"( __forceinline FVector Normalize() { 261 | FVector vector; 262 | float length = this->Size(); 263 | 264 | if (length != 0) { 265 | vector.X = X / length; 266 | vector.Y = Y / length; 267 | vector.Z = Z / length; 268 | } else 269 | vector.X = vector.Y = 0.0f; 270 | vector.Z = 1.0f; 271 | 272 | return vector; 273 | })") 274 | }; 275 | 276 | predefinedMethods["ScriptStruct CoreUObject.Vector2D"] = { 277 | PredefinedMethod::Inline(R"( inline FVector2D() : X(0), Y(0) {})"), 278 | PredefinedMethod::Inline(R"( inline FVector2D(float x, float y) : X(x), Y(y) {})"), 279 | PredefinedMethod::Inline(R"( __forceinline FVector2D operator-(const FVector2D& V) { 280 | return FVector2D(X - V.X, Y - V.Y); 281 | })"), 282 | PredefinedMethod::Inline(R"( __forceinline FVector2D operator+(const FVector2D& V) { 283 | return FVector2D(X + V.X, Y + V.Y); 284 | })"), 285 | PredefinedMethod::Inline(R"( __forceinline FVector2D operator*(float Scale) const { 286 | return FVector2D(X * Scale, Y * Scale); 287 | })"), 288 | PredefinedMethod::Inline(R"( __forceinline FVector2D operator/(float Scale) const { 289 | const float RScale = 1.f / Scale; 290 | return FVector2D(X * RScale, Y * RScale); 291 | })"), 292 | PredefinedMethod::Inline(R"( __forceinline FVector2D operator+(float A) const { 293 | return FVector2D(X + A, Y + A); 294 | })"), 295 | PredefinedMethod::Inline(R"( __forceinline FVector2D operator-(float A) const { 296 | return FVector2D(X - A, Y - A); 297 | })"), 298 | PredefinedMethod::Inline(R"( __forceinline FVector2D operator*(const FVector2D& V) const { 299 | return FVector2D(X * V.X, Y * V.Y); 300 | })"), 301 | PredefinedMethod::Inline(R"( __forceinline FVector2D operator/(const FVector2D& V) const { 302 | return FVector2D(X / V.X, Y / V.Y); 303 | })"), 304 | PredefinedMethod::Inline(R"( __forceinline float operator|(const FVector2D& V) const { 305 | return X*V.X + Y*V.Y; 306 | })"), 307 | PredefinedMethod::Inline(R"( __forceinline float operator^(const FVector2D& V) const { 308 | return X*V.Y - Y*V.X; 309 | })"), 310 | PredefinedMethod::Inline(R"( __forceinline FVector2D& operator+=(const FVector2D& v) { 311 | X += v.X; 312 | Y += v.Y; 313 | return *this; 314 | })"), 315 | PredefinedMethod::Inline(R"( __forceinline FVector2D& operator-=(const FVector2D& v) { 316 | X -= v.X; 317 | Y -= v.Y; 318 | return *this; 319 | })"), 320 | PredefinedMethod::Inline(R"( __forceinline FVector2D& operator*=(const FVector2D& v) { 321 | X *= v.X; 322 | Y *= v.Y; 323 | return *this; 324 | })"), 325 | PredefinedMethod::Inline(R"( __forceinline FVector2D& operator/=(const FVector2D& v) { 326 | X /= v.X; 327 | Y /= v.Y; 328 | return *this; 329 | })"), 330 | PredefinedMethod::Inline(R"( __forceinline bool operator==(const FVector2D& src) const { 331 | return (src.X == X) && (src.Y == Y); 332 | })"), 333 | PredefinedMethod::Inline(R"( __forceinline bool operator!=(const FVector2D& src) const { 334 | return (src.X != X) || (src.Y != Y); 335 | })"), 336 | PredefinedMethod::Inline(R"( __forceinline float Size() const { 337 | return sqrt(X*X + Y*Y); 338 | })"), 339 | PredefinedMethod::Inline(R"( __forceinline float SizeSquared() const { 340 | return X*X + Y*Y; 341 | })"), 342 | PredefinedMethod::Inline(R"( __forceinline float Dot(const FVector2D& vOther) const { 343 | const FVector2D& a = *this; 344 | return (a.X * vOther.X + a.Y * vOther.Y); 345 | })"), 346 | PredefinedMethod::Inline(R"( __forceinline FVector2D Normalize() { 347 | FVector2D vector; 348 | float length = this->Size(); 349 | 350 | if (length != 0) { 351 | vector.X = X / length; 352 | vector.Y = Y / length; 353 | } else 354 | vector.X = vector.Y = 0.0f; 355 | 356 | return vector; 357 | })") 358 | }; 359 | 360 | predefinedMethods["ScriptStruct CoreUObject.Rotator"] = { 361 | PredefinedMethod::Inline(R"( inline FRotator() : Pitch(0), Yaw(0), Roll(0) {})"), 362 | PredefinedMethod::Inline(R"( inline FRotator(float x, float y, float z) : Pitch(x), Yaw(y), Roll(z) {})"), 363 | PredefinedMethod::Inline(R"( __forceinline FRotator operator+(const FRotator& V) { 364 | return FRotator(Pitch + V.Pitch, Yaw + V.Yaw, Roll + V.Roll); 365 | })"), 366 | PredefinedMethod::Inline(R"( __forceinline FRotator operator-(const FRotator& V) { 367 | return FRotator(Pitch - V.Pitch, Yaw - V.Yaw, Roll - V.Roll); 368 | })"), 369 | PredefinedMethod::Inline(R"( __forceinline FRotator operator*(float Scale) const { 370 | return FRotator(Pitch * Scale, Yaw * Scale, Roll * Scale); 371 | })"), 372 | PredefinedMethod::Inline(R"( __forceinline FRotator operator/(float Scale) const { 373 | const float RScale = 1.f / Scale; 374 | return FRotator(Pitch * RScale, Yaw * RScale, Roll * RScale); 375 | })"), 376 | PredefinedMethod::Inline(R"( __forceinline FRotator operator+(float A) const { 377 | return FRotator(Pitch + A, Yaw + A, Roll + A); 378 | })"), 379 | PredefinedMethod::Inline(R"( __forceinline FRotator operator-(float A) const { 380 | return FRotator(Pitch - A, Yaw - A, Roll - A); 381 | })"), 382 | PredefinedMethod::Inline(R"( __forceinline FRotator operator*(const FRotator& V) const { 383 | return FRotator(Pitch * V.Pitch, Yaw * V.Yaw, Roll * V.Roll); 384 | })"), 385 | PredefinedMethod::Inline(R"( __forceinline FRotator operator/(const FRotator& V) const { 386 | return FRotator(Pitch / V.Pitch, Yaw / V.Yaw, Roll / V.Roll); 387 | })"), 388 | PredefinedMethod::Inline(R"( __forceinline float operator|(const FRotator& V) const { 389 | return Pitch*V.Pitch + Yaw*V.Yaw + Roll*V.Roll; 390 | })"), 391 | PredefinedMethod::Inline(R"( __forceinline FRotator& operator+=(const FRotator& v) { 392 | Pitch += v.Pitch; 393 | Yaw += v.Yaw; 394 | Roll += v.Roll; 395 | return *this; 396 | })"), 397 | PredefinedMethod::Inline(R"( __forceinline FRotator& operator-=(const FRotator& v) { 398 | Pitch -= v.Pitch; 399 | Yaw -= v.Yaw; 400 | Roll -= v.Roll; 401 | return *this; 402 | })"), 403 | PredefinedMethod::Inline(R"( __forceinline FRotator& operator*=(const FRotator& v) { 404 | Pitch *= v.Pitch; 405 | Yaw *= v.Yaw; 406 | Roll *= v.Roll; 407 | return *this; 408 | })"), 409 | PredefinedMethod::Inline(R"( __forceinline FRotator& operator/=(const FRotator& v) { 410 | Pitch /= v.Pitch; 411 | Yaw /= v.Yaw; 412 | Roll /= v.Roll; 413 | return *this; 414 | })"), 415 | PredefinedMethod::Inline(R"( __forceinline float operator^(const FRotator& V) const { 416 | return Pitch*V.Yaw - Yaw*V.Pitch - Roll*V.Roll; 417 | })"), 418 | PredefinedMethod::Inline(R"( __forceinline bool operator==(const FRotator& src) const { 419 | return (src.Pitch == Pitch) && (src.Yaw == Yaw) && (src.Roll == Roll); 420 | })"), 421 | PredefinedMethod::Inline(R"( __forceinline bool operator!=(const FRotator& src) const { 422 | return (src.Pitch != Pitch) || (src.Yaw != Yaw) || (src.Roll != Roll); 423 | })"), 424 | PredefinedMethod::Inline(R"( __forceinline float Size() const { 425 | return sqrt(Pitch*Pitch + Yaw* Yaw + Roll*Roll); 426 | })"), 427 | PredefinedMethod::Inline(R"( __forceinline float SizeSquared() const { 428 | return Pitch*Pitch + Yaw* Yaw + Roll*Roll; 429 | })"), 430 | PredefinedMethod::Inline(R"( __forceinline float Dot(const FRotator& vOther) const { 431 | const FRotator& a = *this; 432 | return (a.Pitch * vOther.Pitch + a.Yaw * vOther.Yaw + a.Roll * vOther.Roll); 433 | })"), 434 | PredefinedMethod::Inline(R"( __forceinline float ClampAxis(float Angle) { 435 | Angle = fmod(Angle, 360.f); 436 | 437 | if (Angle < 0.f) { 438 | Angle += 360.f; 439 | } 440 | 441 | return Angle; 442 | })"), 443 | PredefinedMethod::Inline(R"( __forceinline float NormalizeAxis(float Angle) { 444 | Angle = ClampAxis(Angle); 445 | 446 | if (Angle > 180.f) { 447 | Angle -= 360.f; 448 | } 449 | 450 | return Angle; 451 | })"), 452 | PredefinedMethod::Inline(R"( __forceinline void Normalize() { 453 | Pitch = NormalizeAxis(Pitch); 454 | Yaw = NormalizeAxis(Yaw); 455 | Roll = NormalizeAxis(Roll); 456 | })"), 457 | PredefinedMethod::Inline(R"( __forceinline FRotator GetNormalized() const { 458 | FRotator Rot = *this; 459 | Rot.Normalize(); 460 | return Rot; 461 | })"), 462 | PredefinedMethod::Inline(R"( __forceinline FVector ToVector() { 463 | return FVector(Pitch, Yaw, Roll); 464 | })") 465 | }; 466 | 467 | return true; 468 | } 469 | 470 | std::string GetGameName() const override 471 | { 472 | return "PlayerUnknown's Battlegrounds"; 473 | } 474 | 475 | std::string GetGameNameShort() const override 476 | { 477 | return "PUBG"; 478 | } 479 | 480 | std::string GetGameVersion() const override 481 | { 482 | return "3.5.7.7"; 483 | } 484 | 485 | std::string GetNamespaceName() const override 486 | { 487 | return "Classes"; 488 | } 489 | 490 | std::vector GetIncludes() const override 491 | { 492 | return { }; 493 | } 494 | 495 | std::string GetBasicDeclarations() const override 496 | { 497 | return R"(template 498 | inline Fn GetVFunction(const void *instance, std::size_t index) 499 | { 500 | auto vtable = *reinterpret_cast(const_cast(instance)); 501 | return reinterpret_cast(vtable[index]); 502 | } 503 | 504 | // Credits to namazso <3 505 | static unsigned fnv_hash_runtime(const char* str) { 506 | static constexpr auto k_fnv_prime = 16777619u; 507 | static constexpr auto k_offset_basis = 2166136261u; 508 | 509 | auto hash = k_offset_basis; 510 | do { 511 | hash ^= *str++; 512 | hash *= k_fnv_prime; 513 | } while (*(str - 1) != 0); 514 | 515 | return hash; 516 | } 517 | 518 | class UObject; 519 | 520 | class FUObjectItem 521 | { 522 | public: 523 | UObject* Object; 524 | int32_t Flags; 525 | int32_t ClusterIndex; 526 | int32_t SerialNumber; 527 | 528 | enum class ObjectFlags : int32_t 529 | { 530 | None = 0, 531 | Native = 1 << 25, 532 | Async = 1 << 26, 533 | AsyncLoading = 1 << 27, 534 | Unreachable = 1 << 28, 535 | PendingKill = 1 << 29, 536 | RootSet = 1 << 30, 537 | NoStrongReference = 1 << 31 538 | }; 539 | 540 | inline bool IsUnreachable() const 541 | { 542 | return !!(Flags & static_cast>(ObjectFlags::Unreachable)); 543 | } 544 | inline bool IsPendingKill() const 545 | { 546 | return !!(Flags & static_cast>(ObjectFlags::PendingKill)); 547 | } 548 | }; 549 | 550 | class TUObjectArray 551 | { 552 | public: 553 | inline int32_t Num() const 554 | { 555 | return NumElements; 556 | } 557 | 558 | inline UObject* GetByIndex(int32_t index) const 559 | { 560 | return Objects[index].Object; 561 | } 562 | 563 | inline FUObjectItem* GetItemByIndex(int32_t index) const 564 | { 565 | if (index < NumElements) 566 | { 567 | return &Objects[index]; 568 | } 569 | return nullptr; 570 | } 571 | 572 | private: 573 | FUObjectItem* Objects; 574 | int32_t MaxElements; 575 | int32_t NumElements; 576 | }; 577 | 578 | class FUObjectArray 579 | { 580 | public: 581 | int32_t ObjFirstGCIndex; 582 | int32_t ObjLastNonGCIndex; 583 | int32_t MaxObjectsNotConsideredByGC; 584 | int32_t OpenForDisregardForGC; 585 | TUObjectArray ObjObjects; 586 | }; 587 | 588 | template 589 | struct TArray 590 | { 591 | friend struct FString; 592 | 593 | public: 594 | inline TArray() 595 | { 596 | Data = nullptr; 597 | Count = Max = 0; 598 | }; 599 | 600 | inline TArray(T* data, int32_t number) 601 | { 602 | Data = data; 603 | Count = Max = number; 604 | }; 605 | 606 | inline int Num() const 607 | { 608 | return Count; 609 | }; 610 | 611 | inline T& operator[](int i) 612 | { 613 | return Data[i]; 614 | }; 615 | 616 | inline const T& operator[](int i) const 617 | { 618 | return Data[i]; 619 | }; 620 | 621 | inline bool IsValidIndex(int i) const 622 | { 623 | return i < Num(); 624 | } 625 | 626 | private: 627 | T* Data; 628 | int32_t Count; 629 | int32_t Max; 630 | }; 631 | 632 | class FNameEntry 633 | { 634 | public: 635 | static const auto NAME_WIDE_MASK = 0x1; 636 | static const auto NAME_INDEX_SHIFT = 1; 637 | 638 | int32_t Index; 639 | char UnknownData00[0x04]; 640 | FNameEntry* HashNext; 641 | union 642 | { 643 | char AnsiName[1024]; 644 | wchar_t WideName[1024]; 645 | }; 646 | 647 | inline const int32_t GetIndex() const 648 | { 649 | return Index >> NAME_INDEX_SHIFT; 650 | } 651 | 652 | inline bool IsWide() const 653 | { 654 | return Index & NAME_WIDE_MASK; 655 | } 656 | 657 | inline const char* GetAnsiName() const 658 | { 659 | return AnsiName; 660 | } 661 | 662 | inline const wchar_t* GetWideName() const 663 | { 664 | return WideName; 665 | } 666 | }; 667 | 668 | template 669 | class TStaticIndirectArrayThreadSafeRead 670 | { 671 | public: 672 | inline size_t Num() const 673 | { 674 | return NumElements; 675 | } 676 | 677 | inline bool IsValidIndex(int32_t index) const 678 | { 679 | return index < Num() && index >= 0; 680 | } 681 | 682 | inline ElementType const* const& operator[](int32_t index) const 683 | { 684 | return *GetItemPtr(index); 685 | } 686 | 687 | private: 688 | inline ElementType const* const* GetItemPtr(int32_t Index) const 689 | { 690 | int32_t ChunkIndex = Index / ElementsPerChunk; 691 | int32_t WithinChunkIndex = Index % ElementsPerChunk; 692 | ElementType** Chunk = Chunks[ChunkIndex]; 693 | return Chunk + WithinChunkIndex; 694 | } 695 | 696 | enum 697 | { 698 | ChunkTableSize = (MaxTotalElements + ElementsPerChunk - 1) / ElementsPerChunk 699 | }; 700 | 701 | ElementType** Chunks[ChunkTableSize]; 702 | int32_t NumElements; 703 | int32_t NumChunks; 704 | }; 705 | 706 | using TNameEntryArray = TStaticIndirectArrayThreadSafeRead; 707 | 708 | struct FName 709 | { 710 | union 711 | { 712 | struct 713 | { 714 | int32_t ComparisonIndex; 715 | int32_t Number; 716 | }; 717 | 718 | uint64_t CompositeComparisonValue; 719 | }; 720 | 721 | inline FName() 722 | : ComparisonIndex(0), 723 | Number(0) 724 | { 725 | }; 726 | 727 | inline FName(int32_t i) 728 | : ComparisonIndex(i), 729 | Number(0) 730 | { 731 | }; 732 | 733 | FName(const char* nameToFind) 734 | : ComparisonIndex(0), 735 | Number(0) 736 | { 737 | static std::unordered_set cache; 738 | 739 | for (auto i : cache) 740 | { 741 | if (!std::strcmp(GetGlobalNames()[i]->GetAnsiName(), nameToFind)) 742 | { 743 | ComparisonIndex = i; 744 | 745 | return; 746 | } 747 | } 748 | 749 | for (auto i = 0; i < GetGlobalNames().Num(); ++i) 750 | { 751 | if (GetGlobalNames()[i] != nullptr) 752 | { 753 | if (!std::strcmp(GetGlobalNames()[i]->GetAnsiName(), nameToFind)) 754 | { 755 | cache.insert(i); 756 | 757 | ComparisonIndex = i; 758 | 759 | return; 760 | } 761 | } 762 | } 763 | }; 764 | 765 | static TNameEntryArray *GNames; 766 | static inline TNameEntryArray& GetGlobalNames() 767 | { 768 | return *GNames; 769 | }; 770 | 771 | inline const char* GetName() const 772 | { 773 | return GetGlobalNames()[ComparisonIndex]->GetAnsiName(); 774 | }; 775 | 776 | inline bool operator==(const FName &other) const 777 | { 778 | return ComparisonIndex == other.ComparisonIndex; 779 | }; 780 | }; 781 | 782 | struct FString : private TArray 783 | { 784 | inline FString() 785 | { 786 | }; 787 | 788 | FString(const wchar_t* other) 789 | { 790 | Max = Count = *other ? (int32_t)std::wcslen(other) + 1 : 0; 791 | 792 | if (Count) 793 | { 794 | Data = const_cast(other); 795 | } 796 | }; 797 | 798 | inline bool IsValid() const 799 | { 800 | return Data != nullptr; 801 | } 802 | 803 | inline const wchar_t* c_str() const 804 | { 805 | return Data; 806 | } 807 | 808 | std::string ToString() const 809 | { 810 | std::wstring wstr(Data); 811 | return std::string(wstr.begin(), wstr.end()); 812 | } 813 | }; 814 | 815 | template 816 | class TEnumAsByte 817 | { 818 | public: 819 | inline TEnumAsByte() 820 | { 821 | } 822 | 823 | inline TEnumAsByte(TEnum _value) 824 | : value(static_cast(_value)) 825 | { 826 | } 827 | 828 | explicit inline TEnumAsByte(int32_t _value) 829 | : value(static_cast(_value)) 830 | { 831 | } 832 | 833 | explicit inline TEnumAsByte(uint8_t _value) 834 | : value(_value) 835 | { 836 | } 837 | 838 | inline operator TEnum() const 839 | { 840 | return (TEnum)value; 841 | } 842 | 843 | inline TEnum GetValue() const 844 | { 845 | return (TEnum)value; 846 | } 847 | 848 | private: 849 | uint8_t value; 850 | }; 851 | 852 | class FScriptInterface 853 | { 854 | private: 855 | UObject* ObjectPointer; 856 | void* InterfacePointer; 857 | 858 | public: 859 | inline UObject* GetObject() const 860 | { 861 | return ObjectPointer; 862 | } 863 | 864 | inline UObject*& GetObjectRef() 865 | { 866 | return ObjectPointer; 867 | } 868 | 869 | inline void* GetInterface() const 870 | { 871 | return ObjectPointer != nullptr ? InterfacePointer : nullptr; 872 | } 873 | }; 874 | 875 | template 876 | class TScriptInterface : public FScriptInterface 877 | { 878 | public: 879 | inline InterfaceType* operator->() const 880 | { 881 | return (InterfaceType*)GetInterface(); 882 | } 883 | 884 | inline InterfaceType& operator*() const 885 | { 886 | return *((InterfaceType*)GetInterface()); 887 | } 888 | 889 | inline operator bool() const 890 | { 891 | return GetInterface() != nullptr; 892 | } 893 | }; 894 | 895 | struct FTextData 896 | { 897 | unsigned char UnknownData00[0x28]; 898 | wchar_t* Name; 899 | uint32_t Length; 900 | }; 901 | 902 | struct FText 903 | { 904 | FTextData* Data; 905 | char UnknownData[0x10]; 906 | 907 | wchar_t* Get() 908 | { 909 | if (!Data) return nullptr; 910 | 911 | return Data->Name; 912 | } 913 | }; 914 | 915 | struct FScriptDelegate 916 | { 917 | char UnknownData[0x10]; 918 | }; 919 | 920 | struct FScriptMulticastDelegate 921 | { 922 | char UnknownData[0x10]; 923 | }; 924 | 925 | template 926 | class TMap 927 | { 928 | char UnknownData[0x50]; 929 | }; 930 | 931 | struct FWeakObjectPtr 932 | { 933 | public: 934 | inline bool SerialNumbersMatch(FUObjectItem* ObjectItem) const 935 | { 936 | return ObjectItem->SerialNumber == ObjectSerialNumber; 937 | } 938 | 939 | bool IsValid() const; 940 | 941 | UObject* Get() const; 942 | 943 | int32_t ObjectIndex; 944 | int32_t ObjectSerialNumber; 945 | }; 946 | 947 | template 948 | struct TWeakObjectPtr : private TWeakObjectPtrBase 949 | { 950 | public: 951 | inline T* Get() const 952 | { 953 | return (T*)TWeakObjectPtrBase::Get(); 954 | } 955 | 956 | inline T& operator*() const 957 | { 958 | return *Get(); 959 | } 960 | 961 | inline T* operator->() const 962 | { 963 | return Get(); 964 | } 965 | 966 | inline bool IsValid() const 967 | { 968 | return TWeakObjectPtrBase::IsValid(); 969 | } 970 | }; 971 | 972 | template 973 | class TAutoPointer : public TBASE 974 | { 975 | public: 976 | inline operator T*() const 977 | { 978 | return TBASE::Get(); 979 | } 980 | 981 | inline operator const T*() const 982 | { 983 | return (const T*)TBASE::Get(); 984 | } 985 | 986 | explicit inline operator bool() const 987 | { 988 | return TBASE::Get() != nullptr; 989 | } 990 | }; 991 | 992 | template 993 | class TAutoWeakObjectPtr : public TAutoPointer> 994 | { 995 | public: 996 | }; 997 | 998 | template 999 | class TPersistentObjectPtr 1000 | { 1001 | public: 1002 | FWeakObjectPtr WeakPtr; 1003 | int32_t TagAtLastTest; 1004 | TObjectID ObjectID; 1005 | }; 1006 | 1007 | struct FStringAssetReference_ 1008 | { 1009 | char UnknownData[0x10]; 1010 | }; 1011 | 1012 | class FAssetPtr : public TPersistentObjectPtr 1013 | { 1014 | 1015 | }; 1016 | 1017 | template 1018 | class TAssetPtr : FAssetPtr 1019 | { 1020 | 1021 | }; 1022 | 1023 | struct FUniqueObjectGuid_ 1024 | { 1025 | char UnknownData[0x10]; 1026 | }; 1027 | 1028 | class FLazyObjectPtr : public TPersistentObjectPtr 1029 | { 1030 | 1031 | }; 1032 | 1033 | template 1034 | class TLazyObjectPtr : FLazyObjectPtr 1035 | { 1036 | 1037 | };)"; 1038 | } 1039 | 1040 | std::string GetBasicDefinitions() const override 1041 | { 1042 | return R"(TNameEntryArray* FName::GNames = nullptr; 1043 | FUObjectArray* UObject::GObjects = nullptr; 1044 | 1045 | bool FWeakObjectPtr::IsValid() const 1046 | { 1047 | if (ObjectSerialNumber == 0) 1048 | { 1049 | return false; 1050 | } 1051 | if (ObjectIndex < 0) 1052 | { 1053 | return false; 1054 | } 1055 | auto ObjectItem = UObject::GetGlobalObjects().GetItemByIndex(ObjectIndex); 1056 | if (!ObjectItem) 1057 | { 1058 | return false; 1059 | } 1060 | if (!SerialNumbersMatch(ObjectItem)) 1061 | { 1062 | return false; 1063 | } 1064 | return !(ObjectItem->IsUnreachable() || ObjectItem->IsPendingKill()); 1065 | } 1066 | 1067 | UObject* FWeakObjectPtr::Get() const 1068 | { 1069 | if (IsValid()) 1070 | { 1071 | auto ObjectItem = UObject::GetGlobalObjects().GetItemByIndex(ObjectIndex); 1072 | if (ObjectItem) 1073 | { 1074 | return ObjectItem->Object; 1075 | } 1076 | } 1077 | return nullptr; 1078 | } 1079 | )"; 1080 | } 1081 | }; 1082 | 1083 | Generator _generator; 1084 | IGenerator* generator = &_generator; 1085 | -------------------------------------------------------------------------------- /src/GenericTypes.cpp: -------------------------------------------------------------------------------- 1 | #include "IGenerator.hpp" 2 | #include "UE4/GenericTypes.hpp" 3 | #include "ObjectsStore.hpp" 4 | #include "NamesStore.hpp" 5 | #include "NameValidator.hpp" 6 | 7 | #include "EngineClasses.hpp" 8 | 9 | //--------------------------------------------------------------------------- 10 | //UEObject 11 | //--------------------------------------------------------------------------- 12 | size_t UEObject::GetIndex() const 13 | { 14 | return object->InternalIndex; 15 | } 16 | //--------------------------------------------------------------------------- 17 | UEClass UEObject::GetClass() const 18 | { 19 | return UEClass(object->Class); 20 | } 21 | //--------------------------------------------------------------------------- 22 | UEObject UEObject::GetOuter() const 23 | { 24 | return UEObject(object->Outer); 25 | } 26 | //--------------------------------------------------------------------------- 27 | std::string UEObject::GetName() const 28 | { 29 | auto name = NamesStore().GetById(object->Name.ComparisonIndex); 30 | if (object->Name.Number > 0) 31 | { 32 | name += '_' + std::to_string(object->Name.Number); 33 | } 34 | 35 | auto pos = name.rfind('/'); 36 | if (pos == std::string::npos) 37 | { 38 | return name; 39 | } 40 | 41 | return name.substr(pos + 1); 42 | } 43 | //--------------------------------------------------------------------------- 44 | UEClass UEObject::StaticClass() 45 | { 46 | static auto c = ObjectsStore().FindClass("Class CoreUObject.Object"); 47 | return c; 48 | } 49 | //--------------------------------------------------------------------------- 50 | //UEField 51 | //--------------------------------------------------------------------------- 52 | UEField UEField::GetNext() const 53 | { 54 | return UEField(static_cast(object)->Next); 55 | } 56 | //--------------------------------------------------------------------------- 57 | UEClass UEField::StaticClass() 58 | { 59 | static auto c = ObjectsStore().FindClass("Class CoreUObject.Field"); 60 | return c; 61 | } 62 | //--------------------------------------------------------------------------- 63 | //UEEnum 64 | //--------------------------------------------------------------------------- 65 | std::vector UEEnum::GetNames() const 66 | { 67 | std::vector buffer; 68 | auto& names = static_cast(object)->Names; 69 | 70 | for (auto i = 0; i < names.Num(); ++i) 71 | { 72 | buffer.push_back(NamesStore().GetById(names[i].Key.ComparisonIndex)); 73 | } 74 | 75 | return buffer; 76 | } 77 | //--------------------------------------------------------------------------- 78 | UEClass UEEnum::StaticClass() 79 | { 80 | static auto c = ObjectsStore().FindClass("Class CoreUObject.Enum"); 81 | return c; 82 | } 83 | //--------------------------------------------------------------------------- 84 | //UEConst 85 | //--------------------------------------------------------------------------- 86 | std::string UEConst::GetValue() const 87 | { 88 | throw; 89 | } 90 | //--------------------------------------------------------------------------- 91 | UEClass UEConst::StaticClass() 92 | { 93 | //not supported by UE4 94 | return nullptr; 95 | } 96 | //--------------------------------------------------------------------------- 97 | //UEStruct 98 | //--------------------------------------------------------------------------- 99 | UEStruct UEStruct::GetSuper() const 100 | { 101 | return UEStruct(static_cast(object)->SuperField); 102 | } 103 | //--------------------------------------------------------------------------- 104 | UEField UEStruct::GetChildren() const 105 | { 106 | return UEField(static_cast(object)->Children); 107 | } 108 | //--------------------------------------------------------------------------- 109 | size_t UEStruct::GetPropertySize() const 110 | { 111 | return static_cast(object)->PropertySize; 112 | } 113 | //--------------------------------------------------------------------------- 114 | UEClass UEStruct::StaticClass() 115 | { 116 | static auto c = ObjectsStore().FindClass("Class CoreUObject.Struct"); 117 | return c; 118 | } 119 | //--------------------------------------------------------------------------- 120 | //UEScriptStruct 121 | //--------------------------------------------------------------------------- 122 | UEClass UEScriptStruct::StaticClass() 123 | { 124 | static auto c = ObjectsStore().FindClass("Class CoreUObject.ScriptStruct"); 125 | return c; 126 | } 127 | //--------------------------------------------------------------------------- 128 | //UEFunction 129 | //--------------------------------------------------------------------------- 130 | UEFunctionFlags UEFunction::GetFunctionFlags() const 131 | { 132 | return static_cast(static_cast(object)->FunctionFlags); 133 | } 134 | //--------------------------------------------------------------------------- 135 | UEClass UEFunction::StaticClass() 136 | { 137 | static auto c = ObjectsStore().FindClass("Class CoreUObject.Function"); 138 | return c; 139 | } 140 | //--------------------------------------------------------------------------- 141 | //UEClass 142 | //--------------------------------------------------------------------------- 143 | UEClass UEClass::StaticClass() 144 | { 145 | static auto c = ObjectsStore().FindClass("Class CoreUObject.Class"); 146 | return c; 147 | } 148 | //--------------------------------------------------------------------------- 149 | //UEProperty 150 | //--------------------------------------------------------------------------- 151 | size_t UEProperty::GetArrayDim() const 152 | { 153 | return static_cast(object)->ArrayDim; 154 | } 155 | //--------------------------------------------------------------------------- 156 | size_t UEProperty::GetElementSize() const 157 | { 158 | return static_cast(object)->ElementSize; 159 | } 160 | //--------------------------------------------------------------------------- 161 | UEPropertyFlags UEProperty::GetPropertyFlags() const 162 | { 163 | return static_cast(static_cast(object)->PropertyFlags.A); 164 | } 165 | //--------------------------------------------------------------------------- 166 | size_t UEProperty::GetOffset() const 167 | { 168 | return static_cast(object)->Offset; 169 | } 170 | //--------------------------------------------------------------------------- 171 | UEClass UEProperty::StaticClass() 172 | { 173 | static auto c = ObjectsStore().FindClass("Class CoreUObject.Property"); 174 | return c; 175 | } 176 | //--------------------------------------------------------------------------- 177 | //UENumericProperty 178 | //--------------------------------------------------------------------------- 179 | UEClass UENumericProperty::StaticClass() 180 | { 181 | static auto c = ObjectsStore().FindClass("Class CoreUObject.NumericProperty"); 182 | return c; 183 | } 184 | //--------------------------------------------------------------------------- 185 | //UEByteProperty 186 | //--------------------------------------------------------------------------- 187 | UEEnum UEByteProperty::GetEnum() const 188 | { 189 | return UEEnum(static_cast(object)->Enum); 190 | } 191 | //--------------------------------------------------------------------------- 192 | UEProperty::Info UEByteProperty::GetInfo() const 193 | { 194 | if (IsEnum()) 195 | { 196 | return Info::Create(PropertyType::Primitive, sizeof(uint8_t), false, "TEnumAsByte<" + MakeUniqueCppName(GetEnum()) + ">"); 197 | } 198 | return Info::Create(PropertyType::Primitive, sizeof(uint8_t), false, "unsigned char"); 199 | } 200 | //--------------------------------------------------------------------------- 201 | UEClass UEByteProperty::StaticClass() 202 | { 203 | static auto c = ObjectsStore().FindClass("Class CoreUObject.ByteProperty"); 204 | return c; 205 | } 206 | //--------------------------------------------------------------------------- 207 | //UEUInt16Property 208 | //--------------------------------------------------------------------------- 209 | UEProperty::Info UEUInt16Property::GetInfo() const 210 | { 211 | return Info::Create(PropertyType::Primitive, sizeof(uint16_t), false, "uint16_t"); 212 | } 213 | //--------------------------------------------------------------------------- 214 | UEClass UEUInt16Property::StaticClass() 215 | { 216 | static auto c = ObjectsStore().FindClass("Class CoreUObject.UInt16Property"); 217 | return c; 218 | } 219 | //--------------------------------------------------------------------------- 220 | //UEUInt32Property 221 | //--------------------------------------------------------------------------- 222 | UEProperty::Info UEUInt32Property::GetInfo() const 223 | { 224 | return Info::Create(PropertyType::Primitive, sizeof(uint32_t), false, "uint32_t"); 225 | } 226 | //--------------------------------------------------------------------------- 227 | UEClass UEUInt32Property::StaticClass() 228 | { 229 | static auto c = ObjectsStore().FindClass("Class CoreUObject.UInt32Property"); 230 | return c; 231 | } 232 | //--------------------------------------------------------------------------- 233 | //UEUInt64Property 234 | //--------------------------------------------------------------------------- 235 | UEProperty::Info UEUInt64Property::GetInfo() const 236 | { 237 | return Info::Create(PropertyType::Primitive, sizeof(uint64_t), false, "uint64_t"); 238 | } 239 | //--------------------------------------------------------------------------- 240 | UEClass UEUInt64Property::StaticClass() 241 | { 242 | static auto c = ObjectsStore().FindClass("Class CoreUObject.UInt64Property"); 243 | return c; 244 | } 245 | //--------------------------------------------------------------------------- 246 | //UEInt8Property 247 | //--------------------------------------------------------------------------- 248 | UEProperty::Info UEInt8Property::GetInfo() const 249 | { 250 | return Info::Create(PropertyType::Primitive, sizeof(int8_t), false, "int8_t"); 251 | } 252 | //--------------------------------------------------------------------------- 253 | UEClass UEInt8Property::StaticClass() 254 | { 255 | static auto c = ObjectsStore().FindClass("Class CoreUObject.Int8Property"); 256 | return c; 257 | } 258 | //--------------------------------------------------------------------------- 259 | //UEInt16Property 260 | //--------------------------------------------------------------------------- 261 | UEProperty::Info UEInt16Property::GetInfo() const 262 | { 263 | return Info::Create(PropertyType::Primitive, sizeof(int16_t), false, "int16_t"); 264 | } 265 | //--------------------------------------------------------------------------- 266 | UEClass UEInt16Property::StaticClass() 267 | { 268 | static auto c = ObjectsStore().FindClass("Class CoreUObject.Int16Property"); 269 | return c; 270 | } 271 | //--------------------------------------------------------------------------- 272 | //UEIntProperty 273 | //--------------------------------------------------------------------------- 274 | UEProperty::Info UEIntProperty::GetInfo() const 275 | { 276 | return Info::Create(PropertyType::Primitive, sizeof(int), false, "int"); 277 | } 278 | //--------------------------------------------------------------------------- 279 | UEClass UEIntProperty::StaticClass() 280 | { 281 | static auto c = ObjectsStore().FindClass("Class CoreUObject.IntProperty"); 282 | return c; 283 | } 284 | //--------------------------------------------------------------------------- 285 | //UEInt64Property 286 | //--------------------------------------------------------------------------- 287 | UEProperty::Info UEInt64Property::GetInfo() const 288 | { 289 | return Info::Create(PropertyType::Primitive, sizeof(int64_t), false, "int64_t"); 290 | } 291 | //--------------------------------------------------------------------------- 292 | UEClass UEInt64Property::StaticClass() 293 | { 294 | static auto c = ObjectsStore().FindClass("Class CoreUObject.Int64Property"); 295 | return c; 296 | } 297 | //--------------------------------------------------------------------------- 298 | //UEFloatProperty 299 | //--------------------------------------------------------------------------- 300 | UEProperty::Info UEFloatProperty::GetInfo() const 301 | { 302 | return Info::Create(PropertyType::Primitive, sizeof(float), false, "float"); 303 | } 304 | //--------------------------------------------------------------------------- 305 | UEClass UEFloatProperty::StaticClass() 306 | { 307 | static auto c = ObjectsStore().FindClass("Class CoreUObject.FloatProperty"); 308 | return c; 309 | } 310 | //--------------------------------------------------------------------------- 311 | //UEDoubleProperty 312 | //--------------------------------------------------------------------------- 313 | UEProperty::Info UEDoubleProperty::GetInfo() const 314 | { 315 | return Info::Create(PropertyType::Primitive, sizeof(double), false, "double"); 316 | } 317 | //--------------------------------------------------------------------------- 318 | UEClass UEDoubleProperty::StaticClass() 319 | { 320 | static auto c = ObjectsStore().FindClass("Class CoreUObject.DoubleProperty"); 321 | return c; 322 | } 323 | //--------------------------------------------------------------------------- 324 | //UEBoolProperty 325 | //--------------------------------------------------------------------------- 326 | uint8_t UEBoolProperty::GetFieldSize() const 327 | { 328 | return static_cast(object)->FieldSize; 329 | } 330 | //--------------------------------------------------------------------------- 331 | uint8_t UEBoolProperty::GetByteOffset() const 332 | { 333 | return static_cast(object)->ByteOffset; 334 | } 335 | //--------------------------------------------------------------------------- 336 | uint8_t UEBoolProperty::GetByteMask() const 337 | { 338 | return static_cast(object)->ByteMask; 339 | } 340 | //--------------------------------------------------------------------------- 341 | uint8_t UEBoolProperty::GetFieldMask() const 342 | { 343 | return static_cast(object)->FieldMask; 344 | } 345 | //--------------------------------------------------------------------------- 346 | UEProperty::Info UEBoolProperty::GetInfo() const 347 | { 348 | if (IsNativeBool()) 349 | { 350 | return Info::Create(PropertyType::Primitive, sizeof(bool), false, "bool"); 351 | } 352 | return Info::Create(PropertyType::Primitive, sizeof(unsigned char), false, "unsigned char"); 353 | } 354 | //--------------------------------------------------------------------------- 355 | UEClass UEBoolProperty::StaticClass() 356 | { 357 | static auto c = ObjectsStore().FindClass("Class CoreUObject.BoolProperty"); 358 | return c; 359 | } 360 | //--------------------------------------------------------------------------- 361 | //UEObjectPropertyBase 362 | //--------------------------------------------------------------------------- 363 | UEClass UEObjectPropertyBase::GetPropertyClass() const 364 | { 365 | return UEClass(static_cast(object)->PropertyClass); 366 | } 367 | //--------------------------------------------------------------------------- 368 | UEClass UEObjectPropertyBase::StaticClass() 369 | { 370 | static auto c = ObjectsStore().FindClass("Class CoreUObject.ObjectPropertyBase"); 371 | return c; 372 | } 373 | //--------------------------------------------------------------------------- 374 | //UEObjectProperty 375 | //--------------------------------------------------------------------------- 376 | UEProperty::Info UEObjectProperty::GetInfo() const 377 | { 378 | return Info::Create(PropertyType::Primitive, sizeof(void*), false, "class " + MakeValidName(GetPropertyClass().GetNameCPP()) + "*"); 379 | } 380 | //--------------------------------------------------------------------------- 381 | UEClass UEObjectProperty::StaticClass() 382 | { 383 | static auto c = ObjectsStore().FindClass("Class CoreUObject.ObjectProperty"); 384 | return c; 385 | } 386 | //--------------------------------------------------------------------------- 387 | //UEClassProperty 388 | //--------------------------------------------------------------------------- 389 | UEClass UEClassProperty::GetMetaClass() const 390 | { 391 | return UEClass(static_cast(object)->MetaClass); 392 | } 393 | //--------------------------------------------------------------------------- 394 | UEProperty::Info UEClassProperty::GetInfo() const 395 | { 396 | return Info::Create(PropertyType::Primitive, sizeof(void*), false, "class " + MakeValidName(GetMetaClass().GetNameCPP()) + "*"); 397 | } 398 | //--------------------------------------------------------------------------- 399 | UEClass UEClassProperty::StaticClass() 400 | { 401 | static auto c = ObjectsStore().FindClass("Class CoreUObject.ClassProperty"); 402 | return c; 403 | } 404 | //--------------------------------------------------------------------------- 405 | //UEInterfaceProperty 406 | //--------------------------------------------------------------------------- 407 | UEClass UEInterfaceProperty::GetInterfaceClass() const 408 | { 409 | return UEClass(static_cast(object)->InterfaceClass); 410 | } 411 | //--------------------------------------------------------------------------- 412 | UEProperty::Info UEInterfaceProperty::GetInfo() const 413 | { 414 | return Info::Create(PropertyType::PredefinedStruct, sizeof(FScriptInterface), true, "TScriptInterface"); 415 | } 416 | //--------------------------------------------------------------------------- 417 | UEClass UEInterfaceProperty::StaticClass() 418 | { 419 | static auto c = ObjectsStore().FindClass("Class CoreUObject.InterfaceProperty"); 420 | return c; 421 | } 422 | //--------------------------------------------------------------------------- 423 | //UEWeakObjectProperty 424 | //--------------------------------------------------------------------------- 425 | UEProperty::Info UEWeakObjectProperty::GetInfo() const 426 | { 427 | return Info::Create(PropertyType::Container, sizeof(FWeakObjectPtr), false, "TWeakObjectPtr"); 428 | } 429 | //--------------------------------------------------------------------------- 430 | UEClass UEWeakObjectProperty::StaticClass() 431 | { 432 | static auto c = ObjectsStore().FindClass("Class CoreUObject.WeakObjectProperty"); 433 | return c; 434 | } 435 | //--------------------------------------------------------------------------- 436 | //UELazyObjectProperty 437 | //--------------------------------------------------------------------------- 438 | UEProperty::Info UELazyObjectProperty::GetInfo() const 439 | { 440 | return Info::Create(PropertyType::Container, sizeof(FLazyObjectPtr), false, "TLazyObjectPtr"); 441 | } 442 | //--------------------------------------------------------------------------- 443 | UEClass UELazyObjectProperty::StaticClass() 444 | { 445 | static auto c = ObjectsStore().FindClass("Class CoreUObject.LazyObjectProperty"); 446 | return c; 447 | } 448 | //--------------------------------------------------------------------------- 449 | //UEAssetObjectProperty 450 | //--------------------------------------------------------------------------- 451 | UEProperty::Info UEAssetObjectProperty::GetInfo() const 452 | { 453 | return Info::Create(PropertyType::Container, sizeof(FAssetPtr), false, "TAssetPtr"); 454 | } 455 | //--------------------------------------------------------------------------- 456 | UEClass UEAssetObjectProperty::StaticClass() 457 | { 458 | static auto c = ObjectsStore().FindClass("Class CoreUObject.AssetObjectProperty"); 459 | return c; 460 | } 461 | //--------------------------------------------------------------------------- 462 | //UEAssetClassProperty 463 | //--------------------------------------------------------------------------- 464 | UEClass UEAssetClassProperty::GetMetaClass() const 465 | { 466 | return UEClass(static_cast(object)->MetaClass); 467 | } 468 | //--------------------------------------------------------------------------- 469 | UEProperty::Info UEAssetClassProperty::GetInfo() const 470 | { 471 | return Info::Create(PropertyType::Primitive, sizeof(uint8_t), false, ""); 472 | } 473 | //--------------------------------------------------------------------------- 474 | UEClass UEAssetClassProperty::StaticClass() 475 | { 476 | static auto c = ObjectsStore().FindClass("Class CoreUObject.AssetClassProperty"); 477 | return c; 478 | } 479 | //--------------------------------------------------------------------------- 480 | //UENameProperty 481 | //--------------------------------------------------------------------------- 482 | UEProperty::Info UENameProperty::GetInfo() const 483 | { 484 | return Info::Create(PropertyType::PredefinedStruct, sizeof(FName), true, "struct FName"); 485 | } 486 | //--------------------------------------------------------------------------- 487 | UEClass UENameProperty::StaticClass() 488 | { 489 | static auto c = ObjectsStore().FindClass("Class CoreUObject.NameProperty"); 490 | return c; 491 | } 492 | //--------------------------------------------------------------------------- 493 | //UEStructProperty 494 | //--------------------------------------------------------------------------- 495 | UEScriptStruct UEStructProperty::GetStruct() const 496 | { 497 | return UEScriptStruct(static_cast(object)->Struct); 498 | } 499 | //--------------------------------------------------------------------------- 500 | UEProperty::Info UEStructProperty::GetInfo() const 501 | { 502 | return Info::Create(PropertyType::CustomStruct, GetElementSize(), true, "struct " + MakeUniqueCppName(GetStruct())); 503 | } 504 | //--------------------------------------------------------------------------- 505 | UEClass UEStructProperty::StaticClass() 506 | { 507 | static auto c = ObjectsStore().FindClass("Class CoreUObject.StructProperty"); 508 | return c; 509 | } 510 | //--------------------------------------------------------------------------- 511 | //UEStrProperty 512 | //--------------------------------------------------------------------------- 513 | UEProperty::Info UEStrProperty::GetInfo() const 514 | { 515 | return Info::Create(PropertyType::PredefinedStruct, sizeof(FString), true, "struct FString"); 516 | } 517 | //--------------------------------------------------------------------------- 518 | UEClass UEStrProperty::StaticClass() 519 | { 520 | static auto c = ObjectsStore().FindClass("Class CoreUObject.StrProperty"); 521 | return c; 522 | } 523 | //--------------------------------------------------------------------------- 524 | //UETextProperty 525 | //--------------------------------------------------------------------------- 526 | UEProperty::Info UETextProperty::GetInfo() const 527 | { 528 | return Info::Create(PropertyType::PredefinedStruct, sizeof(FText), true, "struct FText"); 529 | } 530 | //--------------------------------------------------------------------------- 531 | UEClass UETextProperty::StaticClass() 532 | { 533 | static auto c = ObjectsStore().FindClass("Class CoreUObject.TextProperty"); 534 | return c; 535 | } 536 | //--------------------------------------------------------------------------- 537 | //UEArrayProperty 538 | //--------------------------------------------------------------------------- 539 | UEProperty UEArrayProperty::GetInner() const 540 | { 541 | return UEProperty(static_cast(object)->Inner); 542 | } 543 | //--------------------------------------------------------------------------- 544 | UEProperty::Info UEArrayProperty::GetInfo() const 545 | { 546 | auto inner = GetInner().GetInfo(); 547 | if (inner.Type != PropertyType::Unknown) 548 | { 549 | extern IGenerator* generator; 550 | 551 | return Info::Create(PropertyType::Container, sizeof(TArray), false, "TArray<" + generator->GetOverrideType(inner.CppType) + ">"); 552 | } 553 | 554 | return { PropertyType::Unknown }; 555 | } 556 | //--------------------------------------------------------------------------- 557 | UEClass UEArrayProperty::StaticClass() 558 | { 559 | static auto c = ObjectsStore().FindClass("Class CoreUObject.ArrayProperty"); 560 | return c; 561 | } 562 | //--------------------------------------------------------------------------- 563 | //UEMapProperty 564 | //--------------------------------------------------------------------------- 565 | UEProperty UEMapProperty::GetKeyProperty() const 566 | { 567 | return UEProperty(static_cast(object)->KeyProp); 568 | } 569 | //--------------------------------------------------------------------------- 570 | UEProperty UEMapProperty::GetValueProperty() const 571 | { 572 | return UEProperty(static_cast(object)->ValueProp); 573 | } 574 | //--------------------------------------------------------------------------- 575 | UEProperty::Info UEMapProperty::GetInfo() const 576 | { 577 | auto key = GetKeyProperty().GetInfo(); 578 | auto value = GetValueProperty().GetInfo(); 579 | if (key.Type != PropertyType::Unknown && value.Type != PropertyType::Unknown) 580 | { 581 | extern IGenerator* generator; 582 | 583 | return Info::Create(PropertyType::Container, 0x50, false, "TMap<" + generator->GetOverrideType(key.CppType) + ", " + generator->GetOverrideType(value.CppType) + ">"); 584 | } 585 | 586 | return { PropertyType::Unknown }; 587 | } 588 | //--------------------------------------------------------------------------- 589 | UEClass UEMapProperty::StaticClass() 590 | { 591 | static auto c = ObjectsStore().FindClass("Class CoreUObject.MapProperty"); 592 | return c; 593 | } 594 | //--------------------------------------------------------------------------- 595 | //UEDelegateProperty 596 | //--------------------------------------------------------------------------- 597 | UEFunction UEDelegateProperty::GetSignatureFunction() const 598 | { 599 | return UEFunction(static_cast(object)->SignatureFunction); 600 | } 601 | //--------------------------------------------------------------------------- 602 | UEProperty::Info UEDelegateProperty::GetInfo() const 603 | { 604 | return Info::Create(PropertyType::PredefinedStruct, sizeof(FScriptDelegate), true, "struct FScriptDelegate"); 605 | } 606 | //--------------------------------------------------------------------------- 607 | UEClass UEDelegateProperty::StaticClass() 608 | { 609 | static auto c = ObjectsStore().FindClass("Class CoreUObject.DelegateProperty"); 610 | return c; 611 | } 612 | //--------------------------------------------------------------------------- 613 | //UEMulticastDelegateProperty 614 | //--------------------------------------------------------------------------- 615 | UEFunction UEMulticastDelegateProperty::GetSignatureFunction() const 616 | { 617 | return UEFunction(static_cast(object)->SignatureFunction); 618 | } 619 | //--------------------------------------------------------------------------- 620 | UEProperty::Info UEMulticastDelegateProperty::GetInfo() const 621 | { 622 | return Info::Create(PropertyType::PredefinedStruct, sizeof(FScriptMulticastDelegate), true, "struct FScriptMulticastDelegate"); 623 | } 624 | //--------------------------------------------------------------------------- 625 | UEClass UEMulticastDelegateProperty::StaticClass() 626 | { 627 | static auto c = ObjectsStore().FindClass("Class CoreUObject.MulticastDelegateProperty"); 628 | return c; 629 | } 630 | //--------------------------------------------------------------------------- 631 | //UEEnumProperty 632 | //--------------------------------------------------------------------------- 633 | UENumericProperty UEEnumProperty::GetUnderlyingProperty() const 634 | { 635 | return UENumericProperty(static_cast(object)->UnderlyingProp); 636 | } 637 | //--------------------------------------------------------------------------- 638 | UEEnum UEEnumProperty::GetEnum() const 639 | { 640 | return UEEnum(static_cast(object)->Enum); 641 | } 642 | //--------------------------------------------------------------------------- 643 | UEProperty::Info UEEnumProperty::GetInfo() const 644 | { 645 | return Info::Create(PropertyType::Primitive, sizeof(uint8_t), false, MakeUniqueCppName(GetEnum())); 646 | } 647 | //--------------------------------------------------------------------------- 648 | UEClass UEEnumProperty::StaticClass() 649 | { 650 | static auto c = ObjectsStore().FindClass("Class CoreUObject.EnumProperty"); 651 | return c; 652 | } 653 | //--------------------------------------------------------------------------- 654 | 655 | void* UEObject::GetAddress() const 656 | { 657 | return object; 658 | } 659 | 660 | UEObject UEObject::GetPackageObject() const 661 | { 662 | UEObject package(nullptr); 663 | 664 | for (auto outer = GetOuter(); outer.IsValid(); outer = outer.GetOuter()) 665 | { 666 | package = outer; 667 | } 668 | 669 | return package; 670 | } 671 | 672 | std::string UEObject::GetFullName() const 673 | { 674 | if (GetClass().IsValid()) 675 | { 676 | std::string temp; 677 | 678 | for (auto outer = GetOuter(); outer.IsValid(); outer = outer.GetOuter()) 679 | { 680 | temp = outer.GetName() + "." + temp; 681 | } 682 | 683 | std::string name = GetClass().GetName(); 684 | name += " "; 685 | name += temp; 686 | name += GetName(); 687 | 688 | return name; 689 | } 690 | 691 | return std::string("(null)"); 692 | } 693 | 694 | std::string UEObject::GetNameCPP() const 695 | { 696 | std::string name; 697 | 698 | if (IsA()) 699 | { 700 | auto c = Cast(); 701 | while (c.IsValid()) 702 | { 703 | const auto className = c.GetName(); 704 | if (className == "Actor") 705 | { 706 | name += "A"; 707 | break; 708 | } 709 | if (className == "Object") 710 | { 711 | name += "U"; 712 | break; 713 | } 714 | 715 | c = c.GetSuper().Cast(); 716 | } 717 | } 718 | else 719 | { 720 | name += "F"; 721 | } 722 | 723 | name += GetName(); 724 | 725 | return name; 726 | } 727 | 728 | UEProperty::Info UEProperty::GetInfo() const 729 | { 730 | if (IsValid()) 731 | { 732 | if (IsA()) 733 | { 734 | return Cast().GetInfo(); 735 | } 736 | if (IsA()) 737 | { 738 | return Cast().GetInfo(); 739 | } 740 | if (IsA()) 741 | { 742 | return Cast().GetInfo(); 743 | } 744 | if (IsA()) 745 | { 746 | return Cast().GetInfo(); 747 | } 748 | if (IsA()) 749 | { 750 | return Cast().GetInfo(); 751 | } 752 | if (IsA()) 753 | { 754 | return Cast().GetInfo(); 755 | } 756 | if (IsA()) 757 | { 758 | return Cast().GetInfo(); 759 | } 760 | if (IsA()) 761 | { 762 | return Cast().GetInfo(); 763 | } 764 | if (IsA()) 765 | { 766 | return Cast().GetInfo(); 767 | } 768 | if (IsA()) 769 | { 770 | return Cast().GetInfo(); 771 | } 772 | if (IsA()) 773 | { 774 | return Cast().GetInfo(); 775 | } 776 | if (IsA()) 777 | { 778 | return Cast().GetInfo(); 779 | } 780 | if (IsA()) 781 | { 782 | return Cast().GetInfo(); 783 | } 784 | if (IsA()) 785 | { 786 | return Cast().GetInfo(); 787 | } 788 | if (IsA()) 789 | { 790 | return Cast().GetInfo(); 791 | } 792 | if (IsA()) 793 | { 794 | return Cast().GetInfo(); 795 | } 796 | if (IsA()) 797 | { 798 | return Cast().GetInfo(); 799 | } 800 | if (IsA()) 801 | { 802 | return Cast().GetInfo(); 803 | } 804 | if (IsA()) 805 | { 806 | return Cast().GetInfo(); 807 | } 808 | if (IsA()) 809 | { 810 | return Cast().GetInfo(); 811 | } 812 | if (IsA()) 813 | { 814 | return Cast().GetInfo(); 815 | } 816 | if (IsA()) 817 | { 818 | return Cast().GetInfo(); 819 | } 820 | if (IsA()) 821 | { 822 | return Cast().GetInfo(); 823 | } 824 | if (IsA()) 825 | { 826 | return Cast().GetInfo(); 827 | } 828 | if (IsA()) 829 | { 830 | return Cast().GetInfo(); 831 | } 832 | if (IsA()) 833 | { 834 | return Cast().GetInfo(); 835 | } 836 | if (IsA()) 837 | { 838 | return Cast().GetInfo(); 839 | } 840 | } 841 | return { PropertyType::Unknown }; 842 | } 843 | 844 | //--------------------------------------------------------------------------- 845 | //UEByteProperty 846 | //--------------------------------------------------------------------------- 847 | bool UEByteProperty::IsEnum() const 848 | { 849 | return GetEnum().IsValid(); 850 | } 851 | //--------------------------------------------------------------------------- 852 | //UEBoolProperty 853 | //--------------------------------------------------------------------------- 854 | 855 | int GetBitPosition(uint8_t value) 856 | { 857 | int i4 = !(value & 0xf) << 2; 858 | value >>= i4; 859 | 860 | int i2 = !(value & 0x3) << 1; 861 | value >>= i2; 862 | 863 | int i1 = !(value & 0x1); 864 | 865 | int i0 = (value >> i1) & 1 ? 0 : -8; 866 | 867 | return i4 + i2 + i1 + i0; 868 | } 869 | 870 | std::array UEBoolProperty::GetMissingBitsCount(const UEBoolProperty& other) const 871 | { 872 | // If there is no previous bitfield member, just calculate the missing bits. 873 | if (!other.IsValid()) 874 | { 875 | return { GetBitPosition(GetByteMask()), -1 }; 876 | } 877 | 878 | // If both bitfield member belong to the same byte, calculate the bit position difference. 879 | if (GetOffset() == other.GetOffset()) 880 | { 881 | return { GetBitPosition(GetByteMask()) - GetBitPosition(other.GetByteMask()) - 1, -1 }; 882 | } 883 | 884 | // If they have different offsets, we need two distances 885 | // |00001000|00100000| 886 | // 1. ^---^ 887 | // 2. ^--^ 888 | 889 | return { std::numeric_limits::digits - GetBitPosition(other.GetByteMask()) - 1, GetBitPosition(GetByteMask()) }; 890 | } -------------------------------------------------------------------------------- /src/IGenerator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class IGenerator 9 | { 10 | public: 11 | virtual ~IGenerator() = default; 12 | 13 | /// 14 | /// Initializes this object. 15 | /// Add predefined types, ... 16 | /// 17 | /// The module handle. 18 | /// true if it succeeds, false if it fails. 19 | virtual bool Initialize(void* module) = 0; 20 | 21 | /// 22 | /// Gets output directory where the files are getting stored. 23 | /// The name of the game gets appended to this directory. 24 | /// 25 | /// The output directory. 26 | virtual std::string GetOutputDirectory() const 27 | { 28 | return "D:/SDK_GEN"; 29 | } 30 | 31 | /// 32 | /// Gets the name of the game. 33 | /// 34 | /// The game name. 35 | virtual std::string GetGameName() const = 0; 36 | 37 | /// 38 | /// Gets the short name of the game. 39 | /// 40 | /// The short name. 41 | virtual std::string GetGameNameShort() const = 0; 42 | 43 | /// 44 | /// Gets the version of the game. 45 | /// 46 | /// The version of the game. 47 | virtual std::string GetGameVersion() const = 0; 48 | 49 | /// 50 | /// Check if the generator should dump the object and name arrays. 51 | /// 52 | /// true if the arrays should get dumped. 53 | virtual bool ShouldDumpArrays() const 54 | { 55 | return true; 56 | } 57 | 58 | /// 59 | /// Check if the generator should generate empty files (no classes, structs, ...). 60 | /// 61 | /// true if empty files should get generated. 62 | virtual bool ShouldGenerateEmptyFiles() const 63 | { 64 | return false; 65 | } 66 | 67 | /// 68 | /// Check if the generated classes should use strings to identify objects. 69 | /// If false the generated classes use the object index. 70 | /// Warning: The object index may change for non default classes. 71 | /// 72 | /// true if strings should be used. 73 | virtual bool ShouldUseStrings() const 74 | { 75 | return false; 76 | } 77 | 78 | /// 79 | /// Check if strings () should be xor encoded. 80 | /// 81 | /// true if string should be xor encoded. 82 | virtual bool ShouldXorStrings() const 83 | { 84 | return false; 85 | } 86 | 87 | /// 88 | /// Check if static methods should get converted to normal methods. 89 | /// Static methods require a CreateDefaultObject() method in the UObject class. 90 | /// 91 | /// true if static methods should get converted to normal methods. 92 | virtual bool ShouldConvertStaticMethods() const 93 | { 94 | return true; 95 | } 96 | 97 | /// 98 | /// Check if we should generate a function parameters file. 99 | /// Otherwise the parameters are declared inside the function body. 100 | /// If hooks with access to the parameters are need, this method should return true. 101 | /// 102 | /// True if a function parameters file should be generated. 103 | virtual bool ShouldGenerateFunctionParametersFile() const 104 | { 105 | return true; 106 | } 107 | 108 | /// 109 | /// Gets namespace name for the classes. If the name is empty no namespace gets generated. 110 | /// 111 | /// The namespace name. 112 | virtual std::string GetNamespaceName() const 113 | { 114 | return std::string(); 115 | } 116 | 117 | /// 118 | /// Gets a list of custom include files which gets inserted in the SDK. 119 | /// 120 | /// The list of include files. 121 | virtual std::vector GetIncludes() const 122 | { 123 | return {}; 124 | } 125 | 126 | /// 127 | /// Gets the member alignment. 128 | /// https://msdn.microsoft.com/en-us/library/2e70t5y1.aspx 129 | /// 130 | /// The member alignment. 131 | virtual unsigned GetGlobalMemberAlignment() const 132 | { 133 | return 0x8; 134 | } 135 | 136 | /// 137 | /// Gets alignas size for the specific class. 138 | /// http://cppreference.com/w/cpp/language/alignas 139 | /// 140 | /// The name. 141 | /// If the class is not found the return value is 0, else the alignas size. 142 | virtual unsigned GetClassAlignas(const std::string& name) const 143 | { 144 | auto it = alignasClasses.find(name); 145 | if (it != std::end(alignasClasses)) 146 | { 147 | return it->second; 148 | } 149 | return 0; 150 | } 151 | 152 | /// 153 | /// Gets the declarations of some basic classes and methods. 154 | /// 155 | /// The basic declarations. 156 | virtual std::string GetBasicDeclarations() const 157 | { 158 | return std::string(); 159 | } 160 | 161 | /// 162 | /// Gets the definitions of the declarations. 163 | /// 164 | /// The basic definitions. 165 | virtual std::string GetBasicDefinitions() const 166 | { 167 | return std::string(); 168 | } 169 | 170 | /// 171 | /// Checks if an override is defined for the given type. 172 | /// 173 | /// The parameter type. 174 | /// If no override is found the original name is returned. 175 | virtual std::string GetOverrideType(const std::string& type) const 176 | { 177 | auto it = overrideTypes.find(type); 178 | if (it == std::end(overrideTypes)) 179 | { 180 | return type; 181 | } 182 | return it->second; 183 | } 184 | 185 | struct PredefinedMember 186 | { 187 | std::string Type; 188 | std::string Name; 189 | }; 190 | 191 | /// 192 | /// Gets the predefined members of the specific class. 193 | /// 194 | /// The name of the class. 195 | /// [out] The predefined members. 196 | /// true if predefined members are found. 197 | virtual bool GetPredefinedClassMembers(const std::string& name, std::vector& members) const 198 | { 199 | auto it = predefinedMembers.find(name); 200 | if (it != std::end(predefinedMembers)) 201 | { 202 | std::copy(std::begin(it->second), std::end(it->second), std::back_inserter(members)); 203 | 204 | return true; 205 | } 206 | 207 | return false; 208 | } 209 | 210 | /// 211 | /// Gets the static predefined members of the specific class. 212 | /// 213 | /// The name of the class. 214 | /// [out] The predefined members. 215 | /// true if predefined members are found. 216 | virtual bool GetPredefinedClassStaticMembers(const std::string& name, std::vector& members) const 217 | { 218 | auto it = predefinedStaticMembers.find(name); 219 | if (it != std::end(predefinedStaticMembers)) 220 | { 221 | std::copy(std::begin(it->second), std::end(it->second), std::back_inserter(members)); 222 | 223 | return true; 224 | } 225 | 226 | return false; 227 | } 228 | 229 | using VirtualFunctionPatterns = std::vector>; 230 | 231 | /// 232 | /// Gets the patterns of virtual functions of the specific class. 233 | /// The generator loops the virtual functions of the class and adds a class method if the pattern matches. 234 | /// 235 | /// The name of the class. 236 | /// [out] The patterns. 237 | /// true if patterns are found. 238 | virtual bool GetVirtualFunctionPatterns(const std::string& name, VirtualFunctionPatterns& patterns) const 239 | { 240 | auto it = virtualFunctionPattern.find(name); 241 | if (it != std::end(virtualFunctionPattern)) 242 | { 243 | std::copy(std::begin(it->second), std::end(it->second), std::back_inserter(patterns)); 244 | 245 | return true; 246 | } 247 | 248 | return false; 249 | } 250 | 251 | struct PredefinedMethod 252 | { 253 | enum class Type 254 | { 255 | Default, 256 | Inline 257 | }; 258 | 259 | std::string Signature; 260 | std::string Body; 261 | Type MethodType; 262 | 263 | /// Adds a predefined method which gets splittet in declaration and definition. 264 | /// The method signature. 265 | /// The method body. 266 | /// The method. 267 | static PredefinedMethod Default(std::string&& signature, std::string&& body) 268 | { 269 | return { signature, body, Type::Default }; 270 | } 271 | 272 | /// Adds a predefined method which gets included as an inline method. 273 | /// The body. 274 | /// The method. 275 | static PredefinedMethod Inline(std::string&& body) 276 | { 277 | return { std::string(), body, Type::Inline }; 278 | } 279 | }; 280 | 281 | /// Gets the predefined methods of the specific class. 282 | /// The name of the class. 283 | /// [out] The predefined methods. 284 | /// true if predefined methods are found. 285 | virtual bool GetPredefinedClassMethods(const std::string& name, std::vector& methods) const 286 | { 287 | auto it = predefinedMethods.find(name); 288 | if (it != std::end(predefinedMethods)) 289 | { 290 | std::copy(std::begin(it->second), std::end(it->second), std::back_inserter(methods)); 291 | 292 | return true; 293 | } 294 | 295 | return false; 296 | } 297 | 298 | protected: 299 | std::unordered_map alignasClasses; 300 | std::unordered_map overrideTypes; 301 | std::unordered_map> predefinedMembers; 302 | std::unordered_map> predefinedStaticMembers; 303 | std::unordered_map> predefinedMethods; 304 | std::unordered_map virtualFunctionPattern; 305 | }; 306 | -------------------------------------------------------------------------------- /src/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "Logger.hpp" 2 | 3 | std::ostream* Logger::stream = nullptr; 4 | 5 | void Logger::SetStream(std::ostream* _stream) 6 | { 7 | stream = _stream; 8 | } 9 | 10 | void Logger::Log(const std::string& message) 11 | { 12 | if (stream != nullptr) 13 | { 14 | (*stream) << message << '\n' << std::flush; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "tinyformat.h" 8 | 9 | class Logger 10 | { 11 | public: 12 | 13 | /// 14 | /// Sets the stream where the output goes to. 15 | /// 16 | /// [in] The stream. 17 | static void SetStream(std::ostream* stream); 18 | 19 | /// 20 | /// Logs the given message. 21 | /// 22 | /// The message. 23 | static void Log(const std::string& message); 24 | 25 | /// 26 | /// Formats and logs the given message. 27 | /// 28 | /// Type of the arguments. 29 | /// Describes the format to use. 30 | /// Variable arguments providing the arguments. 31 | template 32 | static void Log(const char* fmt, const Args&... args) 33 | { 34 | Log(tfm::format(fmt, args...)); 35 | } 36 | 37 | private: 38 | static std::ostream *stream; 39 | }; 40 | -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | // Unreal Engine SDK Generator 2 | // by KN4CK3R 3 | // https://www.oldschoolhack.me 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | namespace fs = std::experimental::filesystem; 14 | #include "cpplinq.hpp" 15 | 16 | #include "Logger.hpp" 17 | 18 | #include "IGenerator.hpp" 19 | #include "ObjectsStore.hpp" 20 | #include "NamesStore.hpp" 21 | #include "Package.hpp" 22 | #include "NameValidator.hpp" 23 | #include "PrintHelper.hpp" 24 | 25 | extern IGenerator* generator; 26 | 27 | /// 28 | /// Dumps the objects and names to files. 29 | /// 30 | /// The path where to create the dumps. 31 | void Dump(const fs::path& path) 32 | { 33 | { 34 | std::ofstream o(path / "ObjectsDump.txt"); 35 | tfm::format(o, "Address: 0x%P\n\n", ObjectsStore::GetAddress()); 36 | 37 | for (auto obj : ObjectsStore()) 38 | { 39 | tfm::format(o, "[%06i] %-100s 0x%P\n", obj.GetIndex(), obj.GetFullName(), obj.GetAddress()); 40 | } 41 | } 42 | 43 | { 44 | std::ofstream o(path / "NamesDump.txt"); 45 | tfm::format(o, "Address: 0x%P\n\n", NamesStore::GetAddress()); 46 | 47 | for (auto name : NamesStore()) 48 | { 49 | tfm::format(o, "[%06i] %s\n", name.Index, name.Name); 50 | } 51 | } 52 | } 53 | 54 | /// 55 | /// Generates the sdk header. 56 | /// 57 | /// The path where to create the sdk header. 58 | /// The list of processed objects. 59 | /// The package order info. 60 | void SaveSDKHeader(const fs::path& path, const std::unordered_map& processedObjects, const std::vector& packages) 61 | { 62 | std::ofstream os(path / "SDK.hpp"); 63 | 64 | os << "#pragma once\n\n" 65 | << tfm::format("// %s (%s) SDK\n\n", generator->GetGameName(), generator->GetGameVersion()); 66 | 67 | //include the basics 68 | { 69 | { 70 | std::ofstream os2(path / "SDK" / tfm::format("%s_Basic.hpp", generator->GetGameNameShort())); 71 | 72 | std::vector includes{ { "" }, { "" } }; 73 | 74 | auto&& generatorIncludes = generator->GetIncludes(); 75 | includes.insert(includes.end(), std::begin(generatorIncludes), std::end(generatorIncludes)); 76 | 77 | PrintFileHeader(os2, includes, true); 78 | 79 | os2 << generator->GetBasicDeclarations() << "\n"; 80 | 81 | PrintFileFooter(os2); 82 | 83 | os << "\n#include \"SDK/" << tfm::format("%s_Basic.hpp", generator->GetGameNameShort()) << "\"\n"; 84 | } 85 | { 86 | std::ofstream os2(path / "SDK" / tfm::format("%s_Basic.cpp", generator->GetGameNameShort())); 87 | 88 | PrintFileHeader(os2, { "../SDK.hpp" }, false); 89 | 90 | os2 << generator->GetBasicDefinitions() << "\n"; 91 | 92 | PrintFileFooter(os2); 93 | } 94 | } 95 | 96 | using namespace cpplinq; 97 | 98 | //check for missing structs 99 | const auto missing = from(processedObjects) >> where([](auto&& kv) { return kv.second == false; }); 100 | if (missing >> any()) 101 | { 102 | std::ofstream os2(path / "SDK" / tfm::format("%s_MISSING.hpp", generator->GetGameNameShort())); 103 | 104 | PrintFileHeader(os2, true); 105 | 106 | for (auto&& s : missing >> select([](auto&& kv) { return kv.first.Cast(); }) >> experimental::container()) 107 | { 108 | os2 << "// " << s.GetFullName() << "\n// "; 109 | os2 << tfm::format("0x%04X\n", s.GetPropertySize()); 110 | 111 | os2 << "struct " << MakeValidName(s.GetNameCPP()) << "\n{\n"; 112 | os2 << "\tunsigned char UnknownData[0x" << tfm::format("%X", s.GetPropertySize()) << "];\n};\n\n"; 113 | } 114 | 115 | PrintFileFooter(os2); 116 | 117 | os << "\n#include \"SDK/" << tfm::format("%s_MISSING.hpp", generator->GetGameNameShort()) << "\"\n"; 118 | } 119 | 120 | os << "\n"; 121 | 122 | for (auto&& package : packages) 123 | { 124 | os << R"(#include "SDK/)" << GenerateFileName(FileContentType::Classes, package) << "\"\n"; 125 | } 126 | } 127 | 128 | /// 129 | /// Process the packages. 130 | /// 131 | /// The path where to create the package files. 132 | void ProcessPackages(const fs::path& path) 133 | { 134 | using namespace cpplinq; 135 | 136 | const auto sdkPath = path / "SDK"; 137 | fs::create_directories(sdkPath); 138 | 139 | std::vector packages; 140 | 141 | std::unordered_map processedObjects; 142 | 143 | auto packageObjects = from(ObjectsStore()) 144 | >> select([](auto&& o) { return o.GetPackageObject(); }) 145 | >> where([](auto&& o) { return o.IsValid(); }) 146 | >> distinct() 147 | >> to_vector(); 148 | 149 | for (auto obj : packageObjects) 150 | { 151 | Package package(obj); 152 | 153 | package.Process(processedObjects); 154 | if (package.Save(sdkPath)) 155 | { 156 | packages.emplace_back(std::move(package)); 157 | } 158 | } 159 | 160 | SaveSDKHeader(path, processedObjects, packages); 161 | } 162 | 163 | DWORD WINAPI OnAttach(LPVOID lpParameter) 164 | { 165 | if (!ObjectsStore::Initialize()) 166 | { 167 | MessageBoxA(nullptr, "ObjectsStore::Initialize failed", "Error", 0); 168 | return -1; 169 | } 170 | if (!NamesStore::Initialize()) 171 | { 172 | MessageBoxA(nullptr, "NamesStore::Initialize failed", "Error", 0); 173 | return -1; 174 | } 175 | 176 | if (!generator->Initialize(lpParameter)) 177 | { 178 | MessageBoxA(nullptr, "Initialize failed", "Error", 0); 179 | return -1; 180 | } 181 | 182 | fs::path outputDirectory(generator->GetOutputDirectory()); 183 | if (!outputDirectory.is_absolute()) 184 | { 185 | char buffer[2048]; 186 | if (GetModuleFileNameA(static_cast(lpParameter), buffer, sizeof(buffer)) == 0) 187 | { 188 | MessageBoxA(nullptr, "GetModuleFileName failed", "Error", 0); 189 | return -1; 190 | } 191 | 192 | outputDirectory = fs::path(buffer).remove_filename() / outputDirectory; 193 | } 194 | 195 | outputDirectory /= generator->GetGameNameShort(); 196 | fs::create_directories(outputDirectory); 197 | 198 | std::ofstream log(outputDirectory / "Generator.log"); 199 | Logger::SetStream(&log); 200 | 201 | if (generator->ShouldDumpArrays()) 202 | { 203 | Dump(outputDirectory); 204 | } 205 | 206 | fs::create_directories(outputDirectory); 207 | 208 | const auto begin = std::chrono::system_clock::now(); 209 | 210 | ProcessPackages(outputDirectory); 211 | 212 | Logger::Log("Finished, took %d seconds.", std::chrono::duration_cast(std::chrono::system_clock::now() - begin).count()); 213 | 214 | Logger::SetStream(nullptr); 215 | 216 | MessageBoxA(nullptr, "Finished!", "Info", 0); 217 | 218 | return 0; 219 | } 220 | 221 | BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) 222 | { 223 | switch (dwReason) 224 | { 225 | case DLL_PROCESS_ATTACH: 226 | DisableThreadLibraryCalls(hModule); 227 | 228 | CreateThread(nullptr, 0, OnAttach, hModule, 0, nullptr); 229 | 230 | return TRUE; 231 | } 232 | 233 | return FALSE; 234 | } 235 | -------------------------------------------------------------------------------- /src/NameValidator.cpp: -------------------------------------------------------------------------------- 1 | #include "NameValidator.hpp" 2 | 3 | #include 4 | 5 | #include "ObjectsStore.hpp" 6 | 7 | std::string MakeValidName(std::string&& name) 8 | { 9 | std::string valid(name); 10 | 11 | for (auto i = 0u; i < name.length(); ++i) 12 | { 13 | if (valid[i] == ' ' 14 | || valid[i] == '?' 15 | || valid[i] == '+' 16 | || valid[i] == '-' 17 | || valid[i] == ':' 18 | || valid[i] == '/' 19 | || valid[i] == '^' 20 | || valid[i] == '(' 21 | || valid[i] == ')' 22 | || valid[i] == '[' 23 | || valid[i] == ']' 24 | || valid[i] == '<' 25 | || valid[i] == '>' 26 | || valid[i] == '&' 27 | || valid[i] == '.' 28 | || valid[i] == '#' 29 | || valid[i] == '\'' 30 | || valid[i] == '"' 31 | || valid[i] == '%') 32 | { 33 | valid[i] = '_'; 34 | } 35 | } 36 | 37 | if (!valid.empty()) 38 | { 39 | if (std::isdigit(valid[0])) 40 | { 41 | valid = '_' + valid; 42 | } 43 | } 44 | 45 | return valid; 46 | } 47 | 48 | std::string SimplifyEnumName(std::string&& name) 49 | { 50 | const auto index = name.find_last_of(':'); 51 | if (index == std::string::npos) 52 | { 53 | return name; 54 | } 55 | 56 | return name.substr(index + 1); 57 | } 58 | 59 | template 60 | std::string MakeUniqueCppNameImpl(const T& t) 61 | { 62 | std::string name; 63 | if (ObjectsStore().CountObjects(t.GetName()) > 1) 64 | { 65 | name += MakeValidName(t.GetOuter().GetName()) + "_"; 66 | } 67 | return name + MakeValidName(t.GetName()); 68 | } 69 | 70 | std::string MakeUniqueCppName(const UEConst& c) 71 | { 72 | return MakeUniqueCppNameImpl(c); 73 | } 74 | 75 | std::string MakeUniqueCppName(const UEEnum& e) 76 | { 77 | auto name = MakeUniqueCppNameImpl(e); 78 | if (!name.empty() && name[0] != 'E') 79 | { 80 | name = 'E' + name; 81 | } 82 | return name; 83 | } 84 | 85 | std::string MakeUniqueCppName(const UEStruct& ss) 86 | { 87 | std::string name; 88 | if (ObjectsStore().CountObjects(ss.GetName()) > 1) 89 | { 90 | name += MakeValidName(ss.GetOuter().GetNameCPP()) + "_"; 91 | } 92 | return name + MakeValidName(ss.GetNameCPP()); 93 | } 94 | -------------------------------------------------------------------------------- /src/NameValidator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class UEConst; 6 | class UEEnum; 7 | class UEStruct; 8 | 9 | /// 10 | /// Makes valid C++ name from the given name. 11 | /// 12 | /// The name to process. 13 | /// A valid C++ name. 14 | std::string MakeValidName(std::string&& name); 15 | 16 | std::string SimplifyEnumName(std::string&& name); 17 | 18 | std::string MakeUniqueCppName(const UEConst& c); 19 | std::string MakeUniqueCppName(const UEEnum& e); 20 | std::string MakeUniqueCppName(const UEStruct& ss); 21 | -------------------------------------------------------------------------------- /src/NamesStore.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "PatternFinder.hpp" 4 | #include "NamesStore.hpp" 5 | 6 | #include "EngineClasses.hpp" 7 | 8 | class FNameEntry 9 | { 10 | public: 11 | __int32 Index; 12 | char pad_0x0004[0x4]; 13 | FNameEntry* HashNext; 14 | union 15 | { 16 | char AnsiName[1024]; 17 | wchar_t WideName[1024]; 18 | }; 19 | 20 | const char* GetName() const 21 | { 22 | return AnsiName; 23 | } 24 | }; 25 | 26 | template 27 | class TStaticIndirectArrayThreadSafeRead 28 | { 29 | public: 30 | int32_t Num() const 31 | { 32 | return NumElements; 33 | } 34 | 35 | bool IsValidIndex(int32_t index) const 36 | { 37 | return index >= 0 && index < Num() && GetById(index) != nullptr; 38 | } 39 | 40 | ElementType const* const& GetById(int32_t index) const 41 | { 42 | return *GetItemPtr(index); 43 | } 44 | 45 | private: 46 | ElementType const* const* GetItemPtr(int32_t Index) const 47 | { 48 | int32_t ChunkIndex = Index / ElementsPerChunk; 49 | int32_t WithinChunkIndex = Index % ElementsPerChunk; 50 | ElementType** Chunk = Chunks[ChunkIndex]; 51 | return Chunk + WithinChunkIndex; 52 | } 53 | 54 | enum 55 | { 56 | ChunkTableSize = (MaxTotalElements + ElementsPerChunk - 1) / ElementsPerChunk 57 | }; 58 | 59 | ElementType** Chunks[ChunkTableSize]; 60 | __int32 NumElements; 61 | __int32 NumChunks; 62 | }; 63 | 64 | using TNameEntryArray = TStaticIndirectArrayThreadSafeRead; 65 | 66 | TNameEntryArray* GlobalNames = nullptr; 67 | 68 | bool NamesStore::Initialize() 69 | { 70 | /*const auto address = FindPattern(GetModuleHandleW(nullptr), reinterpret_cast("\x48\x8B\x3D\x00\x00\x00\x00\x48\x85\xFF\x75\x38"), "xxx????xxxxx"); 71 | if (address == -1) 72 | { 73 | return false; 74 | } 75 | 76 | const auto offset = *reinterpret_cast(address + 3); 77 | GlobalNames = reinterpret_cast(*reinterpret_cast(address + 7 + offset));*/ 78 | 79 | GlobalNames = reinterpret_cast(*reinterpret_cast((uintptr_t)GetModuleHandleW(nullptr) + 0x3DF2F48)); 80 | return true; 81 | } 82 | 83 | void* NamesStore::GetAddress() 84 | { 85 | return GlobalNames; 86 | } 87 | 88 | size_t NamesStore::GetNamesNum() const 89 | { 90 | return GlobalNames->Num(); 91 | } 92 | 93 | bool NamesStore::IsValid(size_t id) const 94 | { 95 | return GlobalNames->IsValidIndex(static_cast(id)); 96 | } 97 | 98 | std::string NamesStore::GetById(size_t id) const 99 | { 100 | return GlobalNames->GetById(static_cast(id))->GetName(); 101 | } 102 | 103 | NamesIterator NamesStore::begin() 104 | { 105 | return NamesIterator(*this, 0); 106 | } 107 | 108 | NamesIterator NamesStore::begin() const 109 | { 110 | return NamesIterator(*this, 0); 111 | } 112 | 113 | NamesIterator NamesStore::end() 114 | { 115 | return NamesIterator(*this); 116 | } 117 | 118 | NamesIterator NamesStore::end() const 119 | { 120 | return NamesIterator(*this); 121 | } 122 | 123 | NamesIterator::NamesIterator(const NamesStore& _store) 124 | : store(_store), 125 | index(_store.GetNamesNum()) 126 | { 127 | } 128 | 129 | NamesIterator::NamesIterator(const NamesStore& _store, size_t _index) 130 | : store(_store), 131 | index(_index) 132 | { 133 | } 134 | 135 | void NamesIterator::swap(NamesIterator& other) noexcept 136 | { 137 | std::swap(index, other.index); 138 | } 139 | 140 | NamesIterator& NamesIterator::operator++() 141 | { 142 | for (++index; index < store.GetNamesNum(); ++index) 143 | { 144 | if (store.IsValid(index)) 145 | { 146 | break; 147 | } 148 | } 149 | return *this; 150 | } 151 | 152 | NamesIterator NamesIterator::operator++ (int) 153 | { 154 | auto tmp(*this); 155 | ++(*this); 156 | return tmp; 157 | } 158 | 159 | bool NamesIterator::operator==(const NamesIterator& rhs) const 160 | { 161 | return index == rhs.index; 162 | } 163 | 164 | bool NamesIterator::operator!=(const NamesIterator& rhs) const 165 | { 166 | return index != rhs.index; 167 | } 168 | 169 | UENameInfo NamesIterator::operator*() const 170 | { 171 | return { index, store.GetById(index) }; 172 | } 173 | 174 | UENameInfo NamesIterator::operator->() const 175 | { 176 | return { index, store.GetById(index) }; 177 | } -------------------------------------------------------------------------------- /src/NamesStore.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "UE4/GenericTypes.hpp" 6 | 7 | class NamesIterator; 8 | 9 | class NamesStore 10 | { 11 | friend NamesIterator; 12 | 13 | public: 14 | 15 | /// 16 | /// Initializes this object. 17 | /// 18 | /// true if it succeeds, false if it fails. 19 | static bool Initialize(); 20 | 21 | /// Gets the address of the global names store. 22 | /// The address of the global names store. 23 | static void* GetAddress(); 24 | 25 | NamesIterator begin(); 26 | 27 | NamesIterator begin() const; 28 | 29 | NamesIterator end(); 30 | 31 | NamesIterator end() const; 32 | 33 | /// 34 | /// Gets the number of available names. 35 | /// 36 | /// The number of names. 37 | size_t GetNamesNum() const; 38 | 39 | /// 40 | /// Test if the given id is valid. 41 | /// 42 | /// The identifier. 43 | /// true if valid, false if not. 44 | bool IsValid(size_t id) const; 45 | 46 | /// 47 | /// Gets a name by id. 48 | /// 49 | /// The identifier. 50 | /// The name. 51 | std::string GetById(size_t id) const; 52 | }; 53 | 54 | struct UENameInfo 55 | { 56 | size_t Index; 57 | std::string Name; 58 | }; 59 | 60 | class NamesIterator : public std::iterator 61 | { 62 | const NamesStore& store; 63 | size_t index; 64 | 65 | public: 66 | NamesIterator(const NamesStore& store); 67 | 68 | explicit NamesIterator(const NamesStore& store, size_t index); 69 | 70 | void swap(NamesIterator& other) noexcept; 71 | 72 | NamesIterator& operator++(); 73 | 74 | NamesIterator operator++ (int); 75 | 76 | bool operator==(const NamesIterator& rhs) const; 77 | 78 | bool operator!=(const NamesIterator& rhs) const; 79 | 80 | UENameInfo operator*() const; 81 | 82 | UENameInfo operator->() const; 83 | }; 84 | -------------------------------------------------------------------------------- /src/ObjectsStore.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "PatternFinder.hpp" 4 | #include "ObjectsStore.hpp" 5 | 6 | #include "EngineClasses.hpp" 7 | 8 | class FUObjectItem 9 | { 10 | public: 11 | UObject* Object; //0x0000 12 | __int32 Flags; //0x0008 13 | __int32 ClusterIndex; //0x000C 14 | __int32 SerialNumber; //0x0010 15 | }; 16 | 17 | class TUObjectArray 18 | { 19 | public: 20 | FUObjectItem* Objects; 21 | int32_t MaxElements; 22 | int32_t NumElements; 23 | }; 24 | 25 | class FUObjectArray 26 | { 27 | public: 28 | __int32 ObjFirstGCIndex; //0x0000 29 | __int32 ObjLastNonGCIndex; //0x0004 30 | __int32 MaxObjectsNotConsideredByGC; //0x0008 31 | __int32 OpenForDisregardForGC; //0x000C 32 | 33 | TUObjectArray ObjObjects; //0x0010 34 | }; 35 | 36 | FUObjectArray* GlobalObjects = nullptr; 37 | 38 | bool ObjectsStore::Initialize() 39 | { 40 | const auto address = FindPattern(GetModuleHandleW(nullptr), reinterpret_cast("\x48\x8D\x05\x00\x00\x00\x00\x48\x89\x01\x33\xC9\x84\xD2\x41\x8B"), "xxx????xxxxxxxxx"); 41 | if (address == -1) 42 | { 43 | return false; 44 | } 45 | const auto offset = *reinterpret_cast(address + 3); 46 | GlobalObjects = reinterpret_cast(address + 7 + offset); 47 | 48 | return true; 49 | } 50 | 51 | void* ObjectsStore::GetAddress() 52 | { 53 | return GlobalObjects; 54 | } 55 | 56 | size_t ObjectsStore::GetObjectsNum() const 57 | { 58 | return GlobalObjects->ObjObjects.NumElements; 59 | } 60 | 61 | UEObject ObjectsStore::GetById(size_t id) const 62 | { 63 | return GlobalObjects->ObjObjects.Objects[id].Object; 64 | } 65 | 66 | ObjectsIterator ObjectsStore::begin() 67 | { 68 | return ObjectsIterator(*this, 0); 69 | } 70 | 71 | ObjectsIterator ObjectsStore::begin() const 72 | { 73 | return ObjectsIterator(*this, 0); 74 | } 75 | 76 | ObjectsIterator ObjectsStore::end() 77 | { 78 | return ObjectsIterator(*this); 79 | } 80 | 81 | ObjectsIterator ObjectsStore::end() const 82 | { 83 | return ObjectsIterator(*this); 84 | } 85 | 86 | UEClass ObjectsStore::FindClass(const std::string& name) const 87 | { 88 | for (auto obj : *this) 89 | { 90 | if (obj.GetFullName() == name) 91 | { 92 | return obj.Cast(); 93 | } 94 | } 95 | return UEClass(nullptr); 96 | } 97 | 98 | ObjectsIterator::ObjectsIterator(const ObjectsStore& _store) 99 | : store(_store), 100 | index(_store.GetObjectsNum()) 101 | { 102 | } 103 | 104 | ObjectsIterator::ObjectsIterator(const ObjectsStore& _store, size_t _index) 105 | : store(_store), 106 | index(_index), 107 | current(_store.GetById(_index)) 108 | { 109 | } 110 | 111 | ObjectsIterator::ObjectsIterator(const ObjectsIterator& other) 112 | : store(other.store), 113 | index(other.index), 114 | current(other.current) 115 | { 116 | } 117 | 118 | ObjectsIterator::ObjectsIterator(ObjectsIterator&& other) noexcept 119 | : store(other.store), 120 | index(other.index), 121 | current(other.current) 122 | { 123 | } 124 | 125 | ObjectsIterator& ObjectsIterator::operator=(const ObjectsIterator& rhs) 126 | { 127 | index = rhs.index; 128 | current = rhs.current; 129 | return *this; 130 | } 131 | 132 | void ObjectsIterator::swap(ObjectsIterator& other) noexcept 133 | { 134 | std::swap(index, other.index); 135 | std::swap(current, other.current); 136 | } 137 | 138 | ObjectsIterator& ObjectsIterator::operator++() 139 | { 140 | current = UEObject(); 141 | 142 | for (++index; index < store.GetObjectsNum(); ++index) 143 | { 144 | current = store.GetById(index); 145 | if (current.IsValid()) 146 | { 147 | break; 148 | } 149 | } 150 | return *this; 151 | } 152 | 153 | ObjectsIterator ObjectsIterator::operator++(int) 154 | { 155 | auto tmp(*this); 156 | ++(*this); 157 | return tmp; 158 | } 159 | 160 | bool ObjectsIterator::operator==(const ObjectsIterator& rhs) const 161 | { 162 | return index == rhs.index; 163 | } 164 | 165 | bool ObjectsIterator::operator!=(const ObjectsIterator& rhs) const 166 | { 167 | return index != rhs.index; 168 | } 169 | 170 | UEObject ObjectsIterator::operator*() const 171 | { 172 | //assert(current.IsValid() && "ObjectsIterator::current is not valid!"); 173 | 174 | return current; 175 | } 176 | 177 | UEObject ObjectsIterator::operator->() const 178 | { 179 | return operator*(); 180 | } -------------------------------------------------------------------------------- /src/ObjectsStore.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "UE4/GenericTypes.hpp" 6 | 7 | class ObjectsIterator; 8 | 9 | class ObjectsStore 10 | { 11 | public: 12 | 13 | /// 14 | /// Initializes this object. 15 | /// 16 | /// 17 | /// true if it succeeds, false if it fails. 18 | /// 19 | static bool Initialize(); 20 | 21 | /// Gets the address of the global objects store. 22 | /// The address of the global objects store. 23 | static void* GetAddress(); 24 | 25 | ObjectsIterator begin(); 26 | 27 | ObjectsIterator begin() const; 28 | 29 | ObjectsIterator end(); 30 | 31 | ObjectsIterator end() const; 32 | 33 | /// 34 | /// Gets the number of available objects. 35 | /// 36 | /// The number of objects. 37 | size_t GetObjectsNum() const; 38 | 39 | /// 40 | /// Gets the object by id. 41 | /// 42 | /// The identifier. 43 | /// The object. 44 | UEObject GetById(size_t id) const; 45 | 46 | /// 47 | /// Searches for the first class with the given name. 48 | /// 49 | /// The name of the class. 50 | /// The found class which is not valid if no class could be found. 51 | UEClass FindClass(const std::string& name) const; 52 | 53 | /// Count objects which have the same name and type. 54 | /// Type of the object. 55 | /// The name to search for. 56 | /// The number of objects which share a name. 57 | template 58 | size_t CountObjects(const std::string& name) const 59 | { 60 | static std::unordered_map cache; 61 | 62 | auto it = cache.find(name); 63 | if (it != std::end(cache)) 64 | { 65 | return it->second; 66 | } 67 | 68 | size_t count = 0; 69 | for (auto obj : *this) 70 | { 71 | if (obj.IsA() && obj.GetName() == name) 72 | { 73 | ++count; 74 | } 75 | } 76 | 77 | cache[name] = count; 78 | 79 | return count; 80 | } 81 | }; 82 | 83 | /// Holds information about an object. 84 | struct UEObjectInfo 85 | { 86 | /// Zero-based index of the object in the global objects store. 87 | size_t Index; 88 | 89 | /// The object. 90 | UEObject Object; 91 | }; 92 | 93 | /// An iterator for objects. 94 | class ObjectsIterator : public std::iterator 95 | { 96 | const ObjectsStore& store; 97 | size_t index; 98 | UEObject current; 99 | 100 | public: 101 | 102 | /// Constructor. 103 | /// The store to iterate. 104 | ObjectsIterator(const ObjectsStore& store); 105 | 106 | /// Constructor. 107 | /// The store to iterate. 108 | /// Zero-based start index. 109 | explicit ObjectsIterator(const ObjectsStore& store, size_t index); 110 | 111 | ObjectsIterator(const ObjectsIterator& other); 112 | ObjectsIterator(ObjectsIterator&& other) noexcept; 113 | 114 | ObjectsIterator& operator=(const ObjectsIterator& rhs); 115 | 116 | void swap(ObjectsIterator& other) noexcept; 117 | 118 | ObjectsIterator& operator++(); 119 | 120 | ObjectsIterator operator++ (int); 121 | 122 | bool operator==(const ObjectsIterator& rhs) const; 123 | 124 | bool operator!=(const ObjectsIterator& rhs) const; 125 | 126 | UEObject operator*() const; 127 | 128 | UEObject operator->() const; 129 | }; 130 | -------------------------------------------------------------------------------- /src/Package.cpp: -------------------------------------------------------------------------------- 1 | #include "Package.hpp" 2 | 3 | #include 4 | #include 5 | #include "tinyformat.h" 6 | #include "cpplinq.hpp" 7 | 8 | #include "IGenerator.hpp" 9 | #include "Logger.hpp" 10 | #include "NameValidator.hpp" 11 | #include "PatternFinder.hpp" 12 | #include "ObjectsStore.hpp" 13 | #include "UE4/PropertyFlags.hpp" 14 | #include "UE4/FunctionFlags.hpp" 15 | #include "PrintHelper.hpp" 16 | 17 | /// 18 | /// Compare two properties. 19 | /// 20 | /// The first property. 21 | /// The second property. 22 | /// true if the first property compares less, else false. 23 | bool ComparePropertyLess(const UEProperty& lhs, const UEProperty& rhs) 24 | { 25 | if (lhs.GetOffset() == rhs.GetOffset() 26 | && lhs.IsA() 27 | && rhs.IsA()) 28 | { 29 | return lhs.Cast() < rhs.Cast(); 30 | } 31 | 32 | return lhs.GetOffset() < rhs.GetOffset(); 33 | } 34 | 35 | Package::Package(const UEObject& _packageObj) 36 | : packageObj(_packageObj) 37 | { 38 | } 39 | 40 | void Package::Process(std::unordered_map& processedObjects) 41 | { 42 | for (auto obj : ObjectsStore()) 43 | { 44 | const auto package = obj.GetPackageObject(); 45 | if (packageObj == package) 46 | { 47 | if (obj.IsA()) 48 | { 49 | GenerateEnum(obj.Cast()); 50 | } 51 | else if (obj.IsA()) 52 | { 53 | GenerateConst(obj.Cast()); 54 | } 55 | else if (obj.IsA()) 56 | { 57 | GeneratePrerequisites(obj, processedObjects); 58 | } 59 | else if (obj.IsA()) 60 | { 61 | GeneratePrerequisites(obj, processedObjects); 62 | } 63 | } 64 | } 65 | } 66 | 67 | bool Package::Save(const fs::path& path) const 68 | { 69 | extern IGenerator* generator; 70 | 71 | using namespace cpplinq; 72 | 73 | //check if package is empty (no enums, structs or classes without members) 74 | if (generator->ShouldGenerateEmptyFiles() 75 | || (from(enums) >> where([](auto&& e) { return !e.Values.empty(); }) >> any() 76 | || from(scriptStructs) >> where([](auto&& s) { return !s.Members.empty() || !s.PredefinedMethods.empty(); }) >> any() 77 | || from(classes) >> where([](auto&& c) {return !c.Members.empty() || !c.PredefinedMethods.empty() || !c.Methods.empty(); }) >> any() 78 | ) 79 | ) 80 | { 81 | SaveStructs(path); 82 | SaveClasses(path); 83 | SaveFunctions(path); 84 | 85 | return true; 86 | } 87 | 88 | Logger::Log("skip empty Package: %s", packageObj.GetName()); 89 | 90 | return false; 91 | } 92 | 93 | bool Package::AddDependency(const UEObject& package) const 94 | { 95 | if (package != packageObj) 96 | { 97 | dependencies.insert(package); 98 | 99 | return true; 100 | } 101 | return false; 102 | } 103 | 104 | // Credits to namazso <3 105 | static unsigned fnv_hash_runtime(const char* str) { 106 | static constexpr auto k_fnv_prime = 16777619u; 107 | static constexpr auto k_offset_basis = 2166136261u; 108 | 109 | auto hash = k_offset_basis; 110 | do { 111 | hash ^= *str++; 112 | hash *= k_fnv_prime; 113 | } while (*(str - 1) != 0); 114 | 115 | return hash; 116 | } 117 | 118 | void Package::GeneratePrerequisites(const UEObject& obj, std::unordered_map& processedObjects) 119 | { 120 | if (!obj.IsValid()) 121 | { 122 | return; 123 | } 124 | 125 | const auto isClass = obj.IsA(); 126 | const auto isScriptStruct = obj.IsA(); 127 | if (!isClass && !isScriptStruct) 128 | { 129 | return; 130 | } 131 | 132 | const auto name = obj.GetName(); 133 | if (name.find("Default__") != std::string::npos 134 | || name.find("") != std::string::npos 135 | || name.find("PLACEHOLDER-CLASS") != std::string::npos) 136 | { 137 | return; 138 | } 139 | 140 | processedObjects[obj] |= false; 141 | 142 | auto classPackage = obj.GetPackageObject(); 143 | if (!classPackage.IsValid()) 144 | { 145 | return; 146 | } 147 | 148 | if (AddDependency(classPackage)) 149 | { 150 | return; 151 | } 152 | 153 | if (processedObjects[obj] == false) 154 | { 155 | processedObjects[obj] = true; 156 | 157 | if (!isScriptStruct) 158 | { 159 | auto outer = obj.GetOuter(); 160 | if (outer.IsValid() && outer != obj) 161 | { 162 | GeneratePrerequisites(outer, processedObjects); 163 | } 164 | } 165 | 166 | auto structObj = obj.Cast(); 167 | 168 | auto super = structObj.GetSuper(); 169 | if (super.IsValid() && super != obj) 170 | { 171 | GeneratePrerequisites(super, processedObjects); 172 | } 173 | 174 | GenerateMemberPrerequisites(structObj.GetChildren().Cast(), processedObjects); 175 | 176 | if (isClass) 177 | { 178 | GenerateClass(obj.Cast()); 179 | } 180 | else 181 | { 182 | GenerateScriptStruct(obj.Cast()); 183 | } 184 | } 185 | } 186 | 187 | void Package::GenerateMemberPrerequisites(const UEProperty& first, std::unordered_map& processedObjects) 188 | { 189 | using namespace cpplinq; 190 | 191 | for (auto prop = first; prop.IsValid(); prop = prop.GetNext().Cast()) 192 | { 193 | const auto info = prop.GetInfo(); 194 | if (info.Type == UEProperty::PropertyType::Primitive) 195 | { 196 | if (prop.IsA()) 197 | { 198 | auto byteProperty = prop.Cast(); 199 | if (byteProperty.IsEnum()) 200 | { 201 | AddDependency(byteProperty.GetEnum().GetPackageObject()); 202 | } 203 | } 204 | else if (prop.IsA()) 205 | { 206 | auto enumProperty = prop.Cast(); 207 | AddDependency(enumProperty.GetEnum().GetPackageObject()); 208 | } 209 | } 210 | else if (info.Type == UEProperty::PropertyType::CustomStruct) 211 | { 212 | GeneratePrerequisites(prop.Cast().GetStruct(), processedObjects); 213 | } 214 | else if (info.Type == UEProperty::PropertyType::Container) 215 | { 216 | std::vector innerProperties; 217 | 218 | if (prop.IsA()) 219 | { 220 | innerProperties.push_back(prop.Cast().GetInner()); 221 | } 222 | else if (prop.IsA()) 223 | { 224 | auto mapProp = prop.Cast(); 225 | innerProperties.push_back(mapProp.GetKeyProperty()); 226 | innerProperties.push_back(mapProp.GetValueProperty()); 227 | } 228 | 229 | for (auto innerProp : from(innerProperties) 230 | >> where([](auto&& p) { return p.GetInfo().Type == UEProperty::PropertyType::CustomStruct; }) 231 | >> experimental::container()) 232 | { 233 | GeneratePrerequisites(innerProp.Cast().GetStruct(), processedObjects); 234 | } 235 | } 236 | else if (prop.IsA()) 237 | { 238 | auto function = prop.Cast(); 239 | 240 | GenerateMemberPrerequisites(function.GetChildren().Cast(), processedObjects); 241 | } 242 | } 243 | } 244 | 245 | void Package::GenerateScriptStruct(const UEScriptStruct& scriptStructObj) 246 | { 247 | extern IGenerator* generator; 248 | 249 | ScriptStruct ss; 250 | ss.Name = scriptStructObj.GetName(); 251 | ss.FullName = scriptStructObj.GetFullName(); 252 | 253 | Logger::Log("ScriptStruct: %-100s - instance: 0x%P", ss.Name, scriptStructObj.GetAddress()); 254 | 255 | ss.NameCpp = MakeValidName(scriptStructObj.GetNameCPP()); 256 | ss.NameCppFull = "struct "; 257 | 258 | //some classes need special alignment 259 | const auto alignment = generator->GetClassAlignas(ss.FullName); 260 | if (alignment != 0) 261 | { 262 | ss.NameCppFull += tfm::format("alignas(%d) ", alignment); 263 | } 264 | 265 | ss.NameCppFull += MakeUniqueCppName(scriptStructObj); 266 | 267 | ss.Size = scriptStructObj.GetPropertySize(); 268 | ss.InheritedSize = 0; 269 | 270 | size_t offset = 0; 271 | 272 | auto super = scriptStructObj.GetSuper(); 273 | if (super.IsValid() && super != scriptStructObj) 274 | { 275 | ss.InheritedSize = offset = super.GetPropertySize(); 276 | 277 | ss.NameCppFull += " : public " + MakeUniqueCppName(super.Cast()); 278 | } 279 | 280 | std::vector properties; 281 | for (auto prop = scriptStructObj.GetChildren().Cast(); prop.IsValid(); prop = prop.GetNext().Cast()) 282 | { 283 | if (prop.GetElementSize() > 0 284 | && !prop.IsA() 285 | && !prop.IsA() 286 | && !prop.IsA() 287 | && !prop.IsA() 288 | ) 289 | { 290 | properties.push_back(prop); 291 | } 292 | } 293 | std::sort(std::begin(properties), std::end(properties), ComparePropertyLess); 294 | 295 | GenerateMembers(scriptStructObj, offset, properties, ss.Members); 296 | 297 | generator->GetPredefinedClassMethods(scriptStructObj.GetFullName(), ss.PredefinedMethods); 298 | 299 | scriptStructs.emplace_back(std::move(ss)); 300 | } 301 | 302 | void Package::GenerateEnum(const UEEnum& enumObj) 303 | { 304 | Enum e; 305 | e.Name = MakeUniqueCppName(enumObj); 306 | 307 | if (e.Name.find("Default__") != std::string::npos 308 | || e.Name.find("PLACEHOLDER-CLASS") != std::string::npos) 309 | { 310 | return; 311 | } 312 | 313 | e.FullName = enumObj.GetFullName(); 314 | 315 | std::unordered_map conflicts; 316 | for (auto&& s : enumObj.GetNames()) 317 | { 318 | const auto clean = MakeValidName(std::move(s)); 319 | 320 | const auto it = conflicts.find(clean); 321 | if (it == std::end(conflicts)) 322 | { 323 | e.Values.push_back(clean); 324 | conflicts[clean] = 1; 325 | } 326 | else 327 | { 328 | e.Values.push_back(clean + tfm::format("%02d", it->second)); 329 | conflicts[clean]++; 330 | } 331 | } 332 | 333 | enums.emplace_back(std::move(e)); 334 | } 335 | 336 | void Package::GenerateConst(const UEConst& constObj) 337 | { 338 | //auto name = MakeValidName(constObj.GetName()); 339 | auto name = MakeUniqueCppName(constObj); 340 | 341 | if (name.find("Default__") != std::string::npos 342 | || name.find("PLACEHOLDER-CLASS") != std::string::npos) 343 | { 344 | return; 345 | } 346 | 347 | constants[name] = constObj.GetValue(); 348 | } 349 | 350 | void Package::GenerateClass(const UEClass& classObj) 351 | { 352 | extern IGenerator* generator; 353 | 354 | Class c; 355 | c.Name = classObj.GetName(); 356 | c.FullName = classObj.GetFullName(); 357 | 358 | Logger::Log("Class: %-100s - instance: 0x%P", c.Name, classObj.GetAddress()); 359 | 360 | c.NameCpp = MakeValidName(classObj.GetNameCPP()); 361 | c.NameCppFull = "class " + c.NameCpp; 362 | 363 | c.Size = classObj.GetPropertySize(); 364 | c.InheritedSize = 0; 365 | 366 | size_t offset = 0; 367 | 368 | auto super = classObj.GetSuper(); 369 | if (super.IsValid() && super != classObj) 370 | { 371 | c.InheritedSize = offset = super.GetPropertySize(); 372 | 373 | c.NameCppFull += " : public " + MakeValidName(super.GetNameCPP()); 374 | } 375 | 376 | std::vector predefinedStaticMembers; 377 | if (generator->GetPredefinedClassStaticMembers(c.FullName, predefinedStaticMembers)) 378 | { 379 | for (auto&& prop : predefinedStaticMembers) 380 | { 381 | Member p; 382 | p.Offset = 0; 383 | p.Size = 0; 384 | p.Name = prop.Name; 385 | p.Type = "static " + prop.Type; 386 | c.Members.push_back(std::move(p)); 387 | } 388 | } 389 | 390 | std::vector predefinedMembers; 391 | if (generator->GetPredefinedClassMembers(c.FullName, predefinedMembers)) 392 | { 393 | for (auto&& prop : predefinedMembers) 394 | { 395 | Member p; 396 | p.Offset = 0; 397 | p.Size = 0; 398 | p.Name = prop.Name; 399 | p.Type = prop.Type; 400 | p.Comment = "NOT AUTO-GENERATED PROPERTY"; 401 | c.Members.push_back(std::move(p)); 402 | } 403 | } 404 | else 405 | { 406 | std::vector properties; 407 | for (auto prop = classObj.GetChildren().Cast(); prop.IsValid(); prop = prop.GetNext().Cast()) 408 | { 409 | if (prop.GetElementSize() > 0 410 | && !prop.IsA() 411 | && !prop.IsA() 412 | && !prop.IsA() 413 | && !prop.IsA() 414 | && (!super.IsValid() 415 | || (super != classObj 416 | && prop.GetOffset() >= super.GetPropertySize() 417 | ) 418 | ) 419 | ) 420 | { 421 | properties.push_back(prop); 422 | } 423 | } 424 | std::sort(std::begin(properties), std::end(properties), ComparePropertyLess); 425 | 426 | GenerateMembers(classObj, offset, properties, c.Members); 427 | } 428 | 429 | generator->GetPredefinedClassMethods(c.FullName, c.PredefinedMethods); 430 | 431 | if (generator->ShouldUseStrings()) 432 | { 433 | c.PredefinedMethods.push_back(IGenerator::PredefinedMethod::Inline(tfm::format(R"( static UClass* StaticClass() 434 | { 435 | static UClass* ptr = nullptr; 436 | if (!ptr) ptr = UObject::FindClass(%s); 437 | return ptr; 438 | })", generator->ShouldXorStrings() ? tfm::format("_xor_(\"%s\")", c.FullName) : tfm::format("\"%s\"", c.FullName)))); 439 | } 440 | else 441 | { 442 | c.PredefinedMethods.push_back(IGenerator::PredefinedMethod::Inline(tfm::format(R"( static UClass* StaticClass() 443 | { 444 | static UClass* ptr = nullptr; 445 | if (!ptr) ptr = UObject::FindClass(0x%08x); 446 | return ptr; 447 | })", fnv_hash_runtime(c.FullName.c_str())))); 448 | } 449 | 450 | GenerateMethods(classObj, c.Methods); 451 | 452 | //search virtual functions 453 | IGenerator::VirtualFunctionPatterns patterns; 454 | if (generator->GetVirtualFunctionPatterns(c.FullName, patterns)) 455 | { 456 | const auto vtable = *reinterpret_cast(classObj.GetAddress()); 457 | 458 | size_t methodCount = 0; 459 | while (true) 460 | { 461 | MEMORY_BASIC_INFORMATION mbi; 462 | auto res = VirtualQuery(reinterpret_cast(vtable[methodCount]), &mbi, sizeof(mbi)); 463 | if (res == 0 || (mbi.Protect != PAGE_EXECUTE_READWRITE && mbi.Protect != PAGE_EXECUTE_READ)) 464 | { 465 | break; 466 | } 467 | ++methodCount; 468 | } 469 | 470 | for (auto&& pattern : patterns) 471 | { 472 | for (auto i = 0u; i < methodCount; ++i) 473 | { 474 | if (vtable[i] != 0 && FindPattern(vtable[i], std::get<2>(pattern), reinterpret_cast(std::get<0>(pattern)), std::get<1>(pattern)) != -1) 475 | { 476 | c.PredefinedMethods.push_back(IGenerator::PredefinedMethod::Inline(tfm::format(std::get<3>(pattern), i))); 477 | break; 478 | } 479 | } 480 | } 481 | } 482 | 483 | classes.emplace_back(std::move(c)); 484 | } 485 | 486 | Package::Member Package::CreatePadding(size_t id, size_t offset, size_t size, std::string reason) 487 | { 488 | Member ss; 489 | ss.Name = tfm::format("UnknownData%02d[0x%X]", id, size); 490 | ss.Type = "unsigned char"; 491 | ss.Offset = offset; 492 | ss.Size = size; 493 | ss.Comment = std::move(reason); 494 | return ss; 495 | } 496 | 497 | Package::Member Package::CreateBitfieldPadding(size_t id, size_t offset, std::string type, size_t bits) 498 | { 499 | Member ss; 500 | ss.Name = tfm::format("UnknownData%02d : %d", id, bits); 501 | ss.Type = std::move(type); 502 | ss.Offset = offset; 503 | ss.Size = 1; 504 | return ss; 505 | } 506 | 507 | void Package::GenerateMembers(const UEStruct& structObj, size_t offset, const std::vector& properties, std::vector& members) const 508 | { 509 | extern IGenerator* generator; 510 | 511 | std::unordered_map uniqueMemberNames; 512 | size_t unknownDataCounter = 0; 513 | UEBoolProperty previousBitfieldProperty; 514 | 515 | for (auto&& prop : properties) 516 | { 517 | if (offset < prop.GetOffset()) 518 | { 519 | previousBitfieldProperty = UEBoolProperty(); 520 | 521 | const auto size = prop.GetOffset() - offset; 522 | members.emplace_back(CreatePadding(unknownDataCounter++, offset, size, "MISSED OFFSET")); 523 | } 524 | 525 | const auto info = prop.GetInfo(); 526 | if (info.Type != UEProperty::PropertyType::Unknown) 527 | { 528 | Member sp; 529 | sp.Offset = prop.GetOffset(); 530 | sp.Size = info.Size; 531 | 532 | sp.Type = info.CppType; 533 | sp.Name = MakeValidName(prop.GetName()); 534 | 535 | const auto it = uniqueMemberNames.find(sp.Name); 536 | if (it == std::end(uniqueMemberNames)) 537 | { 538 | uniqueMemberNames[sp.Name] = 1; 539 | } 540 | else 541 | { 542 | ++uniqueMemberNames[sp.Name]; 543 | sp.Name += tfm::format("%02d", it->second); 544 | } 545 | 546 | if (prop.GetArrayDim() > 1) 547 | { 548 | sp.Name += tfm::format("[0x%X]", prop.GetArrayDim()); 549 | } 550 | 551 | if (prop.IsA() && prop.Cast().IsBitfield()) 552 | { 553 | auto boolProp = prop.Cast(); 554 | 555 | const auto missingBits = boolProp.GetMissingBitsCount(previousBitfieldProperty); 556 | if (missingBits[1] != -1) 557 | { 558 | if (missingBits[0] > 0) 559 | { 560 | members.emplace_back(CreateBitfieldPadding(unknownDataCounter++, previousBitfieldProperty.GetOffset(), info.CppType, missingBits[0])); 561 | } 562 | if (missingBits[1] > 0) 563 | { 564 | members.emplace_back(CreateBitfieldPadding(unknownDataCounter++, sp.Offset, info.CppType, missingBits[1])); 565 | } 566 | } 567 | else if(missingBits[0] > 0) 568 | { 569 | members.emplace_back(CreateBitfieldPadding(unknownDataCounter++, sp.Offset, info.CppType, missingBits[0])); 570 | } 571 | 572 | previousBitfieldProperty = boolProp; 573 | 574 | sp.Name += " : 1"; 575 | } 576 | else 577 | { 578 | previousBitfieldProperty = UEBoolProperty(); 579 | } 580 | 581 | sp.Flags = static_cast(prop.GetPropertyFlags()); 582 | sp.FlagsString = StringifyFlags(prop.GetPropertyFlags()); 583 | 584 | members.emplace_back(std::move(sp)); 585 | 586 | const auto sizeMismatch = static_cast(prop.GetElementSize() * prop.GetArrayDim()) - static_cast(info.Size * prop.GetArrayDim()); 587 | if (sizeMismatch > 0) 588 | { 589 | members.emplace_back(CreatePadding(unknownDataCounter++, offset, sizeMismatch, "FIX WRONG TYPE SIZE OF PREVIOUS PROPERTY")); 590 | } 591 | } 592 | else 593 | { 594 | const auto size = prop.GetElementSize() * prop.GetArrayDim(); 595 | members.emplace_back(CreatePadding(unknownDataCounter++, offset, size, "UNKNOWN PROPERTY: " + prop.GetFullName())); 596 | } 597 | 598 | offset = prop.GetOffset() + prop.GetElementSize() * prop.GetArrayDim(); 599 | } 600 | 601 | if (offset < structObj.GetPropertySize()) 602 | { 603 | const auto size = structObj.GetPropertySize() - offset; 604 | members.emplace_back(CreatePadding(unknownDataCounter++, offset, size, "MISSED OFFSET")); 605 | } 606 | } 607 | 608 | void Package::GenerateMethods(const UEClass& classObj, std::vector& methods) const 609 | { 610 | extern IGenerator* generator; 611 | 612 | //some classes (AnimBlueprintGenerated...) have multiple members with the same name, so filter them out 613 | std::unordered_set uniqueMethods; 614 | 615 | for (auto prop = classObj.GetChildren().Cast(); prop.IsValid(); prop = prop.GetNext().Cast()) 616 | { 617 | if (prop.IsA()) 618 | { 619 | auto function = prop.Cast(); 620 | 621 | Method m; 622 | m.Index = function.GetIndex(); 623 | m.FullName = function.GetFullName(); 624 | m.Name = MakeValidName(function.GetName()); 625 | 626 | if (uniqueMethods.find(m.FullName) != std::end(uniqueMethods)) 627 | { 628 | continue; 629 | } 630 | uniqueMethods.insert(m.FullName); 631 | 632 | m.IsNative = function.GetFunctionFlags() & UEFunctionFlags::Native; 633 | m.IsStatic = function.GetFunctionFlags() & UEFunctionFlags::Static; 634 | m.FlagsString = StringifyFlags(function.GetFunctionFlags()); 635 | 636 | std::vector> parameters; 637 | 638 | std::unordered_map unique; 639 | for (auto param = function.GetChildren().Cast(); param.IsValid(); param = param.GetNext().Cast()) 640 | { 641 | if (param.GetElementSize() == 0) 642 | { 643 | continue; 644 | } 645 | 646 | const auto info = param.GetInfo(); 647 | if (info.Type != UEProperty::PropertyType::Unknown) 648 | { 649 | using Type = Method::Parameter::Type; 650 | 651 | Method::Parameter p; 652 | 653 | if (!Method::Parameter::MakeType(param.GetPropertyFlags(), p.ParamType)) 654 | { 655 | //child isn't a parameter 656 | continue; 657 | } 658 | 659 | p.PassByReference = false; 660 | p.Name = MakeValidName(param.GetName()); 661 | 662 | const auto it = unique.find(p.Name); 663 | if (it == std::end(unique)) 664 | { 665 | unique[p.Name] = 1; 666 | } 667 | else 668 | { 669 | ++unique[p.Name]; 670 | 671 | p.Name += tfm::format("%02d", it->second); 672 | } 673 | 674 | p.FlagsString = StringifyFlags(param.GetPropertyFlags()); 675 | 676 | p.CppType = info.CppType; 677 | if (param.IsA()) 678 | { 679 | p.CppType = generator->GetOverrideType("bool"); 680 | } 681 | switch (p.ParamType) 682 | { 683 | case Type::Default: 684 | if (prop.GetArrayDim() > 1) 685 | { 686 | p.CppType = p.CppType + "*"; 687 | } 688 | else if (info.CanBeReference) 689 | { 690 | p.PassByReference = true; 691 | } 692 | break; 693 | } 694 | 695 | parameters.emplace_back(std::make_pair(prop, std::move(p))); 696 | } 697 | } 698 | 699 | std::sort(std::begin(parameters), std::end(parameters), [](auto&& lhs, auto&& rhs) { return ComparePropertyLess(lhs.first, rhs.first); }); 700 | 701 | for (auto& param : parameters) 702 | { 703 | m.Parameters.emplace_back(std::move(param.second)); 704 | } 705 | 706 | methods.emplace_back(std::move(m)); 707 | } 708 | } 709 | } 710 | 711 | void Package::SaveStructs(const fs::path& path) const 712 | { 713 | extern IGenerator* generator; 714 | 715 | using namespace cpplinq; 716 | 717 | std::ofstream os(path / GenerateFileName(FileContentType::Structs, *this)); 718 | 719 | std::vector includes{ { tfm::format("%s_Basic.hpp", generator->GetGameNameShort()) } }; 720 | 721 | auto dependencyNames = from(this->dependencies) 722 | >> select([](auto&& p) { return GenerateFileName(FileContentType::Classes, Package(p)); }) 723 | >> experimental::container(); 724 | 725 | includes.insert(includes.end(), std::begin(dependencyNames), std::end(dependencyNames)); 726 | 727 | PrintFileHeader(os, includes, true); 728 | 729 | if (!constants.empty()) 730 | { 731 | PrintSectionHeader(os, "Constants"); 732 | for (auto&& c : constants) { PrintConstant(os, c); } 733 | 734 | os << "\n"; 735 | } 736 | 737 | if (!enums.empty()) 738 | { 739 | PrintSectionHeader(os, "Enums"); 740 | for (auto&& e : enums) { PrintEnum(os, e); os << "\n"; } 741 | 742 | os << "\n"; 743 | } 744 | 745 | if (!scriptStructs.empty()) 746 | { 747 | PrintSectionHeader(os, "Script Structs"); 748 | for (auto&& s : scriptStructs) { PrintStruct(os, s); os << "\n"; } 749 | } 750 | 751 | PrintFileFooter(os); 752 | } 753 | 754 | void Package::SaveClasses(const fs::path& path) const 755 | { 756 | extern IGenerator* generator; 757 | 758 | std::ofstream os(path / GenerateFileName(FileContentType::Classes, *this)); 759 | 760 | PrintFileHeader(os, { GenerateFileName(FileContentType::Structs, *this) }, true); 761 | 762 | if (!classes.empty()) 763 | { 764 | PrintSectionHeader(os, "Classes"); 765 | for (auto&& c : classes) { PrintClass(os, c); os << "\n"; } 766 | } 767 | 768 | PrintFileFooter(os); 769 | } 770 | 771 | void Package::SaveFunctions(const fs::path& path) const 772 | { 773 | extern IGenerator* generator; 774 | 775 | if (generator->ShouldGenerateFunctionParametersFile()) 776 | { 777 | SaveFunctionParameters(path); 778 | } 779 | 780 | std::ofstream os(path / GenerateFileName(FileContentType::Functions, *this)); 781 | 782 | PrintFileHeader(os, { GenerateFileName(FileContentType::FunctionParameters, *this) }, false); 783 | 784 | PrintSectionHeader(os, "Functions"); 785 | 786 | for (auto&& s : scriptStructs) 787 | { 788 | for (auto&& m : s.PredefinedMethods) 789 | { 790 | if (m.MethodType != IGenerator::PredefinedMethod::Type::Inline) 791 | { 792 | os << m.Body << "\n\n"; 793 | } 794 | } 795 | } 796 | 797 | for (auto&& c : classes) 798 | { 799 | for (auto&& m : c.PredefinedMethods) 800 | { 801 | if (m.MethodType != IGenerator::PredefinedMethod::Type::Inline) 802 | { 803 | os << m.Body << "\n\n"; 804 | } 805 | } 806 | 807 | for (auto&& m : c.Methods) 808 | { 809 | //Method Info 810 | os << "// " << m.FullName << "\n" 811 | << "// (" << m.FlagsString << ")\n"; 812 | if (!m.Parameters.empty()) 813 | { 814 | os << "// Parameters:\n"; 815 | for (auto&& param : m.Parameters) 816 | { 817 | tfm::format(os, "// %-30s %-30s (%s)\n", param.CppType, param.Name, param.FlagsString); 818 | } 819 | } 820 | 821 | os << "\n"; 822 | os << BuildMethodSignature(m, c, false) << "\n"; 823 | os << BuildMethodBody(c, m) << "\n\n"; 824 | } 825 | } 826 | 827 | PrintFileFooter(os); 828 | } 829 | 830 | void Package::SaveFunctionParameters(const fs::path& path) const 831 | { 832 | using namespace cpplinq; 833 | 834 | std::ofstream os(path / GenerateFileName(FileContentType::FunctionParameters, *this)); 835 | 836 | PrintFileHeader(os, { GenerateFileName(FileContentType::Classes, *this) }, true); 837 | 838 | PrintSectionHeader(os, "Parameters"); 839 | 840 | for (auto&& c : classes) 841 | { 842 | for (auto&& m : c.Methods) 843 | { 844 | os << "// " << m.FullName << "\n"; 845 | tfm::format(os, "struct %s_%s_Params\n{\n", c.NameCpp, m.Name); 846 | for (auto&& param : m.Parameters) 847 | { 848 | tfm::format(os, "\t%-50s %-58s// (%s)\n", param.CppType, param.Name + ";", param.FlagsString); 849 | } 850 | os << "};\n\n"; 851 | } 852 | } 853 | 854 | PrintFileFooter(os); 855 | } 856 | 857 | void Package::PrintConstant(std::ostream& os, const std::pair& c) const 858 | { 859 | tfm::format(os, "#define CONST_%-50s %s\n", c.first, c.second); 860 | } 861 | 862 | void Package::PrintEnum(std::ostream& os, const Enum& e) const 863 | { 864 | using namespace cpplinq; 865 | 866 | os << "// " << e.FullName << "\nenum class " << e.Name << " : uint8_t\n{\n"; 867 | os << (from(e.Values) 868 | >> select([](auto&& name, auto&& i) { return tfm::format("\t%-30s = %d", name, i); }) 869 | >> concatenate(",\n")) 870 | << "\n};\n\n"; 871 | } 872 | 873 | void Package::PrintStruct(std::ostream& os, const ScriptStruct& ss) const 874 | { 875 | using namespace cpplinq; 876 | 877 | os << "// " << ss.FullName << "\n// "; 878 | if (ss.InheritedSize) 879 | { 880 | os << tfm::format("0x%04X (0x%04X - 0x%04X)\n", ss.Size - ss.InheritedSize, ss.Size, ss.InheritedSize); 881 | } 882 | else 883 | { 884 | os << tfm::format("0x%04X\n", ss.Size); 885 | } 886 | 887 | os << ss.NameCppFull << "\n{\n"; 888 | 889 | //Member 890 | os << (from(ss.Members) 891 | >> select([](auto&& m) { 892 | return tfm::format("\t%-50s %-58s// 0x%04X(0x%04X)", m.Type, m.Name + ";", m.Offset, m.Size) 893 | + (!m.Comment.empty() ? " " + m.Comment : "") 894 | + (!m.FlagsString.empty() ? " (" + m.FlagsString + ")" : ""); 895 | }) 896 | >> concatenate("\n")) 897 | << "\n"; 898 | 899 | //Predefined Methods 900 | if (!ss.PredefinedMethods.empty()) 901 | { 902 | os << "\n"; 903 | for (auto&& m : ss.PredefinedMethods) 904 | { 905 | if (m.MethodType == IGenerator::PredefinedMethod::Type::Inline) 906 | { 907 | os << m.Body; 908 | } 909 | else 910 | { 911 | os << "\t" << m.Signature << ";"; 912 | } 913 | os << "\n\n"; 914 | } 915 | } 916 | 917 | os << "};\n"; 918 | } 919 | 920 | void Package::PrintClass(std::ostream& os, const Class& c) const 921 | { 922 | using namespace cpplinq; 923 | 924 | os << "// " << c.FullName << "\n// "; 925 | if (c.InheritedSize) 926 | { 927 | tfm::format(os, "0x%04X (0x%04X - 0x%04X)\n", c.Size - c.InheritedSize, c.Size, c.InheritedSize); 928 | } 929 | else 930 | { 931 | tfm::format(os, "0x%04X\n", c.Size); 932 | } 933 | 934 | os << c.NameCppFull << "\n{\npublic:\n"; 935 | 936 | //Member 937 | for (auto&& m : c.Members) 938 | { 939 | tfm::format(os, "\t%-50s %-58s// 0x%04X(0x%04X)", m.Type, m.Name + ";", m.Offset, m.Size); 940 | if (!m.Comment.empty()) 941 | { 942 | os << " " << m.Comment; 943 | } 944 | if (!m.FlagsString.empty()) 945 | { 946 | os << " (" << m.FlagsString << ")"; 947 | } 948 | os << "\n"; 949 | } 950 | 951 | //Predefined Methods 952 | if (!c.PredefinedMethods.empty()) 953 | { 954 | os << "\n"; 955 | for (auto&& m : c.PredefinedMethods) 956 | { 957 | if (m.MethodType == IGenerator::PredefinedMethod::Type::Inline) 958 | { 959 | os << m.Body; 960 | } 961 | else 962 | { 963 | os << "\t" << m.Signature << ";"; 964 | } 965 | 966 | os << "\n\n"; 967 | } 968 | } 969 | 970 | //Methods 971 | if (!c.Methods.empty()) 972 | { 973 | os << "\n"; 974 | for (auto&& m : c.Methods) 975 | { 976 | os << "\t" << BuildMethodSignature(m, {}, true) << ";\n"; 977 | } 978 | } 979 | 980 | os << "};\n\n"; 981 | } 982 | 983 | std::string Package::BuildMethodSignature(const Method& m, const Class& c, bool inHeader) const 984 | { 985 | extern IGenerator* generator; 986 | 987 | using namespace cpplinq; 988 | using Type = Method::Parameter::Type; 989 | 990 | std::ostringstream ss; 991 | 992 | if (m.IsStatic && inHeader && !generator->ShouldConvertStaticMethods()) 993 | { 994 | ss << "static "; 995 | } 996 | 997 | //Return Type 998 | auto retn = from(m.Parameters) >> where([](auto&& param) { return param.ParamType == Type::Return; }); 999 | if (retn >> any()) 1000 | { 1001 | ss << (retn >> first()).CppType; 1002 | } 1003 | else 1004 | { 1005 | ss << "void"; 1006 | } 1007 | ss << " "; 1008 | 1009 | if (!inHeader) 1010 | { 1011 | ss << c.NameCpp << "::"; 1012 | } 1013 | if (m.IsStatic && generator->ShouldConvertStaticMethods()) 1014 | { 1015 | ss << "STATIC_"; 1016 | } 1017 | ss << m.Name; 1018 | 1019 | //Parameters 1020 | ss << "("; 1021 | ss << (from(m.Parameters) 1022 | >> where([](auto&& param) { return param.ParamType != Type::Return; }) 1023 | >> orderby([](auto&& param) { return param.ParamType; }) 1024 | >> select([](auto&& param) { return (param.PassByReference ? "const " : "") + param.CppType + (param.PassByReference ? "& " : param.ParamType == Type::Out ? "* " : " ") + ((param.Name == "return") ? "_return" : param.Name); }) 1025 | >> concatenate(", ")); 1026 | ss << ")"; 1027 | 1028 | return ss.str(); 1029 | } 1030 | 1031 | std::string Package::BuildMethodBody(const Class& c, const Method& m) const 1032 | { 1033 | extern IGenerator* generator; 1034 | 1035 | using namespace cpplinq; 1036 | using Type = Method::Parameter::Type; 1037 | 1038 | std::ostringstream ss; 1039 | 1040 | //Function Pointer 1041 | ss << "{\n\tstatic UFunction* fn = nullptr; \n\t if (!fn) fn"; 1042 | 1043 | if (generator->ShouldUseStrings()) 1044 | { 1045 | ss << " = UObject::FindObject("; 1046 | 1047 | if (generator->ShouldXorStrings()) 1048 | { 1049 | ss << "_xor_(\"" << m.FullName << "\")"; 1050 | } 1051 | else 1052 | { 1053 | ss << "\"" << m.FullName << "\""; 1054 | } 1055 | 1056 | ss << ");\n\n"; 1057 | } 1058 | else 1059 | { 1060 | ss << " = UObject::GetObjectCasted(" << m.Index << ");\n\n"; 1061 | } 1062 | 1063 | //Parameters 1064 | if (generator->ShouldGenerateFunctionParametersFile()) 1065 | { 1066 | ss << "\t" << c.NameCpp << "_" << m.Name << "_Params params;\n"; 1067 | } 1068 | else 1069 | { 1070 | ss << "\tstruct\n\t{\n"; 1071 | for (auto&& param : m.Parameters) 1072 | { 1073 | tfm::format(ss, "\t\t%-30s %s;\n", param.CppType, param.Name); 1074 | } 1075 | ss << "\t} params;\n"; 1076 | } 1077 | 1078 | auto defaultParameters = from(m.Parameters) >> where([](auto&& param) { return param.ParamType == Type::Default; }); 1079 | if (defaultParameters >> any()) 1080 | { 1081 | for (auto&& param : defaultParameters >> experimental::container()) 1082 | { 1083 | ss << "\tparams." << param.Name << " = " << param.Name << ";\n"; 1084 | } 1085 | } 1086 | 1087 | ss << "\n"; 1088 | 1089 | //Function Call 1090 | ss << "\tauto flags = fn->FunctionFlags;\n"; 1091 | if (m.IsNative) 1092 | { 1093 | ss << "\tfn->FunctionFlags |= 0x" << tfm::format("%X", static_cast>(UEFunctionFlags::Native)) << ";\n"; 1094 | } 1095 | 1096 | ss << "\n"; 1097 | 1098 | if (m.IsStatic && !generator->ShouldConvertStaticMethods()) 1099 | { 1100 | ss << "\tstatic auto defaultObj = StaticClass()->CreateDefaultObject();\n"; 1101 | ss << "\tdefaultObj->ProcessEvent(fn, ¶ms);\n\n"; 1102 | } 1103 | else 1104 | { 1105 | ss << "\tUObject::ProcessEvent(fn, ¶ms);\n\n"; 1106 | } 1107 | 1108 | ss << "\tfn->FunctionFlags = flags;\n"; 1109 | 1110 | //Out Parameters 1111 | auto out = from(m.Parameters) >> where([](auto&& param) { return param.ParamType == Type::Out; }); 1112 | if (out >> any()) 1113 | { 1114 | ss << "\n"; 1115 | 1116 | for (auto&& param : out >> experimental::container()) 1117 | { 1118 | ss << "\tif (" << param.Name << " != nullptr)\n"; 1119 | ss << "\t\t*" << param.Name << " = params." << param.Name << ";\n"; 1120 | } 1121 | } 1122 | 1123 | //Return Value 1124 | auto retn = from(m.Parameters) >> where([](auto&& param) { return param.ParamType == Type::Return; }); 1125 | if (retn >> any()) 1126 | { 1127 | ss << "\n\treturn params." << (retn >> first()).Name << ";\n"; 1128 | } 1129 | 1130 | ss << "}\n"; 1131 | 1132 | return ss.str(); 1133 | } 1134 | 1135 | bool Package::Method::Parameter::MakeType(UEPropertyFlags flags, Type& type) 1136 | { 1137 | if (flags & UEPropertyFlags::ReturnParm) 1138 | { 1139 | type = Type::Return; 1140 | } 1141 | else if (flags & UEPropertyFlags::OutParm) 1142 | { 1143 | //if it is a const parameter make it a default parameter 1144 | if (flags & UEPropertyFlags::ConstParm) 1145 | { 1146 | type = Type::Default; 1147 | } 1148 | else 1149 | { 1150 | type = Type::Out; 1151 | } 1152 | } 1153 | else if (flags & UEPropertyFlags::Parm) 1154 | { 1155 | type = Type::Default; 1156 | } 1157 | else 1158 | { 1159 | return false; 1160 | } 1161 | 1162 | return true; 1163 | } -------------------------------------------------------------------------------- /src/Package.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | namespace fs = std::experimental::filesystem; 8 | 9 | #include "UE4/GenericTypes.hpp" 10 | 11 | class Package 12 | { 13 | friend struct std::hash; 14 | friend struct PackageDependencyComparer; 15 | friend bool operator==(const Package& lhs, const Package& rhs); 16 | 17 | public: 18 | /// 19 | /// Constructor. 20 | /// 21 | /// The package object. 22 | Package(const UEObject& packageObj); 23 | 24 | std::string GetName() const { return packageObj.GetName(); } 25 | 26 | /// 27 | /// Process the classes the package contains. 28 | /// 29 | void Process(std::unordered_map& processedObjects); 30 | 31 | /// 32 | /// Saves the package classes as C++ code. 33 | /// Files are only generated if there is code present or the generator forces the genertion of empty files. 34 | /// 35 | /// The path to save to. 36 | /// true if files got saved, else false. 37 | bool Save(const fs::path& path) const; 38 | 39 | private: 40 | bool AddDependency(const UEObject& package) const; 41 | 42 | /// 43 | /// Checks and generates the prerequisites of the object. 44 | /// Should be a UEClass or UEScriptStruct. 45 | /// 46 | /// The object. 47 | void GeneratePrerequisites(const UEObject& obj, std::unordered_map& processedObjects); 48 | 49 | /// 50 | /// Checks and generates the prerequisites of the members. 51 | /// 52 | /// The first member in the chain. 53 | void GenerateMemberPrerequisites(const UEProperty& first, std::unordered_map& processedObjects); 54 | 55 | /// 56 | /// Generates a script structure. 57 | /// 58 | /// The script structure object. 59 | void GenerateScriptStruct(const UEScriptStruct& scriptStructObj); 60 | 61 | /// 62 | /// Generates a constant. 63 | /// 64 | /// The constant object. 65 | void GenerateConst(const UEConst& constObj); 66 | 67 | /// 68 | /// Generates an enum. 69 | /// 70 | /// The enum object. 71 | void GenerateEnum(const UEEnum& enumObj); 72 | 73 | /// 74 | /// Generates the class. 75 | /// 76 | /// The class object. 77 | void GenerateClass(const UEClass& classObj); 78 | 79 | /// 80 | /// Writes all structs into the appropriate file. 81 | /// 82 | /// The path to save to. 83 | void SaveStructs(const fs::path& path) const; 84 | 85 | /// 86 | /// Writes all classes into the appropriate file. 87 | /// 88 | /// The path to save to. 89 | void SaveClasses(const fs::path& path) const; 90 | 91 | /// 92 | /// Writes all functions into the appropriate file. 93 | /// 94 | /// The path to save to. 95 | void SaveFunctions(const fs::path& path) const; 96 | 97 | /// 98 | /// Writes all function parameters into the appropriate file. 99 | /// 100 | /// The path to save to. 101 | void SaveFunctionParameters(const fs::path& path) const; 102 | 103 | UEObject packageObj; 104 | mutable std::unordered_set dependencies; 105 | 106 | /// 107 | /// Prints the c++ code of the constant. 108 | /// 109 | /// [in] The stream to print to. 110 | /// The constant to print. 111 | void PrintConstant(std::ostream& os, const std::pair& c) const; 112 | 113 | std::unordered_map constants; 114 | 115 | struct Enum 116 | { 117 | std::string Name; 118 | std::string FullName; 119 | std::vector Values; 120 | }; 121 | 122 | /// 123 | /// Prints the c++ code of the enum. 124 | /// 125 | /// [in] The stream to print to. 126 | /// The enum to print. 127 | void PrintEnum(std::ostream& os, const Enum& e) const; 128 | 129 | std::vector enums; 130 | 131 | struct Member 132 | { 133 | std::string Name; 134 | std::string Type; 135 | 136 | size_t Offset; 137 | size_t Size; 138 | 139 | size_t Flags; 140 | std::string FlagsString; 141 | 142 | std::string Comment; 143 | }; 144 | 145 | /// 146 | /// Generates a padding member. 147 | /// 148 | /// The unique name identifier. 149 | /// The offset. 150 | /// The size. 151 | /// The reason. 152 | /// A padding member. 153 | static Member CreatePadding(size_t id, size_t offset, size_t size, std::string reason); 154 | 155 | /// 156 | /// Generates a padding member. 157 | /// 158 | /// The unique name identifier. 159 | /// The offset. 160 | /// The size. 161 | /// The reason. 162 | /// A padding member. 163 | static Member CreateBitfieldPadding(size_t id, size_t offset, std::string type, size_t bits); 164 | 165 | /// 166 | /// Generates the members of a struct or class. 167 | /// 168 | /// The structure object. 169 | /// The start offset. 170 | /// The properties describing the members. 171 | /// [out] The members of the struct or class. 172 | void GenerateMembers(const UEStruct& structObj, size_t offset, const std::vector& properties, std::vector& members) const; 173 | 174 | struct ScriptStruct 175 | { 176 | std::string Name; 177 | std::string FullName; 178 | std::string NameCpp; 179 | std::string NameCppFull; 180 | 181 | size_t Size; 182 | size_t InheritedSize; 183 | 184 | std::vector Members; 185 | 186 | std::vector PredefinedMethods; 187 | }; 188 | 189 | /// 190 | /// Print the C++ code of the structure. 191 | /// 192 | /// [in] The stream to print to. 193 | /// The structure to print. 194 | void PrintStruct(std::ostream& os, const ScriptStruct& ss) const; 195 | 196 | std::vector scriptStructs; 197 | 198 | struct Method 199 | { 200 | struct Parameter 201 | { 202 | enum class Type 203 | { 204 | Default, 205 | Out, 206 | Return 207 | }; 208 | 209 | Type ParamType; 210 | bool PassByReference; 211 | std::string CppType; 212 | std::string Name; 213 | std::string FlagsString; 214 | 215 | /// 216 | /// Generates a valid type of the property flags. 217 | /// 218 | /// The property flags. 219 | /// [out] The parameter type. 220 | /// true if it is a valid type, else false. 221 | static bool MakeType(UEPropertyFlags flags, Type& type); 222 | }; 223 | 224 | size_t Index; 225 | std::string Name; 226 | std::string FullName; 227 | std::vector Parameters; 228 | std::string FlagsString; 229 | bool IsNative; 230 | bool IsStatic; 231 | }; 232 | 233 | /// 234 | /// Generates the methods of a class. 235 | /// 236 | /// The class object. 237 | /// [out] The methods of the class. 238 | void GenerateMethods(const UEClass& classObj, std::vector& methods) const; 239 | 240 | struct Class : ScriptStruct 241 | { 242 | std::vector VirtualFunctions; 243 | std::vector Methods; 244 | }; 245 | 246 | /// 247 | /// Builds the C++ method signature. 248 | /// 249 | /// The Method to process. 250 | /// Name of the class. 251 | /// true if the signature is used as decleration. 252 | /// The method signature. 253 | std::string BuildMethodSignature(const Method& m, const Class& c, bool inHeader) const; 254 | 255 | /// 256 | /// Builds the c++ method body. 257 | /// 258 | /// The Method to process. 259 | /// The method body. 260 | std::string BuildMethodBody(const Class& c, const Method& m) const; 261 | 262 | /// 263 | /// Print the C++ code of the class. 264 | /// 265 | /// [in] The stream to print to. 266 | /// The class to print. 267 | void PrintClass(std::ostream& os, const Class& c) const; 268 | 269 | std::vector classes; 270 | }; 271 | 272 | namespace std 273 | { 274 | template<> 275 | struct hash 276 | { 277 | size_t operator()(const Package& package) const 278 | { 279 | return std::hash()(package.packageObj.GetAddress()); 280 | } 281 | }; 282 | } 283 | 284 | inline bool operator==(const Package& lhs, const Package& rhs) { return rhs.packageObj.GetAddress() == lhs.packageObj.GetAddress(); } 285 | inline bool operator!=(const Package& lhs, const Package& rhs) { return !(lhs == rhs); } 286 | -------------------------------------------------------------------------------- /src/PatternFinder.cpp: -------------------------------------------------------------------------------- 1 | #include "PatternFinder.hpp" 2 | 3 | #include 4 | #include 5 | 6 | uintptr_t FindPattern(HMODULE module, const unsigned char* pattern, const char* mask) 7 | { 8 | MODULEINFO info = { }; 9 | GetModuleInformation(GetCurrentProcess(), module, &info, sizeof(MODULEINFO)); 10 | 11 | return FindPattern(reinterpret_cast(module), info.SizeOfImage, pattern, mask); 12 | } 13 | 14 | uintptr_t FindPattern(uintptr_t start, size_t length, const unsigned char* pattern, const char* mask) 15 | { 16 | size_t pos = 0; 17 | auto maskLength = std::strlen(mask) - 1; 18 | 19 | auto startAdress = start; 20 | for (auto it = startAdress; it < startAdress + length; ++it) 21 | { 22 | if (*reinterpret_cast(it) == pattern[pos] || mask[pos] == '?') 23 | { 24 | if (mask[pos + 1] == '\0') 25 | { 26 | return it - maskLength; 27 | } 28 | 29 | pos++; 30 | } 31 | else 32 | { 33 | pos = 0; 34 | } 35 | } 36 | 37 | return -1; 38 | } -------------------------------------------------------------------------------- /src/PatternFinder.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /// 7 | /// Searches for the first pattern in the module. 8 | /// 9 | /// The module to scan. 10 | /// The pattern (Example: "\x12\xAB\x34") 11 | /// The mask (Example: "x?x") 12 | /// The address of the found pattern or -1 if the pattern was not found. 13 | uintptr_t FindPattern(HMODULE module, const unsigned char* pattern, const char* mask); 14 | 15 | /// 16 | /// Searches for the first pattern in the memory region. 17 | /// 18 | /// The start address of the memory region to scan. 19 | /// The length of the memory region. 20 | /// The pattern (Example: "\x12\xAB\x34") 21 | /// The mask (Example: "x?x") 22 | /// The address of the found pattern or -1 if the pattern was not found. 23 | uintptr_t FindPattern(uintptr_t start, size_t length, const unsigned char* pattern, const char* mask); -------------------------------------------------------------------------------- /src/PrintHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "PrintHelper.hpp" 2 | 3 | #include "tinyformat.h" 4 | 5 | #include "IGenerator.hpp" 6 | #include "Package.hpp" 7 | 8 | void PrintFileHeader(std::ostream& os, const std::vector& includes, const bool isHeaderFile) 9 | { 10 | extern IGenerator* generator; 11 | 12 | if (isHeaderFile) 13 | { 14 | os << "#pragma once\n\n"; 15 | } 16 | 17 | os << tfm::format("// %s (%s) SDK\n\n", generator->GetGameName(), generator->GetGameVersion()) 18 | << tfm::format("#ifdef _MSC_VER\n\t#pragma pack(push, 0x%X)\n#endif\n\n", generator->GetGlobalMemberAlignment()); 19 | 20 | if (!includes.empty()) 21 | { 22 | for (auto&& i : includes) 23 | { 24 | if (i[0] != '<' && i[0] != '"') 25 | { 26 | os << "#include \"" << i << "\"\n"; 27 | } 28 | else 29 | { 30 | os << "#include " << i << "\n"; 31 | } 32 | } 33 | os << "\n"; 34 | } 35 | 36 | if (!generator->GetNamespaceName().empty()) 37 | { 38 | os << "namespace " << generator->GetNamespaceName() << "\n{\n"; 39 | } 40 | } 41 | 42 | void PrintFileHeader(std::ostream& os, const bool isHeaderFile) 43 | { 44 | extern IGenerator* generator; 45 | 46 | PrintFileHeader(os, std::vector(), isHeaderFile); 47 | } 48 | 49 | void PrintFileFooter(std::ostream& os) 50 | { 51 | extern IGenerator* generator; 52 | 53 | if (!generator->GetNamespaceName().empty()) 54 | { 55 | os << "}\n\n"; 56 | } 57 | 58 | os << "#ifdef _MSC_VER\n\t#pragma pack(pop)\n#endif\n"; 59 | } 60 | 61 | void PrintSectionHeader(std::ostream& os, const char* name) 62 | { 63 | os << "//---------------------------------------------------------------------------\n" 64 | << "//" << name << "\n" 65 | << "//---------------------------------------------------------------------------\n\n"; 66 | } 67 | 68 | std::string GenerateFileName(const FileContentType type, const Package& package) 69 | { 70 | extern IGenerator* generator; 71 | 72 | const char* name = ""; 73 | switch (type) 74 | { 75 | case FileContentType::Structs: 76 | name = "%s_%s_structs.hpp"; 77 | break; 78 | case FileContentType::Classes: 79 | name = "%s_%s_classes.hpp"; 80 | break; 81 | case FileContentType::Functions: 82 | name = "%s_%s_functions.cpp"; 83 | break; 84 | case FileContentType::FunctionParameters: 85 | name = "%s_%s_parameters.hpp"; 86 | break; 87 | default: 88 | assert(false); 89 | } 90 | 91 | return tfm::format(name, generator->GetGameNameShort(), package.GetName()); 92 | } 93 | -------------------------------------------------------------------------------- /src/PrintHelper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | void PrintFileHeader(std::ostream& os, const std::vector& includes, const bool isHeaderFile); 7 | 8 | void PrintFileHeader(std::ostream& os, const bool isHeaderFile); 9 | 10 | void PrintFileFooter(std::ostream& os); 11 | 12 | void PrintSectionHeader(std::ostream& os, const char* name); 13 | 14 | enum class FileContentType 15 | { 16 | Structs, 17 | Classes, 18 | Functions, 19 | FunctionParameters 20 | }; 21 | 22 | /// 23 | /// Generates a file name composed by the game name and the package object. 24 | /// 25 | /// The type of the file. 26 | /// 27 | /// The generated file name. 28 | /// 29 | std::string GenerateFileName(const FileContentType type, const class Package& package); 30 | -------------------------------------------------------------------------------- /src/UE4/FunctionFlags.cpp: -------------------------------------------------------------------------------- 1 | #include "FunctionFlags.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | std::string StringifyFlags(const UEFunctionFlags flags) 8 | { 9 | std::vector buffer; 10 | 11 | if (flags & UEFunctionFlags::Final) { buffer.push_back("Final"); } 12 | if (flags & UEFunctionFlags::RequiredAPI) { buffer.push_back("RequiredAPI"); } 13 | if (flags & UEFunctionFlags::BlueprintAuthorityOnly) { buffer.push_back("BlueprintAuthorityOnly"); } 14 | if (flags & UEFunctionFlags::BlueprintCosmetic) { buffer.push_back("BlueprintCosmetic"); } 15 | if (flags & UEFunctionFlags::Net) { buffer.push_back("Net"); } 16 | if (flags & UEFunctionFlags::NetReliable) { buffer.push_back("NetReliable"); } 17 | if (flags & UEFunctionFlags::NetRequest) { buffer.push_back("NetRequest"); } 18 | if (flags & UEFunctionFlags::Exec) { buffer.push_back("Exec"); } 19 | if (flags & UEFunctionFlags::Native) { buffer.push_back("Native"); } 20 | if (flags & UEFunctionFlags::Event) { buffer.push_back("Event"); } 21 | if (flags & UEFunctionFlags::NetResponse) { buffer.push_back("NetResponse"); } 22 | if (flags & UEFunctionFlags::Static) { buffer.push_back("Static"); } 23 | if (flags & UEFunctionFlags::NetMulticast) { buffer.push_back("NetMulticast"); } 24 | if (flags & UEFunctionFlags::MulticastDelegate) { buffer.push_back("MulticastDelegate"); } 25 | if (flags & UEFunctionFlags::Public) { buffer.push_back("Public"); } 26 | if (flags & UEFunctionFlags::Private) { buffer.push_back("Private"); } 27 | if (flags & UEFunctionFlags::Protected) { buffer.push_back("Protected"); } 28 | if (flags & UEFunctionFlags::Delegate) { buffer.push_back("Delegate"); } 29 | if (flags & UEFunctionFlags::NetServer) { buffer.push_back("NetServer"); } 30 | if (flags & UEFunctionFlags::HasOutParms) { buffer.push_back("HasOutParms"); } 31 | if (flags & UEFunctionFlags::HasDefaults) { buffer.push_back("HasDefaults"); } 32 | if (flags & UEFunctionFlags::NetClient) { buffer.push_back("NetClient"); } 33 | if (flags & UEFunctionFlags::DLLImport) { buffer.push_back("DLLImport"); } 34 | if (flags & UEFunctionFlags::BlueprintCallable) { buffer.push_back("BlueprintCallable"); } 35 | if (flags & UEFunctionFlags::BlueprintEvent) { buffer.push_back("BlueprintEvent"); } 36 | if (flags & UEFunctionFlags::BlueprintPure) { buffer.push_back("BlueprintPure"); } 37 | if (flags & UEFunctionFlags::Const) { buffer.push_back("Const"); } 38 | if (flags & UEFunctionFlags::NetValidate) { buffer.push_back("NetValidate"); } 39 | 40 | switch (buffer.size()) 41 | { 42 | case 0: 43 | return std::string(); 44 | case 1: 45 | return std::string(buffer[0]); 46 | default: 47 | std::ostringstream os; 48 | std::copy(buffer.begin(), buffer.end() - 1, std::ostream_iterator(os, ", ")); 49 | os << *buffer.rbegin(); 50 | return os.str(); 51 | } 52 | } -------------------------------------------------------------------------------- /src/UE4/FunctionFlags.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | enum class UEFunctionFlags : uint32_t 7 | { 8 | Final = 0x00000001, 9 | RequiredAPI = 0x00000002, 10 | BlueprintAuthorityOnly = 0x00000004, 11 | BlueprintCosmetic = 0x00000008, 12 | Net = 0x00000040, 13 | NetReliable = 0x00000080, 14 | NetRequest = 0x00000100, 15 | Exec = 0x00000200, 16 | Native = 0x00000400, 17 | Event = 0x00000800, 18 | NetResponse = 0x00001000, 19 | Static = 0x00002000, 20 | NetMulticast = 0x00004000, 21 | MulticastDelegate = 0x00010000, 22 | Public = 0x00020000, 23 | Private = 0x00040000, 24 | Protected = 0x00080000, 25 | Delegate = 0x00100000, 26 | NetServer = 0x00200000, 27 | HasOutParms = 0x00400000, 28 | HasDefaults = 0x00800000, 29 | NetClient = 0x01000000, 30 | DLLImport = 0x02000000, 31 | BlueprintCallable = 0x04000000, 32 | BlueprintEvent = 0x08000000, 33 | BlueprintPure = 0x10000000, 34 | Const = 0x40000000, 35 | NetValidate = 0x80000000 36 | }; 37 | 38 | inline bool operator&(UEFunctionFlags lhs, UEFunctionFlags rhs) 39 | { 40 | return (static_cast>(lhs) & static_cast>(rhs)) == static_cast>(rhs); 41 | } 42 | 43 | std::string StringifyFlags(const UEFunctionFlags flags); 44 | -------------------------------------------------------------------------------- /src/UE4/GenericTypes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "PropertyFlags.hpp" 8 | #include "FunctionFlags.hpp" 9 | #include "../IGenerator.hpp" 10 | 11 | class UObject; 12 | class UEClass; 13 | 14 | class UEObject 15 | { 16 | public: 17 | UEObject() 18 | : object(nullptr) 19 | { 20 | } 21 | UEObject(UObject *_object) 22 | : object(_object) 23 | { 24 | } 25 | 26 | bool IsValid() const 27 | { 28 | return object != nullptr; 29 | } 30 | 31 | size_t GetIndex() const; 32 | 33 | UEClass GetClass() const; 34 | 35 | UEObject GetOuter() const; 36 | 37 | std::string GetName() const; 38 | 39 | std::string GetFullName() const; 40 | 41 | std::string GetNameCPP() const; 42 | 43 | UEObject GetPackageObject() const; 44 | 45 | void* GetAddress() const; 46 | 47 | template 48 | Base Cast() const 49 | { 50 | return Base(object); 51 | } 52 | 53 | template 54 | bool IsA() const; 55 | 56 | static UEClass StaticClass(); 57 | 58 | protected: 59 | UObject* object; 60 | }; 61 | 62 | namespace std 63 | { 64 | template<> 65 | struct hash 66 | { 67 | size_t operator()(const UEObject& obj) const 68 | { 69 | return std::hash()(obj.GetAddress()); 70 | } 71 | }; 72 | } 73 | 74 | inline bool operator==(const UEObject& lhs, const UEObject& rhs) { return rhs.GetAddress() == lhs.GetAddress(); } 75 | inline bool operator!=(const UEObject& lhs, const UEObject& rhs) { return !(lhs == rhs); } 76 | 77 | class UEField : public UEObject 78 | { 79 | public: 80 | using UEObject::UEObject; 81 | 82 | UEField GetNext() const; 83 | 84 | static UEClass StaticClass(); 85 | }; 86 | 87 | class UEEnum : public UEField 88 | { 89 | public: 90 | using UEField::UEField; 91 | 92 | std::vector GetNames() const; 93 | 94 | static UEClass StaticClass(); 95 | }; 96 | 97 | class UEConst : public UEField 98 | { 99 | public: 100 | using UEField::UEField; 101 | 102 | std::string GetValue() const; 103 | 104 | static UEClass StaticClass(); 105 | }; 106 | 107 | class UEStruct : public UEField 108 | { 109 | public: 110 | using UEField::UEField; 111 | 112 | UEStruct GetSuper() const; 113 | 114 | UEField GetChildren() const; 115 | 116 | size_t GetPropertySize() const; 117 | 118 | static UEClass StaticClass(); 119 | }; 120 | 121 | class UEScriptStruct : public UEStruct 122 | { 123 | public: 124 | using UEStruct::UEStruct; 125 | 126 | static UEClass StaticClass(); 127 | }; 128 | 129 | class UEFunction : public UEStruct 130 | { 131 | public: 132 | using UEStruct::UEStruct; 133 | 134 | UEFunctionFlags GetFunctionFlags() const; 135 | 136 | static UEClass StaticClass(); 137 | }; 138 | 139 | class UEClass : public UEStruct 140 | { 141 | public: 142 | using UEStruct::UEStruct; 143 | 144 | static UEClass StaticClass(); 145 | }; 146 | 147 | class UEProperty : public UEField 148 | { 149 | public: 150 | using UEField::UEField; 151 | 152 | size_t GetArrayDim() const; 153 | 154 | size_t GetElementSize() const; 155 | 156 | UEPropertyFlags GetPropertyFlags() const; 157 | 158 | size_t GetOffset() const; 159 | 160 | enum class PropertyType 161 | { 162 | Unknown, 163 | Primitive, 164 | PredefinedStruct, 165 | CustomStruct, 166 | Container 167 | }; 168 | 169 | struct Info 170 | { 171 | PropertyType Type; 172 | size_t Size; 173 | bool CanBeReference; 174 | std::string CppType; 175 | 176 | static Info Create(PropertyType type, size_t size, bool reference, std::string&& cppType) 177 | { 178 | extern IGenerator* generator; 179 | 180 | return { type, size, reference, generator->GetOverrideType(cppType) }; 181 | } 182 | }; 183 | 184 | Info GetInfo() const; 185 | 186 | static UEClass StaticClass(); 187 | }; 188 | 189 | class UENumericProperty : public UEProperty 190 | { 191 | public: 192 | using UEProperty::UEProperty; 193 | 194 | static UEClass StaticClass(); 195 | }; 196 | 197 | class UEByteProperty : public UENumericProperty 198 | { 199 | public: 200 | using UENumericProperty::UENumericProperty; 201 | 202 | bool IsEnum() const; 203 | 204 | UEEnum GetEnum() const; 205 | 206 | UEProperty::Info GetInfo() const; 207 | 208 | static UEClass StaticClass(); 209 | }; 210 | 211 | class UEUInt16Property : public UENumericProperty 212 | { 213 | public: 214 | using UENumericProperty::UENumericProperty; 215 | 216 | UEProperty::Info GetInfo() const; 217 | 218 | static UEClass StaticClass(); 219 | }; 220 | 221 | class UEUInt32Property : public UENumericProperty 222 | { 223 | public: 224 | using UENumericProperty::UENumericProperty; 225 | 226 | UEProperty::Info GetInfo() const; 227 | 228 | static UEClass StaticClass(); 229 | }; 230 | 231 | class UEUInt64Property : public UENumericProperty 232 | { 233 | public: 234 | using UENumericProperty::UENumericProperty; 235 | 236 | UEProperty::Info GetInfo() const; 237 | 238 | static UEClass StaticClass(); 239 | }; 240 | 241 | class UEInt8Property : public UENumericProperty 242 | { 243 | public: 244 | using UENumericProperty::UENumericProperty; 245 | 246 | UEProperty::Info GetInfo() const; 247 | 248 | static UEClass StaticClass(); 249 | }; 250 | 251 | class UEInt16Property : public UENumericProperty 252 | { 253 | public: 254 | using UENumericProperty::UENumericProperty; 255 | 256 | UEProperty::Info GetInfo() const; 257 | 258 | static UEClass StaticClass(); 259 | }; 260 | 261 | class UEIntProperty : public UENumericProperty 262 | { 263 | public: 264 | using UENumericProperty::UENumericProperty; 265 | 266 | UEProperty::Info GetInfo() const; 267 | 268 | static UEClass StaticClass(); 269 | }; 270 | 271 | class UEInt64Property : public UENumericProperty 272 | { 273 | public: 274 | using UENumericProperty::UENumericProperty; 275 | 276 | UEProperty::Info GetInfo() const; 277 | 278 | static UEClass StaticClass(); 279 | }; 280 | 281 | class UEFloatProperty : public UENumericProperty 282 | { 283 | public: 284 | using UENumericProperty::UENumericProperty; 285 | 286 | UEProperty::Info GetInfo() const; 287 | 288 | static UEClass StaticClass(); 289 | }; 290 | 291 | class UEDoubleProperty : public UENumericProperty 292 | { 293 | public: 294 | using UENumericProperty::UENumericProperty; 295 | 296 | UEProperty::Info GetInfo() const; 297 | 298 | static UEClass StaticClass(); 299 | }; 300 | 301 | class UEBoolProperty : public UEProperty 302 | { 303 | public: 304 | using UEProperty::UEProperty; 305 | 306 | bool IsNativeBool() const { return GetFieldMask() == 0xFF; } 307 | 308 | bool IsBitfield() const { return !IsNativeBool(); } 309 | 310 | uint8_t GetFieldSize() const; 311 | 312 | uint8_t GetByteOffset() const; 313 | 314 | uint8_t GetByteMask() const; 315 | 316 | uint8_t GetFieldMask() const; 317 | 318 | std::array GetMissingBitsCount(const UEBoolProperty& other) const; 319 | 320 | UEProperty::Info GetInfo() const; 321 | 322 | static UEClass StaticClass(); 323 | }; 324 | 325 | inline bool operator<(const UEBoolProperty& lhs, const UEBoolProperty& rhs) 326 | { 327 | if (lhs.GetByteOffset() == rhs.GetByteOffset()) 328 | { 329 | return lhs.GetByteMask() < rhs.GetByteMask(); 330 | } 331 | return lhs.GetByteOffset() < rhs.GetByteOffset(); 332 | } 333 | 334 | class UEObjectPropertyBase : public UEProperty 335 | { 336 | public: 337 | using UEProperty::UEProperty; 338 | 339 | UEClass GetPropertyClass() const; 340 | 341 | static UEClass StaticClass(); 342 | }; 343 | 344 | class UEObjectProperty : public UEObjectPropertyBase 345 | { 346 | public: 347 | using UEObjectPropertyBase::UEObjectPropertyBase; 348 | 349 | UEProperty::Info GetInfo() const; 350 | 351 | static UEClass StaticClass(); 352 | }; 353 | 354 | class UEClassProperty : public UEObjectProperty 355 | { 356 | public: 357 | using UEObjectProperty::UEObjectProperty; 358 | 359 | UEClass GetMetaClass() const; 360 | 361 | UEProperty::Info GetInfo() const; 362 | 363 | static UEClass StaticClass(); 364 | }; 365 | 366 | class UEInterfaceProperty : public UEProperty 367 | { 368 | public: 369 | using UEProperty::UEProperty; 370 | 371 | UEClass GetInterfaceClass() const; 372 | 373 | UEProperty::Info GetInfo() const; 374 | 375 | static UEClass StaticClass(); 376 | }; 377 | 378 | class UEWeakObjectProperty : public UEObjectPropertyBase 379 | { 380 | public: 381 | using UEObjectPropertyBase::UEObjectPropertyBase; 382 | 383 | UEProperty::Info GetInfo() const; 384 | 385 | static UEClass StaticClass(); 386 | }; 387 | 388 | class UELazyObjectProperty : public UEObjectPropertyBase 389 | { 390 | public: 391 | using UEObjectPropertyBase::UEObjectPropertyBase; 392 | 393 | UEProperty::Info GetInfo() const; 394 | 395 | static UEClass StaticClass(); 396 | }; 397 | 398 | class UEAssetObjectProperty : public UEObjectPropertyBase 399 | { 400 | public: 401 | using UEObjectPropertyBase::UEObjectPropertyBase; 402 | 403 | UEProperty::Info GetInfo() const; 404 | 405 | static UEClass StaticClass(); 406 | }; 407 | 408 | class UEAssetClassProperty : public UEAssetObjectProperty 409 | { 410 | public: 411 | using UEAssetObjectProperty::UEAssetObjectProperty; 412 | 413 | UEClass GetMetaClass() const; 414 | 415 | UEProperty::Info GetInfo() const; 416 | 417 | static UEClass StaticClass(); 418 | }; 419 | 420 | class UENameProperty : public UEProperty 421 | { 422 | public: 423 | using UEProperty::UEProperty; 424 | 425 | UEProperty::Info GetInfo() const; 426 | 427 | static UEClass StaticClass(); 428 | }; 429 | 430 | class UEStructProperty : public UEProperty 431 | { 432 | public: 433 | using UEProperty::UEProperty; 434 | 435 | UEScriptStruct GetStruct() const; 436 | 437 | UEProperty::Info GetInfo() const; 438 | 439 | static UEClass StaticClass(); 440 | }; 441 | 442 | class UEStrProperty : public UEProperty 443 | { 444 | public: 445 | using UEProperty::UEProperty; 446 | 447 | UEProperty::Info GetInfo() const; 448 | 449 | static UEClass StaticClass(); 450 | }; 451 | 452 | class UETextProperty : public UEProperty 453 | { 454 | public: 455 | using UEProperty::UEProperty; 456 | 457 | UEProperty::Info GetInfo() const; 458 | 459 | static UEClass StaticClass(); 460 | }; 461 | 462 | class UEArrayProperty : public UEProperty 463 | { 464 | public: 465 | using UEProperty::UEProperty; 466 | 467 | UEProperty GetInner() const; 468 | 469 | UEProperty::Info GetInfo() const; 470 | 471 | static UEClass StaticClass(); 472 | }; 473 | 474 | class UEMapProperty : public UEProperty 475 | { 476 | public: 477 | using UEProperty::UEProperty; 478 | 479 | UEProperty GetKeyProperty() const; 480 | UEProperty GetValueProperty() const; 481 | 482 | UEProperty::Info GetInfo() const; 483 | 484 | static UEClass StaticClass(); 485 | }; 486 | 487 | class UEDelegateProperty : public UEProperty 488 | { 489 | public: 490 | using UEProperty::UEProperty; 491 | 492 | UEFunction GetSignatureFunction() const; 493 | 494 | UEProperty::Info GetInfo() const; 495 | 496 | static UEClass StaticClass(); 497 | }; 498 | 499 | class UEMulticastDelegateProperty : public UEProperty 500 | { 501 | public: 502 | using UEProperty::UEProperty; 503 | 504 | UEFunction GetSignatureFunction() const; 505 | 506 | UEProperty::Info GetInfo() const; 507 | 508 | static UEClass StaticClass(); 509 | }; 510 | 511 | class UEEnumProperty : public UEProperty 512 | { 513 | public: 514 | using UEProperty::UEProperty; 515 | 516 | UENumericProperty GetUnderlyingProperty() const; 517 | UEEnum GetEnum() const; 518 | 519 | UEProperty::Info GetInfo() const; 520 | 521 | static UEClass StaticClass(); 522 | }; 523 | 524 | template 525 | bool UEObject::IsA() const 526 | { 527 | auto cmp = T::StaticClass(); 528 | if (!cmp.IsValid()) 529 | { 530 | return false; 531 | } 532 | 533 | for (auto super = GetClass(); super.IsValid(); super = super.GetSuper().Cast()) 534 | { 535 | if (super.object == cmp.object) 536 | { 537 | return true; 538 | } 539 | } 540 | 541 | return false; 542 | } -------------------------------------------------------------------------------- /src/UE4/PropertyFlags.cpp: -------------------------------------------------------------------------------- 1 | #include "PropertyFlags.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | std::string StringifyFlags(const UEPropertyFlags flags) 8 | { 9 | std::vector buffer; 10 | 11 | if (flags & UEPropertyFlags::Edit) { buffer.push_back("Edit"); } 12 | if (flags & UEPropertyFlags::ConstParm) { buffer.push_back("ConstParm"); } 13 | if (flags & UEPropertyFlags::BlueprintVisible) { buffer.push_back("BlueprintVisible"); } 14 | if (flags & UEPropertyFlags::ExportObject) { buffer.push_back("ExportObject"); } 15 | if (flags & UEPropertyFlags::BlueprintReadOnly) { buffer.push_back("BlueprintReadOnly"); } 16 | if (flags & UEPropertyFlags::Net) { buffer.push_back("Net"); } 17 | if (flags & UEPropertyFlags::EditFixedSize) { buffer.push_back("EditFixedSize"); } 18 | if (flags & UEPropertyFlags::Parm) { buffer.push_back("Parm"); } 19 | if (flags & UEPropertyFlags::OutParm) { buffer.push_back("OutParm"); } 20 | if (flags & UEPropertyFlags::ZeroConstructor) { buffer.push_back("ZeroConstructor"); } 21 | if (flags & UEPropertyFlags::ReturnParm) { buffer.push_back("ReturnParm"); } 22 | if (flags & UEPropertyFlags::DisableEditOnTemplate) { buffer.push_back("DisableEditOnTemplate"); } 23 | if (flags & UEPropertyFlags::Transient) { buffer.push_back("Transient"); } 24 | if (flags & UEPropertyFlags::Config) { buffer.push_back("Config"); } 25 | if (flags & UEPropertyFlags::DisableEditOnInstance) { buffer.push_back("DisableEditOnInstance"); } 26 | if (flags & UEPropertyFlags::EditConst) { buffer.push_back("EditConst"); } 27 | if (flags & UEPropertyFlags::GlobalConfig) { buffer.push_back("GlobalConfig"); } 28 | if (flags & UEPropertyFlags::InstancedReference) { buffer.push_back("InstancedReference"); } 29 | if (flags & UEPropertyFlags::DuplicateTransient) { buffer.push_back("DuplicateTransient"); } 30 | if (flags & UEPropertyFlags::SubobjectReference) { buffer.push_back("SubobjectReference"); } 31 | if (flags & UEPropertyFlags::SaveGame) { buffer.push_back("SaveGame"); } 32 | if (flags & UEPropertyFlags::NoClear) { buffer.push_back("NoClear"); } 33 | if (flags & UEPropertyFlags::ReferenceParm) { buffer.push_back("ReferenceParm"); } 34 | if (flags & UEPropertyFlags::BlueprintAssignable) { buffer.push_back("BlueprintAssignable"); } 35 | if (flags & UEPropertyFlags::Deprecated) { buffer.push_back("Deprecated"); } 36 | if (flags & UEPropertyFlags::IsPlainOldData) { buffer.push_back("IsPlainOldData"); } 37 | if (flags & UEPropertyFlags::RepSkip) { buffer.push_back("RepSkip"); } 38 | if (flags & UEPropertyFlags::RepNotify) { buffer.push_back("RepNotify"); } 39 | if (flags & UEPropertyFlags::Interp) { buffer.push_back("Interp"); } 40 | if (flags & UEPropertyFlags::NonTransactional) { buffer.push_back("NonTransactional"); } 41 | if (flags & UEPropertyFlags::EditorOnly) { buffer.push_back("EditorOnly"); } 42 | if (flags & UEPropertyFlags::NoDestructor) { buffer.push_back("NoDestructor"); } 43 | if (flags & UEPropertyFlags::AutoWeak) { buffer.push_back("AutoWeak"); } 44 | if (flags & UEPropertyFlags::ContainsInstancedReference) { buffer.push_back("ContainsInstancedReference"); } 45 | if (flags & UEPropertyFlags::AssetRegistrySearchable) { buffer.push_back("AssetRegistrySearchable"); } 46 | if (flags & UEPropertyFlags::SimpleDisplay) { buffer.push_back("SimpleDisplay"); } 47 | if (flags & UEPropertyFlags::AdvancedDisplay) { buffer.push_back("AdvancedDisplay"); } 48 | if (flags & UEPropertyFlags::Protected) { buffer.push_back("Protected"); } 49 | if (flags & UEPropertyFlags::BlueprintCallable) { buffer.push_back("BlueprintCallable"); } 50 | if (flags & UEPropertyFlags::BlueprintAuthorityOnly) { buffer.push_back("BlueprintAuthorityOnly"); } 51 | if (flags & UEPropertyFlags::TextExportTransient) { buffer.push_back("TextExportTransient"); } 52 | if (flags & UEPropertyFlags::NonPIEDuplicateTransient) { buffer.push_back("NonPIEDuplicateTransient"); } 53 | if (flags & UEPropertyFlags::ExposeOnSpawn) { buffer.push_back("ExposeOnSpawn"); } 54 | if (flags & UEPropertyFlags::PersistentInstance) { buffer.push_back("PersistentInstance"); } 55 | if (flags & UEPropertyFlags::UObjectWrapper) { buffer.push_back("UObjectWrapper"); } 56 | if (flags & UEPropertyFlags::HasGetValueTypeHash) { buffer.push_back("HasGetValueTypeHash"); } 57 | if (flags & UEPropertyFlags::NativeAccessSpecifierPublic) { buffer.push_back("NativeAccessSpecifierPublic"); } 58 | if (flags & UEPropertyFlags::NativeAccessSpecifierProtected) { buffer.push_back("NativeAccessSpecifierProtected"); } 59 | if (flags & UEPropertyFlags::NativeAccessSpecifierPrivate) { buffer.push_back("NativeAccessSpecifierPrivate"); } 60 | 61 | switch (buffer.size()) 62 | { 63 | case 0: 64 | return std::string(); 65 | case 1: 66 | return std::string(buffer[0]); 67 | default: 68 | std::ostringstream os; 69 | std::copy(buffer.begin(), buffer.end() - 1, std::ostream_iterator(os, ", ")); 70 | os << *buffer.rbegin(); 71 | return os.str(); 72 | } 73 | } -------------------------------------------------------------------------------- /src/UE4/PropertyFlags.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | enum class UEPropertyFlags : uint64_t 7 | { 8 | Edit = 0x0000000000000001, 9 | ConstParm = 0x0000000000000002, 10 | BlueprintVisible = 0x0000000000000004, 11 | ExportObject = 0x0000000000000008, 12 | BlueprintReadOnly = 0x0000000000000010, 13 | Net = 0x0000000000000020, 14 | EditFixedSize = 0x0000000000000040, 15 | Parm = 0x0000000000000080, 16 | OutParm = 0x0000000000000100, 17 | ZeroConstructor = 0x0000000000000200, 18 | ReturnParm = 0x0000000000000400, 19 | DisableEditOnTemplate = 0x0000000000000800, 20 | Transient = 0x0000000000002000, 21 | Config = 0x0000000000004000, 22 | DisableEditOnInstance = 0x0000000000010000, 23 | EditConst = 0x0000000000020000, 24 | GlobalConfig = 0x0000000000040000, 25 | InstancedReference = 0x0000000000080000, 26 | DuplicateTransient = 0x0000000000200000, 27 | SubobjectReference = 0x0000000000400000, 28 | SaveGame = 0x0000000001000000, 29 | NoClear = 0x0000000002000000, 30 | ReferenceParm = 0x0000000008000000, 31 | BlueprintAssignable = 0x0000000010000000, 32 | Deprecated = 0x0000000020000000, 33 | IsPlainOldData = 0x0000000040000000, 34 | RepSkip = 0x0000000080000000, 35 | RepNotify = 0x0000000100000000, 36 | Interp = 0x0000000200000000, 37 | NonTransactional = 0x0000000400000000, 38 | EditorOnly = 0x0000000800000000, 39 | NoDestructor = 0x0000001000000000, 40 | AutoWeak = 0x0000004000000000, 41 | ContainsInstancedReference = 0x0000008000000000, 42 | AssetRegistrySearchable = 0x0000010000000000, 43 | SimpleDisplay = 0x0000020000000000, 44 | AdvancedDisplay = 0x0000040000000000, 45 | Protected = 0x0000080000000000, 46 | BlueprintCallable = 0x0000100000000000, 47 | BlueprintAuthorityOnly = 0x0000200000000000, 48 | TextExportTransient = 0x0000400000000000, 49 | NonPIEDuplicateTransient = 0x0000800000000000, 50 | ExposeOnSpawn = 0x0001000000000000, 51 | PersistentInstance = 0x0002000000000000, 52 | UObjectWrapper = 0x0004000000000000, 53 | HasGetValueTypeHash = 0x0008000000000000, 54 | NativeAccessSpecifierPublic = 0x0010000000000000, 55 | NativeAccessSpecifierProtected = 0x0020000000000000, 56 | NativeAccessSpecifierPrivate = 0x0040000000000000 57 | }; 58 | 59 | inline bool operator&(UEPropertyFlags lhs, UEPropertyFlags rhs) 60 | { 61 | return (static_cast>(lhs) & static_cast>(rhs)) == static_cast>(rhs); 62 | } 63 | 64 | std::string StringifyFlags(const UEPropertyFlags flags); --------------------------------------------------------------------------------