Calmer的文章

  • 首页
  • 文章归档
  • 关于页面

  • 搜索
体验游戏 笔记 推荐 工具链 工具使用 小游戏 插件 UI 软件 教程

UE常见数据(UStruct、UObject、AActor)同步应用

发表于 2025-08-25 | 分类于 游戏开发 | 0 | 阅读次数 59

引子

这个问题的探究来自于日常开发过程中遇到的一次崩溃

示例代码

//1. 结构体1
USTRUCT(BlueprintType)
struct FSubStructParamParent
{
	GENERATED_BODY()
        
	UPROPERTY(BlueprintReadWrite, EditAnywhere)
	int64 SubParentIntParam = 0;
    
	virtual bool NetSerialize(FArchive& Ar, UPackageMap* Map, bool& bOutSuccess)
	{
		Ar<<SubParentIntParam;
		return true;
	}
};

template <>
struct TStructOpsTypeTraits<FSubStructParamParent> : public TStructOpsTypeTraitsBase2<FSubStructParamParent>
{
	enum
	{
		WithNetSerializer = true,
	};
};

//2. 结构体2
USTRUCT(BlueprintType)
struct FSubStructParam : public FSubStructParamParent
{
	GENERATED_BODY()

	UPROPERTY(BlueprintReadWrite, EditAnywhere)
	int32 SubIntParam = 0;

	virtual bool NetSerialize(FArchive& Ar, UPackageMap* Map, bool& bOutSuccess) override
	{
		Super::NetSerialize(Ar, Map, bOutSuccess);
		Ar<<SubIntParam;
		return true;
	}
};

template <>
struct TStructOpsTypeTraits<FSubStructParam> : public TStructOpsTypeTraitsBase2<FSubStructParam>
{
	enum
	{
		WithNetSerializer = true,
	};
};

代码中尝试同步FSubStructParam结构体,但是在调用NetSerialize时产生了崩溃。

崩溃堆栈

Fatal error!

Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000000

0x00007ff912356fc8 UnrealEditor-PackProjectTest.dll!UScriptStruct::TCppStructOps<FSubStructParam>::NetSerialize() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Public\UObject\Class.h:1314]
0x00007ff968a6505c UnrealEditor-CoreUObject.dll!FStructProperty::NetSerializeItem() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Private\UObject\PropertyStruct.cpp:192]
0x00007ff923afc52d UnrealEditor-Engine.dll!FRepLayout::SerializeProperties_r() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\RepLayout.cpp:6659]
0x00007ff923af6ff2 UnrealEditor-Engine.dll!FRepLayout::SendPropertiesForRPC() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\RepLayout.cpp:6965]
0x00007ff923459794 UnrealEditor-Engine.dll!UNetDriver::ProcessRemoteFunctionForChannelPrivate() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\NetDriver.cpp:2736]
0x00007ff923446c83 UnrealEditor-Engine.dll!UNetDriver::InternalProcessRemoteFunctionPrivate() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\NetDriver.cpp:2557]
0x00007ff92344655b UnrealEditor-Engine.dll!UNetDriver::InternalProcessRemoteFunction() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\NetDriver.cpp:2459]
0x00007ff9234584b8 UnrealEditor-Engine.dll!UNetDriver::ProcessRemoteFunction() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\NetDriver.cpp:7555]
0x00007ff92264bc1f UnrealEditor-Engine.dll!UActorComponent::CallRemoteFunction() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\Components\ActorComponent.cpp:837]
0x00007ff968ab4cc3 UnrealEditor-CoreUObject.dll!UObject::CallFunction() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:1130]
0x00007ff968acec2e UnrealEditor-CoreUObject.dll!UObject::ProcessContextOpcode() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:3086]
0x00007ff968ad3088 UnrealEditor-CoreUObject.dll!ProcessLocalScriptFunction() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:1206]
0x00007ff968aa4fed UnrealEditor-CoreUObject.dll!ProcessScriptFunction<void (__cdecl*)(UObject *,FFrame &,void *)>() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:1039]
0x00007ff968ad2ad4 UnrealEditor-CoreUObject.dll!ProcessLocalFunction() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:1276]
0x00007ff968ad3088 UnrealEditor-CoreUObject.dll!ProcessLocalScriptFunction() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:1206]
0x00007ff968ad1fef UnrealEditor-CoreUObject.dll!UObject::ProcessInternal() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:1304]
0x00007ff968740962 UnrealEditor-CoreUObject.dll!UFunction::Invoke() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Private\UObject\Class.cpp:6847]
0x00007ff968ad0745 UnrealEditor-CoreUObject.dll!UObject::ProcessEvent() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:2144]
0x00007ff921ee2597 UnrealEditor-Engine.dll!AActor::ProcessEvent() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\Actor.cpp:1092]
0x00007ff921cb58b3 UnrealEditor-Engine.dll!TScriptDelegate<FNotThreadSafeDelegateMode>::ProcessDelegate<UObject>() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Core\Public\UObject\ScriptDelegates.h:448]
0x00007ff9227c0cc4 UnrealEditor-Engine.dll!FInputActionHandlerDynamicSignature_DelegateWrapper() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Intermediate\Build\Win64\UnrealEditor\Inc\Engine\UHT\InputComponent.gen.cpp:73]
0x00007ff9242211e7 UnrealEditor-Engine.dll!FInputActionUnifiedDelegate::Execute() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Classes\Components\InputComponent.h:302]
0x00007ff92421c657 UnrealEditor-Engine.dll!UPlayerInput::EvaluateInputDelegates() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\UserInterface\PlayerInput.cpp:1516]
0x0000027d00d2de0a UnrealEditor-EnhancedInput.dll!UEnhancedPlayerInput::EvaluateInputDelegates() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Plugins\EnhancedInput\Source\EnhancedInput\Private\EnhancedPlayerInput.cpp:749]
0x00007ff9242687d7 UnrealEditor-Engine.dll!UPlayerInput::ProcessInputStack() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\UserInterface\PlayerInput.cpp:1149]
0x00007ff9238c09c9 UnrealEditor-Engine.dll!APlayerController::ProcessPlayerInput() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\PlayerController.cpp:2738]
0x00007ff9238e0a1e UnrealEditor-Engine.dll!APlayerController::TickPlayerInput() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\PlayerController.cpp:5035]
0x00007ff9238bb967 UnrealEditor-Engine.dll!APlayerController::PlayerTick() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\PlayerController.cpp:2342]
0x00007ff9238de29b UnrealEditor-Engine.dll!APlayerController::TickActor() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\PlayerController.cpp:5194]
0x00007ff921eabf96 UnrealEditor-Engine.dll!FActorTickFunction::ExecuteTick() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\Actor.cpp:238]
0x00007ff92404878b UnrealEditor-Engine.dll!FTickFunctionTask::DoTask() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\TickTaskManager.cpp:278]
0x00007ff92404f005 UnrealEditor-Engine.dll!TGraphTask<FTickFunctionTask>::ExecuteTask() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Core\Public\Async\TaskGraphInterfaces.h:1235]
0x00007ff95cb210aa UnrealEditor-Core.dll!FNamedTaskThread::ProcessTasksNamedThread() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Core\Private\Async\TaskGraph.cpp:760]
0x00007ff95cb2174e UnrealEditor-Core.dll!FNamedTaskThread::ProcessTasksUntilQuit() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Core\Private\Async\TaskGraph.cpp:651]
0x00007ff95cb2e4de UnrealEditor-Core.dll!FTaskGraphCompatibilityImplementation::WaitUntilTasksComplete() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Core\Private\Async\TaskGraph.cpp:2122]
0x00007ff9240786c5 UnrealEditor-Engine.dll!FTickTaskSequencer::ReleaseTickGroup() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\TickTaskManager.cpp:556]
0x00007ff92407fa8b UnrealEditor-Engine.dll!FTickTaskManager::RunTickGroup() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\TickTaskManager.cpp:1583]
0x00007ff922ff6fff UnrealEditor-Engine.dll!UWorld::RunTickGroup() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\LevelTick.cpp:775]
0x00007ff9230059b6 UnrealEditor-Engine.dll!UWorld::Tick() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Engine\Private\LevelTick.cpp:1644]
0x00007ff943afcdde UnrealEditor-UnrealEd.dll!UEditorEngine::Tick() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Editor\UnrealEd\Private\EditorEngine.cpp:2041]
0x00007ff944785ba6 UnrealEditor-UnrealEd.dll!UUnrealEdEngine::Tick() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Editor\UnrealEd\Private\UnrealEdEngine.cpp:550]
0x00007ff7adc38e02 UnrealEditor.exe!FEngineLoop::Tick() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp:5924]
0x00007ff7adc5e1bc UnrealEditor.exe!GuardedMain() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Launch\Private\Launch.cpp:180]
0x00007ff7adc5e2aa UnrealEditor.exe!GuardedMainWrapper() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:118]
0x00007ff7adc61724 UnrealEditor.exe!LaunchWindowsStartup() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:258]
0x00007ff7adc76ed4 UnrealEditor.exe!WinMain() [D:\Trunk\trunk\UnrealEngine-5.4\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:298]
0x00007ff7adc7a17a UnrealEditor.exe!__scrt_common_main_seh() [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288]
0x00007ffa2db17374 KERNEL32.DLL!UnknownFunction []

