Advertisement
malice936

AsyncPluginLoader.cpp

Apr 17th, 2025
328
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.35 KB | Gaming | 0 0
  1. /*
  2. Warning! Experimental! No guarantees on functionality! Use at your own risk!!!!!
  3. (Not so much on this one. I have used it and it actually functions very well, but still potentially unstable.)
  4. */
  5. #include "AsyncPluginLoader.h"
  6. #include "Misc/FileHelper.h"
  7. #include "Misc/Paths.h"
  8. #include "Async/Async.h"
  9.  
  10. void UAsyncPluginLoader::LoadPluginFileAsync(const FString& FilePath, const FOnPluginFileLoaded& OnLoaded)
  11. {
  12.     FString FileExtension = FPaths::GetExtension(FilePath);
  13.     if (FileExtension != TEXT("esm") && FileExtension != TEXT("esp"))
  14.     {
  15.         UE_LOG(LogTemp, Warning, TEXT("Invalid file extension for plugin: %s (expected .esm or .esp)"), *FilePath);
  16.         AsyncTask(ENamedThreads::GameThread, [OnLoaded]()
  17.         {
  18.             OnLoaded.ExecuteIfBound(false, TArray<uint8>());
  19.         });
  20.         return;
  21.     }
  22.  
  23.     AsyncTask(ENamedThreads::AnyThread, [FilePath, OnLoaded]()
  24.     {
  25.         TArray<uint8> FileData;
  26.         bool bSuccess = FFileHelper::LoadFileToArray(FileData, *FilePath);
  27.  
  28.         AsyncTask(ENamedThreads::GameThread, [FileData, bSuccess, FilePath, OnLoaded]()
  29.         {
  30.             if (bSuccess)
  31.             {
  32.                 UE_LOG(LogTemp, Log, TEXT("Successfully loaded plugin file: %s"), *FilePath);
  33.                 OnLoaded.ExecuteIfBound(true, FileData);
  34.             }
  35.             else
  36.             {
  37.                 UE_LOG(LogTemp, Warning, TEXT("Failed to load plugin file: %s"), *FilePath);
  38.                 OnLoaded.ExecuteIfBound(false, TArray<uint8>());
  39.             }
  40.         });
  41.     });
  42. }
  43.  
  44. void UAsyncPluginLoader::ParseESMRecords(const TArray<uint8>& FileBytes, TArray<FESMRecord>& OutRecords)
  45. {
  46.     FMemoryReader Ar(FileBytes, true);
  47.     while (!Ar.AtEnd())
  48.     {
  49.         FESMRecord Record;
  50.         Ar << Record.RecordType; // 4 bytes for type (e.g., "LAND")
  51.  
  52.         int32 RecordSize;
  53.         Ar << RecordSize; // 4 bytes for size
  54.  
  55.         // Parse the FormID (4 bytes) and flags (4 bytes) from the header
  56.         int32 FormIDValue;
  57.         Ar << FormIDValue; // 4 bytes for FormID
  58.         FFormID FormID(FormIDValue);
  59.         Record.FormIDs.Add(FormID);
  60.  
  61.         // Skip the remaining 4 bytes (flags)
  62.         Ar.Seek(Ar.Tell() + 4);
  63.  
  64.         // Read the record's data (subrecords)
  65.         int64 RecordEnd = Ar.Tell() + RecordSize;
  66.         Record.RecordData.SetNum(RecordSize);
  67.         Ar.Serialize(Record.RecordData.GetData(), RecordSize);
  68.  
  69.         // Pre-parse subrecords for LAND and other records
  70.         ParseESMSubrecords(Record.RecordData, Record.Subrecords, Record.FormIDs, Record); // Pass the current Record
  71.  
  72.         OutRecords.Add(Record);
  73.         Ar.Seek(RecordEnd);
  74.     }
  75. }
  76.  
  77. void UAsyncPluginLoader::ParseESMSubrecords(const TArray<uint8>& RecordData, TArray<FESMSubrecord>& OutSubrecords, TArray<FFormID>& OutFormIDs, FESMRecord& CurrentRecord)
  78. {
  79.     FMemoryReader Ar(RecordData, true);
  80.     while (!Ar.AtEnd())
  81.     {
  82.         FESMSubrecord Subrecord;
  83.         Ar << Subrecord.SubrecordType; // 4 bytes for type (e.g., "NAME")
  84.  
  85.         int32 SubrecordSize;
  86.         Ar << SubrecordSize; // 4 bytes for size
  87.  
  88.         Subrecord.SubrecordData.SetNum(SubrecordSize);
  89.         Ar.Serialize(Subrecord.SubrecordData.GetData(), SubrecordSize);
  90.  
  91.         // Check for NAME subrecord to store as EditorID
  92.         if (Subrecord.SubrecordType == TEXT("NAME"))
  93.         {
  94.             FString Name = FString(SubrecordSize, (char*)Subrecord.SubrecordData.GetData());
  95.             CurrentRecord.EditorID = Name; // Set directly on the current record
  96.         }
  97.  
  98.         OutSubrecords.Add(Subrecord);
  99.     }
  100. }
  101.  
  102. bool UAsyncPluginLoader::ExtractHeightData(const FESMRecord& Record, FESMHeightData& OutHeightData)
  103. {
  104.     if (Record.RecordType != TEXT("LAND"))
  105.     {
  106.         return false;
  107.     }
  108.  
  109.     for (const FESMSubrecord& Subrecord : Record.Subrecords)
  110.     {
  111.         if (Subrecord.SubrecordType == TEXT("VHGT"))
  112.         {
  113.             FMemoryReader Ar(Subrecord.SubrecordData, true);
  114.  
  115.             Ar << OutHeightData.BaseHeight;
  116.  
  117.             OutHeightData.Heights.SetNum(4225); // 65x65 grid
  118.             for (int32 i = 0; i < 4225; i++)
  119.             {
  120.                 int8 HeightOffset;
  121.                 Ar << HeightOffset;
  122.                 OutHeightData.Heights[i] = OutHeightData.BaseHeight + (HeightOffset * 8.0f);
  123.             }
  124.  
  125.             return true;
  126.         }
  127.     }
  128.  
  129.     return false;
  130. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement