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:
		
							
								
								
									
										
											BIN
										
									
								
								Project/Binaries/Win64/UnrealEditor-Gasa.dll
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Project/Binaries/Win64/UnrealEditor-Gasa.dll
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Project/Binaries/Win64/UnrealEditor-GasaEditor.dll
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Project/Binaries/Win64/UnrealEditor-GasaEditor.dll
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -301,10 +301,6 @@ | ||||
| 			"Name": "VisualStudioSourceCodeAccess", | ||||
| 			"Enabled": true | ||||
| 		}, | ||||
| 		{ | ||||
| 			"Name": "GitSourceControl", | ||||
| 			"Enabled": true | ||||
| 		}, | ||||
| 		{ | ||||
| 			"Name": "SlateInsights", | ||||
| 			"Enabled": true | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8" ?> | ||||
| <Configuration xmlns="https://www.unrealengine.com/BuildConfiguration"> | ||||
| 	<bUsePCHFiles>false</bUsePCHFiles> | ||||
| 	 | ||||
| </Configuration> | ||||
|   | ||||
| @@ -8,34 +8,31 @@ | ||||
|  | ||||
| UGasaAttributeSet::UGasaAttributeSet() | ||||
| { | ||||
| 	InitHealth( 50.f ); | ||||
| 	InitHealth( 100.f ); | ||||
| 	InitMaxHealth( 100.f ); | ||||
| 	InitMana( 50.f ); | ||||
| 	InitMaxMana( 50.f ); | ||||
| } | ||||
| #pragma region Rep Notifies | ||||
|  | ||||
| #pragma region Rep Notifies | ||||
| void UGasaAttributeSet::Client_OnRep_Health( FGameplayAttributeData& PrevHealth ) | ||||
| { | ||||
| 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | ||||
| 	static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, Health ) ); | ||||
| 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), Health, PrevHealth ); | ||||
| } | ||||
|  | ||||
| void UGasaAttributeSet::Client_OnRep_MaxHealth( FGameplayAttributeData& PrevMaxHealth ) | ||||
| { | ||||
| 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | ||||
| 	static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, MaxHealth ) ); | ||||
| 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), MaxHealth, PrevMaxHealth ); | ||||
| } | ||||
|  | ||||
| void UGasaAttributeSet::Client_OnRep_Mana( FGameplayAttributeData& PrevMana ) | ||||
| { | ||||
| 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | ||||
| 	static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, Mana ) ); | ||||
| 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), Mana, PrevMana ); | ||||
| } | ||||
|  | ||||
| void UGasaAttributeSet::Client_OnRep_MaxMana( FGameplayAttributeData& PrevMaxMana ) | ||||
| { | ||||
| 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | ||||
| @@ -43,6 +40,7 @@ void UGasaAttributeSet::Client_OnRep_MaxMana( FGameplayAttributeData& PrevMaxMan | ||||
| 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), MaxMana, PrevMaxMana ); | ||||
| } | ||||
| #pragma endregion Rep Notifies | ||||
|  | ||||
| void UGasaAttributeSet::GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const | ||||
| { | ||||
| 	Super::GetLifetimeReplicatedProps( OutLifetimeProps ); | ||||
|   | ||||
| @@ -23,6 +23,7 @@ public: | ||||
|  | ||||
| 	UGasaAttributeSet(); | ||||
|  | ||||
|  | ||||
| 	UFUNCTION() | ||||
| 	void Client_OnRep_Health( FGameplayAttributeData& PrevHealth ); | ||||
| 	UFUNCTION() | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #include "GasaAttributeSet.h" | ||||
| #include "AbilitySystemComponent.h" | ||||
|  | ||||
| #pragma region Attribute Setters | ||||
| FORCEINLINE | ||||
| void UGasaAttributeSet::SetHealth( float NewVal ) | ||||
| { | ||||
| @@ -40,6 +41,7 @@ void UGasaAttributeSet::SetMaxMana( float NewVal ) | ||||
| 		AbilityComp->SetNumericAttributeBase( GetMaxManaAttribute(), NewVal ); | ||||
| 	}; | ||||
| } | ||||
| #pragma endregion Attribute Setters | ||||
|  | ||||
| namespace Gasa | ||||
| { | ||||
|   | ||||
| @@ -10,13 +10,13 @@ AGasaEffectActor::AGasaEffectActor() | ||||
| 	RootComponent = CreateDefaultSubobject<USceneComponent>("Root"); | ||||
| } | ||||
|  | ||||
| void AGasaEffectActor::ApplyEffectToTarget(AActor* Target, TSubclassOf<UGameplayEffect> EffectClass) | ||||
| void AGasaEffectActor::ApplyEffectToActor(AActor* Actor, TSubclassOf<UGameplayEffect> EffectClass) | ||||
| { | ||||
| 	UGasaAbilitySystemComp* AS = GetAbilitySystem(Target, true); | ||||
| 	UGasaAbilitySystemComp* AS = GetAbilitySystem(Actor, true); | ||||
|  | ||||
| 	FGameplayEffectContextHandle | ||||
| 	Context = AS->MakeEffectContext(); | ||||
| 	Context.AddSourceObject(Target); | ||||
| 	Context.AddSourceObject(Actor); | ||||
| 	 | ||||
| 	FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( EffectClass, 1.0f, Context ); | ||||
| 	AS->ApplyGameplayEffectSpecToSelf( * Spec.Data ); | ||||
|   | ||||
| @@ -1,19 +1,23 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Actors/GasaActor.h" | ||||
| #include "GameFramework/Actor.h" | ||||
|  | ||||
| #include "GasaEffectActor.generated.h" | ||||
|  | ||||
|  | ||||
| UCLASS() | ||||
| class GASA_API AGasaEffectActor : public AActor | ||||
| class GASA_API AGasaEffectActor : public AGasaActor | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
|  | ||||
| 	UPROPERTY(EditAnywhere, Category = "Applied Effects") | ||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects") | ||||
| 	TSoftClassPtr<UGameplayEffect> InstantEffectClass; | ||||
| 	 | ||||
| 	AGasaEffectActor(); | ||||
|  | ||||
| 	void ApplyEffectToTarget(AActor* Target, TSubclassOf<UGameplayEffect> EffectClass ); | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Gameplay Effects") | ||||
| 	void ApplyEffectToActor(AActor* Actor, TSubclassOf<UGameplayEffect> EffectClass ); | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #include "GasaAttributeSet.h" | ||||
| #include "GasaAttributeSet_Inlines.h" | ||||
| #include "Components/SphereComponent.h" | ||||
| #include "Components/StaticMeshComponent.h" | ||||
|  | ||||
|  | ||||
| AGasaEffectActorDemo::AGasaEffectActorDemo() | ||||
|   | ||||
| @@ -1,12 +1,14 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Actors/GasaActor.h" | ||||
| #include "GameFramework/Actor.h" | ||||
|  | ||||
| #include "GasaEffectActorDemo.generated.h" | ||||
|  | ||||
| // Old demonstration code used before part 37. | ||||
| UCLASS() | ||||
| class GASA_API AGasaEffectActorDemo : public AActor | ||||
| class GASA_API AGasaEffectActorDemo : public AGasaActor | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
|   | ||||
| @@ -1,10 +1,12 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "GasaActor.h" | ||||
| #include "GasaCommon.h" | ||||
| #include "GameFramework/Actor.h" | ||||
| #include "CameraMount.generated.h" | ||||
|  | ||||
| UCLASS(Blueprintable) | ||||
| class GASA_API ACameraMount : public AActor | ||||
| class GASA_API ACameraMount : public AGasaActor | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
|   | ||||
							
								
								
									
										0
									
								
								Project/Source/Gasa/Actors/GasaActor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								Project/Source/Gasa/Actors/GasaActor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										33
									
								
								Project/Source/Gasa/Actors/GasaActor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Project/Source/Gasa/Actors/GasaActor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| #pragma once | ||||
| #include "Networking/GasaNetLibrary.h" | ||||
| #include "GameFramework/Actor.h" | ||||
|  | ||||
| #include "GasaActor.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class GASA_API AGasaActor : public AActor | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| #pragma region NetSlime | ||||
| 	// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp | ||||
| 	FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); } | ||||
| 	FORCEINLINE bool IsClient()               const { return Gasa::IsClient( this ); } | ||||
| 	FORCEINLINE bool IsListenServer()         const { return Gasa::IsListenServer( this ); } | ||||
| 	FORCEINLINE bool IsNetOwner()             const { return Gasa::IsNetOwner( this ); } | ||||
| 	FORCEINLINE bool IsServer()               const { return Gasa::IsServer( this ); } | ||||
| 	FORCEINLINE bool IsSimulatedProxy()       const { return Gasa::IsSimulatedProxy( this ); } | ||||
| 	FORCEINLINE void NetLog( | ||||
| 	    FString           Message, | ||||
| 	    EGasaVerbosity    Verbosity = EGasaVerbosity::Log, | ||||
| 	    FLogCategoryBase& Category  = LogGasaNet, | ||||
| 	    bool              DumpStack = false, | ||||
| 	    int32             Line      = __builtin_LINE(), | ||||
| 	    ANSICHAR const*   File      = __builtin_FILE(), | ||||
| 	    ANSICHAR const*   Func      = __builtin_FUNCTION() | ||||
| 	) | ||||
| 	{ | ||||
| 		Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func ); | ||||
| 	} | ||||
| #pragma endregion NetSlime | ||||
| }; | ||||
| @@ -9,7 +9,10 @@ | ||||
|  | ||||
| #include "AbilitySystem/GasaAbilitySystemComponent.h" | ||||
| #include "AbilitySystem/GasaAttributeSet.h" | ||||
| #include "Components/SkeletalMeshComponent.h" | ||||
| #include "Engine/PostProcessVolume.h" | ||||
| #include "Game/GasaLevelScriptActor.h" | ||||
| #include "Materials/MaterialInstanceDynamic.h" | ||||
|  | ||||
| void AGasaCharacter::SetHighlight(EHighlight Desired) | ||||
| { | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Game/GasaPlayerState.h" | ||||
| #include "Networking/GasaNetLibrary.h" | ||||
|  | ||||
| #include "GasaCharacter.generated.h" | ||||
|  | ||||
| @@ -60,6 +61,28 @@ public: | ||||
|  | ||||
| 	FORCEINLINE AGasaPlayerState* GetGasaPlayerState() { return GetPlayerState<AGasaPlayerState>(); } | ||||
|  | ||||
| #pragma region NetSlime | ||||
| 	// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp | ||||
| 	FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); } | ||||
| 	FORCEINLINE bool IsClient()               const { return Gasa::IsClient( this ); } | ||||
| 	FORCEINLINE bool IsListenServer()         const { return Gasa::IsListenServer( this ); } | ||||
| 	FORCEINLINE bool IsNetOwner()             const { return Gasa::IsNetOwner( this ); } | ||||
| 	FORCEINLINE bool IsServer()               const { return Gasa::IsServer( this ); } | ||||
| 	FORCEINLINE bool IsSimulatedProxy()       const { return Gasa::IsSimulatedProxy( this ); } | ||||
| 	FORCEINLINE void NetLog( | ||||
| 	    FString           Message, | ||||
| 	    EGasaVerbosity    Verbosity = EGasaVerbosity::Log, | ||||
| 	    FLogCategoryBase& Category  = LogGasaNet, | ||||
| 	    bool              DumpStack = false, | ||||
| 	    int32             Line      = __builtin_LINE(), | ||||
| 	    ANSICHAR const*   File      = __builtin_FILE(), | ||||
| 	    ANSICHAR const*   Func      = __builtin_FUNCTION() | ||||
| 	) | ||||
| 	{ | ||||
| 		Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func ); | ||||
| 	} | ||||
| #pragma endregion NetSlime | ||||
| 	 | ||||
| #pragma region IAbilitySystem | ||||
| 	FORCEINLINE UAttributeSet*           GetAttributes()                            { return Attributes; } | ||||
| 	FORCEINLINE UAbilitySystemComponent* GetAbilitySystemComponent() const override { return AbilitySystem; } | ||||
|   | ||||
| @@ -25,11 +25,14 @@ void APlayerCharacter::PossessedBy(AController* NewController) | ||||
| 		AbilitySystem->InitAbilityActorInfo(PS, this); | ||||
| 	} | ||||
|  | ||||
| 	if (IsLocallyControlled()) | ||||
| 	{ | ||||
| 		AGasaPlayerController* PC   = GetController<AGasaPlayerController>(); | ||||
| 		AGasaHUD*              HUD  = PC->GetHUD<AGasaHUD>(); | ||||
| 		FWidgetControllerData  Data = { PC, PS, AbilitySystem, Attributes }; | ||||
| 		HUD->InitHostWidget(& Data); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // TODO(Ed): We need to setup Net Slime... | ||||
| void APlayerCharacter::OnRep_PlayerState() | ||||
|   | ||||
| @@ -1,5 +1,84 @@ | ||||
| #include "GasaGameInstance.h" | ||||
|  | ||||
| #include "Engine/NetDriver.h" | ||||
| #include "Engine/World.h" | ||||
| using namespace Gasa; | ||||
|  | ||||
| #pragma region GameFramework | ||||
| // TODO(Ed): Make a NetLog | ||||
|  | ||||
| void UGasaGameInstance::NotifyGameFrameworkClassReady(EGameFrameworkClassFlag ClassReady) | ||||
| { | ||||
| 	switch (ClassReady) | ||||
| 	{ | ||||
| 		case EGameFrameworkClassFlag::GameMode: | ||||
| 			GameFrameworkClassesState |= (uint32)EGameFrameworkClassFlag::GameMode; | ||||
| 			NetLog("Gameplay Framework class ready: Game State", ELogV::Log, LogGasaNet ); | ||||
| 		break; | ||||
| 		case EGameFrameworkClassFlag::GameState: | ||||
| 			GameFrameworkClassesState |= (uint32)EGameFrameworkClassFlag::GameState; | ||||
| 			NetLog("Gameplay Framework class ready: Game State", ELogV::Log, LogGasaNet ); | ||||
| 		break; | ||||
| 		case EGameFrameworkClassFlag::PlayerController: | ||||
| 			GameFrameworkClassesState |= (uint32)EGameFrameworkClassFlag::PlayerController; | ||||
| 			NetLog("Gameplay Framework class ready: Player Controller", ELogV::Log, LogGasaNet); | ||||
| 		break; | ||||
| 		case EGameFrameworkClassFlag::PlayerState: | ||||
| 			GameFrameworkClassesState |= (uint32)EGameFrameworkClassFlag::PlayerState; | ||||
| 			NetLog("Gameplay Framework class ready: Player State", ELogV::Log, LogGasaNet); | ||||
| 		break; | ||||
| 		case EGameFrameworkClassFlag::Levels: | ||||
| 			GameFrameworkClassesState |= (uint32)EGameFrameworkClassFlag::Levels; | ||||
| 			NetLog("Gameplay Framework class ready: Levels", ELogV::Log, LogGasaNet); | ||||
| 		break; | ||||
| 	} | ||||
| 	ProcessGameFrameworkState(); | ||||
| } | ||||
|  | ||||
| void UGasaGameInstance::ProcessGameFrameworkState() | ||||
| { | ||||
| 	switch (GameFrameworkState) | ||||
| 	{ | ||||
| 		case EGameFrameworkState::Uninitialized: | ||||
| 		{ | ||||
| 			uint32 InitializedFlags = | ||||
| 				(uint32)EGameFrameworkClassFlag::GameState        | | ||||
| 				(uint32)EGameFrameworkClassFlag::PlayerController | | ||||
| 				(uint32)EGameFrameworkClassFlag::PlayerState      | | ||||
| 				(uint32)EGameFrameworkClassFlag::Levels | ||||
| 			; | ||||
|  | ||||
| 			if (GetWorld()->NetDriver == nullptr || GetWorld()->NetDriver->IsServer()) | ||||
| 			{ | ||||
| 				InitializedFlags |= (uint32)EGameFrameworkClassFlag::GameMode; | ||||
| 			} | ||||
|  | ||||
| 			FString MsgGM = "GameMode        : " + FString::FromInt( Bitfield_IsSet( GameFrameworkClassesState, scast(uint32, EGameFrameworkClassFlag::GameMode )) ); | ||||
| 			FString MsgGS = "GameState       : " + FString::FromInt( Bitfield_IsSet( GameFrameworkClassesState, scast(uint32, EGameFrameworkClassFlag::GameState )) ); | ||||
| 			FString MsgPC = "PlayerController: " + FString::FromInt( Bitfield_IsSet( GameFrameworkClassesState, scast(uint32, EGameFrameworkClassFlag::PlayerController ) )); | ||||
| 			FString MsgPS = "PlayerState     : " + FString::FromInt( Bitfield_IsSet( GameFrameworkClassesState, scast(uint32, EGameFrameworkClassFlag::PlayerState ) )); | ||||
| 			FString MsgL  = "Levels          : " + FString::FromInt( Bitfield_IsSet( GameFrameworkClassesState, scast(uint32, EGameFrameworkClassFlag::Levels ) )); | ||||
|  | ||||
| 			NetLog(MsgGM, ELogV::Log, LogGasaNet); | ||||
| 			NetLog(MsgGS, ELogV::Log, LogGasaNet); | ||||
| 			NetLog(MsgPC, ELogV::Log, LogGasaNet); | ||||
| 			NetLog(MsgPS, ELogV::Log, LogGasaNet); | ||||
| 			NetLog(MsgL,  ELogV::Log, LogGasaNet); | ||||
| 			 | ||||
| 			if (GameFrameworkClassesState == InitializedFlags) | ||||
| 			{ | ||||
| 				GameFrameworkState = EGameFrameworkState::Initialized; | ||||
| 				NetLog("Gameplay Framework initialized"); | ||||
| 				 | ||||
| 				Event_OnGameFrameworkInitialized.Broadcast(); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| #pragma endregion GameFramework | ||||
|  | ||||
| #pragma region GameInstance | ||||
| void UGasaGameInstance::Init() | ||||
| { | ||||
| 	Super::Init(); | ||||
| @@ -7,5 +86,6 @@ void UGasaGameInstance::Init() | ||||
| 	DevOptionsCache.CachedDevOptions(); | ||||
|  | ||||
| 	using namespace Gasa; | ||||
| 	Log(FString::Printf(TEXT("UObject Size:  %d RT: %d"), sizeof(UObject), UObject::StaticClass()->PropertiesSize )); | ||||
| 	NetLog(FString::Printf(TEXT("UObject Size:  %d RT: %d"), sizeof(UObject), UObject::StaticClass()->PropertiesSize )); | ||||
| } | ||||
| #pragma region GameInstance | ||||
|   | ||||
| @@ -1,10 +1,32 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Networking/GasaNetLibrary.h" | ||||
| #include "GasaDevOptionsCache.h" | ||||
| #include "Engine/Engine.h" | ||||
|  | ||||
| #include "Engine/GameInstance.h" | ||||
| #include "GasaGameInstance.generated.h" | ||||
|  | ||||
| UENUM(BlueprintType) | ||||
| enum class EGameFrameworkClassFlag : uint8 | ||||
| { | ||||
| 	None             = 0 UMETA(Hidden), | ||||
| 	GameMode         = 1 << 0, | ||||
| 	GameState        = 1 << 1, | ||||
| 	PlayerController = 1 << 2, | ||||
| 	PlayerState      = 1 << 3, | ||||
| 	Levels           = 1 << 4 | ||||
| }; | ||||
|  | ||||
| UENUM(BlueprintType) | ||||
| enum class EGameFrameworkState : uint8 | ||||
| { | ||||
| 	Initialized, | ||||
| 	Uninitialized | ||||
| }; | ||||
|  | ||||
| DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnGameFrameworkInitializedSig); | ||||
|  | ||||
| UCLASS(Blueprintable) | ||||
| class GASA_API UGasaGameInstance : public UGameInstance | ||||
| { | ||||
| @@ -14,6 +36,55 @@ public: | ||||
| 	UPROPERTY(VisibleAnywhere, Category="Dev Cache") | ||||
| 	FGasaDevOptionsCache DevOptionsCache; | ||||
|  | ||||
| #pragma region GameFramework | ||||
| 	UPROPERTY(BlueprintAssignable, Category = "GameFramework") | ||||
| 	FOnGameFrameworkInitializedSig Event_OnGameFrameworkInitialized; | ||||
| 	 | ||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameFramework") | ||||
| 	EGameFrameworkState GameFrameworkState; | ||||
|  | ||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameFramework", meta=(Bitmask, BitmaskEnum = EGameFrameworkClassFlag)) | ||||
| 	int32 GameFrameworkClassesState; | ||||
|  | ||||
| 	UFUNCTION(BlueprintCallable, Category="GameFramework") | ||||
| 	void ClearGameplayFrameworkState() 	{ | ||||
| 		Gasa::Log("Clearing game framework state", EGasaVerbosity::Log, LogGasaNet ); // TODO(Ed): Make a default NetLog | ||||
| 		GameFrameworkClassesState = scast(int32, EGameFrameworkClassFlag::None); | ||||
| 		GameFrameworkState        = EGameFrameworkState::Uninitialized; | ||||
| 	} | ||||
|  | ||||
| 	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GameFramework") | ||||
| 	FORCEINLINE bool IsGameFrameworkInitialized() { return GameFrameworkState == EGameFrameworkState::Initialized; } | ||||
| 	 | ||||
| 	UFUNCTION(BlueprintCallable, Category="GameFramework") | ||||
| 	void NotifyGameFrameworkClassReady(EGameFrameworkClassFlag ClassReady); | ||||
|  | ||||
| 	UFUNCTION(BlueprintCallable, Category = "GameFramework", meta=(BlueprintProtected)) | ||||
| 	void ProcessGameFrameworkState(); | ||||
| #pragma endregion GameFramework | ||||
|  | ||||
| #pragma region NetSlime | ||||
| 	// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp | ||||
| 	FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); } | ||||
| 	FORCEINLINE bool IsClient()               const { return Gasa::IsClient( this ); } | ||||
| 	FORCEINLINE bool IsListenServer()         const { return Gasa::IsListenServer( this ); } | ||||
| 	FORCEINLINE bool IsNetOwner()             const { return Gasa::IsNetOwner( this ); } | ||||
| 	FORCEINLINE bool IsServer()               const { return Gasa::IsServer( this ); } | ||||
| 	FORCEINLINE bool IsSimulatedProxy()       const { return Gasa::IsSimulatedProxy( this ); } | ||||
| 	FORCEINLINE void NetLog( | ||||
| 		FString           Message, | ||||
| 		EGasaVerbosity    Verbosity = EGasaVerbosity::Log, | ||||
| 		FLogCategoryBase& Category  = LogGasaNet, | ||||
| 		bool              DumpStack = false, | ||||
| 		int32             Line      = __builtin_LINE(), | ||||
| 		ANSICHAR const*   File      = __builtin_FILE(), | ||||
| 		ANSICHAR const*   Func      = __builtin_FUNCTION() | ||||
| 	) | ||||
| 	{ | ||||
| 		Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func ); | ||||
| 	} | ||||
| #pragma endregion NetSlime | ||||
|  | ||||
| #pragma region GameInstance | ||||
| 	void Init() override; | ||||
| #pragma endregion GameInstance | ||||
|   | ||||
| @@ -1,2 +1,454 @@ | ||||
| #include "GasaGameMode.h" | ||||
|  | ||||
| #include "GasaGameInstance.h" | ||||
| #include "GasaGameState.h" | ||||
| #include "GasaPlayerController.h" | ||||
| #include "GasaPlayerState.h" | ||||
| #include "Engine/Player.h" | ||||
| #include "GameFramework/GameSession.h" | ||||
| #include "GameFramework/GameState.h" | ||||
| #include "GameFramework/PlayerState.h" | ||||
| #include "OnlineSubsystem.h" | ||||
| using namespace Gasa; | ||||
|  | ||||
| #pragma region Game Framework | ||||
| void AGasaGameMode::OnGameFrameworkInitialized() | ||||
| { | ||||
| 	NetLog("OnGameFrameworkInitialized"); | ||||
| 	 | ||||
| 	BP_OnGameFrameworkInitialized(); | ||||
| 	if (MatchState == MatchState::WaitingToStart && ReadyToStartMatch()) | ||||
| 		StartMatch(); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::OwningClient_OnGameFrameworkInitialized(AGasaPlayerController* PC) | ||||
| { | ||||
| 	NetLog("OwningClient_OnGameFrameworkInitialized"); | ||||
| 	HandleStartingNewPlayer(PC); | ||||
| } | ||||
| #pragma endregion Game Framework | ||||
|  | ||||
| #pragma region GameMode | ||||
| void AGasaGameMode::HandleStartingNewPlayer_Implementation(APlayerController* NewPlayer) | ||||
| { | ||||
| 	Super::HandleStartingNewPlayer_Implementation(NewPlayer); | ||||
| 	if (NewPlayer) | ||||
| 		NewPlayer->bBlockInput = false; | ||||
| } | ||||
|  | ||||
| bool AGasaGameMode::ReadyToStartMatch_Implementation() | ||||
| { | ||||
| 	if ( ! GetGameInstance<UGasaGameInstance>()->IsGameFrameworkInitialized())  | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 	 | ||||
| 	// Super::ReadyToStartMatch(); | ||||
| 	{ | ||||
| 		// If bDelayed Start is set, wait for a manual match start | ||||
| 		if (bDelayedStart) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		// By default start when we have > 0 players | ||||
| 		if (GetMatchState() == MatchState::WaitingToStart) | ||||
| 		{ | ||||
| 			if (NumPlayers + NumBots > 0) | ||||
| 			{ | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
| #pragma endregion GameMode | ||||
|  | ||||
| #pragma region GameModeBase | ||||
| void AGasaGameMode::EndPlay(const EEndPlayReason::Type EndPlayReason) | ||||
| { | ||||
| 	Super::EndPlay(EndPlayReason); | ||||
| 	NetLog("EndPlay"); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::GenericPlayerInitialization(AController* C) | ||||
| { | ||||
| 	NetLog("GenericPlayerInitialization: " + C->GetName()); | ||||
| 	 | ||||
| 	// AGameMode::GenericPlayerInitialization(C); | ||||
| 	{ | ||||
| 		APlayerController* PC = Cast<APlayerController>(C); | ||||
| 		if (PC != nullptr) | ||||
| 		{ | ||||
| 			// Moved to: void AGasaGameMode::SetPlayerDefaults(APawn* PlayerPawn) | ||||
| 			// InitializeHUDForPlayer(Cast<APlayerController>(C)); | ||||
| 				 | ||||
| 			// Notify the game that we can now be muted and mute others | ||||
| 			UpdateGameplayMuteList(PC); | ||||
|  | ||||
| 			if (GameSession != nullptr) | ||||
| 			{ | ||||
| 				// Tell the player to enable voice by default or use the push to talk method | ||||
| 				PC->ClientEnableNetworkVoice(!GameSession->RequiresPushToTalk()); | ||||
| 			} | ||||
|  | ||||
| 			ReplicateStreamingStatus(PC); | ||||
|  | ||||
| 			bool HidePlayer = false, HideHUD = false, DisableMovement = false, DisableTurning = false; | ||||
|  | ||||
| 			// Check to see if we should start in cinematic mode (matinee movie capture) | ||||
| 			if (ShouldStartInCinematicMode(PC, HidePlayer, HideHUD, DisableMovement, DisableTurning)) | ||||
| 			{ | ||||
| 				PC->SetCinematicMode(true, HidePlayer, HideHUD, DisableMovement, DisableTurning); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| TSubclassOf<APlayerController> AGasaGameMode::GetPlayerControllerClassToSpawnForSeamlessTravel(APlayerController* PreviousPlayerController) | ||||
| { | ||||
| 	NetLog("GetPlayerControllerClassToSpawnForSeamlessTravel: " + PreviousPlayerController->GetName()); | ||||
| 	return Super::GetPlayerControllerClassToSpawnForSeamlessTravel(PreviousPlayerController); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::HandleSeamlessTravelPlayer(AController*& Controller) | ||||
| { | ||||
| 	NetLog("HandleSeamlessTravelPlayer: " + Controller->GetName()); | ||||
| 	 | ||||
| 	// Super::HandleSeamlessTravelPlayer( C ); | ||||
|  | ||||
| 	UE_LOG(LogGameMode, Log, TEXT(">> GameMode::HandleSeamlessTravelPlayer: %s "), * Controller->GetName()); | ||||
|  | ||||
| 	APlayerController* PC             = Cast<APlayerController>(Controller); | ||||
| 	UClass*            PCClassToSpawn = GetPlayerControllerClassToSpawnForSeamlessTravel(PC); | ||||
| 	// FUniqueNetIdRepl StoredNativePlatformUniqueNetId = C->GetPlayerState<AGasaPlayerState>()->NativePlatformUniqueNetId; | ||||
|  | ||||
| 	if (PC && PC->GetClass() != PCClassToSpawn) | ||||
| 	{ | ||||
| 		if (PC->Player != nullptr) | ||||
| 		{ | ||||
| 			// We need to spawn a new PlayerController to replace the old one | ||||
| 			APlayerController* const NewPC = SpawnPlayerControllerCommon(PC->IsLocalPlayerController() | ||||
| 				? ROLE_SimulatedProxy | ||||
| 				: ROLE_AutonomousProxy, PC->GetFocalLocation(), PC->GetControlRotation(), PCClassToSpawn); | ||||
| 			if (NewPC == nullptr) | ||||
| 			{ | ||||
| 				NetLog(FString::Printf( | ||||
| 					TEXT("Failed to spawn new PlayerController for %s (old class %s)"), *PC->GetHumanReadableName(), *PC->GetClass()->GetName()) | ||||
| 					, ELogV::Warning | ||||
| 				); | ||||
| 				PC->Destroy(); | ||||
| 				return; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				PC->SeamlessTravelTo(NewPC); | ||||
| 				NewPC->SeamlessTravelFrom(PC); | ||||
| 				SwapPlayerControllers(PC, NewPC); | ||||
| 				PC = NewPC; | ||||
| 				Controller = NewPC; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			PC->Destroy(); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// clear out data that was only for the previous game | ||||
| 		Controller->PlayerState->Reset(); | ||||
| 		// create a new PlayerState and copy over info; this is necessary because the old GameMode may have used a different PlayerState class | ||||
| 		APlayerState* OldPlayerState = Controller->PlayerState; | ||||
| 		Controller->InitPlayerState(); | ||||
| 		OldPlayerState->SeamlessTravelTo( Controller->PlayerState); | ||||
| 		// we don"t need the old PlayerState anymore | ||||
| 		//@fixme: need a way to replace PlayerStates that doesn't cause incorrect "player left the game"/"player entered the game" messages | ||||
| 		OldPlayerState->Destroy(); | ||||
| 	} | ||||
|  | ||||
| 	InitSeamlessTravelPlayer(Controller); | ||||
|  | ||||
| 	// Initialize hud and other player details, shared with PostLogin | ||||
| 	GenericPlayerInitialization(Controller); | ||||
| 	 | ||||
| 	if (AGasaGameState* GS = GetGameState<AGasaGameState>()) | ||||
| 	{ | ||||
| #if 0 | ||||
| 		UGasaGameInstance* GI = GetGameInstance<UGasaGameInstance>(); | ||||
| 		int32 NumConnections = GI->SessionSettings.bPublicGame | ||||
| 			? GI->SessionSettings.PublicConnections | ||||
| 			: GI->SessionSettings.PrivateConnections; | ||||
| 		if (GS->OnlinePlayers.Num() < NumConnections) | ||||
| 			GS->OnlinePlayers.Init( nullptr, NumConnections ); | ||||
| 		 | ||||
| 		for (AGasaPlayerState* & PS : GS->OnlinePlayers) | ||||
| 		{ | ||||
| 			if (PS == nullptr) | ||||
| 			{ | ||||
| 				PS = C->GetPlayerState<ASlipgatePlayerState>(); | ||||
| 				PS->SgID = GS->OnlinePlayers.Find( PS ); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	// Controller->GetPlayerState<AGasaPlayerState>()->NativePlatformUniqueNetId = StoredNativePlatformUniqueNetId; | ||||
| 	NetLog(FString::Printf(TEXT("HandleSeamlessTravelPlayer: %s"), * Controller->GetName()) ); | ||||
|  | ||||
| #if 0 | ||||
| 	if (PC) | ||||
| 		PC->Event_NetOwner_OnGameplayFrameworkInitialized.AddDynamic(this, &ThisClass::OwningClient_OnGameFrameworkInitialized); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::InitializeHUDForPlayer_Implementation(APlayerController* NewPlayer) | ||||
| { | ||||
| 	// Super::InitializeHUDForPlayer_Implementation(NewPlayer); | ||||
| 	NewPlayer->ClientSetHUD(HUDClass); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::InitSeamlessTravelPlayer(AController* NewController) | ||||
| { | ||||
| 	if (NewController) | ||||
| 		NewController->bBlockInput = true; | ||||
| 	 | ||||
| 	// GameMode::InitSeamlessTravelPlayer(NewController); | ||||
| 	{ | ||||
| 		// AGameModeBase::InitSeamlessTravelPlayer(NewController); | ||||
| 		{ | ||||
| 			APlayerController* NewPC = Cast<APlayerController>(NewController); | ||||
|  | ||||
| 			FString ErrorMessage; | ||||
| 			if (!UpdatePlayerStartSpot(NewController, TEXT(""), ErrorMessage)) | ||||
| 				NetLog(FString::Printf( TEXT("InitSeamlessTravelPlayer: %s"), *ErrorMessage), ELogV::Warning); | ||||
|  | ||||
| 			if (NewPC != nullptr) | ||||
| 			{ | ||||
| 				NewPC->PostSeamlessTravel(); | ||||
|  | ||||
| 				if (MustSpectate(NewPC)) | ||||
| 				{ | ||||
| 					NewPC->StartSpectatingOnly(); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					NewPC->bPlayerIsWaiting = true; | ||||
| 					NewPC->ChangeState(NAME_Spectating); | ||||
| 					NewPC->ClientGotoState(NAME_Spectating); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		APlayerController* NewPC = Cast<APlayerController>(NewController); | ||||
|  | ||||
| 		if (NewPC != nullptr) | ||||
| 		{ | ||||
| 			SetSeamlessTravelViewTarget(NewPC); | ||||
|  | ||||
| 			if (!MustSpectate(NewPC)) | ||||
| 			{ | ||||
| 				NumPlayers++; | ||||
| 				NumTravellingPlayers--; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			NumBots++; | ||||
| 		} | ||||
| 	} | ||||
| 	NetLog("InitSeamlessTravelPlayer: " + NewController->GetName()); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::HandleMatchAborted() | ||||
| { | ||||
| 	Super::HandleMatchAborted(); | ||||
| 	NetLog("HandleMatchAborted"); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::Logout(AController* Exiting) | ||||
| { | ||||
| 	Super::Logout(Exiting); | ||||
|  | ||||
| 	Event_OnLogout.Broadcast(Cast<AGasaPlayerController>(Exiting)); | ||||
| 	NetLog("User Logged out: " + Exiting->GetName()); | ||||
|  | ||||
| 	if (AGasaGameState* GS = Cast<AGasaGameState>(GetWorld()->GetGameState())) | ||||
| 	{ | ||||
| #if 0 | ||||
| 		int32 Index = GS->OnlinePlayers.Find(Exiting->GetPlayerState<AGasaGameState>()); | ||||
| 		if (Index == INDEX_NONE) | ||||
| 		{ | ||||
| 			NetLog("Could not find exiting player state in online players!", ELogV::Error); | ||||
| 			return; | ||||
| 		} | ||||
| 		GS->OnlinePlayers[Index] = nullptr; | ||||
| #endif | ||||
|  | ||||
| #if 0 | ||||
| 		IOnlineSessionPtr const SessionInterface = Online::GetSessionInterface(GetWorld()); | ||||
| 		if ( ! SessionInterface.IsValid()) | ||||
| 		{ | ||||
| 			NetLog("DestoryCurrentSession: Could not get the session interface.", ELogV::Warning); | ||||
| 			return; | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage) | ||||
| { | ||||
| 	Super::PreLogin(Options, Address, UniqueId, ErrorMessage); | ||||
| 	// TODO(Ed): Refuse players if the server is full. | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::PostLogin(APlayerController* NewPlayer) | ||||
| { | ||||
| 	// AGameMode::PostLogin(NewPlayer); | ||||
| 	{ | ||||
| 		UWorld* World = GetWorld(); | ||||
|  | ||||
| 		// Update player count | ||||
| 		if (MustSpectate(NewPlayer)) | ||||
| 			NumSpectators++; | ||||
| 		else if (World->IsInSeamlessTravel() || NewPlayer->HasClientLoadedCurrentWorld()) | ||||
| 			NumPlayers++; | ||||
| 		else | ||||
| 			NumTravellingPlayers++; | ||||
|  | ||||
| 		// Save network address for re-associating with reconnecting player, after stripping out port number | ||||
| 		FString Address = NewPlayer->GetPlayerNetworkAddress(); | ||||
| 		int32   Pos     = Address.Find(TEXT(":"), ESearchCase::CaseSensitive); | ||||
|  | ||||
| 		NewPlayer->PlayerState->SavedNetworkAddress = (Pos > 0) ? Address.Left(Pos) : Address; | ||||
|  | ||||
| 		// Check if this player is reconnecting and already has PlayerState | ||||
| 		FindInactivePlayer(NewPlayer);	 | ||||
| 	} | ||||
|  | ||||
| 	// AGameModeBase::PostLogin(NewPlayer) | ||||
| 	{ | ||||
| 		// Runs shared initialization that can happen during seamless travel as well | ||||
| 		GenericPlayerInitialization(NewPlayer); | ||||
|  | ||||
| 		// Perform initialization that only happens on initially joining a server | ||||
| 		NewPlayer->ClientCapBandwidth(NewPlayer->Player->CurrentNetSpeed); | ||||
|  | ||||
| 		if (MustSpectate(NewPlayer)) | ||||
| 		{ | ||||
| 			NewPlayer->ClientGotoState(NAME_Spectating); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			// If NewPlayer is not only a spectator and has a valid ID, add him as a user to the replay. | ||||
| 			FUniqueNetIdRepl const& | ||||
| 				NewPlayerStateUniqueId = NewPlayer->PlayerState->GetUniqueId(); | ||||
| 			if (NewPlayerStateUniqueId.IsValid()) | ||||
| 			{ | ||||
| 				GetGameInstance()->AddUserToReplay(NewPlayerStateUniqueId.ToString()); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (GameSession) | ||||
| 		{ | ||||
| 			GameSession->PostLogin(NewPlayer); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (AGasaGameState* GS = GetGameState<AGasaGameState>()) | ||||
| 	{ | ||||
| 		UGasaGameInstance* GI = GetGameInstance<UGasaGameInstance>(); | ||||
| 		 | ||||
| 		// int32 numconnections = gi->sessionsettings.bpublicgame | ||||
| 			// ? GI->SessionSettings.PublicConnections : GI->SessionSettings.PrivateConnections; | ||||
|  | ||||
| #if 0 | ||||
| 		if (GS->OnlinePlayers.Num() < NumConnections) | ||||
| 		{ | ||||
| 			GS->OnlinePlayers.Init( nullptr, NumConnections ); | ||||
| 		} | ||||
| 		 | ||||
| 		for (AGasaPlayerState* & PS : GS->OnlinePlayers) | ||||
| 		{ | ||||
| 			if (PS == nullptr) | ||||
| 			{ | ||||
| 				PS = NewPlayer->GetPlayerState<AGasaPlayerState>(); | ||||
| 				PS->GasaID = GS->OnlinePlayers.Find( PS ); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	// cont. AGameModeBase::PostLogin(NewPlayer) | ||||
| 	{ | ||||
| 		// Notify Blueprints that a new player has logged in.  Calling it here, because this is the first time that the PlayerController can take RPCs | ||||
| 		DispatchPostLogin(NewPlayer); | ||||
| 	} | ||||
|  | ||||
| 	AGasaPlayerController* PC = Cast<AGasaPlayerController>(NewPlayer); | ||||
| 	// if (PC) | ||||
| 	// 	PC->Event_OnNetOwner_GameplayFrameworkInitialized.AddDynamic(this, &ThisClass::OwningClient_OnGameFrameworkInitialized); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::PostSeamlessTravel() | ||||
| { | ||||
| 	Super::PostSeamlessTravel(); | ||||
| 	NetLog("PostSeamlessTravel"); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::SetPlayerDefaults(APawn* PlayerPawn) | ||||
| { | ||||
| 	InitializeHUDForPlayer(Cast<APlayerController>(PlayerPawn->GetController())); | ||||
| 	 | ||||
| 	// Super::SetPlayerDefaults(PlayerPawn); | ||||
| 	{ | ||||
| 		PlayerPawn->SetPlayerDefaults(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::SetSeamlessTravelViewTarget(APlayerController* PC) | ||||
| { | ||||
| 	Super::SetSeamlessTravelViewTarget(PC); | ||||
| 	NetLog("SetSeamlessTravelViewTarget"); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::StartPlay() | ||||
| { | ||||
| 	if (MatchState == MatchState::EnteringMap) | ||||
| 		SetMatchState(MatchState::WaitingToStart); | ||||
| 	 | ||||
| 	// Start match is deferred until the framework is considered initialized. | ||||
| 	NetLog("StartPlay"); | ||||
| 	 | ||||
| 	UGasaGameInstance* GI = GetGameInstance<UGasaGameInstance>(); | ||||
| 	GI->Event_OnGameFrameworkInitialized.AddDynamic(this, &ThisClass::OnGameFrameworkInitialized); | ||||
| 	GI->NotifyGameFrameworkClassReady(EGameFrameworkClassFlag::GameMode); | ||||
|  | ||||
| 	// Not called yet, will wait for initialization of the framework. | ||||
| 	//Super::StartPlay(); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::StartToLeaveMap() | ||||
| { | ||||
| 	NetLog("StartToLeaveMap"); | ||||
| 	Super::StartToLeaveMap(); | ||||
| } | ||||
|  | ||||
| void AGasaGameMode::SwapPlayerControllers(APlayerController* OldPC, APlayerController* NewPC) | ||||
| { | ||||
| 	NetLog("SwapPlayerControllers"); | ||||
| 	NetLog("Old: " + OldPC->GetName()); | ||||
| 	NetLog("New: " + NewPC->GetName()); | ||||
| 	 | ||||
| 	Super::SwapPlayerControllers(OldPC, NewPC); | ||||
| } | ||||
|  | ||||
| APlayerController* AGasaGameMode::SpawnPlayerControllerCommon(ENetRole InRemoteRole, FVector const& SpawnLocation, FRotator const& SpawnRotation, | ||||
| 	TSubclassOf<APlayerController> InPlayerControllerClass) | ||||
| { | ||||
| 	NetLog("SpawnPlayerControllerCommon"); | ||||
| 	return Super::SpawnPlayerControllerCommon(InRemoteRole, SpawnLocation, SpawnRotation, InPlayerControllerClass); | ||||
| } | ||||
| #pragma endregion GameModeBase | ||||
|   | ||||
| @@ -1,21 +1,95 @@ | ||||
| #pragma once | ||||
| #pragma once | ||||
| #include "GameFramework/GameMode.h" | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Networking/GasaNetLibrary_Inlines.h" | ||||
| #include "Engine/Engine.h" | ||||
|  | ||||
| #include "GasaGameMode.generated.h" | ||||
|  | ||||
| DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLogoutSig, AGasaPlayerController*, PC); | ||||
|  | ||||
| UCLASS( Blueprintable ) | ||||
| class GASA_API AGasaGameMode : public AGameMode | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	UPROPERTY(EditAnywhere, BlueprintAssignable) | ||||
| 	FOnLogoutSig Event_OnLogout; | ||||
| 	 | ||||
| #pragma region GameFramework | ||||
| 	UFUNCTION() | ||||
| 	void OnGameFrameworkInitialized(); | ||||
| 	 | ||||
| 	UFUNCTION() | ||||
| 	void OwningClient_OnGameFrameworkInitialized(AGasaPlayerController* PC); | ||||
|  | ||||
| 	UFUNCTION(BlueprintCallable, meta=(DisplayName = "On Game Framework Initialized")) | ||||
| 	void BP_OnGameFrameworkInitialized(); | ||||
| #pragma endregion GameFramework | ||||
| 	 | ||||
| #pragma region NetSlime | ||||
| 	// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp | ||||
| 	FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); } | ||||
| 	FORCEINLINE bool IsClient()               const { return Gasa::IsClient( this ); } | ||||
| 	FORCEINLINE bool IsListenServer()         const { return Gasa::IsListenServer( this ); } | ||||
| 	FORCEINLINE bool IsNetOwner()             const { return Gasa::IsNetOwner( this ); } | ||||
| 	FORCEINLINE bool IsServer()               const { return Gasa::IsServer( this ); } | ||||
| 	FORCEINLINE bool IsSimulatedProxy()       const { return Gasa::IsSimulatedProxy( this ); } | ||||
| 	FORCEINLINE void NetLog( | ||||
| 		FString           Message, | ||||
| 		EGasaVerbosity    Verbosity = EGasaVerbosity::Log, | ||||
| 		FLogCategoryBase& Category  = LogGasaNet, | ||||
| 		bool              DumpStack = false, | ||||
| 		int32             Line      = __builtin_LINE(), | ||||
| 		ANSICHAR const*   File      = __builtin_FILE(), | ||||
| 		ANSICHAR const*   Func      = __builtin_FUNCTION() | ||||
| 	) | ||||
| 	{ | ||||
| 		Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func ); | ||||
| 	} | ||||
| #pragma endregion NetSlime | ||||
|  | ||||
| #pragma region GameMode | ||||
| 	void HandleMatchAborted() override; | ||||
| 	void HandleStartingNewPlayer_Implementation(APlayerController* NewPlayer) override; | ||||
| 	 | ||||
| 	bool ReadyToStartMatch_Implementation() override; | ||||
| #pragma endregion GameMode | ||||
|  | ||||
| #pragma region GameModeBase | ||||
| 	void EndPlay(const EEndPlayReason::Type EndPlayReason) override; | ||||
|  | ||||
| 	void GenericPlayerInitialization(AController* C) override; | ||||
|  | ||||
| 	TSubclassOf<APlayerController> GetPlayerControllerClassToSpawnForSeamlessTravel(APlayerController* PreviousPlayerController) override; | ||||
|  | ||||
| 	void HandleSeamlessTravelPlayer(AController*& C) override; | ||||
|  | ||||
| 	void InitializeHUDForPlayer_Implementation(APlayerController* NewPlayer) override; | ||||
| 	void InitSeamlessTravelPlayer(AController* NewController) override; | ||||
| 	 | ||||
| 	void Logout(AController* Exiting) override; | ||||
| 	 | ||||
| 	void PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage) override; | ||||
| 	void PostLogin(APlayerController* NewPlayer) override; | ||||
| 	void PostSeamlessTravel() override; | ||||
|  | ||||
| 	void SetPlayerDefaults(APawn* PlayerPawn) override; | ||||
| 	void SetSeamlessTravelViewTarget(APlayerController* PC) override; | ||||
| 	 | ||||
| 	void StartPlay() override; | ||||
| 	void StartToLeaveMap() override; | ||||
|  | ||||
| 	void SwapPlayerControllers(APlayerController* OldPC, APlayerController* NewPC) override; | ||||
|  | ||||
| 	APlayerController* SpawnPlayerControllerCommon(ENetRole InRemoteRole, FVector const& SpawnLocation, FRotator const& SpawnRotation, TSubclassOf<APlayerController> InPlayerControllerClass) override; | ||||
| #pragma endregion GameModeBase | ||||
| }; | ||||
|  | ||||
| namespace Gasa | ||||
| { | ||||
| 	inline | ||||
| 	AGasaGameMode* GetGameMode(UObject* Context) | ||||
| 	inline AGasaGameMode* GetGameMode( UObject* Context ) | ||||
| 	{ | ||||
| 		UWorld* World = GEngine->GetWorldFromContextObject( Context, EGetWorldErrorMode::LogAndReturnNull ); | ||||
| 		if ( World == nullptr ) | ||||
|   | ||||
| @@ -2,6 +2,10 @@ | ||||
|  | ||||
| #include "CogAll.h" | ||||
| #include "CogWindowManager.h" | ||||
| #include "GasaPlayerState.h" | ||||
| #include "GasaGameInstance.h" | ||||
| #include "Net/UnrealNetwork.h" | ||||
| using namespace Gasa; | ||||
|  | ||||
| AGasaGameState::AGasaGameState() | ||||
| { | ||||
| @@ -9,11 +13,92 @@ AGasaGameState::AGasaGameState() | ||||
|     PrimaryActorTick.bCanEverTick = true; | ||||
|     PrimaryActorTick.SetTickFunctionEnable(true); | ||||
|     PrimaryActorTick.bStartWithTickEnabled = true; | ||||
|  | ||||
| 	// Replication | ||||
| 	 | ||||
| 	bReplicates            = true; | ||||
| 	bNetLoadOnClient       = false; | ||||
| 	NetDormancy            = DORM_Awake; | ||||
| 	NetCullDistanceSquared = NetCullDist_Default; | ||||
| 	NetUpdateFrequency     = 10.0f; | ||||
| 	MinNetUpdateFrequency  = 1.0f; | ||||
| 	NetPriority            = 5.0f; | ||||
| } | ||||
|  | ||||
| #pragma region GameState | ||||
| #pragma region GameFramework | ||||
| void AGasaGameState::OnGameFrameworkInitialized() | ||||
| { | ||||
| 	NetLog("Received gameplay framework initialization."); | ||||
|  | ||||
| 	if (IsServer()) | ||||
| 	{ | ||||
| 		if (PlayerArray.Num() > 0) | ||||
| 		{ | ||||
| 			ListenServerHost = Cast<AGasaPlayerState>(PlayerArray[0]); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			NetLog("Was not able to assign HostingPlayer!", ELogV::Error); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	BP_OnGameFrameworkInitialized(); | ||||
| } | ||||
| #pragma endregion GameFramework | ||||
|  | ||||
| #pragma region Networking | ||||
| void AGasaGameState::Client_OnRep_OnlinePlayers() | ||||
| { | ||||
| } | ||||
| #pragma endregion Networking | ||||
|  | ||||
| #pragma region Seamless Travel | ||||
| void AGasaGameState::Multicast_R_NotifySeamlessTravelEnd_Implementation() | ||||
| { | ||||
| 	NetLog("Multicast_R_NotifySeamlessTravelEnd_Implementation"); | ||||
| 	BP_Event_OnSeamlessTravelEnd.Broadcast(); | ||||
| 	Event_OnSeamlessTravelEnd.Broadcast(); | ||||
| } | ||||
| #pragma endregion Seamless Travel | ||||
|  | ||||
| #pragma region GameStateBase | ||||
| void AGasaGameState::HandleBeginPlay() | ||||
| { | ||||
| 	Super::HandleBeginPlay(); | ||||
| 	NetLog("HandleBeginPlay: Directly called from GM"); | ||||
| } | ||||
|  | ||||
| void AGasaGameState::SeamlessTravelTransitionCheckpoint(bool bToTransitionMap) | ||||
| { | ||||
| 	Super::SeamlessTravelTransitionCheckpoint(bToTransitionMap); | ||||
|  | ||||
| 	NetLog("SeamlessTravelTransitionCheckpoint"); | ||||
| 	NetLog(FString("ToTransitionMap: ") + FString(bToTransitionMap ? "true" : "false")); | ||||
|  | ||||
| 	if (bToTransitionMap) | ||||
| 	{ | ||||
| 		Event_OnSeamlessTravelStart.Broadcast(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		Multicast_R_NotifySeamlessTravelEnd(); | ||||
| 	} | ||||
| } | ||||
| #pragma endregion GameStateBase | ||||
|  | ||||
| #pragma region Actor | ||||
| void AGasaGameState::BeginPlay() | ||||
| { | ||||
| 	Super::BeginPlay(); | ||||
|  | ||||
| 	NetLog("BeginPlay"); | ||||
|  | ||||
| 	// Notified as initialized here as any possible components should also be initialized by this point. | ||||
| 	UGasaGameInstance* | ||||
| 	GI = GetGameInstance<UGasaGameInstance>(); | ||||
| 	GI->Event_OnGameFrameworkInitialized.AddDynamic(this, & ThisClass::OnGameFrameworkInitialized); | ||||
| 	GI->NotifyGameFrameworkClassReady(EGameFrameworkClassFlag::GameState); | ||||
| 	 | ||||
| #if ENABLE_COG | ||||
|     CogWindowManager = NewObject<UCogWindowManager>(this); | ||||
|     CogWindowManagerRef = CogWindowManager; | ||||
| @@ -23,6 +108,28 @@ void AGasaGameState::BeginPlay() | ||||
| #endif //ENABLE_COG | ||||
| } | ||||
|  | ||||
| void AGasaGameState::PostInitializeComponents() | ||||
| { | ||||
| 	NetLog("PostInitializeComponents"); | ||||
|  | ||||
| 	Super::PostInitializeComponents(); | ||||
|  | ||||
| 	if ( ! GetWorld()->IsEditorWorld() && IsServer()) | ||||
| 	{ | ||||
| 		OnlinePlayers.Empty(); | ||||
| #if 0 | ||||
| 		const auto GI = Cast<UGasaGameInstance>(GetGameInstance()); | ||||
| 		if (GI != nullptr) | ||||
| 		{ | ||||
| 			int32 NumConnections = GI->SessionSettings.bPublicGame | ||||
| 				? GI->SessionSettings.PublicConnections | ||||
| 				: GI->SessionSettings.PrivateConnections; | ||||
| 			OnlinePlayers.Init(nullptr, NumConnections); | ||||
| 		} | ||||
| #endif | ||||
| 	}	 | ||||
| } | ||||
|  | ||||
| void AGasaGameState::Tick(float DeltaSeconds) | ||||
| { | ||||
| 	Super::Tick(DeltaSeconds); | ||||
| @@ -31,4 +138,14 @@ void AGasaGameState::Tick(float DeltaSeconds) | ||||
|     CogWindowManager->Tick(DeltaSeconds); | ||||
| #endif //ENABLE_COG | ||||
| } | ||||
| #pragma endregion GameState | ||||
| #pragma endregion Actor | ||||
|  | ||||
| #pragma region UObject | ||||
| void AGasaGameState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const | ||||
| { | ||||
| 	Super::GetLifetimeReplicatedProps(OutLifetimeProps); | ||||
|  | ||||
| 	DOREPLIFETIME(AGasaGameState, ListenServerHost); | ||||
| 	DOREPLIFETIME(AGasaGameState, OnlinePlayers); | ||||
| } | ||||
| #pragma endregion UObject | ||||
|   | ||||
| @@ -1,11 +1,15 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "GameFramework/GameState.h" | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Engine/Engine.h" | ||||
| #include "Networking/GasaNetLibrary.h" | ||||
|  | ||||
| #include "GasaGameState.generated.h" | ||||
|  | ||||
| DECLARE_MULTICAST_DELEGATE( FOnTravelDelegate ); | ||||
| DECLARE_DYNAMIC_MULTICAST_DELEGATE( FOnTravelSig ); | ||||
| DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPlayerCharacterReadySig, APlayerCharacter*, Character); | ||||
|  | ||||
| UCLASS( Blueprintable ) | ||||
| class GASA_API AGasaGameState : public AGameState | ||||
| { | ||||
| @@ -18,22 +22,88 @@ public: | ||||
|  | ||||
| #if ENABLE_COG | ||||
| 	TObjectPtr<UCogWindowManager> CogWindowManager; | ||||
| #endif // ENABLE_COG | ||||
| #endif | ||||
| // ENABLE_COG | ||||
| #pragma endregion Cog | ||||
|  | ||||
| 	AGasaGameState(); | ||||
|  | ||||
| #pragma region GameState | ||||
| 	void BeginPlay() override; | ||||
| #pragma region GameFramework | ||||
| 	UFUNCTION() | ||||
| 	void OnGameFrameworkInitialized(); | ||||
|  | ||||
| 	void Tick(float DeltaSeconds) override; | ||||
| 	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, meta=(DisplayName = "Game Framework Initialized")) | ||||
| 	void BP_OnGameFrameworkInitialized(); | ||||
| #pragma endregion GameFramework | ||||
|  | ||||
| #pragma region Networking | ||||
| 	UPROPERTY(Replicated, BlueprintReadOnly) | ||||
| 	AGasaPlayerState* ListenServerHost; | ||||
|  | ||||
| 	UPROPERTY(ReplicatedUsing = "Client_OnRep_OnlinePlayers", BlueprintReadOnly) | ||||
| 	TArray<AGasaPlayerState> OnlinePlayers; | ||||
|  | ||||
| 	UFUNCTION() | ||||
| 	void Client_OnRep_OnlinePlayers(); | ||||
| #pragma endregion Networking | ||||
|  | ||||
| #pragma region Seamless Travel | ||||
| 	UPROPERTY(BlueprintAssignable) | ||||
| 	FOnTravelSig Event_OnSeamlessTravelStart; | ||||
|  | ||||
| 	UPROPERTY(BlueprintAssignable, meta=(DisplayName="Event: On Seamless Travel End")) | ||||
| 	FOnTravelSig BP_Event_OnSeamlessTravelEnd; | ||||
| 	 | ||||
| 	FOnTravelDelegate Event_OnSeamlessTravelEnd; | ||||
|  | ||||
| 	UFUNCTION(NetMulticast, Reliable) | ||||
| 	void Multicast_R_NotifySeamlessTravelEnd(); | ||||
| #pragma endregion Seamless Travel | ||||
| 	 | ||||
| #pragma region NetSlime | ||||
| 	// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp | ||||
| 	FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); } | ||||
| 	FORCEINLINE bool IsClient()               const { return Gasa::IsClient( this ); } | ||||
| 	FORCEINLINE bool IsListenServer()         const { return Gasa::IsListenServer( this ); } | ||||
| 	FORCEINLINE bool IsNetOwner()             const { return Gasa::IsNetOwner( this ); } | ||||
| 	FORCEINLINE bool IsServer()               const { return Gasa::IsServer( this ); } | ||||
| 	FORCEINLINE bool IsSimulatedProxy()       const { return Gasa::IsSimulatedProxy( this ); } | ||||
| 	FORCEINLINE void NetLog( | ||||
| 		FString           Message, | ||||
| 		EGasaVerbosity    Verbosity = EGasaVerbosity::Log, | ||||
| 		FLogCategoryBase& Category  = LogGasaNet, | ||||
| 		bool              DumpStack = false, | ||||
| 		int32             Line      = __builtin_LINE(), | ||||
| 		ANSICHAR const*   File      = __builtin_FILE(), | ||||
| 		ANSICHAR const*   Func      = __builtin_FUNCTION() | ||||
| 	) | ||||
| 	{ | ||||
| 		Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func ); | ||||
| 	} | ||||
| #pragma endregion NetSlime | ||||
| 	 | ||||
| #pragma region GameState | ||||
| 	void HandleBeginPlay() override; | ||||
| #pragma endregion GameState | ||||
|  | ||||
| #pragma region GameStateBase | ||||
| 	void SeamlessTravelTransitionCheckpoint(bool bToTransitionMap) override; | ||||
| #pragma endregion GameStateBase | ||||
|  | ||||
| #pragma region Actor | ||||
| 	void BeginPlay() override; | ||||
| 	void PostInitializeComponents() override; | ||||
| 	void Tick( float DeltaSeconds ) override; | ||||
| #pragma endregion Actor | ||||
|  | ||||
| #pragma region UObject | ||||
| 	void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; | ||||
| #pragma endregion UObject | ||||
| }; | ||||
|  | ||||
| namespace Gasa | ||||
| { | ||||
| 	inline | ||||
| 	AGasaGameState* GetGameState(UObject* Context) | ||||
| 	inline AGasaGameState* GetGameState( UObject* Context ) | ||||
| 	{ | ||||
| 		UWorld* World = GEngine->GetWorldFromContextObject( Context, EGetWorldErrorMode::LogAndReturnNull ); | ||||
| 		if ( World == nullptr ) | ||||
|   | ||||
| @@ -1,11 +1,39 @@ | ||||
| #include "GasaLevelScriptActor.h" | ||||
|  | ||||
| #include "GasaDevOptions.h" | ||||
| #include "GasaGameInstance.h" | ||||
| #include "Engine/PostProcessVolume.h" | ||||
| #include "Kismet/GameplayStatics.h" | ||||
| #include "Materials/MaterialInstance.h" | ||||
| #include "Materials/MaterialInstanceDynamic.h" | ||||
| using namespace Gasa; | ||||
|  | ||||
| #pragma region Game Framework | ||||
| AGasaLevelScriptActor::AGasaLevelScriptActor() | ||||
| { | ||||
| 	// Replication | ||||
| 	 | ||||
| 	bReplicates            = true; | ||||
| 	bNetLoadOnClient       = true; | ||||
| 	NetDormancy            = DORM_Awake; | ||||
| 	NetCullDistanceSquared = NetCullDist_Default; | ||||
| 	NetUpdateFrequency     = 10.0f; | ||||
| 	MinNetUpdateFrequency  = 1.0f; | ||||
| 	NetPriority            = 1.0f; | ||||
| } | ||||
|  | ||||
| void AGasaLevelScriptActor::OnGameFrameworkInitialized() | ||||
| { | ||||
| 	NetLog("Received game framework initialization."); | ||||
| 	BP_OnGameFrameworkInitialized(); | ||||
| } | ||||
| #pragma endregion Game Framework | ||||
|  | ||||
| #pragma region Actor | ||||
| void AGasaLevelScriptActor::BeginPlay() | ||||
| { | ||||
| 	Super::BeginPlay(); | ||||
| 	NetLog("BeginPlay"); | ||||
|  | ||||
| 	using namespace Gasa; | ||||
|  | ||||
| @@ -21,4 +49,12 @@ void AGasaLevelScriptActor::BeginPlay() | ||||
| 		PPV->Settings.WeightedBlendables.Array[0].Object = MID; | ||||
| 		break; | ||||
| 	} | ||||
| 	 | ||||
| 	UGasaGameInstance* GI = GetGameInstance<UGasaGameInstance>(); | ||||
| 	if(GI) | ||||
| 		GI->Event_OnGameFrameworkInitialized.AddUniqueDynamic(this, & ThisClass::OnGameFrameworkInitialized); | ||||
|  | ||||
| 	if (!bOverrideGameplayFrameworkReady) | ||||
| 		GI->NotifyGameFrameworkClassReady(EGameFrameworkClassFlag::Levels); | ||||
| } | ||||
| #pragma endregion Actor | ||||
|   | ||||
| @@ -1,8 +1,9 @@ | ||||
| #pragma once | ||||
| #include "GasaCommon.h" | ||||
| #include "Engine/Engine.h" | ||||
|  | ||||
| #include "Engine/LevelScriptActor.h" | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Networking/GasaNetLibrary.h" | ||||
|  | ||||
| #include "GasaLevelScriptActor.generated.h" | ||||
|  | ||||
| @@ -14,6 +15,41 @@ public: | ||||
|     UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Post Process") | ||||
|     TObjectPtr<APostProcessVolume> GlobalPPV; | ||||
|  | ||||
| 	AGasaLevelScriptActor(); | ||||
|  | ||||
| #pragma region GameFramework | ||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) | ||||
| 	bool bOverrideGameplayFrameworkReady = false; | ||||
|  | ||||
| 	UFUNCTION() | ||||
| 	void OnGameFrameworkInitialized(); | ||||
|  | ||||
| 	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, meta=(DisplayName="On Game Framework Initialized")) | ||||
| 	void BP_OnGameFrameworkInitialized();	 | ||||
| #pragma endregion GameFramework | ||||
|  | ||||
| #pragma region NetSlime | ||||
| 	// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp | ||||
| 	FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); } | ||||
| 	FORCEINLINE bool IsClient()               const { return Gasa::IsClient( this ); } | ||||
| 	FORCEINLINE bool IsListenServer()         const { return Gasa::IsListenServer( this ); } | ||||
| 	FORCEINLINE bool IsNetOwner()             const { return Gasa::IsNetOwner( this ); } | ||||
| 	FORCEINLINE bool IsServer()               const { return Gasa::IsServer( this ); } | ||||
| 	FORCEINLINE bool IsSimulatedProxy()       const { return Gasa::IsSimulatedProxy( this ); } | ||||
| 	FORCEINLINE void NetLog( | ||||
| 		FString           Message, | ||||
| 		EGasaVerbosity    Verbosity = EGasaVerbosity::Log, | ||||
| 		FLogCategoryBase& Category  = LogGasaNet, | ||||
| 		bool              DumpStack = false, | ||||
| 		int32             Line      = __builtin_LINE(), | ||||
| 		ANSICHAR const*   File      = __builtin_FILE(), | ||||
| 		ANSICHAR const*   Func      = __builtin_FUNCTION() | ||||
| 	) | ||||
| 	{ | ||||
| 		Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func ); | ||||
| 	} | ||||
| #pragma endregion NetSlime | ||||
|  | ||||
| #pragma region Actor | ||||
|     void BeginPlay() override; | ||||
| #pragma region endActor | ||||
|   | ||||
| @@ -155,6 +155,8 @@ void AGasaPlayerController::BeginPlay() | ||||
| { | ||||
| 	Super::BeginPlay(); | ||||
|  | ||||
| 	if (IsLocalController()) | ||||
| 	{ | ||||
| 		check(IMC); | ||||
| 		 | ||||
| 		UEnhancedInputLocalPlayerSubsystem* | ||||
| @@ -170,6 +172,7 @@ void AGasaPlayerController::BeginPlay() | ||||
| 			SetInputMode(MouseMode); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void AGasaPlayerController::PostInitializeComponents() | ||||
| { | ||||
|   | ||||
| @@ -1,7 +1,9 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Engine/Engine.h" | ||||
| #include "GameFramework/PlayerController.h" | ||||
| #include "Networking/GasaNetLibrary.h" | ||||
|  | ||||
| #include "GasaPlayerController.generated.h" | ||||
|  | ||||
| @@ -52,11 +54,32 @@ public: | ||||
|  | ||||
| 	inline AGasaPlayerState* GetPlayerState(); | ||||
|  | ||||
| #pragma region NetSlime | ||||
| 	// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp | ||||
| 	FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); } | ||||
| 	FORCEINLINE bool IsClient()               const { return Gasa::IsClient( this ); } | ||||
| 	FORCEINLINE bool IsListenServer()         const { return Gasa::IsListenServer( this ); } | ||||
| 	FORCEINLINE bool IsNetOwner()             const { return Gasa::IsNetOwner( this ); } | ||||
| 	FORCEINLINE bool IsServer()               const { return Gasa::IsServer( this ); } | ||||
| 	FORCEINLINE bool IsSimulatedProxy()       const { return Gasa::IsSimulatedProxy( this ); } | ||||
| 	FORCEINLINE void NetLog( | ||||
| 		FString           Message, | ||||
| 		EGasaVerbosity    Verbosity = EGasaVerbosity::Log, | ||||
| 		FLogCategoryBase& Category  = LogGasaNet, | ||||
| 		bool              DumpStack = false, | ||||
| 		int32             Line      = __builtin_LINE(), | ||||
| 		ANSICHAR const*   File      = __builtin_FILE(), | ||||
| 		ANSICHAR const*   Func      = __builtin_FUNCTION() | ||||
| 	) | ||||
| 	{ | ||||
| 		Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func ); | ||||
| 	} | ||||
| #pragma endregion NetSlime | ||||
| 	 | ||||
| #pragma region PlayerController | ||||
| 	void SpawnDefaultHUD() override; | ||||
| 	 | ||||
| 	void OnPossess(APawn* InPawn) override; | ||||
|  | ||||
| 	void OnUnPossess() override; | ||||
| 	 | ||||
| 	void PlayerTick(float DeltaTime) override; | ||||
|   | ||||
| @@ -5,6 +5,8 @@ | ||||
|  | ||||
| AGasaPlayerState::AGasaPlayerState() | ||||
| { | ||||
| 	bAutoAbilitySystem = true; | ||||
| 	 | ||||
| 	AbilitySystem = CreateDefaultSubobject<UGasaAbilitySystemComp>("Ability System"); | ||||
| 	AbilitySystem->SetIsReplicated(true); | ||||
| 	AbilitySystem->SetReplicationMode(EGameplayEffectReplicationMode::Mixed); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include "GameFramework/PlayerState.h" | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Networking/GasaNetLibrary.h" | ||||
|  | ||||
| #include "GasaPlayerState.generated.h" | ||||
|  | ||||
| @@ -16,7 +17,7 @@ class GASA_API AGasaPlayerState : public APlayerState | ||||
| public: | ||||
| #pragma region Ability System | ||||
| 	UPROPERTY(EditAnywhere, Category="Ability System") | ||||
| 	bool bAutoAbilitySystem = true; | ||||
| 	bool bAutoAbilitySystem; | ||||
| 	 | ||||
| 	UPROPERTY(EditAnywhere, Category="Ability System") | ||||
| 	TObjectPtr<UAbilitySystemComponent> AbilitySystem; | ||||
| @@ -27,6 +28,28 @@ public: | ||||
| 	 | ||||
| 	AGasaPlayerState(); | ||||
|  | ||||
| #pragma region NetSlime | ||||
| 	// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp | ||||
| 	FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); } | ||||
| 	FORCEINLINE bool IsClient()               const { return Gasa::IsClient( this ); } | ||||
| 	FORCEINLINE bool IsListenServer()         const { return Gasa::IsListenServer( this ); } | ||||
| 	FORCEINLINE bool IsNetOwner()             const { return Gasa::IsNetOwner( this ); } | ||||
| 	FORCEINLINE bool IsServer()               const { return Gasa::IsServer( this ); } | ||||
| 	FORCEINLINE bool IsSimulatedProxy()       const { return Gasa::IsSimulatedProxy( this ); } | ||||
| 	FORCEINLINE void NetLog( | ||||
| 		FString           Message, | ||||
| 		EGasaVerbosity    Verbosity = EGasaVerbosity::Log, | ||||
| 		FLogCategoryBase& Category  = LogGasaNet, | ||||
| 		bool              DumpStack = false, | ||||
| 		int32             Line      = __builtin_LINE(), | ||||
| 		ANSICHAR const*   File      = __builtin_FILE(), | ||||
| 		ANSICHAR const*   Func      = __builtin_FUNCTION() | ||||
| 	) | ||||
| 	{ | ||||
| 		Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func ); | ||||
| 	} | ||||
| #pragma endregion NetSlime | ||||
|  | ||||
| #pragma region IAbilitySystem | ||||
| 	FORCEINLINE UAttributeSet*           GetAttributes()                            { return Attributes; } | ||||
| 	FORCEINLINE UAbilitySystemComponent* GetAbilitySystemComponent() const override { return AbilitySystem; } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| using UnrealBuildTool; | ||||
| using ModuleRules = UnrealBuildTool.ModuleRules; | ||||
| using ReadOnlyTargetRules = UnrealBuildTool.ReadOnlyTargetRules; | ||||
| using TargetRules = UnrealBuildTool.TargetRules; | ||||
| @@ -11,6 +11,32 @@ public class Gasa : ModuleRules | ||||
|     public Gasa(ReadOnlyTargetRules Target) : base(Target) | ||||
|     { | ||||
| 	    bUseUnity           = false; | ||||
| 	    bMergeUnityFiles    = false; | ||||
| 	    IWYUSupport         = IWYUSupport.None; | ||||
| 	    PCHUsage            = PCHUsageMode.NoPCHs; | ||||
| 	    OptimizeCode        = CodeOptimization.Never; | ||||
| 	    MinCpuArchX64       = MinimumCpuArchitectureX64.AVX512; | ||||
| 	    IncludeOrderVersion = EngineIncludeOrderVersion.Latest; | ||||
| 	     | ||||
| 	    bCodeCoverage                      = false; | ||||
| 	    bDisableStaticAnalysis             = true; | ||||
| 	    bValidateCircularDependencies      = true; | ||||
| 	    bValidateFormatStrings             = false; | ||||
| 	    bValidateInternalApi               = false; | ||||
| 	    bEnableExceptions                  = false; | ||||
| 	    bEnableBufferSecurityChecks        = false; | ||||
| 	    bEnableNonInlinedGenCppWarnings    = false; | ||||
| 	    bEnableUndefinedIdentifierWarnings = false; | ||||
| 	    bIgnoreUnresolvedSymbols           = false; | ||||
| 	     | ||||
| 	    bEnableObjCAutomaticReferenceCounting = false; | ||||
| 	    bEnableObjCExceptions                 = false; | ||||
| 	     | ||||
| 	    var Kilobyte = 1024; | ||||
| 	    NumIncludedBytesPerUnityCPPOverride    = Kilobyte * 32; | ||||
| 	    MinFilesUsingPrecompiledHeaderOverride = 1; | ||||
| 	     | ||||
| 	    PrivatePCHHeaderFile = "GasaColdHeadersPCH.h"; | ||||
| 	     | ||||
|     #region Engine | ||||
|         PrivateIncludePathModuleNames.AddRange(new string[] { | ||||
| @@ -32,6 +58,7 @@ public class Gasa : ModuleRules | ||||
|             "InputCore",  | ||||
|             "NetCore", | ||||
|             "Niagara", | ||||
|             "OnlineSubsystem", | ||||
|             "SlateCore", | ||||
|             "UMG",  | ||||
|         }); | ||||
|   | ||||
							
								
								
									
										53
									
								
								Project/Source/Gasa/GasaColdHeadersPCH.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Project/Source/Gasa/GasaColdHeadersPCH.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "GasaEngineMinimal.h" | ||||
| #include "GasaCommon.h" | ||||
| #include "GasaGameplayTags.h" | ||||
| #include "GasaLibrary.h" | ||||
| #include "GasaModule.h" | ||||
| #include "GasaViewportSubsystem.h" | ||||
| #include "GasaDevOptions.h" | ||||
| #include "GasaDevOptionsCache.h" | ||||
|  | ||||
| // Ability System | ||||
| // #include "AbilitySystem/" | ||||
| #include "AbilitySystem/GasaAbilitySystem.h" | ||||
| // #include "AbilitySystem/GasaAbilitySystemComponent.h" | ||||
| // #include "AbilitySystem/GasaAttributeSet.h" | ||||
| // #include "GasaEffectActor.h" | ||||
|  | ||||
| // Actors | ||||
| #include "Actors/CameraMount.h" | ||||
|  | ||||
| // Characters | ||||
| // #include "Characters/GasaCharacter.h" | ||||
| // #include "Characters/EnemyCharacter.h" | ||||
| // #include "Characters/PlayerCharacter.h" | ||||
|  | ||||
| // Game | ||||
| // #include "Game/GasaGameInstance.h" | ||||
| // #include "Game/GasaGameMode.h" | ||||
| // #include "Game/GasaGameState.h" | ||||
| // #include "Game/GasaLevelScriptActor.h" | ||||
| // #include "Game/GasaPlayerController.h" | ||||
| // #include "Game/GasaPlayerController_Inlines.h" | ||||
| // #include "Game/GasaPlayerState.h" | ||||
| #include "Game/GasaViewport.h" | ||||
|  | ||||
| // Networking | ||||
| // #include "Networking/GasaNetLibrary.h" | ||||
| // #include "Networking/GasaNetLibrary_Inlines.h" | ||||
|  | ||||
| // UI | ||||
| // #include "UI/GasaCanvas.h" | ||||
| // #include "UI/GasaCanvasPanel.h" | ||||
| // #include "UI/GasaHUD.h" | ||||
| // #include "UI/GasaHUD_Inlines.h" | ||||
| // #include "UI/GasaImage.h" | ||||
| // #include "UI/GasaOverlay.h" | ||||
| // #include "UI/GasaProgressBar.h" | ||||
| // #include "UI/GasaSizeBox.h" | ||||
| // #include "UI/GasaUserWidget.h" | ||||
| // #include "UI/HostWidgetController.h" | ||||
| // #include "UI/HUDHostWidget.h" | ||||
| // #include "UI/WidgetController.h" | ||||
| @@ -1,13 +1,16 @@ | ||||
|  | ||||
| #pragma once | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| // #define private protected | ||||
| #include "GasaEngineMinimal.h" | ||||
|  | ||||
| #define global         | ||||
| #define internal      static | ||||
| #define local_persist static | ||||
|  | ||||
| #define ccast( Type, Value ) ( *const_cast<(Type)*>( &( Value ) ) ) | ||||
| #define pcast( Type, Value ) ( *reinterpret_cast<(Type)*>( &( Value ) ) ) | ||||
| #define rcast( Type, Value ) reinterpret_cast<Type>( Value ) | ||||
| #define scast( Type, Value ) static_cast<Type>( Value ) | ||||
|  | ||||
| #pragma region Math | ||||
| #define m_pow2( value ) (value * value) | ||||
| #pragma endregion Math | ||||
| @@ -16,6 +19,9 @@ | ||||
| struct FInputActionValue; | ||||
| struct FOnAttributeChangeData; | ||||
|  | ||||
| class AActor; | ||||
| class APostProcessVolume; | ||||
|  | ||||
| class IAbilitySystemInterface; | ||||
|  | ||||
| class UAbilitySystemComponent; | ||||
| @@ -45,11 +51,13 @@ class AGasaGameState; | ||||
| class AGasaLevelScriptActor; | ||||
| class AGasaPlayerController; | ||||
| class AGasaPlayerState; | ||||
| class APlayerCharacter; | ||||
|  | ||||
| class UGasaAbilitySystemComp; | ||||
| class UGasaAttributeSet; | ||||
| class UGasaDevOptions; | ||||
| class UGasaImage; | ||||
| class UGasaObject; | ||||
| class UGasaOverlay; | ||||
| class UGasaProgressBar; | ||||
| class UGasaSizeBox; | ||||
| @@ -58,6 +66,21 @@ class UHUDHostWidget; | ||||
| class UWidgetController; | ||||
| #pragma endregion Forwards | ||||
|  | ||||
| #pragma region Bitfields | ||||
| namespace Gasa | ||||
| { | ||||
| 	inline | ||||
| 	bool Bitfield_IsSet(int32 Bitfield, int32 Bitmask) { | ||||
| 		int32 Result = Bitmask == (Bitfield & Bitmask); | ||||
| 		return scast(bool, Result); | ||||
| 	} | ||||
|  | ||||
| 	inline void Bitfield_Set   ( int32& Bitfield, int32 BitsToAdd )    { Bitfield |= BitsToAdd; } | ||||
| 	inline void Bitfield_Remove( int32& Bitfield, int32 BitsToRemove ) { Bitfield &= (! BitsToRemove); } | ||||
| 	inline void Bitfield_Toggle( int32& Bitfield, int32 Bitmask )      { Bitfield ^= Bitmask; } | ||||
| } | ||||
| #pragma endregion Bitfields | ||||
|  | ||||
| #pragma region Logging | ||||
| // Straight from the Engine | ||||
| UENUM(BlueprintType) | ||||
| @@ -107,7 +130,6 @@ namespace Gasa | ||||
| { | ||||
| 	using ELogV = EGasaVerbosity; | ||||
|  | ||||
| 	//◞ ‸ ◟// | ||||
| 	// Works for Unreal 5.4, Win64 MSVC (untested in other scenarios, for now) | ||||
| 	inline | ||||
| 	void Log( FString Message, EGasaVerbosity Verbosity = EGasaVerbosity::Log | ||||
|   | ||||
							
								
								
									
										160
									
								
								Project/Source/Gasa/GasaEngineMinimal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								Project/Source/Gasa/GasaEngineMinimal.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| #pragma once | ||||
|  | ||||
| /*---------------------------------------------------------------------------- | ||||
| 	Low level includes. | ||||
| ----------------------------------------------------------------------------*/ | ||||
|  | ||||
| #include "CoreTypes.h" | ||||
|  | ||||
| /*---------------------------------------------------------------------------- | ||||
| 	Forward declarations | ||||
| ----------------------------------------------------------------------------*/ | ||||
|  | ||||
| #include "CoreFwd.h" | ||||
| #include "UObject/UObjectHierarchyFwd.h" | ||||
| #include "Containers/ContainersFwd.h" | ||||
|  | ||||
| /*---------------------------------------------------------------------------- | ||||
| 	Commonly used headers | ||||
| ----------------------------------------------------------------------------*/ | ||||
|  | ||||
| #include "Misc/VarArgs.h" | ||||
| #include "Logging/LogVerbosity.h" | ||||
| #include "UObject/ObjectMacros.h" | ||||
|  | ||||
| // #include "Misc/OutputDevice.h" | ||||
| // #include "HAL/PlatformCrt.h" | ||||
| // #include "HAL/PlatformMisc.h" | ||||
| // #include "Misc/AssertionMacros.h" | ||||
| // #include "Templates/IsPointer.h" | ||||
| // #include "HAL/PlatformMemory.h" | ||||
| // #include "HAL/PlatformAtomics.h" | ||||
| // #include "Misc/Exec.h" | ||||
| // #include "HAL/MemoryBase.h" | ||||
| // #include "HAL/UnrealMemory.h" | ||||
| // #include "Templates/IsArithmetic.h" | ||||
| // #include "Templates/AndOrNot.h" | ||||
| // #include "Templates/IsPODType.h" | ||||
| // #include "Templates/IsUECoreType.h" | ||||
| // #include "Templates/IsTriviallyCopyConstructible.h" | ||||
| // #include "Templates/UnrealTypeTraits.h" | ||||
| // #include "Templates/EnableIf.h" | ||||
| // #include "Templates/RemoveReference.h" | ||||
| // #include "Templates/IntegralConstant.h" | ||||
| // #include "Templates/IsClass.h" | ||||
| // #include "Templates/TypeCompatibleBytes.h" | ||||
| // #include "Traits/IsContiguousContainer.h" | ||||
| // #include "Templates/UnrealTemplate.h" | ||||
| // #include "Math/NumericLimits.h" | ||||
| // #include "HAL/PlatformMath.h" | ||||
| // #include "Templates/IsTriviallyCopyAssignable.h" | ||||
| // #include "Templates/IsTriviallyDestructible.h" | ||||
| // #include "Templates/MemoryOps.h" | ||||
| // #include "Containers/ContainerAllocationPolicies.h" | ||||
| // #include "Templates/IsEnumClass.h" | ||||
| // #include "HAL/PlatformProperties.h" | ||||
| // #include "Misc/EngineVersionBase.h" | ||||
| // #include "Internationalization/TextNamespaceFwd.h" | ||||
| // #include "Serialization/Archive.h" | ||||
| // #include "Templates/Less.h" | ||||
| // #include "Templates/Sorting.h" | ||||
| // #include "Misc/Char.h" | ||||
| // #include "GenericPlatform/GenericPlatformStricmp.h" | ||||
| // #include "GenericPlatform/GenericPlatformString.h" | ||||
| // #include "HAL/PlatformString.h" | ||||
| // #include "Misc/CString.h" | ||||
| // #include "Misc/Crc.h" | ||||
| // #include "Math/UnrealMathUtility.h" | ||||
| // #include "Containers/UnrealString.h" | ||||
| // #include "Containers/Array.h" | ||||
| // #include "Misc/FrameNumber.h" | ||||
| // #include "Misc/Timespan.h" | ||||
| // #include "Containers/StringConv.h" | ||||
| // #include "UObject/UnrealNames.h" | ||||
| // #include "UObject/NameTypes.h" | ||||
| // #include "Misc/Parse.h" | ||||
| // #include "Templates/AlignmentTemplates.h" | ||||
| // #include "Misc/StructBuilder.h" | ||||
| // #include "Templates/Decay.h" | ||||
| // #include "Templates/PointerIsConvertibleFromTo.h" | ||||
| // #include "Templates/Invoke.h" | ||||
| // #include "Templates/Function.h" | ||||
| // #include "Templates/TypeHash.h" | ||||
|  | ||||
| // #include "Containers/ScriptArray.h" | ||||
| // #include "Containers/BitArray.h" | ||||
| // #include "Containers/SparseArray.h" | ||||
| // #include "Containers/Set.h" | ||||
|  | ||||
| // #include "Algo/Reverse.h" | ||||
| // #include "Containers/Map.h" | ||||
| // #include "Math/IntPoint.h" | ||||
| // #include "Math/IntVector.h" | ||||
|  | ||||
| // #include "Logging/LogCategory.h" | ||||
| // #include "Logging/LogMacros.h" | ||||
|  | ||||
| // #include "Math/Vector2D.h" | ||||
| // #include "Math/IntRect.h" | ||||
| // #include "Misc/ByteSwap.h" | ||||
| // #include "Containers/EnumAsByte.h" | ||||
| // #include "HAL/PlatformTLS.h" | ||||
| // #include "CoreGlobals.h" | ||||
|  | ||||
| // #include "Templates/SharedPointer.h" | ||||
| // #include "Internationalization/CulturePointer.h" | ||||
| // #include "UObject/WeakObjectPtrTemplates.h" | ||||
| // #include "Delegates/DelegateSettings.h" | ||||
| // #include "Delegates/IDelegateInstance.h" | ||||
| // #include "Delegates/DelegateBase.h" | ||||
| // #include "Delegates/MulticastDelegateBase.h" | ||||
| // #include "Delegates/IntegerSequence.h" | ||||
| // #include "Templates/Tuple.h" | ||||
| // #include "UObject/ScriptDelegates.h" | ||||
| // #include "Delegates/Delegate.h" | ||||
| // #include "Internationalization/TextLocalizationManager.h" | ||||
| // #include "Misc/Optional.h" | ||||
| // #include "Templates/IsArray.h" | ||||
| // #include "Templates/RemoveExtent.h" | ||||
| // #include "Templates/UniquePtr.h" | ||||
| // #include "Internationalization/Text.h" | ||||
| // #include "Templates/UniqueObj.h" | ||||
| // #include "Internationalization/Internationalization.h" | ||||
| // #include "Math/Vector.h" | ||||
| // #include "Math/Vector4.h" | ||||
| // #include "Math/VectorRegister.h" | ||||
| // #include "Math/TwoVectors.h" | ||||
| // #include "Math/Edge.h" | ||||
| // #include "UObject/ObjectVersion.h" | ||||
| // #include "Math/CapsuleShape.h" | ||||
| // #include "Math/Rotator.h" | ||||
| // #include "Misc/DateTime.h" | ||||
| // #include "Math/RangeBound.h" | ||||
| // #include "Misc/AutomationEvent.h" | ||||
| // #include "Math/Range.h" | ||||
| // #include "Math/RangeSet.h" | ||||
| // #include "Math/Interval.h" | ||||
| // #include "Math/Box.h" | ||||
| // #include "Math/Box2D.h" | ||||
| // #include "Math/BoxSphereBounds.h" | ||||
| // #include "Math/OrientedBox.h" | ||||
| // #include "Math/Axis.h" | ||||
| // #include "Math/Matrix.h" | ||||
| // #include "Math/RotationTranslationMatrix.h" | ||||
| // #include "Math/RotationAboutPointMatrix.h" | ||||
| // #include "Math/ScaleRotationTranslationMatrix.h" | ||||
| // #include "Math/RotationMatrix.h" | ||||
| // #include "Math/Quat.h" | ||||
| // #include "Math/PerspectiveMatrix.h" | ||||
| // #include "Math/OrthoMatrix.h" | ||||
| // #include "Math/TranslationMatrix.h" | ||||
| // #include "Math/QuatRotationTranslationMatrix.h" | ||||
| // #include "Math/InverseRotationMatrix.h" | ||||
| // #include "Math/ScaleMatrix.h" | ||||
| // #include "Math/MirrorMatrix.h" | ||||
| // #include "Math/ClipProjectionMatrix.h" | ||||
| // #include "Math/Float32.h" | ||||
| // #include "Math/Float16.h" | ||||
| // #include "Math/Transform.h" | ||||
| // #include "Math/ConvexHull2d.h" | ||||
| // #include "Math/UnrealMath.h" | ||||
| @@ -8,6 +8,7 @@ | ||||
| #include "Game/GasaGameState.h" | ||||
| #include "Game/GasaPlayerController.h" | ||||
| #include "Kismet/KismetSystemLibrary.h" | ||||
| #include "Misc/ConfigCacheIni.h" | ||||
|  | ||||
| #pragma region Game | ||||
| UGasaDevOptions* UGasaLib::GetGasaDevOptions(UObject* Context) { | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Kismet/BlueprintFunctionLibrary.h" | ||||
|  | ||||
| #include "GasaLibrary.Generated.h" | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "Modules/ModuleInterface.h" | ||||
| #include "Modules/ModuleManager.h" | ||||
|  | ||||
| class GASA_API FGasaModule : public IModuleInterface | ||||
| { | ||||
|   | ||||
							
								
								
									
										77
									
								
								Project/Source/Gasa/GasaObject.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								Project/Source/Gasa/GasaObject.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| #include "GasaObject.h" | ||||
|  | ||||
| #include "Engine/ActorChannel.h" | ||||
| #include "Engine/BlueprintGeneratedClass.h" | ||||
| #include "Engine/NetDriver.h" | ||||
| #include "GameFramework/Actor.h" | ||||
| using namespace Gasa; | ||||
|  | ||||
| UGasaObject::UGasaObject() | ||||
| { | ||||
| 	bReplicates                 = false; | ||||
| 	bDisconnectOnBadReplication = false; | ||||
| } | ||||
|  | ||||
| void UGasaObject::Destroy() | ||||
| { | ||||
| 	if ( ! IsValid(this)) | ||||
| 	{ | ||||
| 		checkf(GetOwningActor()->HasAuthority() == true, TEXT("Destroy:: Object does not have authority to destroy itself!")); | ||||
| 		OnDestroyed(); | ||||
| 		Event_OnDestroyed.Broadcast(); | ||||
| 		ConditionalBeginDestroy(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void UGasaObject::OnDestroyed() | ||||
| { | ||||
| } | ||||
|  | ||||
| bool UGasaObject::ReplicateAsSubobject(AActor* ActorResponsible, UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) | ||||
| { | ||||
| 	if (!ActorResponsible) | ||||
| 	{ | ||||
| 		NetLog("Actor reponsible is null", ELogV::Error); | ||||
| 		return false; | ||||
| 	} | ||||
| 	if (!bDisconnectOnBadReplication && ActorResponsible != GetOuter()) | ||||
| 	{ | ||||
| 		NetLog("Attempted to replicate whose outer was not set to the actor whose responsible for replicating it as a subobject", ELogV::Error); | ||||
| 		return false; | ||||
| 	} | ||||
| 	return Channel->ReplicateSubobject(this, *Bunch, *RepFlags); | ||||
| } | ||||
|  | ||||
| bool UGasaObject::CallRemoteFunction(UFunction* Function, void* Parms, FOutParmRec* OutParms, FFrame* Stack) | ||||
| { | ||||
| 	check(! HasAnyFlags(RF_ClassDefaultObject)); | ||||
| 	AActor*     Owner     = GetOwningActor(); | ||||
| 	UNetDriver* NetDriver = Owner->GetNetDriver(); | ||||
| 	if (NetDriver) | ||||
| 	{ | ||||
| 		NetDriver->ProcessRemoteFunction(Owner, Function, Parms, OutParms, Stack, this); | ||||
| 		return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| int32 UGasaObject::GetFunctionCallspace(UFunction* Function, FFrame* Stack) | ||||
| { | ||||
| 	check(GetOuter() != nullptr); | ||||
| 	return GetOuter()->GetFunctionCallspace(Function, Stack); | ||||
| } | ||||
|  | ||||
| void UGasaObject::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const | ||||
| { | ||||
| 	// Add any Blueprint properties | ||||
| 	// This is not required if you do not want the class to be "Blueprintable" | ||||
| 	if (const UBlueprintGeneratedClass* BP = Cast<UBlueprintGeneratedClass>(GetClass())) | ||||
| 	{ | ||||
| 		BP->GetLifetimeBlueprintReplicationList(OutLifetimeProps); | ||||
| 	}	 | ||||
| } | ||||
|  | ||||
| bool UGasaObject::IsSupportedForNetworking() const | ||||
| { | ||||
| 	return bReplicates; | ||||
| } | ||||
							
								
								
									
										80
									
								
								Project/Source/Gasa/GasaObject.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								Project/Source/Gasa/GasaObject.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "GasaCommon.h" | ||||
| #include "Networking/GasaNetLibrary.h" | ||||
| #include "UObject/Object.h" | ||||
| #include "GasaObject.generated.h" | ||||
|  | ||||
| DECLARE_DYNAMIC_MULTICAST_DELEGATE(FGasaObjectEventSig); | ||||
|  | ||||
| // A UObject which supports replication and other features. | ||||
| UCLASS( Blueprintable ) | ||||
| class GASA_API UGasaObject : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	 | ||||
| 	UGasaObject(); | ||||
|  | ||||
| 	UFUNCTION(BlueprintPure) | ||||
| 	FORCEINLINE AActor* GetOwningActor() const { return GetTypedOuter<AActor>(); }; | ||||
| 	 | ||||
| 	UPROPERTY(BlueprintAssignable, Category="Lifetime") | ||||
| 	FGasaObjectEventSig Event_OnDestroyed; | ||||
| 	 | ||||
| 	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="Lifetime") | ||||
| 	virtual void Destroy(); | ||||
|  | ||||
| 	virtual void OnDestroyed(); | ||||
|  | ||||
| 	UFUNCTION(BlueprintImplementableEvent, meta=(DisplayName = "On Destroyed")) | ||||
| 	void BP_OnDestroyed(); | ||||
|  | ||||
| #pragma region Replication | ||||
| 	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Replication") | ||||
| 	bool bReplicates; | ||||
| 	 | ||||
| 	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Replication") | ||||
| 	bool bDisconnectOnBadReplication ; | ||||
| 	 | ||||
| 	virtual bool ReplicateAsSubobject(AActor* ActorResponsible, UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags); | ||||
|  | ||||
| 	UFUNCTION(BlueprintCallable) | ||||
| 	void SetIsReplicated(bool DesiredValue) | ||||
| 	{ | ||||
| 		bReplicates = DesiredValue; | ||||
| 	} | ||||
| #pragma endregion Replication | ||||
|  | ||||
| #pragma region NetSlime | ||||
| 	// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp | ||||
| 	FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); } | ||||
| 	FORCEINLINE bool IsClient()               const { return Gasa::IsClient( this ); } | ||||
| 	FORCEINLINE bool IsListenServer()         const { return Gasa::IsListenServer( this ); } | ||||
| 	FORCEINLINE bool IsNetOwner()             const { return Gasa::IsNetOwner( this ); } | ||||
| 	FORCEINLINE bool IsServer()               const { return Gasa::IsServer( this ); } | ||||
| 	FORCEINLINE bool IsSimulatedProxy()       const { return Gasa::IsSimulatedProxy( this ); } | ||||
| 	FORCEINLINE void NetLog( | ||||
| 	    FString           Message, | ||||
| 	    EGasaVerbosity    Verbosity = EGasaVerbosity::Log, | ||||
| 	    FLogCategoryBase& Category  = LogGasaNet, | ||||
| 	    bool              DumpStack = false, | ||||
| 	    int32             Line      = __builtin_LINE(), | ||||
| 	    ANSICHAR const*   File      = __builtin_FILE(), | ||||
| 	    ANSICHAR const*   Func      = __builtin_FUNCTION() | ||||
| 	) | ||||
| 	{ | ||||
| 		Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func ); | ||||
| 	} | ||||
| #pragma endregion NetSlime | ||||
|  | ||||
| #pragma region UObject | ||||
| 	bool CallRemoteFunction(UFunction* Function, void* Parms, FOutParmRec* OutParms, FFrame* Stack) override; | ||||
|  | ||||
| 	int32 GetFunctionCallspace(UFunction* Function, FFrame* Stack) override; | ||||
|  | ||||
| 	void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; | ||||
|  | ||||
| 	bool IsSupportedForNetworking() const override; | ||||
| #pragma endregion UObject | ||||
| }; | ||||
| @@ -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; | ||||
| 	} | ||||
| } | ||||
| @@ -3,6 +3,9 @@ | ||||
| #include "AbilitySystem/GasaAttributeSet.h" | ||||
| #include "GameplayEffectTypes.h" | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| #pragma region Attribute Changed Callbacks | ||||
| // Attribute Changed Callbacks are generated by GasaGen/GasaGen_HostWidgetController.cpp | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ using System; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Runtime; | ||||
| using UnrealBuildTool; | ||||
| using BuildSettingsVersion = UnrealBuildTool.BuildSettingsVersion; | ||||
| using TargetInfo = UnrealBuildTool.TargetInfo; | ||||
| using TargetRules = UnrealBuildTool.TargetRules; | ||||
| @@ -17,6 +18,7 @@ public class GasaEditorTarget : TargetRules | ||||
|          | ||||
|         bUseUnityBuild = true; | ||||
|         // bUseXGEController = false; | ||||
|         LinkType = TargetLinkType.Modular; | ||||
|          | ||||
| 		ExtraModuleNames.Add("Gasa"); | ||||
| 		ExtraModuleNames.Add("GasaEditor"); | ||||
|   | ||||
| @@ -18,6 +18,7 @@ using namespace gen; | ||||
| #include "GasaGen_ChangeBPActionMenu.cpp" | ||||
| #include "GasaGen_DevOptionsCache.cpp" | ||||
| #include "GasaGen_HostWidgetController.cpp" | ||||
| #include "GasaGen_NetSlime.cpp" | ||||
|  | ||||
| int gen_main() | ||||
| { | ||||
| @@ -80,6 +81,7 @@ int gen_main() | ||||
| 	gen_UGasaAttributeSet(); | ||||
| 	gen_FGasaDevOptionsCache(); | ||||
| 	gen_UHostWidgetController(); | ||||
| 	// gen_netslime_interfaces(); | ||||
|  | ||||
| 	// One offs | ||||
| 	if (0) | ||||
|   | ||||
| @@ -13,6 +13,9 @@ using namespace gen; | ||||
| #define path_config              path_source      "Config/" | ||||
| #define path_module_gasa         path_source      "Gasa/" | ||||
| #define path_gasa_ability_system path_module_gasa "AbilitySystem/" | ||||
| #define path_gasa_actors         path_module_gasa "Actors/" | ||||
| #define path_gasa_characters     path_module_gasa "Characters/" | ||||
| #define path_gasa_game           path_module_gasa "Game/" | ||||
| #define path_gasa_ui             path_module_gasa "UI/" | ||||
|  | ||||
| constexpr StrC str_DECLARE_CLASS                                         = txt("DECLARE_CLASS("); | ||||
|   | ||||
							
								
								
									
										118
									
								
								Project/Source/GasaGen/GasaGen_NetSlime.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								Project/Source/GasaGen/GasaGen_NetSlime.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| // Used in the GasaGen.cpp translation unit | ||||
| #if GASA_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #include "gen.hpp" | ||||
| #include "gen.builder.hpp" | ||||
| #include "GasaGenCommon.cpp" | ||||
| #endif | ||||
|  | ||||
| void gen_netslime_interface(CodeClass aclass) | ||||
| { | ||||
| 	CodeBody net_slime_class_interface = def_body(ECode::Class_Body); | ||||
| 	{ | ||||
| 	#pragma push_macro("FORCEINLINE") | ||||
| 	#undef FORCEINLINE | ||||
| 		CodeFn DrawNetCullingSphere = parse_function( code( | ||||
| 			FORCEINLINE void DrawNetCullingSphere(float Duration, float Thickness) const final { Gasa::DrawNetCullingSphere(this, Duration, Thickness); } | ||||
| 		)); | ||||
| 		CodeFn GetNetworkMode   = parse_function( code( FORCEINLINE ENetworkMode GetNetworkMode()   const { return Gasa::GetNetworkMode(this); }  )); | ||||
| 		CodeFn IsClient         = parse_function( code( FORCEINLINE bool         IsClient()         const { return Gasa::IsClient(this); }        )); | ||||
| 		CodeFn IsListenServer   = parse_function( code( FORCEINLINE bool         IsListenServer()   const { return Gasa::IsListenServer(this); }  )); | ||||
| 		CodeFn IsNetOwner       = parse_function( code( FORCEINLINE bool         IsNetOwner()       const { return Gasa::IsNetOwner(this); }      )); | ||||
| 		CodeFn IsServer         = parse_function( code( FORCEINLINE bool         IsServer()         const { return Gasa::IsServer(this); }        )); | ||||
| 		CodeFn IsSimulatedProxy = parse_function( code( FORCEINLINE bool         IsSimulatedProxy() const { return Gasa::IsSimulatedProxy(this); } )); | ||||
| 		CodeFn NetLog = parse_function( code( | ||||
| 			FORCEINLINE void NetLog( 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() ) | ||||
| 			{ | ||||
| 				Gasa::NetLog(this, Message, Verbosity, Category, DumpStack, Line, File, Func ); | ||||
| 			} | ||||
| 		)); | ||||
| 		CodeFn ServerAuthorized = parse_function( code( FORCEINLINE bool ServerAuthorized() const { return Gasa::ServerAuthorized(this); } )); | ||||
| 	#pragma pop_macro("FORCEINLINE") | ||||
| 		net_slime_class_interface.append(GetNetworkMode); | ||||
| 		net_slime_class_interface.append(IsClient); | ||||
| 		net_slime_class_interface.append(IsListenServer); | ||||
| 		net_slime_class_interface.append(IsNetOwner); | ||||
| 		net_slime_class_interface.append(IsServer); | ||||
| 		net_slime_class_interface.append(IsSimulatedProxy); | ||||
| 		net_slime_class_interface.append(NetLog); | ||||
| 	} | ||||
|  | ||||
| 	CodeBody new_body = def_body(ECode::Class_Body); | ||||
| 	for(Code code = aclass->Body.begin(); code != aclass->Body.end(); ++ code ) | ||||
| 	{ | ||||
| 		switch (code->Type) | ||||
| 		{ | ||||
| 			default: | ||||
| 				new_body.append(code); | ||||
| 			break; | ||||
|  | ||||
| 			// TODO(Ed): Could this be turned into a singly? void find_and_swap_region_pragma(CodeClass, StrC region) | ||||
| 			// IT could return void if its assumed that the Code passed will have destructive edits to the body. | ||||
| 			case ECode::Preprocess_Pragma: | ||||
| 			{ | ||||
| 				local_persist bool found = false; | ||||
| 				if (found || ! code->Content.starts_with( txt("region NetSlime"))) | ||||
| 				{ | ||||
| 					new_body.append(code); | ||||
| 					continue; | ||||
| 				} | ||||
|  | ||||
| 				// Add pragma | ||||
| 				new_body.append(code); | ||||
| 				++ code; | ||||
|  | ||||
| 				new_body.append( def_comment( txt("NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp"))); | ||||
| 				new_body.append(net_slime_class_interface); | ||||
|  | ||||
| 				while (code->Type != ECode::Preprocess_Pragma | ||||
| 					|| ! code->Content.starts_with(txt("endregion NetSlime"))) | ||||
| 					++ code; | ||||
|  | ||||
| 				new_body.append(code); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	aclass->Body = new_body; | ||||
| } | ||||
|  | ||||
| void gen_netslime_interfaces() | ||||
| { | ||||
| 	Array<StringCached> header_paths = Array<StringCached>::init_reserve(GlobalAllocator, 32); | ||||
| 	// header_paths.append(get_cached_string(txt( path_module_gasa     "GasaObject.h"))); | ||||
| 	// header_paths.append(get_cached_string(txt( path_gasa_actors     "GasaActor.h"))); | ||||
| 	// header_paths.append(get_cached_string(txt( path_gasa_characters "GasaCharacter.h"))); | ||||
| 	// header_paths.append(get_cached_string(txt( path_gasa_game       "GasaGameMode.h"))); | ||||
| 	// header_paths.append(get_cached_string(txt( path_gasa_game       "GasaGameState.h"))); | ||||
|  | ||||
| 	for (StringCached path : header_paths) | ||||
| 	{ | ||||
| 		CodeBody original_header = parse_file(path); | ||||
| 		CodeBody header_body     = def_body(ECode::Global_Body); | ||||
| 		for (Code code : original_header) | ||||
| 		{ | ||||
| 			switch (code->Type) { | ||||
| 			case ECode::Class: | ||||
| 			{ | ||||
| 				CodeClass aclass = code.cast<CodeClass>(); | ||||
| 				gen_netslime_interface(aclass); | ||||
| 				header_body.append(aclass); | ||||
| 			} | ||||
| 			break; | ||||
| 			default: | ||||
| 				header_body.append(code); | ||||
| 			} | ||||
| 		} | ||||
| 		Builder header = Builder::open(path); | ||||
| 		header.print(header_body); | ||||
| 		header.write(); | ||||
| 		format_file(path); | ||||
| 	} | ||||
| } | ||||
| @@ -272,6 +272,7 @@ void def_attribute_field_value_setters( CodeBody body, Array<StringCached> prope | ||||
|  | ||||
| void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name, Array<StringCached> properties ) | ||||
| { | ||||
| 	body.append(def_pragma( txt("region Attribute Setters"))); | ||||
| 	for ( String property : properties ) | ||||
| 	{ | ||||
| 		CodeFn generated_get_attribute = parse_function( | ||||
| @@ -288,6 +289,7 @@ void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name | ||||
| 			))); | ||||
| 		body.append( generated_get_attribute ); | ||||
| 	} | ||||
| 	body.append(def_pragma( txt("endregion Attribute Setters"))); | ||||
| } | ||||
|  | ||||
| void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties ) | ||||
| @@ -307,11 +309,10 @@ void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties | ||||
|  | ||||
| void impl_attribute_fields( CodeBody body, StrC class_name, Array<StringCached> properties ) | ||||
| { | ||||
| 	body.append(fmt_newline); | ||||
| 	body.append(def_pragma( txt("region Rep Notifies"))); | ||||
| 	for ( String property : properties ) | ||||
| 	{ | ||||
| 		body.append(fmt_newline); | ||||
|  | ||||
| 		CodeFn field_impl = parse_function( token_fmt( | ||||
| 			"class_name", class_name, "property", (StrC)property, "from_notice", txt("\n// From GAMEPLAYATTRIBUTE_REPNOTIFY\n"), | ||||
| 		stringize( | ||||
| @@ -326,6 +327,7 @@ void impl_attribute_fields( CodeBody body, StrC class_name, Array<StringCached> | ||||
| 		body.append( field_impl ); | ||||
| 	} | ||||
| 	body.append( def_pragma( txt("endregion Rep Notifies"))); | ||||
| 	body.append(fmt_newline); | ||||
| } | ||||
|  | ||||
| inline | ||||
|   | ||||
| @@ -1610,7 +1610,7 @@ void CodeConstructor::to_string_fwd( String& result ) | ||||
| 	if ( ast->InlineCmt ) | ||||
| 		result.append_fmt( "; // %S\n", ast->InlineCmt->Content ); | ||||
| 	else | ||||
| 		result.append( ";" ); | ||||
| 		result.append( ";\n" ); | ||||
| } | ||||
|  | ||||
| String CodeClass::to_string() | ||||
| @@ -6278,6 +6278,16 @@ namespace parser | ||||
| 			move_forward(); | ||||
| 			preprocess_content.Length++; | ||||
|  | ||||
| 			if ( current == '\r' && scanner[1] == '\n' ) | ||||
| 			{ | ||||
| 				move_forward(); | ||||
| 				move_forward(); | ||||
| 			} | ||||
| 			else if ( current == '\n' ) | ||||
| 			{ | ||||
| 				move_forward(); | ||||
| 			} | ||||
|  | ||||
| 			Tokens.append( preprocess_content ); | ||||
| 			return Lex_Continue;    // Skip found token, its all handled here. | ||||
| 		} | ||||
| @@ -7262,7 +7272,7 @@ namespace parser | ||||
| 		Tokens            = Array<Token>::init_reserve( LexArena, ( LexAllocator_Size - sizeof( Array<Token>::Header ) ) / sizeof( Token ) ); | ||||
|  | ||||
| 		defines_map_arena = Arena_256KB::init(); | ||||
| 		defines           = HashTable<StrC>::init( defines_map_arena ); | ||||
| 		defines           = HashTable<StrC>::init_reserve( defines_map_arena, 256 ); | ||||
| 	} | ||||
|  | ||||
| 	internal void deinit() | ||||
|   | ||||
| @@ -1663,7 +1663,7 @@ struct Array | ||||
| 	{ | ||||
| 		Header& header = *get_header(); | ||||
|  | ||||
| 		if ( begin < 0 || end >= header.Num ) | ||||
| 		if ( begin < 0 || end > header.Num ) | ||||
| 			return false; | ||||
|  | ||||
| 		for ( sw idx = begin; idx < end; idx++ ) | ||||
| @@ -1820,13 +1820,11 @@ struct HashTable | ||||
| 		Type Value; | ||||
| 	}; | ||||
|  | ||||
| 	static constexpr f32 CriticalLoadScale = 0.7f; | ||||
|  | ||||
| 	static HashTable init( AllocatorInfo allocator ) | ||||
| 	{ | ||||
| 		HashTable<Type> result = { { nullptr }, { nullptr } }; | ||||
|  | ||||
| 		result.Hashes          = Array<sw>::init( allocator ); | ||||
| 		result.Entries         = Array<Entry>::init( allocator ); | ||||
|  | ||||
| 		HashTable<Type> result = init_reserve(allocator, 8); | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| @@ -1836,19 +1834,17 @@ struct HashTable | ||||
|  | ||||
| 		result.Hashes = Array<sw>::init_reserve( allocator, num ); | ||||
| 		result.Hashes.get_header()->Num = num; | ||||
| 		result.Hashes.resize( num ); | ||||
| 		result.Hashes.fill( 0, num, -1); | ||||
|  | ||||
| 		result.Entries = Array<Entry>::init_reserve( allocator, num ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	void clear( void ) | ||||
| 	{ | ||||
| 		for ( sw idx = 0; idx < Hashes.num(); idx++ ) | ||||
| 			Hashes[idx] = -1; | ||||
|  | ||||
| 		Hashes.clear(); | ||||
| 		Entries.clear(); | ||||
| 		Hashes.fill( 0, Hashes.num(), -1); | ||||
| 	} | ||||
|  | ||||
| 	void destroy( void ) | ||||
| @@ -1901,32 +1897,19 @@ struct HashTable | ||||
|  | ||||
| 	void rehash( sw new_num ) | ||||
| 	{ | ||||
| 		sw idx; | ||||
| 		sw last_added_index; | ||||
|  | ||||
| 		HashTable<Type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num ); | ||||
|  | ||||
| 		Array<sw>::Header* hash_header = new_ht.Hashes.get_header(); | ||||
|  | ||||
| 		for ( idx = 0; idx < new_ht.Hashes.num(); ++idx ) | ||||
| 			new_ht.Hashes[idx] = -1; | ||||
|  | ||||
| 		for ( idx = 0; idx < Entries.num(); ++idx ) | ||||
| 		for ( sw idx = 0; idx < Entries.num(); ++idx ) | ||||
| 		{ | ||||
| 			Entry& entry = Entries[idx]; | ||||
|  | ||||
| 			FindResult find_result; | ||||
|  | ||||
| 			if ( new_ht.Hashes.num() == 0 ) | ||||
| 				new_ht.grow(); | ||||
|  | ||||
| 			entry            = Entries[idx]; | ||||
| 			Entry& entry     = Entries[idx]; | ||||
| 			find_result      = new_ht.find( entry.Key ); | ||||
| 			last_added_index = new_ht.add_entry( entry.Key ); | ||||
|  | ||||
| 			if ( find_result.PrevIndex < 0 ) | ||||
| 				new_ht.Hashes[find_result.HashIndex] = last_added_index; | ||||
|  | ||||
| 			else | ||||
| 				new_ht.Entries[find_result.PrevIndex].Next = last_added_index; | ||||
|  | ||||
| @@ -1984,11 +1967,10 @@ struct HashTable | ||||
| 		sw         idx; | ||||
| 		FindResult find_result; | ||||
|  | ||||
| 		if ( Hashes.num() == 0 ) | ||||
| 		if ( full() ) | ||||
| 			grow(); | ||||
|  | ||||
| 		find_result = find( key ); | ||||
|  | ||||
| 		if ( find_result.EntryIndex >= 0 ) | ||||
| 		{ | ||||
| 			idx = find_result.EntryIndex; | ||||
| @@ -2060,7 +2042,9 @@ protected: | ||||
|  | ||||
| 	b32 full() | ||||
| 	{ | ||||
| 		return 0.75f * Hashes.num() < Entries.num(); | ||||
| 		uw critical_load = uw( CriticalLoadScale * f32(Hashes.num()) ); | ||||
| 		b32 result = Entries.num() > critical_load; | ||||
| 		return result; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @@ -2096,7 +2080,7 @@ struct StrC | ||||
| #define txt( text )              \ | ||||
| 	StrC                         \ | ||||
| 	{                            \ | ||||
| 		sizeof( text ) - 1, text \ | ||||
| 		sizeof( (text) ) - 1, (text) \ | ||||
| 	} | ||||
|  | ||||
| StrC to_str( char const* str ) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user