SkyPortal-plugin/Source/SkyPortal/Private/SkyPortalSubsystem.cpp

241 lines
5.9 KiB
C++
Raw Normal View History

// A lot of this code is made because of the work of https://github.com/capull0/SkyDumper and https://github.com/silicontrip/SkyReader
2024-09-18 13:30:30 +00:00
#include "SkyPortalSubsystem.h"
#include "Engine/Engine.h"
2024-09-25 15:33:25 +00:00
#include "SkyPortal.h"
2024-09-19 12:03:16 +00:00
2024-09-23 13:48:29 +00:00
#include "HAL/RunnableThread.h"
#include "Misc/ScopeLock.h"
2024-09-18 13:30:30 +00:00
void USkyPortalSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
2024-09-19 12:03:16 +00:00
2024-09-18 13:30:30 +00:00
Super::Initialize(Collection);
2024-09-23 13:48:29 +00:00
// Start the status checker thread
StatusChecker = new FPortalStatusChecker(this, RunnerInterval);
2024-09-23 13:48:29 +00:00
StatusCheckerThread = FRunnableThread::Create(StatusChecker, TEXT("PortalStatusCheckerThread"), 0, TPri_AboveNormal);
UE_LOG(LogTemp, Log, TEXT("SkyPortalSubsystem Initialized"));
2024-09-18 14:54:36 +00:00
2024-09-18 13:30:30 +00:00
}
void USkyPortalSubsystem::Deinitialize()
{
2024-09-23 13:48:29 +00:00
// Stop the thread when the subsystem is deinitialized
if (StatusChecker)
{
StatusChecker->Stop();
StatusCheckerThread->WaitForCompletion();
delete StatusCheckerThread;
delete StatusChecker;
StatusChecker = nullptr;
StatusCheckerThread = nullptr;
}
2024-09-19 12:03:16 +00:00
// Disconnect portal
2024-09-25 11:47:11 +00:00
if (PortalHandle) {
PortalHandle->Close();
2024-09-19 12:03:16 +00:00
}
hid_exit();
2024-09-18 16:10:50 +00:00
UE_LOG(LogTemp, Log, TEXT("SkyPortalSubsystem Deinitialized"));
2024-09-18 13:30:30 +00:00
Super::Deinitialize();
2024-09-19 12:03:16 +00:00
}
2024-09-25 11:47:11 +00:00
void USkyPortalSubsystem::PortalActivate(const bool bShouldActivate)
{
2024-09-25 11:47:11 +00:00
FWriteBlock command;
2024-09-25 11:47:11 +00:00
memset(command.data, 0, write_buf_size);
command.data[1] = 'A';
command.data[2] = bShouldActivate;
uint8* output;
do {
PortalHandle->Write(&command);
output = PortalHandle->Read();
} while (output[0] != 'A');
}
2024-09-25 11:47:11 +00:00
void USkyPortalSubsystem::PortalReady()
{
2024-09-24 22:17:52 +00:00
FWriteBlock command;
2024-09-25 11:47:11 +00:00
memset(command.data, 0, write_buf_size); //maybe not needed here
2024-09-24 22:17:52 +00:00
command.data[1] = 'R';
unsigned char* output;
2024-09-25 11:47:11 +00:00
do {
2024-09-24 22:17:52 +00:00
PortalHandle->Write(&command);
2024-09-25 11:47:11 +00:00
output = PortalHandle->Read();
2024-09-24 22:17:52 +00:00
} while (output[0] != 'R');
2024-09-26 13:01:42 +00:00
unsigned char _PortalId[2] = { output[1],output[2] };
uint16_t BE_PortalId = (_PortalId[0] << 8) | _PortalId[1]; // Big-endian format
2024-09-26 13:01:42 +00:00
uint32 BEU_PortalId = (_PortalId[0] << 8) | _PortalId[1]; // Big-endian format unsigned
uint16_t LE_PortalId = (_PortalId[1] << 8) | _PortalId[0]; //little endian
//uint32 LEU_PortalId = (_PortalId[1] << 8) | _PortalId[0]; //little endian unsigned
PortalId = BEU_PortalId; //Need a conversion as uint16 is not supported in BP
}
2024-09-19 12:03:16 +00:00
2024-09-25 22:19:16 +00:00
FPortalStatusData USkyPortalSubsystem::PortalStatus() {
FWriteBlock command;
memset(command.data, 0, write_buf_size); //maybe not needed here
command.data[1] = 'S';
uint8* output;
do {
PortalHandle->Write(&command);
output = PortalHandle->Read();
} while (output[0] != 'S');
2024-09-26 11:10:47 +00:00
2024-09-25 22:19:16 +00:00
return ParsePortalStatus(output);
}
SKYPORTAL_API bool USkyPortalSubsystem::RestartRunner()
{
if (StatusChecker)
{
StatusChecker->Stop();
StatusCheckerThread->WaitForCompletion();
delete StatusCheckerThread;
delete StatusChecker;
StatusChecker = nullptr;
StatusCheckerThread = nullptr;
}
StatusChecker = new FPortalStatusChecker(this, RunnerInterval); // Check every 10 milliseconds
StatusCheckerThread = FRunnableThread::Create(StatusChecker, TEXT("PortalStatusCheckerThread"), 0, TPri_AboveNormal);
UE_LOG(LogTemp, Log, TEXT("SkyPortalSubsystem Initialized"));
2024-09-26 15:52:10 +00:00
return true;
}
2024-09-25 22:19:16 +00:00
2024-09-19 12:03:16 +00:00
2024-09-25 11:47:11 +00:00
#pragma region Color functions
void USkyPortalSubsystem::ChangePortalColor(const FLinearColor& Color)
{
2024-09-23 16:06:55 +00:00
unsigned char r = FMath::Clamp(Color.R * 100, 0.0f, 255.0f);
unsigned char g = FMath::Clamp(Color.G * 100, 0.0f, 255.0f);
unsigned char b = FMath::Clamp(Color.B * 100, 0.0f, 255.0f);
2024-09-25 11:47:11 +00:00
FWriteBlock command;
2024-09-25 11:47:11 +00:00
memset(command.data, 0, write_buf_size);
2024-09-21 22:01:15 +00:00
2024-09-25 11:47:11 +00:00
command.data[1] = 'C';
command.data[2] = r; // R
command.data[3] = g; // G
command.data[4] = b; // B
// no response for this one.
2024-09-25 11:47:11 +00:00
PortalHandle->Write(&command);
}
2024-09-25 11:47:11 +00:00
void USkyPortalSubsystem::ChangePortalColorSide(const FLinearColor& Color, const EPortalSide PortalSide, const float BlendTime)
2024-09-21 22:01:15 +00:00
{
2024-09-22 21:58:01 +00:00
unsigned char r = FMath::Clamp(Color.R * 100, 0, 255);
unsigned char g = FMath::Clamp(Color.G * 100, 0, 255);
unsigned char b = FMath::Clamp(Color.B * 100, 0, 255);
EPortalSide _portalside;
2024-09-25 11:47:11 +00:00
FWriteBlock command;
2024-09-21 22:01:15 +00:00
2024-09-25 11:47:11 +00:00
memset(command.data, 0, write_buf_size);
2024-09-21 22:01:15 +00:00
2024-09-22 21:58:01 +00:00
if (PortalSide == EPortalSide::BOTH) {
_portalside = EPortalSide::LEFT;
}
2024-09-25 15:33:25 +00:00
else {
_portalside = PortalSide;
}
2024-09-22 21:58:01 +00:00
switch (_portalside) {
2024-09-21 22:01:15 +00:00
case EPortalSide::LEFT:
2024-09-25 11:47:11 +00:00
command.data[1] = 'J';
command.data[2] = 0x00;
2024-09-21 22:01:15 +00:00
case EPortalSide::RIGHT:
2024-09-25 11:47:11 +00:00
command.data[1] = 'J';
command.data[2] = 0x02;
2024-09-22 21:58:01 +00:00
case EPortalSide::TRAP:
2024-09-25 11:47:11 +00:00
command.data[1] = 'L';
command.data[2] = 0x01;
command.data[3] = FMath::Max3(r, g, b); // calculate brightness
PortalHandle->Write(&command); //since it's a color command for trap, only 3 bytes are needed, no response.
2024-09-22 21:58:01 +00:00
return;
2024-09-21 22:01:15 +00:00
}
2024-09-22 21:58:01 +00:00
2024-09-25 11:47:11 +00:00
command.data[3] = r; // R
command.data[4] = g; // G
command.data[5] = b; // B
2024-09-21 22:01:15 +00:00
//Convert the time in millisecond into two bytes
uint16_t _time = BlendTime;
uint8_t _time_low = _time & 0xFF; // Get the low byte by masking the least significant 8 bits
uint8_t _time_high = (_time >> 8) & 0xFF; // Get the high byte extracted by shifting the bits 8 positions to the right and masking the result
2024-09-25 11:47:11 +00:00
command.data[6] = _time_low;
command.data[7] = _time_high;
2024-09-21 22:01:15 +00:00
2024-09-25 11:47:11 +00:00
uint8* output;
do {
PortalHandle->Write(&command);
output = PortalHandle->Read();
} while (output[0] != 'J');
2024-09-21 22:01:15 +00:00
2024-09-22 21:58:01 +00:00
if (PortalSide == EPortalSide::BOTH) {
2024-09-25 11:47:11 +00:00
ChangePortalColorSide(Color, EPortalSide::RIGHT, BlendTime); // send a second command for the right side
2024-09-22 21:58:01 +00:00
}
2024-09-21 22:01:15 +00:00
}
2024-09-25 11:47:11 +00:00
#pragma endregion
2024-09-21 22:01:15 +00:00
2024-09-21 15:12:02 +00:00
void USkyPortalSubsystem::Sleep(int sleepMs) {
FPlatformProcess::Sleep(sleepMs * 0.0001);
2024-09-19 12:03:16 +00:00
}
2024-09-25 11:47:11 +00:00
bool USkyPortalSubsystem::PortalConnect()
{
2024-09-24 22:17:52 +00:00
PortalHandle = NewObject<USkyPortalIO>();
2024-09-25 15:33:25 +00:00
if (IsValid(PortalHandle)) {
2024-09-24 22:17:52 +00:00
UE_LOG(LogSkyportalIO, Log, TEXT("Portal connected: "));
2024-09-25 11:47:11 +00:00
PortalReady();
PortalActivate(1);
2024-09-21 15:12:02 +00:00
Sleep(500);
2024-09-23 16:06:55 +00:00
ChangePortalColor(FLinearColor(0.5, 0.5, 0.5));
2024-09-24 22:17:52 +00:00
return true;
}
2024-09-24 22:17:52 +00:00
return false;
}
2024-09-25 15:33:25 +00:00
bool USkyPortalSubsystem::IsPortalReady()
2024-09-22 21:58:01 +00:00
{
2024-09-25 15:33:25 +00:00
if (PortalHandle) {
return PortalHandle->bPortalReady;
}
//maybe should send a status request ?
2024-09-22 21:58:01 +00:00
return false;
}
2024-09-25 22:19:16 +00:00
SKYPORTAL_API void USkyPortalSubsystem::PortalMusic(const USoundWave* Sound)
2024-09-22 21:58:01 +00:00
{
2024-09-26 11:10:47 +00:00
return;
2024-09-22 21:58:01 +00:00
}