mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-11-11 00:36:00 +00:00
提交新概念 Tile从服务器
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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()}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,4 +80,5 @@ message JNAddTileServer{
|
||||
int32 tile = 1; //TileId
|
||||
string ip = 2; //IP
|
||||
int32 port = 3; //端口
|
||||
bool master = 4; //是否是主服务器
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace JNGame.Sync.State.Tile.Entity.Component
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public IJNTileEntity TileEntity => Entity as IJNTileEntity;
|
||||
|
||||
public virtual void OnTileEnter(){}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
//区块生命周期
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9fc15e9ea9f4f46b05ef0f56aa0423f
|
||||
timeCreated: 1724726167
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
78
JNFrame2/Assets/JNGame/Util/UnityMainThreadDispatcher.cs
Normal file
78
JNFrame2/Assets/JNGame/Util/UnityMainThreadDispatcher.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d1e1ab4d41f4a618dcf3ba40014cf20
|
||||
timeCreated: 1724926741
|
||||
Reference in New Issue
Block a user