Compare commits

...

27 Commits

Author SHA1 Message Date
Ed_
d97ee1d302 Making scripts for major changes 2024-10-18 15:43:22 -04:00
Ed_
1b5d2a3ff6 just origanizing gitignore 2024-10-18 15:15:52 -04:00
Ed_
ca779b627b Commiting last latest changes before making repo modifications 2024-10-18 15:11:13 -04:00
Ed_
a885201b81 60. Animating the Message Widget 2024-04-26 22:04:10 -04:00
Ed_
07c5420bc2 59. Message Widget 2024-04-26 21:36:09 -04:00
Ed_
fe2abe1972 58. Broadcasting Data Table Rows 2024-04-26 20:08:08 -04:00
Ed_
e8fb014d29 54. Get All Asset Tags 2024-04-26 18:23:13 -04:00
Ed_
c4e40037ed 53. Gameplay Effect Delegates 2024-04-25 12:46:26 -04:00
Ed_
33b3723b82 53. Gameplay Effect Delegates 2024-04-25 00:30:54 -04:00
Ed_
ae1e28a072 46. PostGameplayEffectExecute 2024-04-24 20:18:38 -04:00
Ed_
ef002ccf53 45. PreAttributeChange 2024-04-24 18:18:26 -04:00
Ed_
035ad8de6f 44. Infinite Effect Application and Removal 2024-04-24 16:21:22 -04:00
Ed_
a604117e95 43. Instant and Duration Application Policy 2024-04-24 11:58:40 -04:00
Ed_
f17c53a1a9 42. Infinite Gameplay Effects 2024-04-24 11:48:07 -04:00
Ed_
bd0c8a0878 41. Effect Stacking 2024-04-24 11:14:41 -04:00
Ed_
22aee515ed 40. Periodic Gameplay Effects 2024-04-24 10:59:48 -04:00
Ed_
8f84dcf3d3 38. Instant Gameplay Effects 2024-04-24 10:07:23 -04:00
Ed_
3a58e90802 'NetSlime' Initial port finished and working with 2 players (at least) 2024-04-23 18:54:17 -04:00
Ed_
ad41867dc5 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.
2024-04-23 01:10:02 -04:00
Ed_
cc1636b687 37. Effect Actor Improved 2024-04-22 12:01:30 -04:00
Ed_
eaed6cf337 34. Listening for Attribute Changes 2024-04-22 01:54:33 -04:00
Ed_
2c11939244 34. Listening for Attribute Changes 2024-04-22 00:30:29 -04:00
Ed_
811dc33f4a 32. Overlay Widget Controller 2024-04-21 18:56:57 -04:00
Ed_
adfb17b7df Merge remote-tracking branch 'Ed94/master' 2024-04-21 10:26:14 -04:00
Ed_
6c011ac657 Update Readme.md 2024-04-21 10:06:06 -04:00
Ed_
c517cbd45e Update Readme.md 2024-04-21 10:05:42 -04:00
Ed_
b26e02d582 ignore binaries 2024-04-21 09:57:56 -04:00
131 changed files with 4366 additions and 527 deletions

50
.gitignore vendored
View File

@@ -1,30 +1,38 @@
Project/Intermediate
Project/Saved/Crashes
Project/Saved/SourceControl
Project/Saved/ShaderDebugInfo
Project/Saved/Logs
Project/Saved/Autosaves
Project/Saved/Config/CrashReportClient
Project/Saved/Config/WindowsEditor
Project/Saved/Config/WorldState
Project/Saved/AutoScreenshot.png
Project/Platforms
*/Binaries/Win64/*.patch_*.*
Project/.idea
Project/.vs
Project/.vsconfig
*.sln
*.target
*.modules
Project/.idea
Project/Saved/Screenshots
*/Binaries/Win64/*.patch_*.*
Project/Saved/ImGui
Project/Saved/ImGui/imgui.ini
GasaGen_*.pdb
Project/Binaries
Project/Binaries/GasaGen.exe
Project/Binaries/GasaGen.map
Project/Binaries/GasaGen.obj
Project/Binaries/vc140.pdb
Project/Intermediate
Project/Platforms
Project/Saved/Config/ConsoleHistory.ini
*.pdb
Project/Saved/Autosaves
Project/Saved/AutoScreenshot.png
Project/Saved/Config/CrashReportClient
Project/Saved/Config/WindowsEditor
Project/Saved/Config/WorldState
Project/Saved/Crashes
Project/Saved/Diff
Project/Saved/ImGui
Project/Saved/ImGui/imgui.ini
Project/Saved/Logs
Project/Saved/Screenshots
Project/Saved/ShaderDebugInfo
Project/Saved/SourceControl
*.modules
*.pdb
*.sln
*.target
GasaGen_*.pdb

File diff suppressed because one or more lines are too long

View File

@@ -49,6 +49,15 @@ r.ReflectionMethod=1
r.Shadow.Virtual.Enable=1
r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange=True
r.CustomDepth=3
r.DefaultFeature.Bloom=False
r.DefaultFeature.AmbientOcclusion=False
r.DefaultFeature.AmbientOcclusionStaticFraction=False
r.DefaultFeature.AutoExposure=False
r.DefaultFeature.MotionBlur=False
r.AntiAliasingMethod=0
r.MSAACount=1
r.ScreenPercentage.Default=25.000000
r.SupportSkyAtmosphere=False
[/Script/WorldPartitionEditor.WorldPartitionEditorSettings]
CommandletClass=Class'/Script/UnrealEd.WorldPartitionConvertCommandlet'

View File

@@ -9,6 +9,8 @@ Tag_PPV=Global_PPV
Tag_GlobalPPV=Global_PPV
Template_PlayerCamera=/Game/Actors/BP_CameraMount.BP_CameraMount_C
Template_HUD_HostUI=/Game/UI/UI_Host.UI_Host_C
Template_HostWidgetController=/Game/UI/BP_HostWidgetController.BP_HostWidgetController_C
TaggedMessageTable=/Game/Core/Tables/DT_TaggedMessages.DT_TaggedMessages
[/Script/GameplayAbilities.AbilitySystemGlobals]
bUseDebugTargetFromHud=true

View File

@@ -0,0 +1,20 @@
[/Script/GameplayTags.GameplayTagsSettings]
ImportTagsFromConfig=True
WarnOnInvalidTags=True
ClearInvalidTags=False
AllowEditorTagUnloading=True
AllowGameTagUnloading=False
FastReplication=False
InvalidTagCharacters="\"\',"
+GameplayTagTableList=/Game/Core/Tables/DT_PrimaryAttributes.DT_PrimaryAttributes
NumBitsForContainerSize=6
NetIndexFirstBitSegment=16
+GameplayTagList=(Tag="Attributes.Vital.Health",DevComment="")
+GameplayTagList=(Tag="Attributes.Vital.Mana",DevComment="")
+GameplayTagList=(Tag="Attributes.Vital.MaxHealth",DevComment="")
+GameplayTagList=(Tag="Attributes.Vital.MaxMana",DevComment="")
+GameplayTagList=(Tag="Message.Crystal.Health",DevComment="")
+GameplayTagList=(Tag="Message.Crystal.Mana",DevComment="")
+GameplayTagList=(Tag="Message.Potion.Health",DevComment="")
+GameplayTagList=(Tag="Message.Potion.Mana",DevComment="")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -301,10 +301,6 @@
"Name": "VisualStudioSourceCodeAccess",
"Enabled": true
},
{
"Name": "GitSourceControl",
"Enabled": true
},
{
"Name": "SlateInsights",
"Enabled": true

View File

@@ -0,0 +1,7 @@
{
"ColumnWidths":
{
"DevComment": 405,
"Tag": 381
}
}

View File

@@ -0,0 +1,6 @@
{
"ColumnWidths":
{
"TextStyle": 1099
}
}

View File

@@ -0,0 +1,9 @@
{
"ColumnWidths":
{
"Image": 487,
"Tag": 246,
"Message": 439,
"MessageTemplate": 232
}
}

View File

@@ -1,3 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<bUsePCHFiles>false</bUsePCHFiles>
</Configuration>

View File

@@ -0,0 +1,38 @@
#include "EffectProperties.h"
#include "AbilitySystemComponent.h"
#include "AbilitySystemGlobals.h"
#include "GameplayEffect.h"
#include "GameplayEffectExtension.h"
#include "GameFramework/Pawn.h"
#include "GameFramework/PlayerController.h"
void FEffectProperties::Populate(FGameplayEffectModCallbackData const& Data)
{
Context = Data.EffectSpec.GetContext();
SourceAbilitySystem = Context.GetOriginalInstigatorAbilitySystemComponent();
if (IsValid(SourceAbilitySystem)
&& SourceAbilitySystem->AbilityActorInfo.IsValid()
&& SourceAbilitySystem->AbilityActorInfo->AvatarActor.IsValid())
{
FGameplayAbilityActorInfo* AbilityInfo = SourceAbilitySystem->AbilityActorInfo.Get();
SourceAvatar = AbilityInfo->AvatarActor.Get();
SourceController = AbilityInfo->PlayerController.Get();
if (SourceController == nullptr && SourceAvatar)
{
APawn* Pawn = Cast<APawn>(SourceAvatar);
if (Pawn)
SourceController = Pawn->GetController();
}
}
if (Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid())
{
FGameplayAbilityActorInfo* AbilityInfo = Data.Target.AbilityActorInfo.Get();
TargetAvatar = AbilityInfo->AvatarActor.Get();
TargetController = AbilityInfo->PlayerController.Get();
TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(TargetAvatar);
}
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "GameplayEffectTypes.h"
#include "GasaCommon.h"
#include "EffectProperties.generated.h"
USTRUCT()
struct GASA_API FEffectProperties
{
GENERATED_BODY()
FGameplayEffectContextHandle Context;
UPROPERTY(VisibleAnywhere)
UAbilitySystemComponent* SourceAbilitySystem;
UPROPERTY(VisibleAnywhere)
AActor* SourceAvatar;
UPROPERTY(VisibleAnywhere)
AController* SourceController;
UPROPERTY(VisibleAnywhere)
UAbilitySystemComponent* TargetAbilitySystem;
UPROPERTY(VisibleAnywhere)
AActor* TargetAvatar;
UPROPERTY(VisibleAnywhere)
APlayerController* TargetController;
void Populate(FGameplayEffectModCallbackData const& Data);
};

View File

@@ -1 +1,33 @@
#include "GasaAbilitySystemComponent.h"
#include "GasaAbilitySystemComponent.h"
#include "Engine/Engine.h"
#include "Engine/GameViewportClient.h"
#include "Game/GasaGameState.h"
#include "Game/GasaPlayerController.h"
#include "GameFramework/HUD.h"
#include "Slate/SceneViewport.h"
#include "UI/GasaHUD.h"
#include "CogDebugDraw.h"
using namespace Gasa;
void UGasaAbilitySystemComp::OnAbilityActorInfoSet()
{
if ( ! OnGameplayEffectAppliedDelegateToSelf.IsBoundToObject(this))
OnGameplayEffectAppliedDelegateToSelf.AddUObject(this, & ThisClass::EffectApplied);
}
void UGasaAbilitySystemComp::EffectApplied(UAbilitySystemComponent* AbilitySystem, FGameplayEffectSpec const& Spec,
FActiveGameplayEffectHandle ActiveEffect)
{
Log("EFFECT APPLIED?");
FGameplayTagContainer Tags;
Spec.GetAllAssetTags(Tags);
Event_OnEffectAppliedAssetTags.Broadcast(Tags);
}
void UGasaAbilitySystemComp::InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor)
{
Super::InitAbilityActorInfo(InOwnerActor, InAvatarActor);
}

View File

@@ -1,29 +1,27 @@
#pragma once
#include "AbilitySystemComponent.h"
#include "AbilitySystemInterface.h"
#include "GasaCommon.h"
#include "GasaAbilitySystemComponent.generated.h"
DECLARE_MULTICAST_DELEGATE_OneParam(FEffectAssetTagsSig, FGameplayTagContainer const& /*Tags*/);
UCLASS(BlueprintType)
class GASA_API UGasaAbilitySystemComp : public UAbilitySystemComponent
{
GENERATED_BODY()
public:
};
namespace Gasa
{
inline
UGasaAbilitySystemComp* GetAbilitySystem(UObject* Object)
{
if (Object->Implements<UAbilitySystemInterface>())
{
return Cast<UGasaAbilitySystemComp>( Cast<IAbilitySystemInterface>(Object)->GetAbilitySystemComponent() );
}
return nullptr;
}
}
FEffectAssetTagsSig Event_OnEffectAppliedAssetTags;
void OnAbilityActorInfoSet();
void EffectApplied(UAbilitySystemComponent* AbilitySystem, FGameplayEffectSpec const& Spec, FActiveGameplayEffectHandle ActiveEffect);
#pragma region AbilitySystemComponent
void InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor) override;
#pragma endregion AbilitySystemComponent
};

View File

@@ -0,0 +1,38 @@
#pragma once
#include "GasaAbilitySystemComponent.h"
#include "AbilitySystemInterface.h"
#include "AbilitySystemGlobals.h"
namespace Gasa
{
inline
UGasaAbilitySystemComp* GetAbilitySystem(UObject* Object)
{
if (Object->Implements<UAbilitySystemInterface>())
{
return Cast<UGasaAbilitySystemComp>( Cast<IAbilitySystemInterface>(Object)->GetAbilitySystemComponent() );
}
return nullptr;
}
// From: UAbilitySystemGlobals::GetAbilitySystemComponentFromActor
inline
UGasaAbilitySystemComp* GetAbilitySystem(AActor* Actor, bool LookForComponent = true)
{
if (Actor == nullptr)
return nullptr;
const IAbilitySystemInterface* ASI = Cast<IAbilitySystemInterface>(Actor);
if (ASI)
return Cast<UGasaAbilitySystemComp>(ASI->GetAbilitySystemComponent());
if (LookForComponent)
{
// Fall back to a component search to better support BP-only actors
return Cast<UGasaAbilitySystemComp>(Actor->FindComponentByClass<UAbilitySystemComponent>());
}
return nullptr;
}
}

View File

@@ -1,5 +1,7 @@
// This was generated by GasaGen/GasaGen.cpp
// Generated by GasaGen/GasaGen_UGasaAttributeSet.cpp
#include "GasaAttributeSet.h"
#include "GasaAttributeSet_Inlines.h"
#include "EffectProperties.h"
#include "AbilitySystemComponent.h"
#include "Net/UnrealNetwork.h"
@@ -13,24 +15,60 @@ UGasaAttributeSet::UGasaAttributeSet()
InitMaxMana( 50.f );
}
#pragma region Rep Notifies
void UGasaAttributeSet::Client_OnRep_Health( FGameplayAttributeData& PrevHealth )
{
GAMEPLAYATTRIBUTE_REPNOTIFY( UGasaAttributeSet, Health, PrevHealth )
// From GAMEPLAYATTRIBUTE_REPNOTIFY
static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, Health ) );
GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), Health, PrevHealth );
}
void UGasaAttributeSet::Client_OnRep_MaxHealth( FGameplayAttributeData& PrevMaxHealth )
{
GAMEPLAYATTRIBUTE_REPNOTIFY( UGasaAttributeSet, MaxHealth, PrevMaxHealth )
// From GAMEPLAYATTRIBUTE_REPNOTIFY
static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, MaxHealth ) );
GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), MaxHealth, PrevMaxHealth );
}
void UGasaAttributeSet::Client_OnRep_Mana( FGameplayAttributeData& PrevMana )
{
GAMEPLAYATTRIBUTE_REPNOTIFY( UGasaAttributeSet, Mana, PrevMana )
// From GAMEPLAYATTRIBUTE_REPNOTIFY
static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, Mana ) );
GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), Mana, PrevMana );
}
void UGasaAttributeSet::Client_OnRep_MaxMana( FGameplayAttributeData& PrevMaxMana )
{
GAMEPLAYATTRIBUTE_REPNOTIFY( UGasaAttributeSet, MaxMana, PrevMaxMana )
// From GAMEPLAYATTRIBUTE_REPNOTIFY
static FProperty* UGasaAttributeSetProperty = FindFieldChecked<FProperty>( StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, MaxMana ) );
GetOwningAbilitySystemComponentChecked()->SetBaseAttributeValueFromReplication( FGameplayAttribute( UGasaAttributeSetProperty ), MaxMana, PrevMaxMana );
}
#pragma endregion Rep Notifies
void UGasaAttributeSet::PostGameplayEffectExecute( FGameplayEffectModCallbackData const& Data )
{
Super::PostGameplayEffectExecute( Data );
FEffectProperties Props;
Props.Populate( Data );
}
void UGasaAttributeSet::PreAttributeChange( FGameplayAttribute const& Attribute, float& NewValue )
{
Super::PreAttributeChange( Attribute, NewValue );
if ( Attribute == GetHealthAttribute() )
{
NewValue = FMath::Clamp( NewValue, 0, GetMaxHealth() );
}
if ( Attribute == GetMaxHealthAttribute() )
{
NewValue = FMath::Clamp( NewValue, 0, 99999.000000 );
}
if ( Attribute == GetManaAttribute() )
{
NewValue = FMath::Clamp( NewValue, 0, GetMaxMana() );
}
if ( Attribute == GetMaxManaAttribute() )
{
NewValue = FMath::Clamp( NewValue, 0, 99999.000000 );
}
}
void UGasaAttributeSet::GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const

View File

@@ -1,7 +1,7 @@
// This was generated by GasaGen/GasaGen.cpp
// Generated by GasaGen/GasaGen_UGasaAttributeSet.cpp
#pragma once
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "GasaAttributeSet.generated.h"
UCLASS()
@@ -9,20 +9,17 @@ class GASA_API UGasaAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
UGasaAttributeSet();
UPROPERTY( ReplicatedUsing = Client_OnRep_Health, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData Health;
UPROPERTY( ReplicatedUsing = Client_OnRep_MaxHealth, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData MaxHealth;
UPROPERTY( ReplicatedUsing = Client_OnRep_Mana, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData Mana;
UPROPERTY( ReplicatedUsing = Client_OnRep_MaxMana, EditAnywhere, BlueprintReadWrite, Category = "Attributes" )
FGameplayAttributeData MaxMana;
UGasaAttributeSet();
UFUNCTION()
void Client_OnRep_Health( FGameplayAttributeData& PrevHealth );
UFUNCTION()
@@ -53,6 +50,7 @@ public:
static FProperty* Prop = FindFieldChecked<FProperty>( UGasaAttributeSet::StaticClass(), GET_MEMBER_NAME_CHECKED( UGasaAttributeSet, MaxMana ) );
return Prop;
}
FORCEINLINE float GetHealth() const { return Health.GetCurrentValue(); }
FORCEINLINE float GetMaxHealth() const { return MaxHealth.GetCurrentValue(); }
FORCEINLINE float GetMana() const { return Mana.GetCurrentValue(); }
@@ -61,38 +59,11 @@ public:
#pragma region Setters
FORCEINLINE void
SetHealth( float NewVal )
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
if ( ensure( AbilityComp ) )
{
AbilityComp->SetNumericAttributeBase( GetHealthAttribute(), NewVal );
};
}
FORCEINLINE void SetMaxHealth( float NewVal )
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
if ( ensure( AbilityComp ) )
{
AbilityComp->SetNumericAttributeBase( GetMaxHealthAttribute(), NewVal );
};
}
FORCEINLINE void SetMana( float NewVal )
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
if ( ensure( AbilityComp ) )
{
AbilityComp->SetNumericAttributeBase( GetManaAttribute(), NewVal );
};
}
FORCEINLINE void SetMaxMana( float NewVal )
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
if ( ensure( AbilityComp ) )
{
AbilityComp->SetNumericAttributeBase( GetMaxManaAttribute(), NewVal );
};
}
SetHealth( float NewVal );
FORCEINLINE void SetMaxHealth( float NewVal );
FORCEINLINE void SetMana( float NewVal );
FORCEINLINE void SetMaxMana( float NewVal );
FORCEINLINE void InitHealth( float NewVal )
{
Health.SetBaseValue( NewVal );
@@ -115,17 +86,14 @@ public:
}
#pragma endregion Setters
#pragma region UObject
#pragma region AttributeSet
void
PreAttributeChange( const FGameplayAttribute& Attribute, float& NewValue ) override;
void PostGameplayEffectExecute( FGameplayEffectModCallbackData const& Data ) override;
#pragma endregion AttributeSet
#pragma region UObject
void
GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps ) const override;
#pragma endregion UObject
};
namespace Gasa
{
inline UGasaAttributeSet const* GetAttributeSet( UAbilitySystemComponent* ASC )
{
return Cast<UGasaAttributeSet>( ASC->GetAttributeSet( UGasaAttributeSet::StaticClass() ) );
}
}

View File

@@ -0,0 +1,53 @@
// Generated by GasaGen/GasaGen_UGasaAttributeSet.cpp
#pragma once
#include "GasaAttributeSet.h"
#include "AbilitySystemComponent.h"
#pragma region Attribute Setters
FORCEINLINE
void UGasaAttributeSet::SetHealth( float NewVal )
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
if ( ensure( AbilityComp ) )
{
AbilityComp->SetNumericAttributeBase( GetHealthAttribute(), NewVal );
};
}
FORCEINLINE
void UGasaAttributeSet::SetMaxHealth( float NewVal )
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
if ( ensure( AbilityComp ) )
{
AbilityComp->SetNumericAttributeBase( GetMaxHealthAttribute(), NewVal );
};
}
FORCEINLINE
void UGasaAttributeSet::SetMana( float NewVal )
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
if ( ensure( AbilityComp ) )
{
AbilityComp->SetNumericAttributeBase( GetManaAttribute(), NewVal );
};
}
FORCEINLINE
void UGasaAttributeSet::SetMaxMana( float NewVal )
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
if ( ensure( AbilityComp ) )
{
AbilityComp->SetNumericAttributeBase( GetMaxManaAttribute(), NewVal );
};
}
#pragma endregion Attribute Setters
namespace Gasa
{
inline UGasaAttributeSet const* GetAttributeSet( UAbilitySystemComponent* ASC )
{
return Cast<UGasaAttributeSet>( ASC->GetAttributeSet( UGasaAttributeSet::StaticClass() ) );
}
}

View File

@@ -1,61 +1,126 @@
#include "GasaEffectActor.h"
#include "AbilitySystemComponent.h"
#include "AbilitySystemInterface.h"
#include "GasaAttributeSet.h"
#include "Components/SphereComponent.h"
#include "GasaAbilitySystemComponent_Inlines.h"
#include "GasaContainers.h"
using namespace Gasa;
AGasaEffectActor::AGasaEffectActor()
{
PrimaryActorTick.bCanEverTick = false;
Mesh = CreateDefaultSubobject<UStaticMeshComponent>("Mesh");
Sphere = CreateDefaultSubobject<USphereComponent>("Sphere");
RootComponent = CreateDefaultSubobject<USceneComponent>("Root");
SetRootComponent(Mesh);
Sphere->SetupAttachment(Mesh);
}
void AGasaEffectActor::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent
, AActor* OtherActor
, UPrimitiveComponent* OtherComp
, int32 OtherBodyIndex
, bool bFromSweep
, FHitResult const& SweepResult)
{
// Demo of "restricted way"
if ( ! OtherActor->Implements<UAbilitySystemInterface>())
return;
Level = 1.f;
IAbilitySystemInterface* ASI = Cast<IAbilitySystemInterface>(OtherActor);
if (ASI == nullptr)
return;
InstantEffectUsage = EInstantEffectUsagePolicy::DoNotApply;
DurationEffectUsage = DefaultEffectUsagePolicy;
InfiniteEffectUsage = DefaultEffectUsagePolicy;
// TODO(Ed): Change this to use a gameplay effect instead
UAbilitySystemComponent* AbilitySystem = ASI->GetAbilitySystemComponent();
UGasaAttributeSet* MutAttributes = const_cast<UGasaAttributeSet*>(Gasa::GetAttributeSet(AbilitySystem));
bDestroyOnEffectRemoval = false;
}
void AGasaEffectActor::ApplyEffectToActor(AActor* Actor, TSubclassOf<UGameplayEffect> EffectClass, bool bRemoveOnEndOverlap)
{
UGasaAbilitySystemComp* AS = GetAbilitySystem(Actor, true);
FGameplayEffectContextHandle
Context = AS->MakeEffectContext();
Context.AddSourceObject(Actor);
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( EffectClass, Level, Context );
FActiveGameplayEffectHandle ActiveEffect = AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
if (bRemoveOnEndOverlap)
ActiveEffectsToRemove.Add(ActiveEffect, AS);
}
void AGasaEffectActor::OnOverlap(AActor* Actor)
{
UGasaAbilitySystemComp* AS = GetAbilitySystem(Actor, true);
FGameplayEffectContextHandle
Context = AS->MakeEffectContext();
Context.AddSourceObject(Actor);
MutAttributes->SetHealth( MutAttributes->GetHealth() + 25.f );
Destroy();
if (InstantEffectClass && InstantEffectUsage == EInstantEffectUsagePolicy::ApplyOnOverlap)
{
FGameplayEffectSpecHandle Spec= AS->MakeOutgoingSpec( InstantEffectClass, Level, Context );
AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
}
if (DurationEffectClass)
{
if (Bitfield_IsSet(DurationEffectUsage, EEffectUsagePolicy::ApplyOnOverlap))
{
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( DurationEffectClass, Level, Context );
FActiveGameplayEffectHandle ActiveEffect = AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
if (Bitfield_IsSet(DurationEffectUsage, EEffectUsagePolicy::RemoveOnEndOverlap))
ActiveDuration = ActiveEffect;
}
if (ActiveDuration.IsValid() && Bitfield_IsSet(DurationEffectUsage, EEffectUsagePolicy::RemoveOnOverlap))
AS->RemoveActiveGameplayEffect(ActiveDuration);
}
if (InfiniteEffectClass)
{
bool bApplyOnOverlap = Bitfield_IsSet(InfiniteEffectUsage, EEffectUsagePolicy::ApplyOnOverlap);
if (bApplyOnOverlap)
{
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( InfiniteEffectClass, Level, Context );
FActiveGameplayEffectHandle ActiveEffect = AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
if (Bitfield_IsSet(InfiniteEffectUsage, EEffectUsagePolicy::RemoveOnEndOverlap))
ActiveInfinite = ActiveEffect;
}
if (ActiveInfinite.IsValid() && Bitfield_IsSet(InfiniteEffectUsage, EEffectUsagePolicy::RemoveOnOverlap))
{
if (ActiveInfinite.IsValid())
AS->RemoveActiveGameplayEffect(ActiveInfinite);
}
}
}
void AGasaEffectActor::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent
, AActor* OtherActor
, UPrimitiveComponent* OtherComp
, int32 OtherBodyIndex)
void AGasaEffectActor::OnEndOverlap(AActor* Actor)
{
}
UGasaAbilitySystemComp* AS = GetAbilitySystem(Actor, true);
FGameplayEffectContextHandle
Context = AS->MakeEffectContext();
Context.AddSourceObject(Actor);
if (InstantEffectClass && InstantEffectUsage == EInstantEffectUsagePolicy::ApplyOnEndOverlap)
{
FGameplayEffectSpecHandle Spec= AS->MakeOutgoingSpec( InstantEffectClass, Level, Context );
AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
}
if (DurationEffectClass)
{
if (Bitfield_IsSet(DurationEffectUsage, EEffectUsagePolicy::ApplyOnEndOverlap))
{
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( DurationEffectClass, Level, Context );
FActiveGameplayEffectHandle ActiveEffect = AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
if (Bitfield_IsSet(DurationEffectUsage, EEffectUsagePolicy::RemoveOnOverlap))
ActiveDuration = ActiveEffect;
}
if (ActiveDuration.IsValid() && Bitfield_IsSet(DurationEffectUsage, EEffectUsagePolicy::RemoveOnEndOverlap))
AS->RemoveActiveGameplayEffect(ActiveDuration);
}
if (InfiniteEffectClass)
{
if (Bitfield_IsSet(InfiniteEffectUsage, EEffectUsagePolicy::ApplyOnEndOverlap))
{
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( InfiniteEffectClass, Level, Context );
FActiveGameplayEffectHandle ActiveEffect = AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
if (Bitfield_IsSet(InfiniteEffectUsage, EEffectUsagePolicy::RemoveOnOverlap))
ActiveInfinite = ActiveEffect;
}
if (ActiveInfinite.IsValid() && Bitfield_IsSet(InfiniteEffectUsage, EEffectUsagePolicy::RemoveOnEndOverlap))
{
if (ActiveInfinite.IsValid())
AS->RemoveActiveGameplayEffect(ActiveInfinite);
}
}
void AGasaEffectActor::BeginPlay()
{
Super::BeginPlay();
}
void AGasaEffectActor::PostInitializeComponents()
{
Super::PostInitializeComponents();
Sphere->OnComponentBeginOverlap.AddUniqueDynamic(this, &ThisClass::OnOverlapBegin);
Sphere->OnComponentEndOverlap.AddUniqueDynamic(this, &ThisClass::OnOverlapEnd);
TArray<FActiveGameplayEffectHandle> EffectsRemoved;
for (ActiveEffectEntry ActiveEffect : ActiveEffectsToRemove)
{
if (ActiveEffect.Value != AS)
continue;
AS->RemoveActiveGameplayEffect(ActiveEffect.Key, 1);
EffectsRemoved.Add(ActiveEffect.Key);
}
RemoveKeys(ActiveEffectsToRemove, EffectsRemoved);
}