最后定位到导致该崩溃原因为:在同步结构体时,自定义了结构体的NetSerialize方法,且该方法被定为了虚方法导致的。

解决方案:避免使用virtual;或者在外层包一层结构体的Handle,在Handle层定义NetSerialize方法,类似于GAS中FGameplayEffectContextHandle和FGameplayEffectContext

image.png

image.png


下面对UE常见数据同步进行一次回顾,主要讨论结构体、UObject、Actor三种数据的同步,基础类型数据不再赘述。

UE的同步方式主要是:RPC和属性同步。


一、结构体的同步

  1. 需要同步的结构体

    USTRUCT(BlueprintType)
    struct FRPCStruct
    {
    	GENERATED_BODY()
    	UPROPERTY(BlueprintReadWrite, EditAnywhere)
    	int32 IntParam = 0;
    
    	UPROPERTY(BlueprintReadWrite, EditAnywhere)
    	float FloatParam = 0.0f;
    
    	UPROPERTY(BlueprintReadWrite, EditAnywhere)
    	FSubStructParam StructParam;
    
    	UPROPERTY(BlueprintReadWrite, EditAnywhere)
    	TObjectPtr<UPackProjectParam> ParamObj = nullptr;
    
    	FString ToString() const
    	{
    		FString Result = FString::Printf(
    			TEXT("FRPCStructInfo,Int:%d, Float:%f, SubInt:%d, SubParamInt:%lld"), IntParam, FloatParam,
    			StructParam.SubIntParam, StructParam.SubParentIntParam);
    		if (IsValid(ParamObj))
    		{
    			Result += FString::Printf(TEXT("___ExtraParamObj:%d"), ParamObj->ObjIntParam);
    		}
    		return Result;
    	}
    
    	bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
    	{
    		Ar<<IntParam;
    		Ar<<FloatParam;
    		Ar<<StructParam.SubIntParam;
    		Ar<<StructParam.SubParentIntParam;
    		uint8 RepBits = 0;
    		if (Ar.IsSaving())
    		{
    			if (IsValid(ParamObj))
    			{
    				RepBits |= 1 << 0;
    			}
    		}
    		Ar.SerializeBits(&RepBits, 1);
    
    		if (RepBits & (1 << 0))
    		{
    			Ar << ParamObj;
    		}
    		bOutSuccess = true;
    		return bOutSuccess;
    	}
    };
    
    template <>
    struct TStructOpsTypeTraits<FRPCStruct> : public TStructOpsTypeTraitsBase2<FRPCStruct>
    {
    	enum
    	{
    		WithNetSerializer = true,
    	};
    };
    

Note:这里NetSerialize方法一定不能为Virtual

  1. RPC 同步Struct

    • C2S

      UFUNCTION(BlueprintCallable, Server, Reliable)
      void SendStructToServer(const FRPCStruct& InStruct);
      
    • S2C

      UFUNCTION(BlueprintCallable, Client, Reliable)
      void SendStructToClient(const FRPCStruct& InStruct);
      
  2. 属性同步Struct

    image.png

    image.png

Note:

在属性同步中,无论对结构体整体进行赋值,或者修改结构体中某一字段(基础类型),都会触发OnRep方法。

若结构体中嵌套UObject指针,但UObject为新构造对象,则无法一同同步。

