DMM新网络框架开发适配
目前新网络框架(DmmNetwork)第一阶段已经合入主干开发分支。为了确保单局战斗逻辑能在Photon和DmmNetwork的网络框架下都正常运行,需遵照以下流程进行开发。
由于目前项目中同时存在两种网络框架,即Photon和DmmNet,所以需要一个中间层在业务层进行网络接口的封装隔离,以便能通过开关切换单局网络类型。
适配方式:在公共业务层统一使用GameNetwork,不要直接调用PhotonNetwork。
inRoom
//Before
if(PhotonNetwork.inRoom)
//After
if(GameNetwork.inRoom)
isMasterClient
//Before
if(PhotonNetwork.isMasterClient)
//After
if(GameNetwork.isMasterClient)
offlineMode
//Before
if(PhotonNetwork.offlineMode)
//After
if(GameNetwork.offlineMode)
player
//Before
msg.Add("sender", PhotonNetwork.player.UserId);
//After
msg.Add("sender", GameNetwork.player.UserId);
playerList
//Before
foreach (var player in PhotonNetwork.playerList)
{
if (player.UserId == playerName)
{
return true;
}
}
//After
foreach (var player in GameNetwork.playerList)
{
if (player.UserId == playerName)
{
return true;
}
}
InstantiateSceneObject
//Before
GameObject inst = PhotonNetwork.InstantiateSceneObject(prefabName, pos, Quaternion.LookRotation(dir), 0, data);
//After
GameObject inst = GameNetwork.InstantiateSceneObject(prefabName, pos, Quaternion.LookRotation(dir), 0, data);
RaiseEvent
//Before
PhotonNetwork.RaiseEvent(GamePhotonEvents.SynMaster, null, true, new RaiseEventOptions() {Receivers = ReceiverGroup.MasterClient});
//After
GameNetwork.RaiseEvent(GamePhotonEvents.SynMaster, null, true, new RaiseEventOptions() {Receivers = ReceiverGroup.MasterClient});
RPC
//Before
PhotonNetwork.RPC(this, methodName, targetPlayer, false, parameters);
//After
GameNetwork.RPC(this, methodName, targetPlayer, false, parameters);
其他属性和方法替换方式以此类推。
为了避免改动过多的预设,PhotonView脚本保留。在其类内的方法做了区分。
调用方式与原来Photon基本一致,仅在使用规则上有以下区别
1.手动注册rpc回调,减少发射带来的GC。
//该RPC协议号为1
[PunRPC(1)]
void AddPropProxy(int propID)
{
AntiCheatingSystem.BehaviourCheck(RpcBehaviourType.AddProp, m_PlayerController, propID);
m_PlayerController.LocalAddProp(propID);
}
制定RPC的协议号可以使用RPC协议号编号辅助工具:Toos/DmmLightNet/检查全部PunRPC的ID
RPC协议号定义类:RPCID
//RPC调用
public void RpcAddProp(int propID)
{
m_IsDevouring = true;
//需要手动填入要广播的RPC协议号,这里rpcId填1
//如果不传rpcId,则RPC方法走反射通知的方式,和Photon一致。
m_PhotonView.RPC("AddPropProxy", 1, PhotonTargets.AllViaServer, propID);
}
//手动注册
void Awake()
{
if (NetworkType.UseDmmLightNet2)
{
int viewId = m_PlayerController.m_PhotonView.viewID;
//注册
DmmRpcRegister.RegisterCallback(viewId, 1, args => AddPropProxy((int) args[0]));
....
}
}
//不带PhotonView组件的对象需手动注销rpc回调
protected override void OnDestroy()
{
if (NetworkType.UseDmmLightNet2 && m_UsableId > 0)
{
DmmRpcRegister.UnregisterCallback(m_UsableId, 109);
}
}
//带PhotonView的会自动统一注销,不需要手动单独注销
public void RemoveDmmRpc()
{
var player = GetComponent<PlayerController>();
if (player != null && player.IsRealPlayer)
{
//由于玩家对象断线重连时不销毁,所以不注销,统一在退出单局时的Reset中处理
return;
}
DmmRpcRegister.RemoveView(viewID);
}
//为了兼容Photon方式,保留rpc方法名传参,只有当rpcid==0时有效。
public void RPC(string methodName, int rpcId, PhotonTargets target, params object[] parameters)
{
GameNetwork.RPC(this, methodName, rpcId, target, false, parameters);
}
public void RPC(string methodName, PhotonTargets target, params object[] parameters)
{
GameNetwork.RPC(this, methodName, 0, target, false, parameters);
}
2.RPC传参默认不支持新增的自定义枚举类型,统一转换成基础数据类型进行传递。
//Before
//不要直接传自定义的枚举
m_PlayerController.SkillManager.RPCSkillProxy(GameConstants.ID_SKILL_900, Connect.ProxyEnum.TailCooldown);
//After
//把自定义枚举转成整型传递
m_PlayerController.SkillManager.RPCSkillProxy(GameConstants.ID_SKILL_900, (int)Connect.ProxyEnum.TailCooldown);
如果需要传自定义的结构体,去DmmLightNet2CustomTypes.cs下实现序列化/反序列化方法:
public struct UseExtraInfo : ICustomSerializer
{
public int userType; //0:角色 1:木偶 2:分身
public void Serialize(FastBinaryWriter write)
{
write.Write(userType);
}
public void Deserialize(byte[] data, ref int offset)
{
userType = FastBinaryReader.ReadInt32(data, ref offset);
}
}
需要验证开发的战斗逻辑在DmmNet下能正常运行。
1.打开GM工具,设置网络类型为DmmNet,填写本机战斗服务器地址:127.0.0.1:45002
2.服务器工程地址在项目目录下的LightNetServer文件夹内,使用VS打开解决方案,运行即可。
3.单局内可查看单局网络类型
D代表Dmmnet
P代表Photon