View File

@@ -1,39 +1,78 @@
#pragma once
#include "GasaCommon.h"
#include "Actors/GasaActor.h"
#include "ActiveGameplayEffectHandle.h"
#include "GameFramework/Actor.h"
#include "GasaEffectActor.generated.h"
struct FActiveGameplayEffectHandle;
UENUM(BlueprintType)
enum class EInstantEffectUsagePolicy : uint8
{
DoNotApply,
ApplyOnOverlap,
ApplyOnEndOverlap,
};
UENUM(BlueprintType, meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true"))
enum class EEffectUsagePolicy : uint8
{
None = 0 UMETA(Hidden),
ApplyOnOverlap = bit(0),
ApplyOnEndOverlap = bit(1),
RemoveOnOverlap = bit(2),
RemoveOnEndOverlap = bit(3),
};
constexpr int32 DefaultEffectUsagePolicy = (int32(EEffectUsagePolicy::RemoveOnEndOverlap));
UCLASS()
class GASA_API AGasaEffectActor : public AActor
class GASA_API AGasaEffectActor : public AGasaActor
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere)
TObjectPtr<UStaticMeshComponent> Mesh;
UPROPERTY(VisibleAnywhere)
TObjectPtr<USphereComponent> Sphere;
AGasaEffectActor();
UFUNCTION()
void OnOverlapBegin(UPrimitiveComponent* OverlappedComponent
, AActor* OtherActor
, UPrimitiveComponent* OtherComp
, int32 OtherBodyIndex
, bool bFromSweep
, FHitResult const& SweepResult);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
float Level;
UFUNCTION()
void OnOverlapEnd(UPrimitiveComponent* OverlappedComponent
, AActor* OtherActor
, UPrimitiveComponent* OtherComp
, int32 OtherBodyIndex);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
TSubclassOf<UGameplayEffect> InstantEffectClass;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
EInstantEffectUsagePolicy InstantEffectUsage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
TSubclassOf<UGameplayEffect> DurationEffectClass;
#pragma region Actor
void BeginPlay() override;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects", meta=(Bitmask, BitmaskEnum = "/Script/Gasa.EEffectUsagePolicy"))
int32 DurationEffectUsage;
void PostInitializeComponents() override;
#pragma endregion Actor
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
TSubclassOf<UGameplayEffect> InfiniteEffectClass;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects", meta=(Bitmask, BitmaskEnum = "/Script/Gasa.EEffectUsagePolicy"))
int32 InfiniteEffectUsage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
bool bDestroyOnEffectRemoval;
TMap<FActiveGameplayEffectHandle, UAbilitySystemComponent*> ActiveEffectsToRemove;
using ActiveEffectEntry = TTuple<FActiveGameplayEffectHandle, UAbilitySystemComponent*>;
FActiveGameplayEffectHandle ActiveDuration;
FActiveGameplayEffectHandle ActiveInfinite;
UFUNCTION(BlueprintCallable, Category = "Gameplay Effects")
void ApplyEffectToActor(AActor* Actor, TSubclassOf<UGameplayEffect> EffectClass, bool bRemoveOnEndOverlap = false);
UFUNCTION(BlueprintCallable)
void OnOverlap(AActor* Actor);
UFUNCTION(BlueprintCallable)
void OnEndOverlap(AActor* Actor);
};

View File

@@ -0,0 +1,63 @@
#include "GasaEffectActorDemo.h"
#include "AbilitySystemInterface.h"
#include "GasaAttributeSet.h"
#include "GasaAttributeSet_Inlines.h"
#include "Components/SphereComponent.h"
#include "Components/StaticMeshComponent.h"
AGasaEffectActorDemo::AGasaEffectActorDemo()
{
PrimaryActorTick.bCanEverTick = false;
Mesh = CreateDefaultSubobject<UStaticMeshComponent>("Mesh");
Sphere = CreateDefaultSubobject<USphereComponent>("Sphere");
SetRootComponent(Mesh);
Sphere->SetupAttachment(Mesh);
}
void AGasaEffectActorDemo::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent
, AActor* OtherActor
, UPrimitiveComponent* OtherComp
, int32 OtherBodyIndex
, bool bFromSweep
, FHitResult const& SweepResult)
{
// Demo of "restricted way"
if ( ! OtherActor->Implements<UAbilitySystemInterface>())
return;
IAbilitySystemInterface* ASI = Cast<IAbilitySystemInterface>(OtherActor);
if (ASI == nullptr)
return;
// TODO(Ed): Change this to use a gameplay effect instead
UAbilitySystemComponent* AbilitySystem = ASI->GetAbilitySystemComponent();
UGasaAttributeSet* MutAttributes = const_cast<UGasaAttributeSet*>(Gasa::GetAttributeSet(AbilitySystem));
MutAttributes->SetHealth( MutAttributes->GetHealth() + 25.f );
MutAttributes->SetMana( MutAttributes->GetMana() - 25.f );
Destroy();
}
void AGasaEffectActorDemo::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent
, AActor* OtherActor
, UPrimitiveComponent* OtherComp
, int32 OtherBodyIndex)
{
}
void AGasaEffectActorDemo::BeginPlay()
{
Super::BeginPlay();
}
void AGasaEffectActorDemo::PostInitializeComponents()
{
Super::PostInitializeComponents();
Sphere->OnComponentBeginOverlap.AddUniqueDynamic(this, &ThisClass::OnOverlapBegin);
Sphere->OnComponentEndOverlap.AddUniqueDynamic(this, &ThisClass::OnOverlapEnd);
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include "GasaCommon.h"
#include "Actors/GasaActor.h"
#include "GameFramework/Actor.h"
#include "GasaEffectActorDemo.generated.h"
// Old demonstration code used before part 37.
UCLASS()
class GASA_API AGasaEffectActorDemo : public AGasaActor
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere)
TObjectPtr<UStaticMeshComponent> Mesh;
UPROPERTY(VisibleAnywhere)
TObjectPtr<USphereComponent> Sphere;
AGasaEffectActorDemo();
UFUNCTION()
void OnOverlapBegin(UPrimitiveComponent* OverlappedComponent
, AActor* OtherActor
, UPrimitiveComponent* OtherComp
, int32 OtherBodyIndex
, bool bFromSweep
, FHitResult const& SweepResult);
UFUNCTION()
void OnOverlapEnd(UPrimitiveComponent* OverlappedComponent
, AActor* OtherActor
, UPrimitiveComponent* OtherComp
, int32 OtherBodyIndex);
#pragma region Actor
void BeginPlay() override;
void PostInitializeComponents() override;
#pragma endregion Actor
};

View File

@@ -1,10 +1,12 @@
#pragma once
#include "GasaActor.h"
#include "GasaCommon.h"
#include "GameFramework/Actor.h"
#include "CameraMount.generated.h"
UCLASS(Blueprintable)
class GASA_API ACameraMount : public AActor
class GASA_API ACameraMount : public AGasaActor
{
GENERATED_BODY()
public:

View File

View 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
};

View File

@@ -1,4 +1,5 @@
#include "EnemyCharacter.h"
#include "Networking/GasaNetLibrary_Inlines.h"
AEnemyCharacter::AEnemyCharacter()
{

View File

@@ -9,12 +9,14 @@
#include "AbilitySystem/GasaAbilitySystemComponent.h"
#include "AbilitySystem/GasaAttributeSet.h"
#include "Components/SkeletalMeshComponent.h"
#include "Engine/PostProcessVolume.h"
#include "Game/GasaGameInstance.h"
#include "Game/GasaLevelScriptActor.h"
void AGasaCharacter::SetHighlight(EHighlight Desired)
{
HighlightState = Desired;
}
#include "Game/GasaPlayerController.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Networking/GasaNetLibrary_Inlines.h"
using namespace Gasa;
AGasaCharacter::AGasaCharacter()
{
@@ -48,24 +50,129 @@ AGasaCharacter::AGasaCharacter()
Attributes = CreateDefaultSubobject<UGasaAttributeSet>("Attributes");
}
// Replication
bReplicates = false;
bNetLoadOnClient = true;
NetDormancy = DORM_Awake;
NetCullDistanceSquared = NetCullDist_Medium;
NetUpdateFrequency = 30.0f;
MinNetUpdateFrequency = 5.0f;
NetPriority = 2.0f;
ACharacter::SetReplicateMovement(true);
}
#pragma region GameFramework
void AGasaCharacter::Controller_OnPawnPossessed()
{
NetLog("Controller confirmed possession.");
// Do stuff here that you needed to wait for the player controller be aware of you for.
BP_Controller_OnPawnPossessed();
if (Event_OnPawnReady.IsBound())
Event_OnPawnReady.Broadcast();
}
void AGasaCharacter::ServerRPC_R_NotifyClientPawnReady_Implementation()
{
Event_OnPawnReady.Broadcast();
}
#pragma endregion GameFramework
#pragma region Highlight
void AGasaCharacter::SetHighlight(EHighlight Desired)
{
HighlightState = Desired;
}
#pragma endregion Highlight
#pragma region Pawn
void AGasaCharacter::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
if (bAutoAbilitySystem)
{
// TODO(Ed): Do we need to do this for enemies?
AbilitySystem->InitAbilityActorInfo(this, this);
}
}
void AGasaCharacter::OnRep_PlayerState()
{
Super::OnRep_PlayerState();
}
void AGasaCharacter::PossessedBy(AController* NewController)
{
NetLog("Pawn possessed.");
AController* OldController;
// APawn::PossessedBy
{
SetOwner(NewController);
OldController = Controller;
Controller = NewController;
ForceNetUpdate();
#if UE_WITH_IRIS
// The owning connection depends on the Controller having the new value.
UpdateOwningNetConnection();
#endif
if (Controller->PlayerState != nullptr)
SetPlayerState(Controller->PlayerState);
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
{
if (GetNetMode() != NM_Standalone)
{
SetReplicates(true);
SetAutonomousProxy(true);
}
}
else
CopyRemoteRoleFrom(GetDefault<APawn>());
}
if (AGasaPlayerController* PC = Cast<AGasaPlayerController>(NewController))
{
PC->Event_OnPawnPossessed.AddUniqueDynamic(this, & ThisClass::Controller_OnPawnPossessed);
}
else
{
NetLog("Controller assigned to GasaCharacter is not derived from GasaPlayerController.", ELogV::Warning);
NetLog("Controller: Name: " + NewController->GetName() + " Class: " + NewController->GetClass()->GetName(), ELogV::Warning);
}
// cont. APawn::PossessedBy
{
// Dispatch Blueprint event if necessary
if (OldController != NewController)
{
ReceivePossessed(Controller);
NotifyControllerChanged();
}
}
// ACharacter::PossessedBy
{
// If we are controlled remotely, set animation timing to be driven by client's network updates. So timing and events remain in sync.
if (GetMesh() && IsReplicatingMovement() && (GetRemoteRole() == ROLE_AutonomousProxy && GetNetConnection() != nullptr))
GetMesh()->bOnlyAllowAutonomousTickPose = true;
}
#if 0
if (bAutoAbilitySystem)
{
AbilitySystem->InitAbilityActorInfo(this, this);
}
#endif
}
void AGasaCharacter::SetPlayerDefaults()
{
Super::SetPlayerDefaults();
}
void AGasaCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
#pragma endregion Pawn
#pragma region Actor
@@ -73,10 +180,12 @@ void AGasaCharacter::BeginPlay()
{
Super::BeginPlay();
// TODO(Ed): Find out if this is the best spot todo this
// There is also OnPossessed, PostInitializeComponents, etc...
if (bAutoAbilitySystem)
{
// TODO(Ed): Do we need to do this for enemies?
AbilitySystem->InitAbilityActorInfo(this, this);
Cast<UGasaAbilitySystemComp>(AbilitySystem)->OnAbilityActorInfoSet();
}
}

