Add core game mode framework

This commit is contained in:
2026-04-26 15:45:03 +08:00
parent e9d818e999
commit 4677d04b74
11 changed files with 419 additions and 0 deletions

View File

@@ -10,10 +10,14 @@
#include "Class/PHYClassComponent.h"
#include "Class/PHYClassSettings.h"
#include "GGA_AbilitySystemComponent.h"
#include "AI/PHYAIController.h"
APHYAICharacter::APHYAICharacter(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
AIControllerClass = APHYAIController::StaticClass();
AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
AbilitySystemComponent = CreateDefaultSubobject<UGGA_AbilitySystemComponent>(TEXT("AbilitySystemComponent"));
AbilitySystemComponent->SetIsReplicated(true);
AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);

View File

@@ -0,0 +1,22 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Game/PHYGameFrameworkSettings.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYGameFrameworkSettings)
#include "Characters/PHYPlayerCharacter.h"
#include "Game/PHYGameState.h"
#include "Game/PHYHUD.h"
#include "GameFramework/SpectatorPawn.h"
#include "Player/PHYPlayerController.h"
#include "Player/PHYPlayerState.h"
UPHYGameFrameworkSettings::UPHYGameFrameworkSettings()
{
DefaultPawnClass = APHYPlayerCharacter::StaticClass();
PlayerControllerClass = APHYPlayerController::StaticClass();
PlayerStateClass = APHYPlayerState::StaticClass();
GameStateClass = APHYGameState::StaticClass();
HUDClass = APHYHUD::StaticClass();
SpectatorClass = ASpectatorPawn::StaticClass();
}

View File

@@ -0,0 +1,116 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Game/PHYGameModeBase.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYGameModeBase)
#include "Characters/PHYPlayerCharacter.h"
#include "Game/PHYGameFrameworkSettings.h"
#include "Game/PHYGameState.h"
#include "Game/PHYHUD.h"
#include "GameFramework/SpectatorPawn.h"
#include "Player/PHYPlayerController.h"
#include "Player/PHYPlayerState.h"
namespace
{
template <typename TBase>
void ApplyConfiguredClass(const TSoftClassPtr<TBase>& ConfiguredClass, TSubclassOf<TBase>& TargetClass)
{
if (ConfiguredClass.IsNull())
{
return;
}
if (UClass* LoadedClass = ConfiguredClass.LoadSynchronous())
{
TargetClass = LoadedClass;
}
}
}
APHYGameModeBase::APHYGameModeBase(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
DefaultPawnClass = APHYPlayerCharacter::StaticClass();
PlayerControllerClass = APHYPlayerController::StaticClass();
PlayerStateClass = APHYPlayerState::StaticClass();
GameStateClass = APHYGameState::StaticClass();
HUDClass = APHYHUD::StaticClass();
SpectatorClass = ASpectatorPawn::StaticClass();
bUseSeamlessTravel = true;
bStartPlayersAsSpectators = false;
}
void APHYGameModeBase::InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage)
{
ApplyGameFrameworkSettings();
Super::InitGame(MapName, Options, ErrorMessage);
}
void APHYGameModeBase::InitGameState()
{
Super::InitGameState();
SetGameFrameworkReady(false);
}
void APHYGameModeBase::StartPlay()
{
Super::StartPlay();
SetGameFrameworkReady(true);
}
void APHYGameModeBase::PostLogin(APlayerController* NewPlayer)
{
Super::PostLogin(NewPlayer);
// 玩家登录后的队伍、职业、存档恢复由后续对应系统在这里挂接。
}
void APHYGameModeBase::Logout(AController* Exiting)
{
// 玩家退出前的持久化和队伍清理由后续对应系统在这里挂接。
Super::Logout(Exiting);
}
UClass* APHYGameModeBase::GetDefaultPawnClassForController_Implementation(AController* InController)
{
(void)InController;
return DefaultPawnClass ? DefaultPawnClass.Get() : Super::GetDefaultPawnClassForController_Implementation(InController);
}
APHYGameState* APHYGameModeBase::GetPHYGameState() const
{
return GetGameState<APHYGameState>();
}
void APHYGameModeBase::ApplyGameFrameworkSettings()
{
const UPHYGameFrameworkSettings* Settings = GetDefault<UPHYGameFrameworkSettings>();
if (!Settings)
{
return;
}
ApplyConfiguredClass(Settings->DefaultPawnClass, DefaultPawnClass);
ApplyConfiguredClass(Settings->PlayerControllerClass, PlayerControllerClass);
ApplyConfiguredClass(Settings->PlayerStateClass, PlayerStateClass);
ApplyConfiguredClass(Settings->GameStateClass, GameStateClass);
ApplyConfiguredClass(Settings->HUDClass, HUDClass);
ApplyConfiguredClass(Settings->SpectatorClass, SpectatorClass);
bUseSeamlessTravel = Settings->bUseSeamlessTravel;
bStartPlayersAsSpectators = Settings->bStartPlayersAsSpectators;
}
void APHYGameModeBase::SetGameFrameworkReady(const bool bNewReady)
{
if (APHYGameState* PHYGameState = GetPHYGameState())
{
PHYGameState->SetGameFrameworkReady(bNewReady);
}
}

