This commit is contained in:
2023-06-29 11:55:02 +08:00
commit 36e95249b1
1236 changed files with 464197 additions and 0 deletions

View File

@@ -0,0 +1,379 @@
---
title: GAS网络联机笔记
date: 2022-12-09 14:57:04
excerpt:
tags: Online
rating: ⭐
---
## 资料链接
https://docs.unrealengine.com/en-US/Resources/Showcases/BlueprintMultiplayer/index.html
https://docs.unrealengine.com/en-US/ProgrammingAndScripting/Blueprints/UserGuide/OnlineNodes/index.html
### 视频
- 虚幻引擎多人联机网络基础 | Network Multiplayer Fundamentals(真实字幕组) https://www.bilibili.com/video/BV1rV41167Em
## 测试用启动参数
```bash
C:\UnrealEngine\UnrealEngine\Engine\Binaries\Win64\UE4Editor.exe "C:\UnrealEngine\Project\SDHGame\SDHGame.uproject" -game -WINDOWED -WinX=0 -WinY=270 -ResX=960 -ResY=600
C:\UnrealEngine\UnrealEngine\Engine\Binaries\Win64\UE4Editor.exe "C:\UnrealEngine\Project\SDHGame\SDHGame.uproject" /Game/SceneAssets/Maps/GameplayDevelopMap?game=MyGame -server -log
```
## UE4原生部分
### 属性复制
- 对于不想序列化的临时属性比如CurrentHealth可以勾选transient
### RPC
### 网络模式(ENetMode)
- NM_DedicatedServer纯服务器
- NM_ListenServer客户端与服务器
- NM_Client纯客户端
在函数中判断当前模式:
```c++
if(GetNetMode() == NM_DedicatedServer)
{}
```
- 局域网联机的FPS游戏
- 以NM_Standalone启动, 创建或加入房间
- 如果是房主创建房间, 则变为NM_ListenServer
- 如果是加入房间, 则变为NM_Client
- 广域网MMO等游戏
- 服务器以NM_DedicatedServer启动, 并只会是该模式
- 客户端以NM_Standalone启动, 连接服务器后变为NM_Client
- 命令行传递参数启动程序
- 客户端启动参数添加服务器地址, 直接连接, 以NM_Client启动
- 客户端启动参数中地图开启?Listen, 以NM_ListenServer启动
- 客户端启动参数中添加-Server, 以NM_DedicatedServer启动
### 流程
《Exploring in UE4》关于网络同步的理解与思考[概念理解]https://zhuanlan.zhihu.com/p/34721113
主要步骤如下:
1. 客户端发送连接请求
2. 服务器将在本地调用 AGameMode::PreLogin。这样可以使 GameMode 有机会拒绝连接。
3. 如果服务器接受连接,则发送当前地图
4. 服务器等待客户端加载此地图客户端如果加载成功会发送Join信息到服务器
5. 如果接受连接,服务器将调用 AGameMode::Login该函数的作用是创建一个PlayerController可用于在今后复制到新连接的客户端。成功接收后这个PlayerController 将替代客户端的临时PlayerController (之前被用作连接过程中的占位符)。
此时将调用 APlayerController::BeginPlay。应当注意的是在此 actor 上调用RPC 函数尚存在安全风险。您应当等待 AGameMode::PostLogin 被调用完成。
6. 如果一切顺利AGameMode::PostLogin 将被调用。这时,可以放心的让服务器在此 PlayerController 上开始调用RPC 函数。
#### 需要知道的概念
- PlayerController一定是客户端第一次链接到服务器服务器同步过来的这个PlayerController也就是上面的第五点后面称其为拥有连接的PlayerController。进一步来说这个Controller里面包含着相关的NetDriverConnection以及Session信息。
- 对于任何一个Actor客户端上他可以有连接也可以无连接。一旦Actor有连接他的Role控制权限就是ROLE_AutonomousProxy如果没有连接他的Role控制权限就是ROLE_SimulatedProxy 。
#### 问题
##### Actor的Role是ROLE_Authority就是服务端么
**并不是**有了前面的讲述我们已经可以理解如果我在客户端创建一个独有的Actor(不能勾选bReplicate。那么这个Actor的Role就是ROLE_Authority所以这时候你就不能通过判断他的Role来确定当前调试的是客户端还是服务器。这时候最准确的办法是获取到**NetDiver**,然后通过**NetDiver**找到Connection。事实上GetNetMode()函数就是通过这个方法来判断当前是否是服务器的对于服务器来说他只有N个ClientConnections对于客户端来说只有一个serverConnection。
如何找到NetDriver呢?可以参考下面的图片从Outer获取到当前的Level然后通过Level找到World。World里面就有一个NetDiver。当然方法
### 其他
- 编辑器设置-Multipplayer Options-玩家个数,是的播放时能开启多个窗口(代表多个玩家)进行调试。
- 对于角色类除了需要勾选Replicates还需要勾选Replicate Movement
#### Sessions与相关函数
- FindSessions寻找房间并且生成一个Session数组。
##### CreateSession
- PublicConnections:连接数
- UseLan是否是局域网游戏
- OnSuccess=》OpenLevel在Option中添加listen这样就会开启监听服务器
##### JoinSession
GetGameInstanceCast当前自定义游戏实例=》JoinSession
### 蓝图多人设计游戏笔记
- 关卡蓝图中Beginplay中首先通过GameInstance调用TransitionToState()状态为Playing
- 用一个MainMenu关卡作为菜单界面
- PlayerState记录玩家的分数与id原生实现。Replicates=trueNetDormancy=Awake
- GameState
- GameMode实现玩家重生、登录以后的逻辑将玩家Pawn引用加到对应数组中以及指定若干类Pawn、Controller、GameState、PlayerState
- PlayerController控制角色相关UI以及在登录后执行一次角色重生函数。
#### GameInstance
自带状态枚举:
- StartUp
- MainMenu
- ServerList
- LoadingScreen
- ErrorDialog
- Playing
- Unknown
**实现逻辑**
- 实现Transition()根据枚举执行不同的操作比如隐藏UI、销毁Session。
- 实现IsCurrentState()判断是否枚举是否相同返回bool。
- 显示主菜单逻辑根据当前游戏状态Playing或者MainMenu显示游戏菜单或者退回主菜单打开主界面关卡
- 显示载入界面逻辑切换成载入界面。如果没有创建UMG就创建并赋值
- HostGameEvent显示载入界面=》创建Session=》打开游戏地图,
- ShowServerListEvent显示服务器列表UI。
- JoinFromServerListEvent显示载入界面=》JoinSession
- 错误处理打印错误信息。c++代码会触发这些事件NetworkError与TravelError。
### ShooterGame c++ 笔记
#### RPC UFUNCTION Meta
- server服务端执行
- client客户端执行
- NetMulticast多播
- reliable可靠RPC
- unreliable不可靠RPC
- WithValidation需要验证
#### Class
- AShooterTeamStart 出生点
- AShooterCheatManager 作弊管理器
#### AShooterCharacter
```
//////////////////////////////////////////////////////////////////////////
// Replication
void AShooterCharacter::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker)
{
Super::PreReplication(ChangedPropertyTracker);
//只有在这个属性发生变化后才会在短时间内复制这个属性这样加入进度中的玩家才不会在后期加入时被喷fx。
DOREPLIFETIME_ACTIVE_OVERRIDE(AShooterCharacter, LastTakeHitInfo, GetWorld() && GetWorld()->GetTimeSeconds() < LastTakeHitTimeTimeout);
}
void AShooterCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
//只对本地所有者:武器更换请求是本地发起的,其他客户不需要。
DOREPLIFETIME_CONDITION(AShooterCharacter, Inventory, COND_OwnerOnly);
//除了本地拥有者:改变的本地激发者
// everyone except local owner: flag change is locally instigated
DOREPLIFETIME_CONDITION(AShooterCharacter, bIsTargeting, COND_SkipOwner);
DOREPLIFETIME_CONDITION(AShooterCharacter, bWantsToRun, COND_SkipOwner);
DOREPLIFETIME_CONDITION(AShooterCharacter, LastTakeHitInfo, COND_Custom);
// everyone
DOREPLIFETIME(AShooterCharacter, CurrentWeapon);
DOREPLIFETIME(AShooterCharacter, Health);
}
```
#### AShooterPlayerController
- 一堆OnlineSubsystem东西比如查询成绩、加载朋友信息……
- SimulateInputKey():用于自动测试。
- 控制InGame菜单
- ReceivedNetworkEncryptionToken()与ReceivedNetworkEncryptionAck()对传输进行加密。使用一个定义的密钥。
##### ClientStartOnlineGame_Implementation
使用OnlineSession的联机游戏
#### ShooterGameInstance
- HostGame开房间函数url参数为地图。可在FShooterMainMenu::HostGame()查看格式)
- JoinSession进房间调用Session->JoinSession切换地图。
- BeginHostingQuickMatch快速游戏直接切换地图。
- OnPostLoadMap隐藏载入界面。
- FindSessions寻找房间。
- HostQuickSession开始游戏同时开房间。
```
/** Main menu UI */
TSharedPtr<FShooterMainMenu> MainMenuUI;
/** Message menu (Shown in the even of errors - unable to connect etc) */
TSharedPtr<FShooterMessageMenu> MessageMenuUI;
/** Welcome menu UI (for consoles) */
TSharedPtr<FShooterWelcomeMenu> WelcomeMenuUI;
/** Dialog widget to show non-interactive waiting messages for network timeouts and such. */
TSharedPtr<SShooterWaitDialog> WaitMessageWidget;
```
#### Online文件夹中文件
GameMode管理游戏的游戏方式与规则
- ShooterGameMode(基类)
- ShooterGame_FreeForAll
- ShooterGame_TermDeathMatch
##### AShooterGameSession
继承AGameSession。
匹配StartMatchmaking()、ContinueMatchmaking()会调用JoinSession()。
- RegisterServer
- HostSession
- FindSessions
- JoinSession
###### 委托
```
/** Delegate for creating a new session */
FOnCreateSessionCompleteDelegate OnCreateSessionCompleteDelegate;
/** Delegate after starting a session */
FOnStartSessionCompleteDelegate OnStartSessionCompleteDelegate;
/** Delegate for destroying a session */
FOnDestroySessionCompleteDelegate OnDestroySessionCompleteDelegate;
/** Delegate for searching for sessions */
FOnFindSessionsCompleteDelegate OnFindSessionsCompleteDelegate;
/** Delegate after joining a session */
FOnJoinSessionCompleteDelegate OnJoinSessionCompleteDelegate;
//OnlineSubSystem交互的
OnFindSessionsComplete(bool bWasSuccessful)
void AShooterGameSession::OnJoinSessionComplete(FName InSessionName, EOnJoinSessionCompleteResult::Type Result)
{
bool bWillTravel = false;
UE_LOG(LogOnlineGame, Verbose, TEXT("OnJoinSessionComplete %s bSuccess: %d"), *InSessionName.ToString(), static_cast<int32>(Result));
IOnlineSubsystem* OnlineSub = Online::GetSubsystem(GetWorld());
if (OnlineSub)
{
IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface();
if (Sessions.IsValid())
{
Sessions->ClearOnJoinSessionCompleteDelegate_Handle(OnJoinSessionCompleteDelegateHandle);
}
}
OnJoinSessionComplete().Broadcast(Result);
}
```
### 专用服务器
https://docs.unrealengine.com/en-US/InteractiveExperiences/Networking/HowTo/DedicatedServers/index.html
- 打包选择专用服务器(需要使用源码版引擎)
- MyProjectServer.exe -log
### 复制优化
设置Replicate中属性比如
- 当不需要复制时,关闭复制。
- 适当降低Net Update Frequency
- NetCullDistanceSquared
- NetClientTicksPerSecond
- NetDormancy可以一开始将Actor设置为只在初始化同步之后根据事件调用ForceNetUpdate或者将Net Dormancy设置为Awake。
- Relevancy
命令行输入netprofile运行一会后输入netprofile disable来停止记录之后就可以在Saved中找到网络性能报告了。
### 服务器切换
当前服务器掉线时切换为玩家作为服务器。
https://docs.unrealengine.com/zh-CN/InteractiveExperiences/Networking/Travelling/index.html
### 其他
- 蓝图节点IsLocallyController判断角色是本地模拟还是远程控制。在c++是GetRomoteRole
- Instigator每个Actor拥有变量用于判断是谁触发了XX效果可以用来谁击杀了玩家以及谁得分了。
- 尽量避免使用RPC使用OnRep_XX是个好的选择。
- Movement属于不可靠复制。可靠复制会占用一个特殊的buff队列控制每帧发送可靠复制的量以节约资源。
- 主机迁移当前服务器离线时会让其中一个玩家充当服务器1、非无缝会出现加载框
- OnValidData标签用于验证数据是否有效防止作弊需要实现一个返回值为bool的XXX_ValidData函数。
### Online Beacon 基类
Beacon 类执行的常规操作是请求服务质量信息、在客户端需要加入的游戏中预留空位、接收游戏中玩家名列表、获取正在进行的游戏中的得分和运行时间,等等。 以下类由引擎提供,构成了 Online Beacon 系统的基础:
#### AOnlineBeacon
这是 AOnlineBeaconClient 和 AOnlineBeaconHost 的基类。 它直接派生自 AActor。
#### AOnlineBeaconHost
此类使用其自身的 UNetDriver 获得来自远程客户端电脑的传入 Online Beacon 连接。 接收到连接时,它将在注册 AOnlineBeaconHostObject 实例列表中进行查找,找到与传入客户端匹配的实例并转交连接。 此类通常不需要被派生,因其只管理客户端和注册 AOnlineBeaconHostObject 之间的初始连接。
#### AOnlineBeaconClient
此类的子项连接到主机并执行实际的 RPC。 它们其中一个将在客户端电脑上生成,一个由正确的 AOnlineBeaconHostObject注册到服务器的 AOnlineBeaconHost在服务器上生成。 GetBeaconType 函数的输出(即为类名称)将用于对比此类的实例和正确主机对象类的注册实例。 注意:这和普通的 Actor 生成方式(服务器生成 Actor 然后复制到客户端)不同。 然而,客户端和服务器对象副本之间的连接建立后,对象复制将正常进行,任意一方均可向对方执行 RPC而对象的服务器版本可对属性复制发送命令。 该基类实现 OnConnected 和 OnFailure 函数。这两个函数可由子类覆盖,在连接时执行 RPC或处理失败连接。 此类是 Online Beacon 系统的主力,将执行 Beacon 所需的客户端端的工作。 在成功连接事件中,服务器上将生成和源实例同步的另一个实例,此例也可执行服务器端的工作,通过客户端和服务器 RPC或服务器到客户端的复制属性进行协调和交流。
#### AOnlineBeaconHostObject
此类也应被覆盖,使其和覆盖的 AOnlineBeaconClient 类配对。 将客户端 GetBeaconType 的返回值和保存在 BeaconTypeName 成员变量中的值进行匹配即可完成配对。 服务器的 AOnlineBeaconHost 检测到传入 AOnlineBeaconClient 的配对 AOnlineBeaconHostObject 时,它将指示 AOnlineBeaconHostObject 通过虚拟 SpawnBeaconActor 函数生成 AOnlineBeaconClient 的本地副本。 此函数默认使用 ClientBeaconActorClass 成员变量确定要生成的 actor 类,此类应被设为配对的 AOnlineBeaconClient 类。 它还将在生成对象的服务器副本上调用 SetBeaconOwner以便客户端对象的服务器端实例与主机对象进行交流。 此设置多数建立在基类中,无需被覆盖。
### 插件
下面是2个牛逼插件
- Advanced Steam Sessions
- Advanced Session
常规用法:
http://community.metahusk.com/topic/26/community-project-cardinal-menu-system-instructions-help-and-discussion
#### 官方插件
- Steam Sockets https://docs.unrealengine.com/zh-CN/InteractiveExperiences/Networking/HowTo/SteamSockets/index.html
- Online Subsystem
- Replication Graph插件 Replication Graph插件是一个用于多人游戏的网络复制系统它的设计可以很好地适应大量玩家和复制Actor。例如Epic自己的Fortnite Battle Royale 从一开始就支持每场比赛100名玩家包含大约50,000个复制的Actor。https://www.bilibili.com/medialist/play/watchlater/BV1Xb411h7hp
## GAS部分
### Replication
- `#include "UnrealNetwork.h"`
- 给对应的变量添加Replicated标记
- 重写void GetLifetimeReplicatedProps(TArray&amp; OutLifetimeProps),并添加对应变量的代码,例如: DOREPLIFETIME_CONDITION_NOTIFY( UMyAttributeSet, MyAttribute, COND_None, REPNOTIFY_Always);
- 属性钩子函数UPROPERTY( ReplicatedUsing = OnRep_MyAttribute)、void OnRep_MyAttribute()
### 需要在c++对应的构造函数中进行初始化
```c++
AGDPlayerState :: AGDPlayerState
{
//创建能力系统组件,并将其设置为显式复制
AbilitySystemComponent = CreateDefaultSubobject <UGDAbilitySystemComponent> TEXT “ AbilitySystemComponent ”));;
AbilitySystemComponent-> SetIsReplicatedtrue;
// ...
}
void APACharacterBase :: PossessedByAController * NewController
{
Super :: PossessedByNewController;
如果AbilitySystemComponent
{
AbilitySystemComponent-> InitAbilityActorInfothisthis;
}
// ASC MixedMode复制要求ASC所有者的所有者为控制器。
SetOwnerNewController;
}
// Server only
void AGDHeroCharacter::PossessedBy(AController * NewController)
{
Super::PossessedBy(NewController);
AGDPlayerState* PS = GetPlayerState<AGDPlayerState>();
if (PS)
{
// Set the ASC on the Server. Clients do this in OnRep_PlayerState()
AbilitySystemComponent = Cast<UGDAbilitySystemComponent>(PS->GetAbilitySystemComponent());
// AI won't have PlayerControllers so we can init again here just to be sure. No harm in initing twice for heroes that have PlayerControllers.
PS->GetAbilitySystemComponent()->InitAbilityActorInfo(PS, this);
}
//...
}
// Client only
void AGDHeroCharacter::OnRep_PlayerState()
{
Super::OnRep_PlayerState();
AGDPlayerState* PS = GetPlayerState<AGDPlayerState>();
if (PS)
{
// Set the ASC for clients. Server does this in PossessedBy.
AbilitySystemComponent = Cast<UGDAbilitySystemComponent>(PS->GetAbilitySystemComponent());
// Init ASC Actor Info for clients. Server will init its ASC when it possesses a new Actor.
AbilitySystemComponent->InitAbilityActorInfo(PS, this);
}
// ...
}
```
### Net Security Policy
A GameplayAbility's NetSecurityPolicy determines where should an ability execute on the network. It provides protection from clients attempting to execute restricted abilities.
- NetSecurityPolicy Description
ClientOrServer No security requirements. Client or server can trigger execution and termination of this ability freely.
- ServerOnlyExecution A client requesting execution of this ability will be ignored by the server. Clients can still request that the server cancel or end this ability.
- ServerOnlyTermination A client requesting cancellation or ending of this ability will be ignored by the server. Clients can still request execution of the ability.
- ServerOnly Server controls both execution and termination of this ability. A client making any requests will be ignored.
## 专用服务器查找
https://answers.unrealengine.com/questions/502967/dedicated-server-find-session-issues.html?sort=oldest
Dedicated servers must have "Use Presence" and "Allow Join Via Presence" set to false.
Maybe that could solve your problem :)

View File

@@ -0,0 +1,117 @@
---
title: OnlineSubsystem使用笔记
date: 2022-12-09 14:59:15
excerpt:
tags: Online
rating: ⭐
---
## 参考
《Exploring in UE4》Session与Onlinesubsystem[概念理解]https://zhuanlan.zhihu.com/p/34257172
https://dawnarc.com/2019/07/ue4networking-in-baisc-sessions/
## 添加模块
![](https://oscimg.oschina.net/oscnet/6501b00e721d9867e9422c057d79a3f8323.png)
## 添加配置
在DefaultEngine.ini中的 [OnlineSubsytem]标签下将DefaultPlatformService指定为所需服务。测试则使用Steam
在确定平台后UE4就会去加载OnlineSubsystem +Name的模块。
ps1.OnlineSubsystemNull为本地处理模块。
ps2.加载成功后还要继续调用对应平台Module的StartupModule函数。如果是steam还需要到”../Engine/Binaries/ThirdParty/ Steamworks/Steamv132/Win64/”路径下去加载其平台的dll文件(路径可能有些偏差具体看文件steam_api64.dll的位置) 代码如下:
```c++
FString RootSteamPath = GetSteamModulePath();
FPlatformProcess::PushDllDirectory(*RootSteamPath);
SteamDLLHandle = FPlatformProcess::GetDllHandle(*(RootSteamPath + "steam_api64.dll "));
```
### 添加OnlineSubsystemSteam配置
一般默认在非Shipping版本或者配置文件OnlineSubsystemSteam的bEnable为false的情况下在初始化OnlinesubsystemSteam的时候包括其他平台会CreateSubsystem失败然后Destroy该Onlinesubsystem。这样引擎会默认创建OnlinesubsystemNull来替代。所以需要将bEnable设置成true。
![](https://img-blog.csdn.net/20180203094035717?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjk5OTk4NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
### 配置Steam SDK过程
UE4使用steam子系统发布steam包https://www.cnblogs.com/VirtualJourneyStudio/archive/2004/01/13/10557044.html
## 文档笔记
https://docs.unrealengine.com/zh-CN/ProgrammingAndScripting/Online/index.html
static IOnlineSubsystem* Get(const FName& SubsystemName = NAME_None)
### 主要接口
- Achievements列出游戏中的所有成就解锁成就并查看自己和其他用户已解锁的成就。
- External UI打开特定硬件平台或在线服务的内置用户接口。在某些情况下仅可通过此接口获取部分核心功能的访问权。
- Friends好友和好友列表的相关内容例如在好友列表中添加用户、阻止和解除阻止用户以及列出最近遇到的在线玩家。
- Leaderboard访问在线排行榜包括登记自己的得分或时间以及在排行榜中查看好友列表或世界其他玩家的得分。
- Online User收集关于用户的元数据。
- Presence设置用户在线状态的显示方式例如"在线"、"离开"、"游戏中"等。
- Purchase进行游戏内购和查看购买历史。
- Session创建、撤销和管理在线游戏会话。还包括搜索会话和配对系统。
- Store检索游戏内购可用的条目和特定价格。
- User Cloud提供每个用户云文件存储的接口。
#### Sessions
- 使用所需设置创建新会话
- 等待玩家申请加入比赛
- 注册想要加入的玩家
- 开始会话
- 玩游戏
- 终止会话
- 取消玩家注册
或者:
- 如果你想要变更比赛类型并返回以等待玩家加入,则更新会话
- 终止会话
#### FOnlineSessionSettings
FOnlineSessionSettings除了这些基础属性外可以增加一些自定义属性具体是往一个FOnlineKeyValuePairs<FName, FOnlineSessionSetting>里添加属性之后客户端在OnFindSessionsComplete()中再通过指定的FName取出。
- bAllowJoinInProgress
- bIsDedicated
- bIsLANMatch
- ShouldAdvertise
- bUsesPresence
- NumPublicConnections
- NumPrivateConnections
```
/** Array of custom session settings */
FSessionSettings Settings;
/** Type defining an array of session settings accessible by key */
typedef FOnlineKeyValuePairs<FName, FOnlineSessionSetting> FSessionSettings;
struct FOnlineSessionSetting
{
public:
/** Settings value */
FVariantData Data;
/** How is this session setting advertised with the backend or searches */
EOnlineDataAdvertisementType::Type AdvertisementType;
/** Optional ID used in some platforms as the index instead of the session name */
int32 ID;
}
```
##### Steam设置
对于Steam需要设置以下一些属性
- ShooterHostSettings->Set(SETTING_MATCHING_HOPPER, FString("TeamDeathmatch"), EOnlineDataAdvertisementType::DontAdvertise);
- ShooterHostSettings->Set(SETTING_MATCHING_TIMEOUT, 120.0f, EOnlineDataAdvertisementType::ViaOnlineService);
- ShooterHostSettings->Set(SETTING_SESSION_TEMPLATE_NAME, FString("GameSession"), EOnlineDataAdvertisementType::DontAdvertise);
- ShooterHostSettings->Set(SETTING_GAMEMODE, FString("TeamDeathmatch"), EOnlineDataAdvertisementType::ViaOnlineService);
- ShooterHostSettings->Set(SETTING_MAPNAME, GetWorld()->GetMapName(), EOnlineDataAdvertisementType::ViaOnlineService);
##### EOnlineDataAdvertisementType
服务器数据广播方式:
```
/** Don't advertise via the online service or QoS data */
DontAdvertise,
/** Advertise via the server ping data only */
ViaPingOnly,
/** Advertise via the online service only */
ViaOnlineService,
/** Advertise via the online service and via the ping data */
ViaOnlineServiceAndPing
```
## 其他代码参考
在Online模块下有个OnlineFramework文件夹。

View File

@@ -0,0 +1,51 @@
---
title: 在帧同步战斗上加入UE4的DS(专有服务器)的简单尝试
date: 2022-12-09 15:10:14
excerpt:
tags: Online
rating: ⭐
---
## 原文地址
帧同步框架下添加状态同步记录
https://zhuanlan.zhihu.com/p/399047125
在帧同步战斗上加入UE4的DS(专有服务器)的简单尝试
https://zhuanlan.zhihu.com/p/480154978
## 其他工程
https://github.com/HiganFish/UE4SpaceShipBattleOL
## 实现细节
DS本质上使用的是状态同步那么大思路是参考我之前的一个文章参考帧同步框架下添加状态同步记录。
下面主要讲下实现的一些细节:
分离服务器和客户端逻辑
这个工作主要是把战斗中只需要在服务器执行的逻辑分离出来比如属性数值计算相关攻击碰撞检测技能buff释放逻辑子弹释放逻辑怪物AI等。大思路是服务器只下发角色属性和状态信息客户端根据逻辑进行相应的状态切换(包括技能释放)但不会执行和真实逻辑有关的计算。
服务器和客户端通信方式
这里使用UE4提供的RPC调用。使用UStruct定义的结构作为协议。省去了自己实现序列化和反序列化的工作。
调整框架
因为使用DS后GameModeBattle只存在于服务端。固客户端上的BaseBattle就需要另外找个地方可以更新。一番研究后选择了NetPlayerController(继承自PlayerController)。
根据Replication客户端的NetPlayerController是由客户端连上服务器后服务器创建然后复制给客户端的。RPC调用也是写在NetPlayerController里不管是服务器调用客户端还是客户端调用服务器。
调整单位创建流程
之前文章里的服务器其实只要跑逻辑部分不需要Native层相关的资源。现在因为要使用CharacterMovementComponent和移动预测服务器上的单位也必须把GameActor创建出来。创建后是由Replication复制到客户端并且同时复制这个单位的逻辑唯一ID属性(PID)。
原本逻辑上是由BeActor创建GeActor并且创建GameActor。现在需要改成客户端收到服务器创建单位的消息后创建BeActor(也会设置PID)并且创建GeActor但是不创建GameActor。等GameActor从服务器复制到客户端后在GameActor的StartPlay里启动绑定流程把这个GameActor绑定到相同PID的BeActor的GeActor上。PID是服务器和客户端标识同一单位的属性。
删除的时候也是同理。客户端收到删除消息后把BeActor以及GeActor删除GameActor由Replication同步来删除。
这里顺便提下子弹 的做法。子弹因为一般都是以一定速度沿特定轨迹移动所以没有继承CharacterMovementComponent。为了优化流量消耗子弹的位置可以不需要服务器每帧更新。只需在创建信息把速度创建轨迹等参数下发客户端就可以自行创建这个子弹以及轨迹移动做表现。
使用UE4 CharacterMovementComponent
要使用CharacterMovementComponent需要使用Character。于是原本的基于Actor的GameActor改为继承Character并且设置相关的参数调整碰撞胶囊体的大小。
修改逻辑自带的移动组件主要是每帧把逻辑层的速度设置给MovementComponent的Velocity。并且每帧取得组件Location反设给自带移动组件。因为逻辑上层还是通过访问自带移动组件来进行位置的判断。
服务器上也需要每帧把逻辑的信息更新给CharacterMovementComponent包括位置旋转和缩放
使用移动预测
拥有CharacterMovementComponent的Character需要是ROLE_AutonomousProxy才可以进行预测。而且现在的框架上NetPlayerController是先创建然后才会创建GameActor因此需要在服务器上执行PlayerController的Posses函数来设置控制的Actor。
本地客户端对于ROLE_AutonomousProxy的GameActor需要在Run和Idle对CharacterMovementComponent设置Velocity来驱动组件移动。这样对于移动和停止的Idle本地客户端不会等服务器的Replication就会立马进行。 而对于其他玩家和怪物则是ROLE_SimulatedProxy全程由Replication来进行位置变化
怪物寻路
使用navmesh直接在服务器端调用navmesh寻路接口返回得到路径点在原来的AI移动逻辑上调整代码沿着路径点行走即可。