View File

@@ -4,7 +4,8 @@
#include "GameFramework/Character.h"
#include "GasaCommon.h"
#include "Game/GasaPlayerState.h"
#include "Game/GasaGameState.h"
#include "Networking/GasaNetLibrary.h"
#include "GasaCharacter.generated.h"
@@ -21,6 +22,9 @@ class GASA_API AGasaCharacter : public ACharacter
{
GENERATED_BODY()
public:
AGasaCharacter();
#pragma region Ability System
UPROPERTY(EditAnywhere, Category="Ability System")
bool bAutoAbilitySystem = true;
@@ -37,6 +41,20 @@ public:
TObjectPtr<USkeletalMeshComponent> Weapon;
#pragma endregion Combat
#pragma region GameFramework
UPROPERTY(BlueprintAssignable)
FOnPawnSig Event_OnPawnReady;
UFUNCTION()
void Controller_OnPawnPossessed();
UFUNCTION(BlueprintImplementableEvent)
void BP_Controller_OnPawnPossessed();
UFUNCTION(Server, Reliable)
void ServerRPC_R_NotifyClientPawnReady();
#pragma endregion GameFramework
#pragma region Highlighting
static constexpr float HighlightStencilDepth = 256.0;
@@ -56,9 +74,27 @@ public:
FORCEINLINE void Dehighlight() { SetHighlight(EHighlight::Disabled); };
#pragma endregion Highlighting
AGasaCharacter();
FORCEINLINE AGasaPlayerState* GetGasaPlayerState() { return GetPlayerState<AGasaPlayerState>(); }
#pragma region NetSlime
// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp
FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); }
FORCEINLINE bool IsClient() const { return Gasa::IsClient( this ); }
FORCEINLINE bool IsListenServer() const { return Gasa::IsListenServer( this ); }
FORCEINLINE bool IsNetOwner() const { return Gasa::IsNetOwner( this ); }
FORCEINLINE bool IsServer() const { return Gasa::IsServer( this ); }
FORCEINLINE bool IsSimulatedProxy() const { return Gasa::IsSimulatedProxy( this ); }
FORCEINLINE void NetLog(
FString Message,
EGasaVerbosity Verbosity = EGasaVerbosity::Log,
FLogCategoryBase& Category = LogGasaNet,
bool DumpStack = false,
int32 Line = __builtin_LINE(),
ANSICHAR const* File = __builtin_FILE(),
ANSICHAR const* Func = __builtin_FUNCTION()
)
{
Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func );
}
#pragma endregion NetSlime
#pragma region IAbilitySystem
FORCEINLINE UAttributeSet* GetAttributes() { return Attributes; }
@@ -66,14 +102,14 @@ public:
#pragma endregion IAbilitySystem
#pragma region Pawn
void PossessedBy(AController* NewController) override;
void OnRep_PlayerState() override;
void PossessedBy(AController* NewController) override;
void SetPlayerDefaults() override;
void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
#pragma endregion Pawn
#pragma region Actor
void BeginPlay() override;
void Tick(float DeltaSeconds) override;
#pragma endregion Actor
};
@@ -85,3 +121,4 @@ namespace Gasa
//
// }
}

View File

@@ -1,6 +1,10 @@
#include "PlayerCharacter.h"
#include "Networking/GasaNetLibrary_Inlines.h"
#include "AbilitySystemComponent.h"
#include "Game/GasaPlayerController.h"
#include "UI/GasaHUD.h"
#include "UI/WidgetController.h"
APlayerCharacter::APlayerCharacter()
{
@@ -12,25 +16,9 @@ APlayerCharacter::APlayerCharacter()
void APlayerCharacter::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
AGasaPlayerState* PS = GetGasaPlayerState();
// Server setup ability system (character side)
{
AbilitySystem = PS->AbilitySystem;
Attributes = PS->Attributes;
AbilitySystem->InitAbilityActorInfo(PS, this);
}
}
void APlayerCharacter::OnRep_PlayerState()
{
Super::OnRep_PlayerState();
AGasaPlayerState* PS = GetGasaPlayerState();
// Client setup ability system
{
AbilitySystem = PS->AbilitySystem;
Attributes = PS->Attributes;
AbilitySystem->InitAbilityActorInfo(PS, this);
}
}

View File

@@ -1,11 +1,93 @@
#include "GasaGameInstance.h"
#include "Engine/NetDriver.h"
#include "Engine/World.h"
using namespace Gasa;
#pragma region GameFramework
// TODO(Ed): Make a NetLog
UGasaGameInstance::UGasaGameInstance()
{
GameFrameworkState = EGameFrameworkState::Uninitialized;
}
void UGasaGameInstance::NotifyGameFrameworkClassReady(EGameFrameworkClassFlag ClassReady)
{
switch (ClassReady)
{
case EGameFrameworkClassFlag::GameMode:
GameFrameworkClassesState |= (uint32)EGameFrameworkClassFlag::GameMode;
NetLog("Game Framework class ready: Game State", ELogV::Log, LogGasaNet );
break;
case EGameFrameworkClassFlag::GameState:
GameFrameworkClassesState |= (uint32)EGameFrameworkClassFlag::GameState;
NetLog("Game Framework class ready: Game State", ELogV::Log, LogGasaNet );
break;
case EGameFrameworkClassFlag::PlayerController:
GameFrameworkClassesState |= (uint32)EGameFrameworkClassFlag::PlayerController;
NetLog("Game Framework class ready: Player Controller", ELogV::Log, LogGasaNet);
break;
case EGameFrameworkClassFlag::PlayerState:
GameFrameworkClassesState |= (uint32)EGameFrameworkClassFlag::PlayerState;
NetLog("Game Framework class ready: Player State", ELogV::Log, LogGasaNet);
break;
case EGameFrameworkClassFlag::Levels:
GameFrameworkClassesState |= (uint32)EGameFrameworkClassFlag::Levels;
NetLog("Game 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("Game Framework initialized");
Event_OnGameFrameworkInitialized.Broadcast();
}
break;
}
}
}
#pragma endregion GameFramework
#pragma region GameInstance
void UGasaGameInstance::Init()
{
Super::Init();
DevOptionsCache.CachedDevOptions();
using namespace Gasa;
Log(FString::Printf(TEXT("UObject Size: %d RT: %d"), sizeof(UObject), UObject::StaticClass()->PropertiesSize ));
}
#pragma endregion GameInstance

View File

@@ -1,19 +1,92 @@
#pragma once
#include "GasaCommon.h"
#include "Networking/GasaNetLibrary.h"
#include "GasaDevOptionsCache.h"
#include "Engine/Engine.h"
#include "Engine/GameInstance.h"
#include "GasaGameInstance.generated.h"
UENUM(BlueprintType)
enum class EGameFrameworkClassFlag : uint8
{
None = 0 UMETA(Hidden),
GameMode = 1 << 0,
GameState = 1 << 1,
PlayerController = 1 << 2,
PlayerState = 1 << 3,
Levels = 1 << 4
};
UENUM(BlueprintType)
enum class EGameFrameworkState : uint8
{
Uninitialized,
Initialized
};
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnGameFrameworkInitializedSig);
UCLASS(Blueprintable)
class GASA_API UGasaGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
UGasaGameInstance();
UPROPERTY(VisibleAnywhere, Category="Dev Cache")
FGasaDevOptionsCache DevOptionsCache;
#pragma region GameFramework
UPROPERTY(BlueprintAssignable, Category = "GameFramework")
FOnGameFrameworkInitializedSig Event_OnGameFrameworkInitialized;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameFramework")
EGameFrameworkState GameFrameworkState;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameFramework", meta=(Bitmask, BitmaskEnum = "/Script/Gasa.EGameFrameworkClassFlag"))
int32 GameFrameworkClassesState;
UFUNCTION(BlueprintCallable, Category="GameFramework")
void ClearGameplayFrameworkState() {
Gasa::Log("Clearing game framework state", EGasaVerbosity::Log, LogGasaNet ); // TODO(Ed): Make a default NetLog
GameFrameworkClassesState = scast(int32, EGameFrameworkClassFlag::None);
GameFrameworkState = EGameFrameworkState::Uninitialized;
}
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GameFramework")
FORCEINLINE bool IsGameFrameworkInitialized() { return GameFrameworkState == EGameFrameworkState::Initialized; }
UFUNCTION(BlueprintCallable, Category="GameFramework")
void NotifyGameFrameworkClassReady(EGameFrameworkClassFlag ClassReady);
UFUNCTION(BlueprintCallable, Category = "GameFramework", meta=(BlueprintProtected))
void ProcessGameFrameworkState();
#pragma endregion GameFramework
#pragma region NetSlime
// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp
FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); }
FORCEINLINE bool IsClient() const { return Gasa::IsClient( this ); }
FORCEINLINE bool IsListenServer() const { return Gasa::IsListenServer( this ); }
FORCEINLINE bool IsNetOwner() const { return Gasa::IsNetOwner( this ); }
FORCEINLINE bool IsServer() const { return Gasa::IsServer( this ); }
FORCEINLINE bool IsSimulatedProxy() const { return Gasa::IsSimulatedProxy( this ); }
FORCEINLINE void NetLog(
FString Message,
EGasaVerbosity Verbosity = EGasaVerbosity::Log,
FLogCategoryBase& Category = LogGasaNet,
bool DumpStack = false,
int32 Line = __builtin_LINE(),
ANSICHAR const* File = __builtin_FILE(),
ANSICHAR const* Func = __builtin_FUNCTION()
)
{
Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func );
}
#pragma endregion NetSlime
#pragma region GameInstance
void Init() override;
#pragma endregion GameInstance

View File

@@ -1,2 +1,476 @@
#include "GasaGameMode.h"
#include "Online/CoreOnline.h"
#include "GasaGameInstance.h"
#include "GasaGameState.h"
#include "GasaPlayerController.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::FinishRestartPlayer(AController* NewPlayer, const FRotator& StartRotation)
{
// Super::FinishRestartPlayer(NewPlayer, StartRotation);
{
NewPlayer->Possess(NewPlayer->GetPawn());
// If the Pawn is destroyed as part of possession we have to abort
if (!IsValid(NewPlayer->GetPawn()))
{
FailedToRestartPlayer(NewPlayer);
}
else
{
// Set initial control rotation to starting rotation rotation
NewPlayer->ClientSetRotation(NewPlayer->GetPawn()->GetActorRotation(), true);
FRotator NewControllerRot = StartRotation;
NewControllerRot.Roll = 0.f;
NewPlayer->SetControlRotation(NewControllerRot);
SetPlayerDefaults(NewPlayer->GetPawn());
K2_OnRestartPlayer(NewPlayer);
}
}
}
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);
}
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>();
#if 0
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 = 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_NetOwner_OnGameFrameworkInitialized.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);
}
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

View File

