提交新概念 Tile从服务器

This commit is contained in:
PC-20230316NUNE\Administrator
2024-08-31 15:35:12 +08:00
parent 77db4d7d71
commit d67032e1de
1039 changed files with 57738 additions and 412 deletions

View File

@@ -48,6 +48,14 @@ namespace Plugins.JNGame.Network
}
public override void OnClose()
{
client.Close();
client.Dispose();
Debug.Log($"[JNTCPClient] 关闭对象");
base.OnClose();
}
private Task OnReceived(WebSocketClient webSocketClient, WSDataFrameEventArgs e)
{
if (e.DataFrame.Opcode == WSDataType.Binary && e.DataFrame.FIN)

View File

@@ -46,10 +46,9 @@ namespace JNGame.Network
/// <param name="e"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
private Task OnConnecting(ITcpClient client, ConnectingEventArgs e)
private async Task OnConnecting(ITcpClient client, ConnectingEventArgs e)
{
Debug.Log($"[JNTCPClient] 开始连接服务器");
return Task.CompletedTask;
Debug.Log($"[JNTCPClient] 开始连接服务器 {await GetEndPoint()}");
}

View File

@@ -36,7 +36,10 @@ namespace JNGame.Network
service.Connected = OnConnected;//有客户端连接
service.Disconnected = OnDisconnected;//有客户端断开连接
service.Received = OnReceived;//客户端接收到消息
Debug.Log($"[JNTCPServer] 启动服务端中");
await service.StartAsync(_port = await GetPort());//启动
Debug.Log($"[JNTCPServer] 启动服务端成功");
}
@@ -139,11 +142,15 @@ namespace JNGame.Network
service.SendAsync(client, bytes);
}
public void AllSend(int hId,IMessage data = null)
public void AllSend(int hId,IMessage data = null,Func<SocketClient,bool> filter = null)
{
filter ??= (SocketClient client) => true;
service.GetClients().ForEach(client =>
{
Send(client,hId,data);
if (filter(client))
{
Send(client, hId, data);
}
});
}

View File