若UObject本身支持同步,仅修改了UObject对象中某字段的值也是无法触发结构体的OnRep方法。

  1. 关于自定义结构体NetSerialize方法

    结构体本身若是基础数据类型的集合,不用自定义NetSerialize方法也是可以同步的,还可以通过UPROPERTY,NotReplicated标记符控制是否某字段参与同步。

    若需要更深度定义同步数据内容,则可通过自定义NetSerialize方法,而要支持自定义NetSerialize,需要定义以下结构体,这样引擎会根据配置的枚举去萃取结构体的属性。

    自定义数据较为常见的场景应用:支持TMap的同步、某些字段满足条件后才参与同步等

    image.png

    • 常见方法

      • 正在进行序列化:Ar.IsSaving()
      • 正在进行反序列化:Ar.IsLoading()
      • 序列化、反序列比特:Ar.SerializeBits
    • TMap同步方式实现思路:TMap本身是不可同步的,但是TArray可同步,因此常常通过在IsSaving的时候将TMap的Key、Value通过打包成结构体数组同步,在IsLoading时,再将同步来的TArray数据重新解析为TMap。

    • 条件同步

      uint8 RepBits = 0;
      if (Ar.IsSaving())
      {
          if (IsValid(ParamObj))
          {
              RepBits |= 1 << 0;
          }
      }
      Ar.SerializeBits(&RepBits, 1);
      
      if (RepBits & (1 << 0))
      {
          Ar << ParamObj;
      }
      

      上述代码的思路,在序列化结构体(Ar.IsSaving())时,判断ParamObj的有效性,若有效,则将RepBits的第一位置为1。

      无论序列化还是反序列化,都会调用Ar.SerializeBits(),将RepBits读入或写出后,判断ParamObj数据是否进行序列化和反序列化。

扩展思考

  • Struct 中嵌套 UObject

    若UObject本身不支持同步,也无法跟随Struct同步。

  • Struct中嵌套Actor

  • FArchive*、UPackageMap* 的作用是什么?

    image.png

    Map->GetObjectFromNetGUID()
    Map->GetNetGUIDFromObject()
    

二、UObject同步

UObject对象默认在UE中是不支持同步的,但通过某些方式或某些特殊的UObject也支持同步。

  1. RPC UObject对象

    • C2S

      UFUNCTION(BlueprintCallable, Server, Reliable)
      void SendUObjectToServer(const UObject* Param);
      

      image.png

      这里分为三种UObject类型

      • 新构造的UObject,无法同步
      • InstancedObject,可以同步,但是修改Object某字段值是无法同步的
      • 支持ReplicatedObject,可以同步,但是修改Object某字段值是无法同步的
    • S2C

      UFUNCTION(BlueprintCallable, Client, Reliable)
      void SendUObjectToClient(const UObject* Param);
      

      image.png

      这里分为三种UObject类型

      • 新构造的UObject,无法同步
      • InstancedObject,可以同步,但是修改Object某字段值是无法同步的
      • 支持ReplicatedObject,可以同步,若修改了某字段值,因为RPC快于属性同步,其在RPC中获取Object该字段值是为旧值。(其本质是因为RPC并未同步数据内容)
  2. 属性同步UObject对象

    • UObject对象定义

      这里需要重写IsSupportedForNetworkding方法,返回为true

      image.png

    • Actor中标记该UObject为网络复制

      image.png

    • 在服务将UObject对象创建后,调用AddReplicatedSubObject方法

      UStructRPCComponent::UStructRPCComponent()
      {
      	bReplicateUsingRegisteredSubObjectList = true;
      }
      
      void UStructRPCComponent::BeginPlay()
      {
      	Super::BeginPlay();
      	if(GetOwner()->HasAuthority())
      	{
      		PackProjectParam = NewObject<UPackProjectParam>(this, UPackProjectParam::StaticClass());
      		PackProjectParam->ObjIntParam = 10;
      		AddReplicatedSubObject(PackProjectParam);
      	}
      	FTimerHandle TimerHandle;
      	GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateWeakLambda(this,[this]()
      	{
      		if(IsValid(PackProjectParam))
      		{
      			PackProjectParam->ObjIntParam = 20;
      		}
      	}), 2, false);
      }
      

    Note:在Actor中定义的OnRep方法只会在创建赋值后执行一次,若后续若只是修改对象里的值,则此OnRep不会再执行。

    而定义在UObject对象内部的OnRep函数,不仅会在初次赋值UObject对象指针时调用一次,后续变更值也会调用,且时序早于上述Actor中定义的OnRep函数。

  3. 获取可复制UObject NetworkGUID的方法

    GetWorld()->GetNetDriver()->GuidCache->GetObjectFromNetGUID();
    GetWorld()->GetNetDriver()->GuidCache->GetNetGUID();
    