@@ -1,28 +1,104 @@
#pragma once
#pragma once
#include "GameFramework/GameMode.h"
#include "GasaCommon.h"
#include "Networking/GasaNetLibrary_Inlines.h"
#include "Engine/Engine.h"
#include "GasaGameMode.generated.h"
UCLASS(Blueprintable)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLogoutSig, AGasaPlayerController*, PC);
UCLASS( Blueprintable )
class GASA_API AGasaGameMode : public AGameMode
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintAssignable)
FOnLogoutSig Event_OnLogout;
#pragma region GameFramework
UFUNCTION()
void OnGameFrameworkInitialized();
UFUNCTION()
void OwningClient_OnGameFrameworkInitialized(AGasaPlayerController* PC);
UFUNCTION(BlueprintCallable, 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 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 FinishRestartPlayer(AController* NewPlayer, const FRotator& StartRotation) override;
void GenericPlayerInitialization(AController* C) override;
TSubclassOf<APlayerController> GetPlayerControllerClassToSpawnForSeamlessTravel(APlayerController* PreviousPlayerController) override;
void HandleSeamlessTravelPlayer(AController*& C) override;
void InitializeHUDForPlayer_Implementation(APlayerController* NewPlayer) override;
void InitSeamlessTravelPlayer(AController* NewController) override;
void Logout(AController* Exiting) override;
void PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage) override;
void PostLogin(APlayerController* NewPlayer) override;
void PostSeamlessTravel() override;
void SetPlayerDefaults(APawn* PlayerPawn) override;
void SetSeamlessTravelViewTarget(APlayerController* PC) override;
void StartPlay() override;
void StartToLeaveMap() override;
void SwapPlayerControllers(APlayerController* OldPC, APlayerController* NewPC) override;
APlayerController* SpawnPlayerControllerCommon(ENetRole InRemoteRole, FVector const& SpawnLocation, FRotator const& SpawnRotation, TSubclassOf<APlayerController> InPlayerControllerClass) override;
#pragma endregion GameModeBase
};
namespace Gasa
{
inline
AGasaGameMode* GetGameMode(UObject* Context)
inline AGasaGameMode* GetGameMode( UObject* Context )
{
UWorld* World = GEngine->GetWorldFromContextObject(Context, EGetWorldErrorMode::LogAndReturnNull);
if (World == nullptr)
UWorld* World = GEngine->GetWorldFromContextObject( Context, EGetWorldErrorMode::LogAndReturnNull );
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 Cast<AGasaGameMode>(World->GetAuthGameMode());
return Cast<AGasaGameMode>( World->GetAuthGameMode() );
}
}

View File

@@ -2,6 +2,11 @@
#include "CogAll.h"
#include "CogWindowManager.h"
#include "GasaPlayerState.h"
#include "GasaGameInstance.h"
#include "Net/UnrealNetwork.h"
#include "Networking/GasaNetLibrary_Inlines.h"
using namespace Gasa;
AGasaGameState::AGasaGameState()
{
@@ -9,26 +14,134 @@ AGasaGameState::AGasaGameState()
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.SetTickFunctionEnable(true);
PrimaryActorTick.bStartWithTickEnabled = true;
// Replication
bReplicates = true;
bNetLoadOnClient = false;
NetDormancy = DORM_Awake;
NetCullDistanceSquared = NetCullDist_Default;
NetUpdateFrequency = 10.0f;
MinNetUpdateFrequency = 1.0f;
NetPriority = 5.0f;
}
#pragma region GameState
#pragma region GameFramework
void AGasaGameState::OnGameFrameworkInitialized()
{
NetLog("Received gameplay framework initialization.");
if (IsServer())
{
if (PlayerArray.Num() > 0)
{
ListenServerHost = Cast<AGasaPlayerState>(PlayerArray[0]);
}
else
{
NetLog("Was not able to assign HostingPlayer!", ELogV::Error);
}
}
BP_OnGameFrameworkInitialized();
}
#pragma endregion GameFramework
#pragma region Networking
void AGasaGameState::Client_OnRep_OnlinePlayers()
{
}
#pragma endregion Networking
#pragma region Seamless Travel
void AGasaGameState::Multicast_R_NotifySeamlessTravelEnd_Implementation()
{
NetLog("Multicast_R_NotifySeamlessTravelEnd_Implementation");
BP_Event_OnSeamlessTravelEnd.Broadcast();
Event_OnSeamlessTravelEnd.Broadcast();
}
#pragma endregion Seamless Travel
#pragma region GameStateBase
void AGasaGameState::HandleBeginPlay()
{
Super::HandleBeginPlay();
NetLog("HandleBeginPlay: Directly called from GM");
}
void AGasaGameState::SeamlessTravelTransitionCheckpoint(bool bToTransitionMap)
{
Super::SeamlessTravelTransitionCheckpoint(bToTransitionMap);
NetLog("SeamlessTravelTransitionCheckpoint");
NetLog(FString("ToTransitionMap: ") + FString(bToTransitionMap ? "true" : "false"));
if (bToTransitionMap)
{
Event_OnSeamlessTravelStart.Broadcast();
}
else
{
Multicast_R_NotifySeamlessTravelEnd();
}
}
#pragma endregion GameStateBase
#pragma region Actor
void AGasaGameState::BeginPlay()
{
#if ENABLE_COG
CogWindowManager = NewObject<UCogWindowManager>(this);
CogWindowManagerRef = CogWindowManager;
Super::BeginPlay();
NetLog("BeginPlay");
// Add all the built-in windows
Cog::AddAllWindows(*CogWindowManager);
// Notified as initialized here as any possible components should also be initialized by this point.
UGasaGameInstance*
GI = GetGameInstance<UGasaGameInstance>();
GI->Event_OnGameFrameworkInitialized.AddDynamic(this, & ThisClass::OnGameFrameworkInitialized);
GI->NotifyGameFrameworkClassReady(EGameFrameworkClassFlag::GameState);
#if ENABLE_COG
CogWindowManager = NewObject<UCogWindowManager>(this);
CogWindowManagerRef = CogWindowManager;
// Add all the built-in windows
Cog::AddAllWindows(*CogWindowManager);
#endif //ENABLE_COG
}
void AGasaGameState::PostInitializeComponents()
{
NetLog("PostInitializeComponents");
Super::PostInitializeComponents();
if ( ! GetWorld()->IsEditorWorld() && IsServer())
{
OnlinePlayers.Empty();
#if 0
const auto GI = Cast<UGasaGameInstance>(GetGameInstance());
if (GI != nullptr)
{
int32 NumConnections = GI->SessionSettings.bPublicGame
? GI->SessionSettings.PublicConnections
: GI->SessionSettings.PrivateConnections;
OnlinePlayers.Init(nullptr, NumConnections);
}
#endif
}
}
void AGasaGameState::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
#if ENABLE_COG
CogWindowManager->Tick(DeltaSeconds);
if (CogWindowManager)
CogWindowManager->Tick(DeltaSeconds);
#endif //ENABLE_COG
}
#pragma endregion GameState
#pragma endregion Actor
#pragma region UObject
void AGasaGameState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AGasaGameState, ListenServerHost);
DOREPLIFETIME(AGasaGameState, OnlinePlayers);
}
#pragma endregion UObject

View File

@@ -1,46 +1,123 @@
#pragma once
#pragma once
#include "GameFramework/GameState.h"
#include "GasaCommon.h"
#include "Engine/Engine.h"
#include "Networking/GasaNetLibrary.h"
#include "GasaGameState.generated.h"
UCLASS(Blueprintable)
UCLASS( Blueprintable )
class GASA_API AGasaGameState : public AGameState
{
GENERATED_BODY()
public:
#pragma region Cog
// To make sure it doesn't get garbage collected.
UPROPERTY()
TObjectPtr<UObject> CogWindowManagerRef;
// To make sure it doesn't get garbage collected.
UPROPERTY()
TObjectPtr<UObject> CogWindowManagerRef;
#if ENABLE_COG
TObjectPtr<UCogWindowManager> CogWindowManager;
#endif // ENABLE_COG
#endif
// ENABLE_COG
#pragma endregion Cog
AGasaGameState();
#pragma region GameFramework
UPROPERTY(BlueprintAssignable)
FOnPawnReadySig Event_OnPlayerPawnReady;
UFUNCTION()
void OnGameFrameworkInitialized();
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, meta=(DisplayName = "Game Framework Initialized"))
void BP_OnGameFrameworkInitialized();
UFUNCTION()
void NotifyPlayerPawnReady(APawn* Pawn)
{
if (Event_OnPlayerPawnReady.IsBound())
Event_OnPlayerPawnReady.Broadcast(Pawn);
}
#pragma endregion GameFramework
#pragma region Networking
UPROPERTY(Replicated, BlueprintReadOnly)
AGasaPlayerState* ListenServerHost;
UPROPERTY(ReplicatedUsing = "Client_OnRep_OnlinePlayers", BlueprintReadOnly)
TArray<AGasaPlayerState*> OnlinePlayers;
UFUNCTION()
void Client_OnRep_OnlinePlayers();
#pragma endregion Networking
#pragma region Seamless Travel
UPROPERTY(BlueprintAssignable)
FOnTravelSig Event_OnSeamlessTravelStart;
UPROPERTY(BlueprintAssignable, meta=(DisplayName="Event: On Seamless Travel End"))
FOnTravelSig BP_Event_OnSeamlessTravelEnd;
FOnTravelDelegate Event_OnSeamlessTravelEnd;
UFUNCTION(NetMulticast, Reliable)
void Multicast_R_NotifySeamlessTravelEnd();
#pragma endregion Seamless Travel
#pragma region NetSlime
// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp
FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); }
FORCEINLINE bool IsClient() const { return Gasa::IsClient( this ); }
FORCEINLINE bool IsListenServer() const { return Gasa::IsListenServer( this ); }
FORCEINLINE bool IsNetOwner() const { return Gasa::IsNetOwner( this ); }
FORCEINLINE bool IsServer() const { return Gasa::IsServer( this ); }
FORCEINLINE bool IsSimulatedProxy() const { return Gasa::IsSimulatedProxy( this ); }
FORCEINLINE void NetLog(
FString Message,
EGasaVerbosity Verbosity = EGasaVerbosity::Log,
FLogCategoryBase& Category = LogGasaNet,
bool DumpStack = false,
int32 Line = __builtin_LINE(),
ANSICHAR const* File = __builtin_FILE(),
ANSICHAR const* Func = __builtin_FUNCTION()
)
{
Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func );
}
#pragma endregion NetSlime
#pragma region GameState
void BeginPlay() override;
void HandleBeginPlay() override;
#pragma endregion GameState
void Tick(float DeltaSeconds) override;
#pragma endregion GameState
#pragma region GameStateBase
void SeamlessTravelTransitionCheckpoint(bool bToTransitionMap) override;
#pragma endregion GameStateBase
#pragma region Actor
void BeginPlay() override;
void PostInitializeComponents() override;
void Tick( float DeltaSeconds ) override;
#pragma endregion Actor
#pragma region UObject
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
#pragma endregion UObject
};
namespace Gasa
{
inline
AGasaGameState* GetGameState(UObject* Context)
inline AGasaGameState* GetGameState( UObject* Context )
{
UWorld* World = GEngine->GetWorldFromContextObject(Context, EGetWorldErrorMode::LogAndReturnNull);
if (World == nullptr)
UWorld* World = GEngine->GetWorldFromContextObject( Context, EGetWorldErrorMode::LogAndReturnNull );
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 Cast<AGasaGameState>(World->GetGameState());
return Cast<AGasaGameState>( World->GetGameState() );
}
}

View File

@@ -1,11 +1,40 @@
#include "GasaLevelScriptActor.h"
#include "GasaDevOptions.h"
#include "GasaGameInstance.h"
#include "Engine/PostProcessVolume.h"
#include "Kismet/GameplayStatics.h"
#include "Materials/MaterialInstance.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Networking/GasaNetLibrary_Inlines.h"
using namespace Gasa;
#pragma region Game Framework
AGasaLevelScriptActor::AGasaLevelScriptActor()
{
// Replication
bReplicates = true;
bNetLoadOnClient = true;
NetDormancy = DORM_Awake;
NetCullDistanceSquared = NetCullDist_Default;
NetUpdateFrequency = 10.0f;
MinNetUpdateFrequency = 1.0f;
NetPriority = 1.0f;
}
void AGasaLevelScriptActor::OnGameFrameworkInitialized()
{
NetLog("Received game framework initialization.");
BP_OnGameFrameworkInitialized();
}
#pragma endregion Game Framework
#pragma region Actor
void AGasaLevelScriptActor::BeginPlay()
{
Super::BeginPlay();
NetLog("BeginPlay");
using namespace Gasa;
@@ -21,4 +50,12 @@ void AGasaLevelScriptActor::BeginPlay()
PPV->Settings.WeightedBlendables.Array[0].Object = MID;
break;
}
UGasaGameInstance* GI = GetGameInstance<UGasaGameInstance>();
if(GI)
GI->Event_OnGameFrameworkInitialized.AddUniqueDynamic(this, & ThisClass::OnGameFrameworkInitialized);
if (!bOverrideGameFrameworkReady)
GI->NotifyGameFrameworkClassReady(EGameFrameworkClassFlag::Levels);
}
#pragma endregion Actor

View File