@@ -39,9 +39,10 @@ public static partial class JNSyncMessageReflection {
"aWxlSW5wdXRzEgsKA3RJZBgBIAEoBRIfCgdtZXNzYWdlGAIgASgLMg4uSk5G",
"cmFtZUlucHV0cyJAChJKTlN0YXRlVGlsZUFsbERhdGESCwoDdElkGAEgASgF",
"Eh0KBGRhdGEYAiABKAsyDy5KTlN0YXRlQWxsRGF0YSIqChtOU3luY1RpbGVH",
"ZXRUaWxlSW5mb1JlcXVlc3QSCwoDdElkGAEgASgFIjkKD0pOQWRkVGlsZVNl",
"cnZlchIMCgR0aWxlGAEgASgFEgoKAmlwGAIgASgJEgwKBHBvcnQYAyABKAVC",
"FgoUY24uamlzb2wubmdhbWUucHJvdG9iBnByb3RvMw=="));
"ZXRUaWxlSW5mb1JlcXVlc3QSCwoDdElkGAEgASgFIkkKD0pOQWRkVGlsZVNl",
"cnZlchIMCgR0aWxlGAEgASgFEgoKAmlwGAIgASgJEgwKBHBvcnQYAyABKAUS",
"DgoGbWFzdGVyGAQgASgIQhYKFGNuLmppc29sLm5nYW1lLnByb3RvYgZwcm90",
"bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
@@ -58,7 +59,7 @@ public static partial class JNSyncMessageReflection {
new pbr::GeneratedClrTypeInfo(typeof(global::JNStateTileInputs), global::JNStateTileInputs.Parser, new[]{ "TId", "Message" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::JNStateTileAllData), global::JNStateTileAllData.Parser, new[]{ "TId", "Data" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::NSyncTileGetTileInfoRequest), global::NSyncTileGetTileInfoRequest.Parser, new[]{ "TId" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::JNAddTileServer), global::JNAddTileServer.Parser, new[]{ "Tile", "Ip", "Port" }, null, null, null, null)
new pbr::GeneratedClrTypeInfo(typeof(global::JNAddTileServer), global::JNAddTileServer.Parser, new[]{ "Tile", "Ip", "Port", "Master" }, null, null, null, null)
}));
}
#endregion
@@ -2877,6 +2878,7 @@ public sealed partial class JNAddTileServer : pb::IMessage<JNAddTileServer>
tile_ = other.tile_;
ip_ = other.ip_;
port_ = other.port_;
master_ = other.master_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
@@ -2931,6 +2933,21 @@ public sealed partial class JNAddTileServer : pb::IMessage<JNAddTileServer>
}
}
/// <summary>Field number for the "master" field.</summary>
public const int MasterFieldNumber = 4;
private bool master_;
/// <summary>
///是否是主服务器
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool Master {
get { return master_; }
set {
master_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
@@ -2949,6 +2966,7 @@ public sealed partial class JNAddTileServer : pb::IMessage<JNAddTileServer>
if (Tile != other.Tile) return false;
if (Ip != other.Ip) return false;
if (Port != other.Port) return false;
if (Master != other.Master) return false;
return Equals(_unknownFields, other._unknownFields);
}
@@ -2959,6 +2977,7 @@ public sealed partial class JNAddTileServer : pb::IMessage<JNAddTileServer>
if (Tile != 0) hash ^= Tile.GetHashCode();
if (Ip.Length != 0) hash ^= Ip.GetHashCode();
if (Port != 0) hash ^= Port.GetHashCode();
if (Master != false) hash ^= Master.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
@@ -2989,6 +3008,10 @@ public sealed partial class JNAddTileServer : pb::IMessage<JNAddTileServer>
output.WriteRawTag(24);
output.WriteInt32(Port);
}
if (Master != false) {
output.WriteRawTag(32);
output.WriteBool(Master);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
@@ -3011,6 +3034,10 @@ public sealed partial class JNAddTileServer : pb::IMessage<JNAddTileServer>
output.WriteRawTag(24);
output.WriteInt32(Port);
}
if (Master != false) {
output.WriteRawTag(32);
output.WriteBool(Master);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
@@ -3030,6 +3057,9 @@ public sealed partial class JNAddTileServer : pb::IMessage<JNAddTileServer>
if (Port != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Port);
}
if (Master != false) {
size += 1 + 1;
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
@@ -3051,6 +3081,9 @@ public sealed partial class JNAddTileServer : pb::IMessage<JNAddTileServer>
if (other.Port != 0) {
Port = other.Port;
}
if (other.Master != false) {
Master = other.Master;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -3078,6 +3111,10 @@ public sealed partial class JNAddTileServer : pb::IMessage<JNAddTileServer>
Port = input.ReadInt32();
break;
}
case 32: {
Master = input.ReadBool();
break;
}
}
}
#endif
@@ -3105,6 +3142,10 @@ public sealed partial class JNAddTileServer : pb::IMessage<JNAddTileServer>
Port = input.ReadInt32();
break;
}
case 32: {
Master = input.ReadBool();
break;
}
}
}
}

View File

@@ -80,4 +80,5 @@ message JNAddTileServer{
int32 tile = 1; //TileId
string ip = 2; //IP
int32 port = 3; //端口
bool master = 4; //是否是主服务器
}

View File

@@ -20,6 +20,8 @@ namespace JNGame.Sync.State.Tile.Entity.Component
return false;
}
}
public IJNTileEntity TileEntity => Entity as IJNTileEntity;
public virtual void OnTileEnter(){}

View File