扩展思考

  1. 为什么InstancedObject的UObject对象可以支持同步呢?但在服务器上修改UObject对象中某字段值确不能同步呢?

​ 这里其实不难理解,InstancedObject实际是通过Package路径序列化在本地的,这里同步的其实是Package路径,同步后,通过Load恢复UObject指针内容。


三、Actor同步(UE同步的基本单位)

Actor需被标记为Replicates,本质上Actor是特殊的UObject对象,为什么他可以被同步呢?

  1. RPC Actor对象

    UFUNCTION(BlueprintCallable, Client, Reliable)
    void SendActorToClient(const AActor* InActor);
    UFUNCTION(BlueprintCallable, Server, Reliable)
    void SendActorToServer(const AActor* InActor);
    

    同上述同步UObject类似,如果Actor本身支持同步,才能通过RPC上行发到服务器,且客户端修改的内容并不会发送到服务器

    这里更多讨论下行,即SendActorToClient,这里有两种情景

    • case1:Actor是早已同步到客户端的Actor,通过RPC再发送Actor指针,能正确在客户端上获取该Actor指针。

    • case2:Actor是在服务器上临时SpawnActor,立刻通过RPC发送到客户端,那能否获得该Actor的指针呢?

      答案是获取不到。这种情况的应用其实挺多的,比如在制作坐骑系统时,可能需要临时在服务器上spawn一个坐骑actor,然后possess该actor,但是该actor还未同步到客户端,就会有问题;还比如我们网络刚连接进入游戏,会在服务器创建玩家的Pawn,此时Pawn还未复制到客户端,服务器就进行了Possess。

    那如何解决case2的问题呢?

    • 其实引擎提供了一个控制台变量,如下

      [ConsoleVariables]
      net.DelayUnmappedRPCs=1
      

      其会保证RPC中Actor*若还未复制到客户端,会延迟到Actor复制到客户端后再调用对应的RPC。

  2. 属性同步Actor对象

    image.png
    Actor本身未标记未Replicates,那么则不可复制。

    Actor本身标记为Replicates

    • case1:Actor早已复制到客户端,那么在服务器赋值该字段,可以正常在OnRep方法中获取到Actor对象。

    • case2:Actor为临时Spawn的Actor,能否正确在OnRep中获取到Actor对象。

      答案是OnRep可以正确获取到该AActor对象。那说明AActor的复制早于当前属性同步吗?

  3. 获取ActorNetworkGUID的方法

GetWorld()->GetNetDriver()->GetGUIDForActor()
GetWorld()->GetNetDriver()->GetActorForGUID()

扩展讨论

  • UE后续版本支持了InstancedStruct,那么InstancedStruct支持直接同步吗?

  • UE的同步单位是什么呢?

  • 网络通信相关对象:UNetDriver、UNetConnection、Actor、ActorChannel、FOutBunch

  • Socket、网络底层模型(TCP/IP、OSI)

  • UE中DS的常见优化方式

结语

网络同步的基础,是基于OSI七层模型或TCP/IP四层模型,在传输层基于TCP或UDP协议来提供端到端的通信。

而一般网络序列化的思路:将数据结构序列化为二进制数据流进行网络传输,再将二进制数据流反序列化为数据结构。

以UE为例子:

  • 序列化:将UStruct->FString(数据结构格式:Json、Xml等)->TArray
  • 端到端通信:TCP/UDP
  • 反序列化:TArray->FString->UStruct
  • 本文作者: Calmer
  • 本文链接: https://mytechplayer.com/archives/ue常见数据ustructuobjectaactor同步应用
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
# 笔记
UE5局部资源打包方案
  • 文章目录
  • 站点概览
Calmer

Calmer

89 日志
7 分类
10 标签
RSS
Creative Commons
0%
© 2020 — 2025 Calmer
由 Halo 强力驱动
蜀ICP备20010026号-1川公网安备51019002006543
Copyright © 2020-2025 Calmer的文章