New Parser Completed. Verification next.

This commit is contained in:
Norman Lansing
2026-03-10 22:38:12 -04:00
parent 5bfc79cbda
commit 04f5cb37dc
12 changed files with 639 additions and 356 deletions

View File

@@ -1,68 +1,22 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Game/ShooterGameMode.h"
#include "Logging/LogMacros.h"
#include "Logging/StructuredLog.h"
#if WITH_GAMELIFT
#include "GameLiftServerSDK.h"
#endif
#include "GameLiftClpTypes.h"
#include "GameLift/GameLiftClp.h"
DEFINE_LOG_CATEGORY(LogShooterGameMode)
namespace GameLiftValidators {
const FRegexPattern FleetIdPattern(TEXT("^[a-z]*fleet-[a-zA-Z0-9\\-]+$"));
const int32 FleetIdLengthMin = 1;
const int32 FleetIdLengthMax = 128;
const FString ServerRegionPattern(TEXT("^[a-z]{2}-[a-z]+-[0-9]$"));
const int32 ServerRegionLengthMin = 3;
const int32 ServerRegionLengthMax = 16;
const FString WebSocketUrlPattern(TEXT("^(ws|wss):\\/\\/([0-9a-zA-Z.-]+)(:([1-9][0-9]{0,4}))?(\\/.*)?$"));
const int32 WebSocketUrlLengthMin = 1;
const int32 WebSocketUrlLengthMax = 128;
const FString AuthTokenPattern(TEXT("^[A-Za-z0-9+/=]+$"));
const int32 AuthTokenLengthMin = 20;
const int32 AuthTokenLengthMax = 2048;
const FString HostIdPattern(TEXT("^[a-z]*host-[a-zA-Z0-9\\-]+$"));
const int32 HostIdLengthMin = 1;
const int32 HostIdLengthMax = 128;
const int32 ServerPortMin = 1026;
const int32 ServerPortMax = 60000;
const int32 WebSocketPortMin = 1;
const int32 WebSocketPortMax = 60000;
bool IsStringValid(const FString& Value, const FRegexPattern* OptionalPattern, const int32 Min, const int32 Max)
{
if (Value.IsEmpty()) return false;
if (OptionalPattern)
{
return FRegexMatcher(*OptionalPattern, Value).FindNext() &&
Value.Len() >= Min &&
Value.Len() <= Max;
}
else
{
return Value.Len() >= Min && Value.Len() <= Max;
}
}
bool IsNumberValid(const int32 Value, const int32 Min, const int32 Max)
{
return Value >= Min && Value <= Max;
}
}
DEFINE_LOG_CATEGORY(LogShooterGameMode);
// Function implementations.
AShooterGameMode::AShooterGameMode()
{
UE_LOG(LogShooterGameMode, Log, TEXT("Initializing ShooterGameMode..."));
}
void AShooterGameMode::BeginPlay()
{
Super::BeginPlay();
#if WITH_GAMELIFT
InitGameLift();
#endif
@@ -71,248 +25,114 @@ void AShooterGameMode::BeginPlay()
void AShooterGameMode::InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage)
{
Super::InitGame(MapName, Options, ErrorMessage);
UE_LOG(LogShooterGameMode, Log, TEXT("[%s] Parsing CLI"), *FDateTime::UtcNow().ToString(TEXT("%Y%m%d-%H%M%S")));
CachedCommandLine = FCommandLine::Get();
// Parsing of Command Line
GameLiftConfig.bDebugMode = FParse::Param(*CachedCommandLine, TEXT("Debug"));
if (GameLiftConfig.bDebugMode)
GameLiftConfig.ServerPort = cmdlineparser::details::GetConfiguredOrDefaultPort(CachedCommandLine, "port");
if (FParse::Param(*CachedCommandLine, TEXT("-glAnywhereFleet")))
{
UE_LOG(LogShooterGameMode, Log, TEXT("Debug mode: ENABLED"));
#if UE_BUILD_DEBUG
UE_LOG(LogShooterGameMode, Log, TEXT("Command Line Arguments: %s"), *CachedCommandLine);
#endif
GameLiftConfig.bIsAnywhereFleet = true;
}
else
{
GameLiftConfig.bIsAnywhereFleet = false;
}
GameLiftConfig.ServerPort = GetConfiguredOrDefaultPort();
GameLiftConfig.bIsAnywhereFleet = FParse::Param(*CachedCommandLine, TEXT("glAnywhere"));
if (GameLiftConfig.bIsAnywhereFleet)
{
UE_LOGFMT(LogShooterGameMode, Log, "GameLift Anywhere Fleet Command Line Parsing");
UE_LOGFMT(LogShooterGameMode, Log, "======Command Line Parameters======");
UE_LOGFMT(LogShooterGameMode, Log, "===================================");
GetAnywhereFleetParameters(CachedCommandLine);
LogAnywhereFleetParameters();
}
else
{
}
}
void AShooterGameMode::InitGame_original(const FString& MapName, const FString& Options, FString& ErrorMessage)
FString AShooterGameMode::GetSHA256Hash(const FString& InString)
{
Super::InitGame(MapName, Options, ErrorMessage);
UE_LOG(LogShooterGameMode, Log, TEXT("[%s] Parsing CLI"), *FDateTime::UtcNow().ToString(TEXT("%Y%m%d-%H%M%S")));
CachedCommandLine = FCommandLine::Get();
bool bIsCriticalError = false;
if (bDebugMode)
{
UE_LOG(LogShooterGameMode, Log, TEXT("Debug mode: ENABLED"));
#if UE_BUILD_DEBUG
UE_LOG(LogShooterGameMode, Log, TEXT("Command Line Arguments: %s"), *CachedCommandLine);
#endif
}
ServerPort = GetConfiguredOrDefaultPort();
bIsAnywhereFleet = FParse::Param(*CachedCommandLine, TEXT("glAnywhere"));
if (bIsAnywhereFleet)
{
UE_LOG(LogShooterGameMode, Log, TEXT("GameLift Anywhere Fleet Command Line Parsing"));
UE_LOG(LogShooterGameMode, Log, TEXT("======Command Line Parameters======"));
if (!FParse::Value(*CachedCommandLine, TEXT("fleetID="), FleetId))
{
UE_LOG(LogShooterGameMode, Error, TEXT("FleetId Missing in Command Line"));
bIsCriticalError = true;
}
else
{
UE_LOG(LogShooterGameMode, Log, TEXT("Fleet ID: %s"), *FleetId);
}
if (!FParse::Value(*CachedCommandLine, TEXT("authtoken="), AuthToken))
{
UE_LOG(LogShooterGameMode, Error, TEXT("AuthToken Missing in Command Line"));
bIsCriticalError = true;
}
else
{
if (bDebugMode)
{
FString TokenHash = GetSHA256Hash(AuthToken);
UE_LOG(LogShooterGameMode, Log, TEXT("AuthToken: %s"), *TokenHash);
}
else
{
UE_LOG(LogShooterGameMode, Log, TEXT("AuthToken Length: %d"), AuthToken.Len());
}
}
if (!FParse::Value(*CachedCommandLine, TEXT("hostId="), HostId))
{
UE_LOG(LogShooterGameMode, Error, TEXT("HostId Missing in Command Line"));
bIsCriticalError = true;
}
else
{
UE_LOG(LogShooterGameMode, Log, TEXT("Host ID: %s"), *HostId);
}
if (!FParse::Value(*CachedCommandLine, TEXT("websocketUrl="), WebSocketUrl))
{
UE_LOG(LogShooterGameMode, Error, TEXT("WebSocketUrl Missing in Command Line"));
bIsCriticalError = true;
}
else
{
UE_LOG(LogShooterGameMode, Log, TEXT("Websocket URL: %s"), *WebSocketUrl);
bool bValidWebSocket = WebSocketUrl.StartsWith(TEXT("wss://")) || WebSocketUrl.StartsWith(TEXT("ws://"));
if (InString.IsEmpty()) return TEXT("da39a3ee5e6b4b0d3255bfef95601890afd80709");
if (bValidWebSocket)
{
int32 ColonPos = WebSocketUrl.Find(TEXT(":"), ESearchCase::CaseSensitive);
int32 SlashPos = WebSocketUrl.Find(TEXT("/"), ESearchCase::CaseSensitive, ESearchDir::FromStart, ColonPos + 1);
FSHA1 Sha;
FTCHARToUTF8 Utf8(InString);
Sha.Update((uint8*)Utf8.Get(), Utf8.Length() * sizeof(UTF8CHAR));
Sha.Final();
uint8 Hash[FSHA1::DigestSize];
Sha.GetHash(Hash);
int32 ParsedPort = 443; // Default wss
if (WebSocketUrl.StartsWith(TEXT("ws://"))) ParsedPort = 80;
if (ColonPos != INDEX_NONE && SlashPos != INDEX_NONE)
{
FString PortStr = WebSocketUrl.Mid(ColonPos + 1, SlashPos - ColonPos - 1);
int32 ExplicitPort = FCString::Atoi(*PortStr);
if (ExplicitPort > 1024 && ExplicitPort <= 65535) // Privileged ports OK for servers
{
ParsedPort = ExplicitPort;
}
else
{
bValidWebSocket = false; // Invalid explicit port
}
}
UE_LOG(LogShooterGameMode, Log, TEXT("WebSocket Parsed Port: %d"), ParsedPort);
}
// 40-char hex (SHA1 = 160 bits)
return FString::Printf(TEXT("%08X%08X%08X%08X%08X"),
Hash[0], Hash[1], Hash[2], Hash[3], Hash[4]);
if (!bValidWebSocket)
{
UE_LOG(LogShooterGameMode, Error, TEXT("Invalid WebSocketUrl: %s"), *WebSocketUrl);
bIsCriticalError = true;
}
}
if (ServerPort == 0)
{
UE_LOG(LogShooterGameMode, Error, TEXT("Invalid or Missing Server Port Number. Shutting Down."));
bIsCriticalError = true;
}
else
{
UE_LOG(LogShooterGameMode, Log, TEXT("Port: %d"), ServerPort);
}
if (!FParse::Value(*CachedCommandLine, TEXT("serverRegion="), ServerRegion))
{
UE_LOG(LogShooterGameMode, Warning, TEXT("ServerRegion Missing in Command Line"));
}
else
{
UE_LOG(LogShooterGameMode, Log, TEXT(">>>Server Region: %s"), *ServerRegion);
}
UE_LOG(LogShooterGameMode, Log, TEXT("==================================="));
}
else
{
UE_LOG(LogShooterGameMode, Log, TEXT("GameLift EC2 Fleet"));
if (ServerPort == 0)
{
UE_LOG(LogShooterGameMode, Error, TEXT("Invalid or Missing Server Port Number. Shutting Down."));
bIsCriticalError = true;
}
else
{
UE_LOG(LogShooterGameMode, Log, TEXT("Port: %d"), ServerPort);
}
}
if (bIsCriticalError)
{
UE_LOG(LogShooterGameMode, Error, TEXT("Critical Missing or Invalid Arguments in Command Line. Shutting Down."));
FPlatformMisc::RequestExit(true);
}
else
{
UE_LOG(LogShooterGameMode, Log, TEXT("Command Line Parsed Successfully."));
}
}
int32 AShooterGameMode::GetConfiguredOrDefaultPort() const
{
// Default Unreal Engine listen/dedicated server port
constexpr int32 DefaultPort = 7777;
int32 CmdPort = DefaultPort;
// Check if a port was passed via command line: -port=xxxx
if (FParse::Value(*CachedCommandLine, TEXT("port="), CmdPort) &&
GameLiftValidators::IsNumberValid(CmdPort, GameLiftValidators::ServerPortMin, GameLiftValidators::ServerPortMax))
{
return CmdPort;
}
UE_LOGFMT(LogShooterGameMode, Warning, "Invalid/Missing port in command line - using {0}", DefaultPort);
return DefaultPort;
}
FString AShooterGameMode::GetSHA256Hash(const FString& Input)
{
FTCHARToUTF8 Utf8Input(Input);
FSHA256Signature Hash;
if (FPlatformMisc::GetSHA256Signature(reinterpret_cast<const uint8*>(Utf8Input.Get()), Utf8Input.Length(), Hash))
{
return Hash.ToString();
}
return FString::Printf(TEXT("Fail_%dbytes"), Input.Len());
}
bool AShooterGameMode::ParseAndOutputResult(const FString& InString, FString& OutValue, bool bRequired)
{
// Returns True if it is a critical error, returns false
if (!FParse::Value(*InString, TEXT("hostId="), HostId))
{
UE_LOG(LogShooterGameMode, Error, TEXT("HostId Missing in Command Line"));
return bRequired;
}
else
{
UE_LOG(LogShooterGameMode, Log, TEXT("Host ID: %s"), *HostId);
return false;
}
}
bool AShooterGameMode::ValidateFleetId(const FString& InFleetId)
{
// FRegexMatcher Matcher(FleetIdPattern, InFleetId);
// return Matcher.IsMatch() &&
// InFleetId.Len() >= 10 &&
// InFleetId.Len() < 128;
return false;
}
void AShooterGameMode::InitGameLift()
{
#if WITH_GAMELIFT
//TODO: Need to write later, working on parser first.
#else
UE_LOGFMT(LogShooterGameMode, Warning, "GameLift disabled");
#endif
GetAnywhereFleetParameters(CachedCommandLine);
}
bool AShooterGameMode::GetAnywhereFleetParameters(FString CommandLineString)
{
bool bAllAnywhereFleetParametersValid = true;
cmdlineparser::details::FParseResult AuthResult = cmdlineparser::GetValueOfToken(CommandLineString, cmdlineparser::details::EAvailableTokens::AuthToken);
if (AuthResult.bIsValid)
{
GameLiftConfig.AuthToken = AuthResult.Value;
#if UE_BUILD_DEBUG
UE_LOGFMT(LogShooterGameMode, Log, "AuthToken loaded: {0}", GameLiftConfig.AuthToken);
#else
UE_LOGFMT(LogShooterGameMode, Log, "AuthToken loaded: HASH - {0}", GetSHA256Hash(GameLiftConfig.AuthToken));
#endif
}
else
{
bAllAnywhereFleetParametersValid = false;
#if UE_BUILD_DEBUG
UE_LOGFMT(LogShooterGameMode, Error, "AuthToken Invalid: {0}", GameLiftConfig.AuthToken);
#else
UE_LOGFMT(LogShooterGameMode, Error, "AuthToken Invalid: HASH - {0}", GetSHA256Hash(GameLiftConfig.AuthToken));
#endif
}
cmdlineparser::details::FParseResult HostIdResult = cmdlineparser::GetValueOfToken(CommandLineString, cmdlineparser::details::EAvailableTokens::HostId);
if (HostIdResult.bIsValid)
{
GameLiftConfig.HostId = HostIdResult.Value;
UE_LOGFMT(LogShooterGameMode, Log, "HostId loaded: {0}", GameLiftConfig.HostId);
}
else
{
bAllAnywhereFleetParametersValid = false;
UE_LOGFMT(LogShooterGameMode, Error, "HostId Invalid: {0}", HostIdResult.Value);
}
cmdlineparser::details::FParseResult FleetIdResult = cmdlineparser::GetValueOfToken(CommandLineString, cmdlineparser::details::EAvailableTokens::FleetId);
if (FleetIdResult.bIsValid)
{
GameLiftConfig.FleetId = FleetIdResult.Value;
UE_LOGFMT(LogShooterGameMode, Log, "FleetId loaded: {0}", FleetIdResult.Value);
}
else
{
bAllAnywhereFleetParametersValid = false;
UE_LOGFMT(LogShooterGameMode, Error, "FleetId Invalid: {0}", GameLiftConfig.HostId);
}
cmdlineparser::details::FParseResult WebSocketUrlResult = cmdlineparser::GetValueOfToken(CommandLineString, cmdlineparser::details::EAvailableTokens::WebsocketUrl);
if (WebSocketUrlResult.bIsValid)
{
GameLiftConfig.WebSocketUrl = WebSocketUrlResult.Value;
UE_LOGFMT(LogShooterGameMode, Log, "WebSocketUrl loaded: {0}", WebSocketUrlResult.Value);
}
else
{
bAllAnywhereFleetParametersValid = false;
UE_LOGFMT(LogShooterGameMode, Error, "WebSocketUrl Invalid: {0}", WebSocketUrlResult.Value);
}
return bAllAnywhereFleetParametersValid;
}
void AShooterGameMode::LogAnywhereFleetParameters()
{
UE_LOGFMT(LogShooterGameMode, Log, "Anywhere Fleet Parameters:");
UE_LOGFMT(LogShooterGameMode, Log, "AuthToken: {0}", GameLiftConfig.AuthToken);
UE_LOGFMT(LogShooterGameMode, Log, "FleetId: {0}", GameLiftConfig.FleetId);
UE_LOGFMT(LogShooterGameMode, Log, "HostId: {0}", GameLiftConfig.HostId);
UE_LOGFMT(LogShooterGameMode, Log, "WebsocketUrl: {0}", GameLiftConfig.WebSocketUrl);
UE_LOGFMT(LogShooterGameMode, Log, "Server Port: {0}", GameLiftConfig.ServerPort);
}