mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-26 18:26:23 +00:00
修复主从交互bug
This commit is contained in:
@@ -8,8 +8,8 @@
|
||||
|
||||
LocalClientConnect = 11, //客户端连接 (用于客户端通知)
|
||||
LocalClientDisconnect = 12, //客户端断开 (用于客户端通知)
|
||||
ServerClientConnect = 13, //服务器客户端连接 (用于服务端通知)
|
||||
ServerClientDisconnect = 14, //服务器客户端断开 (用于服务端通知)
|
||||
ServerClientConnect = 13, //服务器客户端连接 (用于业务服务端通知)
|
||||
ServerClientDisconnect = 14, //服务器客户端断开 (用于业务服务端通知)
|
||||
|
||||
NSyncFrameStart = 100, //帧同步开始
|
||||
NSyncFrameEnd = 101, //帧同步结束
|
||||
|
@@ -26,6 +26,6 @@ namespace JNGame.Sync.State.Tile.Entity.Component
|
||||
public virtual void OnTileEnter(){}
|
||||
|
||||
public virtual void OnTileExit(){}
|
||||
|
||||
public void OnTileSlaveExit(){}
|
||||
}
|
||||
}
|
@@ -125,6 +125,7 @@ namespace JNGame.Sync.State.Tile.Entity
|
||||
if (isHost && !isContains)
|
||||
{
|
||||
OnTileExit();
|
||||
if (SyncTile.IsSlave) OnTileSlaveExit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,5 +148,13 @@ namespace JNGame.Sync.State.Tile.Entity
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnTileSlaveExit()
|
||||
{
|
||||
//给组件生命周期
|
||||
foreach (var component in GetComponents())
|
||||
{
|
||||
(component as JNTileComponent)?.OnTileSlaveExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -13,5 +13,10 @@
|
||||
/// </summary>
|
||||
public void OnTileExit();
|
||||
|
||||
/// <summary>
|
||||
/// 从服务器 - 退出当前区块
|
||||
/// </summary>
|
||||
public void OnTileSlaveExit();
|
||||
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core.Collections;
|
||||
using Entitas;
|
||||
using JNGame.Sync.Entity;
|
||||
using JNGame.Sync.Frame.Entity.Component.Components;
|
||||
@@ -17,18 +18,20 @@ namespace JNGame.Sync.Frame.Entity
|
||||
|
||||
//方便查抄的实体Map
|
||||
public Dictionary<ulong, T> Entities = new ();
|
||||
|
||||
public JNContext(): base((new T()).NewCLookup().Count, () => new T())
|
||||
|
||||
public JNContext()
|
||||
: this((new T()).NewCLookup().Count, () => new T())
|
||||
{
|
||||
CLookup = (new T()).NewCLookup();
|
||||
}
|
||||
|
||||
public JNContext(int totalComponents, Func<T> entityFactory) : base(totalComponents, entityFactory)
|
||||
public JNContext(int totalComponents, Func<T> entityFactory) : this(totalComponents, 0, null, null, entityFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public JNContext(int totalComponents, int startCreationIndex, ContextInfo contextInfo, Func<IEntity, IAERC> aercFactory, Func<T> entityFactory) : base(totalComponents, startCreationIndex, contextInfo, aercFactory, entityFactory)
|
||||
public JNContext(int totalComponents, int startCreationIndex, ContextInfo contextInfo, Func<IEntity, IAERC> aercFactory, Func<T> entityFactory)
|
||||
: base(totalComponents, startCreationIndex, contextInfo, aercFactory, entityFactory)
|
||||
{
|
||||
CLookup = (new T()).NewCLookup();
|
||||
}
|
||||
|
||||
public JNSyncService GetSync()
|
||||
@@ -96,8 +99,20 @@ namespace JNGame.Sync.Frame.Entity
|
||||
BindLifeCycle(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
//生效延迟销毁
|
||||
public void DelayDestroy()
|
||||
{
|
||||
GetEntities().ForEach(child =>
|
||||
{
|
||||
if (child.IsDelayDestroy)
|
||||
{
|
||||
child.Destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//帧同步 生命周期
|
||||
//生命周期
|
||||
public virtual void OnSyncStart(){}
|
||||
|
||||
public virtual void OnSyncUpdate(int dt)
|
||||
@@ -122,6 +137,7 @@ namespace JNGame.Sync.Frame.Entity
|
||||
public abstract void InitReference(JNSyncService data);
|
||||
public void AddEntity(ulong id,JNEntity entity);
|
||||
public void RemoveEntity(ulong id);
|
||||
public void DelayDestroy();
|
||||
|
||||
}
|
||||
|
||||
|
@@ -19,12 +19,18 @@ namespace JNGame.Sync.Entity
|
||||
}
|
||||
|
||||
//给所有实体推帧
|
||||
public void Simulate()
|
||||
public virtual void Simulate()
|
||||
{
|
||||
for (var i = 0; i < allContexts.Length; i++)
|
||||
{
|
||||
(allContexts[i] as IJNContext)?.OnSyncUpdate(Sync.DeltaTime);
|
||||
}
|
||||
|
||||
//延迟销毁
|
||||
for (var i = 0; i < allContexts.Length; i++)
|
||||
{
|
||||
(allContexts[i] as IJNContext)?.DelayDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
public T GetContext<T>() where T : IContext
|
||||
|
@@ -50,6 +50,8 @@ namespace JNGame.Sync.Entity
|
||||
/// </summary>
|
||||
public LVector3 Position => Transform.Position;
|
||||
|
||||
public bool IsDelayDestroy { get; private set; } = false;
|
||||
|
||||
public virtual void OnInit(IJNContext context,ulong id = 0)
|
||||
{
|
||||
Context = context;
|
||||
@@ -127,12 +129,18 @@ namespace JNGame.Sync.Entity
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
//清理缓存
|
||||
Context.RemoveEntity(Id);
|
||||
OnSyncDestroy();
|
||||
RemoveAllComponents();
|
||||
base.Destroy();
|
||||
}
|
||||
|
||||
public void DelayDestroy()
|
||||
{
|
||||
IsDelayDestroy = true;
|
||||
}
|
||||
|
||||
//生命周期
|
||||
public virtual void OnSyncStart(){}
|
||||
|
||||
@@ -146,7 +154,11 @@ namespace JNGame.Sync.Entity
|
||||
}
|
||||
|
||||
public virtual void OnSyncDestroy()
|
||||
{}
|
||||
{
|
||||
_id = 0;
|
||||
IsDelayDestroy = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -148,7 +148,6 @@ namespace JNGame.Sync.System.Data
|
||||
if (NodeContext.Query(child.Key) is null)
|
||||
{
|
||||
Delete(child.Key);
|
||||
return;
|
||||
}
|
||||
|
||||
//主动更新
|
||||
@@ -179,7 +178,7 @@ namespace JNGame.Sync.System.Data
|
||||
{
|
||||
var entity = NodeContext.Query(keyValue.Key);
|
||||
//给从服务器发送数据
|
||||
if (IsMaster && entity is not null && entity.IsSyncSlave)
|
||||
if (IsMaster && ((entity is not null && entity.IsSyncSlave) || keyValue.Value == SDByteOperate.Delete))
|
||||
{
|
||||
slave[keyValue.Key] = keyValue.Value;
|
||||
}
|
||||
|
@@ -35,7 +35,6 @@ namespace AppGame
|
||||
public static readonly JNGClientGroup Client = new JNGClientGroup();
|
||||
public static readonly JNGResService Resource = new JNGResService();
|
||||
public static readonly JNGGame Game = new JNGGame();
|
||||
public static readonly JNGSocket Socket = new JNGSocket();
|
||||
public static readonly JAPI API = new(new JAPIConfig(){BaseURL = "http://127.0.0.1:8080"});
|
||||
public static readonly GAPI GAPI = new GAPI();
|
||||
public static readonly EventDispatcher Event = new();
|
||||
@@ -50,7 +49,6 @@ namespace AppGame
|
||||
Client,
|
||||
Resource,
|
||||
Game,
|
||||
// Socket,
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -89,7 +89,7 @@ namespace AppGame.Sync
|
||||
protected override void OnSendInput(JNFrameInputs inputs)
|
||||
{
|
||||
//发送帧数据给服务端
|
||||
App.Socket.Send((int)NActionEnum.NSyncFrameInput,inputs);
|
||||
App.Business.Send((int)NActionEnum.NSyncFrameInput,inputs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -89,7 +89,7 @@ namespace AppGame.Sync
|
||||
if (inputs.Inputs.Count > 0)
|
||||
{
|
||||
//发送帧数据给服务端
|
||||
App.Socket.Send((int)NActionEnum.NSyncFrameInput,inputs);
|
||||
App.Business.Send((int)NActionEnum.NSyncFrameInput,inputs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -74,7 +74,7 @@ namespace AppGame.Systems
|
||||
private void OnNSyncStateDataUpdate(byte[] data)
|
||||
{
|
||||
var info = JNStateItemData.Parser.ParseFrom(data);
|
||||
App.Game.AddState(info);
|
||||
App.Game.SyncState(info,true,false);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace AppGame.Systems
|
||||
//生效全局回调
|
||||
allData.Data.Data.ForEach(child =>
|
||||
{
|
||||
App.Game.AddState(child);
|
||||
App.Game.SyncState(child,true,false);
|
||||
});
|
||||
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
||||
using AppGame.Sync;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using DotRecast.Core.Collections;
|
||||
using Game.Logic.System;
|
||||
using Google.Protobuf;
|
||||
using JNGame.Network;
|
||||
using JNGame.Sync.State.Tile;
|
||||
@@ -31,6 +32,7 @@ namespace AppGame.Systems.CServer
|
||||
AddListener((int)NActionEnum.NSyncTileInput,OnNSyncTileInput);
|
||||
AddListener((int)NActionEnum.NSyncTileAllUpdate,OnNSyncTileAllUpdate);
|
||||
AddListener((int)NActionEnum.NSyncTileGetTileInfo,OnNSyncTileGetTileInfo);
|
||||
AddListener((int)NActionEnum.LocalClientDisconnect,OnLocalClientDisconnect);
|
||||
|
||||
OnInit_Game();
|
||||
|
||||
@@ -38,6 +40,7 @@ namespace AppGame.Systems.CServer
|
||||
await base.OnInit();
|
||||
}
|
||||
|
||||
|
||||
public override void OnClose()
|
||||
{
|
||||
isInit = false;
|
||||
@@ -165,5 +168,23 @@ namespace AppGame.Systems.CServer
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 有客户端断开连接
|
||||
/// </summary>
|
||||
private void OnLocalClientDisconnect(JNServerParam args)
|
||||
{
|
||||
|
||||
if (App.Game.Server is null) return;
|
||||
//只有绑定过ID 的客户端才可以执行操作
|
||||
if (!ids.ContainsKey(args.Client)) return;
|
||||
App.Game.Server.GetSystems<DGBasisSystem>().ForEach(child =>
|
||||
{
|
||||
child.OnPlayerExitServer(ids[args.Client]);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -74,7 +74,7 @@ namespace AppGame.Systems
|
||||
private void OnNSyncStateDataUpdate(byte[] data)
|
||||
{
|
||||
var info = JNStateItemData.Parser.ParseFrom(data);
|
||||
App.Game.AddState(info);
|
||||
App.Game.SyncState(info,false,true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -91,7 +91,7 @@ namespace AppGame.Systems
|
||||
//生效全局状态
|
||||
allData.Data.Data.ForEach(child =>
|
||||
{
|
||||
App.Game.AddState(child);
|
||||
App.Game.SyncState(child,false,true);
|
||||
});
|
||||
|
||||
}
|
||||
|
@@ -112,24 +112,30 @@ namespace AppGame.Systems
|
||||
/// <summary>
|
||||
/// 接收状态数据
|
||||
/// </summary>
|
||||
public void AddState(JNStateItemData frame)
|
||||
public void SyncState(JNStateItemData frame,bool isSyncClient,bool isSyncServer)
|
||||
{
|
||||
var message = new Dictionary<ulong, byte[]>();
|
||||
foreach (var data in frame.Messages)
|
||||
{
|
||||
message.Add(data.Key,data.Value.Data.ToByteArray());
|
||||
}
|
||||
|
||||
client?.GetSystems<ISStateDataSystem>().ForEach(child =>
|
||||
|
||||
if (isSyncClient)
|
||||
{
|
||||
if (child.NetID != frame.NetID) return;
|
||||
child.OnInsertUBytes(message);
|
||||
});
|
||||
server?.GetSystems<ISStateDataSystem>().ForEach(child =>
|
||||
client?.GetSystems<ISStateDataSystem>().ForEach(child =>
|
||||
{
|
||||
if (child.NetID != frame.NetID) return;
|
||||
child.OnInsertUBytes(message);
|
||||
});
|
||||
}
|
||||
if (isSyncServer)
|
||||
{
|
||||
if (child.NetID != frame.NetID) return;
|
||||
child.OnInsertUBytes(message);
|
||||
});
|
||||
server?.GetSystems<ISStateDataSystem>().ForEach(child =>
|
||||
{
|
||||
if (child.NetID != frame.NetID) return;
|
||||
child.OnInsertUBytes(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -8,6 +8,8 @@ namespace Game.JNGFrame.Logic.Entity
|
||||
{
|
||||
|
||||
public override IContext[] allContexts { get; } = { new EDNodeContext(),new EDPlayerContext(),new EDBossContext(), };
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -2,6 +2,8 @@
|
||||
using JNGame.Sync.Frame.Service;
|
||||
using JNGame.Sync.State.Tile;
|
||||
using JNGame.Sync.State.Tile.Entity;
|
||||
using JNGame.Sync.System.Data;
|
||||
using NotImplementedException = System.NotImplementedException;
|
||||
|
||||
namespace Game.Logic.Entity
|
||||
{
|
||||
@@ -24,7 +26,17 @@ namespace Game.Logic.Entity
|
||||
}
|
||||
return LVector3.Down;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override void TileSyncData(ISTileData data)
|
||||
{
|
||||
Transform.Position = data.GetDataPosition();
|
||||
}
|
||||
|
||||
public override void OnTileSlaveExit()
|
||||
{
|
||||
base.OnTileSlaveExit();
|
||||
//从服务器 - 实体移出后立即删除
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
}
|
@@ -34,6 +34,10 @@ namespace Game.JNGFrame.Logic.Entity.Controller
|
||||
|
||||
public override void OnSyncStart()
|
||||
{
|
||||
|
||||
//Player 同步到从服务器
|
||||
TileEntity.IsSyncSlave = true;
|
||||
|
||||
base.OnSyncStart();
|
||||
Move.Speed = LFloat.L10;
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Game.JNGFrame.Logic.Entity.Controller;
|
||||
using Entitas;
|
||||
using Game.JNGFrame.Logic.Entity.Controller;
|
||||
using Game.Logic.Entity.Nodes;
|
||||
using Game.Logic.Entity.Nodes.Component.Components;
|
||||
using JNGame.Sync.State.Tile.Entity;
|
||||
@@ -7,6 +8,7 @@ namespace Game.JNGFrame.Logic.Entity.Contexts
|
||||
{
|
||||
public sealed partial class EDPlayerContext : JNTileContext<EDPlayer>
|
||||
{
|
||||
|
||||
protected override EDPlayer BindComponent(EDPlayer entity)
|
||||
{
|
||||
base.BindComponent(entity);
|
||||
@@ -14,5 +16,6 @@ namespace Game.JNGFrame.Logic.Entity.Contexts
|
||||
entity.AddComponent<EDPlayerController>();
|
||||
return entity;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -13,12 +13,6 @@ namespace Game.Logic.Entity.Nodes
|
||||
public EDMoveComponent Move => CLookup.Query<EDMoveComponent>(this);
|
||||
public EDBossController Controller => CLookup.Query<EDBossController>(this);
|
||||
|
||||
public override void TileSyncData(ISTileData data)
|
||||
{
|
||||
var nodeData = data as EDBossData;
|
||||
Transform.Position = nodeData.Value.Position.ToLVector3();
|
||||
}
|
||||
|
||||
public override JNEntityLookup NewCLookup()
|
||||
{
|
||||
return new EDBoosLookup();
|
||||
|
@@ -12,13 +12,6 @@ namespace Game.Logic.Entity.Nodes
|
||||
|
||||
public EDMoveComponent Move => CLookup.Query<EDMoveComponent>(this);
|
||||
|
||||
|
||||
public override void TileSyncData(ISTileData data)
|
||||
{
|
||||
var nodeData = data as EDNodeData;
|
||||
Transform.Position = nodeData.Value.Position.ToLVector3();
|
||||
}
|
||||
|
||||
public override JNEntityLookup NewCLookup()
|
||||
{
|
||||
return new EDNodeLookup();
|
||||
|
@@ -16,9 +16,9 @@ namespace Game.Logic.Entity.Nodes
|
||||
|
||||
public override void TileSyncData(ISTileData data)
|
||||
{
|
||||
base.TileSyncData(data);
|
||||
var nodeData = data as EDPlayerData;
|
||||
Controller.AuthBind(nodeData.Value.Auth.Value);
|
||||
Transform.Position = nodeData.Value.Position.ToLVector3();
|
||||
}
|
||||
|
||||
public override JNEntityLookup NewCLookup()
|
||||
|
@@ -30,5 +30,11 @@ namespace Game.Logic.System
|
||||
return LVector3.Down;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [状态同步生命周期] 玩家离开服务器 不在游戏线程中执行
|
||||
/// </summary>
|
||||
public virtual void OnPlayerExitServer(int auth){}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
using DotRecast.Core.Collections;
|
||||
using Game.Input;
|
||||
using Game.JNGFrame.Logic.Entity;
|
||||
using Game.JNGFrame.Logic.Entity.Contexts;
|
||||
using Game.Logic.Entity.Nodes;
|
||||
using JNGame.Math;
|
||||
@@ -40,5 +39,20 @@ namespace Game.Logic.System.Logic
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override void OnPlayerExitServer(int auth)
|
||||
{
|
||||
base.OnPlayerExitServer(auth);
|
||||
|
||||
NodeContext.GetHostEntities().ForEach(child =>
|
||||
{
|
||||
if (child.Controller.Auth == auth)
|
||||
{
|
||||
child.DelayDestroy();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@@ -14,6 +14,9 @@ namespace Game.JNGFrame.View.Entity
|
||||
public GameObject VWorld => App.Resource.VWorld;
|
||||
public GameObject Player => App.Resource.Player;
|
||||
public CinemachineFreeLook FreeLook => App.Resource.FreeLook;
|
||||
|
||||
//本地玩家 视图
|
||||
private GameObject LocalView;
|
||||
|
||||
public VDPlayers(SViewSystem root) : base(root)
|
||||
{
|
||||
@@ -67,9 +70,20 @@ namespace Game.JNGFrame.View.Entity
|
||||
|
||||
public override GameObject NewView(EDPlayerData data)
|
||||
{
|
||||
var gameObject = Object.Instantiate(Player, VWorld.transform);
|
||||
gameObject.name = $"Player_{data.Id}";
|
||||
return gameObject;
|
||||
GameObject view;
|
||||
//如果这个角色是自己 则 直接拿自己的 View
|
||||
if (App.IsClient() && data.Value.Auth == App.ClientID)
|
||||
{
|
||||
if (LocalView is null) LocalView = Object.Instantiate(Player, VWorld.transform);
|
||||
view = LocalView;
|
||||
}
|
||||
else
|
||||
{
|
||||
view = Object.Instantiate(Player, VWorld.transform);
|
||||
}
|
||||
|
||||
view.name = $"Player_{data.Id}";
|
||||
return view;
|
||||
}
|
||||
|
||||
public override EDPlayerData[] GetData()
|
||||
@@ -80,7 +94,10 @@ namespace Game.JNGFrame.View.Entity
|
||||
public override void ViewRemove(GameObject view)
|
||||
{
|
||||
view.transform.DOKill();
|
||||
Object.Destroy(view);
|
||||
if (LocalView != view)
|
||||
{
|
||||
Object.Destroy(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user