322 lines
9.0 KiB
C++
322 lines
9.0 KiB
C++
// 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
|
|
|
|
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 ValidateString(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 ValidateNumber(const int32 Value, const int32 Min, const int32 Max)
|
|
{
|
|
return Value >= Min && Value <= Max;
|
|
}
|
|
}
|
|
|
|
AShooterGameMode::AShooterGameMode()
|
|
{
|
|
UE_LOG(LogShooterGameMode, Log, TEXT("Initializing ShooterGameMode..."));
|
|
}
|
|
|
|
void AShooterGameMode::BeginPlay()
|
|
{
|
|
Super::BeginPlay();
|
|
|
|
#if WITH_GAMELIFT
|
|
InitGameLift();
|
|
#endif
|
|
}
|
|
|
|
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
|
|
bDebugMode = FParse::Param(*CachedCommandLine, TEXT("Debug"));
|
|
GameLiftConfig.bDebugMode = FParse::Param(*CachedCommandLine, TEXT("Debug"));
|
|
|
|
if (GameLiftConfig.bDebugMode)
|
|
{
|
|
UE_LOG(LogShooterGameMode, Log, TEXT("Debug mode: ENABLED"));
|
|
#if UE_BUILD_DEBUG
|
|
UE_LOG(LogShooterGameMode, Log, TEXT("Command Line Arguments: %s"), *CachedCommandLine);
|
|
#endif
|
|
}
|
|
|
|
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, "===================================");
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void AShooterGameMode::InitGame_original(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();
|
|
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 (bValidWebSocket)
|
|
{
|
|
int32 ColonPos = WebSocketUrl.Find(TEXT(":"), ESearchCase::CaseSensitive);
|
|
int32 SlashPos = WebSocketUrl.Find(TEXT("/"), ESearchCase::CaseSensitive, ESearchDir::FromStart, ColonPos + 1);
|
|
|
|
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);
|
|
}
|
|
|
|
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
|
|
int32 Port = 7777;
|
|
|
|
// Check if a port was passed via command line: -port=xxxx
|
|
int32 CmdPort = 0;
|
|
if (FParse::Value(*CachedCommandLine, TEXT("port="), CmdPort))
|
|
{
|
|
if (CmdPort > 1024 && CmdPort <= 65535)
|
|
{
|
|
Port = CmdPort;
|
|
}
|
|
else
|
|
{
|
|
Port = 0;
|
|
}
|
|
}
|
|
return Port;
|
|
}
|
|
|
|
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
|
|
}
|
|
|