提交修改
This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
namespace NBC
|
||||
{
|
||||
internal interface ISceneUpdate
|
||||
{
|
||||
void Update();
|
||||
}
|
||||
|
||||
internal sealed class EmptySceneUpdate : ISceneUpdate
|
||||
{
|
||||
public void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 459c867d43e7443cd8e9b181b1f61b8c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,399 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NBC.Scheduler;
|
||||
using NBC.Async;
|
||||
using NBC.Entitas;
|
||||
using NBC.Event;
|
||||
using NBC.IdFactory;
|
||||
using NBC.Network;
|
||||
using NBC.Network.Interface;
|
||||
using NBC.Pool;
|
||||
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
#pragma warning disable CS8601 // Possible null reference assignment.
|
||||
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
namespace NBC
|
||||
{
|
||||
/// <summary>
|
||||
/// 当Scene创建完成后发送的事件参数
|
||||
/// </summary>
|
||||
public struct OnCreateScene
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取与事件关联的场景实体。
|
||||
/// </summary>
|
||||
public readonly Scene Scene;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个新的 OnCreateScene 实例。
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
public OnCreateScene(Scene scene)
|
||||
{
|
||||
Scene = scene;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示一个场景实体,用于创建与管理特定的游戏场景信息。
|
||||
/// </summary>
|
||||
public partial class Scene : Entity
|
||||
{
|
||||
#region Members
|
||||
|
||||
/// <summary>
|
||||
/// Scene的运行类型
|
||||
/// </summary>
|
||||
public SceneRuntimeType SceneRuntimeType { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前Scene的上下文
|
||||
/// </summary>
|
||||
public ThreadSynchronizationContext ThreadSynchronizationContext { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前Scene的下创建的Entity
|
||||
/// </summary>
|
||||
private readonly Dictionary<long, Entity> _entities = new Dictionary<long, Entity>();
|
||||
|
||||
internal readonly Dictionary<Type, Func<IPool>> TypeInstance = new Dictionary<Type, Func<IPool>>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region IdFactory
|
||||
|
||||
/// <summary>
|
||||
/// Entity实体Id的生成器
|
||||
/// </summary>
|
||||
public IEntityIdFactory EntityIdFactory { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity实体RuntimeId的生成器
|
||||
/// </summary>
|
||||
public IRuntimeIdFactory RuntimeIdFactory { get; protected set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Pool
|
||||
|
||||
internal EntityPool EntityPool;
|
||||
internal EntityListPool<Entity> EntityListPool;
|
||||
internal EntitySortedDictionaryPool<long, Entity> EntitySortedDictionaryPool;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Component
|
||||
|
||||
/// <summary>
|
||||
/// Scene下的任务调度器系统组件
|
||||
/// </summary>
|
||||
public TimerComponent TimerComponent { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scene下的事件系统组件
|
||||
/// </summary>
|
||||
public EventComponent EventComponent { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scene下的ESC系统组件
|
||||
/// </summary>
|
||||
public EntityComponent EntityComponent { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scene下的网络消息对象池组件
|
||||
/// </summary>
|
||||
public MessagePoolComponent MessagePoolComponent { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scene下的协程锁组件
|
||||
/// </summary>
|
||||
public CoroutineLockComponent CoroutineLockComponent { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scene下的网络消息派发组件
|
||||
/// </summary>
|
||||
internal MessageDispatcherComponent MessageDispatcherComponent { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initialize
|
||||
|
||||
private async FTask Initialize()
|
||||
{
|
||||
EntityPool = new EntityPool();
|
||||
EntityListPool = new EntityListPool<Entity>();
|
||||
EntitySortedDictionaryPool = new EntitySortedDictionaryPool<long, Entity>();
|
||||
SceneUpdate = EntityComponent = await Create<EntityComponent>(this, false, false).Initialize();
|
||||
MessagePoolComponent = Create<MessagePoolComponent>(this, false, true);
|
||||
EventComponent = await Create<EventComponent>(this, false, true).Initialize();
|
||||
TimerComponent = Create<TimerComponent>(this, false, true).Initialize();
|
||||
CoroutineLockComponent = Create<CoroutineLockComponent>(this, false, true).Initialize();
|
||||
MessageDispatcherComponent = await Create<MessageDispatcherComponent>(this, false, true).Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scene销毁方法,执行了该方法会把当前Scene下的所有实体都销毁掉。
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
base.Dispose();
|
||||
_entities.Remove(RuntimeId);
|
||||
|
||||
switch (SceneRuntimeType)
|
||||
{
|
||||
case SceneRuntimeType.Root:
|
||||
{
|
||||
_entities.Remove(EntityComponent.RuntimeId);
|
||||
|
||||
foreach (var (runtimeId, entity) in _entities.ToList())
|
||||
{
|
||||
if (runtimeId != entity.RuntimeId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
entity.Dispose();
|
||||
}
|
||||
|
||||
_entities.Clear();
|
||||
_unityWorldId--;
|
||||
_unitySceneId--;
|
||||
TypeInstance.Clear();
|
||||
EntityComponent.Dispose();
|
||||
EntityPool.Dispose();
|
||||
EntityListPool.Dispose();
|
||||
EntitySortedDictionaryPool.Dispose();
|
||||
break;
|
||||
}
|
||||
case SceneRuntimeType.SubScene:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Log.Error(
|
||||
$"SceneRuntimeType: {SceneRuntimeType} The unsupported SceneRuntimeType of the Scene executed Dispose.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SceneUpdate = null;
|
||||
EntityIdFactory = null;
|
||||
RuntimeIdFactory = null;
|
||||
|
||||
EntityPool = null;
|
||||
EntityListPool = null;
|
||||
EntitySortedDictionaryPool = null;
|
||||
EntityComponent = null;
|
||||
TimerComponent = null;
|
||||
EventComponent = null;
|
||||
MessagePoolComponent = null;
|
||||
CoroutineLockComponent = null;
|
||||
MessageDispatcherComponent = null;
|
||||
Session = null;
|
||||
UnityNetwork = null;
|
||||
ThreadSynchronizationContext = null;
|
||||
SceneRuntimeType = SceneRuntimeType.None;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal ISceneUpdate SceneUpdate { get; set; }
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
try
|
||||
{
|
||||
SceneUpdate.Update();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
#region Create
|
||||
|
||||
private static uint _unitySceneId = 0;
|
||||
private static byte _unityWorldId = 0;
|
||||
public Session Session { get; private set; }
|
||||
private AClientNetwork UnityNetwork { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个Unity的Scene,注意:该方法只能在主线程下使用。
|
||||
/// </summary>
|
||||
/// <param name="sceneRuntimeMode">选择Scene的运行方式</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public static async FTask<Scene> Create(string sceneRuntimeMode = SceneRuntimeMode.MainThread)
|
||||
{
|
||||
var world = ++_unityWorldId;
|
||||
|
||||
if (world > byte.MaxValue - 1)
|
||||
{
|
||||
throw new Exception($"World ID ({world}) exceeds the maximum allowed value of 255.");
|
||||
}
|
||||
|
||||
var sceneId = (uint)(++_unitySceneId + world * 1000);
|
||||
|
||||
if (sceneId > 255255)
|
||||
{
|
||||
throw new Exception($"Scene ID ({sceneId}) exceeds the maximum allowed value of 255255.");
|
||||
}
|
||||
|
||||
var scene = new Scene();
|
||||
scene.Scene = scene;
|
||||
scene.Parent = scene;
|
||||
scene.Type = typeof(Scene);
|
||||
scene.SceneRuntimeType = SceneRuntimeType.Root;
|
||||
scene.EntityIdFactory = IdFactoryHelper.EntityIdFactory(sceneId, world);
|
||||
scene.RuntimeIdFactory = IdFactoryHelper.RuntimeIdFactory(0, sceneId, world);
|
||||
scene.Id = IdFactoryHelper.EntityId(0, sceneId, world, 0);
|
||||
scene.RuntimeId = IdFactoryHelper.RuntimeId(0, sceneId, world, 0);
|
||||
scene.AddEntity(scene);
|
||||
await SetScheduler(scene, sceneRuntimeMode);
|
||||
scene.ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
scene.EventComponent.PublishAsync(new OnCreateScene(scene)).Coroutine();
|
||||
});
|
||||
return scene;
|
||||
}
|
||||
|
||||
public Session Connect(string remoteAddress, NetworkProtocolType networkProtocolType, Action onConnectComplete,
|
||||
Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000)
|
||||
{
|
||||
UnityNetwork?.Dispose();
|
||||
UnityNetwork = NetworkProtocolFactory.CreateClient(this, networkProtocolType, NetworkTarget.Outer);
|
||||
Session = UnityNetwork.Connect(remoteAddress, onConnectComplete, onConnectFail, onConnectDisconnect,
|
||||
isHttps, connectTimeout);
|
||||
return Session;
|
||||
}
|
||||
|
||||
private static async FTask SetScheduler(Scene scene, string sceneRuntimeMode)
|
||||
{
|
||||
switch (sceneRuntimeMode)
|
||||
{
|
||||
case "MainThread":
|
||||
{
|
||||
scene.ThreadSynchronizationContext = ThreadScheduler.MainScheduler.ThreadSynchronizationContext;
|
||||
scene.SceneUpdate = new EmptySceneUpdate();
|
||||
ThreadScheduler.AddMainScheduler(scene);
|
||||
await scene.Initialize();
|
||||
break;
|
||||
}
|
||||
case "MultiThread":
|
||||
{
|
||||
scene.ThreadSynchronizationContext = new ThreadSynchronizationContext();
|
||||
scene.SceneUpdate = new EmptySceneUpdate();
|
||||
ThreadScheduler.AddToMultiThreadScheduler(scene);
|
||||
await scene.Initialize();
|
||||
break;
|
||||
}
|
||||
case "ThreadPool":
|
||||
{
|
||||
scene.ThreadSynchronizationContext = new ThreadSynchronizationContext();
|
||||
scene.SceneUpdate = new EmptySceneUpdate();
|
||||
ThreadScheduler.AddToThreadPoolScheduler(scene);
|
||||
await scene.Initialize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Entities
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个实体到当前Scene下
|
||||
/// </summary>
|
||||
/// <param name="entity">实体实例</param>
|
||||
public virtual void AddEntity(Entity entity)
|
||||
{
|
||||
_entities.Add(entity.RuntimeId, entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据RunTimeId查询一个实体
|
||||
/// </summary>
|
||||
/// <param name="runTimeId">实体的RunTimeId</param>
|
||||
/// <returns>返回的实体</returns>
|
||||
public virtual Entity GetEntity(long runTimeId)
|
||||
{
|
||||
return _entities.TryGetValue(runTimeId, out var entity) ? entity : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据RunTimeId查询一个实体
|
||||
/// </summary>
|
||||
/// <param name="runTimeId">实体的RunTimeId</param>
|
||||
/// <param name="entity">实体实例</param>
|
||||
/// <returns>返回一个bool值来提示是否查找到这个实体</returns>
|
||||
public virtual bool TryGetEntity(long runTimeId, out Entity entity)
|
||||
{
|
||||
return _entities.TryGetValue(runTimeId, out entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据RunTimeId查询一个实体
|
||||
/// </summary>
|
||||
/// <param name="runTimeId">实体的RunTimeId</param>
|
||||
/// <typeparam name="T">要查询实体的泛型类型</typeparam>
|
||||
/// <returns>返回的实体</returns>
|
||||
public virtual T GetEntity<T>(long runTimeId) where T : Entity
|
||||
{
|
||||
return _entities.TryGetValue(runTimeId, out var entity) ? (T)entity : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据RunTimeId查询一个实体
|
||||
/// </summary>
|
||||
/// <param name="runTimeId">实体的RunTimeId</param>
|
||||
/// <param name="entity">实体实例</param>
|
||||
/// <typeparam name="T">要查询实体的泛型类型</typeparam>
|
||||
/// <returns>返回一个bool值来提示是否查找到这个实体</returns>
|
||||
public virtual bool TryGetEntity<T>(long runTimeId, out T entity) where T : Entity
|
||||
{
|
||||
if (_entities.TryGetValue(runTimeId, out var getEntity))
|
||||
{
|
||||
entity = (T)getEntity;
|
||||
return true;
|
||||
}
|
||||
|
||||
entity = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除一个实体,仅是删除不会指定实体的销毁方法
|
||||
/// </summary>
|
||||
/// <param name="runTimeId">实体的RunTimeId</param>
|
||||
/// <returns>返回一个bool值来提示是否删除了这个实体</returns>
|
||||
public virtual bool RemoveEntity(long runTimeId)
|
||||
{
|
||||
return _entities.Remove(runTimeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除一个实体,仅是删除不会指定实体的销毁方法
|
||||
/// </summary>
|
||||
/// <param name="entity">实体实例</param>
|
||||
/// <returns>返回一个bool值来提示是否删除了这个实体</returns>
|
||||
public virtual bool RemoveEntity(Entity entity)
|
||||
{
|
||||
return _entities.Remove(entity.RuntimeId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 968a867914cca474581795824737b521
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace NBC
|
||||
{
|
||||
/// <summary>
|
||||
/// Scene的运行类型
|
||||
/// </summary>
|
||||
public class SceneRuntimeMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Scene在主线程中运行.
|
||||
/// </summary>
|
||||
public const string MainThread = "MainThread";
|
||||
/// <summary>
|
||||
/// Scene在一个独立的线程中运行.
|
||||
/// </summary>
|
||||
public const string MultiThread = "MultiThread";
|
||||
/// <summary>
|
||||
/// Scene在一个根据当前CPU核心数创建的线程池中运行.
|
||||
/// </summary>
|
||||
public const string ThreadPool = "ThreadPool";
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7079cf6927ff4903b7c15488592e6d9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace NBC
|
||||
{
|
||||
/// <summary>
|
||||
/// 代表一个Scene的类型
|
||||
/// </summary>
|
||||
public enum SceneRuntimeType
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// 代表一个普通的Scene,一个普通的Scene肯定是是Root的
|
||||
/// </summary>
|
||||
Root = 1,
|
||||
/// <summary>
|
||||
/// 代表一个子场景,子场景肯定是有父场景的
|
||||
/// </summary>
|
||||
SubScene = 2,
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fce1a72d9b59c4611b4355bc1246a582
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 430e21e71c301427fb3a568d44ec6afa
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace NBC
|
||||
{
|
||||
internal interface ISceneScheduler : IDisposable
|
||||
{
|
||||
void Add(Scene scene);
|
||||
void Remove(Scene scene);
|
||||
void Update();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f39eba01f7f4a4b4eb94287997144b26
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,77 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace NBC
|
||||
{
|
||||
internal sealed class MainScheduler : ISceneScheduler
|
||||
{
|
||||
private readonly Queue<Scene> _queue = new Queue<Scene>();
|
||||
public readonly ThreadSynchronizationContext ThreadSynchronizationContext;
|
||||
|
||||
public MainScheduler()
|
||||
{
|
||||
ThreadSynchronizationContext = new ThreadSynchronizationContext();
|
||||
SynchronizationContext.SetSynchronizationContext(ThreadSynchronizationContext);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
_queue.Clear();
|
||||
}
|
||||
|
||||
public void Add(Scene scene)
|
||||
{
|
||||
ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
if (scene.IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_queue.Enqueue(scene);
|
||||
});
|
||||
}
|
||||
|
||||
public void Remove(Scene scene)
|
||||
{
|
||||
ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
if (scene.IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var initialCount = _queue.Count;
|
||||
for (var i = 0; i < initialCount; i++)
|
||||
{
|
||||
var currentScene = _queue.Dequeue();
|
||||
if (currentScene != scene)
|
||||
{
|
||||
_queue.Enqueue(currentScene);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
ThreadSynchronizationContext.Update();
|
||||
var initialCount = _queue.Count;
|
||||
|
||||
while (initialCount-- > 0)
|
||||
{
|
||||
if(!_queue.TryDequeue(out var scene))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (scene.IsDisposed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
scene.Update();
|
||||
_queue.Enqueue(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c7398438bdaa4c1aa3ae9bd545acc76
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,103 +0,0 @@
|
||||
#if !FANTASY_WEBGL || !FANTASY_SINGLETHREAD
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
namespace NBC
|
||||
{
|
||||
internal struct MultiThreadStruct : IDisposable
|
||||
{
|
||||
public readonly Thread Thread;
|
||||
public readonly CancellationTokenSource Cts;
|
||||
|
||||
public MultiThreadStruct(Thread thread, CancellationTokenSource cts)
|
||||
{
|
||||
Thread = thread;
|
||||
Cts = cts;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Cts.Cancel();
|
||||
if (Thread.IsAlive)
|
||||
{
|
||||
Thread.Join();
|
||||
}
|
||||
Cts.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class MultiThreadScheduler : ISceneScheduler
|
||||
{
|
||||
private bool _isDisposed;
|
||||
private readonly ConcurrentDictionary<long, MultiThreadStruct> _threads = new ConcurrentDictionary<long, MultiThreadStruct>();
|
||||
public int ThreadCount => _threads.Count;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
|
||||
foreach (var (_, multiThreadStruct) in _threads.ToArray())
|
||||
{
|
||||
multiThreadStruct.Dispose();
|
||||
}
|
||||
|
||||
_threads.Clear();
|
||||
}
|
||||
|
||||
public void Add(Scene scene)
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
var thread = new Thread(() => Loop(scene, cts.Token));
|
||||
_threads.TryAdd(scene.RuntimeId, new MultiThreadStruct(thread, cts));
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
public void Remove(Scene scene)
|
||||
{
|
||||
if (_threads.TryRemove(scene.RuntimeId, out var multiThreadStruct))
|
||||
{
|
||||
multiThreadStruct.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void Loop(Scene scene, CancellationToken cancellationToken)
|
||||
{
|
||||
var sceneThreadSynchronizationContext = scene.ThreadSynchronizationContext;
|
||||
SynchronizationContext.SetSynchronizationContext(sceneThreadSynchronizationContext);
|
||||
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (scene.IsDisposed)
|
||||
{
|
||||
Remove(scene);
|
||||
return;
|
||||
}
|
||||
|
||||
sceneThreadSynchronizationContext.Update();
|
||||
scene.Update();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"Error in MultiThreadScheduler loop: {e.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36b6da87c3a674cb5b2d2d9d270c397d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,140 +0,0 @@
|
||||
#if !FANTASY_WEBGL || !FANTASY_SINGLETHREAD
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
#pragma warning disable CS8604 // Possible null reference argument.
|
||||
namespace NBC
|
||||
{
|
||||
internal sealed class ThreadPoolScheduler : ISceneScheduler
|
||||
{
|
||||
private bool _isDisposed;
|
||||
private readonly List<Thread> _threads;
|
||||
private readonly ConcurrentBag<Scene> _queue = new ConcurrentBag<Scene>();
|
||||
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
public ThreadPoolScheduler()
|
||||
{
|
||||
// 最大线程数、避免线程过多发生的资源抢占问题。
|
||||
// 但如果使用了MultiThreadScheduler,那么这里的线程数就算是设置了也有可能导致线程过多的问题。
|
||||
// 线程过多看每个线程的抢占情况,如果抢占资源占用不是很大也没什么大问题。如果过大的情况,就会有性能问题。
|
||||
// 所以根据情况来使用不同的调度器。
|
||||
var maxThreadCount = Environment.ProcessorCount;
|
||||
_threads = new List<Thread>(maxThreadCount);
|
||||
|
||||
for (var i = 0; i < maxThreadCount; ++i)
|
||||
{
|
||||
Thread thread = new(() => Loop(_cancellationTokenSource.Token))
|
||||
{
|
||||
IsBackground = true
|
||||
};
|
||||
_threads.Add(thread);
|
||||
thread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
_cancellationTokenSource.Cancel();
|
||||
|
||||
foreach (var thread in _threads)
|
||||
{
|
||||
if (thread.IsAlive)
|
||||
{
|
||||
thread.Join();
|
||||
}
|
||||
}
|
||||
|
||||
_cancellationTokenSource.Dispose();
|
||||
_threads.Clear();
|
||||
}
|
||||
|
||||
public void Add(Scene scene)
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_queue.Add(scene);
|
||||
}
|
||||
|
||||
public void Remove(Scene scene)
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var newQueue = new Queue<Scene>();
|
||||
|
||||
while (!_queue.IsEmpty)
|
||||
{
|
||||
if (_queue.TryTake(out var currentScene))
|
||||
{
|
||||
if (currentScene != scene)
|
||||
{
|
||||
newQueue.Enqueue(currentScene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (newQueue.TryDequeue(out var newScene))
|
||||
{
|
||||
_queue.Add(newScene);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void Loop(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (_queue.TryTake(out var scene))
|
||||
{
|
||||
if (scene == null || scene.IsDisposed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var sceneThreadSynchronizationContext = scene.ThreadSynchronizationContext;
|
||||
SynchronizationContext.SetSynchronizationContext(sceneThreadSynchronizationContext);
|
||||
|
||||
try
|
||||
{
|
||||
sceneThreadSynchronizationContext.Update();
|
||||
scene.Update();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"Error in ThreadPoolScheduler scene: {e.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(null);
|
||||
}
|
||||
|
||||
_queue.Add(scene);
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 当队列为空的时候、避免无效循环消耗CPU。
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12f33fe68e2b64ac98ecd79b8158e420
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,66 +0,0 @@
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
namespace NBC
|
||||
{
|
||||
/// <summary>
|
||||
/// 线程调度器
|
||||
/// </summary>
|
||||
internal static class ThreadScheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// 主线程调度器
|
||||
/// </summary>
|
||||
public static MainScheduler MainScheduler { get; private set; }
|
||||
/// <summary>
|
||||
/// 多线程调度器,根据当前CPU核心数量创建的固定线程。
|
||||
/// </summary>
|
||||
public static ISceneScheduler MultiThreadScheduler { get; private set; }
|
||||
/// <summary>
|
||||
/// 线程池调度器
|
||||
/// </summary>
|
||||
public static ISceneScheduler ThreadPoolScheduler { get; private set; }
|
||||
|
||||
static ThreadScheduler()
|
||||
{
|
||||
MainScheduler = new MainScheduler();
|
||||
}
|
||||
|
||||
internal static void Update()
|
||||
{
|
||||
MainScheduler.Update();
|
||||
}
|
||||
|
||||
internal static void AddMainScheduler(Scene scene)
|
||||
{
|
||||
MainScheduler.Add(scene);
|
||||
}
|
||||
|
||||
internal static void AddToMultiThreadScheduler(Scene scene)
|
||||
{
|
||||
if (MultiThreadScheduler == null)
|
||||
{
|
||||
#if FANTASY_SINGLETHREAD || FANTASY_WEBGL
|
||||
MultiThreadScheduler = MainScheduler;
|
||||
#else
|
||||
MultiThreadScheduler = new MultiThreadScheduler();
|
||||
#endif
|
||||
}
|
||||
|
||||
MultiThreadScheduler.Add(scene);
|
||||
}
|
||||
|
||||
internal static void AddToThreadPoolScheduler(Scene scene)
|
||||
{
|
||||
if (ThreadPoolScheduler == null)
|
||||
{
|
||||
#if FANTASY_SINGLETHREAD || FANTASY_WEBGL
|
||||
ThreadPoolScheduler = MainScheduler;
|
||||
#else
|
||||
ThreadPoolScheduler = new ThreadPoolScheduler();
|
||||
#endif
|
||||
}
|
||||
|
||||
ThreadPoolScheduler.Add(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9807e33a9ca94371885c6934ff42523
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,154 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NBC.Network;
|
||||
using NBC.Entitas;
|
||||
|
||||
#pragma warning disable CS8601 // Possible null reference assignment.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
|
||||
namespace NBC
|
||||
{
|
||||
/// <summary>
|
||||
/// 代表一个Scene下的子Scene
|
||||
/// </summary>
|
||||
public sealed partial class SubScene : Scene
|
||||
{
|
||||
/// <summary>
|
||||
/// 子Scene的根Scene
|
||||
/// </summary>
|
||||
public Scene RootScene { get; internal set; }
|
||||
/// <summary>
|
||||
/// 存储当前Scene下管理的实体。
|
||||
/// </summary>
|
||||
private readonly Dictionary<long, Entity> _entities = new Dictionary<long, Entity>();
|
||||
|
||||
internal void Initialize(Scene rootScene)
|
||||
{
|
||||
EntityPool = rootScene.EntityPool;
|
||||
EntityListPool = rootScene.EntityListPool;
|
||||
EntitySortedDictionaryPool = rootScene.EntitySortedDictionaryPool;
|
||||
SceneUpdate = rootScene.SceneUpdate;
|
||||
TimerComponent = rootScene.TimerComponent;
|
||||
EventComponent = rootScene.EventComponent;
|
||||
EntityComponent = rootScene.EntityComponent;
|
||||
MessagePoolComponent = rootScene.MessagePoolComponent;
|
||||
CoroutineLockComponent = rootScene.CoroutineLockComponent;
|
||||
MessageDispatcherComponent = rootScene.MessageDispatcherComponent;
|
||||
ThreadSynchronizationContext = rootScene.ThreadSynchronizationContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当子Scene销毁时执行
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadSynchronizationContext.Post(() =>
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (runtimeId, entity) in _entities.ToList())
|
||||
{
|
||||
if (runtimeId != entity.RuntimeId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
entity.Dispose();
|
||||
}
|
||||
|
||||
_entities.Clear();
|
||||
base.Dispose();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个实体到当前Scene下
|
||||
/// </summary>
|
||||
/// <param name="entity">实体实例</param>
|
||||
public override void AddEntity(Entity entity)
|
||||
{
|
||||
_entities.Add(entity.RuntimeId, entity);
|
||||
RootScene.AddEntity(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据RunTimeId查询一个实体
|
||||
/// </summary>
|
||||
/// <param name="runTimeId">实体的RunTimeId</param>
|
||||
/// <returns>返回的实体</returns>
|
||||
public override Entity GetEntity(long runTimeId)
|
||||
{
|
||||
return _entities.GetValueOrDefault(runTimeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据RunTimeId查询一个实体
|
||||
/// </summary>
|
||||
/// <param name="runTimeId">实体的RunTimeId</param>
|
||||
/// <param name="entity">实体实例</param>
|
||||
/// <returns>返回一个bool值来提示是否查找到这个实体</returns>
|
||||
public override bool TryGetEntity(long runTimeId, out Entity entity)
|
||||
{
|
||||
return _entities.TryGetValue(runTimeId, out entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据RunTimeId查询一个实体
|
||||
/// </summary>
|
||||
/// <param name="runTimeId">实体的RunTimeId</param>
|
||||
/// <typeparam name="T">要查询实体的泛型类型</typeparam>
|
||||
/// <returns>返回的实体</returns>
|
||||
public override T GetEntity<T>(long runTimeId)
|
||||
{
|
||||
return _entities.TryGetValue(runTimeId, out var entity) ? (T)entity : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据RunTimeId查询一个实体
|
||||
/// </summary>
|
||||
/// <param name="runTimeId">实体的RunTimeId</param>
|
||||
/// <param name="entity">实体实例</param>
|
||||
/// <typeparam name="T">要查询实体的泛型类型</typeparam>
|
||||
/// <returns>返回一个bool值来提示是否查找到这个实体</returns>
|
||||
public override bool TryGetEntity<T>(long runTimeId, out T entity)
|
||||
{
|
||||
if (_entities.TryGetValue(runTimeId, out var getEntity))
|
||||
{
|
||||
entity = (T)getEntity;
|
||||
return true;
|
||||
}
|
||||
|
||||
entity = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除一个实体,仅是删除不会指定实体的销毁方法
|
||||
/// </summary>
|
||||
/// <param name="runTimeId">实体的RunTimeId</param>
|
||||
/// <returns>返回一个bool值来提示是否删除了这个实体</returns>
|
||||
public override bool RemoveEntity(long runTimeId)
|
||||
{
|
||||
return _entities.Remove(runTimeId) && RootScene.RemoveEntity(runTimeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除一个实体,仅是删除不会指定实体的销毁方法
|
||||
/// </summary>
|
||||
/// <param name="entity">实体实例</param>
|
||||
/// <returns>返回一个bool值来提示是否删除了这个实体</returns>
|
||||
public override bool RemoveEntity(Entity entity)
|
||||
{
|
||||
return RemoveEntity(entity.RuntimeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38f07f37ebbca4379903da052249b06b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user