WIP: Boostrapping NetSlime
- Just a old name for a set of changes to make the game framework hardened for multiplayer as well as some ease of use functionality.
This commit is contained in:
		| @@ -1,2 +1,67 @@ | ||||
| #include "GasaNetLibrary.h" | ||||
| #include "GasaNetLibrary_Inlines.h" | ||||
|  | ||||
| DEFINE_LOG_CATEGORY(LogGasaNet); | ||||
|  | ||||
| void NetLog( UObject const* Context, FString Message, EGasaVerbosity Verbosity = EGasaVerbosity::Log | ||||
| 		, FLogCategoryBase& Category  = LogGasaNet | ||||
| 		, bool              DumpStack = false | ||||
| 		, int32             Line      = __builtin_LINE() | ||||
| 		, const ANSICHAR*   File      = __builtin_FILE() | ||||
| 		, const ANSICHAR*   Func      = __builtin_FUNCTION() ) | ||||
| { | ||||
| #if !UE_BUILD_SHIPPING && !NO_LOGGING | ||||
| 	ELogVerbosity::Type EngineVerbosity = (ELogVerbosity::Type) Verbosity; | ||||
| 	if ((EngineVerbosity & ELogVerbosity::VerbosityMask) > ELogVerbosity::COMPILED_IN_MINIMUM_VERBOSITY) | ||||
| 		return; | ||||
| 	if ((EngineVerbosity & ELogVerbosity::VerbosityMask) > Category.GetVerbosity()) | ||||
| 		return; | ||||
| 	if ( Category.IsSuppressed(EngineVerbosity)) | ||||
| 		return; | ||||
|  | ||||
| 	AActor const* Actor = nullptr; | ||||
| 	FString       ActorLevel; | ||||
| 	{ | ||||
| 		if (Context != nullptr) | ||||
| 		{ | ||||
| 			if (Context->GetClass()->IsChildOf(AActor::StaticClass())) | ||||
| 				Actor = Cast<AActor>(Context); | ||||
| 			else if (Context->GetClass()->IsChildOf(UActorComponent::StaticClass())) | ||||
| 				Actor = Cast<UActorComponent>(Context)->GetOwner(); | ||||
| 			// Its assumed that all GasaObjects have an outer actor | ||||
| 			else if (Context->IsA(UGasaObject::StaticClass())) | ||||
| 				Actor = Cast<AActor>(Context->GetOuter()); | ||||
| 		} | ||||
| 		if (Actor) | ||||
| 		{ | ||||
| 			if (Actor->HasLocalNetOwner()) | ||||
| 				ActorLevel = TEXT("Net Owner"); | ||||
| 			 | ||||
| 			else if (Actor->HasAuthority()) | ||||
| 				ActorLevel = TEXT("Server Authorized"); | ||||
| 				 | ||||
| 			else | ||||
| 				ActorLevel = TEXT("No Authority"); | ||||
| 		} | ||||
| 		else | ||||
| 			ActorLevel = TEXT("Local"); | ||||
| 	} | ||||
|  | ||||
| 	FString NetMode = FString::Printf(TEXT("%-16s"), * GetNetworkModeStr(Context)); | ||||
| 	ActorLevel      = FString::Printf(TEXT("%-18s"), * ActorLevel); | ||||
| 	FString Name    = FString::Printf(TEXT("%-40s"), * Context->GetName()); | ||||
| 	FString FullMsg = NetMode + " " + ActorLevel + " " + Name + " : " + Message; | ||||
| 	 | ||||
| 	static UE::Logging::Private::FStaticBasicLogDynamicData LOG_Dynamic; | ||||
| 	static UE::Logging::Private::FStaticBasicLogRecord | ||||
| 	LOG_Static(TEXT("%s -- %hs %hs(%d)"), File, Line, EngineVerbosity, LOG_Dynamic); | ||||
|  | ||||
| 	SET_WARN_COLOR(COLOR_PURPLE) | ||||
| 	 | ||||
| 	if (DumpStack) | ||||
| 		FDebug::DumpStackTraceToLog(EngineVerbosity); | ||||
| 	BasicLog(Category, &LOG_Static, * FullMsg, File, Func, Line); | ||||
| 	 | ||||
| 	CLEAR_WARN_COLOR() | ||||
| #endif | ||||
| } | ||||
| @@ -1,4 +1,22 @@ | ||||
| #pragma once | ||||
| // NetSlime: Ol'Reliable | ||||
| #pragma once | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
|  | ||||
| #define DOREPLIFETIME_DEFAULT_GAS(Class, ReplicatedVar) \ | ||||
| 	DOREPLIFETIME_CONDITION_NOTIFY(Class, ReplicatedVar, COND_None, REPNOTIFY_Always) | ||||
|  | ||||
| DECLARE_LOG_CATEGORY_EXTERN(LogGasaNet, Log, All); | ||||
|  | ||||
| UENUM(BlueprintType) | ||||
| enum class ENetworkMode : uint8 | ||||
| { | ||||
| 	Standalone, | ||||
| 	DedicatedServer, | ||||
| 	ListenServer, | ||||
| 	Client, | ||||
| 	MAX, | ||||
| }; | ||||
|  | ||||
| namespace Gasa | ||||
| { | ||||
| @@ -12,6 +30,32 @@ namespace Gasa | ||||
| 	constexpr float NetCullDist_VeryFar   = 10000.0f * 10000.0f; | ||||
| 	constexpr float NetCullDist_VisualMax = 15000.0f * 15000.0f; | ||||
|  | ||||
| 	#define DOREPLIFETIME_DEFAULT_GAS(Class, ReplicatedVar) \ | ||||
| 		DOREPLIFETIME_CONDITION_NOTIFY(Class, ReplicatedVar, COND_None, REPNOTIFY_Always) | ||||
| 	void DrawNetCullingSphere(UObject const* Context, float Duration, float Thickness); | ||||
|  | ||||
| 	ENetworkMode GetNetworkMode(UObject const* Context); | ||||
| 	FString GetNetworkModeStr(UObject const* Context); | ||||
|  | ||||
| 	bool IsClient(UObject const* Context); | ||||
| 	bool IsListenServer(UObject const* Context); | ||||
|  | ||||
| 	bool IsNetOwner(UObject const* Context); | ||||
| 	bool IsNetOwner(UGasaObject const* Context); | ||||
| 	bool IsNetOwner(AActor const* Context); | ||||
|  | ||||
| 	bool IsServer(UObject const* Context); | ||||
| 	 | ||||
| 	bool IsSimulatedProxy(UObject const* Context); | ||||
| 	bool IsSimulatedProxy(UGasaObject const* Context); | ||||
| 	bool IsSimulatedProxy(AActor const* Context); | ||||
| 	 | ||||
| 	void NetLog( UObject const* Context, FString Message, EGasaVerbosity Verbosity = EGasaVerbosity::Log | ||||
| 		, FLogCategoryBase& Category  = LogGasaNet | ||||
| 		, bool              DumpStack = false | ||||
| 		, int32             Line      = __builtin_LINE() | ||||
| 		, const ANSICHAR*   File      = __builtin_FILE() | ||||
| 		, const ANSICHAR*   Func      = __builtin_FUNCTION() ); | ||||
| 	 | ||||
| 	bool ServerAuthorized(UObject const* Context); | ||||
| 	bool ServerAuthorized(UGasaObject const* Context); | ||||
| 	bool ServerAuthorized(AActor const* Context); | ||||
| } | ||||
|   | ||||
							
								
								
									
										278
									
								
								Project/Source/Gasa/Networking/GasaNetLibrary_Inlines.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								Project/Source/Gasa/Networking/GasaNetLibrary_Inlines.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,278 @@ | ||||