@@ -1,8 +1,9 @@
#pragma once
#include "GasaCommon.h"
#include "Engine/Engine.h"
#include "Engine/LevelScriptActor.h"
#include "GasaCommon.h"
#include "Networking/GasaNetLibrary.h"
#include "GasaLevelScriptActor.generated.h"
@@ -14,9 +15,44 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Post Process")
TObjectPtr<APostProcessVolume> GlobalPPV;
AGasaLevelScriptActor();
#pragma region GameFramework
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
bool bOverrideGameFrameworkReady = false;
UFUNCTION()
void OnGameFrameworkInitialized();
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, meta=(DisplayName="On Game Framework Initialized"))
void BP_OnGameFrameworkInitialized();
#pragma endregion GameFramework
#pragma region NetSlime
// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp
FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); }
FORCEINLINE bool IsClient() const { return Gasa::IsClient( this ); }
FORCEINLINE bool IsListenServer() const { return Gasa::IsListenServer( this ); }
FORCEINLINE bool IsNetOwner() const { return Gasa::IsNetOwner( this ); }
FORCEINLINE bool IsServer() const { return Gasa::IsServer( this ); }
FORCEINLINE bool IsSimulatedProxy() const { return Gasa::IsSimulatedProxy( this ); }
FORCEINLINE void NetLog(
FString Message,
EGasaVerbosity Verbosity = EGasaVerbosity::Log,
FLogCategoryBase& Category = LogGasaNet,
bool DumpStack = false,
int32 Line = __builtin_LINE(),
ANSICHAR const* File = __builtin_FILE(),
ANSICHAR const* Func = __builtin_FUNCTION()
)
{
Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func );
}
#pragma endregion NetSlime
#pragma region Actor
void BeginPlay() override;
#pragma region endActor
#pragma endregion endActor
};
namespace Gasa

View File

@@ -1,18 +1,28 @@
#include "GasaPlayerController.h"
#include "GasaPlayerController_Inlines.h"
#include "Networking/GasaNetLibrary_Inlines.h"
#include "AbilitySystemComponent.h"
#include "DrawDebugHelpers.h"
#include "Engine/LocalPlayer.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "GasaDevOptions.h"
#include "GasaPlayerState.h"
#include "Actors/CameraMount.h"
#include "Camera/CameraComponent.h"
#include "Characters/GasaCharacter.h"
#include "Characters/PlayerCharacter.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "Interfaces/NetworkPredictionInterface.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Net/UnrealNetwork.h"
#include "GameFramework/PawnMovementComponent.h"
#include "GasaDevOptions.h"
#include "GasaGameInstance.h"
#include "GasaGameState.h"
#include "GasaPlayerState.h"
#include "AbilitySystem/GasaAbilitySystemComponent.h"
#include "Actors/CameraMount.h"
#include "UI/GasaHUD.h"
#include "UI/WidgetController.h"
using namespace Gasa;
AGasaPlayerController::AGasaPlayerController()
@@ -24,6 +34,148 @@ AGasaPlayerController::AGasaPlayerController()
bReplicates = true;
}
void AGasaPlayerController::OnSeamlessTravelStart()
{
}
#pragma region GameFramework
void AGasaPlayerController::Client_CheckIfOwnerReady()
{
if (IsServer())
return;
UGasaGameInstance* GI = GetGameInstance<UGasaGameInstance>();
if ( ! GI->IsGameFrameworkInitialized() || PlayerState == NULL || ! IsValid(GetPawn()))
return;
NetOwner_OnReady();
}
void AGasaPlayerController::NetOwner_OnReady()
{
NetLog("Net Owner of controller is ready to play.");
if ( ! IsNetOwner() || bNetOwnerReady)
return;
BP_NetOwner_OnReady();
Event_NetOwner_OnReady.Broadcast(this);
bNetOwnerReady = true;
AGasaGameState* GS = Cast<AGasaGameState>(GetWorld()->GetGameState());
if (GS)
GS->NotifyPlayerPawnReady(GetPawn());
if (IsClient())
ServerRPC_R_NotifyOwningClientReady();
Cam = GetWorld()->SpawnActor<ACameraMount>(GetDevOptions()->Template_PlayerCamera.Get(), FActorSpawnParameters() );
SetViewTarget(Cam);
AGasaPlayerState* PS = GetPlayerState();
APlayerCharacter* PlayerChar = GetPawn<APlayerCharacter>();
{
PlayerChar->AbilitySystem = PS->AbilitySystem;
PlayerChar->Attributes = PS->Attributes;
PS->AbilitySystem->InitAbilityActorInfo(PS, PlayerChar);
Cast<UGasaAbilitySystemComp>(PS->AbilitySystem)->OnAbilityActorInfoSet();
}
Cam->AttachToActor(PlayerChar, FAttachmentTransformRules::KeepRelativeTransform);
}
void AGasaPlayerController::OnGameFrameworkInitialized()
{
NetLog("Received game framework initialization.");
if (IsNetOwner())
{
Server_SetNetOwner_GameFrameworkInitialized();
Client_CheckIfOwnerReady();
}
AGasaGameState* GS = GetGameState(this);
NullGuard_DEV(GS, Log, "OnGameFrameworkInitialized: GS is null");
GS->Event_OnSeamlessTravelStart.AddDynamic( this, & ThisClass::OnSeamlessTravelStart );
BP_OnGameFrameworkInitialized();
}
void AGasaPlayerController::OnPawnReady()
{
NetLog("Player is ready.");
// Originally: Super::OnPossess(PawnToPossess);
{
ChangeState(NAME_Playing);
if (bAutoManageActiveCameraTarget)
{
AutoManageActiveCameraTarget(GetPawn());
ResetCameraMode();
}
}
// Override this and add your own conditions...
BP_OnPawnReady();
if (IsServer() && IsNetOwner())
{
// The server host doesn't have to wait for the player state to replicate.
NetOwner_OnReady();
}
}
void AGasaPlayerController::Server_SetupOnPawnReadyBinds(APawn* PawnToBindTo)
{
if (IsClient())
return;
#if 0
if (PawnToBindTo->IsA(AGasaPawn::StaticClass()))
{
Cast<AGasaPawn>(PawnToBindTo)->Event_OnPawnReady.AddUniqueDynamic(this, & ThisClass::OnPawnReady);
}
else
#endif
if (PawnToBindTo->IsA(AGasaCharacter::StaticClass()))
{
Cast<AGasaCharacter>(PawnToBindTo)->Event_OnPawnReady.AddUniqueDynamic(this, & ThisClass::OnPawnReady);
}
}
void AGasaPlayerController::Server_SetNetOwner_GameFrameworkInitialized()
{
if (IsClient())
{
ServerRPC_R_SetNetOwner_GameFrameworkInitialized();
return;
}
bNetOwner_GameFrameworkInitialized = true;
if (Event_NetOwner_OnGameFrameworkInitialized.IsBound())
{
Event_NetOwner_OnGameFrameworkInitialized.Broadcast(this);
Event_NetOwner_OnGameFrameworkInitialized.Clear();
}
}
void AGasaPlayerController::ServerRPC_R_NotifyOwningClientReady_Implementation()
{
NetLog("Net Owner Ready: Notified via RPC.");
BP_NetOwner_OnReady();
bNetOwnerReady = true;
Event_NetOwner_OnReady.Broadcast(this);
Event_NetOwner_OnReady.Clear();
AGasaGameState* GS = GetGameState(this);
if (GS)
GS->NotifyPlayerPawnReady(GetPawn());
}
void AGasaPlayerController::ServerRPC_R_SetNetOwner_GameFrameworkInitialized_Implementation()
{
Server_SetNetOwner_GameFrameworkInitialized();
}
#pragma endregion GameFramework
#pragma region Input
void AGasaPlayerController::Move(FInputActionValue const& ActionValue)
{
@@ -31,8 +183,6 @@ void AGasaPlayerController::Move(FInputActionValue const& ActionValue)
if (pawn == nullptr )
return;
// Note(Ed): I did the follow optimization for practice, they are completely unnecessary for this context.
#if 0
FVector2D AxisV = ActionValue.Get<FVector2D>();
@@ -72,28 +222,109 @@ void AGasaPlayerController::Move(FInputActionValue const& ActionValue)
#pragma endregion Input
#pragma region PlayerController
void AGasaPlayerController::SpawnDefaultHUD()
bool AGasaPlayerController::CanRestartPlayer()
{
Super::SpawnDefaultHUD();
bool BaseCheck =
PlayerState &&
!PlayerState->IsOnlyASpectator() &&
HasClientLoadedCurrentWorld() &&
PendingSwapConnection == NULL
;
return BaseCheck && bNetOwner_GameFrameworkInitialized;
}
void AGasaPlayerController::OnPossess(APawn* InPawn)
void AGasaPlayerController::ClientSetHUD_Implementation(TSubclassOf<AHUD> NewHUDClass)
{
Super::OnPossess(InPawn);
Super::ClientSetHUD_Implementation(NewHUDClass);
AGasaPlayerState* PS = GetPlayerState();
AGasaHUD* HUD = GetHUD<AGasaHUD>();
FWidgetControllerData Data = { this, PS, PS->AbilitySystem, PS->Attributes };
HUD->InitHostWidget(& Data);
}
Cam->AttachToActor(InPawn, FAttachmentTransformRules::KeepRelativeTransform);
void AGasaPlayerController::ClientUpdateLevelStreamingStatus_Implementation(FName PackageName, bool bNewShouldBeLoaded, bool bNewShouldBeVisible,
bool bNewShouldBlockOnLoad, int32 LODIndex, FNetLevelVisibilityTransactionId TransactionId, bool bNewShouldBlockOnUnload)
{
Super::ClientUpdateLevelStreamingStatus_Implementation(PackageName, bNewShouldBeLoaded, bNewShouldBeVisible, bNewShouldBlockOnLoad, LODIndex,
TransactionId, bNewShouldBlockOnUnload);
AGasaPlayerState* PS = GetPlayerState();
AGasaCharacter* character = Cast<AGasaCharacter>(InPawn);
// Net Owner setup ability system
if (0)
NetLog("ClientUpdateLevelStreamingStatus");
NetLog(FString("PackageName : ") + PackageName.ToString());
NetLog(FString("NewShouldBeLoaded : ") + FString(bNewShouldBeLoaded ? "true" : "false"));
NetLog(FString("NewShouldBeVisible : ") + FString(bNewShouldBeVisible ? "true" : "false"));
NetLog(FString("bNewShouldBlockOnLoad : ") + FString(bNewShouldBlockOnLoad ? "true" : "false"));
NetLog(FString("bNewShouldBlockOnUnload: ") + FString(bNewShouldBlockOnUnload ? "true" : "false"));
NetLog(FString("LODIndex : ") + FString::FromInt( LODIndex ));
}
// TODO(Ed): We need to setup Net Slime...
void AGasaPlayerController::OnPossess(APawn* PawnPossesed)
{
// Super::OnPossess(PawnPossesed);
{
character->AbilitySystem = PS->AbilitySystem;
character->Attributes = PS->Attributes;
character->AbilitySystem->InitAbilityActorInfo(PS, character);
if (PawnPossesed && (PlayerState == NULL || !PlayerState->IsOnlyASpectator()) )
{
// ====================================================================Originally: Super::OnPossess(PawnToPossess);
const bool bNewPawn = (GetPawn() != PawnPossesed);
if (GetPawn() && bNewPawn)
UnPossess();
if (PawnPossesed->Controller != NULL)
PawnPossesed->Controller->UnPossess();
PawnPossesed->PossessedBy(this);
// update rotation to match possessed pawn's rotation
SetControlRotation( PawnPossesed->GetActorRotation() );
SetPawn(PawnPossesed);
check(GetPawn() != NULL);
if (GetPawn() && GetPawn()->PrimaryActorTick.bStartWithTickEnabled)
GetPawn()->SetActorTickEnabled(true);
INetworkPredictionInterface* NetworkPredictionInterface = GetPawn()
? Cast<INetworkPredictionInterface>(GetPawn()->GetMovementComponent())
: nullptr;
if (NetworkPredictionInterface)
NetworkPredictionInterface->ResetPredictionData_Server();
AcknowledgedPawn = NULL;
// Local PCs will have the Restart() triggered right away in ClientRestart (via PawnClientRestart()), but the server should call Restart() locally for remote PCs.
// We're really just trying to avoid calling Restart() multiple times.
if (!IsLocalPlayerController())
GetPawn()->Restart();
ClientRestart(GetPawn());
// Moved to: void AGasaPlayerController::OnPawnReady
#if 0
ChangeState( NAME_Playing );
if (bAutoManageActiveCameraTarget)
{
AutoManageActiveCameraTarget(GetPawn());
ResetCameraMode();
}
#endif
//==========================================================End of=================== Originally: Super::OnPossess(PawnToPossess);
NetLog("OnPossess");
Server_SetupOnPawnReadyBinds(PawnPossesed);
Event_OnPawnPossessed.Broadcast();
}
}
}
void AGasaPlayerController::OnRep_Pawn()
{
Super::OnRep_Pawn();
NetLog("OnRep_Pawn");
Client_CheckIfOwnerReady();
}
void AGasaPlayerController::OnUnPossess()
{
Super::OnUnPossess();
@@ -137,6 +368,11 @@ void AGasaPlayerController::PlayerTick(float DeltaTime)
}
}
void AGasaPlayerController::PostSeamlessTravel()
{
Super::PostSeamlessTravel();
}
void AGasaPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
@@ -147,41 +383,50 @@ void AGasaPlayerController::SetupInputComponent()
EIC->BindAction(IA_Move, ETriggerEvent::Triggered, this, &ThisClass::Move);
}
}
void AGasaPlayerController::SpawnDefaultHUD()
{
Super::SpawnDefaultHUD();
}
#pragma endregion PlayerController
#pragma region Actor
void AGasaPlayerController::BeginPlay()
{
Super::BeginPlay();
NetLog("BeginPlay");
check(IMC);
UEnhancedInputLocalPlayerSubsystem*
EILP_Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
check(EILP_Subsystem);
EILP_Subsystem->AddMappingContext(IMC, 0);
UGasaGameInstance* GI = GetGameInstance<UGasaGameInstance>();
GI->Event_OnGameFrameworkInitialized.AddUniqueDynamic(this, & AGasaPlayerController::OnGameFrameworkInitialized);
GI->NotifyGameFrameworkClassReady(EGameFrameworkClassFlag::PlayerController);
if (IsLocalController())
{
bShowMouseCursor = true;
DefaultMouseCursor = EMouseCursor::Default;
FInputModeGameAndUI MouseMode;
MouseMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
MouseMode.SetHideCursorDuringCapture(false);
SetInputMode(MouseMode);
check(IMC);
UEnhancedInputLocalPlayerSubsystem*
EILP_Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
check(EILP_Subsystem);
EILP_Subsystem->AddMappingContext(IMC, 0);
{
bShowMouseCursor = true;
DefaultMouseCursor = EMouseCursor::Default;
FInputModeGameAndUI MouseMode;
MouseMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
MouseMode.SetHideCursorDuringCapture(false);
SetInputMode(MouseMode);
}
}
}
void AGasaPlayerController::PostInitializeComponents()
{
Super::PostInitializeComponents();
Cam = GetWorld()->SpawnActor<ACameraMount>(GetDevOptions()->Template_PlayerCamera.Get(), FActorSpawnParameters() );
SetViewTarget(Cam);
}
void AGasaPlayerController::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
#if 0
switch (HighlightState)
{
@@ -205,4 +450,11 @@ void AGasaPlayerController::Tick(float DeltaSeconds)
}
#endif
}
void AGasaPlayerController::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AGasaPlayerController, bNetOwner_GameFrameworkInitialized);
}
#pragma endregion Actor

