wip
Based on https://github.com/mandar1jn/SkylandersToolkit/blob/master
This commit is contained in:
parent
aed30481ea
commit
be72994dc0
7 changed files with 302 additions and 34 deletions
81
Source/SkyPortal/Private/SkyPortalFigure.cpp
Normal file
81
Source/SkyPortal/Private/SkyPortalFigure.cpp
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SkyPortalFigure.h"
|
||||||
|
#include "SkyPortalSubsystem.h"
|
||||||
|
|
||||||
|
uint32 GetFigureID(const FigureDataBlock& DataBlock)
|
||||||
|
{
|
||||||
|
int16_t OutFigureID;
|
||||||
|
// Figure ID is stored in Block 0, bytes 0 to 3 (32-bit integer, little-endian)
|
||||||
|
OutFigureID = DataBlock.blockdata[0][0] |
|
||||||
|
(DataBlock.blockdata[0][1] << 8) |
|
||||||
|
(DataBlock.blockdata[0][2] << 16) |
|
||||||
|
(DataBlock.blockdata[0][3] << 24);
|
||||||
|
/*
|
||||||
|
// Variant ID is stored in Block 0, bytes 4 to 5 (16-bit integer, little-endian)
|
||||||
|
OutVariantID = (DataBlock.blockdata[0][5] << 8) |
|
||||||
|
DataBlock.blockdata[0][4];
|
||||||
|
*/
|
||||||
|
return OutFigureID;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void FigureData::ReadData(uint8 index)
|
||||||
|
{
|
||||||
|
ClearData();
|
||||||
|
for (uint8 i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
USkyPortalSubsystem* SkySubsystem = GEngine->GetEngineSubsystem<USkyPortalSubsystem>();
|
||||||
|
TArray<uint8> 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()
|
||||||
|
{
|
||||||
|
}
|
69
Source/SkyPortal/Private/SkyPortalIO.cpp
Normal file
69
Source/SkyPortal/Private/SkyPortalIO.cpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#include "SkyPortalIO.h"
|
||||||
|
#include "Engine/Engine.h"
|
||||||
|
|
||||||
|
DEFINE_LOG_CATEGORY(LogHIDApi);
|
||||||
|
DEFINE_LOG_CATEGORY(LogSkyportalIO);
|
||||||
|
|
||||||
|
bool OpenPortalHandle() {
|
||||||
|
//reset
|
||||||
|
if (PortalDevice) {
|
||||||
|
hid_close(PortalDevice);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Declare two pointers to hold information about HID devices.
|
||||||
|
"list" will point to the head of the linked list of devices,
|
||||||
|
"attributes" will be used to iterate through the list.
|
||||||
|
*/
|
||||||
|
struct hid_device_info* list, * attributes;
|
||||||
|
|
||||||
|
list = hid_enumerate(0x0, 0x0);
|
||||||
|
// If `list` is NULL, that means no devices were found or there was an error.
|
||||||
|
// In this case, print an error message and terminate the program.
|
||||||
|
if (!list) {
|
||||||
|
UE_LOG(LogHIDApi, Error, TEXT("No devices found"));
|
||||||
|
// Get the error message from the HIDAPI
|
||||||
|
HidError = hid_error(NULL);
|
||||||
|
UE_LOG(LogHIDApi, Error, TEXT("%s"), *HidError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
attributes = list;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Iterate through the linked list of devices
|
||||||
|
int vendorCount = sizeof(VendorIds) / sizeof(VendorIds[0]);
|
||||||
|
int productCount = sizeof(ProductIds) / sizeof(ProductIds[0]);
|
||||||
|
|
||||||
|
while (attributes) {
|
||||||
|
// Check if the devices match any of vendor_id and product_id
|
||||||
|
for (int i = 0; i < vendorCount; i++) {
|
||||||
|
for (int j = 0; j < productCount; j++) {
|
||||||
|
if (attributes->vendor_id == VendorIds[i] && attributes->product_id == ProductIds[j]) {
|
||||||
|
UE_LOG(LogHIDApi, Display, TEXT("Portal found"));
|
||||||
|
UE_LOG(LogHIDApi, Log, TEXT("Vendor ID: 0x%x, Product ID: 0x%x"), attributes->vendor_id, attributes->product_id);
|
||||||
|
|
||||||
|
PortalDevice = hid_open(attributes->vendor_id, attributes->product_id, NULL);
|
||||||
|
if (PortalDevice) {
|
||||||
|
UE_LOG(LogHIDApi, Display, TEXT("Successful connection to Portal."));
|
||||||
|
|
||||||
|
// Free the device list
|
||||||
|
hid_free_enumeration(list);
|
||||||
|
//bPortalConnected = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next device in the list
|
||||||
|
attributes = attributes->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the device list
|
||||||
|
hid_free_enumeration(list);
|
||||||
|
UE_LOG(LogHIDApi, Error, TEXT("No Portals found"));
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -5,9 +5,8 @@
|
||||||
|
|
||||||
#include "HAL/RunnableThread.h"
|
#include "HAL/RunnableThread.h"
|
||||||
#include "Misc/ScopeLock.h"
|
#include "Misc/ScopeLock.h"
|
||||||
|
#include "SkyPortalIO.h"
|
||||||
|
|
||||||
DEFINE_LOG_CATEGORY(LogHIDApi);
|
|
||||||
DEFINE_LOG_CATEGORY(LogSkyportalIO);
|
|
||||||
|
|
||||||
void USkyPortalSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
void USkyPortalSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||||||
{
|
{
|
||||||
|
@ -289,6 +288,7 @@ FPortalStatusData USkyPortalSubsystem::ParsePortalStatus(const RWBlock& Response
|
||||||
FigureStatusArray |= (ResponseBlock.buf[3] << 16); // 3rd byte
|
FigureStatusArray |= (ResponseBlock.buf[3] << 16); // 3rd byte
|
||||||
FigureStatusArray |= (ResponseBlock.buf[4] << 24); // 4th byte
|
FigureStatusArray |= (ResponseBlock.buf[4] << 24); // 4th byte
|
||||||
|
|
||||||
|
TStaticArray<EFigureStatus, 16> tempArray;
|
||||||
// For each of the 16 entries, extract the 2-bit status and map it to EFigureStatus
|
// For each of the 16 entries, extract the 2-bit status and map it to EFigureStatus
|
||||||
for (int32 i = 0; i < 16; ++i)
|
for (int32 i = 0; i < 16; ++i)
|
||||||
{
|
{
|
||||||
|
@ -315,9 +315,11 @@ FPortalStatusData USkyPortalSubsystem::ParsePortalStatus(const RWBlock& Response
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to the array of figure statuses
|
// Add to the array of figure statuses
|
||||||
PortalStatusData.StatusArray.Add(FigureStatus);
|
//PortalStatusData.StatusArray.Insert(FigureStatus, i);
|
||||||
|
tempArray[i] = FigureStatus;
|
||||||
}
|
}
|
||||||
|
PortalStatusData.StatusArray.SetNum(0);
|
||||||
|
PortalStatusData.StatusArray.Append(tempArray);
|
||||||
// The next byte is the response counter
|
// The next byte is the response counter
|
||||||
PortalStatusData.Counter = ResponseBlock.buf[5];
|
PortalStatusData.Counter = ResponseBlock.buf[5];
|
||||||
|
|
||||||
|
@ -373,19 +375,24 @@ void USkyPortalSubsystem::CheckComplexResponse() {
|
||||||
|
|
||||||
for (int i = 0; i < CurrentStatusData.StatusArray.Num(); i++) {
|
for (int i = 0; i < CurrentStatusData.StatusArray.Num(); i++) {
|
||||||
if (CurrentStatusData.StatusArray[i] != OldStatusData.StatusArray[i]) {
|
if (CurrentStatusData.StatusArray[i] != OldStatusData.StatusArray[i]) {
|
||||||
if (!FalsePositive()) {
|
if (
|
||||||
|
//!FalsePositive() //filter conflicting infos
|
||||||
|
true) {
|
||||||
|
FigureDataBlock FigureData;
|
||||||
switch (CurrentStatusData.StatusArray[i])
|
switch (CurrentStatusData.StatusArray[i])
|
||||||
{
|
{
|
||||||
case EFigureStatus::NOT_PRESENT:
|
case EFigureStatus::NOT_PRESENT:
|
||||||
break;
|
OnSkylanderRemoved.Broadcast(00, i);
|
||||||
case EFigureStatus::PRESENT:
|
break;
|
||||||
break;
|
case EFigureStatus::PRESENT:
|
||||||
case EFigureStatus::ADDED:
|
FigureData = ReadFigureBlocks(i);
|
||||||
//get SkylandID
|
OnSkylanderAdded.Broadcast(GetFigureID(FigureData), i);
|
||||||
//ReadBlock;
|
break;
|
||||||
OnSkylanderAdded.Broadcast(01, i);
|
case EFigureStatus::ADDED:
|
||||||
case EFigureStatus::REMOVED:
|
FigureData = ReadFigureBlocks(i);
|
||||||
OnSkylanderRemoved.Broadcast(01, i)
|
OnSkylanderAdded.Broadcast(GetFigureID(FigureData), i);
|
||||||
|
case EFigureStatus::REMOVED:
|
||||||
|
OnSkylanderRemoved.Broadcast(00, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,10 +410,30 @@ void USkyPortalSubsystem::CheckComplexResponse() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USkyPortalSubsystem::FalsePositive()
|
TArray<uint8> USkyPortalSubsystem::QueryBlock(uint8 characterIndex, uint8 block)
|
||||||
|
{
|
||||||
|
TArray<uint8> QueryCommand;
|
||||||
|
QueryCommand.SetNum(0x21);
|
||||||
|
QueryCommand[1] = 'Q';
|
||||||
|
QueryCommand[2] = characterIndex;
|
||||||
|
QueryCommand[3] = block;
|
||||||
|
|
||||||
|
TArray<uint8> Output;
|
||||||
|
|
||||||
|
do {
|
||||||
|
portalConnection->Write(QueryCommand);
|
||||||
|
output = portalConnection->Read();
|
||||||
|
} while (output[0] != 'Q' || (output[1] % 0x10 != characterIndex && output[1] != 0x01) || output[2] != block);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool USkyPortalSubsystem::FalsePositive() const
|
||||||
{
|
{
|
||||||
int dif = FMath::Abs(CurrentStatusData.Counter - OldStatusData.Counter);
|
int dif = FMath::Abs(CurrentStatusData.Counter - OldStatusData.Counter);
|
||||||
return (dif <= 2 || dif > 254);
|
return (dif <= 2 || dif >= 254);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,60 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
//#include "SkyPortalFigure.generated.h"
|
||||||
|
|
||||||
#include "SkyPortalFigure.generated.h"
|
|
||||||
|
|
||||||
|
#define FIGURE_TOTAL_BLOCKS 64
|
||||||
|
#define FIGURE_BLOCK_SIZE 16
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char blockdata[FIGURE_TOTAL_BLOCKS][FIGURE_BLOCK_SIZE]; bool error;
|
||||||
|
} FigureDataBlock;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Category = "SkyPortal|Figure"))
|
||||||
|
uint32 GetFigureID(const FigureDataBlock& DataBlock);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Category = "SkyPortal|Figure"))
|
||||||
|
uint32 GetFigureIdByIndex(uint32 index);
|
||||||
|
|
||||||
|
class FigureData {
|
||||||
|
public:
|
||||||
|
// Data Arrays
|
||||||
|
uint8 data[64][16];
|
||||||
|
uint8 decryptedData[64][16];
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
#pragma region manufacturer
|
||||||
|
uint32 NUID; // should under no circumstances be corrupted. 4-byte
|
||||||
|
uint8 BCC; //Block Check Character. When this BCC does not match the NUID of the tag, the tag ceases to function. stored in block 0 at offset 0x4
|
||||||
|
uint8 SAK = 0x81; //needs to be set to allow for the tag to be read correctly
|
||||||
|
uint16 ATQA; //always set to 0x01 0x0F
|
||||||
|
FString ProductionYear; //last 2 digits of the year that the tag was manufactured as Binary-coded decimal
|
||||||
|
#pragma endregion
|
||||||
|
int16 ID;
|
||||||
|
#pragma region Toy code
|
||||||
|
uint32 ToyCodeNumber1, ToyCodeNumber2;
|
||||||
|
uint64 FullToyCodeNumber;
|
||||||
|
FString ToyCode;
|
||||||
|
#pragma endregion
|
||||||
|
int16 VariantID;
|
||||||
|
#pragma region counters
|
||||||
|
uint8 counter1;
|
||||||
|
uint8 couter2;
|
||||||
|
#pragma endregion
|
||||||
|
FString Nickname;
|
||||||
|
|
||||||
|
FigureData()
|
||||||
|
{
|
||||||
|
ClearData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
void ReadData(uint8 index);
|
||||||
|
void ClearData();
|
||||||
|
uint8 GetByte(int block, int offset);
|
||||||
|
void SetByte(int block, int offset, uint8 value);
|
||||||
|
uint16 GetShort(int block, int offset);
|
||||||
|
uint32 GetUInt(int block, int offset);
|
||||||
|
void Dump(bool decrypted, FString filePath);
|
||||||
|
};
|
33
Source/SkyPortal/Public/SkyPortalIO.h
Normal file
33
Source/SkyPortal/Public/SkyPortalIO.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
* This is the bridge between hidapi and unreal and contains all the rawdata of the portal
|
||||||
|
*/
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "hidapi.h"
|
||||||
|
|
||||||
|
#include "SkyPortalIO.generated.h"
|
||||||
|
|
||||||
|
DECLARE_LOG_CATEGORY_EXTERN(LogHIDApi, Log, All);
|
||||||
|
DECLARE_LOG_CATEGORY_EXTERN(LogSkyportalIO, Log, All);
|
||||||
|
|
||||||
|
UCLASS(MinimalAPI)
|
||||||
|
class SkyPortalIO : public UObjectBase
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
SkyPortalIO()
|
||||||
|
{
|
||||||
|
OpenPortalHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool OpenPortalHandle();
|
||||||
|
|
||||||
|
//Portal ref used in the subsystem
|
||||||
|
hid_device* PortalDevice;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
|
||||||
#include "Subsystems/EngineSubsystem.h"
|
#include "Subsystems/EngineSubsystem.h"
|
||||||
#include "hidapi.h"
|
#include "hidapi.h"
|
||||||
#include "HAL/Runnable.h"
|
#include "HAL/Runnable.h"
|
||||||
|
@ -46,7 +45,7 @@ struct FPortalStatusData
|
||||||
GENERATED_USTRUCT_BODY()
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
// Array of statuses
|
// Array of statuses
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "SkyPortal|Figure")
|
UPROPERTY(BlueprintReadOnly, EditFixedSize, Category = "SkyPortal|Figure", meta = (EditFixedOrder))
|
||||||
TArray<EFigureStatus> StatusArray;
|
TArray<EFigureStatus> StatusArray;
|
||||||
|
|
||||||
// timestamp.
|
// timestamp.
|
||||||
|
@ -59,6 +58,14 @@ struct FPortalStatusData
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "SkyPortal|Figure")
|
UPROPERTY(BlueprintReadOnly, Category = "SkyPortal|Figure")
|
||||||
bool bIsReady;
|
bool bIsReady;
|
||||||
|
|
||||||
|
explicit FPortalStatusData(uint8 ArraySize = 16, EFigureStatus DefaultStatus = EFigureStatus::NOT_PRESENT) :
|
||||||
|
Counter(0), // Utilisation correcte de l'initialisation directe
|
||||||
|
bIsReady(true) // Utilisation correcte de l'initialisation directe
|
||||||
|
{
|
||||||
|
// Initialisation du tableau StatusArray avec 16 éléments par défaut
|
||||||
|
StatusArray.Init(DefaultStatus, ArraySize);
|
||||||
|
}
|
||||||
|
|
||||||
// Overload the == operator
|
// Overload the == operator
|
||||||
bool operator==(const FPortalStatusData& Other) const
|
bool operator==(const FPortalStatusData& Other) const
|
||||||
{
|
{
|
||||||
|
@ -81,19 +88,12 @@ struct FPortalStatusData
|
||||||
#define rw_buf_size 0x21
|
#define rw_buf_size 0x21
|
||||||
#define TIMEOUT 30000
|
#define TIMEOUT 30000
|
||||||
#define DEBUG true
|
#define DEBUG true
|
||||||
#define FIGURE_TOTAL_BLOCKS 64
|
|
||||||
#define FIGURE_BLOCK_SIZE 16
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char buf[rw_buf_size]; int BytesTransferred;
|
unsigned char buf[rw_buf_size]; int BytesTransferred;
|
||||||
} RWBlock;
|
} RWBlock;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned char blockdata[FIGURE_TOTAL_BLOCKS][FIGURE_BLOCK_SIZE]; bool error;
|
|
||||||
} FigureDataBlock;
|
|
||||||
|
|
||||||
DECLARE_LOG_CATEGORY_EXTERN(LogHIDApi, Log, All);
|
|
||||||
DECLARE_LOG_CATEGORY_EXTERN(LogSkyportalIO, Log, All);
|
|
||||||
|
|
||||||
//// Delegates
|
//// Delegates
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkylanderAddedDelegate, int32, SkylanderID, int32, Index);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkylanderAddedDelegate, int32, SkylanderID, int32, Index);
|
||||||
|
@ -184,7 +184,7 @@ public:
|
||||||
* @param PortalSide The actors to record
|
* @param PortalSide The actors to record
|
||||||
* @param BlendTime Blend between current color and NextColor, in milliseconds
|
* @param BlendTime Blend between current color and NextColor, in milliseconds
|
||||||
*/
|
*/
|
||||||
UFUNCTION(BlueprintCallable, CallInEditor, meta = (AutoCreateRefTerm = "NextColor", Category = "SkyPortal|Cosmetic"))
|
UFUNCTION(BlueprintCallable, CallInEditor, meta = (AutoCreateRefTerm = "NextColor", Category = "SkyPortal|Cosmetic", HideAlphaChannel))
|
||||||
SKYPORTAL_API void ChangePortalColorside(const FLinearColor& NextColor = FLinearColor::Green, const EPortalSide PortalSide = EPortalSide::BOTH, const float BlendTime = 500.0f);
|
SKYPORTAL_API void ChangePortalColorside(const FLinearColor& NextColor = FLinearColor::Green, const EPortalSide PortalSide = EPortalSide::BOTH, const float BlendTime = 500.0f);
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,7 +215,8 @@ public:
|
||||||
bool CheckResponse(RWBlock*, char);
|
bool CheckResponse(RWBlock*, char);
|
||||||
void CheckComplexResponse();
|
void CheckComplexResponse();
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
TArray<uint8> QueryBlock(uint8 characterIndex, uint8 block = 0x00);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -237,7 +238,7 @@ private:
|
||||||
bool OpenPortalHandle();
|
bool OpenPortalHandle();
|
||||||
void Write(RWBlock*);
|
void Write(RWBlock*);
|
||||||
FigureDataBlock ReadFigureBlocks(uint8 FigureIndex);
|
FigureDataBlock ReadFigureBlocks(uint8 FigureIndex);
|
||||||
bool FalsePositive();
|
bool FalsePositive() const;
|
||||||
|
|
||||||
// Pointer to the status checker thread
|
// Pointer to the status checker thread
|
||||||
FPortalStatusChecker* StatusChecker;
|
FPortalStatusChecker* StatusChecker;
|
||||||
|
|
Loading…
Reference in a new issue