整体概述参见:https://dreamyouxi.com/blog/1203

服务器战斗端与客户端采用了类似的架构,共享相同的概念(GameObject、Prefab、GetComponent、BoxCollider 等),因此在资源层面可以做到很好的复用。

序列化分为两步:第一步是将 io 文件反序列化为内存中的 Prefab 对象;第二步是从 Prefab 对象生成各种 class 的数据。

第一步:从 io 文件到内存 Prefab


                template<typename Class>
                inline  void DeSerializeRigidbody(Prefabs * pre, Class& obj)
                {
                	bool ok = false;
                	do
                	{
                		PARSE_OBJECT_MEMBER(pre->hasRigidbody, "hasRigidbody");
                		PARSE_OBJECT_MEMBER(pre->rigidbody.useGravity, "useGravity");
                		PARSE_OBJECT_MEMBER(pre->rigidbody.isKinematic, "isKinematic");
                		PARSE_OBJECT_MEMBER(pre->rigidbody.mass, "mass");
                		PARSE_OBJECT_MEMBER(pre->rigidbody.drag, "drag");
                		PARSE_OBJECT_MEMBER(pre->rigidbody.angularDrag, "angularDrag");
                	} while (false);
                }
                
                template<typename Class>
                inline  void DeSerializeCapsuleColliders(Prefabs * pre, Class& obj2)
                {
                	for (auto it = obj2.begin(); it != obj2.end(); ++it)
                	{
                		auto &obj = it->GetJsonObject();
                		pre->capsuleColliders.emplace_back(CapsuleCollider::Serialize());
                		auto &col = pre->capsuleColliders[pre->capsuleColliders.size() - 1];
                		bool ok = false;
                
                		PARSE_OBJECT_MEMBER(col.radius, "radius");
                		PARSE_OBJECT_MEMBER(col.height, "height");
                		PARSE_OBJECT_MEMBER(col.direction, "direction");
                		PARSE_OBJECT_MEMBER(col.isTrigger, "isTrigger");
                	}
                }
                

第二步:从 Prefab 生成 GameObject 或 CppBehaviour

/*
                * Author:  caoshanshan
                * Email:   me@dreamyouxi.com
                
                */
                #pragma  once
                
                #include "battle/BaseAPI.h"
                #include "battle_app/BattleMisc.h"
                
                class BallisticSimulater :public CppBehaviour
                {
                	DEFINE_SUB_CLASS(CLASS_ID_BallisticSimulater, BallisticSimulater, CppBehaviour);
                public:
                	class Serialize : public Super::Serialize
                	{
                	public:
                		float speed = 0.0f;
                		float damage = 0;
                		float lifetime = 6.0f;
                
                	public:
                		void DeSerialize(CppBehaviourSerializeData & data)
                		{
                			TryParseObjectMember(data, speed, "speed");
                			TryParseObjectMember(data, damage, "damage");
                			TryParseObjectMember(data, lifetime, "lifetime");
                		}
                	};
                	Serialize serialize;
                	void* GetSerializeField()override { return &serialize; }
                	//----------------------------end of 协议部分
                	virtual int GetEventCallbackMask()override { return BehaviourEventCallbackMaskUpdate; }
                };

这里有几个与 Unity 实现不同的地方:

  1. 服务器内存充裕,可以通过内存换时间,因此目前在启动时会把所有 Prefab 全部加载进来。
  2. 构造 GameObject 时,直接使用 memcpy 而非逐个反序列化,以达到最高速度,示例如下:
		int size = this->cppscripts.size();
                		for (int i = 0; i < size; i++)
                		{
                			auto &buffer = cppscripts[i];
                			if (buffer.classid > 0 && buffer.data && buffer.size > 0)
                			{
                				CppBehaviour::Ptr  cls = CreateInternalCppBehiviourClassObject(buffer.classid);
                				if (cls)
                				{
                					//class which is build-in
                				}
                				else
                				{
                					if (Prefabs::CREATE_CPP_CLASS  && Prefabs::SERIALIZE_CPPBEHAVIOUR)
                					{
                						//调用自定义初始化数据
                						cls = Prefabs::CREATE_CPP_CLASS(buffer.classid);
                						assert(cls);
                						if (!cls)
                						{
                							//未定义 的class 在序列文件中是不允许的
                							assert(false);
                							continue;
                						}
                					}
                					else
                					{
                						//invalid hook
                						assert(false);
                						continue;
                					}
                				}
                				void *target = cls->GetSerializeField();
                				if (target)
                				{
                					::memcpy(target, buffer.data, buffer.size);
                					ret->AddComponentCppBehaviourInternal(cls);
                				}
                				else
                				{
                					//there has not any data will be serialized
                				}
                			}
                			else
                			{
                				LOG_DEBUG("invalid cpp serialize data");
                				assert(false);
                			}
                		}

至此完成对象生成。配套还需要编写一系列工具,用于生成这些序列化文件。