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", | 			"Name": "VisualStudioSourceCodeAccess", | ||||||
| 			"Enabled": true | 			"Enabled": true | ||||||
| 		}, | 		}, | ||||||
| 		{ |  | ||||||
| 			"Name": "GitSourceControl", |  | ||||||
| 			"Enabled": true |  | ||||||
| 		}, |  | ||||||
| 		{ | 		{ | ||||||
| 			"Name": "SlateInsights", | 			"Name": "SlateInsights", | ||||||
| 			"Enabled": true | 			"Enabled": true | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
| <?xml version="1.0" encoding="utf-8" ?> | <?xml version="1.0" encoding="utf-8" ?> | ||||||
| <Configuration xmlns="https://www.unrealengine.com/BuildConfiguration"> | <Configuration xmlns="https://www.unrealengine.com/BuildConfiguration"> | ||||||
|  | 	<bUsePCHFiles>false</bUsePCHFiles> | ||||||
|  | 	 | ||||||
| </Configuration> | </Configuration> | ||||||
|   | |||||||
| @@ -8,34 +8,31 @@ | |||||||
|  |  | ||||||
| UGasaAttributeSet::UGasaAttributeSet() | UGasaAttributeSet::UGasaAttributeSet() | ||||||
| { | { | ||||||
| 	InitHealth( 50.f ); | 	InitHealth( 100.f ); | ||||||
| 	InitMaxHealth( 100.f ); | 	InitMaxHealth( 100.f ); | ||||||
| 	InitMana( 50.f ); | 	InitMana( 50.f ); | ||||||
| 	InitMaxMana( 50.f ); | 	InitMaxMana( 50.f ); | ||||||
| } | } | ||||||
| #pragma region Rep Notifies |  | ||||||
|  |  | ||||||
|  | #pragma region Rep Notifies | ||||||
| void UGasaAttributeSet::Client_OnRep_Health( FGameplayAttributeData& PrevHealth ) | void UGasaAttributeSet::Client_OnRep_Health( FGameplayAttributeData& PrevHealth ) | ||||||
| { | { | ||||||
| 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | ||||||
| 	static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, Health ) ); | 	static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, Health ) ); | ||||||
| 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), Health, PrevHealth ); | 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), Health, PrevHealth ); | ||||||
| } | } | ||||||
|  |  | ||||||
| void UGasaAttributeSet::Client_OnRep_MaxHealth( FGameplayAttributeData& PrevMaxHealth ) | void UGasaAttributeSet::Client_OnRep_MaxHealth( FGameplayAttributeData& PrevMaxHealth ) | ||||||
| { | { | ||||||
| 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | ||||||
| 	static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, MaxHealth ) ); | 	static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, MaxHealth ) ); | ||||||
| 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), MaxHealth, PrevMaxHealth ); | 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), MaxHealth, PrevMaxHealth ); | ||||||
| } | } | ||||||
|  |  | ||||||
| void UGasaAttributeSet::Client_OnRep_Mana( FGameplayAttributeData& PrevMana ) | void UGasaAttributeSet::Client_OnRep_Mana( FGameplayAttributeData& PrevMana ) | ||||||
| { | { | ||||||
| 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | ||||||
| 	static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, Mana ) ); | 	static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, Mana ) ); | ||||||
| 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), Mana, PrevMana ); | 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), Mana, PrevMana ); | ||||||
| } | } | ||||||
|  |  | ||||||
| void UGasaAttributeSet::Client_OnRep_MaxMana( FGameplayAttributeData& PrevMaxMana ) | void UGasaAttributeSet::Client_OnRep_MaxMana( FGameplayAttributeData& PrevMaxMana ) | ||||||
| { | { | ||||||
| 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | 	// From GAMEPLAYATTRIBUTE_REPNOTIFY | ||||||
| @@ -43,6 +40,7 @@ void UGasaAttributeSet::Client_OnRep_MaxMana( FGameplayAttributeData& PrevMaxMan | |||||||
| 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), MaxMana, PrevMaxMana ); | 	GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), MaxMana, PrevMaxMana ); | ||||||
| } | } | ||||||
| #pragma endregion Rep Notifies | #pragma endregion Rep Notifies | ||||||
|  |  | ||||||
| void UGasaAttributeSet::GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const | void UGasaAttributeSet::GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const | ||||||
| { | { | ||||||
| 	Super::GetLifetimeReplicatedProps( OutLifetimeProps ); | 	Super::GetLifetimeReplicatedProps( OutLifetimeProps ); | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ public: | |||||||
|  |  | ||||||
| 	UGasaAttributeSet(); | 	UGasaAttributeSet(); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	UFUNCTION() | 	UFUNCTION() | ||||||
| 	void Client_OnRep_Health( FGameplayAttributeData& PrevHealth ); | 	void Client_OnRep_Health( FGameplayAttributeData& PrevHealth ); | ||||||
| 	UFUNCTION() | 	UFUNCTION() | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ | |||||||
| #include "GasaAttributeSet.h" | #include "GasaAttributeSet.h" | ||||||
| #include "AbilitySystemComponent.h" | #include "AbilitySystemComponent.h" | ||||||
|  |  | ||||||
|  | #pragma region Attribute Setters | ||||||
| FORCEINLINE | FORCEINLINE | ||||||
| void UGasaAttributeSet::SetHealth( float NewVal ) | void UGasaAttributeSet::SetHealth( float NewVal ) | ||||||
| { | { | ||||||
| @@ -40,6 +41,7 @@ void UGasaAttributeSet::SetMaxMana( float NewVal ) | |||||||
| 		AbilityComp->SetNumericAttributeBase( GetMaxManaAttribute(), NewVal ); | 		AbilityComp->SetNumericAttributeBase( GetMaxManaAttribute(), NewVal ); | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  | #pragma endregion Attribute Setters | ||||||
|  |  | ||||||
| namespace Gasa | namespace Gasa | ||||||
| { | { | ||||||
|   | |||||||
| @@ -10,13 +10,13 @@ AGasaEffectActor::AGasaEffectActor() | |||||||
| 	RootComponent = CreateDefaultSubobject<USceneComponent>("Root"); | 	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 | 	FGameplayEffectContextHandle | ||||||
| 	Context = AS->MakeEffectContext(); | 	Context = AS->MakeEffectContext(); | ||||||
| 	Context.AddSourceObject(Target); | 	Context.AddSourceObject(Actor); | ||||||
| 	 | 	 | ||||||
| 	FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( EffectClass, 1.0f, Context ); | 	FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( EffectClass, 1.0f, Context ); | ||||||
| 	AS->ApplyGameplayEffectSpecToSelf( * Spec.Data ); | 	AS->ApplyGameplayEffectSpecToSelf( * Spec.Data ); | ||||||
|   | |||||||
| @@ -1,19 +1,23 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "GasaCommon.h" | #include "GasaCommon.h" | ||||||
|  | #include "Actors/GasaActor.h" | ||||||
|  | #include "GameFramework/Actor.h" | ||||||
|  |  | ||||||
| #include "GasaEffectActor.generated.h" | #include "GasaEffectActor.generated.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| UCLASS() | UCLASS() | ||||||
| class GASA_API AGasaEffectActor : public AActor | class GASA_API AGasaEffectActor : public AGasaActor | ||||||
| { | { | ||||||
| 	GENERATED_BODY() | 	GENERATED_BODY() | ||||||
| public: | public: | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, Category = "Applied Effects") | 	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects") | ||||||
| 	TSoftClassPtr<UGameplayEffect> InstantEffectClass; | 	TSoftClassPtr<UGameplayEffect> InstantEffectClass; | ||||||
| 	 | 	 | ||||||
| 	AGasaEffectActor(); | 	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.h" | ||||||
| #include "GasaAttributeSet_Inlines.h" | #include "GasaAttributeSet_Inlines.h" | ||||||
| #include "Components/SphereComponent.h" | #include "Components/SphereComponent.h" | ||||||
|  | #include "Components/StaticMeshComponent.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| AGasaEffectActorDemo::AGasaEffectActorDemo() | AGasaEffectActorDemo::AGasaEffectActorDemo() | ||||||
|   | |||||||
| @@ -1,12 +1,14 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "GasaCommon.h" | #include "GasaCommon.h" | ||||||
|  | #include "Actors/GasaActor.h" | ||||||
|  | #include "GameFramework/Actor.h" | ||||||
|  |  | ||||||
| #include "GasaEffectActorDemo.generated.h" | #include "GasaEffectActorDemo.generated.h" | ||||||
|  |  | ||||||
| // Old demonstration code used before part 37. | // Old demonstration code used before part 37. | ||||||
| UCLASS() | UCLASS() | ||||||
| class GASA_API AGasaEffectActorDemo : public AActor | class GASA_API AGasaEffectActorDemo : public AGasaActor | ||||||
| { | { | ||||||
| 	GENERATED_BODY() | 	GENERATED_BODY() | ||||||
| public: | public: | ||||||
|   | |||||||
| @@ -1,10 +1,12 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include "GasaActor.h" | ||||||
| #include "GasaCommon.h" | #include "GasaCommon.h" | ||||||
|  | #include "GameFramework/Actor.h" | ||||||
| #include "CameraMount.generated.h" | #include "CameraMount.generated.h" | ||||||
|  |  | ||||||
| UCLASS(Blueprintable) | UCLASS(Blueprintable) | ||||||
| class GASA_API ACameraMount : public AActor | class GASA_API ACameraMount : public AGasaActor | ||||||
| { | { | ||||||
| 	GENERATED_BODY() | 	GENERATED_BODY() | ||||||
| public: | 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/GasaAbilitySystemComponent.h" | ||||||
| #include "AbilitySystem/GasaAttributeSet.h" | #include "AbilitySystem/GasaAttributeSet.h" | ||||||
|  | #include "Components/SkeletalMeshComponent.h" | ||||||
|  | #include "Engine/PostProcessVolume.h" | ||||||
| #include "Game/GasaLevelScriptActor.h" | #include "Game/GasaLevelScriptActor.h" | ||||||
|  | #include "Materials/MaterialInstanceDynamic.h" | ||||||
|  |  | ||||||
| void AGasaCharacter::SetHighlight(EHighlight Desired) | void AGasaCharacter::SetHighlight(EHighlight Desired) | ||||||
| { | { | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
|  |  | ||||||
| #include "GasaCommon.h" | #include "GasaCommon.h" | ||||||
| #include "Game/GasaPlayerState.h" | #include "Game/GasaPlayerState.h" | ||||||
|  | #include "Networking/GasaNetLibrary.h" | ||||||
|  |  | ||||||
| #include "GasaCharacter.generated.h" | #include "GasaCharacter.generated.h" | ||||||
|  |  | ||||||
| @@ -59,6 +60,28 @@ public: | |||||||
| 	AGasaCharacter(); | 	AGasaCharacter(); | ||||||
|  |  | ||||||
| 	FORCEINLINE AGasaPlayerState* GetGasaPlayerState() { return GetPlayerState<AGasaPlayerState>(); } | 	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 | #pragma region IAbilitySystem | ||||||
| 	FORCEINLINE UAttributeSet*           GetAttributes()                            { return Attributes; } | 	FORCEINLINE UAttributeSet*           GetAttributes()                            { return Attributes; } | ||||||
|   | |||||||
| @@ -25,10 +25,13 @@ void APlayerCharacter::PossessedBy(AController* NewController) | |||||||
| 		AbilitySystem->InitAbilityActorInfo(PS, this); | 		AbilitySystem->InitAbilityActorInfo(PS, this); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	AGasaPlayerController* PC   = GetController<AGasaPlayerController>(); | 	if (IsLocallyControlled()) | ||||||
| 	AGasaHUD*              HUD  = PC->GetHUD<AGasaHUD>(); | 	{ | ||||||
| 	FWidgetControllerData  Data = { PC, PS, AbilitySystem, Attributes }; | 		AGasaPlayerController* PC   = GetController<AGasaPlayerController>(); | ||||||
| 	HUD->InitHostWidget(& Data); | 		AGasaHUD*              HUD  = PC->GetHUD<AGasaHUD>(); | ||||||
|  | 		FWidgetControllerData  Data = { PC, PS, AbilitySystem, Attributes }; | ||||||
|  | 		HUD->InitHostWidget(& Data); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // TODO(Ed): We need to setup Net Slime... | // TODO(Ed): We need to setup Net Slime... | ||||||
|   | |||||||
| @@ -1,5 +1,84 @@ | |||||||
| #include "GasaGameInstance.h" | #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() | void UGasaGameInstance::Init() | ||||||
| { | { | ||||||
| 	Super::Init(); | 	Super::Init(); | ||||||
| @@ -7,5 +86,6 @@ void UGasaGameInstance::Init() | |||||||
| 	DevOptionsCache.CachedDevOptions(); | 	DevOptionsCache.CachedDevOptions(); | ||||||
|  |  | ||||||
| 	using namespace Gasa; | 	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 | #pragma once | ||||||
|  |  | ||||||
| #include "GasaCommon.h" | #include "Networking/GasaNetLibrary.h" | ||||||
| #include "GasaDevOptionsCache.h" | #include "GasaDevOptionsCache.h" | ||||||
|  | #include "Engine/Engine.h" | ||||||
|  |  | ||||||
|  | #include "Engine/GameInstance.h" | ||||||
| #include "GasaGameInstance.generated.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) | UCLASS(Blueprintable) | ||||||
| class GASA_API UGasaGameInstance : public UGameInstance | class GASA_API UGasaGameInstance : public UGameInstance | ||||||
| { | { | ||||||
| @@ -14,6 +36,55 @@ public: | |||||||
| 	UPROPERTY(VisibleAnywhere, Category="Dev Cache") | 	UPROPERTY(VisibleAnywhere, Category="Dev Cache") | ||||||
| 	FGasaDevOptionsCache DevOptionsCache; | 	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 | #pragma region GameInstance | ||||||
| 	void Init() override; | 	void Init() override; | ||||||
| #pragma endregion GameInstance | #pragma endregion GameInstance | ||||||
|   | |||||||
| @@ -1,2 +1,454 @@ | |||||||
| #include "GasaGameMode.h" | #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,28 +1,102 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "GameFramework/GameMode.h" | #include "GameFramework/GameMode.h" | ||||||
|  |  | ||||||
| #include "GasaCommon.h" | #include "GasaCommon.h" | ||||||
|  | #include "Networking/GasaNetLibrary_Inlines.h" | ||||||
|  | #include "Engine/Engine.h" | ||||||
|  |  | ||||||
| #include "GasaGameMode.generated.h" | #include "GasaGameMode.generated.h" | ||||||
|  |  | ||||||
| UCLASS(Blueprintable) | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLogoutSig, AGasaPlayerController*, PC); | ||||||
|  |  | ||||||
|  | UCLASS( Blueprintable ) | ||||||
| class GASA_API AGasaGameMode : public AGameMode | class GASA_API AGasaGameMode : public AGameMode | ||||||
| { | { | ||||||
| 	GENERATED_BODY() | 	GENERATED_BODY() | ||||||
| public: | 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 | namespace Gasa | ||||||
| { | { | ||||||
| 	inline | 	inline AGasaGameMode* GetGameMode( UObject* Context ) | ||||||
| 	AGasaGameMode* GetGameMode(UObject* Context) |  | ||||||
| 	{ | 	{ | ||||||
| 		UWorld* World = GEngine->GetWorldFromContextObject(Context, EGetWorldErrorMode::LogAndReturnNull); | 		UWorld* World = GEngine->GetWorldFromContextObject( Context, EGetWorldErrorMode::LogAndReturnNull ); | ||||||
| 		if (World == nullptr) | 		if ( World == nullptr ) | ||||||
| 		{ | 		{ | ||||||
| 			Log("World is null... are you running in a proper context?", ELogV::Error); | 			Log( "World is null... are you running in a proper context?", ELogV::Error ); | ||||||
| 			return nullptr; | 			return nullptr; | ||||||
| 		} | 		} | ||||||
| 		return Cast<AGasaGameMode>(World->GetAuthGameMode()); | 		return Cast<AGasaGameMode>( World->GetAuthGameMode() ); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,6 +2,10 @@ | |||||||
|  |  | ||||||
| #include "CogAll.h" | #include "CogAll.h" | ||||||
| #include "CogWindowManager.h" | #include "CogWindowManager.h" | ||||||
|  | #include "GasaPlayerState.h" | ||||||
|  | #include "GasaGameInstance.h" | ||||||
|  | #include "Net/UnrealNetwork.h" | ||||||
|  | using namespace Gasa; | ||||||
|  |  | ||||||
| AGasaGameState::AGasaGameState() | AGasaGameState::AGasaGameState() | ||||||
| { | { | ||||||
| @@ -9,11 +13,92 @@ AGasaGameState::AGasaGameState() | |||||||
|     PrimaryActorTick.bCanEverTick = true; |     PrimaryActorTick.bCanEverTick = true; | ||||||
|     PrimaryActorTick.SetTickFunctionEnable(true); |     PrimaryActorTick.SetTickFunctionEnable(true); | ||||||
|     PrimaryActorTick.bStartWithTickEnabled = 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() | 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 | #if ENABLE_COG | ||||||
|     CogWindowManager = NewObject<UCogWindowManager>(this); |     CogWindowManager = NewObject<UCogWindowManager>(this); | ||||||
|     CogWindowManagerRef = CogWindowManager; |     CogWindowManagerRef = CogWindowManager; | ||||||
| @@ -23,6 +108,28 @@ void AGasaGameState::BeginPlay() | |||||||
| #endif //ENABLE_COG | #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) | void AGasaGameState::Tick(float DeltaSeconds) | ||||||
| { | { | ||||||
| 	Super::Tick(DeltaSeconds); | 	Super::Tick(DeltaSeconds); | ||||||
| @@ -31,4 +138,14 @@ void AGasaGameState::Tick(float DeltaSeconds) | |||||||
|     CogWindowManager->Tick(DeltaSeconds); |     CogWindowManager->Tick(DeltaSeconds); | ||||||
| #endif //ENABLE_COG | #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,46 +1,116 @@ | |||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "GameFramework/GameState.h" | #include "GameFramework/GameState.h" | ||||||
|  |  | ||||||
| #include "GasaCommon.h" | #include "GasaCommon.h" | ||||||
|  | #include "Engine/Engine.h" | ||||||
|  | #include "Networking/GasaNetLibrary.h" | ||||||
|  |  | ||||||
| #include "GasaGameState.generated.h" | #include "GasaGameState.generated.h" | ||||||
|  |  | ||||||
| UCLASS(Blueprintable) | 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 | class GASA_API AGasaGameState : public AGameState | ||||||
| { | { | ||||||
| 	GENERATED_BODY() | 	GENERATED_BODY() | ||||||
| public: | public: | ||||||
| #pragma region Cog | #pragma region Cog | ||||||
|     // To make sure it doesn't get garbage collected. | 	// To make sure it doesn't get garbage collected. | ||||||
|     UPROPERTY() | 	UPROPERTY() | ||||||
|     TObjectPtr<UObject> CogWindowManagerRef; | 	TObjectPtr<UObject> CogWindowManagerRef; | ||||||
| 	 |  | ||||||
| #if ENABLE_COG | #if ENABLE_COG | ||||||
| 	TObjectPtr<UCogWindowManager> CogWindowManager; | 	TObjectPtr<UCogWindowManager> CogWindowManager; | ||||||
| #endif // ENABLE_COG | #endif | ||||||
|  | // ENABLE_COG | ||||||
| #pragma endregion Cog | #pragma endregion Cog | ||||||
|  |  | ||||||
| 	AGasaGameState(); | 	AGasaGameState(); | ||||||
|  |  | ||||||
|  | #pragma region GameFramework | ||||||
|  | 	UFUNCTION() | ||||||
|  | 	void OnGameFrameworkInitialized(); | ||||||
|  |  | ||||||
|  | 	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 | #pragma region GameState | ||||||
| 	void BeginPlay() override; | 	void HandleBeginPlay() override; | ||||||
|  | #pragma endregion GameState | ||||||
|  |  | ||||||
| 	void Tick(float DeltaSeconds) override; | #pragma region GameStateBase | ||||||
| #pragma endregion GameState	 | 	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 | namespace Gasa | ||||||
| { | { | ||||||
| 	inline | 	inline AGasaGameState* GetGameState( UObject* Context ) | ||||||
| 	AGasaGameState* GetGameState(UObject* Context) |  | ||||||
| 	{ | 	{ | ||||||
| 		UWorld* World = GEngine->GetWorldFromContextObject(Context, EGetWorldErrorMode::LogAndReturnNull); | 		UWorld* World = GEngine->GetWorldFromContextObject( Context, EGetWorldErrorMode::LogAndReturnNull ); | ||||||
| 		if (World == nullptr) | 		if ( World == nullptr ) | ||||||
| 		{ | 		{ | ||||||
| 			Log("World is null... are you running in a proper context?", ELogV::Error); | 			Log( "World is null... are you running in a proper context?", ELogV::Error ); | ||||||
| 			return nullptr; | 			return nullptr; | ||||||
| 		} | 		} | ||||||
| 		return Cast<AGasaGameState>(World->GetGameState()); | 		return Cast<AGasaGameState>( World->GetGameState() ); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,11 +1,39 @@ | |||||||
| #include "GasaLevelScriptActor.h" | #include "GasaLevelScriptActor.h" | ||||||
|  |  | ||||||
| #include "GasaDevOptions.h" | #include "GasaDevOptions.h" | ||||||
|  | #include "GasaGameInstance.h" | ||||||
|  | #include "Engine/PostProcessVolume.h" | ||||||
| #include "Kismet/GameplayStatics.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() | void AGasaLevelScriptActor::BeginPlay() | ||||||
| { | { | ||||||
| 	Super::BeginPlay(); | 	Super::BeginPlay(); | ||||||
|  | 	NetLog("BeginPlay"); | ||||||
|  |  | ||||||
| 	using namespace Gasa; | 	using namespace Gasa; | ||||||
|  |  | ||||||
| @@ -21,4 +49,12 @@ void AGasaLevelScriptActor::BeginPlay() | |||||||
| 		PPV->Settings.WeightedBlendables.Array[0].Object = MID; | 		PPV->Settings.WeightedBlendables.Array[0].Object = MID; | ||||||
| 		break; | 		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 | #pragma once | ||||||
|  | #include "GasaCommon.h" | ||||||
|  | #include "Engine/Engine.h" | ||||||
|  |  | ||||||
| #include "Engine/LevelScriptActor.h" | #include "Engine/LevelScriptActor.h" | ||||||
|  | #include "Networking/GasaNetLibrary.h" | ||||||
| #include "GasaCommon.h" |  | ||||||
|  |  | ||||||
| #include "GasaLevelScriptActor.generated.h" | #include "GasaLevelScriptActor.generated.h" | ||||||
|  |  | ||||||
| @@ -14,6 +15,41 @@ public: | |||||||
|     UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Post Process") |     UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Post Process") | ||||||
|     TObjectPtr<APostProcessVolume> GlobalPPV; |     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 | #pragma region Actor | ||||||
|     void BeginPlay() override; |     void BeginPlay() override; | ||||||
| #pragma region endActor | #pragma region endActor | ||||||
|   | |||||||
| @@ -155,19 +155,22 @@ void AGasaPlayerController::BeginPlay() | |||||||
| { | { | ||||||
| 	Super::BeginPlay(); | 	Super::BeginPlay(); | ||||||
|  |  | ||||||
| 	check(IMC); | 	if (IsLocalController()) | ||||||
| 	 |  | ||||||
| 	UEnhancedInputLocalPlayerSubsystem* |  | ||||||
| 	EILP_Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()); |  | ||||||
| 	check(EILP_Subsystem); |  | ||||||
| 	EILP_Subsystem->AddMappingContext(IMC, 0); |  | ||||||
| 	{ | 	{ | ||||||
| 		bShowMouseCursor   = true; | 		check(IMC); | ||||||
| 		DefaultMouseCursor = EMouseCursor::Default; | 		 | ||||||
| 		FInputModeGameAndUI MouseMode; | 		UEnhancedInputLocalPlayerSubsystem* | ||||||
| 		MouseMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock); | 		EILP_Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()); | ||||||
| 		MouseMode.SetHideCursorDuringCapture(false); | 		check(EILP_Subsystem); | ||||||
| 		SetInputMode(MouseMode); | 		EILP_Subsystem->AddMappingContext(IMC, 0); | ||||||
|  | 		{ | ||||||
|  | 			bShowMouseCursor   = true; | ||||||
|  | 			DefaultMouseCursor = EMouseCursor::Default; | ||||||
|  | 			FInputModeGameAndUI MouseMode; | ||||||
|  | 			MouseMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock); | ||||||
|  | 			MouseMode.SetHideCursorDuringCapture(false); | ||||||
|  | 			SetInputMode(MouseMode); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,9 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "GasaCommon.h" | #include "GasaCommon.h" | ||||||
|  | #include "Engine/Engine.h" | ||||||
| #include "GameFramework/PlayerController.h" | #include "GameFramework/PlayerController.h" | ||||||
|  | #include "Networking/GasaNetLibrary.h" | ||||||
|  |  | ||||||
| #include "GasaPlayerController.generated.h" | #include "GasaPlayerController.generated.h" | ||||||
|  |  | ||||||
| @@ -51,12 +53,33 @@ public: | |||||||
| 	AGasaPlayerController(); | 	AGasaPlayerController(); | ||||||
|  |  | ||||||
| 	inline AGasaPlayerState* GetPlayerState(); | 	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 | #pragma region PlayerController | ||||||
| 	void SpawnDefaultHUD() override; | 	void SpawnDefaultHUD() override; | ||||||
| 	 | 	 | ||||||
| 	void OnPossess(APawn* InPawn) override; | 	void OnPossess(APawn* InPawn) override; | ||||||
|  |  | ||||||
| 	void OnUnPossess() override; | 	void OnUnPossess() override; | ||||||
| 	 | 	 | ||||||
| 	void PlayerTick(float DeltaTime) override; | 	void PlayerTick(float DeltaTime) override; | ||||||
|   | |||||||
| @@ -5,6 +5,8 @@ | |||||||
|  |  | ||||||
| AGasaPlayerState::AGasaPlayerState() | AGasaPlayerState::AGasaPlayerState() | ||||||
| { | { | ||||||
|  | 	bAutoAbilitySystem = true; | ||||||
|  | 	 | ||||||
| 	AbilitySystem = CreateDefaultSubobject<UGasaAbilitySystemComp>("Ability System"); | 	AbilitySystem = CreateDefaultSubobject<UGasaAbilitySystemComp>("Ability System"); | ||||||
| 	AbilitySystem->SetIsReplicated(true); | 	AbilitySystem->SetIsReplicated(true); | ||||||
| 	AbilitySystem->SetReplicationMode(EGameplayEffectReplicationMode::Mixed); | 	AbilitySystem->SetReplicationMode(EGameplayEffectReplicationMode::Mixed); | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| #include "GameFramework/PlayerState.h" | #include "GameFramework/PlayerState.h" | ||||||
|  |  | ||||||
| #include "GasaCommon.h" | #include "GasaCommon.h" | ||||||
|  | #include "Networking/GasaNetLibrary.h" | ||||||
|  |  | ||||||
| #include "GasaPlayerState.generated.h" | #include "GasaPlayerState.generated.h" | ||||||
|  |  | ||||||
| @@ -16,7 +17,7 @@ class GASA_API AGasaPlayerState : public APlayerState | |||||||
| public: | public: | ||||||
| #pragma region Ability System | #pragma region Ability System | ||||||
| 	UPROPERTY(EditAnywhere, Category="Ability System") | 	UPROPERTY(EditAnywhere, Category="Ability System") | ||||||
| 	bool bAutoAbilitySystem = true; | 	bool bAutoAbilitySystem; | ||||||
| 	 | 	 | ||||||
| 	UPROPERTY(EditAnywhere, Category="Ability System") | 	UPROPERTY(EditAnywhere, Category="Ability System") | ||||||
| 	TObjectPtr<UAbilitySystemComponent> AbilitySystem; | 	TObjectPtr<UAbilitySystemComponent> AbilitySystem; | ||||||
| @@ -27,6 +28,28 @@ public: | |||||||
| 	 | 	 | ||||||
| 	AGasaPlayerState(); | 	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 | #pragma region IAbilitySystem | ||||||
| 	FORCEINLINE UAttributeSet*           GetAttributes()                            { return Attributes; } | 	FORCEINLINE UAttributeSet*           GetAttributes()                            { return Attributes; } | ||||||
| 	FORCEINLINE UAbilitySystemComponent* GetAbilitySystemComponent() const override { return AbilitySystem; } | 	FORCEINLINE UAbilitySystemComponent* GetAbilitySystemComponent() const override { return AbilitySystem; } | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
|  | using UnrealBuildTool; | ||||||
| using ModuleRules = UnrealBuildTool.ModuleRules; | using ModuleRules = UnrealBuildTool.ModuleRules; | ||||||
| using ReadOnlyTargetRules = UnrealBuildTool.ReadOnlyTargetRules; | using ReadOnlyTargetRules = UnrealBuildTool.ReadOnlyTargetRules; | ||||||
| using TargetRules = UnrealBuildTool.TargetRules; | using TargetRules = UnrealBuildTool.TargetRules; | ||||||
| @@ -10,7 +10,33 @@ public class Gasa : ModuleRules | |||||||
| { | { | ||||||
|     public Gasa(ReadOnlyTargetRules Target) : base(Target) |     public Gasa(ReadOnlyTargetRules Target) : base(Target) | ||||||
|     { |     { | ||||||
| 	    bUseUnity = false; | 	    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 |     #region Engine | ||||||
|         PrivateIncludePathModuleNames.AddRange(new string[] { |         PrivateIncludePathModuleNames.AddRange(new string[] { | ||||||
| @@ -32,6 +58,7 @@ public class Gasa : ModuleRules | |||||||
|             "InputCore",  |             "InputCore",  | ||||||
|             "NetCore", |             "NetCore", | ||||||
|             "Niagara", |             "Niagara", | ||||||
|  |             "OnlineSubsystem", | ||||||
|             "SlateCore", |             "SlateCore", | ||||||
|             "UMG",  |             "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" | #include "GasaEngineMinimal.h" | ||||||
| // #define private protected |  | ||||||
|  |  | ||||||
| #define global         | #define global         | ||||||
| #define internal      static | #define internal      static | ||||||
| #define local_persist 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 | #pragma region Math | ||||||
| #define m_pow2( value ) (value * value) | #define m_pow2( value ) (value * value) | ||||||
| #pragma endregion Math | #pragma endregion Math | ||||||
| @@ -16,6 +19,9 @@ | |||||||
| struct FInputActionValue; | struct FInputActionValue; | ||||||
| struct FOnAttributeChangeData; | struct FOnAttributeChangeData; | ||||||
|  |  | ||||||
|  | class AActor; | ||||||
|  | class APostProcessVolume; | ||||||
|  |  | ||||||
| class IAbilitySystemInterface; | class IAbilitySystemInterface; | ||||||
|  |  | ||||||
| class UAbilitySystemComponent; | class UAbilitySystemComponent; | ||||||
| @@ -45,11 +51,13 @@ class AGasaGameState; | |||||||
| class AGasaLevelScriptActor; | class AGasaLevelScriptActor; | ||||||
| class AGasaPlayerController; | class AGasaPlayerController; | ||||||
| class AGasaPlayerState; | class AGasaPlayerState; | ||||||
|  | class APlayerCharacter; | ||||||
|  |  | ||||||
| class UGasaAbilitySystemComp; | class UGasaAbilitySystemComp; | ||||||
| class UGasaAttributeSet; | class UGasaAttributeSet; | ||||||
| class UGasaDevOptions; | class UGasaDevOptions; | ||||||
| class UGasaImage; | class UGasaImage; | ||||||
|  | class UGasaObject; | ||||||
| class UGasaOverlay; | class UGasaOverlay; | ||||||
| class UGasaProgressBar; | class UGasaProgressBar; | ||||||
| class UGasaSizeBox; | class UGasaSizeBox; | ||||||
| @@ -58,6 +66,21 @@ class UHUDHostWidget; | |||||||
| class UWidgetController; | class UWidgetController; | ||||||
| #pragma endregion Forwards | #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 | #pragma region Logging | ||||||
| // Straight from the Engine | // Straight from the Engine | ||||||
| UENUM(BlueprintType) | UENUM(BlueprintType) | ||||||
| @@ -107,7 +130,6 @@ namespace Gasa | |||||||
| { | { | ||||||
| 	using ELogV = EGasaVerbosity; | 	using ELogV = EGasaVerbosity; | ||||||
|  |  | ||||||
| 	//◞ ‸ ◟// |  | ||||||
| 	// Works for Unreal 5.4, Win64 MSVC (untested in other scenarios, for now) | 	// Works for Unreal 5.4, Win64 MSVC (untested in other scenarios, for now) | ||||||
| 	inline | 	inline | ||||||
| 	void Log( FString Message, EGasaVerbosity Verbosity = EGasaVerbosity::Log | 	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/GasaGameState.h" | ||||||
| #include "Game/GasaPlayerController.h" | #include "Game/GasaPlayerController.h" | ||||||
| #include "Kismet/KismetSystemLibrary.h" | #include "Kismet/KismetSystemLibrary.h" | ||||||
|  | #include "Misc/ConfigCacheIni.h" | ||||||
|  |  | ||||||
| #pragma region Game | #pragma region Game | ||||||
| UGasaDevOptions* UGasaLib::GetGasaDevOptions(UObject* Context) { | UGasaDevOptions* UGasaLib::GetGasaDevOptions(UObject* Context) { | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "GasaCommon.h" | #include "GasaCommon.h" | ||||||
|  | #include "Kismet/BlueprintFunctionLibrary.h" | ||||||
|  |  | ||||||
| #include "GasaLibrary.Generated.h" | #include "GasaLibrary.Generated.h" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "Modules/ModuleInterface.h" | #include "Modules/ModuleInterface.h" | ||||||
|  | #include "Modules/ModuleManager.h" | ||||||
|  |  | ||||||
| class GASA_API FGasaModule : public IModuleInterface | 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.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 | namespace Gasa | ||||||
| { | { | ||||||
| @@ -12,6 +30,32 @@ namespace Gasa | |||||||
| 	constexpr float NetCullDist_VeryFar   = 10000.0f * 10000.0f; | 	constexpr float NetCullDist_VeryFar   = 10000.0f * 10000.0f; | ||||||
| 	constexpr float NetCullDist_VisualMax = 15000.0f * 15000.0f; | 	constexpr float NetCullDist_VisualMax = 15000.0f * 15000.0f; | ||||||
|  |  | ||||||
| 	#define DOREPLIFETIME_DEFAULT_GAS(Class, ReplicatedVar) \ | 	void DrawNetCullingSphere(UObject const* Context, float Duration, float Thickness); | ||||||
| 		DOREPLIFETIME_CONDITION_NOTIFY(Class, ReplicatedVar, COND_None, REPNOTIFY_Always) |  | ||||||
|  | 	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; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -8,10 +8,10 @@ using namespace Gasa; | |||||||
|  |  | ||||||
| void AGasaHUD::InitHostWidget(FWidgetControllerData const* WidgetControllerData) | void AGasaHUD::InitHostWidget(FWidgetControllerData const* WidgetControllerData) | ||||||
| { | { | ||||||
| 	HostWidget = CreateWidget<UHUDHostWidget>( GetWorld()  | 	HostWidget = CreateWidget<UHUDHostWidget>( GetWorld()   | ||||||
| 		, GetDevOptions()->Template_HUD_HostUI.LoadSynchronous() ); | 		, GetDevOptions()->Template_HUD_HostUI.LoadSynchronous() ); | ||||||
|  |  | ||||||
| 	HostWidgetController = NewObject<UHostWidgetController>(this, GetDevOptions()->Template_HostWidgetController.Get()); | 	HostWidgetController       = NewObject<UHostWidgetController>(this, GetDevOptions()->Template_HostWidgetController.Get()); | ||||||
| 	HostWidgetController->Data = (* WidgetControllerData); | 	HostWidgetController->Data = (* WidgetControllerData); | ||||||
| 	HostWidget->SetWidgetController(HostWidgetController); | 	HostWidget->SetWidgetController(HostWidgetController); | ||||||
| 	HostWidgetController->BindCallbacksToDependencies(); | 	HostWidgetController->BindCallbacksToDependencies(); | ||||||
|   | |||||||
| @@ -3,6 +3,9 @@ | |||||||
| #include "AbilitySystem/GasaAttributeSet.h" | #include "AbilitySystem/GasaAttributeSet.h" | ||||||
| #include "GameplayEffectTypes.h" | #include "GameplayEffectTypes.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #pragma region Attribute Changed Callbacks | #pragma region Attribute Changed Callbacks | ||||||
| // Attribute Changed Callbacks are generated by GasaGen/GasaGen_HostWidgetController.cpp | // Attribute Changed Callbacks are generated by GasaGen/GasaGen_HostWidgetController.cpp | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ using System; | |||||||
| using System.Diagnostics; | using System.Diagnostics; | ||||||
| using System.IO; | using System.IO; | ||||||
| using System.Runtime; | using System.Runtime; | ||||||
|  | using UnrealBuildTool; | ||||||
| using BuildSettingsVersion = UnrealBuildTool.BuildSettingsVersion; | using BuildSettingsVersion = UnrealBuildTool.BuildSettingsVersion; | ||||||
| using TargetInfo = UnrealBuildTool.TargetInfo; | using TargetInfo = UnrealBuildTool.TargetInfo; | ||||||
| using TargetRules = UnrealBuildTool.TargetRules; | using TargetRules = UnrealBuildTool.TargetRules; | ||||||
| @@ -17,6 +18,7 @@ public class GasaEditorTarget : TargetRules | |||||||
|          |          | ||||||
|         bUseUnityBuild = true; |         bUseUnityBuild = true; | ||||||
|         // bUseXGEController = false; |         // bUseXGEController = false; | ||||||
|  |         LinkType = TargetLinkType.Modular; | ||||||
|          |          | ||||||
| 		ExtraModuleNames.Add("Gasa"); | 		ExtraModuleNames.Add("Gasa"); | ||||||
| 		ExtraModuleNames.Add("GasaEditor"); | 		ExtraModuleNames.Add("GasaEditor"); | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ using namespace gen; | |||||||
| #include "GasaGen_ChangeBPActionMenu.cpp" | #include "GasaGen_ChangeBPActionMenu.cpp" | ||||||
| #include "GasaGen_DevOptionsCache.cpp" | #include "GasaGen_DevOptionsCache.cpp" | ||||||
| #include "GasaGen_HostWidgetController.cpp" | #include "GasaGen_HostWidgetController.cpp" | ||||||
|  | #include "GasaGen_NetSlime.cpp" | ||||||
|  |  | ||||||
| int gen_main() | int gen_main() | ||||||
| { | { | ||||||
| @@ -80,6 +81,7 @@ int gen_main() | |||||||
| 	gen_UGasaAttributeSet(); | 	gen_UGasaAttributeSet(); | ||||||
| 	gen_FGasaDevOptionsCache(); | 	gen_FGasaDevOptionsCache(); | ||||||
| 	gen_UHostWidgetController(); | 	gen_UHostWidgetController(); | ||||||
|  | 	// gen_netslime_interfaces(); | ||||||
|  |  | ||||||
| 	// One offs | 	// One offs | ||||||
| 	if (0) | 	if (0) | ||||||
|   | |||||||
| @@ -13,6 +13,9 @@ using namespace gen; | |||||||
| #define path_config              path_source      "Config/" | #define path_config              path_source      "Config/" | ||||||
| #define path_module_gasa         path_source      "Gasa/" | #define path_module_gasa         path_source      "Gasa/" | ||||||
| #define path_gasa_ability_system path_module_gasa "AbilitySystem/" | #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/" | #define path_gasa_ui             path_module_gasa "UI/" | ||||||
|  |  | ||||||
| constexpr StrC str_DECLARE_CLASS                                         = txt("DECLARE_CLASS("); | 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 ) | 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 ) | 	for ( String property : properties ) | ||||||
| 	{ | 	{ | ||||||
| 		CodeFn generated_get_attribute = parse_function( | 		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( generated_get_attribute ); | ||||||
| 	} | 	} | ||||||
|  | 	body.append(def_pragma( txt("endregion Attribute Setters"))); | ||||||
| } | } | ||||||
|  |  | ||||||
| void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties ) | 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 ) | void impl_attribute_fields( CodeBody body, StrC class_name, Array<StringCached> properties ) | ||||||
| { | { | ||||||
|  | 	body.append(fmt_newline); | ||||||
| 	body.append(def_pragma( txt("region Rep Notifies"))); | 	body.append(def_pragma( txt("region Rep Notifies"))); | ||||||
| 	for ( String property : properties ) | 	for ( String property : properties ) | ||||||
| 	{ | 	{ | ||||||
| 		body.append(fmt_newline); |  | ||||||
|  |  | ||||||
| 		CodeFn field_impl = parse_function( token_fmt( | 		CodeFn field_impl = parse_function( token_fmt( | ||||||
| 			"class_name", class_name, "property", (StrC)property, "from_notice", txt("\n// From GAMEPLAYATTRIBUTE_REPNOTIFY\n"), | 			"class_name", class_name, "property", (StrC)property, "from_notice", txt("\n// From GAMEPLAYATTRIBUTE_REPNOTIFY\n"), | ||||||
| 		stringize( | 		stringize( | ||||||
| @@ -326,6 +327,7 @@ void impl_attribute_fields( CodeBody body, StrC class_name, Array<StringCached> | |||||||
| 		body.append( field_impl ); | 		body.append( field_impl ); | ||||||
| 	} | 	} | ||||||
| 	body.append( def_pragma( txt("endregion Rep Notifies"))); | 	body.append( def_pragma( txt("endregion Rep Notifies"))); | ||||||
|  | 	body.append(fmt_newline); | ||||||
| } | } | ||||||
|  |  | ||||||
| inline | inline | ||||||
|   | |||||||
| @@ -1610,7 +1610,7 @@ void CodeConstructor::to_string_fwd( String& result ) | |||||||
| 	if ( ast->InlineCmt ) | 	if ( ast->InlineCmt ) | ||||||
| 		result.append_fmt( "; // %S\n", ast->InlineCmt->Content ); | 		result.append_fmt( "; // %S\n", ast->InlineCmt->Content ); | ||||||
| 	else | 	else | ||||||
| 		result.append( ";" ); | 		result.append( ";\n" ); | ||||||
| } | } | ||||||
|  |  | ||||||
| String CodeClass::to_string() | String CodeClass::to_string() | ||||||
| @@ -6278,6 +6278,16 @@ namespace parser | |||||||
| 			move_forward(); | 			move_forward(); | ||||||
| 			preprocess_content.Length++; | 			preprocess_content.Length++; | ||||||
|  |  | ||||||
|  | 			if ( current == '\r' && scanner[1] == '\n' ) | ||||||
|  | 			{ | ||||||
|  | 				move_forward(); | ||||||
|  | 				move_forward(); | ||||||
|  | 			} | ||||||
|  | 			else if ( current == '\n' ) | ||||||
|  | 			{ | ||||||
|  | 				move_forward(); | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			Tokens.append( preprocess_content ); | 			Tokens.append( preprocess_content ); | ||||||
| 			return Lex_Continue;    // Skip found token, its all handled here. | 			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 ) ); | 		Tokens            = Array<Token>::init_reserve( LexArena, ( LexAllocator_Size - sizeof( Array<Token>::Header ) ) / sizeof( Token ) ); | ||||||
|  |  | ||||||
| 		defines_map_arena = Arena_256KB::init(); | 		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() | 	internal void deinit() | ||||||
|   | |||||||
| @@ -1663,7 +1663,7 @@ struct Array | |||||||
| 	{ | 	{ | ||||||
| 		Header& header = *get_header(); | 		Header& header = *get_header(); | ||||||
|  |  | ||||||
| 		if ( begin < 0 || end >= header.Num ) | 		if ( begin < 0 || end > header.Num ) | ||||||
| 			return false; | 			return false; | ||||||
|  |  | ||||||
| 		for ( sw idx = begin; idx < end; idx++ ) | 		for ( sw idx = begin; idx < end; idx++ ) | ||||||
| @@ -1820,13 +1820,11 @@ struct HashTable | |||||||
| 		Type Value; | 		Type Value; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	static constexpr f32 CriticalLoadScale = 0.7f; | ||||||
|  |  | ||||||
| 	static HashTable init( AllocatorInfo allocator ) | 	static HashTable init( AllocatorInfo allocator ) | ||||||
| 	{ | 	{ | ||||||
| 		HashTable<Type> result = { { nullptr }, { nullptr } }; | 		HashTable<Type> result = init_reserve(allocator, 8); | ||||||
|  |  | ||||||
| 		result.Hashes          = Array<sw>::init( allocator ); |  | ||||||
| 		result.Entries         = Array<Entry>::init( allocator ); |  | ||||||
|  |  | ||||||
| 		return result; | 		return result; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1834,21 +1832,19 @@ struct HashTable | |||||||
| 	{ | 	{ | ||||||
| 		HashTable<Type> result          = { { nullptr }, { nullptr } }; | 		HashTable<Type> result          = { { nullptr }, { nullptr } }; | ||||||
|  |  | ||||||
| 		result.Hashes                   = Array<sw>::init_reserve( allocator, num ); | 		result.Hashes = Array<sw>::init_reserve( allocator, num ); | ||||||
| 		result.Hashes.get_header()->Num = 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 ); | 		result.Entries = Array<Entry>::init_reserve( allocator, num ); | ||||||
|  |  | ||||||
| 		return result; | 		return result; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void clear( void ) | 	void clear( void ) | ||||||
| 	{ | 	{ | ||||||
| 		for ( sw idx = 0; idx < Hashes.num(); idx++ ) |  | ||||||
| 			Hashes[idx] = -1; |  | ||||||
|  |  | ||||||
| 		Hashes.clear(); |  | ||||||
| 		Entries.clear(); | 		Entries.clear(); | ||||||
|  | 		Hashes.fill( 0, Hashes.num(), -1); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void destroy( void ) | 	void destroy( void ) | ||||||
| @@ -1901,32 +1897,19 @@ struct HashTable | |||||||
|  |  | ||||||
| 	void rehash( sw new_num ) | 	void rehash( sw new_num ) | ||||||
| 	{ | 	{ | ||||||
| 		sw idx; |  | ||||||
| 		sw last_added_index; | 		sw last_added_index; | ||||||
|  |  | ||||||
| 		HashTable<Type> new_ht         = init_reserve( Hashes.get_header()->Allocator, new_num ); | 		HashTable<Type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num ); | ||||||
|  | 		for ( sw idx = 0; idx < Entries.num(); ++idx ) | ||||||
| 		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 ) |  | ||||||
| 		{ | 		{ | ||||||
| 			Entry& entry = Entries[idx]; |  | ||||||
|  |  | ||||||
| 			FindResult find_result; | 			FindResult find_result; | ||||||
|  |  | ||||||
| 			if ( new_ht.Hashes.num() == 0 ) | 			Entry& entry     = Entries[idx]; | ||||||
| 				new_ht.grow(); |  | ||||||
|  |  | ||||||
| 			entry            = Entries[idx]; |  | ||||||
| 			find_result      = new_ht.find( entry.Key ); | 			find_result      = new_ht.find( entry.Key ); | ||||||
| 			last_added_index = new_ht.add_entry( entry.Key ); | 			last_added_index = new_ht.add_entry( entry.Key ); | ||||||
|  |  | ||||||
| 			if ( find_result.PrevIndex < 0 ) | 			if ( find_result.PrevIndex < 0 ) | ||||||
| 				new_ht.Hashes[find_result.HashIndex] = last_added_index; | 				new_ht.Hashes[find_result.HashIndex] = last_added_index; | ||||||
|  |  | ||||||
| 			else | 			else | ||||||
| 				new_ht.Entries[find_result.PrevIndex].Next = last_added_index; | 				new_ht.Entries[find_result.PrevIndex].Next = last_added_index; | ||||||
|  |  | ||||||
| @@ -1984,11 +1967,10 @@ struct HashTable | |||||||
| 		sw         idx; | 		sw         idx; | ||||||
| 		FindResult find_result; | 		FindResult find_result; | ||||||
|  |  | ||||||
| 		if ( Hashes.num() == 0 ) | 		if ( full() ) | ||||||
| 			grow(); | 			grow(); | ||||||
|  |  | ||||||
| 		find_result = find( key ); | 		find_result = find( key ); | ||||||
|  |  | ||||||
| 		if ( find_result.EntryIndex >= 0 ) | 		if ( find_result.EntryIndex >= 0 ) | ||||||
| 		{ | 		{ | ||||||
| 			idx = find_result.EntryIndex; | 			idx = find_result.EntryIndex; | ||||||
| @@ -2060,7 +2042,9 @@ protected: | |||||||
|  |  | ||||||
| 	b32 full() | 	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 )              \ | #define txt( text )              \ | ||||||
| 	StrC                         \ | 	StrC                         \ | ||||||
| 	{                            \ | 	{                            \ | ||||||
| 		sizeof( text ) - 1, text \ | 		sizeof( (text) ) - 1, (text) \ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| StrC to_str( char const* str ) | StrC to_str( char const* str ) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user