| #include "GasaNetLibrary.h" | ||||
| #include "GasaObject.h" | ||||
| #include "Engine/NetDriver.h" | ||||
| #include "Game/GasaGameMode.h" | ||||
| #include "Kismet/KismetMathLibrary.h" | ||||
| #include "Kismet/KismetSystemLibrary.h" | ||||
|  | ||||
| namespace Gasa | ||||
| { | ||||
| 	// TODO(Ed): Profile these... | ||||
|  | ||||
| 	inline | ||||
| 	void DrawNetCullingSphere(const UObject* Context, float Duration, float Thickness) | ||||
| 	{ | ||||
| 		const AActor* actor = nullptr; | ||||
| 	 | ||||
| 		if (Context->IsA(UGasaObject::StaticClass())) | ||||
| 			actor = Cast<AActor>(Context->GetOuter()); | ||||
| 		 | ||||
| 		else if (Context->IsA(AActor::StaticClass())) | ||||
| 			actor = Cast<AActor>(Context);	 | ||||
|  | ||||
| 		if (actor) | ||||
| 			UKismetSystemLibrary::DrawDebugSphere(actor | ||||
| 				, actor->GetActorLocation() | ||||
| 				, UKismetMathLibrary::Sqrt(actor->NetCullDistanceSquared) * 2 | ||||
| 				, 12 | ||||
| 				, FLinearColor(FColor::Emerald) | ||||
| 				, Duration | ||||
| 				, Thickness); | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	ENetworkMode GetNetworkMode(UObject const* Context) | ||||
| 	{ | ||||
| 		if (Context == nullptr) | ||||
| 		{ | ||||
| 			Log("Context is null...", ELogV::Error); | ||||
| 			return scast(ENetworkMode, ENetMode::NM_MAX); | ||||
| 		} | ||||
| 		UWorld* World = Context->GetWorld(); | ||||
| 		if (World == nullptr) { | ||||
| 			Log("World is null... are you running in a proper context?", ELogV::Error); | ||||
| 			return scast(ENetworkMode, ENetMode::NM_MAX); | ||||
| 		} | ||||
|  | ||||
| 		if (IsValid(World) == false) | ||||
| 			return ENetworkMode::Standalone; | ||||
| 		 | ||||
| 		ENetworkMode NetMode = scast(ENetworkMode, World->GetNetMode()); | ||||
| 		return NetMode; | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	FString GetNetworkModeStr(UObject const* Context) | ||||
| 	{ | ||||
| 		FString Str; | ||||
| 		if (Context == nullptr) | ||||
| 			return Str; | ||||
| 		switch (GetNetworkMode(Context)) | ||||
| 		{ | ||||
| 			case ENetworkMode::Standalone: | ||||
| 				Str = TEXT("Standalone"); | ||||
| 			break; | ||||
| 			case ENetworkMode::ListenServer: | ||||
| 				Str = TEXT("ListenServer"); | ||||
| 			break; | ||||
| 			case ENetworkMode::DedicatedServer: | ||||
| 				Str = TEXT("DedicatedServer"); | ||||
| 			break; | ||||
| 			case ENetworkMode::Client: | ||||
| 				Str = TEXT("Client"); | ||||
| 			break; | ||||
| 		} | ||||
| 		return Str; | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	bool IsClient(UObject const* Context) | ||||
| 	{ | ||||
| 		if (Context == nullptr || Context->GetWorld() == nullptr) | ||||
| 			return false; | ||||
| 		 | ||||
| 		UNetDriver* NetDriver = Context->GetWorld()->NetDriver; | ||||
| 		bool Result = NetDriver && ! NetDriver->IsServer(); | ||||
| 		return Result; | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	bool IsListenServer(UObject const* Context) | ||||
| 	{ | ||||
| 		if (Context == nullptr || Context->GetWorld() == nullptr) | ||||
| 			return false; | ||||
|  | ||||
| 		UNetDriver* NetDriver = Context->GetWorld()->NetDriver; | ||||
| 		bool Result = NetDriver && NetDriver->GetNetMode() == ENetMode::NM_ListenServer; | ||||
| 		return Result;	 | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	bool IsNetOwner(UObject const* Context) | ||||
| 	{ | ||||
| 		if (Context == nullptr || Context->GetWorld() == nullptr) | ||||
| 			return false; | ||||
|  | ||||
| 		AActor const* Actor = nullptr; | ||||
| 		 | ||||
| 		if (Context->IsA(AActor::StaticClass())) | ||||
| 			Actor = Cast<AActor>(Context); | ||||
| 		else if (Context->GetClass()->IsChildOf(UActorComponent::StaticClass())) | ||||
| 			Actor = Cast<UActorComponent>(Context)->GetOwner(); | ||||
| 		// Its assumed that all GasaObjects have an outer actor | ||||
| 		else if (Context->IsA(UGasaObject::StaticClass())) | ||||
| 			Actor = Cast<AActor>(Context->GetOuter()); | ||||
| 		else | ||||
| 		{ | ||||
| 			UObject const* Outermost = Context->GetOutermostObject(); | ||||
| 			if (Outermost->IsA(AActor::StaticClass())) | ||||
| 				Actor = Cast<AActor>(Outermost); | ||||
| 		} | ||||
|  | ||||
| 		if (Actor == nullptr) | ||||
| 		{ | ||||
| 			Log("Could not get actor reference", ELogV::Warning, LogGasaNet); | ||||
| 			return false; | ||||
| 		} | ||||
| 		bool Result = Actor->HasLocalNetOwner(); | ||||
| 		return Result; | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	bool IsNetOwner(UGasaObject const* Context) | ||||
| 	{ | ||||
| 		if (Context == nullptr || Context->GetWorld() == nullptr) | ||||
| 			return false; | ||||
|  | ||||
| 		AActor const* Actor = Cast<AActor>(Context->GetOuter()); | ||||
| 		if (Actor == nullptr) | ||||
| 		{ | ||||
| 			Log("Could not get actor reference", ELogV::Warning, LogGasaNet); | ||||
| 			return false; | ||||
| 		} | ||||
| 		bool Result = Actor->HasLocalNetOwner(); | ||||
| 		return Result;	 | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	bool IsNetOwner(AActor const* Actor) | ||||
| 	{ | ||||
| 		if (Actor == nullptr || Actor->GetWorld() == nullptr) | ||||
| 			return false; | ||||
| 		bool Result = Actor->HasLocalNetOwner(); | ||||
| 		return Result;		 | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	bool IsServer(UObject const* Context) | ||||
| 	{ | ||||
| 		if (Context == nullptr || Context->GetWorld() == nullptr) | ||||
| 			return false; | ||||
|  | ||||
| 		UNetDriver* NetDriver = Context->GetWorld()->NetDriver; | ||||
| 		bool Result = NetDriver && NetDriver->IsServer(); | ||||
| 		return Result; | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	bool IsSimulatedProxy(UObject const* Context) | ||||
| 	{ | ||||
| 		if (Context == nullptr || Context->GetWorld() == nullptr) | ||||
| 			return false; | ||||
|  | ||||
| 		AActor const* Actor = nullptr; | ||||
| 		 | ||||
| 		if (Context->IsA(AActor::StaticClass())) | ||||
| 			Actor = Cast<AActor>(Context); | ||||
| 		else if (Context->GetClass()->IsChildOf(UActorComponent::StaticClass())) | ||||
| 			Actor = Cast<UActorComponent>(Context)->GetOwner(); | ||||
| 		// Its assumed that all GasaObjects have an outer actor | ||||
| 		else if (Context->IsA(UGasaObject::StaticClass())) | ||||
| 			Actor = Cast<AActor>(Context->GetOuter()); | ||||
| 		else | ||||
| 		{ | ||||
| 			UObject const* Outermost = Context->GetOutermostObject(); | ||||
| 			if (Outermost->IsA(AActor::StaticClass())) | ||||
| 				Actor = Cast<AActor>(Outermost); | ||||
| 		} | ||||
|  | ||||
| 		if (Actor == nullptr) | ||||
| 		{ | ||||
| 			Log("Could not get actor reference", ELogV::Warning, LogGasaNet); | ||||
| 			return false; | ||||
| 		} | ||||
| 		bool Result = Actor->GetLocalRole() == ENetRole::ROLE_SimulatedProxy; | ||||
| 		return Result;	 | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	bool IsSimulatedProxy(UGasaObject const* Context) | ||||
| 	{ | ||||
| 		if (Context == nullptr || Context->GetWorld() == nullptr) | ||||
| 			return false; | ||||
|  | ||||
| 		AActor const* Actor = Cast<AActor>(Context->GetOuter()); | ||||
| 		if (Actor == nullptr) | ||||
| 		{ | ||||
| 			Log("Could not get actor reference", ELogV::Warning, LogGasaNet); | ||||
| 			return false; | ||||
| 		} | ||||
| 		bool Result = Actor->GetLocalRole() == ENetRole::ROLE_SimulatedProxy; | ||||
| 		return Result;	 | ||||
| 	} | ||||
| 	 | ||||
| 	inline | ||||
| 	bool IsSimulatedProxy(AActor const* Actor) | ||||
| 	{ | ||||
| 		if (Actor == nullptr || Actor->GetWorld() == nullptr) | ||||
| 			return false; | ||||
| 		bool Result = Actor->GetLocalRole() == ENetRole::ROLE_SimulatedProxy; | ||||
| 		return Result;	 | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	bool ServerAuthorized(UObject const* Context) | ||||
| 	{ | ||||
| 		if (Context == nullptr || Context->GetWorld() == nullptr) | ||||
| 			return false; | ||||
|  | ||||
| 		AActor const* Actor = nullptr; | ||||
|  | ||||
| 		if (Context->IsA(AActor::StaticClass())) | ||||
| 			Actor = Cast<AActor>(Context); | ||||
| 		else if (Context->GetClass()->IsChildOf(UActorComponent::StaticClass())) | ||||
| 			Actor = Cast<UActorComponent>(Context)->GetOwner(); | ||||
| 		// Its assumed that all GasaObjects have an outer actor | ||||
| 		else if (Context->IsA(UGasaObject::StaticClass())) | ||||
| 			Actor = Cast<AActor>(Context->GetOuter()); | ||||
| 		else | ||||
| 		{ | ||||
| 			UObject const* Outermost = Context->GetOutermostObject(); | ||||
| 			if (Outermost->IsA(AActor::StaticClass())) | ||||
| 				Actor = Cast<AActor>(Outermost); | ||||
| 		} | ||||
|  | ||||
| 		if (Actor == nullptr) | ||||
| 		{ | ||||
| 			Log("Could not get actor reference", ELogV::Warning, LogGasaNet); | ||||
| 			return false; | ||||
| 		} | ||||
| 		bool Result = Actor->HasAuthority(); | ||||
| 		return Result; | ||||
| 	} | ||||
| 	 | ||||
| 	inline | ||||
| 	bool ServerAuthorized(UGasaObject const* Context) | ||||
| 	{ | ||||
| 		if (Context == nullptr || Context->GetWorld() == nullptr) | ||||
| 			return false; | ||||
|  | ||||
| 		AActor const* Actor = Cast<AActor>(Context->GetOuter()); | ||||
| 		if (Actor == nullptr) | ||||
| 		{ | ||||
| 			Log("Could not get actor reference", ELogV::Warning, LogGasaNet); | ||||
| 			return false; | ||||
| 		} | ||||
| 		bool Result = Actor->HasAuthority(); | ||||
| 		return Result; | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	bool ServerAuthorized(AActor const* Actor) | ||||
| 	{ | ||||
| 		if (Actor == nullptr || Actor->GetWorld() == nullptr) | ||||
| 			return false; | ||||
| 		bool Result = Actor->HasAuthority(); | ||||
| 		return Result; | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user