feat(char-spawn): Fase 4 client + UI WBPs paralelo #2
@@ -19,6 +19,15 @@ void UZMMOWorldSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
|||||||
RemoteEntityClasses.Add(EZMMOEntityType::NPC, AZMMOEntity::StaticClass());
|
RemoteEntityClasses.Add(EZMMOEntityType::NPC, AZMMOEntity::StaticClass());
|
||||||
RemoteEntityClasses.Add(EZMMOEntityType::Object, AZMMOEntity::StaticClass());
|
RemoteEntityClasses.Add(EZMMOEntityType::Object, AZMMOEntity::StaticClass());
|
||||||
}
|
}
|
||||||
|
// Bind + replay vivem em OnWorldBeginPlay (mundo pronto). Initialize roda
|
||||||
|
// MUITO cedo no pipeline de LoadMap — antes do GameMode ser instanciado
|
||||||
|
// e antes do WorldPartition terminar de carregar cells. Spawns dinamicos
|
||||||
|
// feitos aqui podem ser perdidos durante a fase de setup posterior.
|
||||||
|
}
|
||||||
|
|
||||||
|
void UZMMOWorldSubsystem::OnWorldBeginPlay(UWorld& InWorld)
|
||||||
|
{
|
||||||
|
Super::OnWorldBeginPlay(InWorld);
|
||||||
|
|
||||||
if (UZeusNetworkSubsystem* ZeusNet = ResolveZeusNetworkSubsystem())
|
if (UZeusNetworkSubsystem* ZeusNet = ResolveZeusNetworkSubsystem())
|
||||||
{
|
{
|
||||||
@@ -26,10 +35,26 @@ void UZMMOWorldSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
|||||||
ZeusNet->OnPlayerDespawned.AddDynamic(this, &UZMMOWorldSubsystem::HandlePlayerDespawned);
|
ZeusNet->OnPlayerDespawned.AddDynamic(this, &UZMMOWorldSubsystem::HandlePlayerDespawned);
|
||||||
ZeusNet->OnPlayerStateUpdate.AddDynamic(this, &UZMMOWorldSubsystem::HandlePlayerStateUpdate);
|
ZeusNet->OnPlayerStateUpdate.AddDynamic(this, &UZMMOWorldSubsystem::HandlePlayerStateUpdate);
|
||||||
UE_LOG(LogZMMO, Log, TEXT("ZMMOWorldSubsystem bound to ZeusNetworkSubsystem delegates."));
|
UE_LOG(LogZMMO, Log, TEXT("ZMMOWorldSubsystem bound to ZeusNetworkSubsystem delegates."));
|
||||||
|
|
||||||
|
// Catch-up race fix (Fase 3): broadcasts de proxies remotos chegam
|
||||||
|
// enquanto o cliente novo ainda esta em OpenLevel. UZeusNetworkSubsystem
|
||||||
|
// cacheia em PendingRemoteSpawnsByEntity. Aplicamos aqui — mundo ja
|
||||||
|
// esta pronto (GameMode ativo, WorldPartition cells inicializadas).
|
||||||
|
int32 ReplayCount = 0;
|
||||||
|
ZeusNet->ForEachPendingRemoteSpawn(
|
||||||
|
[this, &ReplayCount](const int32 EntityId, const FVector PosCm, const float YawDeg, const int64 ServerTimeMs)
|
||||||
|
{
|
||||||
|
HandlePlayerSpawned(EntityId, /*bIsLocal=*/false, PosCm, YawDeg, ServerTimeMs);
|
||||||
|
++ReplayCount;
|
||||||
|
});
|
||||||
|
if (ReplayCount > 0)
|
||||||
|
{
|
||||||
|
UE_LOG(LogZMMO, Log, TEXT("ZMMOWorldSubsystem: replay de %d proxy(ies) cacheados."), ReplayCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UE_LOG(LogZMMO, Warning, TEXT("ZMMOWorldSubsystem: ZeusNetworkSubsystem not found at Initialize."));
|
UE_LOG(LogZMMO, Warning, TEXT("ZMMOWorldSubsystem: ZeusNetworkSubsystem not found at OnWorldBeginPlay."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class ZMMO_API UZMMOWorldSubsystem : public UWorldSubsystem
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||||
|
virtual void OnWorldBeginPlay(UWorld& InWorld) override;
|
||||||
virtual void Deinitialize() override;
|
virtual void Deinitialize() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "ZMMO.h"
|
#include "ZMMO.h"
|
||||||
#include "CharServerOpcodes.h"
|
#include "CharServerOpcodes.h"
|
||||||
#include "UIFrontEndFlowSubsystem.h"
|
#include "UIFrontEndFlowSubsystem.h"
|
||||||
|
#include "WireHelpers.h"
|
||||||
#include "ZeusCharServerSubsystem.h"
|
#include "ZeusCharServerSubsystem.h"
|
||||||
#include "Components/EditableTextBox.h"
|
#include "Components/EditableTextBox.h"
|
||||||
#include "Components/ComboBoxString.h"
|
#include "Components/ComboBoxString.h"
|
||||||
@@ -10,48 +11,11 @@
|
|||||||
#include "Engine/GameInstance.h"
|
#include "Engine/GameInstance.h"
|
||||||
#include "UI/Widgets/UIButton_Base.h"
|
#include "UI/Widgets/UIButton_Base.h"
|
||||||
|
|
||||||
namespace
|
using ZMMOWire::WriteUuid16;
|
||||||
{
|
using ZMMOWire::WriteUInt8;
|
||||||
bool WriteUuid16(TArray<uint8>& Buf, const FString& Uuid)
|
using ZMMOWire::WriteUInt16;
|
||||||
{
|
using ZMMOWire::WriteUInt32;
|
||||||
FString Hex = Uuid.Replace(TEXT("-"), TEXT(""));
|
using ZMMOWire::WriteStringUtf8;
|
||||||
if (Hex.Len() != 32) return false;
|
|
||||||
for (int32 i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
TCHAR hi = Hex[i * 2];
|
|
||||||
TCHAR lo = Hex[i * 2 + 1];
|
|
||||||
auto HexVal = [](TCHAR c) -> int32 {
|
|
||||||
if (c >= TEXT('0') && c <= TEXT('9')) return c - TEXT('0');
|
|
||||||
if (c >= TEXT('a') && c <= TEXT('f')) return c - TEXT('a') + 10;
|
|
||||||
if (c >= TEXT('A') && c <= TEXT('F')) return c - TEXT('A') + 10;
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
int32 H = HexVal(hi);
|
|
||||||
int32 L = HexVal(lo);
|
|
||||||
if (H < 0 || L < 0) return false;
|
|
||||||
Buf.Add(static_cast<uint8>((H << 4) | L));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteUInt8(TArray<uint8>& Buf, uint8 v) { Buf.Add(v); }
|
|
||||||
void WriteUInt16(TArray<uint8>& Buf, uint16 v)
|
|
||||||
{
|
|
||||||
Buf.Add(static_cast<uint8>(v & 0xFF));
|
|
||||||
Buf.Add(static_cast<uint8>((v >> 8) & 0xFF));
|
|
||||||
}
|
|
||||||
void WriteUInt32(TArray<uint8>& Buf, uint32 v)
|
|
||||||
{
|
|
||||||
for (int32 i = 0; i < 4; ++i) Buf.Add(static_cast<uint8>((v >> (8 * i)) & 0xFF));
|
|
||||||
}
|
|
||||||
void WriteStringUtf8(TArray<uint8>& Buf, const FString& S)
|
|
||||||
{
|
|
||||||
FTCHARToUTF8 Conv(*S);
|
|
||||||
const int32 Len = Conv.Length();
|
|
||||||
WriteUInt16(Buf, static_cast<uint16>(Len));
|
|
||||||
Buf.Append(reinterpret_cast<const uint8*>(Conv.Get()), Len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UUICharacterCreatePage_Base::NativeConstruct()
|
void UUICharacterCreatePage_Base::NativeConstruct()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "CharServerOpcodes.h"
|
#include "CharServerOpcodes.h"
|
||||||
#include "UIFrontEndFlowSubsystem.h"
|
#include "UIFrontEndFlowSubsystem.h"
|
||||||
#include "UIServerCard_Base.h"
|
#include "UIServerCard_Base.h"
|
||||||
|
#include "WireHelpers.h"
|
||||||
#include "ZeusCharServerSubsystem.h"
|
#include "ZeusCharServerSubsystem.h"
|
||||||
#include "CommonTextBlock.h"
|
#include "CommonTextBlock.h"
|
||||||
#include "Components/Border.h"
|
#include "Components/Border.h"
|
||||||
@@ -15,6 +16,10 @@
|
|||||||
#include "Engine/DataTable.h"
|
#include "Engine/DataTable.h"
|
||||||
#include "UI/UIStyleRow.h"
|
#include "UI/UIStyleRow.h"
|
||||||
|
|
||||||
|
using ZMMOWire::ReadU8;
|
||||||
|
using ZMMOWire::ReadU16;
|
||||||
|
using ZMMOWire::ReadStringUtf8;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
FUIStyle ResolveServerSelectStyle(const UUserWidget* Widget, const FUIStyle& Fallback)
|
FUIStyle ResolveServerSelectStyle(const UUserWidget* Widget, const FUIStyle& Fallback)
|
||||||
@@ -43,40 +48,6 @@ namespace
|
|||||||
}
|
}
|
||||||
return bHas ? DesignStyle : Fallback;
|
return bHas ? DesignStyle : Fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Wire reader (LE) ----
|
|
||||||
bool ReadU8(const TArray<uint8>& Buf, int32& Pos, uint8& Out)
|
|
||||||
{
|
|
||||||
if (Pos + 1 > Buf.Num()) return false;
|
|
||||||
Out = Buf[Pos];
|
|
||||||
Pos += 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReadU16(const TArray<uint8>& Buf, int32& Pos, uint16& Out)
|
|
||||||
{
|
|
||||||
if (Pos + 2 > Buf.Num()) return false;
|
|
||||||
Out = static_cast<uint16>(Buf[Pos]) | (static_cast<uint16>(Buf[Pos + 1]) << 8);
|
|
||||||
Pos += 2;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReadStringUtf8(const TArray<uint8>& Buf, int32& Pos, FString& Out)
|
|
||||||
{
|
|
||||||
uint16 Len = 0;
|
|
||||||
if (!ReadU16(Buf, Pos, Len)) return false;
|
|
||||||
if (Pos + Len > Buf.Num()) return false;
|
|
||||||
if (Len == 0)
|
|
||||||
{
|
|
||||||
Out.Reset();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Out = FString(FUTF8ToTCHAR(reinterpret_cast<const ANSICHAR*>(Buf.GetData() + Pos), Len));
|
|
||||||
}
|
|
||||||
Pos += Len;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UUIServerSelectScreen_Base::NativePreConstruct()
|
void UUIServerSelectScreen_Base::NativePreConstruct()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "UIFrontEndFlowSubsystem.h"
|
#include "UIFrontEndFlowSubsystem.h"
|
||||||
#include "UICharCard_Base.h"
|
#include "UICharCard_Base.h"
|
||||||
#include "UICharacterCreatePage_Base.h"
|
#include "UICharacterCreatePage_Base.h"
|
||||||
|
#include "WireHelpers.h"
|
||||||
#include "ZeusCharServerSubsystem.h"
|
#include "ZeusCharServerSubsystem.h"
|
||||||
#include "ZeusNetworkSubsystem.h"
|
#include "ZeusNetworkSubsystem.h"
|
||||||
#include "CommonTextBlock.h"
|
#include "CommonTextBlock.h"
|
||||||
@@ -13,96 +14,14 @@
|
|||||||
#include "Engine/GameInstance.h"
|
#include "Engine/GameInstance.h"
|
||||||
#include "UI/Widgets/UIButton_Base.h"
|
#include "UI/Widgets/UIButton_Base.h"
|
||||||
|
|
||||||
namespace
|
using ZMMOWire::ReadU8;
|
||||||
{
|
using ZMMOWire::ReadU16;
|
||||||
bool ReadU8(const TArray<uint8>& Buf, int32& Pos, uint8& Out)
|
using ZMMOWire::ReadU32;
|
||||||
{
|
using ZMMOWire::ReadU64;
|
||||||
if (Pos + 1 > Buf.Num()) return false;
|
using ZMMOWire::ReadFloat;
|
||||||
Out = Buf[Pos]; Pos += 1; return true;
|
using ZMMOWire::ReadStringUtf8;
|
||||||
}
|
using ZMMOWire::ReadUuid16;
|
||||||
bool ReadU16(const TArray<uint8>& Buf, int32& Pos, uint16& Out)
|
using ZMMOWire::WriteUuid16;
|
||||||
{
|
|
||||||
if (Pos + 2 > Buf.Num()) return false;
|
|
||||||
Out = static_cast<uint16>(Buf[Pos]) | (static_cast<uint16>(Buf[Pos + 1]) << 8);
|
|
||||||
Pos += 2; return true;
|
|
||||||
}
|
|
||||||
bool ReadU32(const TArray<uint8>& Buf, int32& Pos, uint32& Out)
|
|
||||||
{
|
|
||||||
if (Pos + 4 > Buf.Num()) return false;
|
|
||||||
Out = static_cast<uint32>(Buf[Pos])
|
|
||||||
| (static_cast<uint32>(Buf[Pos + 1]) << 8)
|
|
||||||
| (static_cast<uint32>(Buf[Pos + 2]) << 16)
|
|
||||||
| (static_cast<uint32>(Buf[Pos + 3]) << 24);
|
|
||||||
Pos += 4; return true;
|
|
||||||
}
|
|
||||||
bool ReadU64(const TArray<uint8>& Buf, int32& Pos, uint64& Out)
|
|
||||||
{
|
|
||||||
if (Pos + 8 > Buf.Num()) return false;
|
|
||||||
Out = 0;
|
|
||||||
for (int i = 0; i < 8; ++i) Out |= (static_cast<uint64>(Buf[Pos + i]) << (8 * i));
|
|
||||||
Pos += 8; return true;
|
|
||||||
}
|
|
||||||
bool ReadFloat(const TArray<uint8>& Buf, int32& Pos, float& Out)
|
|
||||||
{
|
|
||||||
uint32 raw;
|
|
||||||
if (!ReadU32(Buf, Pos, raw)) return false;
|
|
||||||
FMemory::Memcpy(&Out, &raw, sizeof(float));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool ReadStringUtf8(const TArray<uint8>& Buf, int32& Pos, FString& Out)
|
|
||||||
{
|
|
||||||
uint16 Len = 0;
|
|
||||||
if (!ReadU16(Buf, Pos, Len)) return false;
|
|
||||||
if (Pos + Len > Buf.Num()) return false;
|
|
||||||
if (Len == 0) { Out.Reset(); return true; }
|
|
||||||
Out = FString(FUTF8ToTCHAR(reinterpret_cast<const ANSICHAR*>(Buf.GetData() + Pos), Len));
|
|
||||||
Pos += Len;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool ReadUuid16(const TArray<uint8>& Buf, int32& Pos, FString& Out)
|
|
||||||
{
|
|
||||||
if (Pos + 16 > Buf.Num()) return false;
|
|
||||||
// 16 bytes raw -> 8-4-4-4-12
|
|
||||||
auto Hex = [](uint8 b, ANSICHAR* dst)
|
|
||||||
{
|
|
||||||
static const ANSICHAR* H = "0123456789abcdef";
|
|
||||||
dst[0] = H[(b >> 4) & 0xF];
|
|
||||||
dst[1] = H[b & 0xF];
|
|
||||||
};
|
|
||||||
ANSICHAR raw[37]; raw[36] = 0;
|
|
||||||
int32 j = 0;
|
|
||||||
for (int32 i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
if (i == 4 || i == 6 || i == 8 || i == 10) raw[j++] = '-';
|
|
||||||
Hex(Buf[Pos + i], &raw[j]); j += 2;
|
|
||||||
}
|
|
||||||
Out = ANSI_TO_TCHAR(raw);
|
|
||||||
Pos += 16;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool WriteUuid16(TArray<uint8>& Buf, const FString& Uuid)
|
|
||||||
{
|
|
||||||
// Espera xxxxxxxx-xxxx-...
|
|
||||||
FString Hex = Uuid.Replace(TEXT("-"), TEXT(""));
|
|
||||||
if (Hex.Len() != 32) return false;
|
|
||||||
for (int32 i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
TCHAR hi = Hex[i * 2];
|
|
||||||
TCHAR lo = Hex[i * 2 + 1];
|
|
||||||
auto HexVal = [](TCHAR c) -> int32 {
|
|
||||||
if (c >= TEXT('0') && c <= TEXT('9')) return c - TEXT('0');
|
|
||||||
if (c >= TEXT('a') && c <= TEXT('f')) return c - TEXT('a') + 10;
|
|
||||||
if (c >= TEXT('A') && c <= TEXT('F')) return c - TEXT('A') + 10;
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
int32 H = HexVal(hi);
|
|
||||||
int32 L = HexVal(lo);
|
|
||||||
if (H < 0 || L < 0) return false;
|
|
||||||
Buf.Add(static_cast<uint8>((H << 4) | L));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UUIUserLobbyScreen_Base::NativeOnActivated()
|
void UUIUserLobbyScreen_Base::NativeOnActivated()
|
||||||
{
|
{
|
||||||
|
|||||||
136
Source/ZMMO/Game/UI/FrontEnd/WireHelpers.h
Normal file
136
Source/ZMMO/Game/UI/FrontEnd/WireHelpers.h
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Helpers de leitura/escrita binarios LE (UTF-8) compartilhados pelas telas
|
||||||
|
// do FrontEnd (Boot/Login/ServerSelect/Lobby/CharCreate). Funcoes `inline`
|
||||||
|
// pra evitar ODR violation quando dois .cpp caem no mesmo unity build do
|
||||||
|
// UBT — definicoes em anonymous namespace cada um colidiam apos a
|
||||||
|
// reorganizacao automatica de unities.
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
|
||||||
|
namespace ZMMOWire
|
||||||
|
{
|
||||||
|
inline bool ReadU8(const TArray<uint8>& Buf, int32& Pos, uint8& Out)
|
||||||
|
{
|
||||||
|
if (Pos + 1 > Buf.Num()) return false;
|
||||||
|
Out = Buf[Pos];
|
||||||
|
Pos += 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ReadU16(const TArray<uint8>& Buf, int32& Pos, uint16& Out)
|
||||||
|
{
|
||||||
|
if (Pos + 2 > Buf.Num()) return false;
|
||||||
|
Out = static_cast<uint16>(Buf[Pos]) | (static_cast<uint16>(Buf[Pos + 1]) << 8);
|
||||||
|
Pos += 2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ReadU32(const TArray<uint8>& Buf, int32& Pos, uint32& Out)
|
||||||
|
{
|
||||||
|
if (Pos + 4 > Buf.Num()) return false;
|
||||||
|
Out = static_cast<uint32>(Buf[Pos])
|
||||||
|
| (static_cast<uint32>(Buf[Pos + 1]) << 8)
|
||||||
|
| (static_cast<uint32>(Buf[Pos + 2]) << 16)
|
||||||
|
| (static_cast<uint32>(Buf[Pos + 3]) << 24);
|
||||||
|
Pos += 4;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ReadU64(const TArray<uint8>& Buf, int32& Pos, uint64& Out)
|
||||||
|
{
|
||||||
|
if (Pos + 8 > Buf.Num()) return false;
|
||||||
|
Out = 0;
|
||||||
|
for (int32 i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
Out |= (static_cast<uint64>(Buf[Pos + i]) << (8 * i));
|
||||||
|
}
|
||||||
|
Pos += 8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ReadFloat(const TArray<uint8>& Buf, int32& Pos, float& Out)
|
||||||
|
{
|
||||||
|
uint32 Raw = 0;
|
||||||
|
if (!ReadU32(Buf, Pos, Raw)) return false;
|
||||||
|
FMemory::Memcpy(&Out, &Raw, sizeof(float));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ReadStringUtf8(const TArray<uint8>& Buf, int32& Pos, FString& Out)
|
||||||
|
{
|
||||||
|
uint16 Len = 0;
|
||||||
|
if (!ReadU16(Buf, Pos, Len)) return false;
|
||||||
|
if (Pos + Len > Buf.Num()) return false;
|
||||||
|
if (Len == 0) { Out.Reset(); return true; }
|
||||||
|
Out = FString(FUTF8ToTCHAR(reinterpret_cast<const ANSICHAR*>(Buf.GetData() + Pos), Len));
|
||||||
|
Pos += Len;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Le 16 bytes raw e devolve UUID canonico "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx". */
|
||||||
|
inline bool ReadUuid16(const TArray<uint8>& Buf, int32& Pos, FString& Out)
|
||||||
|
{
|
||||||
|
if (Pos + 16 > Buf.Num()) return false;
|
||||||
|
auto HexNibble = [](uint8 B, ANSICHAR* Dst)
|
||||||
|
{
|
||||||
|
static const ANSICHAR* H = "0123456789abcdef";
|
||||||
|
Dst[0] = H[(B >> 4) & 0xF];
|
||||||
|
Dst[1] = H[B & 0xF];
|
||||||
|
};
|
||||||
|
ANSICHAR Raw[37]; Raw[36] = 0;
|
||||||
|
int32 J = 0;
|
||||||
|
for (int32 I = 0; I < 16; ++I)
|
||||||
|
{
|
||||||
|
if (I == 4 || I == 6 || I == 8 || I == 10) Raw[J++] = '-';
|
||||||
|
HexNibble(Buf[Pos + I], &Raw[J]);
|
||||||
|
J += 2;
|
||||||
|
}
|
||||||
|
Out = ANSI_TO_TCHAR(Raw);
|
||||||
|
Pos += 16;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void WriteUInt8(TArray<uint8>& Buf, uint8 V) { Buf.Add(V); }
|
||||||
|
|
||||||
|
inline void WriteUInt16(TArray<uint8>& Buf, uint16 V)
|
||||||
|
{
|
||||||
|
Buf.Add(static_cast<uint8>(V & 0xFF));
|
||||||
|
Buf.Add(static_cast<uint8>((V >> 8) & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void WriteUInt32(TArray<uint8>& Buf, uint32 V)
|
||||||
|
{
|
||||||
|
for (int32 I = 0; I < 4; ++I) Buf.Add(static_cast<uint8>((V >> (8 * I)) & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void WriteStringUtf8(TArray<uint8>& Buf, const FString& S)
|
||||||
|
{
|
||||||
|
FTCHARToUTF8 Conv(*S);
|
||||||
|
const int32 Len = Conv.Length();
|
||||||
|
WriteUInt16(Buf, static_cast<uint16>(Len));
|
||||||
|
Buf.Append(reinterpret_cast<const uint8*>(Conv.Get()), Len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Aceita UUID canonico (com hifens) e escreve 16 bytes binarios. */
|
||||||
|
inline bool WriteUuid16(TArray<uint8>& Buf, const FString& Uuid)
|
||||||
|
{
|
||||||
|
FString Hex = Uuid.Replace(TEXT("-"), TEXT(""));
|
||||||
|
if (Hex.Len() != 32) return false;
|
||||||
|
auto HexVal = [](TCHAR C) -> int32
|
||||||
|
{
|
||||||
|
if (C >= TEXT('0') && C <= TEXT('9')) return C - TEXT('0');
|
||||||
|
if (C >= TEXT('a') && C <= TEXT('f')) return C - TEXT('a') + 10;
|
||||||
|
if (C >= TEXT('A') && C <= TEXT('F')) return C - TEXT('A') + 10;
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
for (int32 I = 0; I < 16; ++I)
|
||||||
|
{
|
||||||
|
const int32 H = HexVal(Hex[I * 2]);
|
||||||
|
const int32 L = HexVal(Hex[I * 2 + 1]);
|
||||||
|
if (H < 0 || L < 0) return false;
|
||||||
|
Buf.Add(static_cast<uint8>((H << 4) | L));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user