View File

@@ -0,0 +1,36 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Game/PHYGameState.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYGameState)
#include "Net/UnrealNetwork.h"
APHYGameState::APHYGameState(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bReplicates = true;
}
void APHYGameState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ThisClass, bGameFrameworkReady);
}
void APHYGameState::SetGameFrameworkReady(const bool bNewReady)
{
if (!HasAuthority())
{
return;
}
bGameFrameworkReady = bNewReady;
OnRep_GameFrameworkReady();
}
void APHYGameState::OnRep_GameFrameworkReady()
{
// 预留给 HUD、UI 或战局阶段系统监听框架就绪状态。
}

View File

@@ -0,0 +1,28 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Game/PHYHUD.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYHUD)
APHYHUD::APHYHUD(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void APHYHUD::BeginPlay()
{
Super::BeginPlay();
InitializeHUDForPlayer(GetOwningPlayerController());
}
void APHYHUD::InitializeHUDForPlayer(APlayerController* OwningPlayerController)
{
if (!OwningPlayerController || bHUDInitialized)
{
return;
}
// UI 专家后续在这里接入 GenericUISystem/CommonUI 的根层级。
bHUDInitialized = true;
}

View File

@@ -0,0 +1,63 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "UObject/SoftObjectPtr.h"
#include "PHYGameFrameworkSettings.generated.h"
class AGameStateBase;
class AHUD;
class APawn;
class APlayerController;
class APlayerState;
class ASpectatorPawn;
/**
* @brief PHY 游戏框架默认类配置。
*
* GameMode 会优先使用这里配置的类,未配置时回退到项目 C++ 原生骨架。
* 这样后续需要替换为蓝图子类时,只需要改配置,不需要改业务代码。
*/
UCLASS(Config=PHYCore, DefaultConfig)
class PHY_API UPHYGameFrameworkSettings : public UObject
{
GENERATED_BODY()
public:
/** @brief 构造默认 C++ 框架类引用。 */
UPHYGameFrameworkSettings();
/** @brief 默认玩家 Pawn 类。 */
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
TSoftClassPtr<APawn> DefaultPawnClass;
/** @brief 默认玩家控制器类。 */
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
TSoftClassPtr<APlayerController> PlayerControllerClass;
/** @brief 默认玩家状态类。 */
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
TSoftClassPtr<APlayerState> PlayerStateClass;
/** @brief 默认游戏状态类。 */
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
TSoftClassPtr<AGameStateBase> GameStateClass;
/** @brief 默认 HUD 类。 */
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
TSoftClassPtr<AHUD> HUDClass;
/** @brief 默认旁观者 Pawn 类。 */
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
TSoftClassPtr<ASpectatorPawn> SpectatorClass;
/** @brief 是否启用无缝旅行,默认按多人优先启用。 */
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
bool bUseSeamlessTravel = true;
/** @brief 是否让玩家默认以旁观者身份开始。 */
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
bool bStartPlayersAsSpectators = false;
};

View File

@@ -0,0 +1,54 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "PHYGameModeBase.generated.h"
class APHYGameState;
/**
* @brief PHY 游戏模式根类。
*
* GameMode 是服务端玩法框架入口,负责绑定默认 Pawn、Controller、PlayerState、
* GameState 和 HUD。具体玩法系统仍通过 Character、ASC、输入和组件完成。
*/
UCLASS(BlueprintType, Blueprintable)
class PHY_API APHYGameModeBase : public AGameModeBase
{
GENERATED_BODY()
public:
/** @brief 构造默认项目框架类。 */
APHYGameModeBase(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
/** @brief 初始化地图参数并应用项目框架配置。 */
virtual void InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage) override;
/** @brief GameState 初始化后同步项目框架状态。 */
virtual void InitGameState() override;
/** @brief 游戏正式开始时标记框架就绪。 */
virtual void StartPlay() override;
/** @brief 玩家登录后执行项目级初始化扩展点。 */
virtual void PostLogin(APlayerController* NewPlayer) override;
/** @brief 玩家退出时执行项目级清理扩展点。 */
virtual void Logout(AController* Exiting) override;
/** @brief 按控制器返回默认 Pawn 类,后续可扩展职业或模式差异。 */
virtual UClass* GetDefaultPawnClassForController_Implementation(AController* InController) override;
/** @brief 获取强类型 PHY GameState。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Game")
APHYGameState* GetPHYGameState() const;
protected:
/** @brief 从 UPHYGameFrameworkSettings 应用可配置框架类。 */
virtual void ApplyGameFrameworkSettings();
/** @brief 标记 GameState 框架是否就绪。 */
virtual void SetGameFrameworkReady(bool bNewReady);
};

View File

@@ -0,0 +1,43 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameStateBase.h"
#include "PHYGameState.generated.h"
/**
* @brief PHY 游戏状态。
*
* 当前只承载项目框架是否完成初始化的复制状态,后续战局阶段、队伍比分、
* 复活队列等多人状态都应优先汇总到这里,而不是散落在关卡蓝图。
*/
UCLASS(BlueprintType, Blueprintable)
class PHY_API APHYGameState : public AGameStateBase
{
GENERATED_BODY()
public:
/** @brief 构造游戏状态并启用复制。 */
APHYGameState(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
/** @brief 声明需要复制的属性。 */
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
/** @brief 查询游戏框架是否已由服务端标记为就绪。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Game")
bool IsGameFrameworkReady() const { return bGameFrameworkReady; }
/** @brief 服务端设置游戏框架就绪状态。 */
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="PHY|Game")
void SetGameFrameworkReady(bool bNewReady);
protected:
/** @brief 客户端接收框架就绪状态后的扩展点。 */
UFUNCTION()
virtual void OnRep_GameFrameworkReady();
/** @brief 服务端确认 GameMode 已完成基础类和玩家流程初始化。 */
UPROPERTY(ReplicatedUsing=OnRep_GameFrameworkReady, BlueprintReadOnly, Category="PHY|Game")
bool bGameFrameworkReady = false;
};

View File

@@ -0,0 +1,39 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "PHYHUD.generated.h"
/**
* @brief PHY HUD 根入口。
*
* 首期只提供 C++ HUD 生命周期入口。真正 UI 由后续 GenericUISystem/CommonUI
* 专家接入,避免在 GameMode 或 PlayerController 中直接堆 UMG 装配逻辑。
*/
UCLASS(BlueprintType, Blueprintable)
class PHY_API APHYHUD : public AHUD
{
GENERATED_BODY()
public:
/** @brief 构造 HUD 根入口。 */
APHYHUD(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
/** @brief HUD 开始运行时初始化玩家 UI 入口。 */
virtual void BeginPlay() override;
/** @brief 初始化当前玩家的 HUD 逻辑。 */
UFUNCTION(BlueprintCallable, Category="PHY|UI")
virtual void InitializeHUDForPlayer(APlayerController* OwningPlayerController);
/** @brief 查询 HUD 是否已经完成初始化。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|UI")
bool IsHUDInitialized() const { return bHUDInitialized; }
protected:
/** @brief HUD 是否已经完成基础初始化。 */
UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|UI")
bool bHUDInitialized = false;
};