SkyPortal-plugin/Source/SkyPortal/Public/SkyPortalSubsystem.h

262 lines
7 KiB
C
Raw Normal View History

2024-09-18 13:30:30 +00:00
#pragma once
#include "Subsystems/EngineSubsystem.h"
2024-09-19 12:03:16 +00:00
#include "hidapi.h"
2024-09-23 13:48:29 +00:00
#include "HAL/Runnable.h"
2024-09-23 21:55:43 +00:00
#include "SkyPortalFigure.h"
2024-09-19 12:03:16 +00:00
2024-09-18 13:30:30 +00:00
#include "SkyPortalSubsystem.generated.h"
2024-09-22 21:58:01 +00:00
#pragma region Definitions
2024-09-19 12:03:16 +00:00
2024-09-21 22:01:15 +00:00
UENUM(BlueprintType)
enum EPortalSide {
LEFT UMETA(DisplayName = "Left side"),
RIGHT UMETA(DisplayName = "Right side"),
BOTH UMETA(DisplayName = "Both left and right"),
TRAP UMETA(DisplayName = "Trap")
};
2024-09-22 21:58:01 +00:00
UENUM(BlueprintType)
enum EPortalCommand {
A UMETA(DisplayName = "Activate"),
C UMETA(DisplayName = "Color"),
J UMETA(DisplayName = "Advanced color"),
L UMETA(DisplayName = "Trap color"),
M UMETA(DisplayName = "Music"),
Q UMETA(DisplayName = "Query"),
R UMETA(DisplayName = "Ready"),
S UMETA(DisplayName = "Status")
};
2024-09-23 13:48:29 +00:00
UENUM(BlueprintType)
enum class EFigureStatus : uint8
{
NOT_PRESENT = 0b00 UMETA(DisplayName = "Not Present"),
PRESENT = 0b01 UMETA(DisplayName = "Present"),
ADDED = 0b11 UMETA(DisplayName = "Added"),
REMOVED = 0b10 UMETA(DisplayName = "Removed")
};
USTRUCT(BlueprintType)
2024-09-23 16:06:55 +00:00
struct FPortalStatusData
2024-09-23 13:48:29 +00:00
{
2024-09-23 16:06:55 +00:00
GENERATED_USTRUCT_BODY()
2024-09-21 22:01:15 +00:00
2024-09-23 13:48:29 +00:00
// Array of statuses
UPROPERTY(BlueprintReadOnly, EditFixedSize, Category = "SkyPortal|Figure", meta = (EditFixedOrder))
2024-09-23 13:48:29 +00:00
TArray<EFigureStatus> StatusArray;
// timestamp.
2024-09-23 21:55:43 +00:00
// only one byte long. This means that after the value 0xFF, it overflows back to 0x00.
2024-09-23 13:48:29 +00:00
// Since these are so far apart, it can be assumed that 0x00 is newer than anything in the range 0xF0 - 0xFF.
UPROPERTY(BlueprintReadOnly, Category = "SkyPortal|Figure")
uint8 Counter;
// Should always be true
UPROPERTY(BlueprintReadOnly, Category = "SkyPortal|Figure")
bool bIsReady;
2024-09-23 21:55:43 +00:00
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 <20>l<EFBFBD>ments par d<>faut
StatusArray.Init(DefaultStatus, ArraySize);
}
2024-09-23 21:55:43 +00:00
// Overload the == operator
bool operator==(const FPortalStatusData& Other) const
{
if (bIsReady == Other.bIsReady && Counter == Other.Counter) {
if (StatusArray == Other.StatusArray) {
return true;
}
}
return false;
}
// Overload the != operator
bool operator!=(const FPortalStatusData& Other) const
{
return !(*this == Other);
}
2024-09-23 13:48:29 +00:00
};
2024-09-21 22:01:15 +00:00
2024-09-22 21:58:01 +00:00
/* Macro constants Definitions */
#define rw_buf_size 0x21
#define TIMEOUT 30000
#define DEBUG true
2024-09-23 13:48:29 +00:00
typedef struct {
unsigned char buf[rw_buf_size]; int BytesTransferred;
} RWBlock;
2024-09-23 21:55:43 +00:00
2024-09-22 21:58:01 +00:00
//// Delegates
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkylanderAddedDelegate, int32, SkylanderID, int32, Index);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkylanderRemovedDelegate, int32, SkylanderID, int32, Index);
#pragma endregion
2024-09-23 13:48:29 +00:00
class FPortalStatusChecker : public FRunnable {
public:
// Constructor: pass the subsystem and desired check interval (in seconds)
FPortalStatusChecker(USkyPortalSubsystem* InSubsystem, float InCheckInterval);
// FRunnable interface
virtual bool Init() override;
virtual uint32 Run() override;
virtual void Stop() override;
virtual void Exit() override;
private:
// Pointer to the subsystem that contains PortalStatus()
USkyPortalSubsystem* SkyPortalSubsystem;
// Time interval (in seconds) for status checking
float CheckInterval;
// Thread control variables
FThreadSafeBool bShouldRun;
// Helper function to check portal status
void CheckPortalStatus();
};
2024-09-22 21:58:01 +00:00
/* Handle all the portal I/O
*
*
*
*/
2024-09-21 22:01:15 +00:00
UCLASS(MinimalAPI)
class USkyPortalSubsystem : public UEngineSubsystem
2024-09-18 13:30:30 +00:00
{
GENERATED_BODY()
//Portal ref used in the subsystem
hid_device* PortalDevice;
2024-09-18 13:30:30 +00:00
public:
// Override initialization and deinitialization methods
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
2024-09-19 12:03:16 +00:00
2024-09-22 21:58:01 +00:00
/********* Portal Actions *************/
2024-09-22 21:58:01 +00:00
/* The first function to run, before anything else.
* It will re-init and prepare the portal for receiving/sending inputs
*
* return false if portal is not found
*/
UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal"))
2024-09-21 22:01:15 +00:00
SKYPORTAL_API bool ConnectPortal();
2024-09-19 12:03:16 +00:00
2024-09-22 21:58:01 +00:00
/*Send a **Status** command, to see if the portal is ready to receive new commands*/
UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Category = "SkyPortal|NOT FUNCTIONING"))
SKYPORTAL_API bool bIsPortalReady();
2024-09-19 12:03:16 +00:00
2024-09-22 21:58:01 +00:00
UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|NOT FUNCTIONING"))
SKYPORTAL_API void SendPortalCommand(EPortalCommand Command);
2024-09-22 21:58:01 +00:00
UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|NOT FUNCTIONING"))
SKYPORTAL_API void SendPortalSound(USoundWave* Sound);
2024-09-21 22:01:15 +00:00
2024-09-23 21:55:43 +00:00
2024-09-22 21:58:01 +00:00
/* Change portal color, ideally should be called just at the start.For gameplay usage, use ChangePortalColorside()*/
2024-09-21 22:01:15 +00:00
UFUNCTION(BlueprintCallable, CallInEditor, meta = (AutoCreateRefTerm = "Color", Category = "SkyPortal|Cosmetic"))
SKYPORTAL_API void ChangePortalColor(const FLinearColor& Color = FLinearColor::Green);
2024-09-21 22:01:15 +00:00
/**
* Change the color of the portal, can separate side and even trap ligth
2024-09-22 21:58:01 +00:00
* @param NextColor New color
2024-09-21 22:01:15 +00:00
* @param PortalSide The actors to record
2024-09-22 21:58:01 +00:00
* @param BlendTime Blend between current color and NextColor, in milliseconds
2024-09-21 22:01:15 +00:00
*/
UFUNCTION(BlueprintCallable, CallInEditor, meta = (AutoCreateRefTerm = "NextColor", Category = "SkyPortal|Cosmetic", HideAlphaChannel))
2024-09-22 21:58:01 +00:00
SKYPORTAL_API void ChangePortalColorside(const FLinearColor& NextColor = FLinearColor::Green, const EPortalSide PortalSide = EPortalSide::BOTH, const float BlendTime = 500.0f);
// Blueprint-assignable event property
UPROPERTY(BlueprintAssignable, Category = "SkyPortal|Skylander")
FOnSkylanderAddedDelegate OnSkylanderAdded;
// Blueprint-assignable event property
UPROPERTY(BlueprintAssignable, Category = "SkyPortal|Skylander")
FOnSkylanderRemovedDelegate OnSkylanderRemoved;
2024-09-23 16:06:55 +00:00
UPROPERTY(BlueprintReadOnly)
FPortalStatusData CurrentStatusData;
2024-09-22 21:58:01 +00:00
2024-09-23 21:55:43 +00:00
UPROPERTY(BlueprintReadOnly)
FPortalStatusData OldStatusData;
2024-09-23 13:48:29 +00:00
EPortalCommand GetPortalCommandFromChar(unsigned char Char);
2024-09-22 21:58:01 +00:00
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
bool bPortalConnected = false;
FString HidError;
2024-09-23 13:48:29 +00:00
bool ReadBlock(unsigned int block, unsigned char data[0x10], int skylander);
bool WriteBlock(unsigned int, unsigned char[0x10], int);
bool CheckResponse(RWBlock*, char);
void CheckComplexResponse();
2024-09-21 22:01:15 +00:00
UFUNCTION()
TArray<uint8> QueryBlock(uint8 characterIndex, uint8 block = 0x00);
2024-09-23 16:06:55 +00:00
private:
FPortalStatusData ParsePortalStatus(const RWBlock& ResponseBlock);
2024-09-19 12:03:16 +00:00
2024-09-23 13:48:29 +00:00
static void Sleep(int sleepMs);
void ActivatePortal(int active);
void RestartPortal();
// Block/byte related data write/read functions
bool OpenPortalHandle();
2024-09-22 21:58:01 +00:00
void Write(RWBlock*);
2024-09-23 21:55:43 +00:00
FigureDataBlock ReadFigureBlocks(uint8 FigureIndex);
bool FalsePositive() const;
2024-09-19 12:03:16 +00:00
2024-09-23 13:48:29 +00:00
// Pointer to the status checker thread
FPortalStatusChecker* StatusChecker;
FRunnableThread* StatusCheckerThread;
2024-09-19 12:03:16 +00:00
protected:
//Constants
const int VendorIds[4] = { 0x12ba, 0x54c, 0x1430, 0x1430 };
const int ProductIds[4] = { 0x150, 0x967, 0x1f17 };
2024-09-22 21:58:01 +00:00
/////Defaults values, should not be used
//const int VendorId = 5168;
//const int ProductId = 336;
2024-09-18 13:30:30 +00:00
};
2024-09-19 12:03:16 +00:00
2024-09-23 13:48:29 +00:00