@@ -70,9 +70,8 @@ namespace JNGame.Sync.State.Tile.Entity
/// <returns></returns>
public T[] GetHostEntities()
{
if (_entitiesCache is null) return Array.Empty<T>();
var items = new List<T>();
foreach (var item in _entitiesCache)
foreach (var item in GetEntities())
{
if (item.IsHost)
{

View File

@@ -11,9 +11,19 @@ namespace JNGame.Sync.State.Tile.Entity
{
/// <summary>
/// 是否所属当前区块
/// 是否有权限
/// </summary>
public bool IsHost { get; set; }
/// <summary>
/// 是否将数据同步到从服务器
/// </summary>
public bool IsSyncSlave { get; set; }
/// <summary>
/// 是否将数据同步到主服务器
/// </summary>
public bool IsSyncMaster { get; set; }
/// <summary>
/// 区块同步属性(通过网络同步过来的实体数据)
@@ -28,8 +38,21 @@ namespace JNGame.Sync.State.Tile.Entity
public abstract class JNTileEntity : JNEntity,IJNTileCycle,IJNTileEntity
{
/// <summary>
/// 是否有权限
/// </summary>
public bool IsHost { get; set; } = false;
/// <summary>
/// 是否将数据同步到从服务器
/// </summary>
public bool IsSyncSlave { get; set; } = false;
/// <summary>
/// 是否将数据同步到主服务器
/// </summary>
public bool IsSyncMaster { get; set; } = false;
public abstract void TileSyncData(ISTileData data);
//区块生命周期

View File

@@ -0,0 +1,20 @@
namespace JNGame.Sync.State.Tile
{
public enum TileMasterSlaveEnum
{
Master,
Slave,
}
/// <summary>
/// 瓦片状态同步 : 主从服务器代码
/// </summary>
public abstract partial class JNSSTileServerService : JNSStateServerService
{
public abstract TileMasterSlaveEnum MSRole { get; }
public bool IsMaster => MSRole == TileMasterSlaveEnum.Master;
public bool IsSlave => MSRole == TileMasterSlaveEnum.Slave;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b9fc15e9ea9f4f46b05ef0f56aa0423f
timeCreated: 1724726167

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Entitas;
using JNGame.Sync.Entity;
using JNGame.Sync.Frame.Entity.Component.Components;
@@ -13,6 +14,9 @@ namespace JNGame.Sync.Frame.Entity
public JNSyncService Sync { get; private set; }
public JNEntityLookup CLookup;
//方便查抄的实体Map
public Dictionary<ulong, T> Entities = new ();
public JNContext(): base((new T()).NewCLookup().Count, () => new T())
{
@@ -36,7 +40,23 @@ namespace JNGame.Sync.Frame.Entity
{
Sync = data;
}
public T Query(ulong id)
{
Entities.TryGetValue(id, out var entity);
return entity;
}
public void AddEntity(ulong id, JNEntity entity)
{
Entities.Add(id,entity as T);
}
public void RemoveEntity(ulong id)
{
Entities.Remove(id);
}
public T GetService<T>() where T : SLogicSystem
{
return Sync.GetSystem<T>();
@@ -100,7 +120,9 @@ namespace JNGame.Sync.Frame.Entity
{
public abstract JNSyncService GetSync();
public abstract void InitReference(JNSyncService data);
public void AddEntity(ulong id,JNEntity entity);
public void RemoveEntity(ulong id);
}
}

View File

@@ -58,6 +58,7 @@ namespace JNGame.Sync.Entity
{
_id = GetSystem<JNRandomSystem>().NextId();
}
Context.AddEntity(Id,this);
}
public abstract JNEntityLookup NewCLookup();
@@ -126,6 +127,7 @@ namespace JNGame.Sync.Entity
public override void Destroy()
{
Context.RemoveEntity(Id);
OnSyncDestroy();
RemoveAllComponents();
base.Destroy();

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using AppGame.Sync;
using DotRecast.Core.Collections;
using JNGame.Math;
using JNGame.Sync.Entity;
@@ -21,13 +23,17 @@ namespace JNGame.Sync.System.Data
/// <summary>
/// 获取有权限的全部字节
/// </summary>
public Dictionary<ulong, byte[]> GetHostDataBytes();
public Dictionary<ulong, byte[]> GetHostDataBytes(Func<JNTileEntity,bool> filter = null);
/// <summary>
/// 获取有权限的全部字节 (过滤条件 : 需同步从服务器)
/// </summary>
public Dictionary<ulong, byte[]> GetHostDataBytesFilterSlave(Func<JNTileEntity,bool> filter = null);
/// <summary>
/// 获取指定区块的全部字节
/// </summary>
public Dictionary<ulong, byte[]> GetTileDataBytes(int index);
public Dictionary<ulong, byte[]> GetTileDataBytes(int index,Func<JNTileEntity,bool> filter = null);
@@ -35,16 +41,17 @@ namespace JNGame.Sync.System.Data
public abstract class ISTileData : ISStateData
{
public abstract bool IsHost { get; }
public JNTileEntity Entity;
/// <summary>
/// 绑定实体到数据 (销毁数据时顺带销毁实体)
/// 绑定实体到数据
/// </summary>
/// <param name="entity"></param>
public void BindEntity(JNTileEntity entity)
public virtual void BindEntity(JNTileEntity entity)
{
Entity = entity;
Id = entity.Id;
}
/// <summary>
@@ -61,7 +68,10 @@ namespace JNGame.Sync.System.Data
{
public abstract JNTileContext<E> NodeContext { get; }
public JNSSTileServerService TileSync => Sync as JNSSTileServerService;
public bool IsMaster => TileSync is not null && TileSync.IsMaster;
public bool IsSlave => TileSync is not null && TileSync.IsSlave;
protected STileDataSystem(SStateDataEnum type) : base(type)
@@ -76,7 +86,42 @@ namespace JNGame.Sync.System.Data
OnDataSyncContext();
}
}
public override void OnSendUBytes(Dictionary<ulong, byte[]> bytes)
{
Dictionary<ulong, byte[]> all = bytes;
Dictionary<ulong, byte[]> master = new Dictionary<ulong, byte[]>();
Dictionary<ulong, byte[]> slave = new Dictionary<ulong, byte[]>();
all.ForEach(keyValue =>
{
var entity = NodeContext.Query(keyValue.Key);
//给从服务器发送数据
if (IsMaster && entity is not null && entity.IsSyncSlave)
{
slave[keyValue.Key] = keyValue.Value;
}
});
OnSendAllData(all);
OnSendMasterData(master);
OnSendSlaveData(slave);
}
/// <summary>
/// 发送玩家数据
/// </summary>
public abstract void OnSendAllData(Dictionary<ulong, byte[]> bytes);
/// <summary>
/// 发送主服务器数据
/// </summary>
public virtual void OnSendMasterData(Dictionary<ulong, byte[]> bytes){}
/// <summary>
/// 发送从服务器数据
/// </summary>
public virtual void OnSendSlaveData(Dictionary<ulong, byte[]> bytes){}
/// <summary>
/// 将数据Data同步到Context
/// </summary>
@@ -118,12 +163,14 @@ namespace JNGame.Sync.System.Data
//只更新有权限的实体
public override void Update(T data)
{
if (!data.IsHost) return;
var entity = NodeContext.Query(data.Id);
if (entity is null || !entity.IsHost) return;
base.Update(data);
}
public override void Add(T data)
{
if (!data.IsHost) return;
var entity = NodeContext.Query(data.Id);
if (entity is null || !entity.IsHost) return;
base.Add(data);
}
@@ -175,16 +222,27 @@ namespace JNGame.Sync.System.Data
}
public Dictionary<ulong, byte[]> GetHostDataBytes()
public Dictionary<ulong, byte[]> GetHostDataBytesFilterSlave(Func<JNTileEntity,bool> filter = null)
{
if (filter is null) filter = entity => true;
return GetHostDataBytes(entity => entity.IsSyncSlave && filter(entity) );
}
public Dictionary<ulong, byte[]> GetHostDataBytes(Func<JNTileEntity,bool> filter = null)
{
if (filter is null) filter = entity => true;
var data = new Dictionary<ulong, byte[]>();
lock (Data)
{
Data.ForEach(child =>
{
if (child.Value.IsHost)
var entity = NodeContext.Query(child.Key);
if (entity is not null && entity.IsHost && filter(entity))
{
data[child.Key] = child.Value.GetByte();
}
@@ -195,16 +253,19 @@ namespace JNGame.Sync.System.Data
}
public Dictionary<ulong, byte[]> GetTileDataBytes(int index)
public Dictionary<ulong, byte[]> GetTileDataBytes(int index,Func<JNTileEntity,bool> filter = null)
{
if (filter is null) filter = entity => true;
var data = new Dictionary<ulong, byte[]>();
lock (Data)
{
Data.ForEach(child =>
{
if (IsTileInside(index,child.Value))
var entity = NodeContext.Query(child.Key);
if (IsTileInside(index,child.Value) && filter(entity))
{
data[child.Key] = child.Value.GetByte();
}

View File

@@ -53,6 +53,15 @@ namespace Plugins.JNGame.Util
/// <typeparam name="T">事件参数类型</typeparam>
/// <param name="eventId">事件标识符</param>
/// <param name="listener">事件监听器</param>
public void RemoveListener(string eventId, Action listener)
{
if (EventHandlers.ContainsKey(eventId))
{
//eventHandlers[eventId] = (Action<T>)eventHandlers[eventId] - listener;
EventHandlers[eventId].Remove(listener);
Debug.Log(eventId + "RemoveListener" + EventHandlers[eventId].Count);
}
}
public void RemoveListener<T>(string eventId, Action<T> listener)
{
if (EventHandlers.ContainsKey(eventId))

View File

@@ -1,4 +1,7 @@
using System;
using System.IO;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
namespace Plugins.JNGame.Util
{
@@ -15,5 +18,25 @@ namespace Plugins.JNGame.Util
BitConverter.GetBytes(value).CopyTo(result, 0);
return result;
}
public static byte[] ObjectToBytes<T>(T data)
{
var formatter = new BinaryFormatter();
using var mStream = new MemoryStream();
formatter.Serialize(mStream, data);
mStream.Flush();
return mStream.GetBuffer();
}
public static T BytesToObject<T>(byte[] data)
{
var formatter = new BinaryFormatter();
using var mStream = new MemoryStream();
mStream.Write(data, 0, data.Length);
mStream.Flush();
mStream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(mStream);
}
}
}

View File

@@ -0,0 +1,78 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace JNGame.Util
{
/// Author: Pim de Witte (pimdewitte.com) and contributors, https://github.com/PimDeWitte/UnityMainThreadDispatcher
/// <summary>
/// A thread-safe class which holds a queue with actions to execute on the next Update() method. It can be used to make calls to the main thread for
/// things such as UI Manipulation in Unity. It was developed for use in combination with the Firebase Unity plugin, which uses separate threads for event handling
/// </summary>
public class UnityMainThreadDispatcher : SingletonScene<UnityMainThreadDispatcher> {
private readonly Queue<Action> _executionQueue = new Queue<Action>();
public void Update() {
lock(_executionQueue) {
while (_executionQueue.Count > 0) {
_executionQueue.Dequeue().Invoke();
}
}
}
/// <summary>
/// Locks the queue and adds the IEnumerator to the queue
/// </summary>
/// <param name="action">IEnumerator function that will be executed from the main thread.</param>
public void Enqueue(IEnumerator action) {
lock (_executionQueue) {
_executionQueue.Enqueue (() => {
StartCoroutine(action);
});
}
}
/// <summary>
/// Locks the queue and adds the Action to the queue
/// </summary>
/// <param name="action">function that will be executed from the main thread.</param>
public void Enqueue(Action action)
{
Enqueue(ActionWrapper(action));
}
/// <summary>
/// Locks the queue and adds the Action to the queue, returning a Task which is completed when the action completes
/// </summary>
/// <param name="action">function that will be executed from the main thread.</param>
/// <returns>A Task that can be awaited until the action completes</returns>
public Task EnqueueAsync(Action action)
{
var tcs = new TaskCompletionSource<bool>();
void WrappedAction() {
try
{
action();
tcs.TrySetResult(true);
} catch (Exception ex)
{
tcs.TrySetException(ex);
}
}
Enqueue(ActionWrapper(WrappedAction));
return tcs.Task;
}
IEnumerator ActionWrapper(Action a)
{
a();
yield return null;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4d1e1ab4d41f4a618dcf3ba40014cf20
timeCreated: 1724926741