-
-
Save x157/d59d729f6bb62d816175048b446376ee to your computer and use it in GitHub Desktop.
diff --git a/Source/LyraGame/Character/LyraHeroComponent.h b/Source/LyraGame/Character/LyraHeroComponent.h | |
index 312623d..921feb3 100644 | |
--- a/Source/LyraGame/Character/LyraHeroComponent.h | |
+++ b/Source/LyraGame/Character/LyraHeroComponent.h | |
@@ -22,7 +22,7 @@ class ULyraInputConfig; | |
* A component used to create a player controlled pawns (characters, vehicles, etc..). | |
*/ | |
UCLASS(Blueprintable, Meta=(BlueprintSpawnableComponent)) | |
-class ULyraHeroComponent : public ULyraPawnComponent | |
+class LYRAGAME_API ULyraHeroComponent : public ULyraPawnComponent | |
{ | |
GENERATED_BODY() | |
diff --git a/Source/LyraGame/Character/LyraPawn.h b/Source/LyraGame/Character/LyraPawn.h | |
index d2741b0..4220d90 100644 | |
--- a/Source/LyraGame/Character/LyraPawn.h | |
+++ b/Source/LyraGame/Character/LyraPawn.h | |
@@ -12,7 +12,7 @@ | |
* ALyraPawn | |
*/ | |
UCLASS() | |
-class ALyraPawn : public AModularPawn, public ILyraTeamAgentInterface | |
+class LYRAGAME_API ALyraPawn : public AModularPawn, public ILyraTeamAgentInterface | |
{ | |
GENERATED_BODY() | |
@@ -48,10 +48,12 @@ private: | |
UFUNCTION() | |
void OnControllerChangedTeam(UObject* TeamAgent, int32 OldTeam, int32 NewTeam); | |
-private: | |
+protected: | |
+ // must be protected since ALyraPawn doesn't handle NotifyControllerChanged and child classes must do it | |
UPROPERTY(ReplicatedUsing = OnRep_MyTeamID) | |
FGenericTeamId MyTeamID; | |
+private: | |
UPROPERTY() | |
FOnLyraTeamIndexChangedDelegate OnTeamChangedDelegate; | |
diff --git a/Source/LyraGame/Character/LyraPawnExtensionComponent.h b/Source/LyraGame/Character/LyraPawnExtensionComponent.h | |
index 255984e..758c0a6 100644 | |
--- a/Source/LyraGame/Character/LyraPawnExtensionComponent.h | |
+++ b/Source/LyraGame/Character/LyraPawnExtensionComponent.h | |
@@ -21,7 +21,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE(FLyraDynamicMulticastDelegate); | |
* Component used to add functionality to all Pawn classes. | |
*/ | |
UCLASS() | |
-class ULyraPawnExtensionComponent : public ULyraPawnComponent | |
+class LYRAGAME_API ULyraPawnExtensionComponent : public ULyraPawnComponent | |
{ | |
GENERATED_BODY() | |
diff --git a/Source/LyraGame/LyraGameplayTags.h b/Source/LyraGame/LyraGameplayTags.h | |
index f44e0c3..13c08e7 100644 | |
--- a/Source/LyraGame/LyraGameplayTags.h | |
+++ b/Source/LyraGame/LyraGameplayTags.h | |
@@ -12,7 +12,7 @@ class UGameplayTagsManager; | |
* | |
* Singleton containing native gameplay tags. | |
*/ | |
-struct FLyraGameplayTags | |
+struct LYRAGAME_API FLyraGameplayTags | |
{ | |
public: | |
diff --git a/Source/LyraGame/Teams/LyraTeamAgentInterface.h b/Source/LyraGame/Teams/LyraTeamAgentInterface.h | |
index e685a3a..388519b 100644 | |
--- a/Source/LyraGame/Teams/LyraTeamAgentInterface.h | |
+++ b/Source/LyraGame/Teams/LyraTeamAgentInterface.h | |
@@ -23,7 +23,7 @@ inline FGenericTeamId IntegerToGenericTeamId(int32 ID) | |
/** Interface for actors which can be associated with teams */ | |
UINTERFACE(meta=(CannotImplementInterfaceInBlueprint)) | |
-class ULyraTeamAgentInterface : public UGenericTeamAgentInterface | |
+class LYRAGAME_API ULyraTeamAgentInterface : public UGenericTeamAgentInterface | |
{ | |
GENERATED_UINTERFACE_BODY() | |
}; |
#include "Character/XCL_Pawn.h" | |
#include "LyraGameplayTags.h" | |
#include "AbilitySystem/LyraAbilitySystemComponent.h" | |
#include "Character/LyraPawnExtensionComponent.h" | |
#include "GameFramework/PawnMovementComponent.h" | |
// Sets default values | |
AXCL_Pawn::AXCL_Pawn() | |
{ | |
PawnExtComponent = CreateDefaultSubobject<ULyraPawnExtensionComponent>(TEXT("PawnExtensionComponent")); | |
PawnExtComponent->OnAbilitySystemInitialized_RegisterAndCall(FSimpleMulticastDelegate::FDelegate::CreateUObject(this, &ThisClass::OnAbilitySystemInitialized)); | |
PawnExtComponent->OnAbilitySystemUninitialized_Register(FSimpleMulticastDelegate::FDelegate::CreateUObject(this, &ThisClass::OnAbilitySystemUninitialized)); | |
} | |
// add support for controller changing teams | |
// (Epic implemented this in ALyraCharacter but not in ALyraPawn) | |
void AXCL_Pawn::NotifyControllerChanged() | |
{ | |
const FGenericTeamId OldTeamId = GetGenericTeamId(); | |
Super::NotifyControllerChanged(); | |
// Update our team ID based on the controller | |
if (HasAuthority() && (Controller != nullptr)) | |
{ | |
if (ILyraTeamAgentInterface* ControllerWithTeam = Cast<ILyraTeamAgentInterface>(Controller)) | |
{ | |
MyTeamID = ControllerWithTeam->GetGenericTeamId(); | |
ConditionalBroadcastTeamChanged(this, OldTeamId, MyTeamID); | |
} | |
} | |
} | |
void AXCL_Pawn::OnRep_Controller() | |
{ | |
Super::OnRep_Controller(); | |
PawnExtComponent->HandleControllerChanged(); | |
} | |
void AXCL_Pawn::OnRep_PlayerState() | |
{ | |
Super::OnRep_PlayerState(); | |
PawnExtComponent->HandlePlayerStateReplicated(); | |
} | |
void AXCL_Pawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) | |
{ | |
Super::SetupPlayerInputComponent(PlayerInputComponent); | |
PawnExtComponent->SetupPlayerInputComponent(); | |
} | |
void AXCL_Pawn::OnAbilitySystemInitialized() | |
{ | |
// [xist] decided not to force a HealthComponent on every pawn. Some pawns are invincible! | |
// override this yourself in your own pawn if you want a health component. | |
// | |
//ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent(); | |
//check(LyraASC); | |
//HealthComponent->InitializeWithAbilitySystem(LyraASC); | |
InitializeGameplayTags(); | |
} | |
void AXCL_Pawn::OnAbilitySystemUninitialized() | |
{ | |
//HealthComponent->UninitializeFromAbilitySystem(); | |
} | |
void AXCL_Pawn::InitializeGameplayTags() | |
{ | |
// Clear tags that may be lingering on the ability system from the previous pawn. | |
if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) | |
{ | |
const FLyraGameplayTags& GameplayTags = FLyraGameplayTags::Get(); | |
for (const TPair<uint8, FGameplayTag>& TagMapping : GameplayTags.MovementModeTagMap) | |
{ | |
if (TagMapping.Value.IsValid()) | |
{ | |
LyraASC->SetLooseGameplayTagCount(TagMapping.Value, 0); | |
} | |
} | |
for (const TPair<uint8, FGameplayTag>& TagMapping : GameplayTags.CustomMovementModeTagMap) | |
{ | |
if (TagMapping.Value.IsValid()) | |
{ | |
LyraASC->SetLooseGameplayTagCount(TagMapping.Value, 0); | |
} | |
} | |
// [xist] removed explicit ALyraCharacter movement tag logic, made this the | |
// responsibility of derived classes - override this method to add your | |
// movement-based gameplay tag. | |
// | |
// e.g. SetMovementModeTag(MOVE_Walking, 0, true); | |
} | |
} | |
void AXCL_Pawn::SetMovementModeTag(EMovementMode MovementMode, uint8 CustomMovementMode, bool bTagEnabled) | |
{ | |
if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) | |
{ | |
const FLyraGameplayTags& GameplayTags = FLyraGameplayTags::Get(); | |
const FGameplayTag* MovementModeTag = nullptr; | |
if (MovementMode == MOVE_Custom) | |
{ | |
MovementModeTag = GameplayTags.CustomMovementModeTagMap.Find(CustomMovementMode); | |
} | |
else | |
{ | |
MovementModeTag = GameplayTags.MovementModeTagMap.Find(MovementMode); | |
} | |
if (MovementModeTag && MovementModeTag->IsValid()) | |
{ | |
LyraASC->SetLooseGameplayTagCount(*MovementModeTag, (bTagEnabled ? 1 : 0)); | |
} | |
} | |
} | |
ULyraAbilitySystemComponent* AXCL_Pawn::GetLyraAbilitySystemComponent() const | |
{ | |
return PawnExtComponent->GetLyraAbilitySystemComponent(); | |
} | |
UAbilitySystemComponent* AXCL_Pawn::GetAbilitySystemComponent() const | |
{ | |
return PawnExtComponent->GetLyraAbilitySystemComponent(); | |
} | |
void AXCL_Pawn::GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const | |
{ | |
if (const ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) | |
{ | |
LyraASC->GetOwnedGameplayTags(TagContainer); | |
} | |
} | |
bool AXCL_Pawn::HasMatchingGameplayTag(FGameplayTag TagToCheck) const | |
{ | |
if (const ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) | |
{ | |
return LyraASC->HasMatchingGameplayTag(TagToCheck); | |
} | |
return false; | |
} | |
bool AXCL_Pawn::HasAllMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const | |
{ | |
if (const ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) | |
{ | |
return LyraASC->HasAllMatchingGameplayTags(TagContainer); | |
} | |
return false; | |
} | |
bool AXCL_Pawn::HasAnyMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const | |
{ | |
if (const ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) | |
{ | |
return LyraASC->HasAnyMatchingGameplayTags(TagContainer); | |
} | |
return false; | |
} |
#pragma once | |
#include "CoreMinimal.h" | |
#include "AbilitySystemInterface.h" | |
#include "GameplayCueInterface.h" | |
#include "GameplayTagAssetInterface.h" | |
#include "Character/LyraPawn.h" | |
#include "XCL_Pawn.generated.h" | |
/** | |
* Base Pawn Class | |
* | |
* This stuff should really be implemented in ALyraPawn, but Epic put all of their ability system, | |
* gameplay cues and gameplay tags into ALyraCharacter, so we need to recreate the wheel. | |
* | |
* For the most part I just copied what they put in ALyraCharacter. | |
* | |
* If they ever move this stuff into ALyraPawn we can get rid of this class. It literally does | |
* nothing at all except what I would have expected Epic to bundle with ALyraPawn rather than | |
* with ALyraCharacter. | |
*/ | |
UCLASS() | |
class XISTCORELYRARUNTIME_API AXCL_Pawn : public ALyraPawn, public IAbilitySystemInterface, public IGameplayCueInterface, public IGameplayTagAssetInterface | |
{ | |
GENERATED_BODY() | |
private: | |
UPROPERTY(EditDefaultsOnly, Category="Lyra|Pawn", Meta = (AllowPrivateAccess = "true")) | |
class ULyraPawnExtensionComponent* PawnExtComponent; | |
public: | |
// Sets default values for this pawn's properties | |
AXCL_Pawn(); | |
//~APawn interface | |
virtual void NotifyControllerChanged() override; | |
//~End of APawn interface | |
//~Support for UPawnExtensionComponent | |
virtual void OnRep_Controller() override; | |
virtual void OnRep_PlayerState() override; | |
virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override; | |
//~End Support for UPawnExtensionComponent | |
//~ALyraCharacter-like ability system / tags implementation | |
virtual void OnAbilitySystemInitialized(); | |
virtual void OnAbilitySystemUninitialized(); | |
virtual void InitializeGameplayTags(); // [xist] made this virtual | |
virtual void SetMovementModeTag(EMovementMode MovementMode, uint8 CustomMovementMode, bool bTagEnabled); | |
UFUNCTION(BlueprintCallable, Category = "Lyra|Pawn") | |
class ULyraAbilitySystemComponent* GetLyraAbilitySystemComponent() const; | |
//~End of ALyraCharacter-like ability system implementation | |
//~IAbilitySystemInterface | |
virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override; | |
//~End of IAbilitySystemInterface | |
//~IGameplayCueInterface | |
//~End of IGameplayCueInterface | |
//~IGameplayTagAssetInterface | |
virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override; | |
virtual bool HasMatchingGameplayTag(FGameplayTag TagToCheck) const override; | |
virtual bool HasAllMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const override; | |
virtual bool HasAnyMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const override; | |
//~End of IGameplayTagAssetInterface | |
}; |
#include "ThirdPersonStrategy/XCL_TPSPlayerPawn.h" | |
#include "Character/LyraHeroComponent.h" | |
#include "Components/SphereComponent.h" | |
#include "GameFramework/FloatingPawnMovement.h" | |
// Sets default values | |
AXCL_TPSPlayerPawn::AXCL_TPSPlayerPawn() | |
{ | |
// Set this pawn to call Tick() every frame. | |
PrimaryActorTick.bCanEverTick = true; | |
SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("PrimitiveComponent")); | |
SphereComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision); | |
SphereComponent->SetCanEverAffectNavigation(false); | |
RootComponent = SphereComponent; | |
MovementComponent = CreateDefaultSubobject<UFloatingPawnMovement>(TEXT("MovementComponent")); | |
MovementComponent->SetUpdatedComponent(SphereComponent); | |
LyraHeroComponent = CreateDefaultSubobject<ULyraHeroComponent>(TEXT("LyraHeroComponent")); | |
} | |
// Called by base class | |
void AXCL_TPSPlayerPawn::InitializeGameplayTags() | |
{ | |
Super::InitializeGameplayTags(); | |
// tell the ability system that this pawn is flying | |
SetMovementModeTag(MOVE_Flying, 0, true); | |
} | |
UPawnMovementComponent* AXCL_TPSPlayerPawn::GetMovementComponent() const | |
{ | |
return MovementComponent; | |
} |
#pragma once | |
#include "CoreMinimal.h" | |
#include "Character/XCL_Pawn.h" | |
#include "XCL_TPSPlayerPawn.generated.h" | |
UCLASS() | |
class XISTCORELYRARUNTIME_API AXCL_TPSPlayerPawn : public AXCL_Pawn | |
{ | |
GENERATED_BODY() | |
private: | |
UPROPERTY(EditDefaultsOnly, Category="Xist|Pawn", Meta = (AllowPrivateAccess = "true")) | |
class USphereComponent* SphereComponent; | |
UPROPERTY(EditDefaultsOnly, Category="Xist|Pawn", Meta = (AllowPrivateAccess = "true")) | |
class UFloatingPawnMovement* MovementComponent; | |
UPROPERTY(EditDefaultsOnly, Category="Xist|Pawn", Meta = (AllowPrivateAccess = "true")) | |
class ULyraHeroComponent* LyraHeroComponent; | |
public: | |
// Sets default values for this pawn's properties | |
AXCL_TPSPlayerPawn(); | |
// Called by base class | |
virtual void InitializeGameplayTags() override; | |
//~APawn interface | |
virtual UPawnMovementComponent* GetMovementComponent() const override; | |
//~End of APawn interface | |
}; |
{ | |
"FileVersion": 3, | |
"Version": 1, | |
"VersionName": "0.1", | |
"FriendlyName": "XistCoreLyra", | |
"Description": "", | |
"Category": "Game Features", | |
"CreatedBy": "Xist", | |
"CreatedByURL": "http://xist.gg", | |
"DocsURL": "", | |
"MarketplaceURL": "", | |
"SupportURL": "", | |
"EnabledByDefault": false, | |
"CanContainContent": true, | |
"IsBetaVersion": true, | |
"IsExperimentalVersion": true, | |
"Installed": false, | |
"Modules": [ | |
{ | |
"Name": "XistCoreLyraRuntime", | |
"Type": "Runtime", | |
"LoadingPhase": "Default" | |
} | |
], | |
"Plugins": [ | |
{ | |
"Name": "CommonGame", | |
"Enabled": true | |
}, | |
{ | |
"Name": "CommonUI", | |
"Enabled": true | |
}, | |
{ | |
"Name": "EnhancedInput", | |
"Enabled": true | |
}, | |
{ | |
"Name": "GameplayAbilities", | |
"Enabled": true | |
}, | |
{ | |
"Name": "GameplayMessageRouter", | |
"Enabled": true | |
}, | |
{ | |
"Name": "ModularGameplayActors", | |
"Enabled": true | |
} | |
], | |
"ExplicitlyLoaded": true, | |
"BuiltInInitialFeatureState": "Loaded" | |
} |
using UnrealBuildTool; | |
public class XistCoreLyraRuntime : ModuleRules | |
{ | |
public XistCoreLyraRuntime(ReadOnlyTargetRules Target) : base(Target) | |
{ | |
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; | |
PublicIncludePaths.AddRange( | |
new string[] { | |
// ... add public include paths required here ... | |
} | |
); | |
PrivateIncludePaths.AddRange( | |
new string[] { | |
// ... add other private include paths required here ... | |
} | |
); | |
PublicDependencyModuleNames.AddRange( | |
new string[] | |
{ | |
"Core", | |
// ... add other public dependencies that you statically link with here ... | |
"LyraGame", | |
} | |
); | |
PrivateDependencyModuleNames.AddRange( | |
new string[] | |
{ | |
"CoreUObject", | |
"Engine", | |
"Slate", | |
"SlateCore", | |
// ... add private dependencies that you statically link with here ... | |
// Stuff needed for XCL_Pawn: | |
"AIModule", | |
"CommonInput", | |
"EnhancedInput", | |
"GameplayAbilities", | |
"GameplayMessageRuntime", | |
"GameplayTags", | |
"ModularGameplayActors", | |
} | |
); | |
DynamicallyLoadedModuleNames.AddRange( | |
new string[] | |
{ | |
// ... add any modules that your module loads dynamically here ... | |
} | |
); | |
} | |
} |
Great tutorials I really love your deep dive into this, ...
I had compilation issues and solved them exposing the 2 interface classes not just one as in the GIT above... so adding LYRAGAME_API to the second class...
class LYRAGAME_API ULyraTeamAgentInterface : public UGenericTeamAgentInterface
{
GENERATED_UINTERFACE_BODY()
};
class LYRAGAME_API ILyraTeamAgentInterface : public IGenericTeamAgentInterface
{
GENERATED_IINTERFACE_BODY()
....
I had compilation issues and solved them exposing the 2 interface classes not just one as in the GIT above... so adding LYRAGAME_API to the second class...
Thank you for the correction!
I added a note in the original comment that this might be necessary and linked to your comment for an example of how to do it.
Hey! I love your work, but I believe this gist is outdated. @x157
In XCL_Pawn.h
Old
UPROPERTY(EditDefaultsOnly, Category="Lyra|Pawn", Meta = (AllowPrivateAccess = "true"))
class ULyraPawnExtensionComponent* PawnExtComponent;
This UPROPERTY crashes the editor when opening a BP derived class, I copied what was in the ALyraCharacter class and it stopped crashing:
New
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Lyra|Pawn", Meta = (AllowPrivateAccess = "true"))
class ULyraPawnExtensionComponent* PawnExtComponent;
Additionally, I think there was a change since this gist was made and in XCL_Pawn.cpp InitializeGameplayTags() and SetMovementModeTag needs to be changed, here is mine (but I basically copied/pasted the code from ALyraCharacter):
In XCL_Pawn.cpp
void AXCL_Pawn::InitializeGameplayTags()
{
// Clear tags that may be lingering on the ability system from the previous pawn.
if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent())
{
for (const TPair<uint8, FGameplayTag>& TagMapping : LyraGameplayTags::MovementModeTagMap)
{
if (TagMapping.Value.IsValid())
{
LyraASC->SetLooseGameplayTagCount(TagMapping.Value, 0);
}
}
for (const TPair<uint8, FGameplayTag>& TagMapping : LyraGameplayTags::CustomMovementModeTagMap)
{
if (TagMapping.Value.IsValid())
{
LyraASC->SetLooseGameplayTagCount(TagMapping.Value, 0);
}
}
// [xist] removed explicit ALyraCharacter movement tag logic, made this the
// responsibility of derived classes - override this method to add your
// movement-based gameplay tag.
//
// e.g. SetMovementModeTag(MOVE_Walking, 0, true);
}
}
void AXCL_Pawn::SetMovementModeTag(EMovementMode MovementMode, uint8 CustomMovementMode, bool bTagEnabled)
{
if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent())
{
const FGameplayTag* MovementModeTag = nullptr;
if (MovementMode == MOVE_Custom)
{
MovementModeTag = LyraGameplayTags::CustomMovementModeTagMap.Find(CustomMovementMode);
}
else
{
MovementModeTag = LyraGameplayTags::MovementModeTagMap.Find(MovementMode);
}
if (MovementModeTag && MovementModeTag->IsValid())
{
LyraASC->SetLooseGameplayTagCount(*MovementModeTag, (bTagEnabled ? 1 : 0));
}
}
}
Thanks for your amazing resources again, Epic should pay you! Cheers!
Additionally I have found another issue. In the base LyraPawn.cpp
class the function PossessedBy is:
void ALyraPawn::PossessedBy(AController* NewController)
{
const FGenericTeamId OldTeamID = MyTeamID;
Super::PossessedBy(NewController);
// Grab the current team ID and listen for future changes
if (ILyraTeamAgentInterface* ControllerAsTeamProvider = Cast<ILyraTeamAgentInterface>(NewController))
{
MyTeamID = ControllerAsTeamProvider->GetGenericTeamId();
ControllerAsTeamProvider->GetTeamChangedDelegateChecked().AddDynamic(this, &ThisClass::OnControllerChangedTeam);
}
ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID);
}
However in LyraCharacter.cpp
That function is
void ALyraCharacter::PossessedBy(AController* NewController)
{
const FGenericTeamId OldTeamID = MyTeamID;
Super::PossessedBy(NewController);
PawnExtComponent->HandleControllerChanged();
// Grab the current team ID and listen for future changes
if (ILyraTeamAgentInterface* ControllerAsTeamProvider = Cast<ILyraTeamAgentInterface>(NewController))
{
MyTeamID = ControllerAsTeamProvider->GetGenericTeamId();
ControllerAsTeamProvider->GetTeamChangedDelegateChecked().AddDynamic(this, &ThisClass::OnControllerChangedTeam);
}
ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID);
}
The line PawnExtComponent->HandleControllerChanged();
is important because it continues the initialization chain for the interface IGameFrameworkInitStateInterface
that LyraPawnExtensionComponent uses.
To be honest I do not like the way the LyraCharacter is initialized for many reasons. However for my project XCL_Pawn not having PawnExtComponent->HandleControllerChanged();
caused me some issues.
Just throwing this out there just in case someone else get initialization issues. Thanks XCL for all of your work!
I had compilation issues and solved them exposing the 2 interface classes not just one as in the GIT above... so adding LYRAGAME_API to the second class...
Yep. Get private static class / linker issues in all functions using. ILyraTeamAgentInterface::ConditionalBroadcastTeamChanged
Your fix seemed to solve those linker issues for those of that want to ILyraTeamAgentInterface on our own characters.
You saved my bacon. No way I would have figured out that was the issue, as I included the AIModule correctly in the build.cs for my custom game feature. I took X_API as a black box macro for granted.
Gotta submit a report to Epic, so they fix this issue.
Several steps are necessary to accomplish this:
ALyraPawn.MyTeamID
so I could implementNotifyControllerChanged
in my derived class..Build.cs
.uplugin
AXCL_Pawn
h | cpp (XistCoreLyra base Pawn)ALyraPawn
ALyraPawn
's missingNotifyControllerChanged
ALyraPawn
itselfIAbilitySystemInterface
IGameplayCueInterface
IGameplayTagAssetInterface
InitializeGameplayTags
virtual, even though it's not in ALyraCharacterAXCL_TPSPlayerPawn.InitializeGameplayTags
AXCL_TPSPlayerPawn
h | cpp (XistCoreLyra third person strategy player pawn)AXCL_Pawn
(base pawn)Note that the final child class
AXCL_TPSPlayerPawn
doesn't really do much. This is just the bare minimum needed to get the pawn working and moving as a floating sphere connected to user input.Here's a video of me reviewing this code if you want a quick overview:
https://youtu.be/Y_j3PWhYgk4