View File

@@ -2,15 +2,25 @@
#include "GasaCommon.h"
#include "GasaPlayerState.h"
#include "Networking/GasaNetLibrary.h"
#include "Engine/Engine.h"
#include "GameFramework/PlayerController.h"
#include "GasaPlayerController.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnGasaPlayerControllerSig, AGasaPlayerController*, PC);
UCLASS(Blueprintable)
class GASA_API AGasaPlayerController : public APlayerController
{
GENERATED_BODY()
protected:
friend void AGasaPlayerState::ClientInitialize(AController* NewOwner);
public:
UFUNCTION()
void OnSeamlessTravelStart();
#pragma region Camera
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TObjectPtr<ACameraMount> Cam;
@@ -32,6 +42,55 @@ public:
FORCEINLINE void Dehighlight() { SetHighlight(EHighlight::Disabled); };
#pragma endregion Highlighting
#endif
#pragma region GameFramework
UPROPERTY(BlueprintAssignable)
FOnGasaPlayerControllerSig Event_NetOwner_OnGameFrameworkInitialized;
UPROPERTY(BlueprintAssignable)
FOnGasaPlayerControllerSig Event_NetOwner_OnReady;
UPROPERTY(BlueprintAssignable)
FOnPawnSig Event_OnPawnPossessed;
UPROPERTY(Replicated, VisibleAnywhere)
bool bNetOwner_GameFrameworkInitialized = false;
UPROPERTY(VisibleAnywhere, Category = "Game Framework")
bool bNetOwnerReady = false;
void Client_CheckIfOwnerReady();
UFUNCTION()
void NetOwner_OnReady();
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, meta = (DisplayName = "NetOwner: On Ready"))
void BP_NetOwner_OnReady();
UFUNCTION()
void OnGameFrameworkInitialized();
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, meta=(DisplayName = "On Game Framework Initialized"))
void BP_OnGameFrameworkInitialized();
UFUNCTION()
void OnPawnReady();
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, meta=(DisplayName = "On Pawn Ready"))
void BP_OnPawnReady();
UFUNCTION()
void Server_SetupOnPawnReadyBinds(APawn* PawnToBindTo);
UFUNCTION()
void Server_SetNetOwner_GameFrameworkInitialized();
UFUNCTION(Server, Reliable)
void ServerRPC_R_NotifyOwningClientReady();
UFUNCTION(Server, Reliable)
void ServerRPC_R_SetNetOwner_GameFrameworkInitialized();
#pragma endregion GameFramework
#pragma region Input
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
@@ -49,32 +108,57 @@ public:
void Move(FInputActionValue const& ActionValue);
#pragma endregion Input
#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
AGasaPlayerController();
AGasaPlayerState* GetPlayerState()
{
return Cast<AGasaPlayerState>( PlayerState );
}
inline AGasaPlayerState* GetPlayerState();
#pragma region PlayerController
void SpawnDefaultHUD() override;
void OnPossess(APawn* InPawn) override;
void OnUnPossess() override;
bool CanRestartPlayer() override;
void ClientSetHUD_Implementation(TSubclassOf<AHUD> NewHUDClass) override;
void ClientUpdateLevelStreamingStatus_Implementation(FName PackageName, bool bNewShouldBeLoaded, bool bNewShouldBeVisible, bool bNewShouldBlockOnLoad, int32 LODIndex, FNetLevelVisibilityTransactionId TransactionId, bool bNewShouldBlockOnUnload) override;
void PlayerTick(float DeltaTime) override;
void PostSeamlessTravel() override;
void SetupInputComponent() override;
void SpawnDefaultHUD() override;
#pragma endregion PlayerController
#pragma region Controller
void OnPossess(APawn* InPawn) override;
void OnRep_Pawn() override;
void OnUnPossess() override;
#pragma endregion Controller
#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

View File

@@ -0,0 +1,8 @@
#include "GasaPlayerController.h"
#include "GasaPlayerState.h"
inline
AGasaPlayerState* AGasaPlayerController::GetPlayerState()
{
return Cast<AGasaPlayerState>( PlayerState );
}

View File

@@ -1,10 +1,15 @@
#include "GasaPlayerState.h"
#include "Networking/GasaNetLibrary_Inlines.h"
#include "GasaGameInstance.h"
#include "GasaPlayerController.h"
#include "AbilitySystem/GasaAbilitySystemComponent.h"
#include "AbilitySystem/GasaAttributeSet.h"
AGasaPlayerState::AGasaPlayerState()
{
bAutoAbilitySystem = true;
AbilitySystem = CreateDefaultSubobject<UGasaAbilitySystemComp>("Ability System");
AbilitySystem->SetIsReplicated(true);
AbilitySystem->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);
@@ -14,3 +19,74 @@ AGasaPlayerState::AGasaPlayerState()
// Replication
NetUpdateFrequency = 100.f;
}
#pragma region GameFramework
void AGasaPlayerState::OnGameFrameworkInitialized()
{
NetLog("Received game framework initialization.");
BP_OnGameFrameworkInitialized();
}
void AGasaPlayerState::OnNetOwnerReady(AGasaPlayerController* PC)
{
BP_OnNetOwnerReady();
}
void AGasaPlayerState::Reset()
{
Super::Reset();
NetLog("Reset");
}
#pragma endregion GameFramework
#pragma region PlayerState
void AGasaPlayerState::ClientInitialize(AController* NewOwner)
{
Super::ClientInitialize(NewOwner);
NetLog("Client Initialization: This is the OnRep for player state.");
AGasaPlayerController* GasaPC = Cast<AGasaPlayerController>(NewOwner);
if (GasaPC)
GasaPC->Client_CheckIfOwnerReady();
}
#pragma endregion PlayerState
#pragma region Actor
void AGasaPlayerState::BeginPlay()
{
NetLog("Begin Play");
Super::BeginPlay();
UGasaGameInstance* GI = GetGameInstance<UGasaGameInstance>();
GI->Event_OnGameFrameworkInitialized.AddDynamic(this, & ThisClass::OnGameFrameworkInitialized);
GI->NotifyGameFrameworkClassReady(EGameFrameworkClassFlag::PlayerState);
}
void AGasaPlayerState::PostInitializeComponents()
{
Super::PostInitializeComponents();
NetLog("Post Initialization");
}
void AGasaPlayerState::RegisterPlayerWithSession(bool bWasFromInvite)
{
Super::RegisterPlayerWithSession(bWasFromInvite);
NetLog("RegisterPlayerWithSession");
if (IsServer() && GetInstigatorController())
{
AGasaPlayerController* PC = Cast<AGasaPlayerController>(GetInstigatorController());
PC->Event_NetOwner_OnReady.AddDynamic(this, & ThisClass::OnNetOwnerReady);
}
}
#pragma endregion Actor
#pragma region UObject
void AGasaPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
}
#pragma endregion UObject

View File

@@ -5,6 +5,7 @@
#include "GameFramework/PlayerState.h"
#include "GasaCommon.h"
#include "Networking/GasaNetLibrary.h"
#include "GasaPlayerState.generated.h"
@@ -14,9 +15,11 @@ class GASA_API AGasaPlayerState : public APlayerState
{
GENERATED_BODY()
public:
AGasaPlayerState();
#pragma region Ability System
UPROPERTY(EditAnywhere, Category="Ability System")
bool bAutoAbilitySystem = true;
bool bAutoAbilitySystem;
UPROPERTY(EditAnywhere, Category="Ability System")
TObjectPtr<UAbilitySystemComponent> AbilitySystem;
@@ -24,15 +27,70 @@ public:
UPROPERTY(EditAnywhere, Category="Ability System")
TObjectPtr<UAttributeSet> Attributes;
#pragma endregion Ability System
#pragma region GameFramework
UFUNCTION()
void OnGameFrameworkInitialized();
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, meta = (DisplayName = "On Game Framework Initialized"))
void BP_OnGameFrameworkInitialized();
UFUNCTION()
void OnNetOwnerReady(AGasaPlayerController* PC);
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, meta = (DisplayName = "On Net Owner Ready"))
void BP_OnNetOwnerReady();
#pragma endregion GameFramework
#pragma region Networking
#if 0
UPROPERTY(ReplicatedUsing = Client_OnRep_GasaID)
int32 GasaID = INDEX_NONE;
UFUNCTION()
void Client_OnRep_GasaID;
#endif
#pragma endregion Networking
AGasaPlayerState();
#pragma region NetSlime
// NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp
FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode( this ); }
FORCEINLINE bool IsClient() const { return Gasa::IsClient( this ); }
FORCEINLINE bool IsListenServer() const { return Gasa::IsListenServer( this ); }
FORCEINLINE bool IsNetOwner() const { return Gasa::IsNetOwner( this ); }
FORCEINLINE bool IsServer() const { return Gasa::IsServer( this ); }
FORCEINLINE bool IsSimulatedProxy() const { return Gasa::IsSimulatedProxy( this ); }
FORCEINLINE void NetLog(
FString Message,
EGasaVerbosity Verbosity = EGasaVerbosity::Log,
FLogCategoryBase& Category = LogGasaNet,
bool DumpStack = false,
int32 Line = __builtin_LINE(),
ANSICHAR const* File = __builtin_FILE(),
ANSICHAR const* Func = __builtin_FUNCTION()
)
{
Gasa::NetLog( this, Message, Verbosity, Category, DumpStack, Line, File, Func );
}
#pragma endregion NetSlime
#pragma region IAbilitySystem
FORCEINLINE UAttributeSet* GetAttributes() { return Attributes; }
FORCEINLINE UAbilitySystemComponent* GetAbilitySystemComponent() const override { return AbilitySystem; }
#pragma endregion IAbilitySystem
// #pragma region
//
// #pragma endregion
#pragma region PlayerState
void ClientInitialize(AController* C) override;
#pragma endregion PlayerState
#pragma region Actor
void BeginPlay() override;
void PostInitializeComponents() override;
void RegisterPlayerWithSession(bool bWasFromInvite) override;
void Reset() override;
#pragma endregion Actor
#pragma region UObject
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
#pragma endregion UObject
};

View File

