using System; using System.Collections.Generic; using System.Linq; using Fantasy.Async; using Fantasy.Entitas; using Fantasy.Event; using Fantasy.IdFactory; using Fantasy.Network; using Fantasy.Network.Interface; using Fantasy.Pool; using Fantasy.Scheduler; using Fantasy.Timer; #if FANTASY_NET using Fantasy.DataBase; using Fantasy.Platform.Net; using Fantasy.SingleCollection; using System.Runtime.CompilerServices; using Fantasy.Network.Route; using Fantasy.Network.Roaming; #endif // 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 Fantasy { /// /// 当Scene创建完成后发送的事件参数 /// public struct OnCreateScene { /// /// 获取与事件关联的场景实体。 /// public readonly Scene Scene; /// /// 初始化一个新的 OnCreateScene 实例。 /// /// public OnCreateScene(Scene scene) { Scene = scene; } } /// /// 表示一个场景实体,用于创建与管理特定的游戏场景信息。 /// public partial class Scene : Entity { #region Members /// /// Scene的运行类型 /// public SceneRuntimeType SceneRuntimeType { get; protected set; } #if FANTASY_NET /// /// Scene类型,对应SceneConfig的SceneType /// public int SceneType { get; protected set; } /// /// 所属的世界 /// public World World { get; protected set; } /// /// 所在的Process /// public Process Process { get; protected set; } /// /// SceneConfig的Id /// public uint SceneConfigId { get; protected set; } internal ANetwork InnerNetwork { get; private set; } internal ANetwork OuterNetwork { get; private set; } internal SceneConfig SceneConfig => SceneConfigData.Instance.Get(SceneConfigId); private readonly Dictionary _processSessionInfos = new Dictionary(); #endif /// /// 当前Scene的上下文 /// public ThreadSynchronizationContext ThreadSynchronizationContext { get; internal set; } /// /// 当前Scene的下创建的Entity /// private readonly Dictionary _entities = new Dictionary(); internal readonly Dictionary> TypeInstance = new Dictionary>(); #endregion #region IdFactory /// /// Entity实体Id的生成器 /// public IEntityIdFactory EntityIdFactory { get; protected set; } /// /// Entity实体RuntimeId的生成器 /// public IRuntimeIdFactory RuntimeIdFactory { get; protected set; } #endregion #region Pool internal EntityPool EntityPool; internal EntityListPool EntityListPool; internal EntitySortedDictionaryPool EntitySortedDictionaryPool; #endregion #region Component /// /// Scene下的任务调度器系统组件 /// public TimerComponent TimerComponent { get; internal set; } /// /// Scene下的事件系统组件 /// public EventComponent EventComponent { get; internal set; } /// /// Scene下的ESC系统组件 /// public EntityComponent EntityComponent { get; internal set; } /// /// Scene下的网络消息对象池组件 /// public MessagePoolComponent MessagePoolComponent { get; internal set; } /// /// Scene下的协程锁组件 /// public CoroutineLockComponent CoroutineLockComponent { get; internal set; } /// /// Scene下的网络消息派发组件 /// internal MessageDispatcherComponent MessageDispatcherComponent { get; set; } #if FANTASY_NET /// /// Scene下的Entity分表组件 /// public SingleCollectionComponent SingleCollectionComponent { get; internal set; } /// /// Scene下的内网消息发送组件 /// public NetworkMessagingComponent NetworkMessagingComponent { get; internal set; } /// /// Scene下的漫游终端管理组件 /// public TerminusComponent TerminusComponent { get; internal set; } /// /// Scene下的Session漫游组件 /// public RoamingComponent RoamingComponent { get; internal set; } #endif #endregion #region Initialize private async FTask Initialize() { EntityPool = new EntityPool(); EntityListPool = new EntityListPool(); EntitySortedDictionaryPool = new EntitySortedDictionaryPool(); SceneUpdate = EntityComponent = await Create(this, false, false).Initialize(); MessagePoolComponent = Create(this,false,true); EventComponent = await Create(this,false,true).Initialize(); TimerComponent = Create(this, false, true).Initialize(); CoroutineLockComponent = Create(this, false, true).Initialize(); MessageDispatcherComponent = await Create(this, false, true).Initialize(); #if FANTASY_NET NetworkMessagingComponent = Create(this, false, true); SingleCollectionComponent = await Create(this, false, true).Initialize(); TerminusComponent = Create(this, false, true); RoamingComponent = Create(this, false, true).Initialize(); #endif } /// /// Scene销毁方法,执行了该方法会把当前Scene下的所有实体都销毁掉。 /// public override void Dispose() { if (IsDisposed) { return; } base.Dispose(); _entities.Remove(RuntimeId); switch (SceneRuntimeType) { case SceneRuntimeType.Root: { #if FANTASY_NET foreach (var (_, processSessionInfo) in _processSessionInfos.ToList()) { processSessionInfo.Dispose(); } _processSessionInfos.Clear(); #endif _entities.Remove(EntityComponent.RuntimeId); foreach (var (runtimeId, entity) in _entities.ToList()) { if (runtimeId != entity.RuntimeId) { continue; } entity.Dispose(); } _entities.Clear(); #if FANTASY_UNITY _unityWorldId--; _unitySceneId--; #endif TypeInstance.Clear(); #if FANTASY_NET Process.RemoveScene(this, false); Process.RemoveSceneToProcess(this, false); #endif 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; #if FANTASY_NET World = null; Process = null; SceneType = 0; SceneConfigId = 0; SingleCollectionComponent = null; NetworkMessagingComponent = null; TerminusComponent = null; RoamingComponent = null; #elif FANTASY_UNITY Session = null; UnityNetwork = null; #endif 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 #if FANTASY_UNITY || FANTASY_CONSOLE private static uint _unitySceneId = 0; private static byte _unityWorldId = 0; public Session Session { get; private set; } private AClientNetwork UnityNetwork { get; set; } /// /// 创建一个Unity的Scene,注意:该方法只能在主线程下使用。 /// /// 选择Scene的运行方式 /// /// public static async FTask 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; } #endif #if FANTASY_NET [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Scene Create(Process process, byte worldId, uint sceneConfigId) { var scene = new Scene(); scene.Scene = scene; scene.Parent = scene; scene.Type = typeof(Scene); scene.Process = process; scene.SceneRuntimeType = SceneRuntimeType.Root; scene.EntityIdFactory = IdFactoryHelper.EntityIdFactory(sceneConfigId, worldId); scene.RuntimeIdFactory = IdFactoryHelper.RuntimeIdFactory(0,sceneConfigId, worldId); scene.Id = IdFactoryHelper.EntityId(0, sceneConfigId, worldId, 0); scene.RuntimeId = IdFactoryHelper.RuntimeId(0, sceneConfigId, worldId, 0); scene.AddEntity(scene); return scene; } /// /// 创建一个新的Scene /// /// 所属的Process /// 对应的MachineConfig配置文件 /// 对应的SceneConfig配置文件 /// 创建成功后会返回创建的Scene的实例 public static async FTask Create(Process process, MachineConfig machineConfig, SceneConfig sceneConfig) { var scene = Create(process, (byte)sceneConfig.WorldConfigId, sceneConfig.Id); scene.SceneType = sceneConfig.SceneType; scene.SceneConfigId = sceneConfig.Id; await SetScheduler(scene, sceneConfig.SceneRuntimeMode); if (sceneConfig.WorldConfigId != 0) { scene.World = World.Create(scene, (byte)sceneConfig.WorldConfigId); } if (sceneConfig.InnerPort != 0) { // 创建内网网络服务器 scene.InnerNetwork = NetworkProtocolFactory.CreateServer(scene, ProcessDefine.InnerNetwork, NetworkTarget.Inner, machineConfig.InnerBindIP, sceneConfig.InnerPort); } if (sceneConfig.OuterPort != 0) { // 创建外网网络服务 var networkProtocolType = Enum.Parse(sceneConfig.NetworkProtocol); scene.OuterNetwork = NetworkProtocolFactory.CreateServer(scene, networkProtocolType, NetworkTarget.Outer, machineConfig.OuterBindIP, sceneConfig.OuterPort); } Process.AddScene(scene); process.AddSceneToProcess(scene); scene.ThreadSynchronizationContext.Post(() => { if (sceneConfig.SceneTypeString == "Addressable") { // 如果是AddressableScene,自动添加上AddressableManageComponent。 scene.AddComponent(); } scene.EventComponent.PublishAsync(new OnCreateScene(scene)).Coroutine(); }); return scene; } /// /// 在Scene下面创建一个子Scene,一般用于副本,或者一些特殊的场景。 /// /// 主Scene的实例 /// SceneType,可以在SceneType里找到,例如:SceneType.Addressable /// 子Scene创建成功后执行的委托,可以传递null /// public static SubScene CreateSubScene(Scene parentScene, int sceneType, Action onSubSceneComplete = null) { var scene = new SubScene(); scene.Scene = scene; scene.Parent = scene; scene.RootScene = parentScene; scene.Type = typeof(SubScene); scene.SceneType = sceneType; scene.World = parentScene.World; scene.Process = parentScene.Process; scene.SceneRuntimeType = SceneRuntimeType.SubScene; scene.EntityIdFactory = parentScene.EntityIdFactory; scene.RuntimeIdFactory = parentScene.RuntimeIdFactory; scene.Id = scene.EntityIdFactory.Create; scene.RuntimeId = scene.RuntimeIdFactory.Create; scene.AddEntity(scene); scene.Initialize(parentScene); scene.ThreadSynchronizationContext.Post(() => OnEvent().Coroutine()); return scene; async FTask OnEvent() { await scene.EventComponent.PublishAsync(new OnCreateScene(scene)); onSubSceneComplete?.Invoke(scene, parentScene); } } #endif 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": { #if !FANTASY_WEBGL scene.ThreadSynchronizationContext = new ThreadSynchronizationContext(); #endif scene.SceneUpdate = new EmptySceneUpdate(); ThreadScheduler.AddToMultiThreadScheduler(scene); await scene.Initialize(); break; } case "ThreadPool": { #if !FANTASY_WEBGL scene.ThreadSynchronizationContext = new ThreadSynchronizationContext(); #endif scene.SceneUpdate = new EmptySceneUpdate(); ThreadScheduler.AddToThreadPoolScheduler(scene); await scene.Initialize(); break; } } } #endregion #region Entities /// /// 添加一个实体到当前Scene下 /// /// 实体实例 public virtual void AddEntity(Entity entity) { _entities.Add(entity.RuntimeId, entity); } /// /// 根据RunTimeId查询一个实体 /// /// 实体的RunTimeId /// 返回的实体 public virtual Entity GetEntity(long runTimeId) { return _entities.TryGetValue(runTimeId, out var entity) ? entity : null; } /// /// 根据RunTimeId查询一个实体 /// /// 实体的RunTimeId /// 实体实例 /// 返回一个bool值来提示是否查找到这个实体 public virtual bool TryGetEntity(long runTimeId, out Entity entity) { return _entities.TryGetValue(runTimeId, out entity); } /// /// 根据RunTimeId查询一个实体 /// /// 实体的RunTimeId /// 要查询实体的泛型类型 /// 返回的实体 public virtual T GetEntity(long runTimeId) where T : Entity { return _entities.TryGetValue(runTimeId, out var entity) ? (T)entity : null; } /// /// 根据RunTimeId查询一个实体 /// /// 实体的RunTimeId /// 实体实例 /// 要查询实体的泛型类型 /// 返回一个bool值来提示是否查找到这个实体 public virtual bool TryGetEntity(long runTimeId, out T entity) where T : Entity { if (_entities.TryGetValue(runTimeId, out var getEntity)) { entity = (T)getEntity; return true; } entity = null; return false; } /// /// 删除一个实体,仅是删除不会指定实体的销毁方法 /// /// 实体的RunTimeId /// 返回一个bool值来提示是否删除了这个实体 public virtual bool RemoveEntity(long runTimeId) { return _entities.Remove(runTimeId); } /// /// 删除一个实体,仅是删除不会指定实体的销毁方法 /// /// 实体实例 /// 返回一个bool值来提示是否删除了这个实体 public virtual bool RemoveEntity(Entity entity) { return _entities.Remove(entity.RuntimeId); } #endregion #region InnerSession #if FANTASY_NET /// /// 根据runTimeId获得Session /// /// /// /// public virtual Session GetSession(long runTimeId) { var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref runTimeId); if (_processSessionInfos.TryGetValue(sceneId, out var processSessionInfo)) { if (!processSessionInfo.Session.IsDisposed) { return processSessionInfo.Session; } _processSessionInfos.Remove(sceneId); } if (Process.IsInAppliaction(ref sceneId)) { // 如果在同一个Process下,不需要通过Socket发送了,直接通过Process下转发。 var processSession = Session.CreateInnerSession(Scene); _processSessionInfos.Add(sceneId, new ProcessSessionInfo(processSession, null)); return processSession; } if (!SceneConfigData.Instance.TryGet(sceneId, out var sceneConfig)) { throw new Exception($"The scene with sceneId {sceneId} was not found in the configuration file"); } if (!ProcessConfigData.Instance.TryGet(sceneConfig.ProcessConfigId, out var processConfig)) { throw new Exception($"The process with processId {sceneConfig.ProcessConfigId} was not found in the configuration file"); } if (!MachineConfigData.Instance.TryGet(processConfig.MachineId, out var machineConfig)) { throw new Exception($"The machine with machineId {processConfig.MachineId} was not found in the configuration file"); } var remoteAddress = $"{machineConfig.InnerBindIP}:{sceneConfig.InnerPort}"; var client = NetworkProtocolFactory.CreateClient(Scene, ProcessDefine.InnerNetwork, NetworkTarget.Inner); var session = client.Connect(remoteAddress, null, () => { Log.Error($"Unable to connect to the target server sourceServerId:{Scene.Process.Id} targetServerId:{sceneConfig.ProcessConfigId}"); }, null, false); _processSessionInfos.Add(sceneId, new ProcessSessionInfo(session, client)); return session; } #endif #endregion } }