From df5fd8b05b2a40838c10103959e2032aa9035dc8 Mon Sep 17 00:00:00 2001 From: Lucas Peter Date: Thu, 26 Sep 2024 17:52:10 +0200 Subject: [PATCH 1/7] Tried with Unreal base approach --- Source/SkyPortal/Private/SkyPortalIO.cpp | 79 ++++++++++++++++--- .../SkyPortal/Private/SkyPortalSubsystem.cpp | 1 + Source/SkyPortal/Public/SkyPortalFigure.h | 10 ++- Source/SkyPortal/Public/SkyPortalIO.h | 7 +- 4 files changed, 81 insertions(+), 16 deletions(-) diff --git a/Source/SkyPortal/Private/SkyPortalIO.cpp b/Source/SkyPortal/Private/SkyPortalIO.cpp index 9248806..ae6d88a 100644 --- a/Source/SkyPortal/Private/SkyPortalIO.cpp +++ b/Source/SkyPortal/Private/SkyPortalIO.cpp @@ -1,4 +1,9 @@ #include "SkyPortalIO.h" +#include "Misc/AES.h" +#include "Misc/ArchiveMD5.h" +#include "Misc/ScopeLock.h" +#include "HAL/UnrealMemory.h" + DEFINE_LOG_CATEGORY(LogHIDApi); DEFINE_LOG_CATEGORY(LogSkyportalIO); @@ -161,9 +166,20 @@ uint8* USkyPortalIO::Read() return output; } -TArray USkyPortalIO::QueryBlock(uint8 characterIndex, uint8 block) +uint8* USkyPortalIO::QueryBlock(uint8 FigureIndex, uint8 BlockIndex) { - return TArray(); + FWriteBlock command; + memset(command.data, 0, write_buf_size); //maybe not needed here + command.data[1] = 'Q'; + command.data[2] = FigureIndex; // Figure index (0x00-0x0F) + command.data[3] = BlockIndex; + unsigned char* output; + do { + Write(&command); + output = Read(); + } while (output[0] != 'Q' || (output[1] % 0x10 != FigureIndex && output[1] != 0x01) || output[2] != BlockIndex); + + return output; } void USkyPortalIO::Close() { @@ -272,21 +288,59 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) FigureData FigureData; FigureData.dataError = false; // Initialize error flag - FWriteBlock command; + // Loop over all 64 blocks for (uint8 BlockIndex = 0; BlockIndex < FIGURE_TOTAL_BLOCKS; ++BlockIndex) { - memset(command.data, 0, write_buf_size); //maybe not needed here - command.data[1] = 'Q'; - command.data[2] = FigureIndex; // Figure index (0x00-0x0F) - command.data[3] = BlockIndex; - uint8* output; - do { - Write(&command); - output = Read(); - } while (output[0] != 'Q'); + // Query the block from the portal + uint8* output = QueryBlock(FigureIndex, BlockIndex); + // Copy 16 bytes from the output, starting at the third byte + FMemory::Memcpy(FigureData.data, output + 3, FIGURE_BLOCK_SIZE); + + // Block 1 is sometimes a duplicate of block 0 + if (BlockIndex == 1) + { + if (FMemory::Memcmp(FigureData.data, FigureData.data[0], FIGURE_BLOCK_SIZE) == 0) + { + --BlockIndex; // Decrement index to reprocess + continue; + } + } + + if (((BlockIndex + 1) % 4 == 0) || BlockIndex < 8) + { + // Direct copy from data to decryptedData for certain blocks + FMemory::Memcpy(FigureData.decryptedData[BlockIndex], FigureData.data[BlockIndex], FIGURE_BLOCK_SIZE); + + } + else { + /***** MD5 Hash Calculation *****/ + // Prepare the hash input buffer + uint8 hashIn[0x56]; + FMemory::Memcpy(hashIn, FigureData.data[0], 16); + FMemory::Memcpy(hashIn + 0x10, FigureData.data[1], 16); + hashIn[0x20] = BlockIndex; + // Append the 35-byte constant + FMemory::Memcpy(hashIn + 0x21, HASH_CONST, sizeof(HASH_CONST)); + + // Compute the MD5 hash + FMD5 MD5; + MD5.Update(hashIn, sizeof(hashIn)); + uint8 key[16]; // MD5 produces 16 bytes + MD5.Final(key); + + // AES-128 ECB decryption + + FAES::FAESKey AesKey; + FMemory::Memcpy(AesKey.Key, key, 16); + + //TODO: FAES implementation in Unreal is AES-256. We need AES-128 + //FAES::DecryptData(FigureData.decryptedData[BlockIndex], FigureData.data[BlockIndex], 16, AesKey); + } + + /* if (output[1] == (0x10 + 'Q')) // Successful query { // Extract the 16 bytes of block data @@ -312,6 +366,7 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) // Copy block data into FigureData //memcpy(FigureData.blockdata[BlockIndex], &res.buf[4], FIGURE_BLOCK_SIZE); + */ } // Some verifications should happen. Like if dataError is set. diff --git a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp index 9d9ae34..0e057d9 100644 --- a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp +++ b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp @@ -118,6 +118,7 @@ SKYPORTAL_API bool USkyPortalSubsystem::RestartRunner() StatusCheckerThread = FRunnableThread::Create(StatusChecker, TEXT("PortalStatusCheckerThread"), 0, TPri_AboveNormal); UE_LOG(LogTemp, Log, TEXT("SkyPortalSubsystem Initialized")); + return true; } diff --git a/Source/SkyPortal/Public/SkyPortalFigure.h b/Source/SkyPortal/Public/SkyPortalFigure.h index b597203..a697300 100644 --- a/Source/SkyPortal/Public/SkyPortalFigure.h +++ b/Source/SkyPortal/Public/SkyPortalFigure.h @@ -2,6 +2,12 @@ #include "CoreMinimal.h" //#include "SkyPortalFigure.generated.h" +//Copyright (C) 2010 Activision.All Rights Reserved. +static const uint8 HASH_CONST[] = { + 0x20, 0x43, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, 0x32, // Copyright (C) 2 + 0x30, 0x31, 0x30, 0x20, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x20, // 010 Activision. + 0x41, 0x6C, 0x6C, 0x20, 0x52, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x52, 0x65, 0x73, 0x65, 0x72, // All Rights Reser + 0x76, 0x65, 0x64, 0x2E, 0x20 }; // ved. #define FIGURE_TOTAL_BLOCKS 64 #define FIGURE_BLOCK_SIZE 16 @@ -53,8 +59,8 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Category = "SkyPortal|Figure")) uint32 GetFigureIdByIndex(uint32 index); - UFUNCTION() - TArray QueryBlock(uint8 characterIndex, uint8 block = 0x00); + //UFUNCTION() + //TArray QueryBlock(uint8 characterIndex, uint8 block = 0x00); void ReadData(uint8 index); void ClearData(); diff --git a/Source/SkyPortal/Public/SkyPortalIO.h b/Source/SkyPortal/Public/SkyPortalIO.h index c94683d..ea9ed3d 100644 --- a/Source/SkyPortal/Public/SkyPortalIO.h +++ b/Source/SkyPortal/Public/SkyPortalIO.h @@ -72,8 +72,11 @@ public: */ uint8* Read(); - UFUNCTION() - TArray QueryBlock(uint8 characterIndex, uint8 block = 0x00); + + /*Trying to read a figure + * @return + */ + unsigned char* QueryBlock(uint8 characterIndex, uint8 block = 0x00); FigureData ReadFigureBlocks(uint8 FigureIndex); From f1988072a4186d14fdc1c6888ea81d2574dbafe8 Mon Sep 17 00:00:00 2001 From: LUCASTUCIOUS Date: Fri, 27 Sep 2024 01:39:33 +0200 Subject: [PATCH 2/7] OpenSSL implementation --- Source/SkyPortal/Private/SkyPortal.cpp | 4 ++ Source/SkyPortal/Private/SkyPortalFigure.cpp | 60 +----------------- Source/SkyPortal/Private/SkyPortalIO.cpp | 61 +++++++------------ Source/SkyPortal/Private/SkyPortalRunner.cpp | 8 +-- .../SkyPortal/Private/SkyPortalSubsystem.cpp | 22 +++++-- Source/SkyPortal/Public/SkyPortalFigure.h | 10 ++- Source/SkyPortal/Public/SkyPortalSubsystem.h | 19 +++++- Source/SkyPortal/SkyPortal.Build.cs | 9 +-- 8 files changed, 74 insertions(+), 119 deletions(-) diff --git a/Source/SkyPortal/Private/SkyPortal.cpp b/Source/SkyPortal/Private/SkyPortal.cpp index 162c591..4724a77 100644 --- a/Source/SkyPortal/Private/SkyPortal.cpp +++ b/Source/SkyPortal/Private/SkyPortal.cpp @@ -14,6 +14,10 @@ void FSkyPortalModule::ShutdownModule() { // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, // we call this function before unloading the module. + + if (GEngine->GetEngineSubsystem()) { + GEngine->GetEngineSubsystem()->Deinitialize(); + } } #undef LOCTEXT_NAMESPACE diff --git a/Source/SkyPortal/Private/SkyPortalFigure.cpp b/Source/SkyPortal/Private/SkyPortalFigure.cpp index 1b00736..6d927e7 100644 --- a/Source/SkyPortal/Private/SkyPortalFigure.cpp +++ b/Source/SkyPortal/Private/SkyPortalFigure.cpp @@ -9,7 +9,7 @@ uint32 FigureData::GetFigureID() int16_t OutFigureID = 0; // The figure ID is stored in Block 1 of Sector 0 (i.e., data[1]), bytes 0 and 1 (16-bit integer, little-endian) - OutFigureID = data[1][0] | // Least significant byte + OutFigureID = decryptedData[1][0] | // Least significant byte (data[1][1] << 8); // Most significant byte, shifted left by 8 bits ID = OutFigureID;// Return the 16-bit figure ID @@ -25,64 +25,6 @@ uint32 FigureData::GetFigureID() }; -/* -void FigureData::ReadData(uint8 index) -{ - ClearData(); - for (uint8 i = 0; i < 64; i++) - { - GEngine->GetEngineSubsystem(); - TArray output = SkySubsystem->QueryBlock(index, i); - - uint8[] blockData = new uint8[0x10]; - Array.Copy(output, 3, blockData, 0, 16); - - // block 1 is sometimes a duplicate of block 0 - if (i == 1) - { - if (blockData.SequenceEqual(data[0])) - { - i -= 1; - continue; - } - } - - Array.Copy(blockData, 0, data[i], 0, 16); - - if (((i + 1) % 4 == 0) || i < 8) - { - Array.Copy(data[i], 0, decryptedData[i], 0, 16); - } - else - { - uint8[] hashIn = new byte[0x56]; - data[0].CopyTo(hashIn, 0); - data[1].CopyTo(hashIn, 0x10); - hashIn[0x20] = i; - HASH_CONST.CopyTo(hashIn, 0x21); - - uint8[] key = MD5.Create().ComputeHash(hashIn); - - uint8[] decrypted = new byte[0x10]; - - using (Aes aesAlg = Aes.Create()) - { - aesAlg.Key = key; - aesAlg.Mode = CipherMode.ECB; - aesAlg.Padding = PaddingMode.Zeros; - - ICryptoTransform decryptor = aesAlg.CreateDecryptor(); - - decrypted = decryptor.TransformFinalBlock(data[i], 0, data[i].Length); - - } - - Array.Copy(decrypted, 0, decryptedData[i], 0, 16); - } - } -} -*/ - void FigureData::ClearData() { } diff --git a/Source/SkyPortal/Private/SkyPortalIO.cpp b/Source/SkyPortal/Private/SkyPortalIO.cpp index ae6d88a..7663a41 100644 --- a/Source/SkyPortal/Private/SkyPortalIO.cpp +++ b/Source/SkyPortal/Private/SkyPortalIO.cpp @@ -1,8 +1,9 @@ #include "SkyPortalIO.h" #include "Misc/AES.h" -#include "Misc/ArchiveMD5.h" -#include "Misc/ScopeLock.h" + #include "HAL/UnrealMemory.h" +#include "openssl/aes.h" + DEFINE_LOG_CATEGORY(LogHIDApi); @@ -281,12 +282,21 @@ FPortalStatusData ParsePortalStatus(const uint8* StatusResponse) } +void DecryptAES128(uint8* OutData, const uint8* InData, const uint8* Key) +{ + AES_KEY AesKey; + // Set the decryption key (16 bytes for AES-128) + AES_set_decrypt_key(Key, 128, &AesKey); + + // Perform AES-128 decryption (ECB mode) + AES_ecb_encrypt(InData, OutData, &AesKey, AES_DECRYPT); +} FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) { - FigureData FigureData; - FigureData.dataError = false; // Initialize error flag + FigureData TempFigureData; + TempFigureData.dataError = false; // Initialize error flag @@ -297,12 +307,12 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) uint8* output = QueryBlock(FigureIndex, BlockIndex); // Copy 16 bytes from the output, starting at the third byte - FMemory::Memcpy(FigureData.data, output + 3, FIGURE_BLOCK_SIZE); + FMemory::Memcpy(TempFigureData.data, output + 3, FIGURE_BLOCK_SIZE); // Block 1 is sometimes a duplicate of block 0 if (BlockIndex == 1) { - if (FMemory::Memcmp(FigureData.data, FigureData.data[0], FIGURE_BLOCK_SIZE) == 0) + if (FMemory::Memcmp(TempFigureData.data, TempFigureData.data[0], FIGURE_BLOCK_SIZE) == 0) { --BlockIndex; // Decrement index to reprocess continue; @@ -312,15 +322,15 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) if (((BlockIndex + 1) % 4 == 0) || BlockIndex < 8) { // Direct copy from data to decryptedData for certain blocks - FMemory::Memcpy(FigureData.decryptedData[BlockIndex], FigureData.data[BlockIndex], FIGURE_BLOCK_SIZE); + FMemory::Memcpy(TempFigureData.decryptedData[BlockIndex], TempFigureData.data[BlockIndex], FIGURE_BLOCK_SIZE); } else { /***** MD5 Hash Calculation *****/ // Prepare the hash input buffer uint8 hashIn[0x56]; - FMemory::Memcpy(hashIn, FigureData.data[0], 16); - FMemory::Memcpy(hashIn + 0x10, FigureData.data[1], 16); + FMemory::Memcpy(hashIn, TempFigureData.data[0], 16); + FMemory::Memcpy(hashIn + 0x10, TempFigureData.data[1], 16); hashIn[0x20] = BlockIndex; // Append the 35-byte constant FMemory::Memcpy(hashIn + 0x21, HASH_CONST, sizeof(HASH_CONST)); @@ -337,39 +347,14 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) FMemory::Memcpy(AesKey.Key, key, 16); //TODO: FAES implementation in Unreal is AES-256. We need AES-128 - //FAES::DecryptData(FigureData.decryptedData[BlockIndex], FigureData.data[BlockIndex], 16, AesKey); + //FAES::DecryptData(TempFigureData.decryptedData[BlockIndex], TempFigureData.data[BlockIndex], 16, AesKey); + DecryptAES128(TempFigureData.decryptedData[BlockIndex], TempFigureData.data[BlockIndex], key); } - /* - if (output[1] == (0x10 + 'Q')) // Successful query - { - // Extract the 16 bytes of block data - for (int i = 3; i < 19; i++) - { - FigureData.data[BlockIndex][i] = output[i]; - } - } - else if (output[0] == 0x01) { - FigureData.dataError = true; - UE_LOG(LogSkyportalIO, Warning, TEXT("Error querying block %d from figure %d"), BlockIndex, FigureIndex); - break; - } - - // Verify that the block index matches the requested block - uint8 ReturnedBlockIndex = output[3]; - if (ReturnedBlockIndex != BlockIndex) - { - FigureData.dataError = true; - UE_LOG(LogSkyportalIO, Warning, TEXT("Mismatched block index. Expected %d, got %d"), BlockIndex, ReturnedBlockIndex); - break; - } - - // Copy block data into FigureData - //memcpy(FigureData.blockdata[BlockIndex], &res.buf[4], FIGURE_BLOCK_SIZE); - */ } // Some verifications should happen. Like if dataError is set. - return FigureData; // Return the complete figure data + return TempFigureData; // Return the complete figure data } + diff --git a/Source/SkyPortal/Private/SkyPortalRunner.cpp b/Source/SkyPortal/Private/SkyPortalRunner.cpp index fce6818..c537dc7 100644 --- a/Source/SkyPortal/Private/SkyPortalRunner.cpp +++ b/Source/SkyPortal/Private/SkyPortalRunner.cpp @@ -72,15 +72,11 @@ void FPortalStatusChecker::CheckPortalStatus() switch (CurrentStatusData.StatusArray[i]) { case EFigureStatus::NOT_PRESENT: - - break; case EFigureStatus::PRESENT: - //FigureData = ReadFigureBlocks(i); - //subref->OnSkylanderAdded.Broadcast(GetFigureID(FigureData), i); break; case EFigureStatus::ADDED: - figData = PortalHandleRef->ReadFigureBlocks(i); - subref->OnSkylanderAdded.Broadcast(figData.GetFigureID(), i); + //figData = PortalHandleRef->ReadFigureBlocks(i); + subref->OnSkylanderAdded.Broadcast(00, i); break; case EFigureStatus::REMOVED: subref->OnSkylanderRemoved.Broadcast(00, i); diff --git a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp index 0e057d9..f48194c 100644 --- a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp +++ b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp @@ -2,10 +2,9 @@ #include "SkyPortalSubsystem.h" #include "Engine/Engine.h" -#include "SkyPortal.h" #include "HAL/RunnableThread.h" -#include "Misc/ScopeLock.h" +#include "SkyPortalFigure.h" void USkyPortalSubsystem::Initialize(FSubsystemCollectionBase& Collection) @@ -213,7 +212,7 @@ void USkyPortalSubsystem::Sleep(int sleepMs) { bool USkyPortalSubsystem::PortalConnect() { PortalHandle = NewObject(); - if (IsValid(PortalHandle)) { + if (IsValid(PortalHandle) && PortalHandle->bPortalReady) { UE_LOG(LogSkyportalIO, Log, TEXT("Portal connected: ")); PortalReady(); PortalActivate(1); @@ -234,7 +233,22 @@ bool USkyPortalSubsystem::IsPortalReady() return false; } -SKYPORTAL_API void USkyPortalSubsystem::PortalMusic(const USoundWave* Sound) + void USkyPortalSubsystem::PortalMusic(const USoundWave* Sound) { return; } + + void USkyPortalSubsystem::PortalAnalyze(const uint8 index) + { + FigureArray[index] = PortalHandle->ReadFigureBlocks(index); + UE_LOG(LogSkyportalIO, Log, TEXT("Reading figure...")); + UE_LOG(LogSkyportalIO, Log, TEXT("decrypted Figure ID : %d"), FigureArray[index].GetFigureID()); + } + + void USkyPortalSubsystem::GetFigureArray() { + FigureArray; + for (int i = 0; 16; i++) { + FigureArray[i] = PortalHandle->ReadFigureBlocks(i); + } + return; +} \ No newline at end of file diff --git a/Source/SkyPortal/Public/SkyPortalFigure.h b/Source/SkyPortal/Public/SkyPortalFigure.h index a697300..5c3cd93 100644 --- a/Source/SkyPortal/Public/SkyPortalFigure.h +++ b/Source/SkyPortal/Public/SkyPortalFigure.h @@ -12,10 +12,11 @@ static const uint8 HASH_CONST[] = { #define FIGURE_TOTAL_BLOCKS 64 #define FIGURE_BLOCK_SIZE 16 +/* typedef struct { unsigned char blockdata[FIGURE_TOTAL_BLOCKS][FIGURE_BLOCK_SIZE]; bool error; } FigureDataBlock; - +*/ class FigureData { @@ -38,8 +39,8 @@ public: uint64 FullToyCodeNumber; FString ToyCode; #pragma endregion - int16 ID; - int16 VariantID; + int16 ID; //Skylander ID + int16 VariantID; //Skylander Variant ID #pragma region counters uint8 counter1; uint8 couter2; @@ -53,10 +54,7 @@ public: // Methods - UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Category = "SkyPortal|Figure")) uint32 GetFigureID(); - - UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Category = "SkyPortal|Figure")) uint32 GetFigureIdByIndex(uint32 index); //UFUNCTION() diff --git a/Source/SkyPortal/Public/SkyPortalSubsystem.h b/Source/SkyPortal/Public/SkyPortalSubsystem.h index ba065a1..9565cd3 100644 --- a/Source/SkyPortal/Public/SkyPortalSubsystem.h +++ b/Source/SkyPortal/Public/SkyPortalSubsystem.h @@ -1,14 +1,21 @@ #pragma once -#include "Subsystems/EngineSubsystem.h" -#include "SkyPortalRunner.h" +#include "CoreMinimal.h" +#include "SkyPortalFigure.h" #include "SkyPortalIO.h" +#include "SkyPortalRunner.h" +#include "Subsystems/EngineSubsystem.h" +#include "Delegates/DelegateCombinations.h" +#include + #include "SkyPortalSubsystem.generated.h" + #pragma region Definitions //// Delegates DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkylanderAddedDelegate, int32, SkylanderID, int32, Index); + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkylanderRemovedDelegate, int32, SkylanderID, int32, Index); #pragma endregion @@ -74,6 +81,12 @@ public: UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|NOT FUNCTIONING")) SKYPORTAL_API void PortalMusic(const USoundWave* Sound); + UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|Figure|Debug")) + SKYPORTAL_API void PortalAnalyze(const uint8 index); + + UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|Commands|Figure")) + SKYPORTAL_API void GetFigureArray(); + /**/ UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal|Commands")) SKYPORTAL_API FPortalStatusData PortalStatus(); @@ -104,6 +117,8 @@ public: UPROPERTY(BlueprintReadOnly) FPortalStatusData StatusData; + TArray FigureArray; + UPROPERTY(BlueprintReadWrite) float RunnerInterval = 0.01f; //In seconds diff --git a/Source/SkyPortal/SkyPortal.Build.cs b/Source/SkyPortal/SkyPortal.Build.cs index 60e8bb3..d220ca2 100644 --- a/Source/SkyPortal/SkyPortal.Build.cs +++ b/Source/SkyPortal/SkyPortal.Build.cs @@ -62,9 +62,10 @@ public class SkyPortal : ModuleRules { "Core", "CoreUObject", - "Engine" - // ... add other public dependencies that you statically link with here ... - } + "Engine", + "OpenSSL", + "SSL" + } ); @@ -75,7 +76,7 @@ public class SkyPortal : ModuleRules "Engine", "Slate", "SlateCore", - // ... add private dependencies that you statically link with here ... + } ); From 3c7f3d02fd964cc336f3911f700cb9294e1ca66c Mon Sep 17 00:00:00 2001 From: LUCASTUCIOUS Date: Fri, 27 Sep 2024 14:18:20 +0200 Subject: [PATCH 3/7] Logging the fuck out everything --- Source/SkyPortal/Private/SkyPortalIO.cpp | 52 +++++++++++++++---- Source/SkyPortal/Private/SkyPortalRunner.cpp | 7 ++- .../SkyPortal/Private/SkyPortalSubsystem.cpp | 27 +++++++--- .../SkyPortal/Public/SkyPortalDefinitions.h | 2 +- Source/SkyPortal/Public/SkyPortalIO.h | 4 +- Source/SkyPortal/Public/SkyPortalSubsystem.h | 4 +- 6 files changed, 74 insertions(+), 22 deletions(-) diff --git a/Source/SkyPortal/Private/SkyPortalIO.cpp b/Source/SkyPortal/Private/SkyPortalIO.cpp index 7663a41..19821ed 100644 --- a/Source/SkyPortal/Private/SkyPortalIO.cpp +++ b/Source/SkyPortal/Private/SkyPortalIO.cpp @@ -110,11 +110,11 @@ struct hid_device_ { }; -void USkyPortalIO::Write(FWriteBlock* pb) +bool USkyPortalIO::Write(FWriteBlock* pb) { if (!ensure(PortalDevice)) { UE_LOG(LogSkyportalIO, Error, TEXT("No Portal found")); - return; + return false; } BOOL res; @@ -130,11 +130,12 @@ void USkyPortalIO::Write(FWriteBlock* pb) &bytes_returned, &ol); ensureMsgf(res, TEXT("Unable to write to Portal")); pb->BytesTransferred = bytes_returned; + return res; } #else -void USkyPortalIO::Write(FWriteBlock* pb) { +bool USkyPortalIO::Write(FWriteBlock* pb) { if (!ensure(PortalDevice)) { UE_LOG(LogSkyportalIO, Error, TEXT("No Portal found")); @@ -146,6 +147,7 @@ void USkyPortalIO::Write(FWriteBlock* pb) { res = hid_write(PortalDevice, pb->data, write_buf_size); ensureMsgf(res != -1, TEXT("Unable to write to Portal, %s"), hid_error(PortalDevice)); pb->BytesTransferred = res; + return res; } #endif @@ -163,12 +165,16 @@ void USkyPortalIO::WriteRaw(const TArray* block) uint8* USkyPortalIO::Read() { uint8* output = new byte[0x20]; - hid_read(PortalDevice, output, 0x20); + if (hid_read(PortalDevice, output, 0x20) == -1) { + UE_LOG(LogSkyportalIO, Error, TEXT("Unable to read data from Portal. error:\n %s"), hid_error(PortalDevice)); + return 0; + }; return output; } uint8* USkyPortalIO::QueryBlock(uint8 FigureIndex, uint8 BlockIndex) { + UE_LOG(LogSkyportalIO, Verbose, TEXT("Querying block %d - Start"), BlockIndex); FWriteBlock command; memset(command.data, 0, write_buf_size); //maybe not needed here command.data[1] = 'Q'; @@ -177,9 +183,9 @@ uint8* USkyPortalIO::QueryBlock(uint8 FigureIndex, uint8 BlockIndex) unsigned char* output; do { Write(&command); - output = Read(); + output = Read(); } while (output[0] != 'Q' || (output[1] % 0x10 != FigureIndex && output[1] != 0x01) || output[2] != BlockIndex); - + return output; } @@ -229,6 +235,25 @@ EPortalCommand GetPortalCommandFromChar(unsigned char Char) } +FString DataToString(const uint8* data) +{ + FString OutString; + for (int32 i = 0; i < 16; i++) + { + OutString += FString::Printf(TEXT("%02x"), data[i]); + } + return OutString; +} + +FString OutputToString(const unsigned char* output) { + FString OutString; + for (int32 i = 0; i < 0x20; i++) + { + OutString += FString::Printf(TEXT("%02x"), output[i]); + } + return OutString; +} + FPortalStatusData ParsePortalStatus(const uint8* StatusResponse) { FPortalStatusData result; @@ -284,12 +309,14 @@ FPortalStatusData ParsePortalStatus(const uint8* StatusResponse) void DecryptAES128(uint8* OutData, const uint8* InData, const uint8* Key) { + UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("DECRYPT -- Starting decryting data %s with %s key"), *DataToString(InData), *DataToString(Key)); AES_KEY AesKey; // Set the decryption key (16 bytes for AES-128) AES_set_decrypt_key(Key, 128, &AesKey); // Perform AES-128 decryption (ECB mode) AES_ecb_encrypt(InData, OutData, &AesKey, AES_DECRYPT); + UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("DECRYPT -- data %s with %s key decryted"), *DataToString(InData), *DataToString(Key)); } FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) @@ -305,16 +332,18 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) { // Query the block from the portal uint8* output = QueryBlock(FigureIndex, BlockIndex); - + // Copy 16 bytes from the output, starting at the third byte FMemory::Memcpy(TempFigureData.data, output + 3, FIGURE_BLOCK_SIZE); // Block 1 is sometimes a duplicate of block 0 if (BlockIndex == 1) { - if (FMemory::Memcmp(TempFigureData.data, TempFigureData.data[0], FIGURE_BLOCK_SIZE) == 0) + if (FMemory::Memcmp(TempFigureData.data[1], TempFigureData.data[0], FIGURE_BLOCK_SIZE) == 0) { - --BlockIndex; // Decrement index to reprocess + // Decrement BlockIndex to reprocess block 1 if it's a duplicate of block 0 + --BlockIndex; + UE_LOG(LogSkyportalIO, Verbose, TEXT("Block 1 is a duplicate of block 0, reprocessing...")); continue; } } @@ -323,11 +352,12 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) { // Direct copy from data to decryptedData for certain blocks FMemory::Memcpy(TempFigureData.decryptedData[BlockIndex], TempFigureData.data[BlockIndex], FIGURE_BLOCK_SIZE); - + UE_LOG(LogSkyportalIO, Verbose, TEXT("Block %d doesnt need decryption"), BlockIndex); } else { /***** MD5 Hash Calculation *****/ // Prepare the hash input buffer + UE_LOG(LogSkyportalIO, Verbose, TEXT("DECRYPT -- Starting decryting block %d"), BlockIndex); uint8 hashIn[0x56]; FMemory::Memcpy(hashIn, TempFigureData.data[0], 16); FMemory::Memcpy(hashIn + 0x10, TempFigureData.data[1], 16); @@ -349,7 +379,9 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) //TODO: FAES implementation in Unreal is AES-256. We need AES-128 //FAES::DecryptData(TempFigureData.decryptedData[BlockIndex], TempFigureData.data[BlockIndex], 16, AesKey); DecryptAES128(TempFigureData.decryptedData[BlockIndex], TempFigureData.data[BlockIndex], key); + UE_LOG(LogSkyportalIO, Verbose, TEXT("DECRYPT -- block %d decrypted"), BlockIndex); } + UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("block %d readed with success"), BlockIndex); } diff --git a/Source/SkyPortal/Private/SkyPortalRunner.cpp b/Source/SkyPortal/Private/SkyPortalRunner.cpp index c537dc7..bb2fda3 100644 --- a/Source/SkyPortal/Private/SkyPortalRunner.cpp +++ b/Source/SkyPortal/Private/SkyPortalRunner.cpp @@ -18,8 +18,11 @@ uint32 FPortalStatusChecker::Run() // Main loop of the thread, runs until Stop() is called while (bShouldRun) { - // Check the portal status - CheckPortalStatus(); + USkyPortalSubsystem* subref = Cast(SkyPortalSubsystemRef); + if (subref && !(subref->bShouldPauseRunner)) { + // Check the portal status + CheckPortalStatus(); + } // Sleep for the specified interval FPlatformProcess::Sleep(CheckInterval); diff --git a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp index f48194c..fb3124c 100644 --- a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp +++ b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp @@ -11,10 +11,7 @@ void USkyPortalSubsystem::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); - // Start the status checker thread - StatusChecker = new FPortalStatusChecker(this, RunnerInterval); - StatusCheckerThread = FRunnableThread::Create(StatusChecker, TEXT("PortalStatusCheckerThread"), 0, TPri_AboveNormal); - + UE_LOG(LogTemp, Log, TEXT("SkyPortalSubsystem Initialized")); } @@ -211,6 +208,17 @@ void USkyPortalSubsystem::Sleep(int sleepMs) { bool USkyPortalSubsystem::PortalConnect() { + if (StatusChecker) + { + StatusChecker->Stop(); + StatusCheckerThread->WaitForCompletion(); + + delete StatusCheckerThread; + delete StatusChecker; + StatusChecker = nullptr; + StatusCheckerThread = nullptr; + } + PortalHandle = NewObject(); if (IsValid(PortalHandle) && PortalHandle->bPortalReady) { UE_LOG(LogSkyportalIO, Log, TEXT("Portal connected: ")); @@ -219,6 +227,11 @@ bool USkyPortalSubsystem::PortalConnect() Sleep(500); ChangePortalColor(FLinearColor(0.5, 0.5, 0.5)); + + // Start the status checker thread + StatusChecker = new FPortalStatusChecker(this, RunnerInterval); + StatusCheckerThread = FRunnableThread::Create(StatusChecker, TEXT("PortalStatusCheckerThread"), 0, TPri_AboveNormal); + return true; } return false; @@ -240,9 +253,11 @@ bool USkyPortalSubsystem::IsPortalReady() void USkyPortalSubsystem::PortalAnalyze(const uint8 index) { - FigureArray[index] = PortalHandle->ReadFigureBlocks(index); + bShouldPauseRunner = true; UE_LOG(LogSkyportalIO, Log, TEXT("Reading figure...")); - UE_LOG(LogSkyportalIO, Log, TEXT("decrypted Figure ID : %d"), FigureArray[index].GetFigureID()); + FigureArray[index] = PortalHandle->ReadFigureBlocks(index); + UE_LOG(LogSkyportalIO, Log, TEXT("Figure ID : %d"), FigureArray[index].GetFigureID()); + bShouldPauseRunner = false; } void USkyPortalSubsystem::GetFigureArray() { diff --git a/Source/SkyPortal/Public/SkyPortalDefinitions.h b/Source/SkyPortal/Public/SkyPortalDefinitions.h index fda362b..5e87a14 100644 --- a/Source/SkyPortal/Public/SkyPortalDefinitions.h +++ b/Source/SkyPortal/Public/SkyPortalDefinitions.h @@ -80,4 +80,4 @@ struct FPortalStatusData { return !(*this == Other); } -}; \ No newline at end of file +}; diff --git a/Source/SkyPortal/Public/SkyPortalIO.h b/Source/SkyPortal/Public/SkyPortalIO.h index ea9ed3d..c1aa39a 100644 --- a/Source/SkyPortal/Public/SkyPortalIO.h +++ b/Source/SkyPortal/Public/SkyPortalIO.h @@ -25,6 +25,8 @@ const int ProductIds[4] = { 0x150, 0x967, 0x1f17 }; FPortalStatusData ParsePortalStatus(const uint8* StatusResponse); EPortalCommand GetPortalCommandFromChar(unsigned char Char); +FString DataToString(const uint8* data); +FString OutputToString(const unsigned char* output); /* Contain all the data that pass inside hidapi write + the number of bytes in case of successful write * @@ -62,7 +64,7 @@ public: bool OpenPortalHandle(); /* Send block to portal. In windows, don't use the hidapi */ - void Write(FWriteBlock* Block); + bool Write(FWriteBlock* Block); /* Send raw command to portal */ void WriteRaw(const TArray* block); diff --git a/Source/SkyPortal/Public/SkyPortalSubsystem.h b/Source/SkyPortal/Public/SkyPortalSubsystem.h index 9565cd3..b9b51d4 100644 --- a/Source/SkyPortal/Public/SkyPortalSubsystem.h +++ b/Source/SkyPortal/Public/SkyPortalSubsystem.h @@ -142,8 +142,8 @@ public: UPROPERTY() bool bPortalConnected_DEPRECATED = PortalHandle ? PortalHandle->bPortalReady : false; - - + UPROPERTY() + bool bShouldPauseRunner; From 6c7cde03e9919c0bd3e0bf7ed7d952581dc949ff Mon Sep 17 00:00:00 2001 From: LUCASTUCIOUS Date: Sat, 28 Sep 2024 23:34:12 +0200 Subject: [PATCH 4/7] update --- Source/SkyPortal/Private/SkyPortalIO.cpp | 28 +++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Source/SkyPortal/Private/SkyPortalIO.cpp b/Source/SkyPortal/Private/SkyPortalIO.cpp index 19821ed..32152e0 100644 --- a/Source/SkyPortal/Private/SkyPortalIO.cpp +++ b/Source/SkyPortal/Private/SkyPortalIO.cpp @@ -181,11 +181,25 @@ uint8* USkyPortalIO::QueryBlock(uint8 FigureIndex, uint8 BlockIndex) command.data[2] = FigureIndex; // Figure index (0x00-0x0F) command.data[3] = BlockIndex; unsigned char* output; + int attempt=0; do { - Write(&command); + attempt++; + UE_LOG(LogSkyportalIO, Verbose, TEXT("Trying to write... attempt:%d"), attempt); + if (Write(&command)) { output = Read(); - } while (output[0] != 'Q' || (output[1] % 0x10 != FigureIndex && output[1] != 0x01) || output[2] != BlockIndex); + if (output == 0) { + UE_LOG(LogSkyportalIO, Error, TEXT("Something went wrong"), attempt); + return 0; + } + } + else { + UE_LOG(LogSkyportalIO, Error, TEXT("Something went wrong"), attempt); + return 0; + } + } while (output[0] != 'Q' || (output[1] % 0x10 != FigureIndex && output[1] != 0x01) || output[2] != BlockIndex|| attempt <10); + UE_LOG(LogSkyportalIO, Verbose, TEXT("Querying block %d - success"), BlockIndex); + UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("Data block %d = \n %s"), BlockIndex,*OutputToString(output)); return output; } @@ -330,11 +344,19 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) // Loop over all 64 blocks for (uint8 BlockIndex = 0; BlockIndex < FIGURE_TOTAL_BLOCKS; ++BlockIndex) { + UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("Reading block %d"), BlockIndex); + // Query the block from the portal uint8* output = QueryBlock(FigureIndex, BlockIndex); + if (output == 0) { + --BlockIndex; + UE_LOG(LogSkyportalIO, Error, TEXT("Query error, reprocessing...")); + continue; + } // Copy 16 bytes from the output, starting at the third byte - FMemory::Memcpy(TempFigureData.data, output + 3, FIGURE_BLOCK_SIZE); + FMemory::Memcpy(TempFigureData.data[BlockIndex], output + 3, FIGURE_BLOCK_SIZE); + // Block 1 is sometimes a duplicate of block 0 if (BlockIndex == 1) From 67a5aa000e8e4a326abb6d19fa9d50e71ed92c4a Mon Sep 17 00:00:00 2001 From: LUCASTUCIOUS Date: Sun, 29 Sep 2024 00:52:33 +0200 Subject: [PATCH 5/7] log & async --- Source/SkyPortal/Private/SkyPortalIO.cpp | 33 +++++++++++-------- .../SkyPortal/Private/SkyPortalSubsystem.cpp | 25 ++++++++++++-- Source/SkyPortal/Public/SkyPortalSubsystem.h | 4 ++- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/Source/SkyPortal/Private/SkyPortalIO.cpp b/Source/SkyPortal/Private/SkyPortalIO.cpp index 32152e0..4aad7d4 100644 --- a/Source/SkyPortal/Private/SkyPortalIO.cpp +++ b/Source/SkyPortal/Private/SkyPortalIO.cpp @@ -164,11 +164,20 @@ void USkyPortalIO::WriteRaw(const TArray* block) uint8* USkyPortalIO::Read() { - uint8* output = new byte[0x20]; - if (hid_read(PortalDevice, output, 0x20) == -1) { - UE_LOG(LogSkyportalIO, Error, TEXT("Unable to read data from Portal. error:\n %s"), hid_error(PortalDevice)); - return 0; - }; + uint8* output = new uint8[0x20]; + int result = hid_read(PortalDevice, output, 0x20); + + if (result == -1) { + UE_LOG(LogSkyportalIO, Error, TEXT("Unable to read data from Portal. Error:\n%s"), hid_error(PortalDevice)); + delete[] output; // Prevent memory leak + return nullptr; + } + + if (result == 0) { // No data was read + UE_LOG(LogSkyportalIO, Warning, TEXT("No data read from portal")); + delete[] output; + return nullptr; + } return output; } @@ -180,24 +189,22 @@ uint8* USkyPortalIO::QueryBlock(uint8 FigureIndex, uint8 BlockIndex) command.data[1] = 'Q'; command.data[2] = FigureIndex; // Figure index (0x00-0x0F) command.data[3] = BlockIndex; - unsigned char* output; + unsigned char* output = nullptr; int attempt=0; do { attempt++; UE_LOG(LogSkyportalIO, Verbose, TEXT("Trying to write... attempt:%d"), attempt); if (Write(&command)) { output = Read(); - if (output == 0) { - UE_LOG(LogSkyportalIO, Error, TEXT("Something went wrong"), attempt); + if (output != 0) { + UE_LOG(LogSkyportalIO, Verbose, TEXT("Read success: output[0]=%d, output[1]=%d, output[2]=%d"), output[0], output[1], output[2]); + }else{ + UE_LOG(LogSkyportalIO, Error, TEXT("Read failed, output is null")); return 0; } } - else { - UE_LOG(LogSkyportalIO, Error, TEXT("Something went wrong"), attempt); - return 0; - } - } while (output[0] != 'Q' || (output[1] % 0x10 != FigureIndex && output[1] != 0x01) || output[2] != BlockIndex|| attempt <10); + } while ((output[0] != 'Q' || (output[1] % 0x10 != FigureIndex && output[1] != 0x01) || output[2] != BlockIndex) && attempt < 10); UE_LOG(LogSkyportalIO, Verbose, TEXT("Querying block %d - success"), BlockIndex); UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("Data block %d = \n %s"), BlockIndex,*OutputToString(output)); return output; diff --git a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp index fb3124c..a9910b9 100644 --- a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp +++ b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp @@ -251,13 +251,34 @@ bool USkyPortalSubsystem::IsPortalReady() return; } - void USkyPortalSubsystem::PortalAnalyze(const uint8 index) +void USkyPortalSubsystem::PortalAnalyzeAsync(const uint8 Index) { bShouldPauseRunner = true; + UE_LOG(LogSkyportalIO, Log, TEXT("Starting async figure analysis...")); + + // Run the PortalAnalyze function asynchronously on a background thread + AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [this, Index]() + { + // Perform the blocking operation on the background thread + PortalAnalyze(Index); + + // Once done, switch back to the main game thread + AsyncTask(ENamedThreads::GameThread, [this, Index]() + { + // This will be executed on the game thread after the async task is complete + bShouldPauseRunner = false; + UE_LOG(LogSkyportalIO, Log, TEXT("Figure analysis complete for index: %d"), Index); + }); + }); + } + + void USkyPortalSubsystem::PortalAnalyze(const uint8 index) + { + UE_LOG(LogSkyportalIO, Log, TEXT("Reading figure...")); FigureArray[index] = PortalHandle->ReadFigureBlocks(index); UE_LOG(LogSkyportalIO, Log, TEXT("Figure ID : %d"), FigureArray[index].GetFigureID()); - bShouldPauseRunner = false; + } void USkyPortalSubsystem::GetFigureArray() { diff --git a/Source/SkyPortal/Public/SkyPortalSubsystem.h b/Source/SkyPortal/Public/SkyPortalSubsystem.h index b9b51d4..275beb0 100644 --- a/Source/SkyPortal/Public/SkyPortalSubsystem.h +++ b/Source/SkyPortal/Public/SkyPortalSubsystem.h @@ -82,7 +82,7 @@ public: SKYPORTAL_API void PortalMusic(const USoundWave* Sound); UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|Figure|Debug")) - SKYPORTAL_API void PortalAnalyze(const uint8 index); + SKYPORTAL_API void PortalAnalyzeAsync(const uint8 index); UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|Commands|Figure")) SKYPORTAL_API void GetFigureArray(); @@ -155,6 +155,8 @@ private: */ static void Sleep(int sleepMs); + void PortalAnalyze(const uint8 Index); + // Pointer to the status checker thread FPortalStatusChecker* StatusChecker; FRunnableThread* StatusCheckerThread; From a377bf6f008f00ad02a59508165028d0938ce795 Mon Sep 17 00:00:00 2001 From: LUCASTUCIOUS Date: Sun, 29 Sep 2024 11:36:40 +0200 Subject: [PATCH 6/7] IT WORKS --- Source/SkyPortal/Private/SkyPortalFigure.cpp | 8 ++++++-- Source/SkyPortal/Private/SkyPortalIO.cpp | 20 +++++++++---------- Source/SkyPortal/Private/SkyPortalRunner.cpp | 8 ++++---- .../SkyPortal/Private/SkyPortalSubsystem.cpp | 17 +++++++++++++--- Source/SkyPortal/Public/SkyPortalFigure.h | 20 +++++++++++-------- Source/SkyPortal/Public/SkyPortalIO.h | 2 +- Source/SkyPortal/Public/SkyPortalSubsystem.h | 3 ++- 7 files changed, 49 insertions(+), 29 deletions(-) diff --git a/Source/SkyPortal/Private/SkyPortalFigure.cpp b/Source/SkyPortal/Private/SkyPortalFigure.cpp index 6d927e7..0fb8652 100644 --- a/Source/SkyPortal/Private/SkyPortalFigure.cpp +++ b/Source/SkyPortal/Private/SkyPortalFigure.cpp @@ -2,8 +2,12 @@ #include "SkyPortalFigure.h" +UFigureData::UFigureData() +{ + ClearData(); +} -uint32 FigureData::GetFigureID() +int32 UFigureData::GetFigureID() { if (ID == 0) { int16_t OutFigureID = 0; @@ -25,6 +29,6 @@ uint32 FigureData::GetFigureID() }; -void FigureData::ClearData() +void UFigureData::ClearData() { } diff --git a/Source/SkyPortal/Private/SkyPortalIO.cpp b/Source/SkyPortal/Private/SkyPortalIO.cpp index 4aad7d4..2dcb737 100644 --- a/Source/SkyPortal/Private/SkyPortalIO.cpp +++ b/Source/SkyPortal/Private/SkyPortalIO.cpp @@ -196,7 +196,7 @@ uint8* USkyPortalIO::QueryBlock(uint8 FigureIndex, uint8 BlockIndex) UE_LOG(LogSkyportalIO, Verbose, TEXT("Trying to write... attempt:%d"), attempt); if (Write(&command)) { output = Read(); - if (output != 0) { + if (output != nullptr && output != 0) { UE_LOG(LogSkyportalIO, Verbose, TEXT("Read success: output[0]=%d, output[1]=%d, output[2]=%d"), output[0], output[1], output[2]); }else{ UE_LOG(LogSkyportalIO, Error, TEXT("Read failed, output is null")); @@ -340,11 +340,11 @@ void DecryptAES128(uint8* OutData, const uint8* InData, const uint8* Key) UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("DECRYPT -- data %s with %s key decryted"), *DataToString(InData), *DataToString(Key)); } -FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) +UFigureData* USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) { - FigureData TempFigureData; - TempFigureData.dataError = false; // Initialize error flag + UFigureData* TempFigureData = NewObject(); + TempFigureData->dataError = false; // Initialize error flag @@ -362,13 +362,13 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) } // Copy 16 bytes from the output, starting at the third byte - FMemory::Memcpy(TempFigureData.data[BlockIndex], output + 3, FIGURE_BLOCK_SIZE); + FMemory::Memcpy(TempFigureData->data[BlockIndex], output + 3, FIGURE_BLOCK_SIZE); // Block 1 is sometimes a duplicate of block 0 if (BlockIndex == 1) { - if (FMemory::Memcmp(TempFigureData.data[1], TempFigureData.data[0], FIGURE_BLOCK_SIZE) == 0) + if (FMemory::Memcmp(TempFigureData->data[1], TempFigureData->data[0], FIGURE_BLOCK_SIZE) == 0) { // Decrement BlockIndex to reprocess block 1 if it's a duplicate of block 0 --BlockIndex; @@ -380,7 +380,7 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) if (((BlockIndex + 1) % 4 == 0) || BlockIndex < 8) { // Direct copy from data to decryptedData for certain blocks - FMemory::Memcpy(TempFigureData.decryptedData[BlockIndex], TempFigureData.data[BlockIndex], FIGURE_BLOCK_SIZE); + FMemory::Memcpy(TempFigureData->decryptedData[BlockIndex], TempFigureData->data[BlockIndex], FIGURE_BLOCK_SIZE); UE_LOG(LogSkyportalIO, Verbose, TEXT("Block %d doesnt need decryption"), BlockIndex); } else { @@ -388,8 +388,8 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) // Prepare the hash input buffer UE_LOG(LogSkyportalIO, Verbose, TEXT("DECRYPT -- Starting decryting block %d"), BlockIndex); uint8 hashIn[0x56]; - FMemory::Memcpy(hashIn, TempFigureData.data[0], 16); - FMemory::Memcpy(hashIn + 0x10, TempFigureData.data[1], 16); + FMemory::Memcpy(hashIn, TempFigureData->data[0], 16); + FMemory::Memcpy(hashIn + 0x10, TempFigureData->data[1], 16); hashIn[0x20] = BlockIndex; // Append the 35-byte constant FMemory::Memcpy(hashIn + 0x21, HASH_CONST, sizeof(HASH_CONST)); @@ -407,7 +407,7 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) //TODO: FAES implementation in Unreal is AES-256. We need AES-128 //FAES::DecryptData(TempFigureData.decryptedData[BlockIndex], TempFigureData.data[BlockIndex], 16, AesKey); - DecryptAES128(TempFigureData.decryptedData[BlockIndex], TempFigureData.data[BlockIndex], key); + DecryptAES128(TempFigureData->decryptedData[BlockIndex], TempFigureData->data[BlockIndex], key); UE_LOG(LogSkyportalIO, Verbose, TEXT("DECRYPT -- block %d decrypted"), BlockIndex); } UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("block %d readed with success"), BlockIndex); diff --git a/Source/SkyPortal/Private/SkyPortalRunner.cpp b/Source/SkyPortal/Private/SkyPortalRunner.cpp index bb2fda3..5fa3c4f 100644 --- a/Source/SkyPortal/Private/SkyPortalRunner.cpp +++ b/Source/SkyPortal/Private/SkyPortalRunner.cpp @@ -49,18 +49,18 @@ void FPortalStatusChecker::CheckPortalStatus() { USkyPortalSubsystem* subref = Cast(SkyPortalSubsystemRef); USkyPortalIO* PortalHandleRef = subref->PortalHandle; - UE_LOG(LogSkyportalIO, Verbose, TEXT("Check portal")); + UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("Check portal")); if (PortalHandleRef && PortalHandleRef->bPortalReady) { // Call the subsystem function to get portal status uint8* output = PortalHandleRef->Read(); EPortalCommand CommandResponse = GetPortalCommandFromChar(output[0]); - FigureData figData; + //UFigureData figData; switch (CommandResponse) { case S: CurrentStatusData = ParsePortalStatus(output); - UE_LOG(LogSkyportalIO, Verbose, TEXT("Output Data: %s"), *BytesToHex(output, sizeof(output))); + UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("Output Data: %s"), *BytesToHex(output, sizeof(output))); //Send delegate when new informations are received if (OldStatusData != CurrentStatusData) { @@ -97,7 +97,7 @@ void FPortalStatusChecker::CheckPortalStatus() } // Do something with the status (log, notify, etc.) - UE_LOG(LogSkyportalIO, Verbose, TEXT("Portal Status:")); + UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("Portal Status:")); } } diff --git a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp index a9910b9..83a8000 100644 --- a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp +++ b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp @@ -11,7 +11,12 @@ void USkyPortalSubsystem::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); - + FigureArray.SetNum(16); + // Create UFigureData objects dynamically + for (uint8 i = 0; i < FigureArray.Num(); i++) + { + FigureArray[i] = NewObject(this); + } UE_LOG(LogTemp, Log, TEXT("SkyPortalSubsystem Initialized")); } @@ -276,8 +281,14 @@ void USkyPortalSubsystem::PortalAnalyzeAsync(const uint8 Index) { UE_LOG(LogSkyportalIO, Log, TEXT("Reading figure...")); - FigureArray[index] = PortalHandle->ReadFigureBlocks(index); - UE_LOG(LogSkyportalIO, Log, TEXT("Figure ID : %d"), FigureArray[index].GetFigureID()); + if (FigureArray.IsValidIndex(index)) { + FigureArray[index] = PortalHandle->ReadFigureBlocks(index); + UE_LOG(LogSkyportalIO, Log, TEXT("Figure ID : %d"), FigureArray[index]->GetFigureID()); + return; + } + UE_LOG(LogSkyportalIO, Error, TEXT("Error in FigureArray")); + + } diff --git a/Source/SkyPortal/Public/SkyPortalFigure.h b/Source/SkyPortal/Public/SkyPortalFigure.h index 5c3cd93..8b39588 100644 --- a/Source/SkyPortal/Public/SkyPortalFigure.h +++ b/Source/SkyPortal/Public/SkyPortalFigure.h @@ -1,6 +1,7 @@ #pragma once + #include "CoreMinimal.h" -//#include "SkyPortalFigure.generated.h" +#include "SkyPortalFigure.generated.h" //Copyright (C) 2010 Activision.All Rights Reserved. static const uint8 HASH_CONST[] = { @@ -18,9 +19,14 @@ typedef struct { } FigureDataBlock; */ +UCLASS() +class UFigureData : public UObject { + GENERATED_BODY() -class FigureData { public: + + UFigureData(); + // Data Arrays uint8 data[64][16]; uint8 decryptedData[64][16]; @@ -43,18 +49,16 @@ public: int16 VariantID; //Skylander Variant ID #pragma region counters uint8 counter1; - uint8 couter2; + uint8 counter2; #pragma endregion FString Nickname; - FigureData() - { - ClearData(); - } + // Methods + UFUNCTION(BlueprintCallable) + int32 GetFigureID(); - uint32 GetFigureID(); uint32 GetFigureIdByIndex(uint32 index); //UFUNCTION() diff --git a/Source/SkyPortal/Public/SkyPortalIO.h b/Source/SkyPortal/Public/SkyPortalIO.h index c1aa39a..c6287c8 100644 --- a/Source/SkyPortal/Public/SkyPortalIO.h +++ b/Source/SkyPortal/Public/SkyPortalIO.h @@ -80,7 +80,7 @@ public: */ unsigned char* QueryBlock(uint8 characterIndex, uint8 block = 0x00); - FigureData ReadFigureBlocks(uint8 FigureIndex); + UFigureData* ReadFigureBlocks(uint8 FigureIndex); /* Close connection to Portal*/ void Close(); diff --git a/Source/SkyPortal/Public/SkyPortalSubsystem.h b/Source/SkyPortal/Public/SkyPortalSubsystem.h index 275beb0..a79f543 100644 --- a/Source/SkyPortal/Public/SkyPortalSubsystem.h +++ b/Source/SkyPortal/Public/SkyPortalSubsystem.h @@ -117,7 +117,8 @@ public: UPROPERTY(BlueprintReadOnly) FPortalStatusData StatusData; - TArray FigureArray; + UPROPERTY(BlueprintReadOnly) + TArray FigureArray; UPROPERTY(BlueprintReadWrite) float RunnerInterval = 0.01f; //In seconds From 4a998821187327c32840101ccdb02f3f035fa436 Mon Sep 17 00:00:00 2001 From: LUCASTUCIOUS Date: Sun, 29 Sep 2024 15:00:36 +0200 Subject: [PATCH 7/7] fix some memory issues --- Source/SkyPortal/Private/SkyPortalIO.cpp | 6 ++++-- Source/SkyPortal/Private/SkyPortalSubsystem.cpp | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/SkyPortal/Private/SkyPortalIO.cpp b/Source/SkyPortal/Private/SkyPortalIO.cpp index 2dcb737..a3a4b3e 100644 --- a/Source/SkyPortal/Private/SkyPortalIO.cpp +++ b/Source/SkyPortal/Private/SkyPortalIO.cpp @@ -191,10 +191,12 @@ uint8* USkyPortalIO::QueryBlock(uint8 FigureIndex, uint8 BlockIndex) command.data[3] = BlockIndex; unsigned char* output = nullptr; int attempt=0; + bool write; do { attempt++; UE_LOG(LogSkyportalIO, Verbose, TEXT("Trying to write... attempt:%d"), attempt); - if (Write(&command)) { + write = Write(&command); + if (write) { output = Read(); if (output != nullptr && output != 0) { UE_LOG(LogSkyportalIO, Verbose, TEXT("Read success: output[0]=%d, output[1]=%d, output[2]=%d"), output[0], output[1], output[2]); @@ -204,7 +206,7 @@ uint8* USkyPortalIO::QueryBlock(uint8 FigureIndex, uint8 BlockIndex) } } - } while ((output[0] != 'Q' || (output[1] % 0x10 != FigureIndex && output[1] != 0x01) || output[2] != BlockIndex) && attempt < 10); + } while (write == false && (output[0] != 'Q' || (output[1] % 0x10 != FigureIndex && output[1] != 0x01) || output[2] != BlockIndex) && attempt < 10); UE_LOG(LogSkyportalIO, Verbose, TEXT("Querying block %d - success"), BlockIndex); UE_LOG(LogSkyportalIO, VeryVerbose, TEXT("Data block %d = \n %s"), BlockIndex,*OutputToString(output)); return output; diff --git a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp index 83a8000..7a59cd1 100644 --- a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp +++ b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp @@ -5,6 +5,8 @@ #include "HAL/RunnableThread.h" #include "SkyPortalFigure.h" +#include +#include void USkyPortalSubsystem::Initialize(FSubsystemCollectionBase& Collection) @@ -259,7 +261,7 @@ bool USkyPortalSubsystem::IsPortalReady() void USkyPortalSubsystem::PortalAnalyzeAsync(const uint8 Index) { bShouldPauseRunner = true; - UE_LOG(LogSkyportalIO, Log, TEXT("Starting async figure analysis...")); + UE_LOG(LogSkyportalIO, Log, TEXT("Starting async figure analysis for index %d..."), Index); // Run the PortalAnalyze function asynchronously on a background thread AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [this, Index]()