@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using UnrealBuildTool;
using ModuleRules = UnrealBuildTool.ModuleRules;
using ReadOnlyTargetRules = UnrealBuildTool.ReadOnlyTargetRules;
using TargetRules = UnrealBuildTool.TargetRules;
@@ -10,7 +10,33 @@ public class Gasa : ModuleRules
{
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
PrivateIncludePathModuleNames.AddRange(new string[] {
@@ -22,6 +48,7 @@ public class Gasa : ModuleRules
"Core",
"AIModule",
"CoreOnline",
"CoreUObject",
"DeveloperSettings",
"Engine",
@@ -32,6 +59,7 @@ public class Gasa : ModuleRules
"InputCore",
"NetCore",
"Niagara",
"OnlineSubsystem",
"SlateCore",
"UMG",
});
@@ -56,6 +84,15 @@ public class Gasa : ModuleRules
PrivateIncludePathModuleNames.AddRange( new string[]
{
"CogCommon",
"CogAbility",
"CogAI",
"CogAll",
"CogDebug",
"CogDebugEditor",
"CogEngine",
"CogImgui",
"CogInput",
"CogWindow",
});
PrivateDependencyModuleNames.AddRange(new string[]
{

View 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"

View File

@@ -1,30 +1,51 @@

#pragma once
#pragma once
#include "CoreMinimal.h"
// #define private protected
#include "GasaEngineMinimal.h"
#include "GasaCommon.generated.h"
#define global
#define internal static
#define local_persist static
#define ccast( Type, Value ) ( *const_cast<(Type)*>( &( Value ) ) )
#define pcast( Type, Value ) ( *reinterpret_cast<(Type)*>( &( Value ) ) )
#define rcast( Type, Value ) reinterpret_cast<Type>( Value )
#define scast( Type, Value ) static_cast<Type>( Value )
#define bit(position) (1 << position)
#pragma region Math
#define m_pow2( value ) (value * value)
#pragma endregion Math
#pragma region Engine Forwards
struct FInputActionValue;
struct FGameplayEffectContextHandle;
struct FGameplayEffectModCallbackData;
struct FGameplayTagContainer;
struct FOnAttributeChangeData;
struct FReplicationFlags;
class AActor;
class APawn;
class APostProcessVolume;
class FOutBunch;
class IAbilitySystemInterface;
class UAbilitySystemComponent;
class UAbilitySystemInterface;
class UActorChannel;
class UAttributeSet;
class UCameraComponent;
class UGameplayEffect;
class UInputAction;
class UInputMappingContext;
class USphereComponent;
class USpringArmComponent;
class UTexture2D;
#pragma endregion Engine Forwards
#pragma region Engine Plugin Forwards
@@ -34,23 +55,63 @@ class UCogWindowManager;
// Gasa
#pragma region Forwards
struct FWidgetControllerData;
class ACameraMount;
class AGasaCharacter;
class AGasaGameInstance;
class AGasaGameState;
class AGasaLevelScriptActor;
class AGasaPlayerController;
class AGasaPlayerState;
class APlayerCharacter;
class UGasaAbilitySystemComp;
class UGasaAttributeSet;
class UGasaDevOptions;
class UGasaImage;
class UGasaObject;
class UGasaOverlay;
class UGasaProgressBar;
class UGasaSizeBox;
class UUI_HostWidget;
class UGasaUserWidget;
class UHostWidgetController;
class UHUDHostWidget;
class UWidgetController;
#pragma endregion Forwards
#pragma region Bitfields
namespace Gasa
{
inline
bool Bitfield_IsSet(int32 Bitfield, int32 Bitmask) {
bool Result = Bitmask == (Bitfield & Bitmask);
return Result;
}
inline
bool Bitfield_IsSetExactly(int32 Bitfield, int32 Bitmask)
{
bool Result = Bitfield == (Bitfield & Bitmask);
return 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; }
template<typename EnumType>
inline
bool Bitfield_IsSet(int32 Bitfield, EnumType Mask)
{
bool Result = int32(Mask) == (Bitfield & int32(Mask));
return Result;
}
template<typename EnumType> inline void Bitfield_Set ( int32& Bitfield, EnumType BitToAdd ) { Bitfield |= int32(BitToAdd); }
template<typename EnumType> inline void Bitfield_Remove( int32& Bitfield, EnumType BitToRemove ) { Bitfield &= (! int32(BitToRemove)); }
template<typename EnumType> inline void Bitfield_Toggle( int32& Bitfield, EnumType BitToToggle ) { Bitfield ^= int32(BitToToggle); }
}
#pragma endregion Bitfields
#pragma region Logging
// Straight from the Engine
UENUM(BlueprintType)
@@ -100,10 +161,10 @@ namespace Gasa
{
using ELogV = EGasaVerbosity;
//◞ ‸ ◟//
// Works for Unreal 5.4, Win64 MSVC (untested in other scenarios, for now)
inline
void Log( FString Message, EGasaVerbosity Verbosity = EGasaVerbosity::Log
void Log( FString Message
, EGasaVerbosity Verbosity = EGasaVerbosity::Log
, FLogCategoryBase& Category = LogGasa
, bool DumpStack = false
, int32 Line = __builtin_LINE()
@@ -160,3 +221,12 @@ namespace Gasa
constexpr float _480Hz = .002f;
}
#pragma endregion Timing
#pragma region Delegates
DECLARE_MULTICAST_DELEGATE(FOnTravelDelegate);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnTravelSig);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnPawnSig);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPlayerCharacterReadySig, APlayerCharacter*, Character);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPawnReadySig, APawn*, Pawn);
#pragma endregion Delegates

View File

View File

@@ -0,0 +1,22 @@
#pragma once
#include "GasaCommon.h"
template<typename RowType>
inline
RowType* GetDataTableRowByTag(UDataTable* DT, FGameplayTag& Tag)
{
RowType* Row = DT->FindRow<RowType>(Tag.GetTagName(), TEXT(""));
return Row;
}
template<typename KeyType, typename ValueType>
inline
void RemoveKeys(TMap<KeyType, ValueType> Map, TArray<KeyType> Keys)
{
for (KeyType& Key : Keys )
{
Map.Remove(Key);
}
}

View File

@@ -1,7 +1,8 @@
#include "GasaDevOptions.h"
#include "Actors/CameraMount.h"
#include "UI/UI_HostWidget.h"
#include "UI/HUDHostWidget.h"
#include "UI/HostWidgetController.h"
using namespace Gasa;

View File

@@ -1,11 +1,12 @@
#pragma once
#include "Engine/DataTable.h"
#include "Engine/DeveloperSettings.h"
#include "GasaCommon.h"
#include "GasaDevOptions.generated.h"
UCLASS(Config=Game, DefaultConfig, meta=(DisplayName="Gasa"))
class GASA_API UGasaDevOptions : public UDeveloperSettings
{
@@ -15,11 +16,17 @@ public:
// NOTE(Ed): Any Soft-References must have their includes defined in GasaDevOptions.cpp
// They are used by GasaGen for the GasaDevOptionsCache
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="UI")
TSoftObjectPtr<UDataTable> TaggedMessageTable;
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="UI")
TSoftClassPtr<ACameraMount> Template_PlayerCamera;
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="UI")
TSoftClassPtr<UUI_HostWidget> Template_HUD_HostUI;
TSoftClassPtr<UHUDHostWidget> Template_HUD_HostUI;
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="UI")
TSoftClassPtr<UHostWidgetController> Template_HostWidgetController;
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="Tags")
FName Tag_GlobalPPV;

View File

@@ -1,17 +1,32 @@
// This was generated by GasaGen/GasaGen.cpp
// Generated by GasaGen/GasaGen_DevOptionsCache.cpp
#include "GasaDevOptionsCache.h"
#include "GasaDevOptions.h"
#include "Actors/CameraMount.h"
#include "UI/UI_HostWidget.h"
#include "UI/HUDHostWidget.h"
#include "UI/HostWidgetController.h"
using namespace Gasa;
void FGasaDevOptionsCache::CachedDevOptions()
{
UGasaDevOptions* DevOpts = GetMutDevOptions();
TaggedMessageTable = DevOpts->TaggedMessageTable.LoadSynchronous();
ensureMsgf( TaggedMessageTable != nullptr, TEXT( "TaggedMessageTable is null, DO NOT RUN PIE or else you may get a crash if not handled in BP or C++" ) );
Template_PlayerCamera = DevOpts->Template_PlayerCamera.LoadSynchronous();
Template_HUD_HostUI = DevOpts->Template_HUD_HostUI.LoadSynchronous();
ensureMsgf(
Template_PlayerCamera != nullptr, TEXT( "Template_PlayerCamera is null, DO NOT RUN PIE or else you may get a crash if not handled in BP or C++" )
);
Template_HUD_HostUI = DevOpts->Template_HUD_HostUI.LoadSynchronous();
ensureMsgf( Template_HUD_HostUI != nullptr, TEXT( "Template_HUD_HostUI is null, DO NOT RUN PIE or else you may get a crash if not handled in BP or C++" ) );
Template_HostWidgetController = DevOpts->Template_HostWidgetController.LoadSynchronous();
ensureMsgf(
Template_HostWidgetController != nullptr,
TEXT( "Template_HostWidgetController is null, DO NOT RUN PIE or else you may get a crash if not handled in BP or C++" )
);
Tag_GlobalPPV = DevOpts->Tag_GlobalPPV;
}

View File

@@ -1,4 +1,4 @@
// This was generated by GasaGen/GasaGen.cpp
// Generated by GasaGen/GasaGen_DevOptionsCache.cpp
#pragma once
#include "GasaDevOptionsCache.generated.h"
@@ -8,10 +8,14 @@ struct GASA_API FGasaDevOptionsCache
{
GENERATED_BODY()
UPROPERTY()
UObject* TaggedMessageTable;
UPROPERTY()
UClass* Template_PlayerCamera;
UPROPERTY()
UClass* Template_HUD_HostUI;
UPROPERTY()
UClass* Template_HostWidgetController;
void CachedDevOptions();
};

View File

@@ -0,0 +1,25 @@
#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 "Delegates/Delegate.h"
#include "Delegates/DelegateCombinations.h"

View File

@@ -8,6 +8,7 @@
#include "Game/GasaGameState.h"
#include "Game/GasaPlayerController.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Misc/ConfigCacheIni.h"
#pragma region Game
UGasaDevOptions* UGasaLib::GetGasaDevOptions(UObject* Context) {

View File

@@ -1,6 +1,7 @@
#pragma once
#include "GasaCommon.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "GasaLibrary.Generated.h"

View File

@@ -1,6 +1,7 @@
#pragma once
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"
class GASA_API FGasaModule : public IModuleInterface
{

View 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;
}

View 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
};

View File

@@ -1,2 +1,94 @@
#include "GasaNetLibrary.h"
#include "GasaNetLibrary_Inlines.h"
#include "GasaObject.h"
#include "Kismet/KismetMathLibrary.h"
#include "Kismet/KismetSystemLibrary.h"
DEFINE_LOG_CATEGORY(LogGasaNet);
namespace Gasa
{
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);
}
void NetLog( UObject const* Context, FString Message, EGasaVerbosity Verbosity
, FLogCategoryBase& Category
, bool DumpStack
, int32 Line
, const ANSICHAR* File
, const ANSICHAR* Func )
{
#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
}
}

View File

@@ -1,4 +1,50 @@
#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);
#define NullGuard( Object_, Logger_, Message_ ) \
do { \
if ( ! IsValid(Object_) ) \
{ \
Logger_( (Message_) , ELogV::Error ); \
ensure( IsValid(Object_) ); \
return; \
} \
} while (0)
#define NetGuard( Condition_, Logger_, Message_ ) \
do { \
if ( Condition_ ) \
{ \
Logger_( (Message_) , ELogV::Error ); \
ensure( Condition_ ); \
return; \
} \
} while (0)
#if UE_BUILD_DEVELOPMENT
# define NullGuard_DEV NullGuard
# define NetGuard_DEV NetGuard
#else
# define NullGuard_DEV( Object_, Logger_, Message_)
# define NetGuard_DEV( Object_, Logger_, Message_)
#endif
UENUM(BlueprintType)
enum class ENetworkMode : uint8
{
Standalone,
DedicatedServer,
ListenServer,
Client,
MAX,
};
namespace Gasa
{
@@ -12,6 +58,31 @@ namespace Gasa
constexpr float NetCullDist_VeryFar = 10000.0f * 10000.0f;
constexpr float NetCullDist_VisualMax = 15000.0f * 15000.0f;
#define DOREPLIFETIME_DEFAULT_GAS(Class, ReplicatedVar) \
DOREPLIFETIME_CONDITION_NOTIFY(Class, ReplicatedVar, COND_None, REPNOTIFY_Always)
void DrawNetCullingSphere(UObject const* Context, float Duration, float Thickness);
ENetworkMode GetNetworkMode(UObject const* Context);
FString GetNetworkModeStr(UObject const* Context);
bool IsClient(UObject const* Context);
bool IsListenServer(UObject const* Context);
bool IsNetOwner(UObject const* Context);
bool IsNetOwner(AActor const* Context);
bool IsServer(UObject const* Context);
bool IsSimulatedProxy(UObject 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(AActor const* Context);
}
#include "GasaNetLibrary_Inlines.h"

View File

@@ -0,0 +1,201 @@
#pragma once
#include "GasaNetLibrary.h"
#include "Engine/NetDriver.h"
#include "Engine/World.h"
namespace Gasa
{
// TODO(Ed): Profile these...
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
{
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(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
{
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(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
{
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(AActor const* Actor)
{
if (Actor == nullptr || Actor->GetWorld() == nullptr)
return false;
bool Result = Actor->HasAuthority();
return Result;
}
}

Some files were not shown because too many files have changed in this diff Show More