Repository: EllanJiang/GameFramework Branch: master Commit: d0c010b05167 Files: 335 Total size: 1.9 MB Directory structure: gitextract_cx5fvckj/ ├── .gitignore ├── GameFramework/ │ ├── Base/ │ │ ├── DataProvider/ │ │ │ ├── DataProvider.cs │ │ │ ├── DataProviderCreator.cs │ │ │ ├── IDataProvider.cs │ │ │ ├── IDataProviderHelper.cs │ │ │ ├── ReadDataDependencyAssetEventArgs.cs │ │ │ ├── ReadDataFailureEventArgs.cs │ │ │ ├── ReadDataSuccessEventArgs.cs │ │ │ └── ReadDataUpdateEventArgs.cs │ │ ├── DataStruct/ │ │ │ └── TypeNamePair.cs │ │ ├── EventPool/ │ │ │ ├── BaseEventArgs.cs │ │ │ ├── EventPool.Event.cs │ │ │ ├── EventPool.cs │ │ │ └── EventPoolMode.cs │ │ ├── GameFrameworkAction.cs │ │ ├── GameFrameworkEntry.cs │ │ ├── GameFrameworkEventArgs.cs │ │ ├── GameFrameworkException.cs │ │ ├── GameFrameworkFunc.cs │ │ ├── GameFrameworkLinkedList.cs │ │ ├── GameFrameworkLinkedListRange.cs │ │ ├── GameFrameworkModule.cs │ │ ├── GameFrameworkMultiDictionary.cs │ │ ├── GameFrameworkSerializer.cs │ │ ├── Log/ │ │ │ ├── GameFrameworkLog.ILogHelper.cs │ │ │ ├── GameFrameworkLog.cs │ │ │ └── GameFrameworkLogLevel.cs │ │ ├── ReferencePool/ │ │ │ ├── IReference.cs │ │ │ ├── ReferencePool.ReferenceCollection.cs │ │ │ ├── ReferencePool.cs │ │ │ └── ReferencePoolInfo.cs │ │ ├── TaskPool/ │ │ │ ├── ITaskAgent.cs │ │ │ ├── StartTaskStatus.cs │ │ │ ├── TaskBase.cs │ │ │ ├── TaskInfo.cs │ │ │ ├── TaskPool.cs │ │ │ └── TaskStatus.cs │ │ ├── Variable/ │ │ │ ├── GenericVariable.cs │ │ │ └── Variable.cs │ │ └── Version/ │ │ ├── Version.IVersionHelper.cs │ │ └── Version.cs │ ├── Config/ │ │ ├── ConfigManager.ConfigData.cs │ │ ├── ConfigManager.cs │ │ ├── IConfigHelper.cs │ │ └── IConfigManager.cs │ ├── DataNode/ │ │ ├── DataNodeManager.DataNode.cs │ │ ├── DataNodeManager.cs │ │ ├── IDataNode.cs │ │ └── IDataNodeManager.cs │ ├── DataTable/ │ │ ├── DataTableBase.cs │ │ ├── DataTableManager.DataTable.cs │ │ ├── DataTableManager.cs │ │ ├── IDataRow.cs │ │ ├── IDataTable.cs │ │ ├── IDataTableHelper.cs │ │ └── IDataTableManager.cs │ ├── Debugger/ │ │ ├── DebuggerManager.DebuggerWindowGroup.cs │ │ ├── DebuggerManager.cs │ │ ├── IDebuggerManager.cs │ │ ├── IDebuggerWindow.cs │ │ └── IDebuggerWindowGroup.cs │ ├── Download/ │ │ ├── Constant.cs │ │ ├── DownloadAgentHelperCompleteEventArgs.cs │ │ ├── DownloadAgentHelperErrorEventArgs.cs │ │ ├── DownloadAgentHelperUpdateBytesEventArgs.cs │ │ ├── DownloadAgentHelperUpdateLengthEventArgs.cs │ │ ├── DownloadFailureEventArgs.cs │ │ ├── DownloadManager.DownloadAgent.cs │ │ ├── DownloadManager.DownloadCounter.DownloadCounterNode.cs │ │ ├── DownloadManager.DownloadCounter.cs │ │ ├── DownloadManager.DownloadTask.cs │ │ ├── DownloadManager.DownloadTaskStatus.cs │ │ ├── DownloadManager.cs │ │ ├── DownloadStartEventArgs.cs │ │ ├── DownloadSuccessEventArgs.cs │ │ ├── DownloadUpdateEventArgs.cs │ │ ├── IDownloadAgentHelper.cs │ │ └── IDownloadManager.cs │ ├── Entity/ │ │ ├── EntityManager.EntityGroup.cs │ │ ├── EntityManager.EntityInfo.cs │ │ ├── EntityManager.EntityInstanceObject.cs │ │ ├── EntityManager.EntityStatus.cs │ │ ├── EntityManager.ShowEntityInfo.cs │ │ ├── EntityManager.cs │ │ ├── HideEntityCompleteEventArgs.cs │ │ ├── IEntity.cs │ │ ├── IEntityGroup.cs │ │ ├── IEntityGroupHelper.cs │ │ ├── IEntityHelper.cs │ │ ├── IEntityManager.cs │ │ ├── ShowEntityDependencyAssetEventArgs.cs │ │ ├── ShowEntityFailureEventArgs.cs │ │ ├── ShowEntitySuccessEventArgs.cs │ │ └── ShowEntityUpdateEventArgs.cs │ ├── Event/ │ │ ├── EventManager.cs │ │ ├── GameEventArgs.cs │ │ └── IEventManager.cs │ ├── FileSystem/ │ │ ├── CommonFileSystemStream.cs │ │ ├── FileInfo.cs │ │ ├── FileSystem.BlockData.cs │ │ ├── FileSystem.HeaderData.cs │ │ ├── FileSystem.StringData.cs │ │ ├── FileSystem.cs │ │ ├── FileSystemAccess.cs │ │ ├── FileSystemManager.cs │ │ ├── FileSystemStream.cs │ │ ├── IFileSystem.cs │ │ ├── IFileSystemHelper.cs │ │ └── IFileSystemManager.cs │ ├── Fsm/ │ │ ├── Fsm.cs │ │ ├── FsmBase.cs │ │ ├── FsmManager.cs │ │ ├── FsmState.cs │ │ ├── IFsm.cs │ │ └── IFsmManager.cs │ ├── GameFramework.csproj │ ├── Localization/ │ │ ├── ILocalizationHelper.cs │ │ ├── ILocalizationManager.cs │ │ ├── Language.cs │ │ └── LocalizationManager.cs │ ├── Network/ │ │ ├── AddressFamily.cs │ │ ├── INetworkChannel.cs │ │ ├── INetworkChannelHelper.cs │ │ ├── INetworkManager.cs │ │ ├── IPacketHandler.cs │ │ ├── IPacketHeader.cs │ │ ├── NetworkClosedEventArgs.cs │ │ ├── NetworkConnectedEventArgs.cs │ │ ├── NetworkCustomErrorEventArgs.cs │ │ ├── NetworkErrorCode.cs │ │ ├── NetworkErrorEventArgs.cs │ │ ├── NetworkManager.ConnectState.cs │ │ ├── NetworkManager.HeartBeatState.cs │ │ ├── NetworkManager.NetworkChannelBase.cs │ │ ├── NetworkManager.ReceiveState.cs │ │ ├── NetworkManager.SendState.cs │ │ ├── NetworkManager.TcpNetworkChannel.cs │ │ ├── NetworkManager.TcpWithSyncReceiveNetworkChannel.cs │ │ ├── NetworkManager.cs │ │ ├── NetworkMissHeartBeatEventArgs.cs │ │ ├── Packet.cs │ │ └── ServiceType.cs │ ├── ObjectPool/ │ │ ├── IObjectPool.cs │ │ ├── IObjectPoolManager.cs │ │ ├── ObjectBase.cs │ │ ├── ObjectInfo.cs │ │ ├── ObjectPoolBase.cs │ │ ├── ObjectPoolManager.Object.cs │ │ ├── ObjectPoolManager.ObjectPool.cs │ │ ├── ObjectPoolManager.cs │ │ └── ReleaseObjectFilterCallback.cs │ ├── Procedure/ │ │ ├── IProcedureManager.cs │ │ ├── ProcedureBase.cs │ │ └── ProcedureManager.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── Resource/ │ │ ├── ApplyResourcesCompleteCallback.cs │ │ ├── CheckResourcesCompleteCallback.cs │ │ ├── CheckVersionListResult.cs │ │ ├── Constant.cs │ │ ├── DecryptResourceCallback.cs │ │ ├── HasAssetResult.cs │ │ ├── ILoadResourceAgentHelper.cs │ │ ├── IResourceGroup.cs │ │ ├── IResourceGroupCollection.cs │ │ ├── IResourceHelper.cs │ │ ├── IResourceManager.cs │ │ ├── InitResourcesCompleteCallback.cs │ │ ├── LoadAssetCallbacks.cs │ │ ├── LoadAssetDependencyAssetCallback.cs │ │ ├── LoadAssetFailureCallback.cs │ │ ├── LoadAssetSuccessCallback.cs │ │ ├── LoadAssetUpdateCallback.cs │ │ ├── LoadBinaryCallbacks.cs │ │ ├── LoadBinaryFailureCallback.cs │ │ ├── LoadBinarySuccessCallback.cs │ │ ├── LoadBytesCallbacks.cs │ │ ├── LoadBytesFailureCallback.cs │ │ ├── LoadBytesSuccessCallback.cs │ │ ├── LoadResourceAgentHelperErrorEventArgs.cs │ │ ├── LoadResourceAgentHelperLoadCompleteEventArgs.cs │ │ ├── LoadResourceAgentHelperParseBytesCompleteEventArgs.cs │ │ ├── LoadResourceAgentHelperReadBytesCompleteEventArgs.cs │ │ ├── LoadResourceAgentHelperReadFileCompleteEventArgs.cs │ │ ├── LoadResourceAgentHelperUpdateEventArgs.cs │ │ ├── LoadResourceProgress.cs │ │ ├── LoadResourceStatus.cs │ │ ├── LoadSceneCallbacks.cs │ │ ├── LoadSceneDependencyAssetCallback.cs │ │ ├── LoadSceneFailureCallback.cs │ │ ├── LoadSceneSuccessCallback.cs │ │ ├── LoadSceneUpdateCallback.cs │ │ ├── LocalVersionList.FileSystem.cs │ │ ├── LocalVersionList.Resource.cs │ │ ├── LocalVersionList.cs │ │ ├── PackageVersionList.Asset.cs │ │ ├── PackageVersionList.FileSystem.cs │ │ ├── PackageVersionList.Resource.cs │ │ ├── PackageVersionList.ResourceGroup.cs │ │ ├── PackageVersionList.cs │ │ ├── PackageVersionListSerializer.cs │ │ ├── ReadOnlyVersionListSerializer.cs │ │ ├── ReadWriteVersionListSerializer.cs │ │ ├── ResourceApplyFailureEventArgs.cs │ │ ├── ResourceApplyStartEventArgs.cs │ │ ├── ResourceApplySuccessEventArgs.cs │ │ ├── ResourceManager.AssetInfo.cs │ │ ├── ResourceManager.LoadType.cs │ │ ├── ResourceManager.ReadWriteResourceInfo.cs │ │ ├── ResourceManager.ResourceChecker.CheckInfo.CheckStatus.cs │ │ ├── ResourceManager.ResourceChecker.CheckInfo.LocalVersionInfo.cs │ │ ├── ResourceManager.ResourceChecker.CheckInfo.RemoteVersionInfo.cs │ │ ├── ResourceManager.ResourceChecker.CheckInfo.cs │ │ ├── ResourceManager.ResourceChecker.cs │ │ ├── ResourceManager.ResourceGroup.cs │ │ ├── ResourceManager.ResourceGroupCollection.cs │ │ ├── ResourceManager.ResourceInfo.cs │ │ ├── ResourceManager.ResourceIniter.cs │ │ ├── ResourceManager.ResourceLoader.AssetObject.cs │ │ ├── ResourceManager.ResourceLoader.LoadAssetTask.cs │ │ ├── ResourceManager.ResourceLoader.LoadBinaryInfo.cs │ │ ├── ResourceManager.ResourceLoader.LoadDependencyAssetTask.cs │ │ ├── ResourceManager.ResourceLoader.LoadResourceAgent.cs │ │ ├── ResourceManager.ResourceLoader.LoadResourceTaskBase.cs │ │ ├── ResourceManager.ResourceLoader.LoadSceneTask.cs │ │ ├── ResourceManager.ResourceLoader.ResourceObject.cs │ │ ├── ResourceManager.ResourceLoader.cs │ │ ├── ResourceManager.ResourceName.cs │ │ ├── ResourceManager.ResourceNameComparer.cs │ │ ├── ResourceManager.ResourceUpdater.ApplyInfo.cs │ │ ├── ResourceManager.ResourceUpdater.UpdateInfo.cs │ │ ├── ResourceManager.ResourceUpdater.cs │ │ ├── ResourceManager.ResourceVerifier.VerifyInfo.cs │ │ ├── ResourceManager.ResourceVerifier.cs │ │ ├── ResourceManager.VersionListProcessor.cs │ │ ├── ResourceManager.cs │ │ ├── ResourceMode.cs │ │ ├── ResourcePackVersionList.Resource.cs │ │ ├── ResourcePackVersionList.cs │ │ ├── ResourcePackVersionListSerializer.cs │ │ ├── ResourceUpdateAllCompleteEventArgs.cs │ │ ├── ResourceUpdateChangedEventArgs.cs │ │ ├── ResourceUpdateFailureEventArgs.cs │ │ ├── ResourceUpdateStartEventArgs.cs │ │ ├── ResourceUpdateSuccessEventArgs.cs │ │ ├── ResourceVerifyFailureEventArgs.cs │ │ ├── ResourceVerifyStartEventArgs.cs │ │ ├── ResourceVerifySuccessEventArgs.cs │ │ ├── UnloadSceneCallbacks.cs │ │ ├── UnloadSceneFailureCallback.cs │ │ ├── UnloadSceneSuccessCallback.cs │ │ ├── UpdatableVersionList.Asset.cs │ │ ├── UpdatableVersionList.FileSystem.cs │ │ ├── UpdatableVersionList.Resource.cs │ │ ├── UpdatableVersionList.ResourceGroup.cs │ │ ├── UpdatableVersionList.cs │ │ ├── UpdatableVersionListSerializer.cs │ │ ├── UpdateResourcesCompleteCallback.cs │ │ ├── UpdateVersionListCallbacks.cs │ │ ├── UpdateVersionListFailureCallback.cs │ │ ├── UpdateVersionListSuccessCallback.cs │ │ └── VerifyResourcesCompleteCallback.cs │ ├── Scene/ │ │ ├── ISceneManager.cs │ │ ├── LoadSceneDependencyAssetEventArgs.cs │ │ ├── LoadSceneFailureEventArgs.cs │ │ ├── LoadSceneSuccessEventArgs.cs │ │ ├── LoadSceneUpdateEventArgs.cs │ │ ├── SceneManager.cs │ │ ├── UnloadSceneFailureEventArgs.cs │ │ └── UnloadSceneSuccessEventArgs.cs │ ├── Setting/ │ │ ├── ISettingHelper.cs │ │ ├── ISettingManager.cs │ │ └── SettingManager.cs │ ├── Sound/ │ │ ├── Constant.cs │ │ ├── ISoundAgent.cs │ │ ├── ISoundAgentHelper.cs │ │ ├── ISoundGroup.cs │ │ ├── ISoundGroupHelper.cs │ │ ├── ISoundHelper.cs │ │ ├── ISoundManager.cs │ │ ├── PlaySoundDependencyAssetEventArgs.cs │ │ ├── PlaySoundErrorCode.cs │ │ ├── PlaySoundFailureEventArgs.cs │ │ ├── PlaySoundParams.cs │ │ ├── PlaySoundSuccessEventArgs.cs │ │ ├── PlaySoundUpdateEventArgs.cs │ │ ├── ResetSoundAgentEventArgs.cs │ │ ├── SoundManager.PlaySoundInfo.cs │ │ ├── SoundManager.SoundAgent.cs │ │ ├── SoundManager.SoundGroup.cs │ │ └── SoundManager.cs │ ├── UI/ │ │ ├── CloseUIFormCompleteEventArgs.cs │ │ ├── IUIForm.cs │ │ ├── IUIFormHelper.cs │ │ ├── IUIGroup.cs │ │ ├── IUIGroupHelper.cs │ │ ├── IUIManager.cs │ │ ├── OpenUIFormDependencyAssetEventArgs.cs │ │ ├── OpenUIFormFailureEventArgs.cs │ │ ├── OpenUIFormSuccessEventArgs.cs │ │ ├── OpenUIFormUpdateEventArgs.cs │ │ ├── UIManager.OpenUIFormInfo.cs │ │ ├── UIManager.UIFormInstanceObject.cs │ │ ├── UIManager.UIGroup.UIFormInfo.cs │ │ ├── UIManager.UIGroup.cs │ │ └── UIManager.cs │ ├── Utility/ │ │ ├── Utility.Assembly.cs │ │ ├── Utility.Compression.ICompressionHelper.cs │ │ ├── Utility.Compression.cs │ │ ├── Utility.Converter.cs │ │ ├── Utility.Encryption.cs │ │ ├── Utility.Json.IJsonHelper.cs │ │ ├── Utility.Json.cs │ │ ├── Utility.Marshal.cs │ │ ├── Utility.Path.cs │ │ ├── Utility.Random.cs │ │ ├── Utility.Text.ITextHelper.cs │ │ ├── Utility.Text.cs │ │ ├── Utility.Verifier.Crc32.cs │ │ ├── Utility.Verifier.cs │ │ └── Utility.cs │ └── WebRequest/ │ ├── Constant.cs │ ├── IWebRequestAgentHelper.cs │ ├── IWebRequestManager.cs │ ├── WebRequestAgentHelperCompleteEventArgs.cs │ ├── WebRequestAgentHelperErrorEventArgs.cs │ ├── WebRequestFailureEventArgs.cs │ ├── WebRequestManager.WebRequestAgent.cs │ ├── WebRequestManager.WebRequestTask.cs │ ├── WebRequestManager.WebRequestTaskStatus.cs │ ├── WebRequestManager.cs │ ├── WebRequestStartEventArgs.cs │ └── WebRequestSuccessEventArgs.cs ├── GameFramework.sln ├── LICENSE.md └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ build/ bld/ [Bb]in/ [Oo]bj/ # Visual Studio 2015 cache/options directory .vs/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # DNX project.lock.json artifacts/ *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch _NCrunch_* .*crunch*.local.xml # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml ## TODO: Comment the next line if you want to checkin your ## web deploy settings but do note that will include unencrypted ## passwords #*.pubxml *.publishproj # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # Windows Azure Build Output csx/ *.build.csdef # Windows Store app package directory AppPackages/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview *.pfx *.publishsettings node_modules/ orleans.codegen.cs # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files *.mdf *.ldf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # Node.js Tools for Visual Studio .ntvs_analysis.dat # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # LightSwitch generated files GeneratedArtifacts/ _Pvt_Extensions/ ModelManifest.xml ================================================ FILE: GameFramework/Base/DataProvider/DataProvider.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; using System; namespace GameFramework { /// /// 数据提供者。 /// /// 数据提供者的持有者的类型。 internal sealed class DataProvider : IDataProvider { private const int BlockSize = 1024 * 4; private static byte[] s_CachedBytes = null; private readonly T m_Owner; private readonly LoadAssetCallbacks m_LoadAssetCallbacks; private readonly LoadBinaryCallbacks m_LoadBinaryCallbacks; private IResourceManager m_ResourceManager; private IDataProviderHelper m_DataProviderHelper; private EventHandler m_ReadDataSuccessEventHandler; private EventHandler m_ReadDataFailureEventHandler; private EventHandler m_ReadDataUpdateEventHandler; private EventHandler m_ReadDataDependencyAssetEventHandler; /// /// 初始化数据提供者的新实例。 /// /// 数据提供者的持有者。 public DataProvider(T owner) { m_Owner = owner; m_LoadAssetCallbacks = new LoadAssetCallbacks(LoadAssetSuccessCallback, LoadAssetOrBinaryFailureCallback, LoadAssetUpdateCallback, LoadAssetDependencyAssetCallback); m_LoadBinaryCallbacks = new LoadBinaryCallbacks(LoadBinarySuccessCallback, LoadAssetOrBinaryFailureCallback); m_ResourceManager = null; m_DataProviderHelper = null; m_ReadDataSuccessEventHandler = null; m_ReadDataFailureEventHandler = null; m_ReadDataUpdateEventHandler = null; m_ReadDataDependencyAssetEventHandler = null; } /// /// 获取缓冲二进制流的大小。 /// public static int CachedBytesSize { get { return s_CachedBytes != null ? s_CachedBytes.Length : 0; } } /// /// 读取数据成功事件。 /// public event EventHandler ReadDataSuccess { add { m_ReadDataSuccessEventHandler += value; } remove { m_ReadDataSuccessEventHandler -= value; } } /// /// 读取数据失败事件。 /// public event EventHandler ReadDataFailure { add { m_ReadDataFailureEventHandler += value; } remove { m_ReadDataFailureEventHandler -= value; } } /// /// 读取数据更新事件。 /// public event EventHandler ReadDataUpdate { add { m_ReadDataUpdateEventHandler += value; } remove { m_ReadDataUpdateEventHandler -= value; } } /// /// 读取数据时加载依赖资源事件。 /// public event EventHandler ReadDataDependencyAsset { add { m_ReadDataDependencyAssetEventHandler += value; } remove { m_ReadDataDependencyAssetEventHandler -= value; } } /// /// 确保二进制流缓存分配足够大小的内存并缓存。 /// /// 要确保二进制流缓存分配内存的大小。 public static void EnsureCachedBytesSize(int ensureSize) { if (ensureSize < 0) { throw new GameFrameworkException("Ensure size is invalid."); } if (s_CachedBytes == null || s_CachedBytes.Length < ensureSize) { FreeCachedBytes(); int size = (ensureSize - 1 + BlockSize) / BlockSize * BlockSize; s_CachedBytes = new byte[size]; } } /// /// 释放缓存的二进制流。 /// public static void FreeCachedBytes() { s_CachedBytes = null; } /// /// 读取数据。 /// /// 内容资源名称。 public void ReadData(string dataAssetName) { ReadData(dataAssetName, Constant.DefaultPriority, null); } /// /// 读取数据。 /// /// 内容资源名称。 /// 加载数据资源的优先级。 public void ReadData(string dataAssetName, int priority) { ReadData(dataAssetName, priority, null); } /// /// 读取数据。 /// /// 内容资源名称。 /// 用户自定义数据。 public void ReadData(string dataAssetName, object userData) { ReadData(dataAssetName, Constant.DefaultPriority, userData); } /// /// 读取数据。 /// /// 内容资源名称。 /// 加载数据资源的优先级。 /// 用户自定义数据。 public void ReadData(string dataAssetName, int priority, object userData) { if (m_ResourceManager == null) { throw new GameFrameworkException("You must set resource manager first."); } if (m_DataProviderHelper == null) { throw new GameFrameworkException("You must set data provider helper first."); } HasAssetResult result = m_ResourceManager.HasAsset(dataAssetName); switch (result) { case HasAssetResult.AssetOnDisk: case HasAssetResult.AssetOnFileSystem: m_ResourceManager.LoadAsset(dataAssetName, priority, m_LoadAssetCallbacks, userData); break; case HasAssetResult.BinaryOnDisk: m_ResourceManager.LoadBinary(dataAssetName, m_LoadBinaryCallbacks, userData); break; case HasAssetResult.BinaryOnFileSystem: int dataLength = m_ResourceManager.GetBinaryLength(dataAssetName); EnsureCachedBytesSize(dataLength); if (dataLength != m_ResourceManager.LoadBinaryFromFileSystem(dataAssetName, s_CachedBytes)) { throw new GameFrameworkException(Utility.Text.Format("Load binary '{0}' from file system with internal error.", dataAssetName)); } try { if (!m_DataProviderHelper.ReadData(m_Owner, dataAssetName, s_CachedBytes, 0, dataLength, userData)) { throw new GameFrameworkException(Utility.Text.Format("Load data failure in data provider helper, data asset name '{0}'.", dataAssetName)); } if (m_ReadDataSuccessEventHandler != null) { ReadDataSuccessEventArgs loadDataSuccessEventArgs = ReadDataSuccessEventArgs.Create(dataAssetName, 0f, userData); m_ReadDataSuccessEventHandler(this, loadDataSuccessEventArgs); ReferencePool.Release(loadDataSuccessEventArgs); } } catch (Exception exception) { if (m_ReadDataFailureEventHandler != null) { ReadDataFailureEventArgs loadDataFailureEventArgs = ReadDataFailureEventArgs.Create(dataAssetName, exception.ToString(), userData); m_ReadDataFailureEventHandler(this, loadDataFailureEventArgs); ReferencePool.Release(loadDataFailureEventArgs); return; } throw; } break; default: throw new GameFrameworkException(Utility.Text.Format("Data asset '{0}' is '{1}'.", dataAssetName, result)); } } /// /// 解析内容。 /// /// 要解析的内容字符串。 /// 是否解析内容成功。 public bool ParseData(string dataString) { return ParseData(dataString, null); } /// /// 解析内容。 /// /// 要解析的内容字符串。 /// 用户自定义数据。 /// 是否解析内容成功。 public bool ParseData(string dataString, object userData) { if (m_DataProviderHelper == null) { throw new GameFrameworkException("You must set data helper first."); } if (dataString == null) { throw new GameFrameworkException("Data string is invalid."); } try { return m_DataProviderHelper.ParseData(m_Owner, dataString, userData); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Utility.Text.Format("Can not parse data string with exception '{0}'.", exception), exception); } } /// /// 解析内容。 /// /// 要解析的内容二进制流。 /// 是否解析内容成功。 public bool ParseData(byte[] dataBytes) { if (dataBytes == null) { throw new GameFrameworkException("Data bytes is invalid."); } return ParseData(dataBytes, 0, dataBytes.Length, null); } /// /// 解析内容。 /// /// 要解析的内容二进制流。 /// 用户自定义数据。 /// 是否解析内容成功。 public bool ParseData(byte[] dataBytes, object userData) { if (dataBytes == null) { throw new GameFrameworkException("Data bytes is invalid."); } return ParseData(dataBytes, 0, dataBytes.Length, userData); } /// /// 解析内容。 /// /// 要解析的内容二进制流。 /// 内容二进制流的起始位置。 /// 内容二进制流的长度。 /// 是否解析内容成功。 public bool ParseData(byte[] dataBytes, int startIndex, int length) { return ParseData(dataBytes, startIndex, length, null); } /// /// 解析内容。 /// /// 要解析的内容二进制流。 /// 内容二进制流的起始位置。 /// 内容二进制流的长度。 /// 用户自定义数据。 /// 是否解析内容成功。 public bool ParseData(byte[] dataBytes, int startIndex, int length, object userData) { if (m_DataProviderHelper == null) { throw new GameFrameworkException("You must set data helper first."); } if (dataBytes == null) { throw new GameFrameworkException("Data bytes is invalid."); } if (startIndex < 0 || length < 0 || startIndex + length > dataBytes.Length) { throw new GameFrameworkException("Start index or length is invalid."); } try { return m_DataProviderHelper.ParseData(m_Owner, dataBytes, startIndex, length, userData); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Utility.Text.Format("Can not parse data bytes with exception '{0}'.", exception), exception); } } /// /// 设置资源管理器。 /// /// 资源管理器。 internal void SetResourceManager(IResourceManager resourceManager) { if (resourceManager == null) { throw new GameFrameworkException("Resource manager is invalid."); } m_ResourceManager = resourceManager; } /// /// 设置数据提供者辅助器。 /// /// 数据提供者辅助器。 internal void SetDataProviderHelper(IDataProviderHelper dataProviderHelper) { if (dataProviderHelper == null) { throw new GameFrameworkException("Data provider helper is invalid."); } m_DataProviderHelper = dataProviderHelper; } private void LoadAssetSuccessCallback(string dataAssetName, object dataAsset, float duration, object userData) { try { if (!m_DataProviderHelper.ReadData(m_Owner, dataAssetName, dataAsset, userData)) { throw new GameFrameworkException(Utility.Text.Format("Load data failure in data provider helper, data asset name '{0}'.", dataAssetName)); } if (m_ReadDataSuccessEventHandler != null) { ReadDataSuccessEventArgs loadDataSuccessEventArgs = ReadDataSuccessEventArgs.Create(dataAssetName, duration, userData); m_ReadDataSuccessEventHandler(this, loadDataSuccessEventArgs); ReferencePool.Release(loadDataSuccessEventArgs); } } catch (Exception exception) { if (m_ReadDataFailureEventHandler != null) { ReadDataFailureEventArgs loadDataFailureEventArgs = ReadDataFailureEventArgs.Create(dataAssetName, exception.ToString(), userData); m_ReadDataFailureEventHandler(this, loadDataFailureEventArgs); ReferencePool.Release(loadDataFailureEventArgs); return; } throw; } finally { m_DataProviderHelper.ReleaseDataAsset(m_Owner, dataAsset); } } private void LoadAssetOrBinaryFailureCallback(string dataAssetName, LoadResourceStatus status, string errorMessage, object userData) { string appendErrorMessage = Utility.Text.Format("Load data failure, data asset name '{0}', status '{1}', error message '{2}'.", dataAssetName, status, errorMessage); if (m_ReadDataFailureEventHandler != null) { ReadDataFailureEventArgs loadDataFailureEventArgs = ReadDataFailureEventArgs.Create(dataAssetName, appendErrorMessage, userData); m_ReadDataFailureEventHandler(this, loadDataFailureEventArgs); ReferencePool.Release(loadDataFailureEventArgs); return; } throw new GameFrameworkException(appendErrorMessage); } private void LoadAssetUpdateCallback(string dataAssetName, float progress, object userData) { if (m_ReadDataUpdateEventHandler != null) { ReadDataUpdateEventArgs loadDataUpdateEventArgs = ReadDataUpdateEventArgs.Create(dataAssetName, progress, userData); m_ReadDataUpdateEventHandler(this, loadDataUpdateEventArgs); ReferencePool.Release(loadDataUpdateEventArgs); } } private void LoadAssetDependencyAssetCallback(string dataAssetName, string dependencyAssetName, int loadedCount, int totalCount, object userData) { if (m_ReadDataDependencyAssetEventHandler != null) { ReadDataDependencyAssetEventArgs loadDataDependencyAssetEventArgs = ReadDataDependencyAssetEventArgs.Create(dataAssetName, dependencyAssetName, loadedCount, totalCount, userData); m_ReadDataDependencyAssetEventHandler(this, loadDataDependencyAssetEventArgs); ReferencePool.Release(loadDataDependencyAssetEventArgs); } } private void LoadBinarySuccessCallback(string dataAssetName, byte[] dataBytes, float duration, object userData) { try { if (!m_DataProviderHelper.ReadData(m_Owner, dataAssetName, dataBytes, 0, dataBytes.Length, userData)) { throw new GameFrameworkException(Utility.Text.Format("Load data failure in data provider helper, data asset name '{0}'.", dataAssetName)); } if (m_ReadDataSuccessEventHandler != null) { ReadDataSuccessEventArgs loadDataSuccessEventArgs = ReadDataSuccessEventArgs.Create(dataAssetName, duration, userData); m_ReadDataSuccessEventHandler(this, loadDataSuccessEventArgs); ReferencePool.Release(loadDataSuccessEventArgs); } } catch (Exception exception) { if (m_ReadDataFailureEventHandler != null) { ReadDataFailureEventArgs loadDataFailureEventArgs = ReadDataFailureEventArgs.Create(dataAssetName, exception.ToString(), userData); m_ReadDataFailureEventHandler(this, loadDataFailureEventArgs); ReferencePool.Release(loadDataFailureEventArgs); return; } throw; } } } } ================================================ FILE: GameFramework/Base/DataProvider/DataProviderCreator.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; namespace GameFramework { /// /// 数据提供者创建器。 /// public static class DataProviderCreator { /// /// 获取缓冲二进制流的大小。 /// /// 数据提供者的持有者的类型。 /// 缓冲二进制流的大小。 public static int GetCachedBytesSize() { return DataProvider.CachedBytesSize; } /// /// 确保二进制流缓存分配足够大小的内存并缓存。 /// /// 数据提供者的持有者的类型。 /// 要确保二进制流缓存分配内存的大小。 public static void EnsureCachedBytesSize(int ensureSize) { DataProvider.EnsureCachedBytesSize(ensureSize); } /// /// 释放缓存的二进制流。 /// /// 数据提供者的持有者的类型。 public static void FreeCachedBytes() { DataProvider.FreeCachedBytes(); } /// /// 创建数据提供者。 /// /// 数据提供者的持有者的类型。 /// 数据提供者的持有者。 /// 资源管理器。 /// 数据提供者辅助器。 /// 创建的数据提供者。 public static IDataProvider Create(T owner, IResourceManager resourceManager, IDataProviderHelper dataProviderHelper) { if (owner == null) { throw new GameFrameworkException("Owner is invalid."); } if (resourceManager == null) { throw new GameFrameworkException("Resource manager is invalid."); } if (dataProviderHelper == null) { throw new GameFrameworkException("Data provider helper is invalid."); } DataProvider dataProvider = new DataProvider(owner); dataProvider.SetResourceManager(resourceManager); dataProvider.SetDataProviderHelper(dataProviderHelper); return dataProvider; } } } ================================================ FILE: GameFramework/Base/DataProvider/IDataProvider.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework { /// /// 数据提供者接口。 /// /// 数据提供者的持有者的类型。 public interface IDataProvider { /// /// 读取数据成功事件。 /// event EventHandler ReadDataSuccess; /// /// 读取数据失败事件。 /// event EventHandler ReadDataFailure; /// /// 读取数据更新事件。 /// event EventHandler ReadDataUpdate; /// /// 读取数据时加载依赖资源事件。 /// event EventHandler ReadDataDependencyAsset; /// /// 读取数据。 /// /// 内容资源名称。 void ReadData(string dataAssetName); /// /// 读取数据。 /// /// 内容资源名称。 /// 加载数据资源的优先级。 void ReadData(string dataAssetName, int priority); /// /// 读取数据。 /// /// 内容资源名称。 /// 用户自定义数据。 void ReadData(string dataAssetName, object userData); /// /// 读取数据。 /// /// 内容资源名称。 /// 加载数据资源的优先级。 /// 用户自定义数据。 void ReadData(string dataAssetName, int priority, object userData); /// /// 解析内容。 /// /// 要解析的内容字符串。 /// 是否解析内容成功。 bool ParseData(string dataString); /// /// 解析内容。 /// /// 要解析的内容字符串。 /// 用户自定义数据。 /// 是否解析内容成功。 bool ParseData(string dataString, object userData); /// /// 解析内容。 /// /// 要解析的内容二进制流。 /// 是否解析内容成功。 bool ParseData(byte[] dataBytes); /// /// 解析内容。 /// /// 要解析的内容二进制流。 /// 用户自定义数据。 /// 是否解析内容成功。 bool ParseData(byte[] dataBytes, object userData); /// /// 解析内容。 /// /// 要解析的内容二进制流。 /// 内容二进制流的起始位置。 /// 内容二进制流的长度。 /// 是否解析内容成功。 bool ParseData(byte[] dataBytes, int startIndex, int length); /// /// 解析内容。 /// /// 要解析的内容二进制流。 /// 内容二进制流的起始位置。 /// 内容二进制流的长度。 /// 用户自定义数据。 /// 是否解析内容成功。 bool ParseData(byte[] dataBytes, int startIndex, int length, object userData); } } ================================================ FILE: GameFramework/Base/DataProvider/IDataProviderHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 数据提供者辅助器接口。 /// public interface IDataProviderHelper { /// /// 读取数据。 /// /// 数据提供者的持有者。 /// 内容资源名称。 /// 内容资源。 /// 用户自定义数据。 /// 是否读取数据成功。 bool ReadData(T dataProviderOwner, string dataAssetName, object dataAsset, object userData); /// /// 读取数据。 /// /// 数据提供者的持有者。 /// 内容资源名称。 /// 内容二进制流。 /// 内容二进制流的起始位置。 /// 内容二进制流的长度。 /// 用户自定义数据。 /// 是否读取数据成功。 bool ReadData(T dataProviderOwner, string dataAssetName, byte[] dataBytes, int startIndex, int length, object userData); /// /// 解析内容。 /// /// 数据提供者的持有者。 /// 要解析的内容字符串。 /// 用户自定义数据。 /// 是否解析内容成功。 bool ParseData(T dataProviderOwner, string dataString, object userData); /// /// 解析内容。 /// /// 数据提供者的持有者。 /// 要解析的内容二进制流。 /// 内容二进制流的起始位置。 /// 内容二进制流的长度。 /// 用户自定义数据。 /// 是否解析内容成功。 bool ParseData(T dataProviderOwner, byte[] dataBytes, int startIndex, int length, object userData); /// /// 释放内容资源。 /// /// 数据提供者的持有者。 /// 要释放的内容资源。 void ReleaseDataAsset(T dataProviderOwner, object dataAsset); } } ================================================ FILE: GameFramework/Base/DataProvider/ReadDataDependencyAssetEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 读取数据时加载依赖资源事件。 /// public sealed class ReadDataDependencyAssetEventArgs : GameFrameworkEventArgs { /// /// 初始化读取数据时加载依赖资源事件的新实例。 /// public ReadDataDependencyAssetEventArgs() { DataAssetName = null; DependencyAssetName = null; LoadedCount = 0; TotalCount = 0; UserData = null; } /// /// 获取内容资源名称。 /// public string DataAssetName { get; private set; } /// /// 获取被加载的依赖资源名称。 /// public string DependencyAssetName { get; private set; } /// /// 获取当前已加载依赖资源数量。 /// public int LoadedCount { get; private set; } /// /// 获取总共加载依赖资源数量。 /// public int TotalCount { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建读取数据时加载依赖资源事件。 /// /// 内容资源名称。 /// 被加载的依赖资源名称。 /// 当前已加载依赖资源数量。 /// 总共加载依赖资源数量。 /// 用户自定义数据。 /// 创建的读取数据时加载依赖资源事件。 public static ReadDataDependencyAssetEventArgs Create(string dataAssetName, string dependencyAssetName, int loadedCount, int totalCount, object userData) { ReadDataDependencyAssetEventArgs loadDataDependencyAssetEventArgs = ReferencePool.Acquire(); loadDataDependencyAssetEventArgs.DataAssetName = dataAssetName; loadDataDependencyAssetEventArgs.DependencyAssetName = dependencyAssetName; loadDataDependencyAssetEventArgs.LoadedCount = loadedCount; loadDataDependencyAssetEventArgs.TotalCount = totalCount; loadDataDependencyAssetEventArgs.UserData = userData; return loadDataDependencyAssetEventArgs; } /// /// 清理读取数据时加载依赖资源事件。 /// public override void Clear() { DataAssetName = null; DependencyAssetName = null; LoadedCount = 0; TotalCount = 0; UserData = null; } } } ================================================ FILE: GameFramework/Base/DataProvider/ReadDataFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 读取数据失败事件。 /// public sealed class ReadDataFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化读取数据失败事件的新实例。 /// public ReadDataFailureEventArgs() { DataAssetName = null; ErrorMessage = null; UserData = null; } /// /// 获取内容资源名称。 /// public string DataAssetName { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建读取数据失败事件。 /// /// 内容资源名称。 /// 错误信息。 /// 用户自定义数据。 /// 创建的读取数据失败事件。 public static ReadDataFailureEventArgs Create(string dataAssetName, string errorMessage, object userData) { ReadDataFailureEventArgs loadDataFailureEventArgs = ReferencePool.Acquire(); loadDataFailureEventArgs.DataAssetName = dataAssetName; loadDataFailureEventArgs.ErrorMessage = errorMessage; loadDataFailureEventArgs.UserData = userData; return loadDataFailureEventArgs; } /// /// 清理读取数据失败事件。 /// public override void Clear() { DataAssetName = null; ErrorMessage = null; UserData = null; } } } ================================================ FILE: GameFramework/Base/DataProvider/ReadDataSuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 读取数据成功事件。 /// public sealed class ReadDataSuccessEventArgs : GameFrameworkEventArgs { /// /// 初始化读取数据成功事件的新实例。 /// public ReadDataSuccessEventArgs() { DataAssetName = null; Duration = 0f; UserData = null; } /// /// 获取内容资源名称。 /// public string DataAssetName { get; private set; } /// /// 获取加载持续时间。 /// public float Duration { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建读取数据成功事件。 /// /// 内容资源名称。 /// 加载持续时间。 /// 用户自定义数据。 /// 创建的读取数据成功事件。 public static ReadDataSuccessEventArgs Create(string dataAssetName, float duration, object userData) { ReadDataSuccessEventArgs loadDataSuccessEventArgs = ReferencePool.Acquire(); loadDataSuccessEventArgs.DataAssetName = dataAssetName; loadDataSuccessEventArgs.Duration = duration; loadDataSuccessEventArgs.UserData = userData; return loadDataSuccessEventArgs; } /// /// 清理读取数据成功事件。 /// public override void Clear() { DataAssetName = null; Duration = 0f; UserData = null; } } } ================================================ FILE: GameFramework/Base/DataProvider/ReadDataUpdateEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 读取数据更新事件。 /// public sealed class ReadDataUpdateEventArgs : GameFrameworkEventArgs { /// /// 初始化读取数据更新事件的新实例。 /// public ReadDataUpdateEventArgs() { DataAssetName = null; Progress = 0f; UserData = null; } /// /// 获取内容资源名称。 /// public string DataAssetName { get; private set; } /// /// 获取读取数据进度。 /// public float Progress { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建读取数据更新事件。 /// /// 内容资源名称。 /// 读取数据进度。 /// 用户自定义数据。 /// 创建的读取数据更新事件。 public static ReadDataUpdateEventArgs Create(string dataAssetName, float progress, object userData) { ReadDataUpdateEventArgs loadDataUpdateEventArgs = ReferencePool.Acquire(); loadDataUpdateEventArgs.DataAssetName = dataAssetName; loadDataUpdateEventArgs.Progress = progress; loadDataUpdateEventArgs.UserData = userData; return loadDataUpdateEventArgs; } /// /// 清理读取数据更新事件。 /// public override void Clear() { DataAssetName = null; Progress = 0f; UserData = null; } } } ================================================ FILE: GameFramework/Base/DataStruct/TypeNamePair.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Runtime.InteropServices; namespace GameFramework { /// /// 类型和名称的组合值。 /// [StructLayout(LayoutKind.Auto)] internal struct TypeNamePair : IEquatable { private readonly Type m_Type; private readonly string m_Name; /// /// 初始化类型和名称的组合值的新实例。 /// /// 类型。 public TypeNamePair(Type type) : this(type, string.Empty) { } /// /// 初始化类型和名称的组合值的新实例。 /// /// 类型。 /// 名称。 public TypeNamePair(Type type, string name) { if (type == null) { throw new GameFrameworkException("Type is invalid."); } m_Type = type; m_Name = name ?? string.Empty; } /// /// 获取类型。 /// public Type Type { get { return m_Type; } } /// /// 获取名称。 /// public string Name { get { return m_Name; } } /// /// 获取类型和名称的组合值字符串。 /// /// 类型和名称的组合值字符串。 public override string ToString() { if (m_Type == null) { throw new GameFrameworkException("Type is invalid."); } string typeName = m_Type.FullName; return string.IsNullOrEmpty(m_Name) ? typeName : Utility.Text.Format("{0}.{1}", typeName, m_Name); } /// /// 获取对象的哈希值。 /// /// 对象的哈希值。 public override int GetHashCode() { return m_Type.GetHashCode() ^ m_Name.GetHashCode(); } /// /// 比较对象是否与自身相等。 /// /// 要比较的对象。 /// 被比较的对象是否与自身相等。 public override bool Equals(object obj) { return obj is TypeNamePair && Equals((TypeNamePair)obj); } /// /// 比较对象是否与自身相等。 /// /// 要比较的对象。 /// 被比较的对象是否与自身相等。 public bool Equals(TypeNamePair value) { return m_Type == value.m_Type && m_Name == value.m_Name; } /// /// 判断两个对象是否相等。 /// /// 值 a。 /// 值 b。 /// 两个对象是否相等。 public static bool operator ==(TypeNamePair a, TypeNamePair b) { return a.Equals(b); } /// /// 判断两个对象是否不相等。 /// /// 值 a。 /// 值 b。 /// 两个对象是否不相等。 public static bool operator !=(TypeNamePair a, TypeNamePair b) { return !(a == b); } } } ================================================ FILE: GameFramework/Base/EventPool/BaseEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 事件基类。 /// public abstract class BaseEventArgs : GameFrameworkEventArgs { /// /// 获取类型编号。 /// public abstract int Id { get; } } } ================================================ FILE: GameFramework/Base/EventPool/EventPool.Event.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { internal sealed partial class EventPool where T : BaseEventArgs { /// /// 事件结点。 /// private sealed class Event : IReference { private object m_Sender; private T m_EventArgs; public Event() { m_Sender = null; m_EventArgs = null; } public object Sender { get { return m_Sender; } } public T EventArgs { get { return m_EventArgs; } } public static Event Create(object sender, T e) { Event eventNode = ReferencePool.Acquire(); eventNode.m_Sender = sender; eventNode.m_EventArgs = e; return eventNode; } public void Clear() { m_Sender = null; m_EventArgs = null; } } } } ================================================ FILE: GameFramework/Base/EventPool/EventPool.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework { /// /// 事件池。 /// /// 事件类型。 internal sealed partial class EventPool where T : BaseEventArgs { private readonly GameFrameworkMultiDictionary> m_EventHandlers; private readonly Queue m_Events; private readonly Dictionary>> m_CachedNodes; private readonly Dictionary>> m_TempNodes; private readonly EventPoolMode m_EventPoolMode; private EventHandler m_DefaultHandler; /// /// 初始化事件池的新实例。 /// /// 事件池模式。 public EventPool(EventPoolMode mode) { m_EventHandlers = new GameFrameworkMultiDictionary>(); m_Events = new Queue(); m_CachedNodes = new Dictionary>>(); m_TempNodes = new Dictionary>>(); m_EventPoolMode = mode; m_DefaultHandler = null; } /// /// 获取事件处理函数的数量。 /// public int EventHandlerCount { get { return m_EventHandlers.Count; } } /// /// 获取事件数量。 /// public int EventCount { get { return m_Events.Count; } } /// /// 事件池轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void Update(float elapseSeconds, float realElapseSeconds) { lock (m_Events) { while (m_Events.Count > 0) { Event eventNode = m_Events.Dequeue(); HandleEvent(eventNode.Sender, eventNode.EventArgs); ReferencePool.Release(eventNode); } } } /// /// 关闭并清理事件池。 /// public void Shutdown() { Clear(); m_EventHandlers.Clear(); m_CachedNodes.Clear(); m_TempNodes.Clear(); m_DefaultHandler = null; } /// /// 清理事件。 /// public void Clear() { lock (m_Events) { m_Events.Clear(); } } /// /// 获取事件处理函数的数量。 /// /// 事件类型编号。 /// 事件处理函数的数量。 public int Count(int id) { GameFrameworkLinkedListRange> range = default(GameFrameworkLinkedListRange>); if (m_EventHandlers.TryGetValue(id, out range)) { return range.Count; } return 0; } /// /// 检查是否存在事件处理函数。 /// /// 事件类型编号。 /// 要检查的事件处理函数。 /// 是否存在事件处理函数。 public bool Check(int id, EventHandler handler) { if (handler == null) { throw new GameFrameworkException("Event handler is invalid."); } return m_EventHandlers.Contains(id, handler); } /// /// 订阅事件处理函数。 /// /// 事件类型编号。 /// 要订阅的事件处理函数。 public void Subscribe(int id, EventHandler handler) { if (handler == null) { throw new GameFrameworkException("Event handler is invalid."); } if (!m_EventHandlers.Contains(id)) { m_EventHandlers.Add(id, handler); } else if ((m_EventPoolMode & EventPoolMode.AllowMultiHandler) != EventPoolMode.AllowMultiHandler) { throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow multi handler.", id)); } else if ((m_EventPoolMode & EventPoolMode.AllowDuplicateHandler) != EventPoolMode.AllowDuplicateHandler && Check(id, handler)) { throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow duplicate handler.", id)); } else { m_EventHandlers.Add(id, handler); } } /// /// 取消订阅事件处理函数。 /// /// 事件类型编号。 /// 要取消订阅的事件处理函数。 public void Unsubscribe(int id, EventHandler handler) { if (handler == null) { throw new GameFrameworkException("Event handler is invalid."); } if (m_CachedNodes.Count > 0) { foreach (KeyValuePair>> cachedNode in m_CachedNodes) { if (cachedNode.Value != null && cachedNode.Value.Value == handler) { m_TempNodes.Add(cachedNode.Key, cachedNode.Value.Next); } } if (m_TempNodes.Count > 0) { foreach (KeyValuePair>> cachedNode in m_TempNodes) { m_CachedNodes[cachedNode.Key] = cachedNode.Value; } m_TempNodes.Clear(); } } if (!m_EventHandlers.Remove(id, handler)) { throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not exists specified handler.", id)); } } /// /// 设置默认事件处理函数。 /// /// 要设置的默认事件处理函数。 public void SetDefaultHandler(EventHandler handler) { m_DefaultHandler = handler; } /// /// 抛出事件,这个操作是线程安全的,即使不在主线程中抛出,也可保证在主线程中回调事件处理函数,但事件会在抛出后的下一帧分发。 /// /// 事件源。 /// 事件参数。 public void Fire(object sender, T e) { if (e == null) { throw new GameFrameworkException("Event is invalid."); } Event eventNode = Event.Create(sender, e); lock (m_Events) { m_Events.Enqueue(eventNode); } } /// /// 抛出事件立即模式,这个操作不是线程安全的,事件会立刻分发。 /// /// 事件源。 /// 事件参数。 public void FireNow(object sender, T e) { if (e == null) { throw new GameFrameworkException("Event is invalid."); } HandleEvent(sender, e); } /// /// 处理事件结点。 /// /// 事件源。 /// 事件参数。 private void HandleEvent(object sender, T e) { bool noHandlerException = false; GameFrameworkLinkedListRange> range = default(GameFrameworkLinkedListRange>); if (m_EventHandlers.TryGetValue(e.Id, out range)) { LinkedListNode> current = range.First; while (current != null && current != range.Terminal) { m_CachedNodes[e] = current.Next != range.Terminal ? current.Next : null; current.Value(sender, e); current = m_CachedNodes[e]; } m_CachedNodes.Remove(e); } else if (m_DefaultHandler != null) { m_DefaultHandler(sender, e); } else if ((m_EventPoolMode & EventPoolMode.AllowNoHandler) == 0) { noHandlerException = true; } ReferencePool.Release(e); if (noHandlerException) { throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow no handler.", e.Id)); } } } } ================================================ FILE: GameFramework/Base/EventPool/EventPoolMode.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework { /// /// 事件池模式。 /// [Flags] internal enum EventPoolMode : byte { /// /// 默认事件池模式,即必须存在有且只有一个事件处理函数。 /// Default = 0, /// /// 允许不存在事件处理函数。 /// AllowNoHandler = 1, /// /// 允许存在多个事件处理函数。 /// AllowMultiHandler = 2, /// /// 允许存在重复的事件处理函数。 /// AllowDuplicateHandler = 4 } } ================================================ FILE: GameFramework/Base/GameFrameworkAction.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 封装一个方法,该方法不具有参数并且不返回值。 /// public delegate void GameFrameworkAction(); /// /// 封装一个方法,该方法只有一个参数并且不返回值。 /// /// 此委托封装的方法的参数类型。 /// 此委托封装的方法的参数。 public delegate void GameFrameworkAction(T obj); /// /// 封装一个方法,该方法具有两个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2); /// /// 封装一个方法,该方法具有三个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3); /// /// 封装一个方法,该方法具有四个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4); /// /// 封装一个方法,该方法具有五个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); /// /// 封装一个方法,该方法具有六个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); /// /// 封装一个方法,该方法具有七个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); /// /// 封装一个方法,该方法具有八个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); /// /// 封装一个方法,该方法具有九个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); /// /// 封装一个方法,该方法具有十个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); /// /// 封装一个方法,该方法具有十一个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); /// /// 封装一个方法,该方法具有十二个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第十二个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的第十二个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); /// /// 封装一个方法,该方法具有十三个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第十二个参数的类型。 /// 此委托封装的方法的第十三个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的第十二个参数。 /// 此委托封装的方法的第十三个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); /// /// 封装一个方法,该方法具有十四个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第十二个参数的类型。 /// 此委托封装的方法的第十三个参数的类型。 /// 此委托封装的方法的第十四个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的第十二个参数。 /// 此委托封装的方法的第十三个参数。 /// 此委托封装的方法的第十四个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); /// /// 封装一个方法,该方法具有十五个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第十二个参数的类型。 /// 此委托封装的方法的第十三个参数的类型。 /// 此委托封装的方法的第十四个参数的类型。 /// 此委托封装的方法的第十五个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的第十二个参数。 /// 此委托封装的方法的第十三个参数。 /// 此委托封装的方法的第十四个参数。 /// 此委托封装的方法的第十五个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); /// /// 封装一个方法,该方法具有十六个参数并且不返回值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第十二个参数的类型。 /// 此委托封装的方法的第十三个参数的类型。 /// 此委托封装的方法的第十四个参数的类型。 /// 此委托封装的方法的第十五个参数的类型。 /// 此委托封装的方法的第十六个参数的类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的第十二个参数。 /// 此委托封装的方法的第十三个参数。 /// 此委托封装的方法的第十四个参数。 /// 此委托封装的方法的第十五个参数。 /// 此委托封装的方法的第十六个参数。 public delegate void GameFrameworkAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); } ================================================ FILE: GameFramework/Base/GameFrameworkEntry.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework { /// /// 游戏框架入口。 /// public static class GameFrameworkEntry { private static readonly GameFrameworkLinkedList s_GameFrameworkModules = new GameFrameworkLinkedList(); /// /// 所有游戏框架模块轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public static void Update(float elapseSeconds, float realElapseSeconds) { foreach (GameFrameworkModule module in s_GameFrameworkModules) { module.Update(elapseSeconds, realElapseSeconds); } } /// /// 关闭并清理所有游戏框架模块。 /// public static void Shutdown() { for (LinkedListNode current = s_GameFrameworkModules.Last; current != null; current = current.Previous) { current.Value.Shutdown(); } s_GameFrameworkModules.Clear(); ReferencePool.ClearAll(); Utility.Marshal.FreeCachedHGlobal(); GameFrameworkLog.SetLogHelper(null); } /// /// 获取游戏框架模块。 /// /// 要获取的游戏框架模块类型。 /// 要获取的游戏框架模块。 /// 如果要获取的游戏框架模块不存在,则自动创建该游戏框架模块。 public static T GetModule() where T : class { Type interfaceType = typeof(T); if (!interfaceType.IsInterface) { throw new GameFrameworkException(Utility.Text.Format("You must get module by interface, but '{0}' is not.", interfaceType.FullName)); } if (!interfaceType.FullName.StartsWith("GameFramework.", StringComparison.Ordinal)) { throw new GameFrameworkException(Utility.Text.Format("You must get a Game Framework module, but '{0}' is not.", interfaceType.FullName)); } string moduleName = Utility.Text.Format("{0}.{1}", interfaceType.Namespace, interfaceType.Name.Substring(1)); Type moduleType = Type.GetType(moduleName); if (moduleType == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find Game Framework module type '{0}'.", moduleName)); } return GetModule(moduleType) as T; } /// /// 获取游戏框架模块。 /// /// 要获取的游戏框架模块类型。 /// 要获取的游戏框架模块。 /// 如果要获取的游戏框架模块不存在,则自动创建该游戏框架模块。 private static GameFrameworkModule GetModule(Type moduleType) { foreach (GameFrameworkModule module in s_GameFrameworkModules) { if (module.GetType() == moduleType) { return module; } } return CreateModule(moduleType); } /// /// 创建游戏框架模块。 /// /// 要创建的游戏框架模块类型。 /// 要创建的游戏框架模块。 private static GameFrameworkModule CreateModule(Type moduleType) { GameFrameworkModule module = (GameFrameworkModule)Activator.CreateInstance(moduleType); if (module == null) { throw new GameFrameworkException(Utility.Text.Format("Can not create module '{0}'.", moduleType.FullName)); } LinkedListNode current = s_GameFrameworkModules.First; while (current != null) { if (module.Priority > current.Value.Priority) { break; } current = current.Next; } if (current != null) { s_GameFrameworkModules.AddBefore(current, module); } else { s_GameFrameworkModules.AddLast(module); } return module; } } } ================================================ FILE: GameFramework/Base/GameFrameworkEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework { /// /// 游戏框架中包含事件数据的类的基类。 /// public abstract class GameFrameworkEventArgs : EventArgs, IReference { /// /// 初始化游戏框架中包含事件数据的类的新实例。 /// public GameFrameworkEventArgs() { } /// /// 清理引用。 /// public abstract void Clear(); } } ================================================ FILE: GameFramework/Base/GameFrameworkException.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Runtime.Serialization; namespace GameFramework { /// /// 游戏框架异常类。 /// [Serializable] public class GameFrameworkException : Exception { /// /// 初始化游戏框架异常类的新实例。 /// public GameFrameworkException() : base() { } /// /// 使用指定错误消息初始化游戏框架异常类的新实例。 /// /// 描述错误的消息。 public GameFrameworkException(string message) : base(message) { } /// /// 使用指定错误消息和对作为此异常原因的内部异常的引用来初始化游戏框架异常类的新实例。 /// /// 解释异常原因的错误消息。 /// 导致当前异常的异常。如果 innerException 参数不为空引用,则在处理内部异常的 catch 块中引发当前异常。 public GameFrameworkException(string message, Exception innerException) : base(message, innerException) { } /// /// 用序列化数据初始化游戏框架异常类的新实例。 /// /// 存有有关所引发异常的序列化的对象数据。 /// 包含有关源或目标的上下文信息。 protected GameFrameworkException(SerializationInfo info, StreamingContext context) : base(info, context) { } } } ================================================ FILE: GameFramework/Base/GameFrameworkFunc.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 封装一个方法,该方法不具有参数,但却返回 TResult 参数指定的类型的值。 /// /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(); /// /// 封装一个方法,该方法具有一个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的参数类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T arg); /// /// 封装一个方法,该方法具有两个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2); /// /// 封装一个方法,该方法具有三个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3); /// /// 封装一个方法,该方法具有四个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4); /// /// 封装一个方法,该方法具有五个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); /// /// 封装一个方法,该方法具有六个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); /// /// 封装一个方法,该方法具有七个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); /// /// 封装一个方法,该方法具有八个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); /// /// 封装一个方法,该方法具有九个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); /// /// 封装一个方法,该方法具有十个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); /// /// 封装一个方法,该方法具有十一个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); /// /// 封装一个方法,该方法具有十二个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第十二个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的第十二个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); /// /// 封装一个方法,该方法具有十三个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第十二个参数的类型。 /// 此委托封装的方法的第十三个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的第十二个参数。 /// 此委托封装的方法的第十三个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); /// /// 封装一个方法,该方法具有十四个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第十二个参数的类型。 /// 此委托封装的方法的第十三个参数的类型。 /// 此委托封装的方法的第十四个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的第十二个参数。 /// 此委托封装的方法的第十三个参数。 /// 此委托封装的方法的第十四个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); /// /// 封装一个方法,该方法具有十五个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第十二个参数的类型。 /// 此委托封装的方法的第十三个参数的类型。 /// 此委托封装的方法的第十四个参数的类型。 /// 此委托封装的方法的第十五个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的第十二个参数。 /// 此委托封装的方法的第十三个参数。 /// 此委托封装的方法的第十四个参数。 /// 此委托封装的方法的第十五个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); /// /// 封装一个方法,该方法具有十六个参数,并返回 TResult 参数所指定的类型的值。 /// /// 此委托封装的方法的第一个参数的类型。 /// 此委托封装的方法的第二个参数的类型。 /// 此委托封装的方法的第三个参数的类型。 /// 此委托封装的方法的第四个参数的类型。 /// 此委托封装的方法的第五个参数的类型。 /// 此委托封装的方法的第六个参数的类型。 /// 此委托封装的方法的第七个参数的类型。 /// 此委托封装的方法的第八个参数的类型。 /// 此委托封装的方法的第九个参数的类型。 /// 此委托封装的方法的第十个参数的类型。 /// 此委托封装的方法的第十一个参数的类型。 /// 此委托封装的方法的第十二个参数的类型。 /// 此委托封装的方法的第十三个参数的类型。 /// 此委托封装的方法的第十四个参数的类型。 /// 此委托封装的方法的第十五个参数的类型。 /// 此委托封装的方法的第十六个参数的类型。 /// 此委托封装的方法的返回值类型。 /// 此委托封装的方法的第一个参数。 /// 此委托封装的方法的第二个参数。 /// 此委托封装的方法的第三个参数。 /// 此委托封装的方法的第四个参数。 /// 此委托封装的方法的第五个参数。 /// 此委托封装的方法的第六个参数。 /// 此委托封装的方法的第七个参数。 /// 此委托封装的方法的第八个参数。 /// 此委托封装的方法的第九个参数。 /// 此委托封装的方法的第十个参数。 /// 此委托封装的方法的第十一个参数。 /// 此委托封装的方法的第十二个参数。 /// 此委托封装的方法的第十三个参数。 /// 此委托封装的方法的第十四个参数。 /// 此委托封装的方法的第十五个参数。 /// 此委托封装的方法的第十六个参数。 /// 此委托封装的方法的返回值。 public delegate TResult GameFrameworkFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); } ================================================ FILE: GameFramework/Base/GameFrameworkLinkedList.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; namespace GameFramework { /// /// 游戏框架链表类。 /// /// 指定链表的元素类型。 public sealed class GameFrameworkLinkedList : ICollection, IEnumerable, ICollection, IEnumerable { private readonly LinkedList m_LinkedList; private readonly Queue> m_CachedNodes; /// /// 初始化游戏框架链表类的新实例。 /// public GameFrameworkLinkedList() { m_LinkedList = new LinkedList(); m_CachedNodes = new Queue>(); } /// /// 获取链表中实际包含的结点数量。 /// public int Count { get { return m_LinkedList.Count; } } /// /// 获取链表结点缓存数量。 /// public int CachedNodeCount { get { return m_CachedNodes.Count; } } /// /// 获取链表的第一个结点。 /// public LinkedListNode First { get { return m_LinkedList.First; } } /// /// 获取链表的最后一个结点。 /// public LinkedListNode Last { get { return m_LinkedList.Last; } } /// /// 获取一个值,该值指示 ICollection`1 是否为只读。 /// public bool IsReadOnly { get { return ((ICollection)m_LinkedList).IsReadOnly; } } /// /// 获取可用于同步对 ICollection 的访问的对象。 /// public object SyncRoot { get { return ((ICollection)m_LinkedList).SyncRoot; } } /// /// 获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。 /// public bool IsSynchronized { get { return ((ICollection)m_LinkedList).IsSynchronized; } } /// /// 在链表中指定的现有结点后添加包含指定值的新结点。 /// /// 指定的现有结点。 /// 指定值。 /// 包含指定值的新结点。 public LinkedListNode AddAfter(LinkedListNode node, T value) { LinkedListNode newNode = AcquireNode(value); m_LinkedList.AddAfter(node, newNode); return newNode; } /// /// 在链表中指定的现有结点后添加指定的新结点。 /// /// 指定的现有结点。 /// 指定的新结点。 public void AddAfter(LinkedListNode node, LinkedListNode newNode) { m_LinkedList.AddAfter(node, newNode); } /// /// 在链表中指定的现有结点前添加包含指定值的新结点。 /// /// 指定的现有结点。 /// 指定值。 /// 包含指定值的新结点。 public LinkedListNode AddBefore(LinkedListNode node, T value) { LinkedListNode newNode = AcquireNode(value); m_LinkedList.AddBefore(node, newNode); return newNode; } /// /// 在链表中指定的现有结点前添加指定的新结点。 /// /// 指定的现有结点。 /// 指定的新结点。 public void AddBefore(LinkedListNode node, LinkedListNode newNode) { m_LinkedList.AddBefore(node, newNode); } /// /// 在链表的开头处添加包含指定值的新结点。 /// /// 指定值。 /// 包含指定值的新结点。 public LinkedListNode AddFirst(T value) { LinkedListNode node = AcquireNode(value); m_LinkedList.AddFirst(node); return node; } /// /// 在链表的开头处添加指定的新结点。 /// /// 指定的新结点。 public void AddFirst(LinkedListNode node) { m_LinkedList.AddFirst(node); } /// /// 在链表的结尾处添加包含指定值的新结点。 /// /// 指定值。 /// 包含指定值的新结点。 public LinkedListNode AddLast(T value) { LinkedListNode node = AcquireNode(value); m_LinkedList.AddLast(node); return node; } /// /// 在链表的结尾处添加指定的新结点。 /// /// 指定的新结点。 public void AddLast(LinkedListNode node) { m_LinkedList.AddLast(node); } /// /// 从链表中移除所有结点。 /// public void Clear() { LinkedListNode current = m_LinkedList.First; while (current != null) { ReleaseNode(current); current = current.Next; } m_LinkedList.Clear(); } /// /// 清除链表结点缓存。 /// public void ClearCachedNodes() { m_CachedNodes.Clear(); } /// /// 确定某值是否在链表中。 /// /// 指定值。 /// 某值是否在链表中。 public bool Contains(T value) { return m_LinkedList.Contains(value); } /// /// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组。 /// /// 一维数组,它是从链表复制的元素的目标。数组必须具有从零开始的索引。 /// array 中从零开始的索引,从此处开始复制。 public void CopyTo(T[] array, int index) { m_LinkedList.CopyTo(array, index); } /// /// 从特定的 ICollection 索引开始,将数组的元素复制到一个数组中。 /// /// 一维数组,它是从 ICollection 复制的元素的目标。数组必须具有从零开始的索引。 /// array 中从零开始的索引,从此处开始复制。 public void CopyTo(Array array, int index) { ((ICollection)m_LinkedList).CopyTo(array, index); } /// /// 查找包含指定值的第一个结点。 /// /// 要查找的指定值。 /// 包含指定值的第一个结点。 public LinkedListNode Find(T value) { return m_LinkedList.Find(value); } /// /// 查找包含指定值的最后一个结点。 /// /// 要查找的指定值。 /// 包含指定值的最后一个结点。 public LinkedListNode FindLast(T value) { return m_LinkedList.FindLast(value); } /// /// 从链表中移除指定值的第一个匹配项。 /// /// 指定值。 /// 是否移除成功。 public bool Remove(T value) { LinkedListNode node = m_LinkedList.Find(value); if (node != null) { m_LinkedList.Remove(node); ReleaseNode(node); return true; } return false; } /// /// 从链表中移除指定的结点。 /// /// 指定的结点。 public void Remove(LinkedListNode node) { m_LinkedList.Remove(node); ReleaseNode(node); } /// /// 移除位于链表开头处的结点。 /// public void RemoveFirst() { LinkedListNode first = m_LinkedList.First; if (first == null) { throw new GameFrameworkException("First is invalid."); } m_LinkedList.RemoveFirst(); ReleaseNode(first); } /// /// 移除位于链表结尾处的结点。 /// public void RemoveLast() { LinkedListNode last = m_LinkedList.Last; if (last == null) { throw new GameFrameworkException("Last is invalid."); } m_LinkedList.RemoveLast(); ReleaseNode(last); } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 public Enumerator GetEnumerator() { return new Enumerator(m_LinkedList); } private LinkedListNode AcquireNode(T value) { LinkedListNode node = null; if (m_CachedNodes.Count > 0) { node = m_CachedNodes.Dequeue(); node.Value = value; } else { node = new LinkedListNode(value); } return node; } private void ReleaseNode(LinkedListNode node) { node.Value = default(T); m_CachedNodes.Enqueue(node); } /// /// 将值添加到 ICollection`1 的结尾处。 /// /// 要添加的值。 void ICollection.Add(T value) { AddLast(value); } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// 循环访问集合的枚举数。 /// [StructLayout(LayoutKind.Auto)] public struct Enumerator : IEnumerator, IEnumerator { private LinkedList.Enumerator m_Enumerator; internal Enumerator(LinkedList linkedList) { if (linkedList == null) { throw new GameFrameworkException("Linked list is invalid."); } m_Enumerator = linkedList.GetEnumerator(); } /// /// 获取当前结点。 /// public T Current { get { return m_Enumerator.Current; } } /// /// 获取当前的枚举数。 /// object IEnumerator.Current { get { return m_Enumerator.Current; } } /// /// 清理枚举数。 /// public void Dispose() { m_Enumerator.Dispose(); } /// /// 获取下一个结点。 /// /// 返回下一个结点。 public bool MoveNext() { return m_Enumerator.MoveNext(); } /// /// 重置枚举数。 /// void IEnumerator.Reset() { ((IEnumerator)m_Enumerator).Reset(); } } } } ================================================ FILE: GameFramework/Base/GameFrameworkLinkedListRange.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; namespace GameFramework { /// /// 游戏框架链表范围。 /// /// 指定链表范围的元素类型。 [StructLayout(LayoutKind.Auto)] public struct GameFrameworkLinkedListRange : IEnumerable, IEnumerable { private readonly LinkedListNode m_First; private readonly LinkedListNode m_Terminal; /// /// 初始化游戏框架链表范围的新实例。 /// /// 链表范围的开始结点。 /// 链表范围的终结标记结点。 public GameFrameworkLinkedListRange(LinkedListNode first, LinkedListNode terminal) { if (first == null || terminal == null || first == terminal) { throw new GameFrameworkException("Range is invalid."); } m_First = first; m_Terminal = terminal; } /// /// 获取链表范围是否有效。 /// public bool IsValid { get { return m_First != null && m_Terminal != null && m_First != m_Terminal; } } /// /// 获取链表范围的开始结点。 /// public LinkedListNode First { get { return m_First; } } /// /// 获取链表范围的终结标记结点。 /// public LinkedListNode Terminal { get { return m_Terminal; } } /// /// 获取链表范围的结点数量。 /// public int Count { get { if (!IsValid) { return 0; } int count = 0; for (LinkedListNode current = m_First; current != null && current != m_Terminal; current = current.Next) { count++; } return count; } } /// /// 检查是否包含指定值。 /// /// 要检查的值。 /// 是否包含指定值。 public bool Contains(T value) { for (LinkedListNode current = m_First; current != null && current != m_Terminal; current = current.Next) { if (current.Value.Equals(value)) { return true; } } return false; } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 public Enumerator GetEnumerator() { return new Enumerator(this); } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// 循环访问集合的枚举数。 /// [StructLayout(LayoutKind.Auto)] public struct Enumerator : IEnumerator, IEnumerator { private readonly GameFrameworkLinkedListRange m_GameFrameworkLinkedListRange; private LinkedListNode m_Current; private T m_CurrentValue; internal Enumerator(GameFrameworkLinkedListRange range) { if (!range.IsValid) { throw new GameFrameworkException("Range is invalid."); } m_GameFrameworkLinkedListRange = range; m_Current = m_GameFrameworkLinkedListRange.m_First; m_CurrentValue = default(T); } /// /// 获取当前结点。 /// public T Current { get { return m_CurrentValue; } } /// /// 获取当前的枚举数。 /// object IEnumerator.Current { get { return m_CurrentValue; } } /// /// 清理枚举数。 /// public void Dispose() { } /// /// 获取下一个结点。 /// /// 返回下一个结点。 public bool MoveNext() { if (m_Current == null || m_Current == m_GameFrameworkLinkedListRange.m_Terminal) { return false; } m_CurrentValue = m_Current.Value; m_Current = m_Current.Next; return true; } /// /// 重置枚举数。 /// void IEnumerator.Reset() { m_Current = m_GameFrameworkLinkedListRange.m_First; m_CurrentValue = default(T); } } } } ================================================ FILE: GameFramework/Base/GameFrameworkModule.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 游戏框架模块抽象类。 /// internal abstract class GameFrameworkModule { /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal virtual int Priority { get { return 0; } } /// /// 游戏框架模块轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal abstract void Update(float elapseSeconds, float realElapseSeconds); /// /// 关闭并清理游戏框架模块。 /// internal abstract void Shutdown(); } } ================================================ FILE: GameFramework/Base/GameFrameworkMultiDictionary.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; namespace GameFramework { /// /// 游戏框架多值字典类。 /// /// 指定多值字典的主键类型。 /// 指定多值字典的值类型。 public sealed class GameFrameworkMultiDictionary : IEnumerable>>, IEnumerable { private readonly GameFrameworkLinkedList m_LinkedList; private readonly Dictionary> m_Dictionary; /// /// 初始化游戏框架多值字典类的新实例。 /// public GameFrameworkMultiDictionary() { m_LinkedList = new GameFrameworkLinkedList(); m_Dictionary = new Dictionary>(); } /// /// 获取多值字典中实际包含的主键数量。 /// public int Count { get { return m_Dictionary.Count; } } /// /// 获取多值字典中指定主键的范围。 /// /// 指定的主键。 /// 指定主键的范围。 public GameFrameworkLinkedListRange this[TKey key] { get { GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); m_Dictionary.TryGetValue(key, out range); return range; } } /// /// 清理多值字典。 /// public void Clear() { m_Dictionary.Clear(); m_LinkedList.Clear(); } /// /// 检查多值字典中是否包含指定主键。 /// /// 要检查的主键。 /// 多值字典中是否包含指定主键。 public bool Contains(TKey key) { return m_Dictionary.ContainsKey(key); } /// /// 检查多值字典中是否包含指定值。 /// /// 要检查的主键。 /// 要检查的值。 /// 多值字典中是否包含指定值。 public bool Contains(TKey key, TValue value) { GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); if (m_Dictionary.TryGetValue(key, out range)) { return range.Contains(value); } return false; } /// /// 尝试获取多值字典中指定主键的范围。 /// /// 指定的主键。 /// 指定主键的范围。 /// 是否获取成功。 public bool TryGetValue(TKey key, out GameFrameworkLinkedListRange range) { return m_Dictionary.TryGetValue(key, out range); } /// /// 向指定的主键增加指定的值。 /// /// 指定的主键。 /// 指定的值。 public void Add(TKey key, TValue value) { GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); if (m_Dictionary.TryGetValue(key, out range)) { m_LinkedList.AddBefore(range.Terminal, value); } else { LinkedListNode first = m_LinkedList.AddLast(value); LinkedListNode terminal = m_LinkedList.AddLast(default(TValue)); m_Dictionary.Add(key, new GameFrameworkLinkedListRange(first, terminal)); } } /// /// 从指定的主键中移除指定的值。 /// /// 指定的主键。 /// 指定的值。 /// 是否移除成功。 public bool Remove(TKey key, TValue value) { GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); if (m_Dictionary.TryGetValue(key, out range)) { for (LinkedListNode current = range.First; current != null && current != range.Terminal; current = current.Next) { if (current.Value.Equals(value)) { if (current == range.First) { LinkedListNode next = current.Next; if (next == range.Terminal) { m_LinkedList.Remove(next); m_Dictionary.Remove(key); } else { m_Dictionary[key] = new GameFrameworkLinkedListRange(next, range.Terminal); } } m_LinkedList.Remove(current); return true; } } } return false; } /// /// 从指定的主键中移除所有的值。 /// /// 指定的主键。 /// 是否移除成功。 public bool RemoveAll(TKey key) { GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); if (m_Dictionary.TryGetValue(key, out range)) { m_Dictionary.Remove(key); LinkedListNode current = range.First; while (current != null) { LinkedListNode next = current != range.Terminal ? current.Next : null; m_LinkedList.Remove(current); current = next; } return true; } return false; } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 public Enumerator GetEnumerator() { return new Enumerator(m_Dictionary); } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 IEnumerator>> IEnumerable>>.GetEnumerator() { return GetEnumerator(); } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// 循环访问集合的枚举数。 /// [StructLayout(LayoutKind.Auto)] public struct Enumerator : IEnumerator>>, IEnumerator { private Dictionary>.Enumerator m_Enumerator; internal Enumerator(Dictionary> dictionary) { if (dictionary == null) { throw new GameFrameworkException("Dictionary is invalid."); } m_Enumerator = dictionary.GetEnumerator(); } /// /// 获取当前结点。 /// public KeyValuePair> Current { get { return m_Enumerator.Current; } } /// /// 获取当前的枚举数。 /// object IEnumerator.Current { get { return m_Enumerator.Current; } } /// /// 清理枚举数。 /// public void Dispose() { m_Enumerator.Dispose(); } /// /// 获取下一个结点。 /// /// 返回下一个结点。 public bool MoveNext() { return m_Enumerator.MoveNext(); } /// /// 重置枚举数。 /// void IEnumerator.Reset() { ((IEnumerator>>)m_Enumerator).Reset(); } } } } ================================================ FILE: GameFramework/Base/GameFrameworkSerializer.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; using System.IO; namespace GameFramework { /// /// 游戏框架序列化器基类。 /// /// 要序列化的数据类型。 public abstract class GameFrameworkSerializer { private readonly Dictionary m_SerializeCallbacks; private readonly Dictionary m_DeserializeCallbacks; private readonly Dictionary m_TryGetValueCallbacks; private byte m_LatestSerializeCallbackVersion; /// /// 初始化游戏框架序列化器基类的新实例。 /// public GameFrameworkSerializer() { m_SerializeCallbacks = new Dictionary(); m_DeserializeCallbacks = new Dictionary(); m_TryGetValueCallbacks = new Dictionary(); m_LatestSerializeCallbackVersion = 0; } /// /// 序列化回调函数。 /// /// 目标流。 /// 要序列化的数据。 /// 是否序列化数据成功。 public delegate bool SerializeCallback(Stream stream, T data); /// /// 反序列化回调函数。 /// /// 指定流。 /// 反序列化的数据。 public delegate T DeserializeCallback(Stream stream); /// /// 尝试从指定流获取指定键的值回调函数。 /// /// 指定流。 /// 指定键。 /// 指定键的值。 /// 是否从指定流获取指定键的值成功。 public delegate bool TryGetValueCallback(Stream stream, string key, out object value); /// /// 注册序列化回调函数。 /// /// 序列化回调函数的版本。 /// 序列化回调函数。 public void RegisterSerializeCallback(byte version, SerializeCallback callback) { if (callback == null) { throw new GameFrameworkException("Serialize callback is invalid."); } m_SerializeCallbacks[version] = callback; if (version > m_LatestSerializeCallbackVersion) { m_LatestSerializeCallbackVersion = version; } } /// /// 注册反序列化回调函数。 /// /// 反序列化回调函数的版本。 /// 反序列化回调函数。 public void RegisterDeserializeCallback(byte version, DeserializeCallback callback) { if (callback == null) { throw new GameFrameworkException("Deserialize callback is invalid."); } m_DeserializeCallbacks[version] = callback; } /// /// 注册尝试从指定流获取指定键的值回调函数。 /// /// 尝试从指定流获取指定键的值回调函数的版本。 /// 尝试从指定流获取指定键的值回调函数。 public void RegisterTryGetValueCallback(byte version, TryGetValueCallback callback) { if (callback == null) { throw new GameFrameworkException("Try get value callback is invalid."); } m_TryGetValueCallbacks[version] = callback; } /// /// 序列化数据到目标流中。 /// /// 目标流。 /// 要序列化的数据。 /// 是否序列化数据成功。 public bool Serialize(Stream stream, T data) { if (m_SerializeCallbacks.Count <= 0) { throw new GameFrameworkException("No serialize callback registered."); } return Serialize(stream, data, m_LatestSerializeCallbackVersion); } /// /// 序列化数据到目标流中。 /// /// 目标流。 /// 要序列化的数据。 /// 序列化回调函数的版本。 /// 是否序列化数据成功。 public bool Serialize(Stream stream, T data, byte version) { byte[] header = GetHeader(); stream.WriteByte(header[0]); stream.WriteByte(header[1]); stream.WriteByte(header[2]); stream.WriteByte(version); SerializeCallback callback = null; if (!m_SerializeCallbacks.TryGetValue(version, out callback)) { throw new GameFrameworkException(Utility.Text.Format("Serialize callback '{0}' is not exist.", version)); } return callback(stream, data); } /// /// 从指定流反序列化数据。 /// /// 指定流。 /// 反序列化的数据。 public T Deserialize(Stream stream) { byte[] header = GetHeader(); byte header0 = (byte)stream.ReadByte(); byte header1 = (byte)stream.ReadByte(); byte header2 = (byte)stream.ReadByte(); if (header0 != header[0] || header1 != header[1] || header2 != header[2]) { throw new GameFrameworkException(Utility.Text.Format("Header is invalid, need '{0}{1}{2}', current '{3}{4}{5}'.", (char)header[0], (char)header[1], (char)header[2], (char)header0, (char)header1, (char)header2)); } byte version = (byte)stream.ReadByte(); DeserializeCallback callback = null; if (!m_DeserializeCallbacks.TryGetValue(version, out callback)) { throw new GameFrameworkException(Utility.Text.Format("Deserialize callback '{0}' is not exist.", version)); } return callback(stream); } /// /// 尝试从指定流获取指定键的值。 /// /// 指定流。 /// 指定键。 /// 指定键的值。 /// 是否从指定流获取指定键的值成功。 public bool TryGetValue(Stream stream, string key, out object value) { value = null; byte[] header = GetHeader(); byte header0 = (byte)stream.ReadByte(); byte header1 = (byte)stream.ReadByte(); byte header2 = (byte)stream.ReadByte(); if (header0 != header[0] || header1 != header[1] || header2 != header[2]) { return false; } byte version = (byte)stream.ReadByte(); TryGetValueCallback callback = null; if (!m_TryGetValueCallbacks.TryGetValue(version, out callback)) { return false; } return callback(stream, key, out value); } /// /// 获取数据头标识。 /// /// 数据头标识。 protected abstract byte[] GetHeader(); } } ================================================ FILE: GameFramework/Base/Log/GameFrameworkLog.ILogHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { public static partial class GameFrameworkLog { /// /// 游戏框架日志辅助器接口。 /// public interface ILogHelper { /// /// 记录日志。 /// /// 游戏框架日志等级。 /// 日志内容。 void Log(GameFrameworkLogLevel level, object message); } } } ================================================ FILE: GameFramework/Base/Log/GameFrameworkLog.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 游戏框架日志类。 /// public static partial class GameFrameworkLog { private static ILogHelper s_LogHelper = null; /// /// 设置游戏框架日志辅助器。 /// /// 要设置的游戏框架日志辅助器。 public static void SetLogHelper(ILogHelper logHelper) { s_LogHelper = logHelper; } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志内容。 public static void Debug(object message) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, message); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志内容。 public static void Debug(string message) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, message); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数的类型。 /// 日志格式。 /// 日志参数。 public static void Debug(string format, T arg) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 public static void Debug(string format, T1 arg1, T2 arg2) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志参数 15 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 /// 日志参数 15。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); } /// /// 打印调试级别日志,用于记录调试类日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志参数 15 的类型。 /// 日志参数 16 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 /// 日志参数 15。 /// 日志参数 16。 public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志内容。 public static void Info(object message) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, message); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志内容。 public static void Info(string message) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, message); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数的类型。 /// 日志格式。 /// 日志参数。 public static void Info(string format, T arg) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 public static void Info(string format, T1 arg1, T2 arg2) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志参数 15 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 /// 日志参数 15。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); } /// /// 打印信息级别日志,用于记录程序正常运行日志信息。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志参数 15 的类型。 /// 日志参数 16 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 /// 日志参数 15。 /// 日志参数 16。 public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志内容。 public static void Warning(object message) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, message); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志内容。 public static void Warning(string message) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, message); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数的类型。 /// 日志格式。 /// 日志参数。 public static void Warning(string format, T arg) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 public static void Warning(string format, T1 arg1, T2 arg2) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志参数 15 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 /// 日志参数 15。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); } /// /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志参数 15 的类型。 /// 日志参数 16 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 /// 日志参数 15。 /// 日志参数 16。 public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志内容。 public static void Error(object message) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, message); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志内容。 public static void Error(string message) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, message); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数的类型。 /// 日志格式。 /// 日志参数。 public static void Error(string format, T arg) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 public static void Error(string format, T1 arg1, T2 arg2) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志参数 15 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 /// 日志参数 15。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); } /// /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志参数 15 的类型。 /// 日志参数 16 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 /// 日志参数 15。 /// 日志参数 16。 public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志内容。 public static void Fatal(object message) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, message); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志内容。 public static void Fatal(string message) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, message); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数的类型。 /// 日志格式。 /// 日志参数。 public static void Fatal(string format, T arg) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 public static void Fatal(string format, T1 arg1, T2 arg2) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志参数 15 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 /// 日志参数 15。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); } /// /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 /// /// 日志参数 1 的类型。 /// 日志参数 2 的类型。 /// 日志参数 3 的类型。 /// 日志参数 4 的类型。 /// 日志参数 5 的类型。 /// 日志参数 6 的类型。 /// 日志参数 7 的类型。 /// 日志参数 8 的类型。 /// 日志参数 9 的类型。 /// 日志参数 10 的类型。 /// 日志参数 11 的类型。 /// 日志参数 12 的类型。 /// 日志参数 13 的类型。 /// 日志参数 14 的类型。 /// 日志参数 15 的类型。 /// 日志参数 16 的类型。 /// 日志格式。 /// 日志参数 1。 /// 日志参数 2。 /// 日志参数 3。 /// 日志参数 4。 /// 日志参数 5。 /// 日志参数 6。 /// 日志参数 7。 /// 日志参数 8。 /// 日志参数 9。 /// 日志参数 10。 /// 日志参数 11。 /// 日志参数 12。 /// 日志参数 13。 /// 日志参数 14。 /// 日志参数 15。 /// 日志参数 16。 public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) { if (s_LogHelper == null) { return; } s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); } } } ================================================ FILE: GameFramework/Base/Log/GameFrameworkLogLevel.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 游戏框架日志等级。 /// public enum GameFrameworkLogLevel : byte { /// /// 调试。 /// Debug = 0, /// /// 信息。 /// Info, /// /// 警告。 /// Warning, /// /// 错误。 /// Error, /// /// 严重错误。 /// Fatal } } ================================================ FILE: GameFramework/Base/ReferencePool/IReference.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 引用接口。 /// public interface IReference { /// /// 清理引用。 /// void Clear(); } } ================================================ FILE: GameFramework/Base/ReferencePool/ReferencePool.ReferenceCollection.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework { public static partial class ReferencePool { private sealed class ReferenceCollection { private readonly Queue m_References; private readonly Type m_ReferenceType; private int m_UsingReferenceCount; private int m_AcquireReferenceCount; private int m_ReleaseReferenceCount; private int m_AddReferenceCount; private int m_RemoveReferenceCount; public ReferenceCollection(Type referenceType) { m_References = new Queue(); m_ReferenceType = referenceType; m_UsingReferenceCount = 0; m_AcquireReferenceCount = 0; m_ReleaseReferenceCount = 0; m_AddReferenceCount = 0; m_RemoveReferenceCount = 0; } public Type ReferenceType { get { return m_ReferenceType; } } public int UnusedReferenceCount { get { return m_References.Count; } } public int UsingReferenceCount { get { return m_UsingReferenceCount; } } public int AcquireReferenceCount { get { return m_AcquireReferenceCount; } } public int ReleaseReferenceCount { get { return m_ReleaseReferenceCount; } } public int AddReferenceCount { get { return m_AddReferenceCount; } } public int RemoveReferenceCount { get { return m_RemoveReferenceCount; } } public T Acquire() where T : class, IReference, new() { if (typeof(T) != m_ReferenceType) { throw new GameFrameworkException("Type is invalid."); } m_UsingReferenceCount++; m_AcquireReferenceCount++; lock (m_References) { if (m_References.Count > 0) { return (T)m_References.Dequeue(); } } m_AddReferenceCount++; return new T(); } public IReference Acquire() { m_UsingReferenceCount++; m_AcquireReferenceCount++; lock (m_References) { if (m_References.Count > 0) { return m_References.Dequeue(); } } m_AddReferenceCount++; return (IReference)Activator.CreateInstance(m_ReferenceType); } public void Release(IReference reference) { reference.Clear(); lock (m_References) { if (m_EnableStrictCheck && m_References.Contains(reference)) { throw new GameFrameworkException("The reference has been released."); } m_References.Enqueue(reference); } m_ReleaseReferenceCount++; m_UsingReferenceCount--; } public void Add(int count) where T : class, IReference, new() { if (typeof(T) != m_ReferenceType) { throw new GameFrameworkException("Type is invalid."); } lock (m_References) { m_AddReferenceCount += count; while (count-- > 0) { m_References.Enqueue(new T()); } } } public void Add(int count) { lock (m_References) { m_AddReferenceCount += count; while (count-- > 0) { m_References.Enqueue((IReference)Activator.CreateInstance(m_ReferenceType)); } } } public void Remove(int count) { lock (m_References) { if (count > m_References.Count) { count = m_References.Count; } m_RemoveReferenceCount += count; while (count-- > 0) { m_References.Dequeue(); } } } public void RemoveAll() { lock (m_References) { m_RemoveReferenceCount += m_References.Count; m_References.Clear(); } } } } } ================================================ FILE: GameFramework/Base/ReferencePool/ReferencePool.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework { /// /// 引用池。 /// public static partial class ReferencePool { private static readonly Dictionary s_ReferenceCollections = new Dictionary(); private static bool m_EnableStrictCheck = false; /// /// 获取或设置是否开启强制检查。 /// public static bool EnableStrictCheck { get { return m_EnableStrictCheck; } set { m_EnableStrictCheck = value; } } /// /// 获取引用池的数量。 /// public static int Count { get { return s_ReferenceCollections.Count; } } /// /// 获取所有引用池的信息。 /// /// 所有引用池的信息。 public static ReferencePoolInfo[] GetAllReferencePoolInfos() { int index = 0; ReferencePoolInfo[] results = null; lock (s_ReferenceCollections) { results = new ReferencePoolInfo[s_ReferenceCollections.Count]; foreach (KeyValuePair referenceCollection in s_ReferenceCollections) { results[index++] = new ReferencePoolInfo(referenceCollection.Key, referenceCollection.Value.UnusedReferenceCount, referenceCollection.Value.UsingReferenceCount, referenceCollection.Value.AcquireReferenceCount, referenceCollection.Value.ReleaseReferenceCount, referenceCollection.Value.AddReferenceCount, referenceCollection.Value.RemoveReferenceCount); } } return results; } /// /// 清除所有引用池。 /// public static void ClearAll() { lock (s_ReferenceCollections) { foreach (KeyValuePair referenceCollection in s_ReferenceCollections) { referenceCollection.Value.RemoveAll(); } s_ReferenceCollections.Clear(); } } /// /// 从引用池获取引用。 /// /// 引用类型。 /// 引用。 public static T Acquire() where T : class, IReference, new() { return GetReferenceCollection(typeof(T)).Acquire(); } /// /// 从引用池获取引用。 /// /// 引用类型。 /// 引用。 public static IReference Acquire(Type referenceType) { InternalCheckReferenceType(referenceType); return GetReferenceCollection(referenceType).Acquire(); } /// /// 将引用归还引用池。 /// /// 引用。 public static void Release(IReference reference) { if (reference == null) { throw new GameFrameworkException("Reference is invalid."); } Type referenceType = reference.GetType(); InternalCheckReferenceType(referenceType); GetReferenceCollection(referenceType).Release(reference); } /// /// 向引用池中追加指定数量的引用。 /// /// 引用类型。 /// 追加数量。 public static void Add(int count) where T : class, IReference, new() { GetReferenceCollection(typeof(T)).Add(count); } /// /// 向引用池中追加指定数量的引用。 /// /// 引用类型。 /// 追加数量。 public static void Add(Type referenceType, int count) { InternalCheckReferenceType(referenceType); GetReferenceCollection(referenceType).Add(count); } /// /// 从引用池中移除指定数量的引用。 /// /// 引用类型。 /// 移除数量。 public static void Remove(int count) where T : class, IReference { GetReferenceCollection(typeof(T)).Remove(count); } /// /// 从引用池中移除指定数量的引用。 /// /// 引用类型。 /// 移除数量。 public static void Remove(Type referenceType, int count) { InternalCheckReferenceType(referenceType); GetReferenceCollection(referenceType).Remove(count); } /// /// 从引用池中移除所有的引用。 /// /// 引用类型。 public static void RemoveAll() where T : class, IReference { GetReferenceCollection(typeof(T)).RemoveAll(); } /// /// 从引用池中移除所有的引用。 /// /// 引用类型。 public static void RemoveAll(Type referenceType) { InternalCheckReferenceType(referenceType); GetReferenceCollection(referenceType).RemoveAll(); } private static void InternalCheckReferenceType(Type referenceType) { if (!m_EnableStrictCheck) { return; } if (referenceType == null) { throw new GameFrameworkException("Reference type is invalid."); } if (!referenceType.IsClass || referenceType.IsAbstract) { throw new GameFrameworkException("Reference type is not a non-abstract class type."); } if (!typeof(IReference).IsAssignableFrom(referenceType)) { throw new GameFrameworkException(Utility.Text.Format("Reference type '{0}' is invalid.", referenceType.FullName)); } } private static ReferenceCollection GetReferenceCollection(Type referenceType) { if (referenceType == null) { throw new GameFrameworkException("ReferenceType is invalid."); } ReferenceCollection referenceCollection = null; lock (s_ReferenceCollections) { if (!s_ReferenceCollections.TryGetValue(referenceType, out referenceCollection)) { referenceCollection = new ReferenceCollection(referenceType); s_ReferenceCollections.Add(referenceType, referenceCollection); } } return referenceCollection; } } } ================================================ FILE: GameFramework/Base/ReferencePool/ReferencePoolInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Runtime.InteropServices; namespace GameFramework { /// /// 引用池信息。 /// [StructLayout(LayoutKind.Auto)] public struct ReferencePoolInfo { private readonly Type m_Type; private readonly int m_UnusedReferenceCount; private readonly int m_UsingReferenceCount; private readonly int m_AcquireReferenceCount; private readonly int m_ReleaseReferenceCount; private readonly int m_AddReferenceCount; private readonly int m_RemoveReferenceCount; /// /// 初始化引用池信息的新实例。 /// /// 引用池类型。 /// 未使用引用数量。 /// 正在使用引用数量。 /// 获取引用数量。 /// 归还引用数量。 /// 增加引用数量。 /// 移除引用数量。 public ReferencePoolInfo(Type type, int unusedReferenceCount, int usingReferenceCount, int acquireReferenceCount, int releaseReferenceCount, int addReferenceCount, int removeReferenceCount) { m_Type = type; m_UnusedReferenceCount = unusedReferenceCount; m_UsingReferenceCount = usingReferenceCount; m_AcquireReferenceCount = acquireReferenceCount; m_ReleaseReferenceCount = releaseReferenceCount; m_AddReferenceCount = addReferenceCount; m_RemoveReferenceCount = removeReferenceCount; } /// /// 获取引用池类型。 /// public Type Type { get { return m_Type; } } /// /// 获取未使用引用数量。 /// public int UnusedReferenceCount { get { return m_UnusedReferenceCount; } } /// /// 获取正在使用引用数量。 /// public int UsingReferenceCount { get { return m_UsingReferenceCount; } } /// /// 获取获取引用数量。 /// public int AcquireReferenceCount { get { return m_AcquireReferenceCount; } } /// /// 获取归还引用数量。 /// public int ReleaseReferenceCount { get { return m_ReleaseReferenceCount; } } /// /// 获取增加引用数量。 /// public int AddReferenceCount { get { return m_AddReferenceCount; } } /// /// 获取移除引用数量。 /// public int RemoveReferenceCount { get { return m_RemoveReferenceCount; } } } } ================================================ FILE: GameFramework/Base/TaskPool/ITaskAgent.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 任务代理接口。 /// /// 任务类型。 internal interface ITaskAgent where T : TaskBase { /// /// 获取任务。 /// T Task { get; } /// /// 初始化任务代理。 /// void Initialize(); /// /// 任务代理轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 void Update(float elapseSeconds, float realElapseSeconds); /// /// 关闭并清理任务代理。 /// void Shutdown(); /// /// 开始处理任务。 /// /// 要处理的任务。 /// 开始处理任务的状态。 StartTaskStatus Start(T task); /// /// 停止正在处理的任务并重置任务代理。 /// void Reset(); } } ================================================ FILE: GameFramework/Base/TaskPool/StartTaskStatus.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 开始处理任务的状态。 /// public enum StartTaskStatus : byte { /// /// 可以立刻处理完成此任务。 /// Done = 0, /// /// 可以继续处理此任务。 /// CanResume, /// /// 不能继续处理此任务,需等待其它任务执行完成。 /// HasToWait, /// /// 不能继续处理此任务,出现未知错误。 /// UnknownError } } ================================================ FILE: GameFramework/Base/TaskPool/TaskBase.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 任务基类。 /// internal abstract class TaskBase : IReference { /// /// 任务默认优先级。 /// public const int DefaultPriority = 0; private int m_SerialId; private string m_Tag; private int m_Priority; private object m_UserData; private bool m_Done; /// /// 初始化任务基类的新实例。 /// public TaskBase() { m_SerialId = 0; m_Tag = null; m_Priority = DefaultPriority; m_Done = false; m_UserData = null; } /// /// 获取任务的序列编号。 /// public int SerialId { get { return m_SerialId; } } /// /// 获取任务的标签。 /// public string Tag { get { return m_Tag; } } /// /// 获取任务的优先级。 /// public int Priority { get { return m_Priority; } } /// /// 获取任务的用户自定义数据。 /// public object UserData { get { return m_UserData; } } /// /// 获取或设置任务是否完成。 /// public bool Done { get { return m_Done; } set { m_Done = value; } } /// /// 获取任务描述。 /// public virtual string Description { get { return null; } } /// /// 初始化任务基类。 /// /// 任务的序列编号。 /// 任务的标签。 /// 任务的优先级。 /// 任务的用户自定义数据。 internal void Initialize(int serialId, string tag, int priority, object userData) { m_SerialId = serialId; m_Tag = tag; m_Priority = priority; m_UserData = userData; m_Done = false; } /// /// 清理任务基类。 /// public virtual void Clear() { m_SerialId = 0; m_Tag = null; m_Priority = DefaultPriority; m_UserData = null; m_Done = false; } } } ================================================ FILE: GameFramework/Base/TaskPool/TaskInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework { /// /// 任务信息。 /// [StructLayout(LayoutKind.Auto)] public struct TaskInfo { private readonly bool m_IsValid; private readonly int m_SerialId; private readonly string m_Tag; private readonly int m_Priority; private readonly object m_UserData; private readonly TaskStatus m_Status; private readonly string m_Description; /// /// 初始化任务信息的新实例。 /// /// 任务的序列编号。 /// 任务的标签。 /// 任务的优先级。 /// 任务的用户自定义数据。 /// 任务状态。 /// 任务描述。 public TaskInfo(int serialId, string tag, int priority, object userData, TaskStatus status, string description) { m_IsValid = true; m_SerialId = serialId; m_Tag = tag; m_Priority = priority; m_UserData = userData; m_Status = status; m_Description = description; } /// /// 获取任务信息是否有效。 /// public bool IsValid { get { return m_IsValid; } } /// /// 获取任务的序列编号。 /// public int SerialId { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_SerialId; } } /// /// 获取任务的标签。 /// public string Tag { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Tag; } } /// /// 获取任务的优先级。 /// public int Priority { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Priority; } } /// /// 获取任务的用户自定义数据。 /// public object UserData { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_UserData; } } /// /// 获取任务状态。 /// public TaskStatus Status { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Status; } } /// /// 获取任务描述。 /// public string Description { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Description; } } } } ================================================ FILE: GameFramework/Base/TaskPool/TaskPool.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework { /// /// 任务池。 /// /// 任务类型。 internal sealed class TaskPool where T : TaskBase { private readonly Stack> m_FreeAgents; private readonly GameFrameworkLinkedList> m_WorkingAgents; private readonly GameFrameworkLinkedList m_WaitingTasks; private bool m_Paused; /// /// 初始化任务池的新实例。 /// public TaskPool() { m_FreeAgents = new Stack>(); m_WorkingAgents = new GameFrameworkLinkedList>(); m_WaitingTasks = new GameFrameworkLinkedList(); m_Paused = false; } /// /// 获取或设置任务池是否被暂停。 /// public bool Paused { get { return m_Paused; } set { m_Paused = value; } } /// /// 获取任务代理总数量。 /// public int TotalAgentCount { get { return FreeAgentCount + WorkingAgentCount; } } /// /// 获取可用任务代理数量。 /// public int FreeAgentCount { get { return m_FreeAgents.Count; } } /// /// 获取工作中任务代理数量。 /// public int WorkingAgentCount { get { return m_WorkingAgents.Count; } } /// /// 获取等待任务数量。 /// public int WaitingTaskCount { get { return m_WaitingTasks.Count; } } /// /// 任务池轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void Update(float elapseSeconds, float realElapseSeconds) { if (m_Paused) { return; } ProcessRunningTasks(elapseSeconds, realElapseSeconds); ProcessWaitingTasks(elapseSeconds, realElapseSeconds); } /// /// 关闭并清理任务池。 /// public void Shutdown() { RemoveAllTasks(); while (FreeAgentCount > 0) { m_FreeAgents.Pop().Shutdown(); } } /// /// 增加任务代理。 /// /// 要增加的任务代理。 public void AddAgent(ITaskAgent agent) { if (agent == null) { throw new GameFrameworkException("Task agent is invalid."); } agent.Initialize(); m_FreeAgents.Push(agent); } /// /// 根据任务的序列编号获取任务的信息。 /// /// 要获取信息的任务的序列编号。 /// 任务的信息。 public TaskInfo GetTaskInfo(int serialId) { foreach (ITaskAgent workingAgent in m_WorkingAgents) { T workingTask = workingAgent.Task; if (workingTask.SerialId == serialId) { return new TaskInfo(workingTask.SerialId, workingTask.Tag, workingTask.Priority, workingTask.UserData, workingTask.Done ? TaskStatus.Done : TaskStatus.Doing, workingTask.Description); } } foreach (T waitingTask in m_WaitingTasks) { if (waitingTask.SerialId == serialId) { return new TaskInfo(waitingTask.SerialId, waitingTask.Tag, waitingTask.Priority, waitingTask.UserData, TaskStatus.Todo, waitingTask.Description); } } return default(TaskInfo); } /// /// 根据任务的标签获取任务的信息。 /// /// 要获取信息的任务的标签。 /// 任务的信息。 public TaskInfo[] GetTaskInfos(string tag) { List results = new List(); GetTaskInfos(tag, results); return results.ToArray(); } /// /// 根据任务的标签获取任务的信息。 /// /// 要获取信息的任务的标签。 /// 任务的信息。 public void GetTaskInfos(string tag, List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (ITaskAgent workingAgent in m_WorkingAgents) { T workingTask = workingAgent.Task; if (workingTask.Tag == tag) { results.Add(new TaskInfo(workingTask.SerialId, workingTask.Tag, workingTask.Priority, workingTask.UserData, workingTask.Done ? TaskStatus.Done : TaskStatus.Doing, workingTask.Description)); } } foreach (T waitingTask in m_WaitingTasks) { if (waitingTask.Tag == tag) { results.Add(new TaskInfo(waitingTask.SerialId, waitingTask.Tag, waitingTask.Priority, waitingTask.UserData, TaskStatus.Todo, waitingTask.Description)); } } } /// /// 获取所有任务的信息。 /// /// 所有任务的信息。 public TaskInfo[] GetAllTaskInfos() { int index = 0; TaskInfo[] results = new TaskInfo[m_WorkingAgents.Count + m_WaitingTasks.Count]; foreach (ITaskAgent workingAgent in m_WorkingAgents) { T workingTask = workingAgent.Task; results[index++] = new TaskInfo(workingTask.SerialId, workingTask.Tag, workingTask.Priority, workingTask.UserData, workingTask.Done ? TaskStatus.Done : TaskStatus.Doing, workingTask.Description); } foreach (T waitingTask in m_WaitingTasks) { results[index++] = new TaskInfo(waitingTask.SerialId, waitingTask.Tag, waitingTask.Priority, waitingTask.UserData, TaskStatus.Todo, waitingTask.Description); } return results; } /// /// 获取所有任务的信息。 /// /// 所有任务的信息。 public void GetAllTaskInfos(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (ITaskAgent workingAgent in m_WorkingAgents) { T workingTask = workingAgent.Task; results.Add(new TaskInfo(workingTask.SerialId, workingTask.Tag, workingTask.Priority, workingTask.UserData, workingTask.Done ? TaskStatus.Done : TaskStatus.Doing, workingTask.Description)); } foreach (T waitingTask in m_WaitingTasks) { results.Add(new TaskInfo(waitingTask.SerialId, waitingTask.Tag, waitingTask.Priority, waitingTask.UserData, TaskStatus.Todo, waitingTask.Description)); } } /// /// 增加任务。 /// /// 要增加的任务。 public void AddTask(T task) { LinkedListNode current = m_WaitingTasks.Last; while (current != null) { if (task.Priority <= current.Value.Priority) { break; } current = current.Previous; } if (current != null) { m_WaitingTasks.AddAfter(current, task); } else { m_WaitingTasks.AddFirst(task); } } /// /// 根据任务的序列编号移除任务。 /// /// 要移除任务的序列编号。 /// 是否移除任务成功。 public bool RemoveTask(int serialId) { foreach (T task in m_WaitingTasks) { if (task.SerialId == serialId) { m_WaitingTasks.Remove(task); ReferencePool.Release(task); return true; } } LinkedListNode> currentWorkingAgent = m_WorkingAgents.First; while (currentWorkingAgent != null) { LinkedListNode> next = currentWorkingAgent.Next; ITaskAgent workingAgent = currentWorkingAgent.Value; T task = workingAgent.Task; if (task.SerialId == serialId) { workingAgent.Reset(); m_FreeAgents.Push(workingAgent); m_WorkingAgents.Remove(currentWorkingAgent); ReferencePool.Release(task); return true; } currentWorkingAgent = next; } return false; } /// /// 根据任务的标签移除任务。 /// /// 要移除任务的标签。 /// 移除任务的数量。 public int RemoveTasks(string tag) { int count = 0; LinkedListNode currentWaitingTask = m_WaitingTasks.First; while (currentWaitingTask != null) { LinkedListNode next = currentWaitingTask.Next; T task = currentWaitingTask.Value; if (task.Tag == tag) { m_WaitingTasks.Remove(currentWaitingTask); ReferencePool.Release(task); count++; } currentWaitingTask = next; } LinkedListNode> currentWorkingAgent = m_WorkingAgents.First; while (currentWorkingAgent != null) { LinkedListNode> next = currentWorkingAgent.Next; ITaskAgent workingAgent = currentWorkingAgent.Value; T task = workingAgent.Task; if (task.Tag == tag) { workingAgent.Reset(); m_FreeAgents.Push(workingAgent); m_WorkingAgents.Remove(currentWorkingAgent); ReferencePool.Release(task); count++; } currentWorkingAgent = next; } return count; } /// /// 移除所有任务。 /// /// 移除任务的数量。 public int RemoveAllTasks() { int count = m_WaitingTasks.Count + m_WorkingAgents.Count; foreach (T task in m_WaitingTasks) { ReferencePool.Release(task); } m_WaitingTasks.Clear(); foreach (ITaskAgent workingAgent in m_WorkingAgents) { T task = workingAgent.Task; workingAgent.Reset(); m_FreeAgents.Push(workingAgent); ReferencePool.Release(task); } m_WorkingAgents.Clear(); return count; } private void ProcessRunningTasks(float elapseSeconds, float realElapseSeconds) { LinkedListNode> current = m_WorkingAgents.First; while (current != null) { T task = current.Value.Task; if (!task.Done) { current.Value.Update(elapseSeconds, realElapseSeconds); current = current.Next; continue; } LinkedListNode> next = current.Next; current.Value.Reset(); m_FreeAgents.Push(current.Value); m_WorkingAgents.Remove(current); ReferencePool.Release(task); current = next; } } private void ProcessWaitingTasks(float elapseSeconds, float realElapseSeconds) { LinkedListNode current = m_WaitingTasks.First; while (current != null && FreeAgentCount > 0) { ITaskAgent agent = m_FreeAgents.Pop(); LinkedListNode> agentNode = m_WorkingAgents.AddLast(agent); T task = current.Value; LinkedListNode next = current.Next; StartTaskStatus status = agent.Start(task); if (status == StartTaskStatus.Done || status == StartTaskStatus.HasToWait || status == StartTaskStatus.UnknownError) { agent.Reset(); m_FreeAgents.Push(agent); m_WorkingAgents.Remove(agentNode); } if (status == StartTaskStatus.Done || status == StartTaskStatus.CanResume || status == StartTaskStatus.UnknownError) { m_WaitingTasks.Remove(current); } if (status == StartTaskStatus.Done || status == StartTaskStatus.UnknownError) { ReferencePool.Release(task); } current = next; } } } } ================================================ FILE: GameFramework/Base/TaskPool/TaskStatus.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 任务状态。 /// public enum TaskStatus : byte { /// /// 未开始。 /// Todo = 0, /// /// 执行中。 /// Doing, /// /// 完成。 /// Done } } ================================================ FILE: GameFramework/Base/Variable/GenericVariable.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework { /// /// 变量。 /// /// 变量类型。 public abstract class Variable : Variable { private T m_Value; /// /// 初始化变量的新实例。 /// public Variable() { m_Value = default(T); } /// /// 获取变量类型。 /// public override Type Type { get { return typeof(T); } } /// /// 获取或设置变量值。 /// public T Value { get { return m_Value; } set { m_Value = value; } } /// /// 获取变量值。 /// /// 变量值。 public override object GetValue() { return m_Value; } /// /// 设置变量值。 /// /// 变量值。 public override void SetValue(object value) { m_Value = (T)value; } /// /// 清理变量值。 /// public override void Clear() { m_Value = default(T); } /// /// 获取变量字符串。 /// /// 变量字符串。 public override string ToString() { return (m_Value != null) ? m_Value.ToString() : ""; } } } ================================================ FILE: GameFramework/Base/Variable/Variable.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework { /// /// 变量。 /// public abstract class Variable : IReference { /// /// 初始化变量的新实例。 /// public Variable() { } /// /// 获取变量类型。 /// public abstract Type Type { get; } /// /// 获取变量值。 /// /// 变量值。 public abstract object GetValue(); /// /// 设置变量值。 /// /// 变量值。 public abstract void SetValue(object value); /// /// 清理变量值。 /// public abstract void Clear(); } } ================================================ FILE: GameFramework/Base/Version/Version.IVersionHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { public static partial class Version { /// /// 版本号辅助器接口。 /// public interface IVersionHelper { /// /// 获取游戏版本号。 /// string GameVersion { get; } /// /// 获取内部游戏版本号。 /// int InternalGameVersion { get; } } } } ================================================ FILE: GameFramework/Base/Version/Version.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 版本号类。 /// public static partial class Version { private const string GameFrameworkVersionString = "2021.05.31"; private static IVersionHelper s_VersionHelper = null; /// /// 获取游戏框架版本号。 /// public static string GameFrameworkVersion { get { return GameFrameworkVersionString; } } /// /// 获取游戏版本号。 /// public static string GameVersion { get { if (s_VersionHelper == null) { return string.Empty; } return s_VersionHelper.GameVersion; } } /// /// 获取内部游戏版本号。 /// public static int InternalGameVersion { get { if (s_VersionHelper == null) { return 0; } return s_VersionHelper.InternalGameVersion; } } /// /// 设置版本号辅助器。 /// /// 要设置的版本号辅助器。 public static void SetVersionHelper(IVersionHelper versionHelper) { s_VersionHelper = versionHelper; } } } ================================================ FILE: GameFramework/Config/ConfigManager.ConfigData.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Config { internal sealed partial class ConfigManager : GameFrameworkModule, IConfigManager { [StructLayout(LayoutKind.Auto)] private struct ConfigData { private readonly bool m_BoolValue; private readonly int m_IntValue; private readonly float m_FloatValue; private readonly string m_StringValue; public ConfigData(bool boolValue, int intValue, float floatValue, string stringValue) { m_BoolValue = boolValue; m_IntValue = intValue; m_FloatValue = floatValue; m_StringValue = stringValue; } public bool BoolValue { get { return m_BoolValue; } } public int IntValue { get { return m_IntValue; } } public float FloatValue { get { return m_FloatValue; } } public string StringValue { get { return m_StringValue; } } } } } ================================================ FILE: GameFramework/Config/ConfigManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.Config { /// /// 全局配置管理器。 /// internal sealed partial class ConfigManager : GameFrameworkModule, IConfigManager { private readonly Dictionary m_ConfigDatas; private readonly DataProvider m_DataProvider; private IConfigHelper m_ConfigHelper; /// /// 初始化全局配置管理器的新实例。 /// public ConfigManager() { m_ConfigDatas = new Dictionary(StringComparer.Ordinal); m_DataProvider = new DataProvider(this); m_ConfigHelper = null; } /// /// 获取全局配置项数量。 /// public int Count { get { return m_ConfigDatas.Count; } } /// /// 获取缓冲二进制流的大小。 /// public int CachedBytesSize { get { return DataProvider.CachedBytesSize; } } /// /// 读取全局配置成功事件。 /// public event EventHandler ReadDataSuccess { add { m_DataProvider.ReadDataSuccess += value; } remove { m_DataProvider.ReadDataSuccess -= value; } } /// /// 读取全局配置失败事件。 /// public event EventHandler ReadDataFailure { add { m_DataProvider.ReadDataFailure += value; } remove { m_DataProvider.ReadDataFailure -= value; } } /// /// 读取全局配置更新事件。 /// public event EventHandler ReadDataUpdate { add { m_DataProvider.ReadDataUpdate += value; } remove { m_DataProvider.ReadDataUpdate -= value; } } /// /// 读取全局配置时加载依赖资源事件。 /// public event EventHandler ReadDataDependencyAsset { add { m_DataProvider.ReadDataDependencyAsset += value; } remove { m_DataProvider.ReadDataDependencyAsset -= value; } } /// /// 全局配置管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { } /// /// 关闭并清理全局配置管理器。 /// internal override void Shutdown() { } /// /// 设置资源管理器。 /// /// 资源管理器。 public void SetResourceManager(IResourceManager resourceManager) { m_DataProvider.SetResourceManager(resourceManager); } /// /// 设置全局配置数据提供者辅助器。 /// /// 全局配置数据提供者辅助器。 public void SetDataProviderHelper(IDataProviderHelper dataProviderHelper) { m_DataProvider.SetDataProviderHelper(dataProviderHelper); } /// /// 设置全局配置辅助器。 /// /// 全局配置辅助器。 public void SetConfigHelper(IConfigHelper configHelper) { if (configHelper == null) { throw new GameFrameworkException("Config helper is invalid."); } m_ConfigHelper = configHelper; } /// /// 确保二进制流缓存分配足够大小的内存并缓存。 /// /// 要确保二进制流缓存分配内存的大小。 public void EnsureCachedBytesSize(int ensureSize) { DataProvider.EnsureCachedBytesSize(ensureSize); } /// /// 释放缓存的二进制流。 /// public void FreeCachedBytes() { DataProvider.FreeCachedBytes(); } /// /// 读取全局配置。 /// /// 全局配置资源名称。 public void ReadData(string configAssetName) { m_DataProvider.ReadData(configAssetName); } /// /// 读取全局配置。 /// /// 全局配置资源名称。 /// 加载全局配置资源的优先级。 public void ReadData(string configAssetName, int priority) { m_DataProvider.ReadData(configAssetName, priority); } /// /// 读取全局配置。 /// /// 全局配置资源名称。 /// 用户自定义数据。 public void ReadData(string configAssetName, object userData) { m_DataProvider.ReadData(configAssetName, userData); } /// /// 读取全局配置。 /// /// 全局配置资源名称。 /// 加载全局配置资源的优先级。 /// 用户自定义数据。 public void ReadData(string configAssetName, int priority, object userData) { m_DataProvider.ReadData(configAssetName, priority, userData); } /// /// 解析全局配置。 /// /// 要解析的全局配置字符串。 /// 是否解析全局配置成功。 public bool ParseData(string configString) { return m_DataProvider.ParseData(configString); } /// /// 解析全局配置。 /// /// 要解析的全局配置字符串。 /// 用户自定义数据。 /// 是否解析全局配置成功。 public bool ParseData(string configString, object userData) { return m_DataProvider.ParseData(configString, userData); } /// /// 解析全局配置。 /// /// 要解析的全局配置二进制流。 /// 是否解析全局配置成功。 public bool ParseData(byte[] configBytes) { return m_DataProvider.ParseData(configBytes); } /// /// 解析全局配置。 /// /// 要解析的全局配置二进制流。 /// 用户自定义数据。 /// 是否解析全局配置成功。 public bool ParseData(byte[] configBytes, object userData) { return m_DataProvider.ParseData(configBytes, userData); } /// /// 解析全局配置。 /// /// 要解析的全局配置二进制流。 /// 全局配置二进制流的起始位置。 /// 全局配置二进制流的长度。 /// 是否解析全局配置成功。 public bool ParseData(byte[] configBytes, int startIndex, int length) { return m_DataProvider.ParseData(configBytes, startIndex, length); } /// /// 解析全局配置。 /// /// 要解析的全局配置二进制流。 /// 全局配置二进制流的起始位置。 /// 全局配置二进制流的长度。 /// 用户自定义数据。 /// 是否解析全局配置成功。 public bool ParseData(byte[] configBytes, int startIndex, int length, object userData) { return m_DataProvider.ParseData(configBytes, startIndex, length, userData); } /// /// 检查是否存在指定全局配置项。 /// /// 要检查全局配置项的名称。 /// 指定的全局配置项是否存在。 public bool HasConfig(string configName) { return GetConfigData(configName).HasValue; } /// /// 从指定全局配置项中读取布尔值。 /// /// 要获取全局配置项的名称。 /// 读取的布尔值。 public bool GetBool(string configName) { ConfigData? configData = GetConfigData(configName); if (!configData.HasValue) { throw new GameFrameworkException(Utility.Text.Format("Config name '{0}' is not exist.", configName)); } return configData.Value.BoolValue; } /// /// 从指定全局配置项中读取布尔值。 /// /// 要获取全局配置项的名称。 /// 当指定的全局配置项不存在时,返回此默认值。 /// 读取的布尔值。 public bool GetBool(string configName, bool defaultValue) { ConfigData? configData = GetConfigData(configName); return configData.HasValue ? configData.Value.BoolValue : defaultValue; } /// /// 从指定全局配置项中读取整数值。 /// /// 要获取全局配置项的名称。 /// 读取的整数值。 public int GetInt(string configName) { ConfigData? configData = GetConfigData(configName); if (!configData.HasValue) { throw new GameFrameworkException(Utility.Text.Format("Config name '{0}' is not exist.", configName)); } return configData.Value.IntValue; } /// /// 从指定全局配置项中读取整数值。 /// /// 要获取全局配置项的名称。 /// 当指定的全局配置项不存在时,返回此默认值。 /// 读取的整数值。 public int GetInt(string configName, int defaultValue) { ConfigData? configData = GetConfigData(configName); return configData.HasValue ? configData.Value.IntValue : defaultValue; } /// /// 从指定全局配置项中读取浮点数值。 /// /// 要获取全局配置项的名称。 /// 读取的浮点数值。 public float GetFloat(string configName) { ConfigData? configData = GetConfigData(configName); if (!configData.HasValue) { throw new GameFrameworkException(Utility.Text.Format("Config name '{0}' is not exist.", configName)); } return configData.Value.FloatValue; } /// /// 从指定全局配置项中读取浮点数值。 /// /// 要获取全局配置项的名称。 /// 当指定的全局配置项不存在时,返回此默认值。 /// 读取的浮点数值。 public float GetFloat(string configName, float defaultValue) { ConfigData? configData = GetConfigData(configName); return configData.HasValue ? configData.Value.FloatValue : defaultValue; } /// /// 从指定全局配置项中读取字符串值。 /// /// 要获取全局配置项的名称。 /// 读取的字符串值。 public string GetString(string configName) { ConfigData? configData = GetConfigData(configName); if (!configData.HasValue) { throw new GameFrameworkException(Utility.Text.Format("Config name '{0}' is not exist.", configName)); } return configData.Value.StringValue; } /// /// 从指定全局配置项中读取字符串值。 /// /// 要获取全局配置项的名称。 /// 当指定的全局配置项不存在时,返回此默认值。 /// 读取的字符串值。 public string GetString(string configName, string defaultValue) { ConfigData? configData = GetConfigData(configName); return configData.HasValue ? configData.Value.StringValue : defaultValue; } /// /// 增加指定全局配置项。 /// /// 要增加全局配置项的名称。 /// 全局配置项的值。 /// 是否增加全局配置项成功。 public bool AddConfig(string configName, string configValue) { bool boolValue = false; bool.TryParse(configValue, out boolValue); int intValue = 0; int.TryParse(configValue, out intValue); float floatValue = 0f; float.TryParse(configValue, out floatValue); return AddConfig(configName, boolValue, intValue, floatValue, configValue); } /// /// 增加指定全局配置项。 /// /// 要增加全局配置项的名称。 /// 全局配置项布尔值。 /// 全局配置项整数值。 /// 全局配置项浮点数值。 /// 全局配置项字符串值。 /// 是否增加全局配置项成功。 public bool AddConfig(string configName, bool boolValue, int intValue, float floatValue, string stringValue) { if (HasConfig(configName)) { return false; } m_ConfigDatas.Add(configName, new ConfigData(boolValue, intValue, floatValue, stringValue)); return true; } /// /// 移除指定全局配置项。 /// /// 要移除全局配置项的名称。 public bool RemoveConfig(string configName) { if (!HasConfig(configName)) { return false; } return m_ConfigDatas.Remove(configName); } /// /// 清空所有全局配置项。 /// public void RemoveAllConfigs() { m_ConfigDatas.Clear(); } private ConfigData? GetConfigData(string configName) { if (string.IsNullOrEmpty(configName)) { throw new GameFrameworkException("Config name is invalid."); } ConfigData configData = default(ConfigData); if (m_ConfigDatas.TryGetValue(configName, out configData)) { return configData; } return null; } } } ================================================ FILE: GameFramework/Config/IConfigHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Config { /// /// 全局配置辅助器接口。 /// public interface IConfigHelper { } } ================================================ FILE: GameFramework/Config/IConfigManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; namespace GameFramework.Config { /// /// 全局配置管理器接口。 /// public interface IConfigManager : IDataProvider { /// /// 获取全局配置项数量。 /// int Count { get; } /// /// 获取缓冲二进制流的大小。 /// int CachedBytesSize { get; } /// /// 设置资源管理器。 /// /// 资源管理器。 void SetResourceManager(IResourceManager resourceManager); /// /// 设置全局配置数据提供者辅助器。 /// /// 全局配置数据提供者辅助器。 void SetDataProviderHelper(IDataProviderHelper dataProviderHelper); /// /// 设置全局配置辅助器。 /// /// 全局配置辅助器。 void SetConfigHelper(IConfigHelper configHelper); /// /// 确保二进制流缓存分配足够大小的内存并缓存。 /// /// 要确保二进制流缓存分配内存的大小。 void EnsureCachedBytesSize(int ensureSize); /// /// 释放缓存的二进制流。 /// void FreeCachedBytes(); /// /// 检查是否存在指定全局配置项。 /// /// 要检查全局配置项的名称。 /// 指定的全局配置项是否存在。 bool HasConfig(string configName); /// /// 从指定全局配置项中读取布尔值。 /// /// 要获取全局配置项的名称。 /// 读取的布尔值。 bool GetBool(string configName); /// /// 从指定全局配置项中读取布尔值。 /// /// 要获取全局配置项的名称。 /// 当指定的全局配置项不存在时,返回此默认值。 /// 读取的布尔值。 bool GetBool(string configName, bool defaultValue); /// /// 从指定全局配置项中读取整数值。 /// /// 要获取全局配置项的名称。 /// 读取的整数值。 int GetInt(string configName); /// /// 从指定全局配置项中读取整数值。 /// /// 要获取全局配置项的名称。 /// 当指定的全局配置项不存在时,返回此默认值。 /// 读取的整数值。 int GetInt(string configName, int defaultValue); /// /// 从指定全局配置项中读取浮点数值。 /// /// 要获取全局配置项的名称。 /// 读取的浮点数值。 float GetFloat(string configName); /// /// 从指定全局配置项中读取浮点数值。 /// /// 要获取全局配置项的名称。 /// 当指定的全局配置项不存在时,返回此默认值。 /// 读取的浮点数值。 float GetFloat(string configName, float defaultValue); /// /// 从指定全局配置项中读取字符串值。 /// /// 要获取全局配置项的名称。 /// 读取的字符串值。 string GetString(string configName); /// /// 从指定全局配置项中读取字符串值。 /// /// 要获取全局配置项的名称。 /// 当指定的全局配置项不存在时,返回此默认值。 /// 读取的字符串值。 string GetString(string configName, string defaultValue); /// /// 增加指定全局配置项。 /// /// 要增加全局配置项的名称。 /// 全局配置项的值。 /// 是否增加全局配置项成功。 bool AddConfig(string configName, string configValue); /// /// 增加指定全局配置项。 /// /// 要增加全局配置项的名称。 /// 全局配置项布尔值。 /// 全局配置项整数值。 /// 全局配置项浮点数值。 /// 全局配置项字符串值。 /// 是否增加全局配置项成功。 bool AddConfig(string configName, bool boolValue, int intValue, float floatValue, string stringValue); /// /// 移除指定全局配置项。 /// /// 要移除全局配置项的名称。 /// 是否移除全局配置项成功。 bool RemoveConfig(string configName); /// /// 清空所有全局配置项。 /// void RemoveAllConfigs(); } } ================================================ FILE: GameFramework/DataNode/DataNodeManager.DataNode.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.DataNode { internal sealed partial class DataNodeManager : GameFrameworkModule, IDataNodeManager { /// /// 数据结点。 /// private sealed class DataNode : IDataNode, IReference { private static readonly DataNode[] EmptyDataNodeArray = new DataNode[] { }; private string m_Name; private Variable m_Data; private DataNode m_Parent; private List m_Childs; public DataNode() { m_Name = null; m_Data = null; m_Parent = null; m_Childs = null; } /// /// 创建数据结点。 /// /// 数据结点名称。 /// 父数据结点。 /// 创建的数据结点。 public static DataNode Create(string name, DataNode parent) { if (!IsValidName(name)) { throw new GameFrameworkException("Name of data node is invalid."); } DataNode node = ReferencePool.Acquire(); node.m_Name = name; node.m_Parent = parent; return node; } /// /// 获取数据结点的名称。 /// public string Name { get { return m_Name; } } /// /// 获取数据结点的完整名称。 /// public string FullName { get { return m_Parent == null ? m_Name : Utility.Text.Format("{0}{1}{2}", m_Parent.FullName, PathSplitSeparator[0], m_Name); } } /// /// 获取父数据结点。 /// public IDataNode Parent { get { return m_Parent; } } /// /// 获取子数据结点的数量。 /// public int ChildCount { get { return m_Childs != null ? m_Childs.Count : 0; } } /// /// 根据类型获取数据结点的数据。 /// /// 要获取的数据类型。 /// 指定类型的数据。 public T GetData() where T : Variable { return (T)m_Data; } /// /// 获取数据结点的数据。 /// /// 数据结点数据。 public Variable GetData() { return m_Data; } /// /// 设置数据结点的数据。 /// /// 要设置的数据类型。 /// 要设置的数据。 public void SetData(T data) where T : Variable { SetData((Variable)data); } /// /// 设置数据结点的数据。 /// /// 要设置的数据。 public void SetData(Variable data) { if (m_Data != null) { ReferencePool.Release(m_Data); } m_Data = data; } /// /// 根据索引检查是否存在子数据结点。 /// /// 子数据结点的索引。 /// 是否存在子数据结点。 public bool HasChild(int index) { return index >= 0 && index < ChildCount; } /// /// 根据名称检查是否存在子数据结点。 /// /// 子数据结点名称。 /// 是否存在子数据结点。 public bool HasChild(string name) { if (!IsValidName(name)) { throw new GameFrameworkException("Name is invalid."); } if (m_Childs == null) { return false; } foreach (DataNode child in m_Childs) { if (child.Name == name) { return true; } } return false; } /// /// 根据索引获取子数据结点。 /// /// 子数据结点的索引。 /// 指定索引的子数据结点,如果索引越界,则返回空。 public IDataNode GetChild(int index) { return index >= 0 && index < ChildCount ? m_Childs[index] : null; } /// /// 根据名称获取子数据结点。 /// /// 子数据结点名称。 /// 指定名称的子数据结点,如果没有找到,则返回空。 public IDataNode GetChild(string name) { if (!IsValidName(name)) { throw new GameFrameworkException("Name is invalid."); } if (m_Childs == null) { return null; } foreach (DataNode child in m_Childs) { if (child.Name == name) { return child; } } return null; } /// /// 根据名称获取或增加子数据结点。 /// /// 子数据结点名称。 /// 指定名称的子数据结点,如果对应名称的子数据结点已存在,则返回已存在的子数据结点,否则增加子数据结点。 public IDataNode GetOrAddChild(string name) { DataNode node = (DataNode)GetChild(name); if (node != null) { return node; } node = Create(name, this); if (m_Childs == null) { m_Childs = new List(); } m_Childs.Add(node); return node; } /// /// 获取所有子数据结点。 /// /// 所有子数据结点。 public IDataNode[] GetAllChild() { if (m_Childs == null) { return EmptyDataNodeArray; } return m_Childs.ToArray(); } /// /// 获取所有子数据结点。 /// /// 所有子数据结点。 public void GetAllChild(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); if (m_Childs == null) { return; } foreach (DataNode child in m_Childs) { results.Add(child); } } /// /// 根据索引移除子数据结点。 /// /// 子数据结点的索引位置。 public void RemoveChild(int index) { DataNode node = (DataNode)GetChild(index); if (node == null) { return; } m_Childs.Remove(node); ReferencePool.Release(node); } /// /// 根据名称移除子数据结点。 /// /// 子数据结点名称。 public void RemoveChild(string name) { DataNode node = (DataNode)GetChild(name); if (node == null) { return; } m_Childs.Remove(node); ReferencePool.Release(node); } public void Clear() { if (m_Data != null) { ReferencePool.Release(m_Data); m_Data = null; } if (m_Childs != null) { foreach (DataNode child in m_Childs) { ReferencePool.Release(child); } m_Childs.Clear(); } } /// /// 获取数据结点字符串。 /// /// 数据结点字符串。 public override string ToString() { return Utility.Text.Format("{0}: {1}", FullName, ToDataString()); } /// /// 获取数据字符串。 /// /// 数据字符串。 public string ToDataString() { if (m_Data == null) { return ""; } return Utility.Text.Format("[{0}] {1}", m_Data.Type.Name, m_Data); } /// /// 检测数据结点名称是否合法。 /// /// 要检测的数据结点名称。 /// 是否是合法的数据结点名称。 private static bool IsValidName(string name) { if (string.IsNullOrEmpty(name)) { return false; } foreach (string pathSplitSeparator in PathSplitSeparator) { if (name.Contains(pathSplitSeparator)) { return false; } } return true; } void IReference.Clear() { m_Name = null; m_Parent = null; Clear(); } } } } ================================================ FILE: GameFramework/DataNode/DataNodeManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.DataNode { /// /// 数据结点管理器。 /// internal sealed partial class DataNodeManager : GameFrameworkModule, IDataNodeManager { private static readonly string[] EmptyStringArray = new string[] { }; private static readonly string[] PathSplitSeparator = new string[] { ".", "/", "\\" }; private const string RootName = ""; private DataNode m_Root; /// /// 初始化数据结点管理器的新实例。 /// public DataNodeManager() { m_Root = DataNode.Create(RootName, null); } /// /// 获取根数据结点。 /// public IDataNode Root { get { return m_Root; } } /// /// 数据结点管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { } /// /// 关闭并清理数据结点管理器。 /// internal override void Shutdown() { ReferencePool.Release(m_Root); m_Root = null; } /// /// 根据类型获取数据结点的数据。 /// /// 要获取的数据类型。 /// 相对于 node 的查找路径。 /// 指定类型的数据。 public T GetData(string path) where T : Variable { return GetData(path, null); } /// /// 获取数据结点的数据。 /// /// 相对于 node 的查找路径。 /// 数据结点的数据。 public Variable GetData(string path) { return GetData(path, null); } /// /// 根据类型获取数据结点的数据。 /// /// 要获取的数据类型。 /// 相对于 node 的查找路径。 /// 查找起始结点。 /// 指定类型的数据。 public T GetData(string path, IDataNode node) where T : Variable { IDataNode current = GetNode(path, node); if (current == null) { throw new GameFrameworkException(Utility.Text.Format("Data node is not exist, path '{0}', node '{1}'.", path, node != null ? node.FullName : string.Empty)); } return current.GetData(); } /// /// 获取数据结点的数据。 /// /// 相对于 node 的查找路径。 /// 查找起始结点。 /// 数据结点的数据。 public Variable GetData(string path, IDataNode node) { IDataNode current = GetNode(path, node); if (current == null) { throw new GameFrameworkException(Utility.Text.Format("Data node is not exist, path '{0}', node '{1}'.", path, node != null ? node.FullName : string.Empty)); } return current.GetData(); } /// /// 设置数据结点的数据。 /// /// 要设置的数据类型。 /// 相对于 node 的查找路径。 /// 要设置的数据。 public void SetData(string path, T data) where T : Variable { SetData(path, data, null); } /// /// 设置数据结点的数据。 /// /// 相对于 node 的查找路径。 /// 要设置的数据。 public void SetData(string path, Variable data) { SetData(path, data, null); } /// /// 设置数据结点的数据。 /// /// 要设置的数据类型。 /// 相对于 node 的查找路径。 /// 要设置的数据。 /// 查找起始结点。 public void SetData(string path, T data, IDataNode node) where T : Variable { IDataNode current = GetOrAddNode(path, node); current.SetData(data); } /// /// 设置数据结点的数据。 /// /// 相对于 node 的查找路径。 /// 要设置的数据。 /// 查找起始结点。 public void SetData(string path, Variable data, IDataNode node) { IDataNode current = GetOrAddNode(path, node); current.SetData(data); } /// /// 获取数据结点。 /// /// 相对于 node 的查找路径。 /// 指定位置的数据结点,如果没有找到,则返回空。 public IDataNode GetNode(string path) { return GetNode(path, null); } /// /// 获取数据结点。 /// /// 相对于 node 的查找路径。 /// 查找起始结点。 /// 指定位置的数据结点,如果没有找到,则返回空。 public IDataNode GetNode(string path, IDataNode node) { IDataNode current = node ?? m_Root; string[] splitedPath = GetSplitedPath(path); foreach (string i in splitedPath) { current = current.GetChild(i); if (current == null) { return null; } } return current; } /// /// 获取或增加数据结点。 /// /// 相对于 node 的查找路径。 /// 指定位置的数据结点,如果没有找到,则创建相应的数据结点。 public IDataNode GetOrAddNode(string path) { return GetOrAddNode(path, null); } /// /// 获取或增加数据结点。 /// /// 相对于 node 的查找路径。 /// 查找起始结点。 /// 指定位置的数据结点,如果没有找到,则增加相应的数据结点。 public IDataNode GetOrAddNode(string path, IDataNode node) { IDataNode current = node ?? m_Root; string[] splitedPath = GetSplitedPath(path); foreach (string i in splitedPath) { current = current.GetOrAddChild(i); } return current; } /// /// 移除数据结点。 /// /// 相对于 node 的查找路径。 public void RemoveNode(string path) { RemoveNode(path, null); } /// /// 移除数据结点。 /// /// 相对于 node 的查找路径。 /// 查找起始结点。 public void RemoveNode(string path, IDataNode node) { IDataNode current = node ?? m_Root; IDataNode parent = current.Parent; string[] splitedPath = GetSplitedPath(path); foreach (string i in splitedPath) { parent = current; current = current.GetChild(i); if (current == null) { return; } } if (parent != null) { parent.RemoveChild(current.Name); } } /// /// 移除所有数据结点。 /// public void Clear() { m_Root.Clear(); } /// /// 数据结点路径切分工具函数。 /// /// 要切分的数据结点路径。 /// 切分后的字符串数组。 private static string[] GetSplitedPath(string path) { if (string.IsNullOrEmpty(path)) { return EmptyStringArray; } return path.Split(PathSplitSeparator, StringSplitOptions.RemoveEmptyEntries); } } } ================================================ FILE: GameFramework/DataNode/IDataNode.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.DataNode { /// /// 数据结点接口。 /// public interface IDataNode { /// /// 获取数据结点的名称。 /// string Name { get; } /// /// 获取数据结点的完整名称。 /// string FullName { get; } /// /// 获取父数据结点。 /// IDataNode Parent { get; } /// /// 获取子数据结点的数量。 /// int ChildCount { get; } /// /// 根据类型获取数据结点的数据。 /// /// 要获取的数据类型。 /// 指定类型的数据。 T GetData() where T : Variable; /// /// 获取数据结点的数据。 /// /// 数据结点数据。 Variable GetData(); /// /// 设置数据结点的数据。 /// /// 要设置的数据类型。 /// 要设置的数据。 void SetData(T data) where T : Variable; /// /// 设置数据结点的数据。 /// /// 要设置的数据。 void SetData(Variable data); /// /// 根据索引检查是否存在子数据结点。 /// /// 子数据结点的索引。 /// 是否存在子数据结点。 bool HasChild(int index); /// /// 根据名称检查是否存在子数据结点。 /// /// 子数据结点名称。 /// 是否存在子数据结点。 bool HasChild(string name); /// /// 根据索引获取子数据结点。 /// /// 子数据结点的索引。 /// 指定索引的子数据结点,如果索引越界,则返回空。 IDataNode GetChild(int index); /// /// 根据名称获取子数据结点。 /// /// 子数据结点名称。 /// 指定名称的子数据结点,如果没有找到,则返回空。 IDataNode GetChild(string name); /// /// 根据名称获取或增加子数据结点。 /// /// 子数据结点名称。 /// 指定名称的子数据结点,如果对应名称的子数据结点已存在,则返回已存在的子数据结点,否则增加子数据结点。 IDataNode GetOrAddChild(string name); /// /// 获取所有子数据结点。 /// /// 所有子数据结点。 IDataNode[] GetAllChild(); /// /// 获取所有子数据结点。 /// /// 所有子数据结点。 void GetAllChild(List results); /// /// 根据索引移除子数据结点。 /// /// 子数据结点的索引。 void RemoveChild(int index); /// /// 根据名称移除子数据结点。 /// /// 子数据结点名称。 void RemoveChild(string name); /// /// 移除当前数据结点的数据和所有子数据结点。 /// void Clear(); /// /// 获取数据结点字符串。 /// /// 数据结点字符串。 string ToString(); /// /// 获取数据字符串。 /// /// 数据字符串。 string ToDataString(); } } ================================================ FILE: GameFramework/DataNode/IDataNodeManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.DataNode { /// /// 数据结点管理器接口。 /// public interface IDataNodeManager { /// /// 获取根数据结点。 /// IDataNode Root { get; } /// /// 根据类型获取数据结点的数据。 /// /// 要获取的数据类型。 /// 相对于 node 的查找路径。 /// 指定类型的数据。 T GetData(string path) where T : Variable; /// /// 获取数据结点的数据。 /// /// 相对于 node 的查找路径。 /// 数据结点的数据。 Variable GetData(string path); /// /// 根据类型获取数据结点的数据。 /// /// 要获取的数据类型。 /// 相对于 node 的查找路径。 /// 查找起始结点。 /// 指定类型的数据。 T GetData(string path, IDataNode node) where T : Variable; /// /// 获取数据结点的数据。 /// /// 相对于 node 的查找路径。 /// 查找起始结点。 /// 数据结点的数据。 Variable GetData(string path, IDataNode node); /// /// 设置数据结点的数据。 /// /// 要设置的数据类型。 /// 相对于 node 的查找路径。 /// 要设置的数据。 void SetData(string path, T data) where T : Variable; /// /// 设置数据结点的数据。 /// /// 相对于 node 的查找路径。 /// 要设置的数据。 void SetData(string path, Variable data); /// /// 设置数据结点的数据。 /// /// 要设置的数据类型。 /// 相对于 node 的查找路径。 /// 要设置的数据。 /// 查找起始结点。 void SetData(string path, T data, IDataNode node) where T : Variable; /// /// 设置数据结点的数据。 /// /// 相对于 node 的查找路径。 /// 要设置的数据。 /// 查找起始结点。 void SetData(string path, Variable data, IDataNode node); /// /// 获取数据结点。 /// /// 相对于 node 的查找路径。 /// 指定位置的数据结点,如果没有找到,则返回空。 IDataNode GetNode(string path); /// /// 获取数据结点。 /// /// 相对于 node 的查找路径。 /// 查找起始结点。 /// 指定位置的数据结点,如果没有找到,则返回空。 IDataNode GetNode(string path, IDataNode node); /// /// 获取或增加数据结点。 /// /// 相对于 node 的查找路径。 /// 指定位置的数据结点,如果没有找到,则创建相应的数据结点。 IDataNode GetOrAddNode(string path); /// /// 获取或增加数据结点。 /// /// 相对于 node 的查找路径。 /// 查找起始结点。 /// 指定位置的数据结点,如果没有找到,则创建相应的数据结点。 IDataNode GetOrAddNode(string path, IDataNode node); /// /// 移除数据结点。 /// /// 相对于 node 的查找路径。 void RemoveNode(string path); /// /// 移除数据结点。 /// /// 相对于 node 的查找路径。 /// 查找起始结点。 void RemoveNode(string path, IDataNode node); /// /// 移除所有数据结点。 /// void Clear(); } } ================================================ FILE: GameFramework/DataTable/DataTableBase.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; using System; namespace GameFramework.DataTable { /// /// 数据表基类。 /// public abstract class DataTableBase : IDataProvider { private readonly string m_Name; private readonly DataProvider m_DataProvider; /// /// 初始化数据表基类的新实例。 /// public DataTableBase() : this(null) { } /// /// 初始化数据表基类的新实例。 /// /// 数据表名称。 public DataTableBase(string name) { m_Name = name ?? string.Empty; m_DataProvider = new DataProvider(this); } /// /// 获取数据表名称。 /// public string Name { get { return m_Name; } } /// /// 获取数据表完整名称。 /// public string FullName { get { return new TypeNamePair(Type, m_Name).ToString(); } } /// /// 获取数据表行的类型。 /// public abstract Type Type { get; } /// /// 获取数据表行数。 /// public abstract int Count { get; } /// /// 读取数据表成功事件。 /// public event EventHandler ReadDataSuccess { add { m_DataProvider.ReadDataSuccess += value; } remove { m_DataProvider.ReadDataSuccess -= value; } } /// /// 读取数据表失败事件。 /// public event EventHandler ReadDataFailure { add { m_DataProvider.ReadDataFailure += value; } remove { m_DataProvider.ReadDataFailure -= value; } } /// /// 读取数据表更新事件。 /// public event EventHandler ReadDataUpdate { add { m_DataProvider.ReadDataUpdate += value; } remove { m_DataProvider.ReadDataUpdate -= value; } } /// /// 读取数据表时加载依赖资源事件。 /// public event EventHandler ReadDataDependencyAsset { add { m_DataProvider.ReadDataDependencyAsset += value; } remove { m_DataProvider.ReadDataDependencyAsset -= value; } } /// /// 读取数据表。 /// /// 数据表资源名称。 public void ReadData(string dataTableAssetName) { m_DataProvider.ReadData(dataTableAssetName); } /// /// 读取数据表。 /// /// 数据表资源名称。 /// 加载数据表资源的优先级。 public void ReadData(string dataTableAssetName, int priority) { m_DataProvider.ReadData(dataTableAssetName, priority); } /// /// 读取数据表。 /// /// 数据表资源名称。 /// 用户自定义数据。 public void ReadData(string dataTableAssetName, object userData) { m_DataProvider.ReadData(dataTableAssetName, userData); } /// /// 读取数据表。 /// /// 数据表资源名称。 /// 加载数据表资源的优先级。 /// 用户自定义数据。 public void ReadData(string dataTableAssetName, int priority, object userData) { m_DataProvider.ReadData(dataTableAssetName, priority, userData); } /// /// 解析数据表。 /// /// 要解析的数据表字符串。 /// 是否解析数据表成功。 public bool ParseData(string dataTableString) { return m_DataProvider.ParseData(dataTableString); } /// /// 解析数据表。 /// /// 要解析的数据表字符串。 /// 用户自定义数据。 /// 是否解析数据表成功。 public bool ParseData(string dataTableString, object userData) { return m_DataProvider.ParseData(dataTableString, userData); } /// /// 解析数据表。 /// /// 要解析的数据表二进制流。 /// 是否解析数据表成功。 public bool ParseData(byte[] dataTableBytes) { return m_DataProvider.ParseData(dataTableBytes); } /// /// 解析数据表。 /// /// 要解析的数据表二进制流。 /// 用户自定义数据。 /// 是否解析数据表成功。 public bool ParseData(byte[] dataTableBytes, object userData) { return m_DataProvider.ParseData(dataTableBytes, userData); } /// /// 解析数据表。 /// /// 要解析的数据表二进制流。 /// 数据表二进制流的起始位置。 /// 数据表二进制流的长度。 /// 是否解析数据表成功。 public bool ParseData(byte[] dataTableBytes, int startIndex, int length) { return m_DataProvider.ParseData(dataTableBytes, startIndex, length); } /// /// 解析数据表。 /// /// 要解析的数据表二进制流。 /// 数据表二进制流的起始位置。 /// 数据表二进制流的长度。 /// 用户自定义数据。 /// 是否解析数据表成功。 public bool ParseData(byte[] dataTableBytes, int startIndex, int length, object userData) { return m_DataProvider.ParseData(dataTableBytes, startIndex, length, userData); } /// /// 检查是否存在数据表行。 /// /// 数据表行的编号。 /// 是否存在数据表行。 public abstract bool HasDataRow(int id); /// /// 增加数据表行。 /// /// 要解析的数据表行字符串。 /// 用户自定义数据。 /// 是否增加数据表行成功。 public abstract bool AddDataRow(string dataRowString, object userData); /// /// 增加数据表行。 /// /// 要解析的数据表行二进制流。 /// 数据表行二进制流的起始位置。 /// 数据表行二进制流的长度。 /// 用户自定义数据。 /// 是否增加数据表行成功。 public abstract bool AddDataRow(byte[] dataRowBytes, int startIndex, int length, object userData); /// /// 移除指定数据表行。 /// /// 要移除数据表行的编号。 /// 是否移除数据表行成功。 public abstract bool RemoveDataRow(int id); /// /// 清空所有数据表行。 /// public abstract void RemoveAllDataRows(); /// /// 设置资源管理器。 /// /// 资源管理器。 internal void SetResourceManager(IResourceManager resourceManager) { m_DataProvider.SetResourceManager(resourceManager); } /// /// 设置数据提供者辅助器。 /// /// 数据提供者辅助器。 internal void SetDataProviderHelper(IDataProviderHelper dataProviderHelper) { m_DataProvider.SetDataProviderHelper(dataProviderHelper); } /// /// 关闭并清理数据表。 /// internal abstract void Shutdown(); } } ================================================ FILE: GameFramework/DataTable/DataTableManager.DataTable.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections; using System.Collections.Generic; namespace GameFramework.DataTable { internal sealed partial class DataTableManager : GameFrameworkModule, IDataTableManager { /// /// 数据表。 /// /// 数据表行的类型。 private sealed class DataTable : DataTableBase, IDataTable where T : class, IDataRow, new() { private readonly Dictionary m_DataSet; private T m_MinIdDataRow; private T m_MaxIdDataRow; /// /// 初始化数据表的新实例。 /// /// 数据表名称。 public DataTable(string name) : base(name) { m_DataSet = new Dictionary(); m_MinIdDataRow = null; m_MaxIdDataRow = null; } /// /// 获取数据表行的类型。 /// public override Type Type { get { return typeof(T); } } /// /// 获取数据表行数。 /// public override int Count { get { return m_DataSet.Count; } } /// /// 获取数据表行。 /// /// 数据表行的编号。 /// 数据表行。 public T this[int id] { get { return GetDataRow(id); } } /// /// 获取编号最小的数据表行。 /// public T MinIdDataRow { get { return m_MinIdDataRow; } } /// /// 获取编号最大的数据表行。 /// public T MaxIdDataRow { get { return m_MaxIdDataRow; } } /// /// 检查是否存在数据表行。 /// /// 数据表行的编号。 /// 是否存在数据表行。 public override bool HasDataRow(int id) { return m_DataSet.ContainsKey(id); } /// /// 检查是否存在数据表行。 /// /// 要检查的条件。 /// 是否存在数据表行。 public bool HasDataRow(Predicate condition) { if (condition == null) { throw new GameFrameworkException("Condition is invalid."); } foreach (KeyValuePair dataRow in m_DataSet) { if (condition(dataRow.Value)) { return true; } } return false; } /// /// 获取数据表行。 /// /// 数据表行的编号。 /// 数据表行。 public T GetDataRow(int id) { T dataRow = null; if (m_DataSet.TryGetValue(id, out dataRow)) { return dataRow; } return null; } /// /// 获取符合条件的数据表行。 /// /// 要检查的条件。 /// 符合条件的数据表行。 /// 当存在多个符合条件的数据表行时,仅返回第一个符合条件的数据表行。 public T GetDataRow(Predicate condition) { if (condition == null) { throw new GameFrameworkException("Condition is invalid."); } foreach (KeyValuePair dataRow in m_DataSet) { if (condition(dataRow.Value)) { return dataRow.Value; } } return null; } /// /// 获取符合条件的数据表行。 /// /// 要检查的条件。 /// 符合条件的数据表行。 public T[] GetDataRows(Predicate condition) { if (condition == null) { throw new GameFrameworkException("Condition is invalid."); } List results = new List(); foreach (KeyValuePair dataRow in m_DataSet) { if (condition(dataRow.Value)) { results.Add(dataRow.Value); } } return results.ToArray(); } /// /// 获取符合条件的数据表行。 /// /// 要检查的条件。 /// 符合条件的数据表行。 public void GetDataRows(Predicate condition, List results) { if (condition == null) { throw new GameFrameworkException("Condition is invalid."); } if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair dataRow in m_DataSet) { if (condition(dataRow.Value)) { results.Add(dataRow.Value); } } } /// /// 获取排序后的数据表行。 /// /// 要排序的条件。 /// 排序后的数据表行。 public T[] GetDataRows(Comparison comparison) { if (comparison == null) { throw new GameFrameworkException("Comparison is invalid."); } List results = new List(); foreach (KeyValuePair dataRow in m_DataSet) { results.Add(dataRow.Value); } results.Sort(comparison); return results.ToArray(); } /// /// 获取排序后的数据表行。 /// /// 要排序的条件。 /// 排序后的数据表行。 public void GetDataRows(Comparison comparison, List results) { if (comparison == null) { throw new GameFrameworkException("Comparison is invalid."); } if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair dataRow in m_DataSet) { results.Add(dataRow.Value); } results.Sort(comparison); } /// /// 获取排序后的符合条件的数据表行。 /// /// 要检查的条件。 /// 要排序的条件。 /// 排序后的符合条件的数据表行。 public T[] GetDataRows(Predicate condition, Comparison comparison) { if (condition == null) { throw new GameFrameworkException("Condition is invalid."); } if (comparison == null) { throw new GameFrameworkException("Comparison is invalid."); } List results = new List(); foreach (KeyValuePair dataRow in m_DataSet) { if (condition(dataRow.Value)) { results.Add(dataRow.Value); } } results.Sort(comparison); return results.ToArray(); } /// /// 获取排序后的符合条件的数据表行。 /// /// 要检查的条件。 /// 要排序的条件。 /// 排序后的符合条件的数据表行。 public void GetDataRows(Predicate condition, Comparison comparison, List results) { if (condition == null) { throw new GameFrameworkException("Condition is invalid."); } if (comparison == null) { throw new GameFrameworkException("Comparison is invalid."); } if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair dataRow in m_DataSet) { if (condition(dataRow.Value)) { results.Add(dataRow.Value); } } results.Sort(comparison); } /// /// 获取所有数据表行。 /// /// 所有数据表行。 public T[] GetAllDataRows() { int index = 0; T[] results = new T[m_DataSet.Count]; foreach (KeyValuePair dataRow in m_DataSet) { results[index++] = dataRow.Value; } return results; } /// /// 获取所有数据表行。 /// /// 所有数据表行。 public void GetAllDataRows(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair dataRow in m_DataSet) { results.Add(dataRow.Value); } } /// /// 增加数据表行。 /// /// 要解析的数据表行字符串。 /// 用户自定义数据。 /// 是否增加数据表行成功。 public override bool AddDataRow(string dataRowString, object userData) { try { T dataRow = new T(); if (!dataRow.ParseDataRow(dataRowString, userData)) { return false; } InternalAddDataRow(dataRow); return true; } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Utility.Text.Format("Can not parse data row string for data table '{0}' with exception '{1}'.", new TypeNamePair(typeof(T), Name), exception), exception); } } /// /// 增加数据表行。 /// /// 要解析的数据表行二进制流。 /// 数据表行二进制流的起始位置。 /// 数据表行二进制流的长度。 /// 用户自定义数据。 /// 是否增加数据表行成功。 public override bool AddDataRow(byte[] dataRowBytes, int startIndex, int length, object userData) { try { T dataRow = new T(); if (!dataRow.ParseDataRow(dataRowBytes, startIndex, length, userData)) { return false; } InternalAddDataRow(dataRow); return true; } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Utility.Text.Format("Can not parse data row bytes for data table '{0}' with exception '{1}'.", new TypeNamePair(typeof(T), Name), exception), exception); } } /// /// 移除指定数据表行。 /// /// 要移除数据表行的编号。 /// 是否移除数据表行成功。 public override bool RemoveDataRow(int id) { if (!HasDataRow(id)) { return false; } if (!m_DataSet.Remove(id)) { return false; } if (m_MinIdDataRow != null && m_MinIdDataRow.Id == id || m_MaxIdDataRow != null && m_MaxIdDataRow.Id == id) { m_MinIdDataRow = null; m_MaxIdDataRow = null; foreach (KeyValuePair dataRow in m_DataSet) { if (m_MinIdDataRow == null || m_MinIdDataRow.Id > dataRow.Key) { m_MinIdDataRow = dataRow.Value; } if (m_MaxIdDataRow == null || m_MaxIdDataRow.Id < dataRow.Key) { m_MaxIdDataRow = dataRow.Value; } } } return true; } /// /// 清空所有数据表行。 /// public override void RemoveAllDataRows() { m_DataSet.Clear(); m_MinIdDataRow = null; m_MaxIdDataRow = null; } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 public IEnumerator GetEnumerator() { return m_DataSet.Values.GetEnumerator(); } /// /// 返回循环访问集合的枚举数。 /// /// 循环访问集合的枚举数。 IEnumerator IEnumerable.GetEnumerator() { return m_DataSet.Values.GetEnumerator(); } /// /// 关闭并清理数据表。 /// internal override void Shutdown() { m_DataSet.Clear(); } private void InternalAddDataRow(T dataRow) { if (m_DataSet.ContainsKey(dataRow.Id)) { throw new GameFrameworkException(Utility.Text.Format("Already exist '{0}' in data table '{1}'.", dataRow.Id, new TypeNamePair(typeof(T), Name))); } m_DataSet.Add(dataRow.Id, dataRow); if (m_MinIdDataRow == null || m_MinIdDataRow.Id > dataRow.Id) { m_MinIdDataRow = dataRow; } if (m_MaxIdDataRow == null || m_MaxIdDataRow.Id < dataRow.Id) { m_MaxIdDataRow = dataRow; } } } } } ================================================ FILE: GameFramework/DataTable/DataTableManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.DataTable { /// /// 数据表管理器。 /// internal sealed partial class DataTableManager : GameFrameworkModule, IDataTableManager { private readonly Dictionary m_DataTables; private IResourceManager m_ResourceManager; private IDataProviderHelper m_DataProviderHelper; private IDataTableHelper m_DataTableHelper; /// /// 初始化数据表管理器的新实例。 /// public DataTableManager() { m_DataTables = new Dictionary(); m_ResourceManager = null; m_DataProviderHelper = null; m_DataTableHelper = null; } /// /// 获取数据表数量。 /// public int Count { get { return m_DataTables.Count; } } /// /// 获取缓冲二进制流的大小。 /// public int CachedBytesSize { get { return DataProvider.CachedBytesSize; } } /// /// 数据表管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { } /// /// 关闭并清理数据表管理器。 /// internal override void Shutdown() { foreach (KeyValuePair dataTable in m_DataTables) { dataTable.Value.Shutdown(); } m_DataTables.Clear(); } /// /// 设置资源管理器。 /// /// 资源管理器。 public void SetResourceManager(IResourceManager resourceManager) { if (resourceManager == null) { throw new GameFrameworkException("Resource manager is invalid."); } m_ResourceManager = resourceManager; } /// /// 设置数据表数据提供者辅助器。 /// /// 数据表数据提供者辅助器。 public void SetDataProviderHelper(IDataProviderHelper dataProviderHelper) { if (dataProviderHelper == null) { throw new GameFrameworkException("Data provider helper is invalid."); } m_DataProviderHelper = dataProviderHelper; } /// /// 设置数据表辅助器。 /// /// 数据表辅助器。 public void SetDataTableHelper(IDataTableHelper dataTableHelper) { if (dataTableHelper == null) { throw new GameFrameworkException("Data table helper is invalid."); } m_DataTableHelper = dataTableHelper; } /// /// 确保二进制流缓存分配足够大小的内存并缓存。 /// /// 要确保二进制流缓存分配内存的大小。 public void EnsureCachedBytesSize(int ensureSize) { DataProvider.EnsureCachedBytesSize(ensureSize); } /// /// 释放缓存的二进制流。 /// public void FreeCachedBytes() { DataProvider.FreeCachedBytes(); } /// /// 是否存在数据表。 /// /// 数据表行的类型。 /// 是否存在数据表。 public bool HasDataTable() where T : IDataRow { return InternalHasDataTable(new TypeNamePair(typeof(T))); } /// /// 是否存在数据表。 /// /// 数据表行的类型。 /// 是否存在数据表。 public bool HasDataTable(Type dataRowType) { if (dataRowType == null) { throw new GameFrameworkException("Data row type is invalid."); } if (!typeof(IDataRow).IsAssignableFrom(dataRowType)) { throw new GameFrameworkException(Utility.Text.Format("Data row type '{0}' is invalid.", dataRowType.FullName)); } return InternalHasDataTable(new TypeNamePair(dataRowType)); } /// /// 是否存在数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 是否存在数据表。 public bool HasDataTable(string name) where T : IDataRow { return InternalHasDataTable(new TypeNamePair(typeof(T), name)); } /// /// 是否存在数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 是否存在数据表。 public bool HasDataTable(Type dataRowType, string name) { if (dataRowType == null) { throw new GameFrameworkException("Data row type is invalid."); } if (!typeof(IDataRow).IsAssignableFrom(dataRowType)) { throw new GameFrameworkException(Utility.Text.Format("Data row type '{0}' is invalid.", dataRowType.FullName)); } return InternalHasDataTable(new TypeNamePair(dataRowType, name)); } /// /// 获取数据表。 /// /// 数据表行的类型。 /// 要获取的数据表。 public IDataTable GetDataTable() where T : IDataRow { return (IDataTable)InternalGetDataTable(new TypeNamePair(typeof(T))); } /// /// 获取数据表。 /// /// 数据表行的类型。 /// 要获取的数据表。 public DataTableBase GetDataTable(Type dataRowType) { if (dataRowType == null) { throw new GameFrameworkException("Data row type is invalid."); } if (!typeof(IDataRow).IsAssignableFrom(dataRowType)) { throw new GameFrameworkException(Utility.Text.Format("Data row type '{0}' is invalid.", dataRowType.FullName)); } return InternalGetDataTable(new TypeNamePair(dataRowType)); } /// /// 获取数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 要获取的数据表。 public IDataTable GetDataTable(string name) where T : IDataRow { return (IDataTable)InternalGetDataTable(new TypeNamePair(typeof(T), name)); } /// /// 获取数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 要获取的数据表。 public DataTableBase GetDataTable(Type dataRowType, string name) { if (dataRowType == null) { throw new GameFrameworkException("Data row type is invalid."); } if (!typeof(IDataRow).IsAssignableFrom(dataRowType)) { throw new GameFrameworkException(Utility.Text.Format("Data row type '{0}' is invalid.", dataRowType.FullName)); } return InternalGetDataTable(new TypeNamePair(dataRowType, name)); } /// /// 获取所有数据表。 /// /// 所有数据表。 public DataTableBase[] GetAllDataTables() { int index = 0; DataTableBase[] results = new DataTableBase[m_DataTables.Count]; foreach (KeyValuePair dataTable in m_DataTables) { results[index++] = dataTable.Value; } return results; } /// /// 获取所有数据表。 /// /// 所有数据表。 public void GetAllDataTables(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair dataTable in m_DataTables) { results.Add(dataTable.Value); } } /// /// 创建数据表。 /// /// 数据表行的类型。 /// 要创建的数据表。 public IDataTable CreateDataTable() where T : class, IDataRow, new() { return CreateDataTable(string.Empty); } /// /// 创建数据表。 /// /// 数据表行的类型。 /// 要创建的数据表。 public DataTableBase CreateDataTable(Type dataRowType) { return CreateDataTable(dataRowType, string.Empty); } /// /// 创建数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 要创建的数据表。 public IDataTable CreateDataTable(string name) where T : class, IDataRow, new() { if (m_ResourceManager == null) { throw new GameFrameworkException("You must set resource manager first."); } if (m_DataProviderHelper == null) { throw new GameFrameworkException("You must set data provider helper first."); } TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name); if (HasDataTable(name)) { throw new GameFrameworkException(Utility.Text.Format("Already exist data table '{0}'.", typeNamePair)); } DataTable dataTable = new DataTable(name); dataTable.SetResourceManager(m_ResourceManager); dataTable.SetDataProviderHelper(m_DataProviderHelper); m_DataTables.Add(typeNamePair, dataTable); return dataTable; } /// /// 创建数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 要创建的数据表。 public DataTableBase CreateDataTable(Type dataRowType, string name) { if (m_ResourceManager == null) { throw new GameFrameworkException("You must set resource manager first."); } if (m_DataProviderHelper == null) { throw new GameFrameworkException("You must set data provider helper first."); } if (dataRowType == null) { throw new GameFrameworkException("Data row type is invalid."); } if (!typeof(IDataRow).IsAssignableFrom(dataRowType)) { throw new GameFrameworkException(Utility.Text.Format("Data row type '{0}' is invalid.", dataRowType.FullName)); } TypeNamePair typeNamePair = new TypeNamePair(dataRowType, name); if (HasDataTable(dataRowType, name)) { throw new GameFrameworkException(Utility.Text.Format("Already exist data table '{0}'.", typeNamePair)); } Type dataTableType = typeof(DataTable<>).MakeGenericType(dataRowType); DataTableBase dataTable = (DataTableBase)Activator.CreateInstance(dataTableType, name); dataTable.SetResourceManager(m_ResourceManager); dataTable.SetDataProviderHelper(m_DataProviderHelper); m_DataTables.Add(typeNamePair, dataTable); return dataTable; } /// /// 销毁数据表。 /// /// 数据表行的类型。 public bool DestroyDataTable() where T : IDataRow { return InternalDestroyDataTable(new TypeNamePair(typeof(T))); } /// /// 销毁数据表。 /// /// 数据表行的类型。 /// 是否销毁数据表成功。 public bool DestroyDataTable(Type dataRowType) { if (dataRowType == null) { throw new GameFrameworkException("Data row type is invalid."); } if (!typeof(IDataRow).IsAssignableFrom(dataRowType)) { throw new GameFrameworkException(Utility.Text.Format("Data row type '{0}' is invalid.", dataRowType.FullName)); } return InternalDestroyDataTable(new TypeNamePair(dataRowType)); } /// /// 销毁数据表。 /// /// 数据表行的类型。 /// 数据表名称。 public bool DestroyDataTable(string name) where T : IDataRow { return InternalDestroyDataTable(new TypeNamePair(typeof(T), name)); } /// /// 销毁数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 是否销毁数据表成功。 public bool DestroyDataTable(Type dataRowType, string name) { if (dataRowType == null) { throw new GameFrameworkException("Data row type is invalid."); } if (!typeof(IDataRow).IsAssignableFrom(dataRowType)) { throw new GameFrameworkException(Utility.Text.Format("Data row type '{0}' is invalid.", dataRowType.FullName)); } return InternalDestroyDataTable(new TypeNamePair(dataRowType, name)); } /// /// 销毁数据表。 /// /// 数据表行的类型。 /// 要销毁的数据表。 /// 是否销毁数据表成功。 public bool DestroyDataTable(IDataTable dataTable) where T : IDataRow { if (dataTable == null) { throw new GameFrameworkException("Data table is invalid."); } return InternalDestroyDataTable(new TypeNamePair(typeof(T), dataTable.Name)); } /// /// 销毁数据表。 /// /// 要销毁的数据表。 /// 是否销毁数据表成功。 public bool DestroyDataTable(DataTableBase dataTable) { if (dataTable == null) { throw new GameFrameworkException("Data table is invalid."); } return InternalDestroyDataTable(new TypeNamePair(dataTable.Type, dataTable.Name)); } private bool InternalHasDataTable(TypeNamePair typeNamePair) { return m_DataTables.ContainsKey(typeNamePair); } private DataTableBase InternalGetDataTable(TypeNamePair typeNamePair) { DataTableBase dataTable = null; if (m_DataTables.TryGetValue(typeNamePair, out dataTable)) { return dataTable; } return null; } private bool InternalDestroyDataTable(TypeNamePair typeNamePair) { DataTableBase dataTable = null; if (m_DataTables.TryGetValue(typeNamePair, out dataTable)) { dataTable.Shutdown(); return m_DataTables.Remove(typeNamePair); } return false; } } } ================================================ FILE: GameFramework/DataTable/IDataRow.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.DataTable { /// /// 数据表行接口。 /// public interface IDataRow { /// /// 获取数据表行的编号。 /// int Id { get; } /// /// 解析数据表行。 /// /// 要解析的数据表行字符串。 /// 用户自定义数据。 /// 是否解析数据表行成功。 bool ParseDataRow(string dataRowString, object userData); /// /// 解析数据表行。 /// /// 要解析的数据表行二进制流。 /// 数据表行二进制流的起始位置。 /// 数据表行二进制流的长度。 /// 用户自定义数据。 /// 是否解析数据表行成功。 bool ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData); } } ================================================ FILE: GameFramework/DataTable/IDataTable.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.DataTable { /// /// 数据表接口。 /// /// 数据表行的类型。 public interface IDataTable : IEnumerable where T : IDataRow { /// /// 获取数据表名称。 /// string Name { get; } /// /// 获取数据表完整名称。 /// string FullName { get; } /// /// 获取数据表行的类型。 /// Type Type { get; } /// /// 获取数据表行数。 /// int Count { get; } /// /// 获取数据表行。 /// /// 数据表行的编号。 /// 数据表行。 T this[int id] { get; } /// /// 获取编号最小的数据表行。 /// T MinIdDataRow { get; } /// /// 获取编号最大的数据表行。 /// T MaxIdDataRow { get; } /// /// 检查是否存在数据表行。 /// /// 数据表行的编号。 /// 是否存在数据表行。 bool HasDataRow(int id); /// /// 检查是否存在数据表行。 /// /// 要检查的条件。 /// 是否存在数据表行。 bool HasDataRow(Predicate condition); /// /// 获取数据表行。 /// /// 数据表行的编号。 /// 数据表行。 T GetDataRow(int id); /// /// 获取符合条件的数据表行。 /// /// 要检查的条件。 /// 符合条件的数据表行。 /// 当存在多个符合条件的数据表行时,仅返回第一个符合条件的数据表行。 T GetDataRow(Predicate condition); /// /// 获取符合条件的数据表行。 /// /// 要检查的条件。 /// 符合条件的数据表行。 T[] GetDataRows(Predicate condition); /// /// 获取符合条件的数据表行。 /// /// 要检查的条件。 /// 符合条件的数据表行。 void GetDataRows(Predicate condition, List results); /// /// 获取排序后的数据表行。 /// /// 要排序的条件。 /// 排序后的数据表行。 T[] GetDataRows(Comparison comparison); /// /// 获取排序后的数据表行。 /// /// 要排序的条件。 /// 排序后的数据表行。 void GetDataRows(Comparison comparison, List results); /// /// 获取排序后的符合条件的数据表行。 /// /// 要检查的条件。 /// 要排序的条件。 /// 排序后的符合条件的数据表行。 T[] GetDataRows(Predicate condition, Comparison comparison); /// /// 获取排序后的符合条件的数据表行。 /// /// 要检查的条件。 /// 要排序的条件。 /// 排序后的符合条件的数据表行。 void GetDataRows(Predicate condition, Comparison comparison, List results); /// /// 获取所有数据表行。 /// /// 所有数据表行。 T[] GetAllDataRows(); /// /// 获取所有数据表行。 /// /// 所有数据表行。 void GetAllDataRows(List results); /// /// 增加数据表行。 /// /// 要解析的数据表行字符串。 /// 用户自定义数据。 /// 是否增加数据表行成功。 bool AddDataRow(string dataRowString, object userData); /// /// 增加数据表行。 /// /// 要解析的数据表行二进制流。 /// 数据表行二进制流的起始位置。 /// 数据表行二进制流的长度。 /// 用户自定义数据。 /// 是否增加数据表行成功。 bool AddDataRow(byte[] dataRowBytes, int startIndex, int length, object userData); /// /// 移除指定数据表行。 /// /// 要移除数据表行的编号。 /// 是否移除数据表行成功。 bool RemoveDataRow(int id); /// /// 清空所有数据表行。 /// void RemoveAllDataRows(); } } ================================================ FILE: GameFramework/DataTable/IDataTableHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.DataTable { /// /// 数据表辅助器接口。 /// public interface IDataTableHelper { } } ================================================ FILE: GameFramework/DataTable/IDataTableManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.DataTable { /// /// 数据表管理器接口。 /// public interface IDataTableManager { /// /// 获取数据表数量。 /// int Count { get; } /// /// 获取缓冲二进制流的大小。 /// int CachedBytesSize { get; } /// /// 设置资源管理器。 /// /// 资源管理器。 void SetResourceManager(IResourceManager resourceManager); /// /// 设置数据表数据提供者辅助器。 /// /// 数据表数据提供者辅助器。 void SetDataProviderHelper(IDataProviderHelper dataProviderHelper); /// /// 设置数据表辅助器。 /// /// 数据表辅助器。 void SetDataTableHelper(IDataTableHelper dataTableHelper); /// /// 确保二进制流缓存分配足够大小的内存并缓存。 /// /// 要确保二进制流缓存分配内存的大小。 void EnsureCachedBytesSize(int ensureSize); /// /// 释放缓存的二进制流。 /// void FreeCachedBytes(); /// /// 是否存在数据表。 /// /// 数据表行的类型。 /// 是否存在数据表。 bool HasDataTable() where T : IDataRow; /// /// 是否存在数据表。 /// /// 数据表行的类型。 /// 是否存在数据表。 bool HasDataTable(Type dataRowType); /// /// 是否存在数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 是否存在数据表。 bool HasDataTable(string name) where T : IDataRow; /// /// 是否存在数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 是否存在数据表。 bool HasDataTable(Type dataRowType, string name); /// /// 获取数据表。 /// /// 数据表行的类型。 /// 要获取的数据表。 IDataTable GetDataTable() where T : IDataRow; /// /// 获取数据表。 /// /// 数据表行的类型。 /// 要获取的数据表。 DataTableBase GetDataTable(Type dataRowType); /// /// 获取数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 要获取的数据表。 IDataTable GetDataTable(string name) where T : IDataRow; /// /// 获取数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 要获取的数据表。 DataTableBase GetDataTable(Type dataRowType, string name); /// /// 获取所有数据表。 /// /// 所有数据表。 DataTableBase[] GetAllDataTables(); /// /// 获取所有数据表。 /// /// 所有数据表。 void GetAllDataTables(List results); /// /// 创建数据表。 /// /// 数据表行的类型。 /// 要创建的数据表。 IDataTable CreateDataTable() where T : class, IDataRow, new(); /// /// 创建数据表。 /// /// 数据表行的类型。 /// 要创建的数据表。 DataTableBase CreateDataTable(Type dataRowType); /// /// 创建数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 要创建的数据表。 IDataTable CreateDataTable(string name) where T : class, IDataRow, new(); /// /// 创建数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 要创建的数据表。 DataTableBase CreateDataTable(Type dataRowType, string name); /// /// 销毁数据表。 /// /// 数据表行的类型。 /// 是否销毁数据表成功。 bool DestroyDataTable() where T : IDataRow; /// /// 销毁数据表。 /// /// 数据表行的类型。 /// 是否销毁数据表成功。 bool DestroyDataTable(Type dataRowType); /// /// 销毁数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 是否销毁数据表成功。 bool DestroyDataTable(string name) where T : IDataRow; /// /// 销毁数据表。 /// /// 数据表行的类型。 /// 数据表名称。 /// 是否销毁数据表成功。 bool DestroyDataTable(Type dataRowType, string name); /// /// 销毁数据表。 /// /// 数据表行的类型。 /// 要销毁的数据表。 /// 是否销毁数据表成功。 bool DestroyDataTable(IDataTable dataTable) where T : IDataRow; /// /// 销毁数据表。 /// /// 要销毁的数据表。 /// 是否销毁数据表成功。 bool DestroyDataTable(DataTableBase dataTable); } } ================================================ FILE: GameFramework/Debugger/DebuggerManager.DebuggerWindowGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.Debugger { internal sealed partial class DebuggerManager : GameFrameworkModule, IDebuggerManager { /// /// 调试器窗口组。 /// private sealed class DebuggerWindowGroup : IDebuggerWindowGroup { private readonly List> m_DebuggerWindows; private int m_SelectedIndex; private string[] m_DebuggerWindowNames; public DebuggerWindowGroup() { m_DebuggerWindows = new List>(); m_SelectedIndex = 0; m_DebuggerWindowNames = null; } /// /// 获取调试器窗口数量。 /// public int DebuggerWindowCount { get { return m_DebuggerWindows.Count; } } /// /// 获取或设置当前选中的调试器窗口索引。 /// public int SelectedIndex { get { return m_SelectedIndex; } set { m_SelectedIndex = value; } } /// /// 获取当前选中的调试器窗口。 /// public IDebuggerWindow SelectedWindow { get { if (m_SelectedIndex >= m_DebuggerWindows.Count) { return null; } return m_DebuggerWindows[m_SelectedIndex].Value; } } /// /// 初始化调试组。 /// /// 初始化调试组参数。 public void Initialize(params object[] args) { } /// /// 关闭调试组。 /// public void Shutdown() { foreach (KeyValuePair debuggerWindow in m_DebuggerWindows) { debuggerWindow.Value.Shutdown(); } m_DebuggerWindows.Clear(); } /// /// 进入调试器窗口。 /// public void OnEnter() { SelectedWindow.OnEnter(); } /// /// 离开调试器窗口。 /// public void OnLeave() { SelectedWindow.OnLeave(); } /// /// 调试组轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void OnUpdate(float elapseSeconds, float realElapseSeconds) { SelectedWindow.OnUpdate(elapseSeconds, realElapseSeconds); } /// /// 调试器窗口绘制。 /// public void OnDraw() { } private void RefreshDebuggerWindowNames() { int index = 0; m_DebuggerWindowNames = new string[m_DebuggerWindows.Count]; foreach (KeyValuePair debuggerWindow in m_DebuggerWindows) { m_DebuggerWindowNames[index++] = debuggerWindow.Key; } } /// /// 获取调试组的调试器窗口名称集合。 /// public string[] GetDebuggerWindowNames() { return m_DebuggerWindowNames; } /// /// 获取调试器窗口。 /// /// 调试器窗口路径。 /// 要获取的调试器窗口。 public IDebuggerWindow GetDebuggerWindow(string path) { if (string.IsNullOrEmpty(path)) { return null; } int pos = path.IndexOf('/'); if (pos < 0 || pos >= path.Length - 1) { return InternalGetDebuggerWindow(path); } string debuggerWindowGroupName = path.Substring(0, pos); string leftPath = path.Substring(pos + 1); DebuggerWindowGroup debuggerWindowGroup = (DebuggerWindowGroup)InternalGetDebuggerWindow(debuggerWindowGroupName); if (debuggerWindowGroup == null) { return null; } return debuggerWindowGroup.GetDebuggerWindow(leftPath); } /// /// 选中调试器窗口。 /// /// 调试器窗口路径。 /// 是否成功选中调试器窗口。 public bool SelectDebuggerWindow(string path) { if (string.IsNullOrEmpty(path)) { return false; } int pos = path.IndexOf('/'); if (pos < 0 || pos >= path.Length - 1) { return InternalSelectDebuggerWindow(path); } string debuggerWindowGroupName = path.Substring(0, pos); string leftPath = path.Substring(pos + 1); DebuggerWindowGroup debuggerWindowGroup = (DebuggerWindowGroup)InternalGetDebuggerWindow(debuggerWindowGroupName); if (debuggerWindowGroup == null || !InternalSelectDebuggerWindow(debuggerWindowGroupName)) { return false; } return debuggerWindowGroup.SelectDebuggerWindow(leftPath); } /// /// 注册调试器窗口。 /// /// 调试器窗口路径。 /// 要注册的调试器窗口。 public void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow) { if (string.IsNullOrEmpty(path)) { throw new GameFrameworkException("Path is invalid."); } int pos = path.IndexOf('/'); if (pos < 0 || pos >= path.Length - 1) { if (InternalGetDebuggerWindow(path) != null) { throw new GameFrameworkException("Debugger window has been registered."); } m_DebuggerWindows.Add(new KeyValuePair(path, debuggerWindow)); RefreshDebuggerWindowNames(); } else { string debuggerWindowGroupName = path.Substring(0, pos); string leftPath = path.Substring(pos + 1); DebuggerWindowGroup debuggerWindowGroup = (DebuggerWindowGroup)InternalGetDebuggerWindow(debuggerWindowGroupName); if (debuggerWindowGroup == null) { if (InternalGetDebuggerWindow(debuggerWindowGroupName) != null) { throw new GameFrameworkException("Debugger window has been registered, can not create debugger window group."); } debuggerWindowGroup = new DebuggerWindowGroup(); m_DebuggerWindows.Add(new KeyValuePair(debuggerWindowGroupName, debuggerWindowGroup)); RefreshDebuggerWindowNames(); } debuggerWindowGroup.RegisterDebuggerWindow(leftPath, debuggerWindow); } } /// /// 解除注册调试器窗口。 /// /// 调试器窗口路径。 /// 是否解除注册调试器窗口成功。 public bool UnregisterDebuggerWindow(string path) { if (string.IsNullOrEmpty(path)) { return false; } int pos = path.IndexOf('/'); if (pos < 0 || pos >= path.Length - 1) { IDebuggerWindow debuggerWindow = InternalGetDebuggerWindow(path); bool result = m_DebuggerWindows.Remove(new KeyValuePair(path, debuggerWindow)); debuggerWindow.Shutdown(); RefreshDebuggerWindowNames(); return result; } string debuggerWindowGroupName = path.Substring(0, pos); string leftPath = path.Substring(pos + 1); DebuggerWindowGroup debuggerWindowGroup = (DebuggerWindowGroup)InternalGetDebuggerWindow(debuggerWindowGroupName); if (debuggerWindowGroup == null) { return false; } return debuggerWindowGroup.UnregisterDebuggerWindow(leftPath); } private IDebuggerWindow InternalGetDebuggerWindow(string name) { foreach (KeyValuePair debuggerWindow in m_DebuggerWindows) { if (debuggerWindow.Key == name) { return debuggerWindow.Value; } } return null; } private bool InternalSelectDebuggerWindow(string name) { for (int i = 0; i < m_DebuggerWindows.Count; i++) { if (m_DebuggerWindows[i].Key == name) { m_SelectedIndex = i; return true; } } return false; } } } } ================================================ FILE: GameFramework/Debugger/DebuggerManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Debugger { /// /// 调试器管理器。 /// internal sealed partial class DebuggerManager : GameFrameworkModule, IDebuggerManager { private readonly DebuggerWindowGroup m_DebuggerWindowRoot; private bool m_ActiveWindow; /// /// 初始化调试器管理器的新实例。 /// public DebuggerManager() { m_DebuggerWindowRoot = new DebuggerWindowGroup(); m_ActiveWindow = false; } /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal override int Priority { get { return -1; } } /// /// 获取或设置调试器窗口是否激活。 /// public bool ActiveWindow { get { return m_ActiveWindow; } set { m_ActiveWindow = value; } } /// /// 调试器窗口根结点。 /// public IDebuggerWindowGroup DebuggerWindowRoot { get { return m_DebuggerWindowRoot; } } /// /// 调试器管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { if (!m_ActiveWindow) { return; } m_DebuggerWindowRoot.OnUpdate(elapseSeconds, realElapseSeconds); } /// /// 关闭并清理调试器管理器。 /// internal override void Shutdown() { m_ActiveWindow = false; m_DebuggerWindowRoot.Shutdown(); } /// /// 注册调试器窗口。 /// /// 调试器窗口路径。 /// 要注册的调试器窗口。 /// 初始化调试器窗口参数。 public void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow, params object[] args) { if (string.IsNullOrEmpty(path)) { throw new GameFrameworkException("Path is invalid."); } if (debuggerWindow == null) { throw new GameFrameworkException("Debugger window is invalid."); } m_DebuggerWindowRoot.RegisterDebuggerWindow(path, debuggerWindow); debuggerWindow.Initialize(args); } /// /// 解除注册调试器窗口。 /// /// 调试器窗口路径。 /// 是否解除注册调试器窗口成功。 public bool UnregisterDebuggerWindow(string path) { return m_DebuggerWindowRoot.UnregisterDebuggerWindow(path); } /// /// 获取调试器窗口。 /// /// 调试器窗口路径。 /// 要获取的调试器窗口。 public IDebuggerWindow GetDebuggerWindow(string path) { return m_DebuggerWindowRoot.GetDebuggerWindow(path); } /// /// 选中调试器窗口。 /// /// 调试器窗口路径。 /// 是否成功选中调试器窗口。 public bool SelectDebuggerWindow(string path) { return m_DebuggerWindowRoot.SelectDebuggerWindow(path); } } } ================================================ FILE: GameFramework/Debugger/IDebuggerManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Debugger { /// /// 调试器管理器接口。 /// public interface IDebuggerManager { /// /// 获取或设置调试器窗口是否激活。 /// bool ActiveWindow { get; set; } /// /// 调试器窗口根结点。 /// IDebuggerWindowGroup DebuggerWindowRoot { get; } /// /// 注册调试器窗口。 /// /// 调试器窗口路径。 /// 要注册的调试器窗口。 /// 初始化调试器窗口参数。 void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow, params object[] args); /// /// 解除注册调试器窗口。 /// /// 调试器窗口路径。 /// 是否解除注册调试器窗口成功。 bool UnregisterDebuggerWindow(string path); /// /// 获取调试器窗口。 /// /// 调试器窗口路径。 /// 要获取的调试器窗口。 IDebuggerWindow GetDebuggerWindow(string path); /// /// 选中调试器窗口。 /// /// 调试器窗口路径。 /// 是否成功选中调试器窗口。 bool SelectDebuggerWindow(string path); } } ================================================ FILE: GameFramework/Debugger/IDebuggerWindow.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Debugger { /// /// 调试器窗口接口。 /// public interface IDebuggerWindow { /// /// 初始化调试器窗口。 /// /// 初始化调试器窗口参数。 void Initialize(params object[] args); /// /// 关闭调试器窗口。 /// void Shutdown(); /// /// 进入调试器窗口。 /// void OnEnter(); /// /// 离开调试器窗口。 /// void OnLeave(); /// /// 调试器窗口轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 void OnUpdate(float elapseSeconds, float realElapseSeconds); /// /// 调试器窗口绘制。 /// void OnDraw(); } } ================================================ FILE: GameFramework/Debugger/IDebuggerWindowGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Debugger { /// /// 调试器窗口组接口。 /// public interface IDebuggerWindowGroup : IDebuggerWindow { /// /// 获取调试器窗口数量。 /// int DebuggerWindowCount { get; } /// /// 获取或设置当前选中的调试器窗口索引。 /// int SelectedIndex { get; set; } /// /// 获取当前选中的调试器窗口。 /// IDebuggerWindow SelectedWindow { get; } /// /// 获取调试组的调试器窗口名称集合。 /// string[] GetDebuggerWindowNames(); /// /// 获取调试器窗口。 /// /// 调试器窗口路径。 /// 要获取的调试器窗口。 IDebuggerWindow GetDebuggerWindow(string path); /// /// 注册调试器窗口。 /// /// 调试器窗口路径。 /// 要注册的调试器窗口。 void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow); } } ================================================ FILE: GameFramework/Download/Constant.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { /// /// 下载相关常量。 /// internal static class Constant { /// /// 默认下载任务优先级。 /// internal const int DefaultPriority = 0; } } ================================================ FILE: GameFramework/Download/DownloadAgentHelperCompleteEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { /// /// 下载代理辅助器完成事件。 /// public sealed class DownloadAgentHelperCompleteEventArgs : GameFrameworkEventArgs { /// /// 初始化下载代理辅助器完成事件的新实例。 /// public DownloadAgentHelperCompleteEventArgs() { Length = 0L; } /// /// 获取下载的数据大小。 /// public long Length { get; private set; } /// /// 创建下载代理辅助器完成事件。 /// /// 下载的数据大小。 /// 创建的下载代理辅助器完成事件。 public static DownloadAgentHelperCompleteEventArgs Create(long length) { if (length < 0L) { throw new GameFrameworkException("Length is invalid."); } DownloadAgentHelperCompleteEventArgs downloadAgentHelperCompleteEventArgs = ReferencePool.Acquire(); downloadAgentHelperCompleteEventArgs.Length = length; return downloadAgentHelperCompleteEventArgs; } /// /// 清理下载代理辅助器完成事件。 /// public override void Clear() { Length = 0L; } } } ================================================ FILE: GameFramework/Download/DownloadAgentHelperErrorEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { /// /// 下载代理辅助器错误事件。 /// public sealed class DownloadAgentHelperErrorEventArgs : GameFrameworkEventArgs { /// /// 初始化下载代理辅助器错误事件的新实例。 /// public DownloadAgentHelperErrorEventArgs() { DeleteDownloading = false; ErrorMessage = null; } /// /// 获取是否需要删除正在下载的文件。 /// public bool DeleteDownloading { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 创建下载代理辅助器错误事件。 /// /// 是否需要删除正在下载的文件。 /// 错误信息。 /// 创建的下载代理辅助器错误事件。 public static DownloadAgentHelperErrorEventArgs Create(bool deleteDownloading, string errorMessage) { DownloadAgentHelperErrorEventArgs downloadAgentHelperErrorEventArgs = ReferencePool.Acquire(); downloadAgentHelperErrorEventArgs.DeleteDownloading = deleteDownloading; downloadAgentHelperErrorEventArgs.ErrorMessage = errorMessage; return downloadAgentHelperErrorEventArgs; } /// /// 清理下载代理辅助器错误事件。 /// public override void Clear() { DeleteDownloading = false; ErrorMessage = null; } } } ================================================ FILE: GameFramework/Download/DownloadAgentHelperUpdateBytesEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { /// /// 下载代理辅助器更新数据流事件。 /// public sealed class DownloadAgentHelperUpdateBytesEventArgs : GameFrameworkEventArgs { private byte[] m_Bytes; /// /// 初始化下载代理辅助器更新数据流事件的新实例。 /// public DownloadAgentHelperUpdateBytesEventArgs() { m_Bytes = null; Offset = 0; Length = 0; } /// /// 获取数据流的偏移。 /// public int Offset { get; private set; } /// /// 获取数据流的长度。 /// public int Length { get; private set; } /// /// 创建下载代理辅助器更新数据流事件。 /// /// 下载的数据流。 /// 数据流的偏移。 /// 数据流的长度。 /// 创建的下载代理辅助器更新数据流事件。 public static DownloadAgentHelperUpdateBytesEventArgs Create(byte[] bytes, int offset, int length) { if (bytes == null) { throw new GameFrameworkException("Bytes is invalid."); } if (offset < 0 || offset >= bytes.Length) { throw new GameFrameworkException("Offset is invalid."); } if (length <= 0 || offset + length > bytes.Length) { throw new GameFrameworkException("Length is invalid."); } DownloadAgentHelperUpdateBytesEventArgs downloadAgentHelperUpdateBytesEventArgs = ReferencePool.Acquire(); downloadAgentHelperUpdateBytesEventArgs.m_Bytes = bytes; downloadAgentHelperUpdateBytesEventArgs.Offset = offset; downloadAgentHelperUpdateBytesEventArgs.Length = length; return downloadAgentHelperUpdateBytesEventArgs; } /// /// 清理下载代理辅助器更新数据流事件。 /// public override void Clear() { m_Bytes = null; Offset = 0; Length = 0; } /// /// 获取下载的数据流。 /// public byte[] GetBytes() { return m_Bytes; } } } ================================================ FILE: GameFramework/Download/DownloadAgentHelperUpdateLengthEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { /// /// 下载代理辅助器更新数据大小事件。 /// public sealed class DownloadAgentHelperUpdateLengthEventArgs : GameFrameworkEventArgs { /// /// 初始化下载代理辅助器更新数据大小事件的新实例。 /// public DownloadAgentHelperUpdateLengthEventArgs() { DeltaLength = 0; } /// /// 获取下载的增量数据大小。 /// public int DeltaLength { get; private set; } /// /// 创建下载代理辅助器更新数据大小事件。 /// /// 下载的增量数据大小。 /// 创建的下载代理辅助器更新数据大小事件。 public static DownloadAgentHelperUpdateLengthEventArgs Create(int deltaLength) { if (deltaLength <= 0) { throw new GameFrameworkException("Delta length is invalid."); } DownloadAgentHelperUpdateLengthEventArgs downloadAgentHelperUpdateLengthEventArgs = ReferencePool.Acquire(); downloadAgentHelperUpdateLengthEventArgs.DeltaLength = deltaLength; return downloadAgentHelperUpdateLengthEventArgs; } /// /// 清理下载代理辅助器更新数据大小事件。 /// public override void Clear() { DeltaLength = 0; } } } ================================================ FILE: GameFramework/Download/DownloadFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { /// /// 下载失败事件。 /// public sealed class DownloadFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化下载失败事件的新实例。 /// public DownloadFailureEventArgs() { SerialId = 0; DownloadPath = null; DownloadUri = null; ErrorMessage = null; UserData = null; } /// /// 获取下载任务的序列编号。 /// public int SerialId { get; private set; } /// /// 获取下载后存放路径。 /// public string DownloadPath { get; private set; } /// /// 获取下载地址。 /// public string DownloadUri { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建下载失败事件。 /// /// 下载任务的序列编号。 /// 下载后存放路径。 /// 下载地址。 /// 错误信息。 /// 用户自定义数据。 /// 创建的下载失败事件。 public static DownloadFailureEventArgs Create(int serialId, string downloadPath, string downloadUri, string errorMessage, object userData) { DownloadFailureEventArgs downloadFailureEventArgs = ReferencePool.Acquire(); downloadFailureEventArgs.SerialId = serialId; downloadFailureEventArgs.DownloadPath = downloadPath; downloadFailureEventArgs.DownloadUri = downloadUri; downloadFailureEventArgs.ErrorMessage = errorMessage; downloadFailureEventArgs.UserData = userData; return downloadFailureEventArgs; } /// /// 清理下载失败事件。 /// public override void Clear() { SerialId = 0; DownloadPath = null; DownloadUri = null; ErrorMessage = null; UserData = null; } } } ================================================ FILE: GameFramework/Download/DownloadManager.DownloadAgent.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.IO; namespace GameFramework.Download { internal sealed partial class DownloadManager : GameFrameworkModule, IDownloadManager { /// /// 下载代理。 /// private sealed class DownloadAgent : ITaskAgent, IDisposable { private readonly IDownloadAgentHelper m_Helper; private DownloadTask m_Task; private FileStream m_FileStream; private int m_WaitFlushSize; private float m_WaitTime; private long m_StartLength; private long m_DownloadedLength; private long m_SavedLength; private bool m_Disposed; public GameFrameworkAction DownloadAgentStart; public GameFrameworkAction DownloadAgentUpdate; public GameFrameworkAction DownloadAgentSuccess; public GameFrameworkAction DownloadAgentFailure; /// /// 初始化下载代理的新实例。 /// /// 下载代理辅助器。 public DownloadAgent(IDownloadAgentHelper downloadAgentHelper) { if (downloadAgentHelper == null) { throw new GameFrameworkException("Download agent helper is invalid."); } m_Helper = downloadAgentHelper; m_Task = null; m_FileStream = null; m_WaitFlushSize = 0; m_WaitTime = 0f; m_StartLength = 0L; m_DownloadedLength = 0L; m_SavedLength = 0L; m_Disposed = false; DownloadAgentStart = null; DownloadAgentUpdate = null; DownloadAgentSuccess = null; DownloadAgentFailure = null; } /// /// 获取下载任务。 /// public DownloadTask Task { get { return m_Task; } } /// /// 获取已经等待时间。 /// public float WaitTime { get { return m_WaitTime; } } /// /// 获取开始下载时已经存在的大小。 /// public long StartLength { get { return m_StartLength; } } /// /// 获取本次已经下载的大小。 /// public long DownloadedLength { get { return m_DownloadedLength; } } /// /// 获取当前的大小。 /// public long CurrentLength { get { return m_StartLength + m_DownloadedLength; } } /// /// 获取已经存盘的大小。 /// public long SavedLength { get { return m_SavedLength; } } /// /// 初始化下载代理。 /// public void Initialize() { m_Helper.DownloadAgentHelperUpdateBytes += OnDownloadAgentHelperUpdateBytes; m_Helper.DownloadAgentHelperUpdateLength += OnDownloadAgentHelperUpdateLength; m_Helper.DownloadAgentHelperComplete += OnDownloadAgentHelperComplete; m_Helper.DownloadAgentHelperError += OnDownloadAgentHelperError; } /// /// 下载代理轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void Update(float elapseSeconds, float realElapseSeconds) { if (m_Task.Status == DownloadTaskStatus.Doing) { m_WaitTime += realElapseSeconds; if (m_WaitTime >= m_Task.Timeout) { DownloadAgentHelperErrorEventArgs downloadAgentHelperErrorEventArgs = DownloadAgentHelperErrorEventArgs.Create(false, "Timeout"); OnDownloadAgentHelperError(this, downloadAgentHelperErrorEventArgs); ReferencePool.Release(downloadAgentHelperErrorEventArgs); } } } /// /// 关闭并清理下载代理。 /// public void Shutdown() { Dispose(); m_Helper.DownloadAgentHelperUpdateBytes -= OnDownloadAgentHelperUpdateBytes; m_Helper.DownloadAgentHelperUpdateLength -= OnDownloadAgentHelperUpdateLength; m_Helper.DownloadAgentHelperComplete -= OnDownloadAgentHelperComplete; m_Helper.DownloadAgentHelperError -= OnDownloadAgentHelperError; } /// /// 开始处理下载任务。 /// /// 要处理的下载任务。 /// 开始处理任务的状态。 public StartTaskStatus Start(DownloadTask task) { if (task == null) { throw new GameFrameworkException("Task is invalid."); } m_Task = task; m_Task.Status = DownloadTaskStatus.Doing; string downloadFile = Utility.Text.Format("{0}.download", m_Task.DownloadPath); try { if (File.Exists(downloadFile)) { m_FileStream = File.OpenWrite(downloadFile); m_FileStream.Seek(0L, SeekOrigin.End); m_StartLength = m_SavedLength = m_FileStream.Length; m_DownloadedLength = 0L; } else { string directory = Path.GetDirectoryName(m_Task.DownloadPath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } m_FileStream = new FileStream(downloadFile, FileMode.Create, FileAccess.Write); m_StartLength = m_SavedLength = m_DownloadedLength = 0L; } if (DownloadAgentStart != null) { DownloadAgentStart(this); } if (m_StartLength > 0L) { m_Helper.Download(m_Task.DownloadUri, m_StartLength, m_Task.UserData); } else { m_Helper.Download(m_Task.DownloadUri, m_Task.UserData); } return StartTaskStatus.CanResume; } catch (Exception exception) { DownloadAgentHelperErrorEventArgs downloadAgentHelperErrorEventArgs = DownloadAgentHelperErrorEventArgs.Create(false, exception.ToString()); OnDownloadAgentHelperError(this, downloadAgentHelperErrorEventArgs); ReferencePool.Release(downloadAgentHelperErrorEventArgs); return StartTaskStatus.UnknownError; } } /// /// 重置下载代理。 /// public void Reset() { m_Helper.Reset(); if (m_FileStream != null) { m_FileStream.Close(); m_FileStream = null; } m_Task = null; m_WaitFlushSize = 0; m_WaitTime = 0f; m_StartLength = 0L; m_DownloadedLength = 0L; m_SavedLength = 0L; } /// /// 释放资源。 /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// 释放资源。 /// /// 释放资源标记。 private void Dispose(bool disposing) { if (m_Disposed) { return; } if (disposing) { if (m_FileStream != null) { m_FileStream.Dispose(); m_FileStream = null; } } m_Disposed = true; } private void OnDownloadAgentHelperUpdateBytes(object sender, DownloadAgentHelperUpdateBytesEventArgs e) { m_WaitTime = 0f; try { m_FileStream.Write(e.GetBytes(), e.Offset, e.Length); m_WaitFlushSize += e.Length; m_SavedLength += e.Length; if (m_WaitFlushSize >= m_Task.FlushSize) { m_FileStream.Flush(); m_WaitFlushSize = 0; } } catch (Exception exception) { DownloadAgentHelperErrorEventArgs downloadAgentHelperErrorEventArgs = DownloadAgentHelperErrorEventArgs.Create(false, exception.ToString()); OnDownloadAgentHelperError(this, downloadAgentHelperErrorEventArgs); ReferencePool.Release(downloadAgentHelperErrorEventArgs); } } private void OnDownloadAgentHelperUpdateLength(object sender, DownloadAgentHelperUpdateLengthEventArgs e) { m_WaitTime = 0f; m_DownloadedLength += e.DeltaLength; if (DownloadAgentUpdate != null) { DownloadAgentUpdate(this, e.DeltaLength); } } private void OnDownloadAgentHelperComplete(object sender, DownloadAgentHelperCompleteEventArgs e) { m_WaitTime = 0f; m_DownloadedLength = e.Length; if (m_SavedLength != CurrentLength) { throw new GameFrameworkException("Internal download error."); } m_Helper.Reset(); m_FileStream.Close(); m_FileStream = null; if (File.Exists(m_Task.DownloadPath)) { File.Delete(m_Task.DownloadPath); } File.Move(Utility.Text.Format("{0}.download", m_Task.DownloadPath), m_Task.DownloadPath); m_Task.Status = DownloadTaskStatus.Done; if (DownloadAgentSuccess != null) { DownloadAgentSuccess(this, e.Length); } m_Task.Done = true; } private void OnDownloadAgentHelperError(object sender, DownloadAgentHelperErrorEventArgs e) { m_Helper.Reset(); if (m_FileStream != null) { m_FileStream.Close(); m_FileStream = null; } if (e.DeleteDownloading) { File.Delete(Utility.Text.Format("{0}.download", m_Task.DownloadPath)); } m_Task.Status = DownloadTaskStatus.Error; if (DownloadAgentFailure != null) { DownloadAgentFailure(this, e.ErrorMessage); } m_Task.Done = true; } } } } ================================================ FILE: GameFramework/Download/DownloadManager.DownloadCounter.DownloadCounterNode.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { internal sealed partial class DownloadManager : GameFrameworkModule, IDownloadManager { private sealed partial class DownloadCounter { private sealed class DownloadCounterNode : IReference { private long m_DeltaLength; private float m_ElapseSeconds; public DownloadCounterNode() { m_DeltaLength = 0L; m_ElapseSeconds = 0f; } public long DeltaLength { get { return m_DeltaLength; } } public float ElapseSeconds { get { return m_ElapseSeconds; } } public static DownloadCounterNode Create() { return ReferencePool.Acquire(); } public void Update(float elapseSeconds, float realElapseSeconds) { m_ElapseSeconds += realElapseSeconds; } public void AddDeltaLength(int deltaLength) { m_DeltaLength += deltaLength; } public void Clear() { m_DeltaLength = 0L; m_ElapseSeconds = 0f; } } } } } ================================================ FILE: GameFramework/Download/DownloadManager.DownloadCounter.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { internal sealed partial class DownloadManager : GameFrameworkModule, IDownloadManager { private sealed partial class DownloadCounter { private readonly GameFrameworkLinkedList m_DownloadCounterNodes; private float m_UpdateInterval; private float m_RecordInterval; private float m_CurrentSpeed; private float m_Accumulator; private float m_TimeLeft; public DownloadCounter(float updateInterval, float recordInterval) { if (updateInterval <= 0f) { throw new GameFrameworkException("Update interval is invalid."); } if (recordInterval <= 0f) { throw new GameFrameworkException("Record interval is invalid."); } m_DownloadCounterNodes = new GameFrameworkLinkedList(); m_UpdateInterval = updateInterval; m_RecordInterval = recordInterval; Reset(); } public float UpdateInterval { get { return m_UpdateInterval; } set { if (value <= 0f) { throw new GameFrameworkException("Update interval is invalid."); } m_UpdateInterval = value; Reset(); } } public float RecordInterval { get { return m_RecordInterval; } set { if (value <= 0f) { throw new GameFrameworkException("Record interval is invalid."); } m_RecordInterval = value; Reset(); } } public float CurrentSpeed { get { return m_CurrentSpeed; } } public void Shutdown() { Reset(); } public void Update(float elapseSeconds, float realElapseSeconds) { if (m_DownloadCounterNodes.Count <= 0) { return; } m_Accumulator += realElapseSeconds; if (m_Accumulator > m_RecordInterval) { m_Accumulator = m_RecordInterval; } m_TimeLeft -= realElapseSeconds; foreach (DownloadCounterNode downloadCounterNode in m_DownloadCounterNodes) { downloadCounterNode.Update(elapseSeconds, realElapseSeconds); } while (m_DownloadCounterNodes.Count > 0) { DownloadCounterNode downloadCounterNode = m_DownloadCounterNodes.First.Value; if (downloadCounterNode.ElapseSeconds < m_RecordInterval) { break; } ReferencePool.Release(downloadCounterNode); m_DownloadCounterNodes.RemoveFirst(); } if (m_DownloadCounterNodes.Count <= 0) { Reset(); return; } if (m_TimeLeft <= 0f) { long totalDeltaLength = 0L; foreach (DownloadCounterNode downloadCounterNode in m_DownloadCounterNodes) { totalDeltaLength += downloadCounterNode.DeltaLength; } m_CurrentSpeed = m_Accumulator > 0f ? totalDeltaLength / m_Accumulator : 0f; m_TimeLeft += m_UpdateInterval; } } public void RecordDeltaLength(int deltaLength) { if (deltaLength <= 0) { return; } DownloadCounterNode downloadCounterNode = null; if (m_DownloadCounterNodes.Count > 0) { downloadCounterNode = m_DownloadCounterNodes.Last.Value; if (downloadCounterNode.ElapseSeconds < m_UpdateInterval) { downloadCounterNode.AddDeltaLength(deltaLength); return; } } downloadCounterNode = DownloadCounterNode.Create(); downloadCounterNode.AddDeltaLength(deltaLength); m_DownloadCounterNodes.AddLast(downloadCounterNode); } private void Reset() { m_DownloadCounterNodes.Clear(); m_CurrentSpeed = 0f; m_Accumulator = 0f; m_TimeLeft = 0f; } } } } ================================================ FILE: GameFramework/Download/DownloadManager.DownloadTask.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { internal sealed partial class DownloadManager : GameFrameworkModule, IDownloadManager { /// /// 下载任务。 /// private sealed class DownloadTask : TaskBase { private static int s_Serial = 0; private DownloadTaskStatus m_Status; private string m_DownloadPath; private string m_DownloadUri; private int m_FlushSize; private float m_Timeout; /// /// 初始化下载任务的新实例。 /// public DownloadTask() { m_Status = DownloadTaskStatus.Todo; m_DownloadPath = null; m_DownloadUri = null; m_FlushSize = 0; m_Timeout = 0f; } /// /// 获取或设置下载任务的状态。 /// public DownloadTaskStatus Status { get { return m_Status; } set { m_Status = value; } } /// /// 获取下载后存放路径。 /// public string DownloadPath { get { return m_DownloadPath; } } /// /// 获取原始下载地址。 /// public string DownloadUri { get { return m_DownloadUri; } } /// /// 获取将缓冲区写入磁盘的临界大小。 /// public int FlushSize { get { return m_FlushSize; } } /// /// 获取下载超时时长,以秒为单位。 /// public float Timeout { get { return m_Timeout; } } /// /// 获取下载任务的描述。 /// public override string Description { get { return m_DownloadPath; } } /// /// 创建下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的标签。 /// 下载任务的优先级。 /// 将缓冲区写入磁盘的临界大小。 /// 下载超时时长,以秒为单位。 /// 用户自定义数据。 /// 创建的下载任务。 public static DownloadTask Create(string downloadPath, string downloadUri, string tag, int priority, int flushSize, float timeout, object userData) { DownloadTask downloadTask = ReferencePool.Acquire(); downloadTask.Initialize(++s_Serial, tag, priority, userData); downloadTask.m_DownloadPath = downloadPath; downloadTask.m_DownloadUri = downloadUri; downloadTask.m_FlushSize = flushSize; downloadTask.m_Timeout = timeout; return downloadTask; } /// /// 清理下载任务。 /// public override void Clear() { base.Clear(); m_Status = DownloadTaskStatus.Todo; m_DownloadPath = null; m_DownloadUri = null; m_FlushSize = 0; m_Timeout = 0f; } } } } ================================================ FILE: GameFramework/Download/DownloadManager.DownloadTaskStatus.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { internal sealed partial class DownloadManager : GameFrameworkModule, IDownloadManager { /// /// 下载任务的状态。 /// private enum DownloadTaskStatus : byte { /// /// 准备下载。 /// Todo = 0, /// /// 下载中。 /// Doing, /// /// 下载完成。 /// Done, /// /// 下载错误。 /// Error } } } ================================================ FILE: GameFramework/Download/DownloadManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Download { /// /// 下载管理器。 /// internal sealed partial class DownloadManager : GameFrameworkModule, IDownloadManager { private const int OneMegaBytes = 1024 * 1024; private readonly TaskPool m_TaskPool; private readonly DownloadCounter m_DownloadCounter; private int m_FlushSize; private float m_Timeout; private EventHandler m_DownloadStartEventHandler; private EventHandler m_DownloadUpdateEventHandler; private EventHandler m_DownloadSuccessEventHandler; private EventHandler m_DownloadFailureEventHandler; /// /// 初始化下载管理器的新实例。 /// public DownloadManager() { m_TaskPool = new TaskPool(); m_DownloadCounter = new DownloadCounter(1f, 10f); m_FlushSize = OneMegaBytes; m_Timeout = 30f; m_DownloadStartEventHandler = null; m_DownloadUpdateEventHandler = null; m_DownloadSuccessEventHandler = null; m_DownloadFailureEventHandler = null; } /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal override int Priority { get { return 5; } } /// /// 获取或设置下载是否被暂停。 /// public bool Paused { get { return m_TaskPool.Paused; } set { m_TaskPool.Paused = value; } } /// /// 获取下载代理总数量。 /// public int TotalAgentCount { get { return m_TaskPool.TotalAgentCount; } } /// /// 获取可用下载代理数量。 /// public int FreeAgentCount { get { return m_TaskPool.FreeAgentCount; } } /// /// 获取工作中下载代理数量。 /// public int WorkingAgentCount { get { return m_TaskPool.WorkingAgentCount; } } /// /// 获取等待下载任务数量。 /// public int WaitingTaskCount { get { return m_TaskPool.WaitingTaskCount; } } /// /// 获取或设置将缓冲区写入磁盘的临界大小。 /// public int FlushSize { get { return m_FlushSize; } set { m_FlushSize = value; } } /// /// 获取或设置下载超时时长,以秒为单位。 /// public float Timeout { get { return m_Timeout; } set { m_Timeout = value; } } /// /// 获取当前下载速度。 /// public float CurrentSpeed { get { return m_DownloadCounter.CurrentSpeed; } } /// /// 下载开始事件。 /// public event EventHandler DownloadStart { add { m_DownloadStartEventHandler += value; } remove { m_DownloadStartEventHandler -= value; } } /// /// 下载更新事件。 /// public event EventHandler DownloadUpdate { add { m_DownloadUpdateEventHandler += value; } remove { m_DownloadUpdateEventHandler -= value; } } /// /// 下载成功事件。 /// public event EventHandler DownloadSuccess { add { m_DownloadSuccessEventHandler += value; } remove { m_DownloadSuccessEventHandler -= value; } } /// /// 下载失败事件。 /// public event EventHandler DownloadFailure { add { m_DownloadFailureEventHandler += value; } remove { m_DownloadFailureEventHandler -= value; } } /// /// 下载管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { m_TaskPool.Update(elapseSeconds, realElapseSeconds); m_DownloadCounter.Update(elapseSeconds, realElapseSeconds); } /// /// 关闭并清理下载管理器。 /// internal override void Shutdown() { m_TaskPool.Shutdown(); m_DownloadCounter.Shutdown(); } /// /// 增加下载代理辅助器。 /// /// 要增加的下载代理辅助器。 public void AddDownloadAgentHelper(IDownloadAgentHelper downloadAgentHelper) { DownloadAgent agent = new DownloadAgent(downloadAgentHelper); agent.DownloadAgentStart += OnDownloadAgentStart; agent.DownloadAgentUpdate += OnDownloadAgentUpdate; agent.DownloadAgentSuccess += OnDownloadAgentSuccess; agent.DownloadAgentFailure += OnDownloadAgentFailure; m_TaskPool.AddAgent(agent); } /// /// 根据下载任务的序列编号获取下载任务的信息。 /// /// 要获取信息的下载任务的序列编号。 /// 下载任务的信息。 public TaskInfo GetDownloadInfo(int serialId) { return m_TaskPool.GetTaskInfo(serialId); } /// /// 根据下载任务的标签获取下载任务的信息。 /// /// 要获取信息的下载任务的标签。 /// 下载任务的信息。 public TaskInfo[] GetDownloadInfos(string tag) { return m_TaskPool.GetTaskInfos(tag); } /// /// 根据下载任务的标签获取下载任务的信息。 /// /// 要获取信息的下载任务的标签。 /// 下载任务的信息。 public void GetDownloadInfos(string tag, List results) { m_TaskPool.GetTaskInfos(tag, results); } /// /// 获取所有下载任务的信息。 /// /// 所有下载任务的信息。 public TaskInfo[] GetAllDownloadInfos() { return m_TaskPool.GetAllTaskInfos(); } /// /// 获取所有下载任务的信息。 /// /// 所有下载任务的信息。 public void GetAllDownloadInfos(List results) { m_TaskPool.GetAllTaskInfos(results); } /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 新增下载任务的序列编号。 public int AddDownload(string downloadPath, string downloadUri) { return AddDownload(downloadPath, downloadUri, null, Constant.DefaultPriority, null); } /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的标签。 /// 新增下载任务的序列编号。 public int AddDownload(string downloadPath, string downloadUri, string tag) { return AddDownload(downloadPath, downloadUri, tag, Constant.DefaultPriority, null); } /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的优先级。 /// 新增下载任务的序列编号。 public int AddDownload(string downloadPath, string downloadUri, int priority) { return AddDownload(downloadPath, downloadUri, null, priority, null); } /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 用户自定义数据。 /// 新增下载任务的序列编号。 public int AddDownload(string downloadPath, string downloadUri, object userData) { return AddDownload(downloadPath, downloadUri, null, Constant.DefaultPriority, userData); } /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的标签。 /// 下载任务的优先级。 /// 新增下载任务的序列编号。 public int AddDownload(string downloadPath, string downloadUri, string tag, int priority) { return AddDownload(downloadPath, downloadUri, tag, priority, null); } /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的标签。 /// 用户自定义数据。 /// 新增下载任务的序列编号。 public int AddDownload(string downloadPath, string downloadUri, string tag, object userData) { return AddDownload(downloadPath, downloadUri, tag, Constant.DefaultPriority, userData); } /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的优先级。 /// 用户自定义数据。 /// 新增下载任务的序列编号。 public int AddDownload(string downloadPath, string downloadUri, int priority, object userData) { return AddDownload(downloadPath, downloadUri, null, priority, userData); } /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的标签。 /// 下载任务的优先级。 /// 用户自定义数据。 /// 新增下载任务的序列编号。 public int AddDownload(string downloadPath, string downloadUri, string tag, int priority, object userData) { if (string.IsNullOrEmpty(downloadPath)) { throw new GameFrameworkException("Download path is invalid."); } if (string.IsNullOrEmpty(downloadUri)) { throw new GameFrameworkException("Download uri is invalid."); } if (TotalAgentCount <= 0) { throw new GameFrameworkException("You must add download agent first."); } DownloadTask downloadTask = DownloadTask.Create(downloadPath, downloadUri, tag, priority, m_FlushSize, m_Timeout, userData); m_TaskPool.AddTask(downloadTask); return downloadTask.SerialId; } /// /// 根据下载任务的序列编号移除下载任务。 /// /// 要移除下载任务的序列编号。 /// 是否移除下载任务成功。 public bool RemoveDownload(int serialId) { return m_TaskPool.RemoveTask(serialId); } /// /// 根据下载任务的标签移除下载任务。 /// /// 要移除下载任务的标签。 /// 移除下载任务的数量。 public int RemoveDownloads(string tag) { return m_TaskPool.RemoveTasks(tag); } /// /// 移除所有下载任务。 /// /// 移除下载任务的数量。 public int RemoveAllDownloads() { return m_TaskPool.RemoveAllTasks(); } private void OnDownloadAgentStart(DownloadAgent sender) { if (m_DownloadStartEventHandler != null) { DownloadStartEventArgs downloadStartEventArgs = DownloadStartEventArgs.Create(sender.Task.SerialId, sender.Task.DownloadPath, sender.Task.DownloadUri, sender.CurrentLength, sender.Task.UserData); m_DownloadStartEventHandler(this, downloadStartEventArgs); ReferencePool.Release(downloadStartEventArgs); } } private void OnDownloadAgentUpdate(DownloadAgent sender, int deltaLength) { m_DownloadCounter.RecordDeltaLength(deltaLength); if (m_DownloadUpdateEventHandler != null) { DownloadUpdateEventArgs downloadUpdateEventArgs = DownloadUpdateEventArgs.Create(sender.Task.SerialId, sender.Task.DownloadPath, sender.Task.DownloadUri, sender.CurrentLength, sender.Task.UserData); m_DownloadUpdateEventHandler(this, downloadUpdateEventArgs); ReferencePool.Release(downloadUpdateEventArgs); } } private void OnDownloadAgentSuccess(DownloadAgent sender, long length) { if (m_DownloadSuccessEventHandler != null) { DownloadSuccessEventArgs downloadSuccessEventArgs = DownloadSuccessEventArgs.Create(sender.Task.SerialId, sender.Task.DownloadPath, sender.Task.DownloadUri, sender.CurrentLength, sender.Task.UserData); m_DownloadSuccessEventHandler(this, downloadSuccessEventArgs); ReferencePool.Release(downloadSuccessEventArgs); } } private void OnDownloadAgentFailure(DownloadAgent sender, string errorMessage) { if (m_DownloadFailureEventHandler != null) { DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(sender.Task.SerialId, sender.Task.DownloadPath, sender.Task.DownloadUri, errorMessage, sender.Task.UserData); m_DownloadFailureEventHandler(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); } } } } ================================================ FILE: GameFramework/Download/DownloadStartEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { /// /// 下载开始事件。 /// public sealed class DownloadStartEventArgs : GameFrameworkEventArgs { /// /// 初始化下载开始事件的新实例。 /// public DownloadStartEventArgs() { SerialId = 0; DownloadPath = null; DownloadUri = null; CurrentLength = 0L; UserData = null; } /// /// 获取下载任务的序列编号。 /// public int SerialId { get; private set; } /// /// 获取下载后存放路径。 /// public string DownloadPath { get; private set; } /// /// 获取下载地址。 /// public string DownloadUri { get; private set; } /// /// 获取当前大小。 /// public long CurrentLength { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建下载开始事件。 /// /// 下载任务的序列编号。 /// 下载后存放路径。 /// 下载地址。 /// 当前大小。 /// 用户自定义数据。 /// 创建的下载开始事件。 public static DownloadStartEventArgs Create(int serialId, string downloadPath, string downloadUri, long currentLength, object userData) { DownloadStartEventArgs downloadStartEventArgs = ReferencePool.Acquire(); downloadStartEventArgs.SerialId = serialId; downloadStartEventArgs.DownloadPath = downloadPath; downloadStartEventArgs.DownloadUri = downloadUri; downloadStartEventArgs.CurrentLength = currentLength; downloadStartEventArgs.UserData = userData; return downloadStartEventArgs; } /// /// 清理下载开始事件。 /// public override void Clear() { SerialId = 0; DownloadPath = null; DownloadUri = null; CurrentLength = 0L; UserData = null; } } } ================================================ FILE: GameFramework/Download/DownloadSuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { /// /// 下载成功事件。 /// public sealed class DownloadSuccessEventArgs : GameFrameworkEventArgs { /// /// 初始化下载成功事件的新实例。 /// public DownloadSuccessEventArgs() { SerialId = 0; DownloadPath = null; DownloadUri = null; CurrentLength = 0L; UserData = null; } /// /// 获取下载任务的序列编号。 /// public int SerialId { get; private set; } /// /// 获取下载后存放路径。 /// public string DownloadPath { get; private set; } /// /// 获取下载地址。 /// public string DownloadUri { get; private set; } /// /// 获取当前大小。 /// public long CurrentLength { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建下载成功事件。 /// /// 下载任务的序列编号。 /// 下载后存放路径。 /// 下载地址。 /// 当前大小。 /// 用户自定义数据。 /// 创建的下载成功事件。 public static DownloadSuccessEventArgs Create(int serialId, string downloadPath, string downloadUri, long currentLength, object userData) { DownloadSuccessEventArgs downloadSuccessEventArgs = ReferencePool.Acquire(); downloadSuccessEventArgs.SerialId = serialId; downloadSuccessEventArgs.DownloadPath = downloadPath; downloadSuccessEventArgs.DownloadUri = downloadUri; downloadSuccessEventArgs.CurrentLength = currentLength; downloadSuccessEventArgs.UserData = userData; return downloadSuccessEventArgs; } /// /// 清理下载成功事件。 /// public override void Clear() { SerialId = 0; DownloadPath = null; DownloadUri = null; CurrentLength = 0L; UserData = null; } } } ================================================ FILE: GameFramework/Download/DownloadUpdateEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Download { /// /// 下载更新事件。 /// public sealed class DownloadUpdateEventArgs : GameFrameworkEventArgs { /// /// 初始化下载更新事件的新实例。 /// public DownloadUpdateEventArgs() { SerialId = 0; DownloadPath = null; DownloadUri = null; CurrentLength = 0L; UserData = null; } /// /// 获取下载任务的序列编号。 /// public int SerialId { get; private set; } /// /// 获取下载后存放路径。 /// public string DownloadPath { get; private set; } /// /// 获取下载地址。 /// public string DownloadUri { get; private set; } /// /// 获取当前大小。 /// public long CurrentLength { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建下载更新事件。 /// /// 下载任务的序列编号。 /// 下载后存放路径。 /// 下载地址。 /// 当前大小。 /// 用户自定义数据。 /// 创建的下载更新事件。 public static DownloadUpdateEventArgs Create(int serialId, string downloadPath, string downloadUri, long currentLength, object userData) { DownloadUpdateEventArgs downloadUpdateEventArgs = ReferencePool.Acquire(); downloadUpdateEventArgs.SerialId = serialId; downloadUpdateEventArgs.DownloadPath = downloadPath; downloadUpdateEventArgs.DownloadUri = downloadUri; downloadUpdateEventArgs.CurrentLength = currentLength; downloadUpdateEventArgs.UserData = userData; return downloadUpdateEventArgs; } /// /// 清理下载更新事件。 /// public override void Clear() { SerialId = 0; DownloadPath = null; DownloadUri = null; CurrentLength = 0L; UserData = null; } } } ================================================ FILE: GameFramework/Download/IDownloadAgentHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.Download { /// /// 下载代理辅助器接口。 /// public interface IDownloadAgentHelper { /// /// 下载代理辅助器更新数据流事件。 /// event EventHandler DownloadAgentHelperUpdateBytes; /// /// 下载代理辅助器更新数据大小事件。 /// event EventHandler DownloadAgentHelperUpdateLength; /// /// 下载代理辅助器完成事件。 /// event EventHandler DownloadAgentHelperComplete; /// /// 下载代理辅助器错误事件。 /// event EventHandler DownloadAgentHelperError; /// /// 通过下载代理辅助器下载指定地址的数据。 /// /// 下载地址。 /// 用户自定义数据。 void Download(string downloadUri, object userData); /// /// 通过下载代理辅助器下载指定地址的数据。 /// /// 下载地址。 /// 下载数据起始位置。 /// 用户自定义数据。 void Download(string downloadUri, long fromPosition, object userData); /// /// 通过下载代理辅助器下载指定地址的数据。 /// /// 下载地址。 /// 下载数据起始位置。 /// 下载数据结束位置。 /// 用户自定义数据。 void Download(string downloadUri, long fromPosition, long toPosition, object userData); /// /// 重置下载代理辅助器。 /// void Reset(); } } ================================================ FILE: GameFramework/Download/IDownloadManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Download { /// /// 下载管理器接口。 /// public interface IDownloadManager { /// /// 获取或设置下载是否被暂停。 /// bool Paused { get; set; } /// /// 获取下载代理总数量。 /// int TotalAgentCount { get; } /// /// 获取可用下载代理数量。 /// int FreeAgentCount { get; } /// /// 获取工作中下载代理数量。 /// int WorkingAgentCount { get; } /// /// 获取等待下载任务数量。 /// int WaitingTaskCount { get; } /// /// 获取或设置将缓冲区写入磁盘的临界大小。 /// int FlushSize { get; set; } /// /// 获取或设置下载超时时长,以秒为单位。 /// float Timeout { get; set; } /// /// 获取当前下载速度。 /// float CurrentSpeed { get; } /// /// 下载开始事件。 /// event EventHandler DownloadStart; /// /// 下载更新事件。 /// event EventHandler DownloadUpdate; /// /// 下载成功事件。 /// event EventHandler DownloadSuccess; /// /// 下载失败事件。 /// event EventHandler DownloadFailure; /// /// 增加下载代理辅助器。 /// /// 要增加的下载代理辅助器。 void AddDownloadAgentHelper(IDownloadAgentHelper downloadAgentHelper); /// /// 根据下载任务的序列编号获取下载任务的信息。 /// /// 要获取信息的下载任务的序列编号。 /// 下载任务的信息。 TaskInfo GetDownloadInfo(int serialId); /// /// 根据下载任务的标签获取下载任务的信息。 /// /// 要获取信息的下载任务的标签。 /// 下载任务的信息。 TaskInfo[] GetDownloadInfos(string tag); /// /// 根据下载任务的标签获取下载任务的信息。 /// /// 要获取信息的下载任务的标签。 /// 下载任务的信息。 void GetDownloadInfos(string tag, List results); /// /// 获取所有下载任务的信息。 /// /// 所有下载任务的信息。 TaskInfo[] GetAllDownloadInfos(); /// /// 获取所有下载任务的信息。 /// /// 所有下载任务的信息。 void GetAllDownloadInfos(List results); /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 新增下载任务的序列编号。 int AddDownload(string downloadPath, string downloadUri); /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的标签。 /// 新增下载任务的序列编号。 int AddDownload(string downloadPath, string downloadUri, string tag); /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的优先级。 /// 新增下载任务的序列编号。 int AddDownload(string downloadPath, string downloadUri, int priority); /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 用户自定义数据。 /// 新增下载任务的序列编号。 int AddDownload(string downloadPath, string downloadUri, object userData); /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的标签。 /// 下载任务的优先级。 /// 新增下载任务的序列编号。 int AddDownload(string downloadPath, string downloadUri, string tag, int priority); /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的标签。 /// 用户自定义数据。 /// 新增下载任务的序列编号。 int AddDownload(string downloadPath, string downloadUri, string tag, object userData); /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的优先级。 /// 用户自定义数据。 /// 新增下载任务的序列编号。 int AddDownload(string downloadPath, string downloadUri, int priority, object userData); /// /// 增加下载任务。 /// /// 下载后存放路径。 /// 原始下载地址。 /// 下载任务的标签。 /// 下载任务的优先级。 /// 用户自定义数据。 /// 新增下载任务的序列编号。 int AddDownload(string downloadPath, string downloadUri, string tag, int priority, object userData); /// /// 根据下载任务的序列编号移除下载任务。 /// /// 要移除下载任务的序列编号。 /// 是否移除下载任务成功。 bool RemoveDownload(int serialId); /// /// 根据下载任务的标签移除下载任务。 /// /// 要移除下载任务的标签。 /// 移除下载任务的数量。 int RemoveDownloads(string tag); /// /// 移除所有下载任务。 /// /// 移除下载任务的数量。 int RemoveAllDownloads(); } } ================================================ FILE: GameFramework/Entity/EntityManager.EntityGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.ObjectPool; using System.Collections.Generic; namespace GameFramework.Entity { internal sealed partial class EntityManager : GameFrameworkModule, IEntityManager { /// /// 实体组。 /// private sealed class EntityGroup : IEntityGroup { private readonly string m_Name; private readonly IEntityGroupHelper m_EntityGroupHelper; private readonly IObjectPool m_InstancePool; private readonly GameFrameworkLinkedList m_Entities; private LinkedListNode m_CachedNode; /// /// 初始化实体组的新实例。 /// /// 实体组名称。 /// 实体实例对象池自动释放可释放对象的间隔秒数。 /// 实体实例对象池容量。 /// 实体实例对象池对象过期秒数。 /// 实体实例对象池的优先级。 /// 实体组辅助器。 /// 对象池管理器。 public EntityGroup(string name, float instanceAutoReleaseInterval, int instanceCapacity, float instanceExpireTime, int instancePriority, IEntityGroupHelper entityGroupHelper, IObjectPoolManager objectPoolManager) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Entity group name is invalid."); } if (entityGroupHelper == null) { throw new GameFrameworkException("Entity group helper is invalid."); } m_Name = name; m_EntityGroupHelper = entityGroupHelper; m_InstancePool = objectPoolManager.CreateSingleSpawnObjectPool(Utility.Text.Format("Entity Instance Pool ({0})", name), instanceCapacity, instanceExpireTime, instancePriority); m_InstancePool.AutoReleaseInterval = instanceAutoReleaseInterval; m_Entities = new GameFrameworkLinkedList(); m_CachedNode = null; } /// /// 获取实体组名称。 /// public string Name { get { return m_Name; } } /// /// 获取实体组中实体数量。 /// public int EntityCount { get { return m_Entities.Count; } } /// /// 获取或设置实体组实例对象池自动释放可释放对象的间隔秒数。 /// public float InstanceAutoReleaseInterval { get { return m_InstancePool.AutoReleaseInterval; } set { m_InstancePool.AutoReleaseInterval = value; } } /// /// 获取或设置实体组实例对象池的容量。 /// public int InstanceCapacity { get { return m_InstancePool.Capacity; } set { m_InstancePool.Capacity = value; } } /// /// 获取或设置实体组实例对象池对象过期秒数。 /// public float InstanceExpireTime { get { return m_InstancePool.ExpireTime; } set { m_InstancePool.ExpireTime = value; } } /// /// 获取或设置实体组实例对象池的优先级。 /// public int InstancePriority { get { return m_InstancePool.Priority; } set { m_InstancePool.Priority = value; } } /// /// 获取实体组辅助器。 /// public IEntityGroupHelper Helper { get { return m_EntityGroupHelper; } } /// /// 实体组轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void Update(float elapseSeconds, float realElapseSeconds) { LinkedListNode current = m_Entities.First; while (current != null) { m_CachedNode = current.Next; current.Value.OnUpdate(elapseSeconds, realElapseSeconds); current = m_CachedNode; m_CachedNode = null; } } /// /// 实体组中是否存在实体。 /// /// 实体序列编号。 /// 实体组中是否存在实体。 public bool HasEntity(int entityId) { foreach (IEntity entity in m_Entities) { if (entity.Id == entityId) { return true; } } return false; } /// /// 实体组中是否存在实体。 /// /// 实体资源名称。 /// 实体组中是否存在实体。 public bool HasEntity(string entityAssetName) { if (string.IsNullOrEmpty(entityAssetName)) { throw new GameFrameworkException("Entity asset name is invalid."); } foreach (IEntity entity in m_Entities) { if (entity.EntityAssetName == entityAssetName) { return true; } } return false; } /// /// 从实体组中获取实体。 /// /// 实体序列编号。 /// 要获取的实体。 public IEntity GetEntity(int entityId) { foreach (IEntity entity in m_Entities) { if (entity.Id == entityId) { return entity; } } return null; } /// /// 从实体组中获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 public IEntity GetEntity(string entityAssetName) { if (string.IsNullOrEmpty(entityAssetName)) { throw new GameFrameworkException("Entity asset name is invalid."); } foreach (IEntity entity in m_Entities) { if (entity.EntityAssetName == entityAssetName) { return entity; } } return null; } /// /// 从实体组中获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 public IEntity[] GetEntities(string entityAssetName) { if (string.IsNullOrEmpty(entityAssetName)) { throw new GameFrameworkException("Entity asset name is invalid."); } List results = new List(); foreach (IEntity entity in m_Entities) { if (entity.EntityAssetName == entityAssetName) { results.Add(entity); } } return results.ToArray(); } /// /// 从实体组中获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 public void GetEntities(string entityAssetName, List results) { if (string.IsNullOrEmpty(entityAssetName)) { throw new GameFrameworkException("Entity asset name is invalid."); } if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (IEntity entity in m_Entities) { if (entity.EntityAssetName == entityAssetName) { results.Add(entity); } } } /// /// 从实体组中获取所有实体。 /// /// 实体组中的所有实体。 public IEntity[] GetAllEntities() { List results = new List(); foreach (IEntity entity in m_Entities) { results.Add(entity); } return results.ToArray(); } /// /// 从实体组中获取所有实体。 /// /// 实体组中的所有实体。 public void GetAllEntities(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (IEntity entity in m_Entities) { results.Add(entity); } } /// /// 往实体组增加实体。 /// /// 要增加的实体。 public void AddEntity(IEntity entity) { m_Entities.AddLast(entity); } /// /// 从实体组移除实体。 /// /// 要移除的实体。 public void RemoveEntity(IEntity entity) { if (m_CachedNode != null && m_CachedNode.Value == entity) { m_CachedNode = m_CachedNode.Next; } if (!m_Entities.Remove(entity)) { throw new GameFrameworkException(Utility.Text.Format("Entity group '{0}' not exists specified entity '[{1}]{2}'.", m_Name, entity.Id, entity.EntityAssetName)); } } public void RegisterEntityInstanceObject(EntityInstanceObject obj, bool spawned) { m_InstancePool.Register(obj, spawned); } public EntityInstanceObject SpawnEntityInstanceObject(string name) { return m_InstancePool.Spawn(name); } public void UnspawnEntity(IEntity entity) { m_InstancePool.Unspawn(entity.Handle); } public void SetEntityInstanceLocked(object entityInstance, bool locked) { if (entityInstance == null) { throw new GameFrameworkException("Entity instance is invalid."); } m_InstancePool.SetLocked(entityInstance, locked); } public void SetEntityInstancePriority(object entityInstance, int priority) { if (entityInstance == null) { throw new GameFrameworkException("Entity instance is invalid."); } m_InstancePool.SetPriority(entityInstance, priority); } } } } ================================================ FILE: GameFramework/Entity/EntityManager.EntityInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.Entity { internal sealed partial class EntityManager : GameFrameworkModule, IEntityManager { /// /// 实体信息。 /// private sealed class EntityInfo : IReference { private IEntity m_Entity; private EntityStatus m_Status; private IEntity m_ParentEntity; private List m_ChildEntities; public EntityInfo() { m_Entity = null; m_Status = EntityStatus.Unknown; m_ParentEntity = null; m_ChildEntities = new List(); } public IEntity Entity { get { return m_Entity; } } public EntityStatus Status { get { return m_Status; } set { m_Status = value; } } public IEntity ParentEntity { get { return m_ParentEntity; } set { m_ParentEntity = value; } } public int ChildEntityCount { get { return m_ChildEntities.Count; } } public static EntityInfo Create(IEntity entity) { if (entity == null) { throw new GameFrameworkException("Entity is invalid."); } EntityInfo entityInfo = ReferencePool.Acquire(); entityInfo.m_Entity = entity; entityInfo.m_Status = EntityStatus.WillInit; return entityInfo; } public void Clear() { m_Entity = null; m_Status = EntityStatus.Unknown; m_ParentEntity = null; m_ChildEntities.Clear(); } public IEntity GetChildEntity() { return m_ChildEntities.Count > 0 ? m_ChildEntities[0] : null; } public IEntity[] GetChildEntities() { return m_ChildEntities.ToArray(); } public void GetChildEntities(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (IEntity childEntity in m_ChildEntities) { results.Add(childEntity); } } public void AddChildEntity(IEntity childEntity) { if (m_ChildEntities.Contains(childEntity)) { throw new GameFrameworkException("Can not add child entity which is already exist."); } m_ChildEntities.Add(childEntity); } public void RemoveChildEntity(IEntity childEntity) { if (!m_ChildEntities.Remove(childEntity)) { throw new GameFrameworkException("Can not remove child entity which is not exist."); } } } } } ================================================ FILE: GameFramework/Entity/EntityManager.EntityInstanceObject.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.ObjectPool; namespace GameFramework.Entity { internal sealed partial class EntityManager : GameFrameworkModule, IEntityManager { /// /// 实体实例对象。 /// private sealed class EntityInstanceObject : ObjectBase { private object m_EntityAsset; private IEntityHelper m_EntityHelper; public EntityInstanceObject() { m_EntityAsset = null; m_EntityHelper = null; } public static EntityInstanceObject Create(string name, object entityAsset, object entityInstance, IEntityHelper entityHelper) { if (entityAsset == null) { throw new GameFrameworkException("Entity asset is invalid."); } if (entityHelper == null) { throw new GameFrameworkException("Entity helper is invalid."); } EntityInstanceObject entityInstanceObject = ReferencePool.Acquire(); entityInstanceObject.Initialize(name, entityInstance); entityInstanceObject.m_EntityAsset = entityAsset; entityInstanceObject.m_EntityHelper = entityHelper; return entityInstanceObject; } public override void Clear() { base.Clear(); m_EntityAsset = null; m_EntityHelper = null; } protected internal override void Release(bool isShutdown) { m_EntityHelper.ReleaseEntity(m_EntityAsset, Target); } } } } ================================================ FILE: GameFramework/Entity/EntityManager.EntityStatus.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Entity { internal sealed partial class EntityManager : GameFrameworkModule, IEntityManager { /// /// 实体状态。 /// private enum EntityStatus : byte { Unknown = 0, WillInit, Inited, WillShow, Showed, WillHide, Hidden, WillRecycle, Recycled } } } ================================================ FILE: GameFramework/Entity/EntityManager.ShowEntityInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Entity { internal sealed partial class EntityManager : GameFrameworkModule, IEntityManager { private sealed class ShowEntityInfo : IReference { private int m_SerialId; private int m_EntityId; private EntityGroup m_EntityGroup; private object m_UserData; public ShowEntityInfo() { m_SerialId = 0; m_EntityId = 0; m_EntityGroup = null; m_UserData = null; } public int SerialId { get { return m_SerialId; } } public int EntityId { get { return m_EntityId; } } public EntityGroup EntityGroup { get { return m_EntityGroup; } } public object UserData { get { return m_UserData; } } public static ShowEntityInfo Create(int serialId, int entityId, EntityGroup entityGroup, object userData) { ShowEntityInfo showEntityInfo = ReferencePool.Acquire(); showEntityInfo.m_SerialId = serialId; showEntityInfo.m_EntityId = entityId; showEntityInfo.m_EntityGroup = entityGroup; showEntityInfo.m_UserData = userData; return showEntityInfo; } public void Clear() { m_SerialId = 0; m_EntityId = 0; m_EntityGroup = null; m_UserData = null; } } } } ================================================ FILE: GameFramework/Entity/EntityManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.ObjectPool; using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.Entity { /// /// 实体管理器。 /// internal sealed partial class EntityManager : GameFrameworkModule, IEntityManager { private readonly Dictionary m_EntityInfos; private readonly Dictionary m_EntityGroups; private readonly Dictionary m_EntitiesBeingLoaded; private readonly HashSet m_EntitiesToReleaseOnLoad; private readonly Queue m_RecycleQueue; private readonly LoadAssetCallbacks m_LoadAssetCallbacks; private IObjectPoolManager m_ObjectPoolManager; private IResourceManager m_ResourceManager; private IEntityHelper m_EntityHelper; private int m_Serial; private bool m_IsShutdown; private EventHandler m_ShowEntitySuccessEventHandler; private EventHandler m_ShowEntityFailureEventHandler; private EventHandler m_ShowEntityUpdateEventHandler; private EventHandler m_ShowEntityDependencyAssetEventHandler; private EventHandler m_HideEntityCompleteEventHandler; /// /// 初始化实体管理器的新实例。 /// public EntityManager() { m_EntityInfos = new Dictionary(); m_EntityGroups = new Dictionary(StringComparer.Ordinal); m_EntitiesBeingLoaded = new Dictionary(); m_EntitiesToReleaseOnLoad = new HashSet(); m_RecycleQueue = new Queue(); m_LoadAssetCallbacks = new LoadAssetCallbacks(LoadAssetSuccessCallback, LoadAssetFailureCallback, LoadAssetUpdateCallback, LoadAssetDependencyAssetCallback); m_ObjectPoolManager = null; m_ResourceManager = null; m_EntityHelper = null; m_Serial = 0; m_IsShutdown = false; m_ShowEntitySuccessEventHandler = null; m_ShowEntityFailureEventHandler = null; m_ShowEntityUpdateEventHandler = null; m_ShowEntityDependencyAssetEventHandler = null; m_HideEntityCompleteEventHandler = null; } /// /// 获取实体数量。 /// public int EntityCount { get { return m_EntityInfos.Count; } } /// /// 获取实体组数量。 /// public int EntityGroupCount { get { return m_EntityGroups.Count; } } /// /// 显示实体成功事件。 /// public event EventHandler ShowEntitySuccess { add { m_ShowEntitySuccessEventHandler += value; } remove { m_ShowEntitySuccessEventHandler -= value; } } /// /// 显示实体失败事件。 /// public event EventHandler ShowEntityFailure { add { m_ShowEntityFailureEventHandler += value; } remove { m_ShowEntityFailureEventHandler -= value; } } /// /// 显示实体更新事件。 /// public event EventHandler ShowEntityUpdate { add { m_ShowEntityUpdateEventHandler += value; } remove { m_ShowEntityUpdateEventHandler -= value; } } /// /// 显示实体时加载依赖资源事件。 /// public event EventHandler ShowEntityDependencyAsset { add { m_ShowEntityDependencyAssetEventHandler += value; } remove { m_ShowEntityDependencyAssetEventHandler -= value; } } /// /// 隐藏实体完成事件。 /// public event EventHandler HideEntityComplete { add { m_HideEntityCompleteEventHandler += value; } remove { m_HideEntityCompleteEventHandler -= value; } } /// /// 实体管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { while (m_RecycleQueue.Count > 0) { EntityInfo entityInfo = m_RecycleQueue.Dequeue(); IEntity entity = entityInfo.Entity; EntityGroup entityGroup = (EntityGroup)entity.EntityGroup; if (entityGroup == null) { throw new GameFrameworkException("Entity group is invalid."); } entityInfo.Status = EntityStatus.WillRecycle; entity.OnRecycle(); entityInfo.Status = EntityStatus.Recycled; entityGroup.UnspawnEntity(entity); ReferencePool.Release(entityInfo); } foreach (KeyValuePair entityGroup in m_EntityGroups) { entityGroup.Value.Update(elapseSeconds, realElapseSeconds); } } /// /// 关闭并清理实体管理器。 /// internal override void Shutdown() { m_IsShutdown = true; HideAllLoadedEntities(); m_EntityGroups.Clear(); m_EntitiesBeingLoaded.Clear(); m_EntitiesToReleaseOnLoad.Clear(); m_RecycleQueue.Clear(); } /// /// 设置对象池管理器。 /// /// 对象池管理器。 public void SetObjectPoolManager(IObjectPoolManager objectPoolManager) { if (objectPoolManager == null) { throw new GameFrameworkException("Object pool manager is invalid."); } m_ObjectPoolManager = objectPoolManager; } /// /// 设置资源管理器。 /// /// 资源管理器。 public void SetResourceManager(IResourceManager resourceManager) { if (resourceManager == null) { throw new GameFrameworkException("Resource manager is invalid."); } m_ResourceManager = resourceManager; } /// /// 设置实体辅助器。 /// /// 实体辅助器。 public void SetEntityHelper(IEntityHelper entityHelper) { if (entityHelper == null) { throw new GameFrameworkException("Entity helper is invalid."); } m_EntityHelper = entityHelper; } /// /// 是否存在实体组。 /// /// 实体组名称。 /// 是否存在实体组。 public bool HasEntityGroup(string entityGroupName) { if (string.IsNullOrEmpty(entityGroupName)) { throw new GameFrameworkException("Entity group name is invalid."); } return m_EntityGroups.ContainsKey(entityGroupName); } /// /// 获取实体组。 /// /// 实体组名称。 /// 要获取的实体组。 public IEntityGroup GetEntityGroup(string entityGroupName) { if (string.IsNullOrEmpty(entityGroupName)) { throw new GameFrameworkException("Entity group name is invalid."); } EntityGroup entityGroup = null; if (m_EntityGroups.TryGetValue(entityGroupName, out entityGroup)) { return entityGroup; } return null; } /// /// 获取所有实体组。 /// /// 所有实体组。 public IEntityGroup[] GetAllEntityGroups() { int index = 0; IEntityGroup[] results = new IEntityGroup[m_EntityGroups.Count]; foreach (KeyValuePair entityGroup in m_EntityGroups) { results[index++] = entityGroup.Value; } return results; } /// /// 获取所有实体组。 /// /// 所有实体组。 public void GetAllEntityGroups(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair entityGroup in m_EntityGroups) { results.Add(entityGroup.Value); } } /// /// 增加实体组。 /// /// 实体组名称。 /// 实体实例对象池自动释放可释放对象的间隔秒数。 /// 实体实例对象池容量。 /// 实体实例对象池对象过期秒数。 /// 实体实例对象池的优先级。 /// 实体组辅助器。 /// 是否增加实体组成功。 public bool AddEntityGroup(string entityGroupName, float instanceAutoReleaseInterval, int instanceCapacity, float instanceExpireTime, int instancePriority, IEntityGroupHelper entityGroupHelper) { if (string.IsNullOrEmpty(entityGroupName)) { throw new GameFrameworkException("Entity group name is invalid."); } if (entityGroupHelper == null) { throw new GameFrameworkException("Entity group helper is invalid."); } if (m_ObjectPoolManager == null) { throw new GameFrameworkException("You must set object pool manager first."); } if (HasEntityGroup(entityGroupName)) { return false; } m_EntityGroups.Add(entityGroupName, new EntityGroup(entityGroupName, instanceAutoReleaseInterval, instanceCapacity, instanceExpireTime, instancePriority, entityGroupHelper, m_ObjectPoolManager)); return true; } /// /// 是否存在实体。 /// /// 实体编号。 /// 是否存在实体。 public bool HasEntity(int entityId) { return m_EntityInfos.ContainsKey(entityId); } /// /// 是否存在实体。 /// /// 实体资源名称。 /// 是否存在实体。 public bool HasEntity(string entityAssetName) { if (string.IsNullOrEmpty(entityAssetName)) { throw new GameFrameworkException("Entity asset name is invalid."); } foreach (KeyValuePair entityInfo in m_EntityInfos) { if (entityInfo.Value.Entity.EntityAssetName == entityAssetName) { return true; } } return false; } /// /// 获取实体。 /// /// 实体编号。 /// 要获取的实体。 public IEntity GetEntity(int entityId) { EntityInfo entityInfo = GetEntityInfo(entityId); if (entityInfo == null) { return null; } return entityInfo.Entity; } /// /// 获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 public IEntity GetEntity(string entityAssetName) { if (string.IsNullOrEmpty(entityAssetName)) { throw new GameFrameworkException("Entity asset name is invalid."); } foreach (KeyValuePair entityInfo in m_EntityInfos) { if (entityInfo.Value.Entity.EntityAssetName == entityAssetName) { return entityInfo.Value.Entity; } } return null; } /// /// 获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 public IEntity[] GetEntities(string entityAssetName) { if (string.IsNullOrEmpty(entityAssetName)) { throw new GameFrameworkException("Entity asset name is invalid."); } List results = new List(); foreach (KeyValuePair entityInfo in m_EntityInfos) { if (entityInfo.Value.Entity.EntityAssetName == entityAssetName) { results.Add(entityInfo.Value.Entity); } } return results.ToArray(); } /// /// 获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 public void GetEntities(string entityAssetName, List results) { if (string.IsNullOrEmpty(entityAssetName)) { throw new GameFrameworkException("Entity asset name is invalid."); } if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair entityInfo in m_EntityInfos) { if (entityInfo.Value.Entity.EntityAssetName == entityAssetName) { results.Add(entityInfo.Value.Entity); } } } /// /// 获取所有已加载的实体。 /// /// 所有已加载的实体。 public IEntity[] GetAllLoadedEntities() { int index = 0; IEntity[] results = new IEntity[m_EntityInfos.Count]; foreach (KeyValuePair entityInfo in m_EntityInfos) { results[index++] = entityInfo.Value.Entity; } return results; } /// /// 获取所有已加载的实体。 /// /// 所有已加载的实体。 public void GetAllLoadedEntities(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair entityInfo in m_EntityInfos) { results.Add(entityInfo.Value.Entity); } } /// /// 获取所有正在加载实体的编号。 /// /// 所有正在加载实体的编号。 public int[] GetAllLoadingEntityIds() { int index = 0; int[] results = new int[m_EntitiesBeingLoaded.Count]; foreach (KeyValuePair entityBeingLoaded in m_EntitiesBeingLoaded) { results[index++] = entityBeingLoaded.Key; } return results; } /// /// 获取所有正在加载实体的编号。 /// /// 所有正在加载实体的编号。 public void GetAllLoadingEntityIds(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair entityBeingLoaded in m_EntitiesBeingLoaded) { results.Add(entityBeingLoaded.Key); } } /// /// 是否正在加载实体。 /// /// 实体编号。 /// 是否正在加载实体。 public bool IsLoadingEntity(int entityId) { return m_EntitiesBeingLoaded.ContainsKey(entityId); } /// /// 是否是合法的实体。 /// /// 实体。 /// 实体是否合法。 public bool IsValidEntity(IEntity entity) { if (entity == null) { return false; } return HasEntity(entity.Id); } /// /// 显示实体。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 public void ShowEntity(int entityId, string entityAssetName, string entityGroupName) { ShowEntity(entityId, entityAssetName, entityGroupName, Constant.DefaultPriority, null); } /// /// 显示实体。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 /// 加载实体资源的优先级。 public void ShowEntity(int entityId, string entityAssetName, string entityGroupName, int priority) { ShowEntity(entityId, entityAssetName, entityGroupName, priority, null); } /// /// 显示实体。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 /// 用户自定义数据。 public void ShowEntity(int entityId, string entityAssetName, string entityGroupName, object userData) { ShowEntity(entityId, entityAssetName, entityGroupName, Constant.DefaultPriority, userData); } /// /// 显示实体。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 /// 加载实体资源的优先级。 /// 用户自定义数据。 public void ShowEntity(int entityId, string entityAssetName, string entityGroupName, int priority, object userData) { if (m_ResourceManager == null) { throw new GameFrameworkException("You must set resource manager first."); } if (m_EntityHelper == null) { throw new GameFrameworkException("You must set entity helper first."); } if (string.IsNullOrEmpty(entityAssetName)) { throw new GameFrameworkException("Entity asset name is invalid."); } if (string.IsNullOrEmpty(entityGroupName)) { throw new GameFrameworkException("Entity group name is invalid."); } if (HasEntity(entityId)) { throw new GameFrameworkException(Utility.Text.Format("Entity id '{0}' is already exist.", entityId)); } if (IsLoadingEntity(entityId)) { throw new GameFrameworkException(Utility.Text.Format("Entity '{0}' is already being loaded.", entityId)); } EntityGroup entityGroup = (EntityGroup)GetEntityGroup(entityGroupName); if (entityGroup == null) { throw new GameFrameworkException(Utility.Text.Format("Entity group '{0}' is not exist.", entityGroupName)); } EntityInstanceObject entityInstanceObject = entityGroup.SpawnEntityInstanceObject(entityAssetName); if (entityInstanceObject == null) { int serialId = ++m_Serial; m_EntitiesBeingLoaded.Add(entityId, serialId); m_ResourceManager.LoadAsset(entityAssetName, priority, m_LoadAssetCallbacks, ShowEntityInfo.Create(serialId, entityId, entityGroup, userData)); return; } InternalShowEntity(entityId, entityAssetName, entityGroup, entityInstanceObject.Target, false, 0f, userData); } /// /// 隐藏实体。 /// /// 实体编号。 public void HideEntity(int entityId) { HideEntity(entityId, null); } /// /// 隐藏实体。 /// /// 实体编号。 /// 用户自定义数据。 public void HideEntity(int entityId, object userData) { if (IsLoadingEntity(entityId)) { m_EntitiesToReleaseOnLoad.Add(m_EntitiesBeingLoaded[entityId]); m_EntitiesBeingLoaded.Remove(entityId); return; } EntityInfo entityInfo = GetEntityInfo(entityId); if (entityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find entity '{0}'.", entityId)); } InternalHideEntity(entityInfo, userData); } /// /// 隐藏实体。 /// /// 实体。 public void HideEntity(IEntity entity) { HideEntity(entity, null); } /// /// 隐藏实体。 /// /// 实体。 /// 用户自定义数据。 public void HideEntity(IEntity entity, object userData) { if (entity == null) { throw new GameFrameworkException("Entity is invalid."); } HideEntity(entity.Id, userData); } /// /// 隐藏所有已加载的实体。 /// public void HideAllLoadedEntities() { HideAllLoadedEntities(null); } /// /// 隐藏所有已加载的实体。 /// /// 用户自定义数据。 public void HideAllLoadedEntities(object userData) { while (m_EntityInfos.Count > 0) { foreach (KeyValuePair entityInfo in m_EntityInfos) { InternalHideEntity(entityInfo.Value, userData); break; } } } /// /// 隐藏所有正在加载的实体。 /// public void HideAllLoadingEntities() { foreach (KeyValuePair entityBeingLoaded in m_EntitiesBeingLoaded) { m_EntitiesToReleaseOnLoad.Add(entityBeingLoaded.Value); } m_EntitiesBeingLoaded.Clear(); } /// /// 获取父实体。 /// /// 要获取父实体的子实体的实体编号。 /// 子实体的父实体。 public IEntity GetParentEntity(int childEntityId) { EntityInfo childEntityInfo = GetEntityInfo(childEntityId); if (childEntityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find child entity '{0}'.", childEntityId)); } return childEntityInfo.ParentEntity; } /// /// 获取父实体。 /// /// 要获取父实体的子实体。 /// 子实体的父实体。 public IEntity GetParentEntity(IEntity childEntity) { if (childEntity == null) { throw new GameFrameworkException("Child entity is invalid."); } return GetParentEntity(childEntity.Id); } /// /// 获取子实体数量。 /// /// 要获取子实体数量的父实体的实体编号。 /// 子实体数量。 public int GetChildEntityCount(int parentEntityId) { EntityInfo parentEntityInfo = GetEntityInfo(parentEntityId); if (parentEntityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find parent entity '{0}'.", parentEntityId)); } return parentEntityInfo.ChildEntityCount; } /// /// 获取子实体。 /// /// 要获取子实体的父实体的实体编号。 /// 子实体。 public IEntity GetChildEntity(int parentEntityId) { EntityInfo parentEntityInfo = GetEntityInfo(parentEntityId); if (parentEntityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find parent entity '{0}'.", parentEntityId)); } return parentEntityInfo.GetChildEntity(); } /// /// 获取子实体。 /// /// 要获取子实体的父实体。 /// 子实体。 public IEntity GetChildEntity(IEntity parentEntity) { if (parentEntity == null) { throw new GameFrameworkException("Parent entity is invalid."); } return GetChildEntity(parentEntity.Id); } /// /// 获取所有子实体。 /// /// 要获取所有子实体的父实体的实体编号。 /// 所有子实体。 public IEntity[] GetChildEntities(int parentEntityId) { EntityInfo parentEntityInfo = GetEntityInfo(parentEntityId); if (parentEntityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find parent entity '{0}'.", parentEntityId)); } return parentEntityInfo.GetChildEntities(); } /// /// 获取所有子实体。 /// /// 要获取所有子实体的父实体的实体编号。 /// 所有子实体。 public void GetChildEntities(int parentEntityId, List results) { EntityInfo parentEntityInfo = GetEntityInfo(parentEntityId); if (parentEntityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find parent entity '{0}'.", parentEntityId)); } parentEntityInfo.GetChildEntities(results); } /// /// 获取所有子实体。 /// /// 要获取所有子实体的父实体。 /// 所有子实体。 public IEntity[] GetChildEntities(IEntity parentEntity) { if (parentEntity == null) { throw new GameFrameworkException("Parent entity is invalid."); } return GetChildEntities(parentEntity.Id); } /// /// 获取所有子实体。 /// /// 要获取所有子实体的父实体。 /// 所有子实体。 public void GetChildEntities(IEntity parentEntity, List results) { if (parentEntity == null) { throw new GameFrameworkException("Parent entity is invalid."); } GetChildEntities(parentEntity.Id, results); } /// /// 附加子实体。 /// /// 要附加的子实体的实体编号。 /// 被附加的父实体的实体编号。 public void AttachEntity(int childEntityId, int parentEntityId) { AttachEntity(childEntityId, parentEntityId, null); } /// /// 附加子实体。 /// /// 要附加的子实体的实体编号。 /// 被附加的父实体的实体编号。 /// 用户自定义数据。 public void AttachEntity(int childEntityId, int parentEntityId, object userData) { if (childEntityId == parentEntityId) { throw new GameFrameworkException(Utility.Text.Format("Can not attach entity when child entity id equals to parent entity id '{0}'.", parentEntityId)); } EntityInfo childEntityInfo = GetEntityInfo(childEntityId); if (childEntityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find child entity '{0}'.", childEntityId)); } if (childEntityInfo.Status >= EntityStatus.WillHide) { throw new GameFrameworkException(Utility.Text.Format("Can not attach entity when child entity status is '{0}'.", childEntityInfo.Status)); } EntityInfo parentEntityInfo = GetEntityInfo(parentEntityId); if (parentEntityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find parent entity '{0}'.", parentEntityId)); } if (parentEntityInfo.Status >= EntityStatus.WillHide) { throw new GameFrameworkException(Utility.Text.Format("Can not attach entity when parent entity status is '{0}'.", parentEntityInfo.Status)); } IEntity childEntity = childEntityInfo.Entity; IEntity parentEntity = parentEntityInfo.Entity; DetachEntity(childEntity.Id, userData); childEntityInfo.ParentEntity = parentEntity; parentEntityInfo.AddChildEntity(childEntity); parentEntity.OnAttached(childEntity, userData); childEntity.OnAttachTo(parentEntity, userData); } /// /// 附加子实体。 /// /// 要附加的子实体的实体编号。 /// 被附加的父实体。 public void AttachEntity(int childEntityId, IEntity parentEntity) { AttachEntity(childEntityId, parentEntity, null); } /// /// 附加子实体。 /// /// 要附加的子实体的实体编号。 /// 被附加的父实体。 /// 用户自定义数据。 public void AttachEntity(int childEntityId, IEntity parentEntity, object userData) { if (parentEntity == null) { throw new GameFrameworkException("Parent entity is invalid."); } AttachEntity(childEntityId, parentEntity.Id, userData); } /// /// 附加子实体。 /// /// 要附加的子实体。 /// 被附加的父实体的实体编号。 public void AttachEntity(IEntity childEntity, int parentEntityId) { AttachEntity(childEntity, parentEntityId, null); } /// /// 附加子实体。 /// /// 要附加的子实体。 /// 被附加的父实体的实体编号。 /// 用户自定义数据。 public void AttachEntity(IEntity childEntity, int parentEntityId, object userData) { if (childEntity == null) { throw new GameFrameworkException("Child entity is invalid."); } AttachEntity(childEntity.Id, parentEntityId, userData); } /// /// 附加子实体。 /// /// 要附加的子实体。 /// 被附加的父实体。 public void AttachEntity(IEntity childEntity, IEntity parentEntity) { AttachEntity(childEntity, parentEntity, null); } /// /// 附加子实体。 /// /// 要附加的子实体。 /// 被附加的父实体。 /// 用户自定义数据。 public void AttachEntity(IEntity childEntity, IEntity parentEntity, object userData) { if (childEntity == null) { throw new GameFrameworkException("Child entity is invalid."); } if (parentEntity == null) { throw new GameFrameworkException("Parent entity is invalid."); } AttachEntity(childEntity.Id, parentEntity.Id, userData); } /// /// 解除子实体。 /// /// 要解除的子实体的实体编号。 public void DetachEntity(int childEntityId) { DetachEntity(childEntityId, null); } /// /// 解除子实体。 /// /// 要解除的子实体的实体编号。 /// 用户自定义数据。 public void DetachEntity(int childEntityId, object userData) { EntityInfo childEntityInfo = GetEntityInfo(childEntityId); if (childEntityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find child entity '{0}'.", childEntityId)); } IEntity parentEntity = childEntityInfo.ParentEntity; if (parentEntity == null) { return; } EntityInfo parentEntityInfo = GetEntityInfo(parentEntity.Id); if (parentEntityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find parent entity '{0}'.", parentEntity.Id)); } IEntity childEntity = childEntityInfo.Entity; childEntityInfo.ParentEntity = null; parentEntityInfo.RemoveChildEntity(childEntity); parentEntity.OnDetached(childEntity, userData); childEntity.OnDetachFrom(parentEntity, userData); } /// /// 解除子实体。 /// /// 要解除的子实体。 public void DetachEntity(IEntity childEntity) { DetachEntity(childEntity, null); } /// /// 解除子实体。 /// /// 要解除的子实体。 /// 用户自定义数据。 public void DetachEntity(IEntity childEntity, object userData) { if (childEntity == null) { throw new GameFrameworkException("Child entity is invalid."); } DetachEntity(childEntity.Id, userData); } /// /// 解除所有子实体。 /// /// 被解除的父实体的实体编号。 public void DetachChildEntities(int parentEntityId) { DetachChildEntities(parentEntityId, null); } /// /// 解除所有子实体。 /// /// 被解除的父实体的实体编号。 /// 用户自定义数据。 public void DetachChildEntities(int parentEntityId, object userData) { EntityInfo parentEntityInfo = GetEntityInfo(parentEntityId); if (parentEntityInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find parent entity '{0}'.", parentEntityId)); } while (parentEntityInfo.ChildEntityCount > 0) { IEntity childEntity = parentEntityInfo.GetChildEntity(); DetachEntity(childEntity.Id, userData); } } /// /// 解除所有子实体。 /// /// 被解除的父实体。 public void DetachChildEntities(IEntity parentEntity) { DetachChildEntities(parentEntity, null); } /// /// 解除所有子实体。 /// /// 被解除的父实体。 /// 用户自定义数据。 public void DetachChildEntities(IEntity parentEntity, object userData) { if (parentEntity == null) { throw new GameFrameworkException("Parent entity is invalid."); } DetachChildEntities(parentEntity.Id, userData); } /// /// 获取实体信息。 /// /// 实体编号。 /// 实体信息。 private EntityInfo GetEntityInfo(int entityId) { EntityInfo entityInfo = null; if (m_EntityInfos.TryGetValue(entityId, out entityInfo)) { return entityInfo; } return null; } private void InternalShowEntity(int entityId, string entityAssetName, EntityGroup entityGroup, object entityInstance, bool isNewInstance, float duration, object userData) { try { IEntity entity = m_EntityHelper.CreateEntity(entityInstance, entityGroup, userData); if (entity == null) { throw new GameFrameworkException("Can not create entity in entity helper."); } EntityInfo entityInfo = EntityInfo.Create(entity); m_EntityInfos.Add(entityId, entityInfo); entityInfo.Status = EntityStatus.WillInit; entity.OnInit(entityId, entityAssetName, entityGroup, isNewInstance, userData); entityInfo.Status = EntityStatus.Inited; entityGroup.AddEntity(entity); entityInfo.Status = EntityStatus.WillShow; entity.OnShow(userData); entityInfo.Status = EntityStatus.Showed; if (m_ShowEntitySuccessEventHandler != null) { ShowEntitySuccessEventArgs showEntitySuccessEventArgs = ShowEntitySuccessEventArgs.Create(entity, duration, userData); m_ShowEntitySuccessEventHandler(this, showEntitySuccessEventArgs); ReferencePool.Release(showEntitySuccessEventArgs); } } catch (Exception exception) { if (m_ShowEntityFailureEventHandler != null) { ShowEntityFailureEventArgs showEntityFailureEventArgs = ShowEntityFailureEventArgs.Create(entityId, entityAssetName, entityGroup.Name, exception.ToString(), userData); m_ShowEntityFailureEventHandler(this, showEntityFailureEventArgs); ReferencePool.Release(showEntityFailureEventArgs); return; } throw; } } private void InternalHideEntity(EntityInfo entityInfo, object userData) { while (entityInfo.ChildEntityCount > 0) { IEntity childEntity = entityInfo.GetChildEntity(); HideEntity(childEntity.Id, userData); } if (entityInfo.Status == EntityStatus.Hidden) { return; } IEntity entity = entityInfo.Entity; DetachEntity(entity.Id, userData); entityInfo.Status = EntityStatus.WillHide; entity.OnHide(m_IsShutdown, userData); entityInfo.Status = EntityStatus.Hidden; EntityGroup entityGroup = (EntityGroup)entity.EntityGroup; if (entityGroup == null) { throw new GameFrameworkException("Entity group is invalid."); } entityGroup.RemoveEntity(entity); if (!m_EntityInfos.Remove(entity.Id)) { throw new GameFrameworkException("Entity info is unmanaged."); } if (m_HideEntityCompleteEventHandler != null) { HideEntityCompleteEventArgs hideEntityCompleteEventArgs = HideEntityCompleteEventArgs.Create(entity.Id, entity.EntityAssetName, entityGroup, userData); m_HideEntityCompleteEventHandler(this, hideEntityCompleteEventArgs); ReferencePool.Release(hideEntityCompleteEventArgs); } m_RecycleQueue.Enqueue(entityInfo); } private void LoadAssetSuccessCallback(string entityAssetName, object entityAsset, float duration, object userData) { ShowEntityInfo showEntityInfo = (ShowEntityInfo)userData; if (showEntityInfo == null) { throw new GameFrameworkException("Show entity info is invalid."); } if (m_EntitiesToReleaseOnLoad.Contains(showEntityInfo.SerialId)) { m_EntitiesToReleaseOnLoad.Remove(showEntityInfo.SerialId); ReferencePool.Release(showEntityInfo); m_EntityHelper.ReleaseEntity(entityAsset, null); return; } m_EntitiesBeingLoaded.Remove(showEntityInfo.EntityId); EntityInstanceObject entityInstanceObject = EntityInstanceObject.Create(entityAssetName, entityAsset, m_EntityHelper.InstantiateEntity(entityAsset), m_EntityHelper); showEntityInfo.EntityGroup.RegisterEntityInstanceObject(entityInstanceObject, true); InternalShowEntity(showEntityInfo.EntityId, entityAssetName, showEntityInfo.EntityGroup, entityInstanceObject.Target, true, duration, showEntityInfo.UserData); ReferencePool.Release(showEntityInfo); } private void LoadAssetFailureCallback(string entityAssetName, LoadResourceStatus status, string errorMessage, object userData) { ShowEntityInfo showEntityInfo = (ShowEntityInfo)userData; if (showEntityInfo == null) { throw new GameFrameworkException("Show entity info is invalid."); } if (m_EntitiesToReleaseOnLoad.Contains(showEntityInfo.SerialId)) { m_EntitiesToReleaseOnLoad.Remove(showEntityInfo.SerialId); return; } m_EntitiesBeingLoaded.Remove(showEntityInfo.EntityId); string appendErrorMessage = Utility.Text.Format("Load entity failure, asset name '{0}', status '{1}', error message '{2}'.", entityAssetName, status, errorMessage); if (m_ShowEntityFailureEventHandler != null) { ShowEntityFailureEventArgs showEntityFailureEventArgs = ShowEntityFailureEventArgs.Create(showEntityInfo.EntityId, entityAssetName, showEntityInfo.EntityGroup.Name, appendErrorMessage, showEntityInfo.UserData); m_ShowEntityFailureEventHandler(this, showEntityFailureEventArgs); ReferencePool.Release(showEntityFailureEventArgs); return; } throw new GameFrameworkException(appendErrorMessage); } private void LoadAssetUpdateCallback(string entityAssetName, float progress, object userData) { ShowEntityInfo showEntityInfo = (ShowEntityInfo)userData; if (showEntityInfo == null) { throw new GameFrameworkException("Show entity info is invalid."); } if (m_ShowEntityUpdateEventHandler != null) { ShowEntityUpdateEventArgs showEntityUpdateEventArgs = ShowEntityUpdateEventArgs.Create(showEntityInfo.EntityId, entityAssetName, showEntityInfo.EntityGroup.Name, progress, showEntityInfo.UserData); m_ShowEntityUpdateEventHandler(this, showEntityUpdateEventArgs); ReferencePool.Release(showEntityUpdateEventArgs); } } private void LoadAssetDependencyAssetCallback(string entityAssetName, string dependencyAssetName, int loadedCount, int totalCount, object userData) { ShowEntityInfo showEntityInfo = (ShowEntityInfo)userData; if (showEntityInfo == null) { throw new GameFrameworkException("Show entity info is invalid."); } if (m_ShowEntityDependencyAssetEventHandler != null) { ShowEntityDependencyAssetEventArgs showEntityDependencyAssetEventArgs = ShowEntityDependencyAssetEventArgs.Create(showEntityInfo.EntityId, entityAssetName, showEntityInfo.EntityGroup.Name, dependencyAssetName, loadedCount, totalCount, showEntityInfo.UserData); m_ShowEntityDependencyAssetEventHandler(this, showEntityDependencyAssetEventArgs); ReferencePool.Release(showEntityDependencyAssetEventArgs); } } } } ================================================ FILE: GameFramework/Entity/HideEntityCompleteEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Entity { /// /// 隐藏实体完成事件。 /// public sealed class HideEntityCompleteEventArgs : GameFrameworkEventArgs { /// /// 初始化隐藏实体完成事件的新实例。 /// public HideEntityCompleteEventArgs() { EntityId = 0; EntityAssetName = null; EntityGroup = null; UserData = null; } /// /// 获取实体编号。 /// public int EntityId { get; private set; } /// /// 获取实体资源名称。 /// public string EntityAssetName { get; private set; } /// /// 获取实体所属的实体组。 /// public IEntityGroup EntityGroup { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建隐藏实体完成事件。 /// /// 实体编号。 /// 实体资源名称。 /// 实体所属的实体组。 /// 用户自定义数据。 /// 创建的隐藏实体完成事件。 public static HideEntityCompleteEventArgs Create(int entityId, string entityAssetName, IEntityGroup entityGroup, object userData) { HideEntityCompleteEventArgs hideEntityCompleteEventArgs = ReferencePool.Acquire(); hideEntityCompleteEventArgs.EntityId = entityId; hideEntityCompleteEventArgs.EntityAssetName = entityAssetName; hideEntityCompleteEventArgs.EntityGroup = entityGroup; hideEntityCompleteEventArgs.UserData = userData; return hideEntityCompleteEventArgs; } /// /// 清理隐藏实体完成事件。 /// public override void Clear() { EntityId = 0; EntityAssetName = null; EntityGroup = null; UserData = null; } } } ================================================ FILE: GameFramework/Entity/IEntity.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Entity { /// /// 实体接口。 /// public interface IEntity { /// /// 获取实体编号。 /// int Id { get; } /// /// 获取实体资源名称。 /// string EntityAssetName { get; } /// /// 获取实体实例。 /// object Handle { get; } /// /// 获取实体所属的实体组。 /// IEntityGroup EntityGroup { get; } /// /// 实体初始化。 /// /// 实体编号。 /// 实体资源名称。 /// 实体所属的实体组。 /// 是否是新实例。 /// 用户自定义数据。 void OnInit(int entityId, string entityAssetName, IEntityGroup entityGroup, bool isNewInstance, object userData); /// /// 实体回收。 /// void OnRecycle(); /// /// 实体显示。 /// /// 用户自定义数据。 void OnShow(object userData); /// /// 实体隐藏。 /// /// 是否是关闭实体管理器时触发。 /// 用户自定义数据。 void OnHide(bool isShutdown, object userData); /// /// 实体附加子实体。 /// /// 附加的子实体。 /// 用户自定义数据。 void OnAttached(IEntity childEntity, object userData); /// /// 实体解除子实体。 /// /// 解除的子实体。 /// 用户自定义数据。 void OnDetached(IEntity childEntity, object userData); /// /// 实体附加子实体。 /// /// 被附加的父实体。 /// 用户自定义数据。 void OnAttachTo(IEntity parentEntity, object userData); /// /// 实体解除子实体。 /// /// 被解除的父实体。 /// 用户自定义数据。 void OnDetachFrom(IEntity parentEntity, object userData); /// /// 实体轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 void OnUpdate(float elapseSeconds, float realElapseSeconds); } } ================================================ FILE: GameFramework/Entity/IEntityGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.Entity { /// /// 实体组接口。 /// public interface IEntityGroup { /// /// 获取实体组名称。 /// string Name { get; } /// /// 获取实体组中实体数量。 /// int EntityCount { get; } /// /// 获取或设置实体组实例对象池自动释放可释放对象的间隔秒数。 /// float InstanceAutoReleaseInterval { get; set; } /// /// 获取或设置实体组实例对象池的容量。 /// int InstanceCapacity { get; set; } /// /// 获取或设置实体组实例对象池对象过期秒数。 /// float InstanceExpireTime { get; set; } /// /// 获取或设置实体组实例对象池的优先级。 /// int InstancePriority { get; set; } /// /// 获取实体组辅助器。 /// IEntityGroupHelper Helper { get; } /// /// 实体组中是否存在实体。 /// /// 实体序列编号。 /// 实体组中是否存在实体。 bool HasEntity(int entityId); /// /// 实体组中是否存在实体。 /// /// 实体资源名称。 /// 实体组中是否存在实体。 bool HasEntity(string entityAssetName); /// /// 从实体组中获取实体。 /// /// 实体序列编号。 /// 要获取的实体。 IEntity GetEntity(int entityId); /// /// 从实体组中获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 IEntity GetEntity(string entityAssetName); /// /// 从实体组中获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 IEntity[] GetEntities(string entityAssetName); /// /// 从实体组中获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 void GetEntities(string entityAssetName, List results); /// /// 从实体组中获取所有实体。 /// /// 实体组中的所有实体。 IEntity[] GetAllEntities(); /// /// 从实体组中获取所有实体。 /// /// 实体组中的所有实体。 void GetAllEntities(List results); /// /// 设置实体实例是否被加锁。 /// /// 实体实例。 /// 实体实例是否被加锁。 void SetEntityInstanceLocked(object entityInstance, bool locked); /// /// 设置实体实例的优先级。 /// /// 实体实例。 /// 实体实例优先级。 void SetEntityInstancePriority(object entityInstance, int priority); } } ================================================ FILE: GameFramework/Entity/IEntityGroupHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Entity { /// /// 实体组辅助器接口。 /// public interface IEntityGroupHelper { } } ================================================ FILE: GameFramework/Entity/IEntityHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Entity { /// /// 实体辅助器接口。 /// public interface IEntityHelper { /// /// 实例化实体。 /// /// 要实例化的实体资源。 /// 实例化后的实体。 object InstantiateEntity(object entityAsset); /// /// 创建实体。 /// /// 实体实例。 /// 实体所属的实体组。 /// 用户自定义数据。 /// 实体。 IEntity CreateEntity(object entityInstance, IEntityGroup entityGroup, object userData); /// /// 释放实体。 /// /// 要释放的实体资源。 /// 要释放的实体实例。 void ReleaseEntity(object entityAsset, object entityInstance); } } ================================================ FILE: GameFramework/Entity/IEntityManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.ObjectPool; using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.Entity { /// /// 实体管理器接口。 /// public interface IEntityManager { /// /// 获取实体数量。 /// int EntityCount { get; } /// /// 获取实体组数量。 /// int EntityGroupCount { get; } /// /// 显示实体成功事件。 /// event EventHandler ShowEntitySuccess; /// /// 显示实体失败事件。 /// event EventHandler ShowEntityFailure; /// /// 显示实体更新事件。 /// event EventHandler ShowEntityUpdate; /// /// 显示实体时加载依赖资源事件。 /// event EventHandler ShowEntityDependencyAsset; /// /// 隐藏实体完成事件。 /// event EventHandler HideEntityComplete; /// /// 设置对象池管理器。 /// /// 对象池管理器。 void SetObjectPoolManager(IObjectPoolManager objectPoolManager); /// /// 设置资源管理器。 /// /// 资源管理器。 void SetResourceManager(IResourceManager resourceManager); /// /// 设置实体辅助器。 /// /// 实体辅助器。 void SetEntityHelper(IEntityHelper entityHelper); /// /// 是否存在实体组。 /// /// 实体组名称。 /// 是否存在实体组。 bool HasEntityGroup(string entityGroupName); /// /// 获取实体组。 /// /// 实体组名称。 /// 要获取的实体组。 IEntityGroup GetEntityGroup(string entityGroupName); /// /// 获取所有实体组。 /// /// 所有实体组。 IEntityGroup[] GetAllEntityGroups(); /// /// 获取所有实体组。 /// /// 所有实体组。 void GetAllEntityGroups(List results); /// /// 增加实体组。 /// /// 实体组名称。 /// 实体实例对象池自动释放可释放对象的间隔秒数。 /// 实体实例对象池容量。 /// 实体实例对象池对象过期秒数。 /// 实体实例对象池的优先级。 /// 实体组辅助器。 /// 是否增加实体组成功。 bool AddEntityGroup(string entityGroupName, float instanceAutoReleaseInterval, int instanceCapacity, float instanceExpireTime, int instancePriority, IEntityGroupHelper entityGroupHelper); /// /// 是否存在实体。 /// /// 实体编号。 /// 是否存在实体。 bool HasEntity(int entityId); /// /// 是否存在实体。 /// /// 实体资源名称。 /// 是否存在实体。 bool HasEntity(string entityAssetName); /// /// 获取实体。 /// /// 实体编号。 /// 要获取的实体。 IEntity GetEntity(int entityId); /// /// 获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 IEntity GetEntity(string entityAssetName); /// /// 获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 IEntity[] GetEntities(string entityAssetName); /// /// 获取实体。 /// /// 实体资源名称。 /// 要获取的实体。 void GetEntities(string entityAssetName, List results); /// /// 获取所有已加载的实体。 /// /// 所有已加载的实体。 IEntity[] GetAllLoadedEntities(); /// /// 获取所有已加载的实体。 /// /// 所有已加载的实体。 void GetAllLoadedEntities(List results); /// /// 获取所有正在加载实体的编号。 /// /// 所有正在加载实体的编号。 int[] GetAllLoadingEntityIds(); /// /// 获取所有正在加载实体的编号。 /// /// 所有正在加载实体的编号。 void GetAllLoadingEntityIds(List results); /// /// 是否正在加载实体。 /// /// 实体编号。 /// 是否正在加载实体。 bool IsLoadingEntity(int entityId); /// /// 是否是合法的实体。 /// /// 实体。 /// 实体是否合法。 bool IsValidEntity(IEntity entity); /// /// 显示实体。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 void ShowEntity(int entityId, string entityAssetName, string entityGroupName); /// /// 显示实体。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 /// 加载实体资源的优先级。 void ShowEntity(int entityId, string entityAssetName, string entityGroupName, int priority); /// /// 显示实体。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 /// 用户自定义数据。 void ShowEntity(int entityId, string entityAssetName, string entityGroupName, object userData); /// /// 显示实体。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 /// 加载实体资源的优先级。 /// 用户自定义数据。 void ShowEntity(int entityId, string entityAssetName, string entityGroupName, int priority, object userData); /// /// 隐藏实体。 /// /// 实体编号。 void HideEntity(int entityId); /// /// 隐藏实体。 /// /// 实体编号。 /// 用户自定义数据。 void HideEntity(int entityId, object userData); /// /// 隐藏实体。 /// /// 实体。 void HideEntity(IEntity entity); /// /// 隐藏实体。 /// /// 实体。 /// 用户自定义数据。 void HideEntity(IEntity entity, object userData); /// /// 隐藏所有已加载的实体。 /// void HideAllLoadedEntities(); /// /// 隐藏所有已加载的实体。 /// /// 用户自定义数据。 void HideAllLoadedEntities(object userData); /// /// 隐藏所有正在加载的实体。 /// void HideAllLoadingEntities(); /// /// 获取父实体。 /// /// 要获取父实体的子实体的实体编号。 /// 子实体的父实体。 IEntity GetParentEntity(int childEntityId); /// /// 获取父实体。 /// /// 要获取父实体的子实体。 /// 子实体的父实体。 IEntity GetParentEntity(IEntity childEntity); /// /// 获取子实体数量。 /// /// 要获取子实体数量的父实体的实体编号。 /// 子实体数量。 int GetChildEntityCount(int parentEntityId); /// /// 获取子实体。 /// /// 要获取子实体的父实体的实体编号。 /// 子实体。 IEntity GetChildEntity(int parentEntityId); /// /// 获取子实体。 /// /// 要获取子实体的父实体。 /// 子实体。 IEntity GetChildEntity(IEntity parentEntity); /// /// 获取所有子实体。 /// /// 要获取所有子实体的父实体的实体编号。 /// 所有子实体。 IEntity[] GetChildEntities(int parentEntityId); /// /// 获取所有子实体。 /// /// 要获取所有子实体的父实体的实体编号。 /// 所有子实体。 void GetChildEntities(int parentEntityId, List results); /// /// 获取所有子实体。 /// /// 要获取所有子实体的父实体。 /// 所有子实体。 IEntity[] GetChildEntities(IEntity parentEntity); /// /// 获取所有子实体。 /// /// 要获取所有子实体的父实体。 /// 所有子实体。 void GetChildEntities(IEntity parentEntity, List results); /// /// 附加子实体。 /// /// 要附加的子实体的实体编号。 /// 被附加的父实体的实体编号。 void AttachEntity(int childEntityId, int parentEntityId); /// /// 附加子实体。 /// /// 要附加的子实体的实体编号。 /// 被附加的父实体的实体编号。 /// 用户自定义数据。 void AttachEntity(int childEntityId, int parentEntityId, object userData); /// /// 附加子实体。 /// /// 要附加的子实体的实体编号。 /// 被附加的父实体。 void AttachEntity(int childEntityId, IEntity parentEntity); /// /// 附加子实体。 /// /// 要附加的子实体的实体编号。 /// 被附加的父实体。 /// 用户自定义数据。 void AttachEntity(int childEntityId, IEntity parentEntity, object userData); /// /// 附加子实体。 /// /// 要附加的子实体。 /// 被附加的父实体的实体编号。 void AttachEntity(IEntity childEntity, int parentEntityId); /// /// 附加子实体。 /// /// 要附加的子实体。 /// 被附加的父实体的实体编号。 /// 用户自定义数据。 void AttachEntity(IEntity childEntity, int parentEntityId, object userData); /// /// 附加子实体。 /// /// 要附加的子实体。 /// 被附加的父实体。 void AttachEntity(IEntity childEntity, IEntity parentEntity); /// /// 附加子实体。 /// /// 要附加的子实体。 /// 被附加的父实体。 /// 用户自定义数据。 void AttachEntity(IEntity childEntity, IEntity parentEntity, object userData); /// /// 解除子实体。 /// /// 要解除的子实体的实体编号。 void DetachEntity(int childEntityId); /// /// 解除子实体。 /// /// 要解除的子实体的实体编号。 /// 用户自定义数据。 void DetachEntity(int childEntityId, object userData); /// /// 解除子实体。 /// /// 要解除的子实体。 void DetachEntity(IEntity childEntity); /// /// 解除子实体。 /// /// 要解除的子实体。 /// 用户自定义数据。 void DetachEntity(IEntity childEntity, object userData); /// /// 解除所有子实体。 /// /// 被解除的父实体的实体编号。 void DetachChildEntities(int parentEntityId); /// /// 解除所有子实体。 /// /// 被解除的父实体的实体编号。 /// 用户自定义数据。 void DetachChildEntities(int parentEntityId, object userData); /// /// 解除所有子实体。 /// /// 被解除的父实体。 void DetachChildEntities(IEntity parentEntity); /// /// 解除所有子实体。 /// /// 被解除的父实体。 /// 用户自定义数据。 void DetachChildEntities(IEntity parentEntity, object userData); } } ================================================ FILE: GameFramework/Entity/ShowEntityDependencyAssetEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Entity { /// /// 显示实体时加载依赖资源事件。 /// public sealed class ShowEntityDependencyAssetEventArgs : GameFrameworkEventArgs { /// /// 初始化显示实体时加载依赖资源事件的新实例。 /// public ShowEntityDependencyAssetEventArgs() { EntityId = 0; EntityAssetName = null; EntityGroupName = null; DependencyAssetName = null; LoadedCount = 0; TotalCount = 0; UserData = null; } /// /// 获取实体编号。 /// public int EntityId { get; private set; } /// /// 获取实体资源名称。 /// public string EntityAssetName { get; private set; } /// /// 获取实体组名称。 /// public string EntityGroupName { get; private set; } /// /// 获取被加载的依赖资源名称。 /// public string DependencyAssetName { get; private set; } /// /// 获取当前已加载依赖资源数量。 /// public int LoadedCount { get; private set; } /// /// 获取总共加载依赖资源数量。 /// public int TotalCount { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建显示实体时加载依赖资源事件。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 /// 被加载的依赖资源名称。 /// 当前已加载依赖资源数量。 /// 总共加载依赖资源数量。 /// 用户自定义数据。 /// 创建的显示实体时加载依赖资源事件。 public static ShowEntityDependencyAssetEventArgs Create(int entityId, string entityAssetName, string entityGroupName, string dependencyAssetName, int loadedCount, int totalCount, object userData) { ShowEntityDependencyAssetEventArgs showEntityDependencyAssetEventArgs = ReferencePool.Acquire(); showEntityDependencyAssetEventArgs.EntityId = entityId; showEntityDependencyAssetEventArgs.EntityAssetName = entityAssetName; showEntityDependencyAssetEventArgs.EntityGroupName = entityGroupName; showEntityDependencyAssetEventArgs.DependencyAssetName = dependencyAssetName; showEntityDependencyAssetEventArgs.LoadedCount = loadedCount; showEntityDependencyAssetEventArgs.TotalCount = totalCount; showEntityDependencyAssetEventArgs.UserData = userData; return showEntityDependencyAssetEventArgs; } /// /// 清理显示实体时加载依赖资源事件。 /// public override void Clear() { EntityId = 0; EntityAssetName = null; EntityGroupName = null; DependencyAssetName = null; LoadedCount = 0; TotalCount = 0; UserData = null; } } } ================================================ FILE: GameFramework/Entity/ShowEntityFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Entity { /// /// 显示实体失败事件。 /// public sealed class ShowEntityFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化显示实体失败事件的新实例。 /// public ShowEntityFailureEventArgs() { EntityId = 0; EntityAssetName = null; EntityGroupName = null; ErrorMessage = null; UserData = null; } /// /// 获取实体编号。 /// public int EntityId { get; private set; } /// /// 获取实体资源名称。 /// public string EntityAssetName { get; private set; } /// /// 获取实体组名称。 /// public string EntityGroupName { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建显示实体失败事件。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 /// 错误信息。 /// 用户自定义数据。 /// 创建的显示实体失败事件。 public static ShowEntityFailureEventArgs Create(int entityId, string entityAssetName, string entityGroupName, string errorMessage, object userData) { ShowEntityFailureEventArgs showEntityFailureEventArgs = ReferencePool.Acquire(); showEntityFailureEventArgs.EntityId = entityId; showEntityFailureEventArgs.EntityAssetName = entityAssetName; showEntityFailureEventArgs.EntityGroupName = entityGroupName; showEntityFailureEventArgs.ErrorMessage = errorMessage; showEntityFailureEventArgs.UserData = userData; return showEntityFailureEventArgs; } /// /// 清理显示实体失败事件。 /// public override void Clear() { EntityId = 0; EntityAssetName = null; EntityGroupName = null; ErrorMessage = null; UserData = null; } } } ================================================ FILE: GameFramework/Entity/ShowEntitySuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Entity { /// /// 显示实体成功事件。 /// public sealed class ShowEntitySuccessEventArgs : GameFrameworkEventArgs { /// /// 初始化显示实体成功事件的新实例。 /// public ShowEntitySuccessEventArgs() { Entity = null; Duration = 0f; UserData = null; } /// /// 获取显示成功的实体。 /// public IEntity Entity { get; private set; } /// /// 获取加载持续时间。 /// public float Duration { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建显示实体成功事件。 /// /// 加载成功的实体。 /// 加载持续时间。 /// 用户自定义数据。 /// 创建的显示实体成功事件。 public static ShowEntitySuccessEventArgs Create(IEntity entity, float duration, object userData) { ShowEntitySuccessEventArgs showEntitySuccessEventArgs = ReferencePool.Acquire(); showEntitySuccessEventArgs.Entity = entity; showEntitySuccessEventArgs.Duration = duration; showEntitySuccessEventArgs.UserData = userData; return showEntitySuccessEventArgs; } /// /// 清理显示实体成功事件。 /// public override void Clear() { Entity = null; Duration = 0f; UserData = null; } } } ================================================ FILE: GameFramework/Entity/ShowEntityUpdateEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Entity { /// /// 显示实体更新事件。 /// public sealed class ShowEntityUpdateEventArgs : GameFrameworkEventArgs { /// /// 初始化显示实体更新事件的新实例。 /// public ShowEntityUpdateEventArgs() { EntityId = 0; EntityAssetName = null; EntityGroupName = null; Progress = 0f; UserData = null; } /// /// 获取实体编号。 /// public int EntityId { get; private set; } /// /// 获取实体资源名称。 /// public string EntityAssetName { get; private set; } /// /// 获取实体组名称。 /// public string EntityGroupName { get; private set; } /// /// 获取显示实体进度。 /// public float Progress { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建显示实体更新事件。 /// /// 实体编号。 /// 实体资源名称。 /// 实体组名称。 /// 显示实体进度。 /// 用户自定义数据。 /// 创建的显示实体更新事件。 public static ShowEntityUpdateEventArgs Create(int entityId, string entityAssetName, string entityGroupName, float progress, object userData) { ShowEntityUpdateEventArgs showEntityUpdateEventArgs = ReferencePool.Acquire(); showEntityUpdateEventArgs.EntityId = entityId; showEntityUpdateEventArgs.EntityAssetName = entityAssetName; showEntityUpdateEventArgs.EntityGroupName = entityGroupName; showEntityUpdateEventArgs.Progress = progress; showEntityUpdateEventArgs.UserData = userData; return showEntityUpdateEventArgs; } /// /// 清理显示实体更新事件。 /// public override void Clear() { EntityId = 0; EntityAssetName = null; EntityGroupName = null; Progress = 0f; UserData = null; } } } ================================================ FILE: GameFramework/Event/EventManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.Event { /// /// 事件管理器。 /// internal sealed class EventManager : GameFrameworkModule, IEventManager { private readonly EventPool m_EventPool; /// /// 初始化事件管理器的新实例。 /// public EventManager() { m_EventPool = new EventPool(EventPoolMode.AllowNoHandler | EventPoolMode.AllowMultiHandler); } /// /// 获取事件处理函数的数量。 /// public int EventHandlerCount { get { return m_EventPool.EventHandlerCount; } } /// /// 获取事件数量。 /// public int EventCount { get { return m_EventPool.EventCount; } } /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal override int Priority { get { return 7; } } /// /// 事件管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { m_EventPool.Update(elapseSeconds, realElapseSeconds); } /// /// 关闭并清理事件管理器。 /// internal override void Shutdown() { m_EventPool.Shutdown(); } /// /// 获取事件处理函数的数量。 /// /// 事件类型编号。 /// 事件处理函数的数量。 public int Count(int id) { return m_EventPool.Count(id); } /// /// 检查是否存在事件处理函数。 /// /// 事件类型编号。 /// 要检查的事件处理函数。 /// 是否存在事件处理函数。 public bool Check(int id, EventHandler handler) { return m_EventPool.Check(id, handler); } /// /// 订阅事件处理函数。 /// /// 事件类型编号。 /// 要订阅的事件处理函数。 public void Subscribe(int id, EventHandler handler) { m_EventPool.Subscribe(id, handler); } /// /// 取消订阅事件处理函数。 /// /// 事件类型编号。 /// 要取消订阅的事件处理函数。 public void Unsubscribe(int id, EventHandler handler) { m_EventPool.Unsubscribe(id, handler); } /// /// 设置默认事件处理函数。 /// /// 要设置的默认事件处理函数。 public void SetDefaultHandler(EventHandler handler) { m_EventPool.SetDefaultHandler(handler); } /// /// 抛出事件,这个操作是线程安全的,即使不在主线程中抛出,也可保证在主线程中回调事件处理函数,但事件会在抛出后的下一帧分发。 /// /// 事件源。 /// 事件参数。 public void Fire(object sender, GameEventArgs e) { m_EventPool.Fire(sender, e); } /// /// 抛出事件立即模式,这个操作不是线程安全的,事件会立刻分发。 /// /// 事件源。 /// 事件参数。 public void FireNow(object sender, GameEventArgs e) { m_EventPool.FireNow(sender, e); } } } ================================================ FILE: GameFramework/Event/GameEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Event { /// /// 游戏逻辑事件基类。 /// public abstract class GameEventArgs : BaseEventArgs { } } ================================================ FILE: GameFramework/Event/IEventManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.Event { /// /// 事件管理器接口。 /// public interface IEventManager { /// /// 获取事件处理函数的数量。 /// int EventHandlerCount { get; } /// /// 获取事件数量。 /// int EventCount { get; } /// /// 获取事件处理函数的数量。 /// /// 事件类型编号。 /// 事件处理函数的数量。 int Count(int id); /// /// 检查是否存在事件处理函数。 /// /// 事件类型编号。 /// 要检查的事件处理函数。 /// 是否存在事件处理函数。 bool Check(int id, EventHandler handler); /// /// 订阅事件处理函数。 /// /// 事件类型编号。 /// 要订阅的事件处理函数。 void Subscribe(int id, EventHandler handler); /// /// 取消订阅事件处理函数。 /// /// 事件类型编号。 /// 要取消订阅的事件处理函数。 void Unsubscribe(int id, EventHandler handler); /// /// 设置默认事件处理函数。 /// /// 要设置的默认事件处理函数。 void SetDefaultHandler(EventHandler handler); /// /// 抛出事件,这个操作是线程安全的,即使不在主线程中抛出,也可保证在主线程中回调事件处理函数,但事件会在抛出后的下一帧分发。 /// /// 事件源。 /// 事件参数。 void Fire(object sender, GameEventArgs e); /// /// 抛出事件立即模式,这个操作不是线程安全的,事件会立刻分发。 /// /// 事件源。 /// 事件参数。 void FireNow(object sender, GameEventArgs e); } } ================================================ FILE: GameFramework/FileSystem/CommonFileSystemStream.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.IO; namespace GameFramework.FileSystem { /// /// 通用文件系统流。 /// public sealed class CommonFileSystemStream : FileSystemStream, IDisposable { private readonly FileStream m_FileStream; /// /// 初始化通用文件系统流的新实例。 /// /// 要加载的文件系统的完整路径。 /// 要加载的文件系统的访问方式。 /// 是否创建新的文件系统流。 public CommonFileSystemStream(string fullPath, FileSystemAccess access, bool createNew) { if (string.IsNullOrEmpty(fullPath)) { throw new GameFrameworkException("Full path is invalid."); } switch (access) { case FileSystemAccess.Read: m_FileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read); break; case FileSystemAccess.Write: m_FileStream = new FileStream(fullPath, createNew ? FileMode.Create : FileMode.Open, FileAccess.Write, FileShare.Read); break; case FileSystemAccess.ReadWrite: m_FileStream = new FileStream(fullPath, createNew ? FileMode.Create : FileMode.Open, FileAccess.ReadWrite, FileShare.Read); break; default: throw new GameFrameworkException("Access is invalid."); } } /// /// 获取或设置文件系统流位置。 /// protected internal override long Position { get { return m_FileStream.Position; } set { m_FileStream.Position = value; } } /// /// 获取文件系统流长度。 /// protected internal override long Length { get { return m_FileStream.Length; } } /// /// 设置文件系统流长度。 /// /// 要设置的文件系统流的长度。 protected internal override void SetLength(long length) { m_FileStream.SetLength(length); } /// /// 定位文件系统流位置。 /// /// 要定位的文件系统流位置的偏移。 /// 要定位的文件系统流位置的方式。 protected internal override void Seek(long offset, SeekOrigin origin) { m_FileStream.Seek(offset, origin); } /// /// 从文件系统流中读取一个字节。 /// /// 读取的字节,若已经到达文件结尾,则返回 -1。 protected internal override int ReadByte() { return m_FileStream.ReadByte(); } /// /// 从文件系统流中读取二进制流。 /// /// 存储读取文件内容的二进制流。 /// 存储读取文件内容的二进制流的起始位置。 /// 存储读取文件内容的二进制流的长度。 /// 实际读取了多少字节。 protected internal override int Read(byte[] buffer, int startIndex, int length) { return m_FileStream.Read(buffer, startIndex, length); } /// /// 向文件系统流中写入一个字节。 /// /// 要写入的字节。 protected internal override void WriteByte(byte value) { m_FileStream.WriteByte(value); } /// /// 向文件系统流中写入二进制流。 /// /// 存储写入文件内容的二进制流。 /// 存储写入文件内容的二进制流的起始位置。 /// 存储写入文件内容的二进制流的长度。 protected internal override void Write(byte[] buffer, int startIndex, int length) { m_FileStream.Write(buffer, startIndex, length); } /// /// 将文件系统流立刻更新到存储介质中。 /// protected internal override void Flush() { m_FileStream.Flush(); } /// /// 关闭文件系统流。 /// protected internal override void Close() { m_FileStream.Close(); } /// /// 销毁文件系统流。 /// public void Dispose() { m_FileStream.Dispose(); } } } ================================================ FILE: GameFramework/FileSystem/FileInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.FileSystem { /// /// 文件信息。 /// [StructLayout(LayoutKind.Auto)] public struct FileInfo { private readonly string m_Name; private readonly long m_Offset; private readonly int m_Length; /// /// 初始化文件信息的新实例。 /// /// 文件名称。 /// 文件偏移。 /// 文件长度。 public FileInfo(string name, long offset, int length) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } if (offset < 0L) { throw new GameFrameworkException("Offset is invalid."); } if (length < 0) { throw new GameFrameworkException("Length is invalid."); } m_Name = name; m_Offset = offset; m_Length = length; } /// /// 获取文件信息是否有效。 /// public bool IsValid { get { return !string.IsNullOrEmpty(m_Name) && m_Offset >= 0L && m_Length >= 0; } } /// /// 获取文件名称。 /// public string Name { get { return m_Name; } } /// /// 获取文件偏移。 /// public long Offset { get { return m_Offset; } } /// /// 获取文件长度。 /// public int Length { get { return m_Length; } } } } ================================================ FILE: GameFramework/FileSystem/FileSystem.BlockData.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.FileSystem { internal sealed partial class FileSystem : IFileSystem { /// /// 块数据。 /// [StructLayout(LayoutKind.Sequential)] private struct BlockData { public static readonly BlockData Empty = new BlockData(0, 0); private readonly int m_StringIndex; private readonly int m_ClusterIndex; private readonly int m_Length; public BlockData(int clusterIndex, int length) : this(-1, clusterIndex, length) { } public BlockData(int stringIndex, int clusterIndex, int length) { m_StringIndex = stringIndex; m_ClusterIndex = clusterIndex; m_Length = length; } public bool Using { get { return m_StringIndex >= 0; } } public int StringIndex { get { return m_StringIndex; } } public int ClusterIndex { get { return m_ClusterIndex; } } public int Length { get { return m_Length; } } public BlockData Free() { return new BlockData(m_ClusterIndex, (int)GetUpBoundClusterOffset(m_Length)); } } } } ================================================ FILE: GameFramework/FileSystem/FileSystem.HeaderData.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.FileSystem { internal sealed partial class FileSystem : IFileSystem { /// /// 头数据。 /// [StructLayout(LayoutKind.Sequential)] private struct HeaderData { private const int HeaderLength = 3; private const int FileSystemVersion = 0; private const int EncryptBytesLength = 4; private static readonly byte[] Header = new byte[HeaderLength] { (byte)'G', (byte)'F', (byte)'F' }; [MarshalAs(UnmanagedType.ByValArray, SizeConst = HeaderLength)] private readonly byte[] m_Header; private readonly byte m_Version; [MarshalAs(UnmanagedType.ByValArray, SizeConst = EncryptBytesLength)] private readonly byte[] m_EncryptBytes; private readonly int m_MaxFileCount; private readonly int m_MaxBlockCount; private readonly int m_BlockCount; public HeaderData(int maxFileCount, int maxBlockCount) : this(FileSystemVersion, new byte[EncryptBytesLength], maxFileCount, maxBlockCount, 0) { Utility.Random.GetRandomBytes(m_EncryptBytes); } public HeaderData(byte version, byte[] encryptBytes, int maxFileCount, int maxBlockCount, int blockCount) { m_Header = Header; m_Version = version; m_EncryptBytes = encryptBytes; m_MaxFileCount = maxFileCount; m_MaxBlockCount = maxBlockCount; m_BlockCount = blockCount; } public bool IsValid { get { return m_Header.Length == HeaderLength && m_Header[0] == Header[0] && m_Header[1] == Header[1] && m_Header[2] == Header[2] && m_Version == FileSystemVersion && m_EncryptBytes.Length == EncryptBytesLength && m_MaxFileCount > 0 && m_MaxBlockCount > 0 && m_MaxFileCount <= m_MaxBlockCount && m_BlockCount > 0 && m_BlockCount <= m_MaxBlockCount; } } public byte Version { get { return m_Version; } } public int MaxFileCount { get { return m_MaxFileCount; } } public int MaxBlockCount { get { return m_MaxBlockCount; } } public int BlockCount { get { return m_BlockCount; } } public byte[] GetEncryptBytes() { return m_EncryptBytes; } public HeaderData SetBlockCount(int blockCount) { return new HeaderData(m_Version, m_EncryptBytes, m_MaxFileCount, m_MaxBlockCount, blockCount); } } } } ================================================ FILE: GameFramework/FileSystem/FileSystem.StringData.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Runtime.InteropServices; namespace GameFramework.FileSystem { internal sealed partial class FileSystem : IFileSystem { /// /// 字符串数据。 /// [StructLayout(LayoutKind.Sequential)] private struct StringData { private static readonly byte[] s_CachedBytes = new byte[byte.MaxValue + 1]; private readonly byte m_Length; [MarshalAs(UnmanagedType.ByValArray, SizeConst = byte.MaxValue)] private readonly byte[] m_Bytes; public StringData(byte length, byte[] bytes) { m_Length = length; m_Bytes = bytes; } public string GetString(byte[] encryptBytes) { if (m_Length <= 0) { return null; } Array.Copy(m_Bytes, 0, s_CachedBytes, 0, m_Length); Utility.Encryption.GetSelfXorBytes(s_CachedBytes, 0, m_Length, encryptBytes); return Utility.Converter.GetString(s_CachedBytes, 0, m_Length); } public StringData SetString(string value, byte[] encryptBytes) { if (string.IsNullOrEmpty(value)) { return Clear(); } int length = Utility.Converter.GetBytes(value, s_CachedBytes); if (length > byte.MaxValue) { throw new GameFrameworkException(Utility.Text.Format("String '{0}' is too long.", value)); } Utility.Encryption.GetSelfXorBytes(s_CachedBytes, encryptBytes); Array.Copy(s_CachedBytes, 0, m_Bytes, 0, length); return new StringData((byte)length, m_Bytes); } public StringData Clear() { return new StringData(0, m_Bytes); } } } } ================================================ FILE: GameFramework/FileSystem/FileSystem.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; namespace GameFramework.FileSystem { /// /// 文件系统。 /// internal sealed partial class FileSystem : IFileSystem { private const int ClusterSize = 1024 * 4; private const int CachedBytesLength = 0x1000; private static readonly string[] EmptyStringArray = new string[] { }; private static readonly byte[] s_CachedBytes = new byte[CachedBytesLength]; private static readonly int HeaderDataSize = Marshal.SizeOf(typeof(HeaderData)); private static readonly int BlockDataSize = Marshal.SizeOf(typeof(BlockData)); private static readonly int StringDataSize = Marshal.SizeOf(typeof(StringData)); private readonly string m_FullPath; private readonly FileSystemAccess m_Access; private readonly FileSystemStream m_Stream; private readonly Dictionary m_FileDatas; private readonly List m_BlockDatas; private readonly GameFrameworkMultiDictionary m_FreeBlockIndexes; private readonly SortedDictionary m_StringDatas; private readonly Queue m_FreeStringIndexes; private readonly Queue m_FreeStringDatas; private HeaderData m_HeaderData; private int m_BlockDataOffset; private int m_StringDataOffset; private int m_FileDataOffset; /// /// 初始化文件系统的新实例。 /// /// 文件系统完整路径。 /// 文件系统访问方式。 /// 文件系统流。 private FileSystem(string fullPath, FileSystemAccess access, FileSystemStream stream) { if (string.IsNullOrEmpty(fullPath)) { throw new GameFrameworkException("Full path is invalid."); } if (access == FileSystemAccess.Unspecified) { throw new GameFrameworkException("Access is invalid."); } if (stream == null) { throw new GameFrameworkException("Stream is invalid."); } m_FullPath = fullPath; m_Access = access; m_Stream = stream; m_FileDatas = new Dictionary(StringComparer.Ordinal); m_BlockDatas = new List(); m_FreeBlockIndexes = new GameFrameworkMultiDictionary(); m_StringDatas = new SortedDictionary(); m_FreeStringIndexes = new Queue(); m_FreeStringDatas = new Queue(); m_HeaderData = default(HeaderData); m_BlockDataOffset = 0; m_StringDataOffset = 0; m_FileDataOffset = 0; Utility.Marshal.EnsureCachedHGlobalSize(CachedBytesLength); } /// /// 获取文件系统完整路径。 /// public string FullPath { get { return m_FullPath; } } /// /// 获取文件系统访问方式。 /// public FileSystemAccess Access { get { return m_Access; } } /// /// 获取文件数量。 /// public int FileCount { get { return m_FileDatas.Count; } } /// /// 获取最大文件数量。 /// public int MaxFileCount { get { return m_HeaderData.MaxFileCount; } } /// /// 创建文件系统。 /// /// 要创建的文件系统的完整路径。 /// 要创建的文件系统的访问方式。 /// 要创建的文件系统的文件系统流。 /// 要创建的文件系统的最大文件数量。 /// 要创建的文件系统的最大块数据数量。 /// 创建的文件系统。 public static FileSystem Create(string fullPath, FileSystemAccess access, FileSystemStream stream, int maxFileCount, int maxBlockCount) { if (maxFileCount <= 0) { throw new GameFrameworkException("Max file count is invalid."); } if (maxBlockCount <= 0) { throw new GameFrameworkException("Max block count is invalid."); } if (maxFileCount > maxBlockCount) { throw new GameFrameworkException("Max file count can not larger than max block count."); } FileSystem fileSystem = new FileSystem(fullPath, access, stream); fileSystem.m_HeaderData = new HeaderData(maxFileCount, maxBlockCount); CalcOffsets(fileSystem); Utility.Marshal.StructureToBytes(fileSystem.m_HeaderData, HeaderDataSize, s_CachedBytes); try { stream.Write(s_CachedBytes, 0, HeaderDataSize); stream.SetLength(fileSystem.m_FileDataOffset); return fileSystem; } catch { fileSystem.Shutdown(); return null; } } /// /// 加载文件系统。 /// /// 要加载的文件系统的完整路径。 /// 要加载的文件系统的访问方式。 /// 要加载的文件系统的文件系统流。 /// 加载的文件系统。 public static FileSystem Load(string fullPath, FileSystemAccess access, FileSystemStream stream) { FileSystem fileSystem = new FileSystem(fullPath, access, stream); stream.Read(s_CachedBytes, 0, HeaderDataSize); fileSystem.m_HeaderData = Utility.Marshal.BytesToStructure(HeaderDataSize, s_CachedBytes); if (!fileSystem.m_HeaderData.IsValid) { return null; } CalcOffsets(fileSystem); if (fileSystem.m_BlockDatas.Capacity < fileSystem.m_HeaderData.BlockCount) { fileSystem.m_BlockDatas.Capacity = fileSystem.m_HeaderData.BlockCount; } for (int i = 0; i < fileSystem.m_HeaderData.BlockCount; i++) { stream.Read(s_CachedBytes, 0, BlockDataSize); BlockData blockData = Utility.Marshal.BytesToStructure(BlockDataSize, s_CachedBytes); fileSystem.m_BlockDatas.Add(blockData); } for (int i = 0; i < fileSystem.m_BlockDatas.Count; i++) { BlockData blockData = fileSystem.m_BlockDatas[i]; if (blockData.Using) { StringData stringData = fileSystem.ReadStringData(blockData.StringIndex); fileSystem.m_StringDatas.Add(blockData.StringIndex, stringData); fileSystem.m_FileDatas.Add(stringData.GetString(fileSystem.m_HeaderData.GetEncryptBytes()), i); } else { fileSystem.m_FreeBlockIndexes.Add(blockData.Length, i); } } int index = 0; foreach (KeyValuePair i in fileSystem.m_StringDatas) { while (index < i.Key) { fileSystem.m_FreeStringIndexes.Enqueue(index++); } index++; } return fileSystem; } /// /// 关闭并清理文件系统。 /// public void Shutdown() { m_Stream.Close(); m_FileDatas.Clear(); m_BlockDatas.Clear(); m_FreeBlockIndexes.Clear(); m_StringDatas.Clear(); m_FreeStringIndexes.Clear(); m_FreeStringDatas.Clear(); m_BlockDataOffset = 0; m_StringDataOffset = 0; m_FileDataOffset = 0; } /// /// 获取文件信息。 /// /// 要获取文件信息的文件名称。 /// 获取的文件信息。 public FileInfo GetFileInfo(string name) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } int blockIndex = 0; if (!m_FileDatas.TryGetValue(name, out blockIndex)) { return default(FileInfo); } BlockData blockData = m_BlockDatas[blockIndex]; return new FileInfo(name, GetClusterOffset(blockData.ClusterIndex), blockData.Length); } /// /// 获取所有文件信息。 /// /// 获取的所有文件信息。 public FileInfo[] GetAllFileInfos() { int index = 0; FileInfo[] results = new FileInfo[m_FileDatas.Count]; foreach (KeyValuePair fileData in m_FileDatas) { BlockData blockData = m_BlockDatas[fileData.Value]; results[index++] = new FileInfo(fileData.Key, GetClusterOffset(blockData.ClusterIndex), blockData.Length); } return results; } /// /// 获取所有文件信息。 /// /// 获取的所有文件信息。 public void GetAllFileInfos(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair fileData in m_FileDatas) { BlockData blockData = m_BlockDatas[fileData.Value]; results.Add(new FileInfo(fileData.Key, GetClusterOffset(blockData.ClusterIndex), blockData.Length)); } } /// /// 检查是否存在指定文件。 /// /// 要检查的文件名称。 /// 是否存在指定文件。 public bool HasFile(string name) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } return m_FileDatas.ContainsKey(name); } /// /// 读取指定文件。 /// /// 要读取的文件名称。 /// 存储读取文件内容的二进制流。 public byte[] ReadFile(string name) { if (m_Access != FileSystemAccess.Read && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not readable."); } if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } FileInfo fileInfo = GetFileInfo(name); if (!fileInfo.IsValid) { return null; } int length = fileInfo.Length; byte[] buffer = new byte[length]; if (length > 0) { m_Stream.Position = fileInfo.Offset; m_Stream.Read(buffer, 0, length); } return buffer; } /// /// 读取指定文件。 /// /// 要读取的文件名称。 /// 存储读取文件内容的二进制流。 /// 实际读取了多少字节。 public int ReadFile(string name, byte[] buffer) { if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return ReadFile(name, buffer, 0, buffer.Length); } /// /// 读取指定文件。 /// /// 要读取的文件名称。 /// 存储读取文件内容的二进制流。 /// 存储读取文件内容的二进制流的起始位置。 /// 实际读取了多少字节。 public int ReadFile(string name, byte[] buffer, int startIndex) { if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return ReadFile(name, buffer, startIndex, buffer.Length - startIndex); } /// /// 读取指定文件。 /// /// 要读取的文件名称。 /// 存储读取文件内容的二进制流。 /// 存储读取文件内容的二进制流的起始位置。 /// 存储读取文件内容的二进制流的长度。 /// 实际读取了多少字节。 public int ReadFile(string name, byte[] buffer, int startIndex, int length) { if (m_Access != FileSystemAccess.Read && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not readable."); } if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } if (startIndex < 0 || length < 0 || startIndex + length > buffer.Length) { throw new GameFrameworkException("Start index or length is invalid."); } FileInfo fileInfo = GetFileInfo(name); if (!fileInfo.IsValid) { return 0; } m_Stream.Position = fileInfo.Offset; if (length > fileInfo.Length) { length = fileInfo.Length; } if (length > 0) { return m_Stream.Read(buffer, startIndex, length); } return 0; } /// /// 读取指定文件。 /// /// 要读取的文件名称。 /// 存储读取文件内容的二进制流。 /// 实际读取了多少字节。 public int ReadFile(string name, Stream stream) { if (m_Access != FileSystemAccess.Read && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not readable."); } if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } if (stream == null) { throw new GameFrameworkException("Stream is invalid."); } if (!stream.CanWrite) { throw new GameFrameworkException("Stream is not writable."); } FileInfo fileInfo = GetFileInfo(name); if (!fileInfo.IsValid) { return 0; } int length = fileInfo.Length; if (length > 0) { m_Stream.Position = fileInfo.Offset; return m_Stream.Read(stream, length); } return 0; } /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的长度。 /// 存储读取文件片段内容的二进制流。 public byte[] ReadFileSegment(string name, int length) { return ReadFileSegment(name, 0, length); } /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的偏移。 /// 要读取片段的长度。 /// 存储读取文件片段内容的二进制流。 public byte[] ReadFileSegment(string name, int offset, int length) { if (m_Access != FileSystemAccess.Read && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not readable."); } if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } if (offset < 0) { throw new GameFrameworkException("Index is invalid."); } if (length < 0) { throw new GameFrameworkException("Length is invalid."); } FileInfo fileInfo = GetFileInfo(name); if (!fileInfo.IsValid) { return null; } if (offset > fileInfo.Length) { offset = fileInfo.Length; } int leftLength = fileInfo.Length - offset; if (length > leftLength) { length = leftLength; } byte[] buffer = new byte[length]; if (length > 0) { m_Stream.Position = fileInfo.Offset + offset; m_Stream.Read(buffer, 0, length); } return buffer; } /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 存储读取文件片段内容的二进制流。 /// 实际读取了多少字节。 public int ReadFileSegment(string name, byte[] buffer) { if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return ReadFileSegment(name, 0, buffer, 0, buffer.Length); } /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 存储读取文件片段内容的二进制流。 /// 要读取片段的长度。 /// 实际读取了多少字节。 public int ReadFileSegment(string name, byte[] buffer, int length) { return ReadFileSegment(name, 0, buffer, 0, length); } /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 存储读取文件片段内容的二进制流。 /// 存储读取文件片段内容的二进制流的起始位置。 /// 要读取片段的长度。 /// 实际读取了多少字节。 public int ReadFileSegment(string name, byte[] buffer, int startIndex, int length) { return ReadFileSegment(name, 0, buffer, startIndex, length); } /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的偏移。 /// 存储读取文件片段内容的二进制流。 /// 实际读取了多少字节。 public int ReadFileSegment(string name, int offset, byte[] buffer) { if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return ReadFileSegment(name, offset, buffer, 0, buffer.Length); } /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的偏移。 /// 存储读取文件片段内容的二进制流。 /// 要读取片段的长度。 /// 实际读取了多少字节。 public int ReadFileSegment(string name, int offset, byte[] buffer, int length) { return ReadFileSegment(name, offset, buffer, 0, length); } /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的偏移。 /// 存储读取文件片段内容的二进制流。 /// 存储读取文件片段内容的二进制流的起始位置。 /// 要读取片段的长度。 /// 实际读取了多少字节。 public int ReadFileSegment(string name, int offset, byte[] buffer, int startIndex, int length) { if (m_Access != FileSystemAccess.Read && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not readable."); } if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } if (offset < 0) { throw new GameFrameworkException("Index is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } if (startIndex < 0 || length < 0 || startIndex + length > buffer.Length) { throw new GameFrameworkException("Start index or length is invalid."); } FileInfo fileInfo = GetFileInfo(name); if (!fileInfo.IsValid) { return 0; } if (offset > fileInfo.Length) { offset = fileInfo.Length; } int leftLength = fileInfo.Length - offset; if (length > leftLength) { length = leftLength; } if (length > 0) { m_Stream.Position = fileInfo.Offset + offset; return m_Stream.Read(buffer, startIndex, length); } return 0; } /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 存储读取文件片段内容的二进制流。 /// 要读取片段的长度。 /// 实际读取了多少字节。 public int ReadFileSegment(string name, Stream stream, int length) { return ReadFileSegment(name, 0, stream, length); } /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的偏移。 /// 存储读取文件片段内容的二进制流。 /// 要读取片段的长度。 /// 实际读取了多少字节。 public int ReadFileSegment(string name, int offset, Stream stream, int length) { if (m_Access != FileSystemAccess.Read && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not readable."); } if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } if (offset < 0) { throw new GameFrameworkException("Index is invalid."); } if (stream == null) { throw new GameFrameworkException("Stream is invalid."); } if (!stream.CanWrite) { throw new GameFrameworkException("Stream is not writable."); } if (length < 0) { throw new GameFrameworkException("Length is invalid."); } FileInfo fileInfo = GetFileInfo(name); if (!fileInfo.IsValid) { return 0; } if (offset > fileInfo.Length) { offset = fileInfo.Length; } int leftLength = fileInfo.Length - offset; if (length > leftLength) { length = leftLength; } if (length > 0) { m_Stream.Position = fileInfo.Offset + offset; return m_Stream.Read(stream, length); } return 0; } /// /// 写入指定文件。 /// /// 要写入的文件名称。 /// 存储写入文件内容的二进制流。 /// 是否写入指定文件成功。 public bool WriteFile(string name, byte[] buffer) { if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return WriteFile(name, buffer, 0, buffer.Length); } /// /// 写入指定文件。 /// /// 要写入的文件名称。 /// 存储写入文件内容的二进制流。 /// 存储写入文件内容的二进制流的起始位置。 /// 是否写入指定文件成功。 public bool WriteFile(string name, byte[] buffer, int startIndex) { if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return WriteFile(name, buffer, startIndex, buffer.Length - startIndex); } /// /// 写入指定文件。 /// /// 要写入的文件名称。 /// 存储写入文件内容的二进制流。 /// 存储写入文件内容的二进制流的起始位置。 /// 存储写入文件内容的二进制流的长度。 /// 是否写入指定文件成功。 public bool WriteFile(string name, byte[] buffer, int startIndex, int length) { if (m_Access != FileSystemAccess.Write && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not writable."); } if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } if (name.Length > byte.MaxValue) { throw new GameFrameworkException(Utility.Text.Format("Name '{0}' is too long.", name)); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } if (startIndex < 0 || length < 0 || startIndex + length > buffer.Length) { throw new GameFrameworkException("Start index or length is invalid."); } bool hasFile = false; int oldBlockIndex = -1; if (m_FileDatas.TryGetValue(name, out oldBlockIndex)) { hasFile = true; } if (!hasFile && m_FileDatas.Count >= m_HeaderData.MaxFileCount) { return false; } int blockIndex = AllocBlock(length); if (blockIndex < 0) { return false; } if (length > 0) { m_Stream.Position = GetClusterOffset(m_BlockDatas[blockIndex].ClusterIndex); m_Stream.Write(buffer, startIndex, length); } ProcessWriteFile(name, hasFile, oldBlockIndex, blockIndex, length); m_Stream.Flush(); return true; } /// /// 写入指定文件。 /// /// 要写入的文件名称。 /// 存储写入文件内容的二进制流。 /// 是否写入指定文件成功。 public bool WriteFile(string name, Stream stream) { if (m_Access != FileSystemAccess.Write && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not writable."); } if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } if (name.Length > byte.MaxValue) { throw new GameFrameworkException(Utility.Text.Format("Name '{0}' is too long.", name)); } if (stream == null) { throw new GameFrameworkException("Stream is invalid."); } if (!stream.CanRead) { throw new GameFrameworkException("Stream is not readable."); } bool hasFile = false; int oldBlockIndex = -1; if (m_FileDatas.TryGetValue(name, out oldBlockIndex)) { hasFile = true; } if (!hasFile && m_FileDatas.Count >= m_HeaderData.MaxFileCount) { return false; } int length = (int)(stream.Length - stream.Position); int blockIndex = AllocBlock(length); if (blockIndex < 0) { return false; } if (length > 0) { m_Stream.Position = GetClusterOffset(m_BlockDatas[blockIndex].ClusterIndex); m_Stream.Write(stream, length); } ProcessWriteFile(name, hasFile, oldBlockIndex, blockIndex, length); m_Stream.Flush(); return true; } /// /// 写入指定文件。 /// /// 要写入的文件名称。 /// 存储写入文件内容的文件路径。 /// 是否写入指定文件成功。 public bool WriteFile(string name, string filePath) { if (string.IsNullOrEmpty(filePath)) { throw new GameFrameworkException("File path is invalid"); } if (!File.Exists(filePath)) { return false; } using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { return WriteFile(name, fileStream); } } /// /// 将指定文件另存为物理文件。 /// /// 要另存为的文件名称。 /// 存储写入文件内容的文件路径。 /// 是否将指定文件另存为物理文件成功。 public bool SaveAsFile(string name, string filePath) { if (m_Access != FileSystemAccess.Read && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not readable."); } if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } if (string.IsNullOrEmpty(filePath)) { throw new GameFrameworkException("File path is invalid"); } FileInfo fileInfo = GetFileInfo(name); if (!fileInfo.IsValid) { return false; } if (File.Exists(filePath)) { File.Delete(filePath); } string directory = Path.GetDirectoryName(filePath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)) { int length = fileInfo.Length; if (length > 0) { m_Stream.Position = fileInfo.Offset; return m_Stream.Read(fileStream, length) == length; } return true; } } /// /// 重命名指定文件。 /// /// 要重命名的文件名称。 /// 重命名后的文件名称。 /// 是否重命名指定文件成功。 public bool RenameFile(string oldName, string newName) { if (m_Access != FileSystemAccess.Write && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not writable."); } if (string.IsNullOrEmpty(oldName)) { throw new GameFrameworkException("Old name is invalid."); } if (string.IsNullOrEmpty(newName)) { throw new GameFrameworkException("New name is invalid."); } if (newName.Length > byte.MaxValue) { throw new GameFrameworkException(Utility.Text.Format("New name '{0}' is too long.", newName)); } if (oldName == newName) { return true; } if (m_FileDatas.ContainsKey(newName)) { return false; } int blockIndex = 0; if (!m_FileDatas.TryGetValue(oldName, out blockIndex)) { return false; } int stringIndex = m_BlockDatas[blockIndex].StringIndex; StringData stringData = m_StringDatas[stringIndex].SetString(newName, m_HeaderData.GetEncryptBytes()); m_StringDatas[stringIndex] = stringData; WriteStringData(stringIndex, stringData); m_FileDatas.Add(newName, blockIndex); m_FileDatas.Remove(oldName); m_Stream.Flush(); return true; } /// /// 删除指定文件。 /// /// 要删除的文件名称。 /// 是否删除指定文件成功。 public bool DeleteFile(string name) { if (m_Access != FileSystemAccess.Write && m_Access != FileSystemAccess.ReadWrite) { throw new GameFrameworkException("File system is not writable."); } if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } int blockIndex = 0; if (!m_FileDatas.TryGetValue(name, out blockIndex)) { return false; } m_FileDatas.Remove(name); BlockData blockData = m_BlockDatas[blockIndex]; int stringIndex = blockData.StringIndex; StringData stringData = m_StringDatas[stringIndex].Clear(); m_FreeStringIndexes.Enqueue(stringIndex); m_FreeStringDatas.Enqueue(stringData); m_StringDatas.Remove(stringIndex); WriteStringData(stringIndex, stringData); blockData = blockData.Free(); m_BlockDatas[blockIndex] = blockData; if (!TryCombineFreeBlocks(blockIndex)) { m_FreeBlockIndexes.Add(blockData.Length, blockIndex); WriteBlockData(blockIndex); } m_Stream.Flush(); return true; } private void ProcessWriteFile(string name, bool hasFile, int oldBlockIndex, int blockIndex, int length) { BlockData blockData = m_BlockDatas[blockIndex]; if (hasFile) { BlockData oldBlockData = m_BlockDatas[oldBlockIndex]; blockData = new BlockData(oldBlockData.StringIndex, blockData.ClusterIndex, length); m_BlockDatas[blockIndex] = blockData; WriteBlockData(blockIndex); oldBlockData = oldBlockData.Free(); m_BlockDatas[oldBlockIndex] = oldBlockData; if (!TryCombineFreeBlocks(oldBlockIndex)) { m_FreeBlockIndexes.Add(oldBlockData.Length, oldBlockIndex); WriteBlockData(oldBlockIndex); } } else { int stringIndex = AllocString(name); blockData = new BlockData(stringIndex, blockData.ClusterIndex, length); m_BlockDatas[blockIndex] = blockData; WriteBlockData(blockIndex); } if (hasFile) { m_FileDatas[name] = blockIndex; } else { m_FileDatas.Add(name, blockIndex); } } private bool TryCombineFreeBlocks(int freeBlockIndex) { BlockData freeBlockData = m_BlockDatas[freeBlockIndex]; if (freeBlockData.Length <= 0) { return false; } int previousFreeBlockIndex = -1; int nextFreeBlockIndex = -1; int nextBlockDataClusterIndex = freeBlockData.ClusterIndex + GetUpBoundClusterCount(freeBlockData.Length); foreach (KeyValuePair> blockIndexes in m_FreeBlockIndexes) { if (blockIndexes.Key <= 0) { continue; } int blockDataClusterCount = GetUpBoundClusterCount(blockIndexes.Key); foreach (int blockIndex in blockIndexes.Value) { BlockData blockData = m_BlockDatas[blockIndex]; if (blockData.ClusterIndex + blockDataClusterCount == freeBlockData.ClusterIndex) { previousFreeBlockIndex = blockIndex; } else if (blockData.ClusterIndex == nextBlockDataClusterIndex) { nextFreeBlockIndex = blockIndex; } } } if (previousFreeBlockIndex < 0 && nextFreeBlockIndex < 0) { return false; } m_FreeBlockIndexes.Remove(freeBlockData.Length, freeBlockIndex); if (previousFreeBlockIndex >= 0) { BlockData previousFreeBlockData = m_BlockDatas[previousFreeBlockIndex]; m_FreeBlockIndexes.Remove(previousFreeBlockData.Length, previousFreeBlockIndex); freeBlockData = new BlockData(previousFreeBlockData.ClusterIndex, previousFreeBlockData.Length + freeBlockData.Length); m_BlockDatas[previousFreeBlockIndex] = BlockData.Empty; m_FreeBlockIndexes.Add(0, previousFreeBlockIndex); WriteBlockData(previousFreeBlockIndex); } if (nextFreeBlockIndex >= 0) { BlockData nextFreeBlockData = m_BlockDatas[nextFreeBlockIndex]; m_FreeBlockIndexes.Remove(nextFreeBlockData.Length, nextFreeBlockIndex); freeBlockData = new BlockData(freeBlockData.ClusterIndex, freeBlockData.Length + nextFreeBlockData.Length); m_BlockDatas[nextFreeBlockIndex] = BlockData.Empty; m_FreeBlockIndexes.Add(0, nextFreeBlockIndex); WriteBlockData(nextFreeBlockIndex); } m_BlockDatas[freeBlockIndex] = freeBlockData; m_FreeBlockIndexes.Add(freeBlockData.Length, freeBlockIndex); WriteBlockData(freeBlockIndex); return true; } private int GetEmptyBlockIndex() { GameFrameworkLinkedListRange lengthRange = default(GameFrameworkLinkedListRange); if (m_FreeBlockIndexes.TryGetValue(0, out lengthRange)) { int blockIndex = lengthRange.First.Value; m_FreeBlockIndexes.Remove(0, blockIndex); return blockIndex; } if (m_BlockDatas.Count < m_HeaderData.MaxBlockCount) { int blockIndex = m_BlockDatas.Count; m_BlockDatas.Add(BlockData.Empty); WriteHeaderData(); return blockIndex; } return -1; } private int AllocBlock(int length) { if (length <= 0) { return GetEmptyBlockIndex(); } length = (int)GetUpBoundClusterOffset(length); int lengthFound = -1; GameFrameworkLinkedListRange lengthRange = default(GameFrameworkLinkedListRange); foreach (KeyValuePair> i in m_FreeBlockIndexes) { if (i.Key < length) { continue; } if (lengthFound >= 0 && lengthFound < i.Key) { continue; } lengthFound = i.Key; lengthRange = i.Value; } if (lengthFound >= 0) { if (lengthFound > length && m_BlockDatas.Count >= m_HeaderData.MaxBlockCount) { return -1; } int blockIndex = lengthRange.First.Value; m_FreeBlockIndexes.Remove(lengthFound, blockIndex); if (lengthFound > length) { BlockData blockData = m_BlockDatas[blockIndex]; m_BlockDatas[blockIndex] = new BlockData(blockData.ClusterIndex, length); WriteBlockData(blockIndex); int deltaLength = lengthFound - length; int anotherBlockIndex = GetEmptyBlockIndex(); m_BlockDatas[anotherBlockIndex] = new BlockData(blockData.ClusterIndex + GetUpBoundClusterCount(length), deltaLength); m_FreeBlockIndexes.Add(deltaLength, anotherBlockIndex); WriteBlockData(anotherBlockIndex); } return blockIndex; } else { int blockIndex = GetEmptyBlockIndex(); if (blockIndex < 0) { return -1; } long fileLength = m_Stream.Length; try { m_Stream.SetLength(fileLength + length); } catch { return -1; } m_BlockDatas[blockIndex] = new BlockData(GetUpBoundClusterCount(fileLength), length); WriteBlockData(blockIndex); return blockIndex; } } private int AllocString(string value) { int stringIndex = -1; StringData stringData = default(StringData); if (m_FreeStringIndexes.Count > 0) { stringIndex = m_FreeStringIndexes.Dequeue(); } else { stringIndex = m_StringDatas.Count; } if (m_FreeStringDatas.Count > 0) { stringData = m_FreeStringDatas.Dequeue(); } else { byte[] bytes = new byte[byte.MaxValue]; Utility.Random.GetRandomBytes(bytes); stringData = new StringData(0, bytes); } stringData = stringData.SetString(value, m_HeaderData.GetEncryptBytes()); m_StringDatas.Add(stringIndex, stringData); WriteStringData(stringIndex, stringData); return stringIndex; } private void WriteHeaderData() { m_HeaderData = m_HeaderData.SetBlockCount(m_BlockDatas.Count); Utility.Marshal.StructureToBytes(m_HeaderData, HeaderDataSize, s_CachedBytes); m_Stream.Position = 0L; m_Stream.Write(s_CachedBytes, 0, HeaderDataSize); } private void WriteBlockData(int blockIndex) { Utility.Marshal.StructureToBytes(m_BlockDatas[blockIndex], BlockDataSize, s_CachedBytes); m_Stream.Position = m_BlockDataOffset + BlockDataSize * blockIndex; m_Stream.Write(s_CachedBytes, 0, BlockDataSize); } private StringData ReadStringData(int stringIndex) { m_Stream.Position = m_StringDataOffset + StringDataSize * stringIndex; m_Stream.Read(s_CachedBytes, 0, StringDataSize); return Utility.Marshal.BytesToStructure(StringDataSize, s_CachedBytes); } private void WriteStringData(int stringIndex, StringData stringData) { Utility.Marshal.StructureToBytes(stringData, StringDataSize, s_CachedBytes); m_Stream.Position = m_StringDataOffset + StringDataSize * stringIndex; m_Stream.Write(s_CachedBytes, 0, StringDataSize); } private static void CalcOffsets(FileSystem fileSystem) { fileSystem.m_BlockDataOffset = HeaderDataSize; fileSystem.m_StringDataOffset = fileSystem.m_BlockDataOffset + BlockDataSize * fileSystem.m_HeaderData.MaxBlockCount; fileSystem.m_FileDataOffset = (int)GetUpBoundClusterOffset(fileSystem.m_StringDataOffset + StringDataSize * fileSystem.m_HeaderData.MaxFileCount); } private static long GetUpBoundClusterOffset(long offset) { return (offset - 1L + ClusterSize) / ClusterSize * ClusterSize; } private static int GetUpBoundClusterCount(long length) { return (int)((length - 1L + ClusterSize) / ClusterSize); } private static long GetClusterOffset(int clusterIndex) { return (long)ClusterSize * clusterIndex; } } } ================================================ FILE: GameFramework/FileSystem/FileSystemAccess.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.FileSystem { /// /// 文件系统访问方式。 /// [Flags] public enum FileSystemAccess : byte { /// /// 未指定。 /// Unspecified = 0, /// /// 只可读。 /// Read = 1, /// /// 只可写。 /// Write = 2, /// /// 可读写。 /// ReadWrite = 3 } } ================================================ FILE: GameFramework/FileSystem/FileSystemManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; using System.IO; namespace GameFramework.FileSystem { /// /// 文件系统管理器。 /// internal sealed class FileSystemManager : GameFrameworkModule, IFileSystemManager { private readonly Dictionary m_FileSystems; private IFileSystemHelper m_FileSystemHelper; /// /// 初始化文件系统管理器的新实例。 /// public FileSystemManager() { m_FileSystems = new Dictionary(StringComparer.Ordinal); m_FileSystemHelper = null; } /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal override int Priority { get { return 4; } } /// /// 获取文件系统数量。 /// public int Count { get { return m_FileSystems.Count; } } /// /// 文件系统管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { } /// /// 关闭并清理文件系统管理器。 /// internal override void Shutdown() { while (m_FileSystems.Count > 0) { foreach (KeyValuePair fileSystem in m_FileSystems) { DestroyFileSystem(fileSystem.Value, false); break; } } } /// /// 设置文件系统辅助器。 /// /// 文件系统辅助器。 public void SetFileSystemHelper(IFileSystemHelper fileSystemHelper) { if (fileSystemHelper == null) { throw new GameFrameworkException("File system helper is invalid."); } m_FileSystemHelper = fileSystemHelper; } /// /// 检查是否存在文件系统。 /// /// 要检查的文件系统的完整路径。 /// 是否存在文件系统。 public bool HasFileSystem(string fullPath) { if (string.IsNullOrEmpty(fullPath)) { throw new GameFrameworkException("Full path is invalid."); } return m_FileSystems.ContainsKey(Utility.Path.GetRegularPath(fullPath)); } /// /// 获取文件系统。 /// /// 要获取的文件系统的完整路径。 /// 获取的文件系统。 public IFileSystem GetFileSystem(string fullPath) { if (string.IsNullOrEmpty(fullPath)) { throw new GameFrameworkException("Full path is invalid."); } FileSystem fileSystem = null; if (m_FileSystems.TryGetValue(Utility.Path.GetRegularPath(fullPath), out fileSystem)) { return fileSystem; } return null; } /// /// 创建文件系统。 /// /// 要创建的文件系统的完整路径。 /// 要创建的文件系统的访问方式。 /// 要创建的文件系统的最大文件数量。 /// 要创建的文件系统的最大块数据数量。 /// 创建的文件系统。 public IFileSystem CreateFileSystem(string fullPath, FileSystemAccess access, int maxFileCount, int maxBlockCount) { if (m_FileSystemHelper == null) { throw new GameFrameworkException("File system helper is invalid."); } if (string.IsNullOrEmpty(fullPath)) { throw new GameFrameworkException("Full path is invalid."); } if (access == FileSystemAccess.Unspecified) { throw new GameFrameworkException("Access is invalid."); } if (access == FileSystemAccess.Read) { throw new GameFrameworkException("Access read is invalid."); } fullPath = Utility.Path.GetRegularPath(fullPath); if (m_FileSystems.ContainsKey(fullPath)) { throw new GameFrameworkException(Utility.Text.Format("File system '{0}' is already exist.", fullPath)); } FileSystemStream fileSystemStream = m_FileSystemHelper.CreateFileSystemStream(fullPath, access, true); if (fileSystemStream == null) { throw new GameFrameworkException(Utility.Text.Format("Create file system stream for '{0}' failure.", fullPath)); } FileSystem fileSystem = FileSystem.Create(fullPath, access, fileSystemStream, maxFileCount, maxBlockCount); if (fileSystem == null) { throw new GameFrameworkException(Utility.Text.Format("Create file system '{0}' failure.", fullPath)); } m_FileSystems.Add(fullPath, fileSystem); return fileSystem; } /// /// 加载文件系统。 /// /// 要加载的文件系统的完整路径。 /// 要加载的文件系统的访问方式。 /// 加载的文件系统。 public IFileSystem LoadFileSystem(string fullPath, FileSystemAccess access) { if (m_FileSystemHelper == null) { throw new GameFrameworkException("File system helper is invalid."); } if (string.IsNullOrEmpty(fullPath)) { throw new GameFrameworkException("Full path is invalid."); } if (access == FileSystemAccess.Unspecified) { throw new GameFrameworkException("Access is invalid."); } fullPath = Utility.Path.GetRegularPath(fullPath); if (m_FileSystems.ContainsKey(fullPath)) { throw new GameFrameworkException(Utility.Text.Format("File system '{0}' is already exist.", fullPath)); } FileSystemStream fileSystemStream = m_FileSystemHelper.CreateFileSystemStream(fullPath, access, false); if (fileSystemStream == null) { throw new GameFrameworkException(Utility.Text.Format("Create file system stream for '{0}' failure.", fullPath)); } FileSystem fileSystem = FileSystem.Load(fullPath, access, fileSystemStream); if (fileSystem == null) { fileSystemStream.Close(); throw new GameFrameworkException(Utility.Text.Format("Load file system '{0}' failure.", fullPath)); } m_FileSystems.Add(fullPath, fileSystem); return fileSystem; } /// /// 销毁文件系统。 /// /// 要销毁的文件系统。 /// 是否删除文件系统对应的物理文件。 public void DestroyFileSystem(IFileSystem fileSystem, bool deletePhysicalFile) { if (fileSystem == null) { throw new GameFrameworkException("File system is invalid."); } string fullPath = fileSystem.FullPath; ((FileSystem)fileSystem).Shutdown(); m_FileSystems.Remove(fullPath); if (deletePhysicalFile && File.Exists(fullPath)) { File.Delete(fullPath); } } /// /// 获取所有文件系统集合。 /// /// 获取的所有文件系统集合。 public IFileSystem[] GetAllFileSystems() { int index = 0; IFileSystem[] results = new IFileSystem[m_FileSystems.Count]; foreach (KeyValuePair fileSystem in m_FileSystems) { results[index++] = fileSystem.Value; } return results; } /// /// 获取所有文件系统集合。 /// /// 获取的所有文件系统集合。 public void GetAllFileSystems(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair fileSystem in m_FileSystems) { results.Add(fileSystem.Value); } } } } ================================================ FILE: GameFramework/FileSystem/FileSystemStream.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.IO; namespace GameFramework.FileSystem { /// /// 文件系统流。 /// public abstract class FileSystemStream { /// /// 缓存二进制流的长度。 /// protected const int CachedBytesLength = 0x1000; /// /// 缓存二进制流。 /// protected static readonly byte[] s_CachedBytes = new byte[CachedBytesLength]; /// /// 获取或设置文件系统流位置。 /// protected internal abstract long Position { get; set; } /// /// 获取文件系统流长度。 /// protected internal abstract long Length { get; } /// /// 设置文件系统流长度。 /// /// 要设置的文件系统流的长度。 protected internal abstract void SetLength(long length); /// /// 定位文件系统流位置。 /// /// 要定位的文件系统流位置的偏移。 /// 要定位的文件系统流位置的方式。 protected internal abstract void Seek(long offset, SeekOrigin origin); /// /// 从文件系统流中读取一个字节。 /// /// 读取的字节,若已经到达文件结尾,则返回 -1。 protected internal abstract int ReadByte(); /// /// 从文件系统流中读取二进制流。 /// /// 存储读取文件内容的二进制流。 /// 存储读取文件内容的二进制流的起始位置。 /// 存储读取文件内容的二进制流的长度。 /// 实际读取了多少字节。 protected internal abstract int Read(byte[] buffer, int startIndex, int length); /// /// 从文件系统流中读取二进制流。 /// /// 存储读取文件内容的二进制流。 /// 存储读取文件内容的二进制流的长度。 /// 实际读取了多少字节。 protected internal int Read(Stream stream, int length) { int bytesRead = 0; int bytesLeft = length; while ((bytesRead = Read(s_CachedBytes, 0, bytesLeft < CachedBytesLength ? bytesLeft : CachedBytesLength)) > 0) { bytesLeft -= bytesRead; stream.Write(s_CachedBytes, 0, bytesRead); } Array.Clear(s_CachedBytes, 0, CachedBytesLength); return length - bytesLeft; } /// /// 向文件系统流中写入一个字节。 /// /// 要写入的字节。 protected internal abstract void WriteByte(byte value); /// /// 向文件系统流中写入二进制流。 /// /// 存储写入文件内容的二进制流。 /// 存储写入文件内容的二进制流的起始位置。 /// 存储写入文件内容的二进制流的长度。 protected internal abstract void Write(byte[] buffer, int startIndex, int length); /// /// 向文件系统流中写入二进制流。 /// /// 存储写入文件内容的二进制流。 /// 存储写入文件内容的二进制流的长度。 protected internal void Write(Stream stream, int length) { int bytesRead = 0; int bytesLeft = length; while ((bytesRead = stream.Read(s_CachedBytes, 0, bytesLeft < CachedBytesLength ? bytesLeft : CachedBytesLength)) > 0) { bytesLeft -= bytesRead; Write(s_CachedBytes, 0, bytesRead); } Array.Clear(s_CachedBytes, 0, CachedBytesLength); } /// /// 将文件系统流立刻更新到存储介质中。 /// protected internal abstract void Flush(); /// /// 关闭文件系统流。 /// protected internal abstract void Close(); } } ================================================ FILE: GameFramework/FileSystem/IFileSystem.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; using System.IO; namespace GameFramework.FileSystem { /// /// 文件系统接口。 /// public interface IFileSystem { /// /// 获取文件系统完整路径。 /// string FullPath { get; } /// /// 获取文件系统访问方式。 /// FileSystemAccess Access { get; } /// /// 获取文件数量。 /// int FileCount { get; } /// /// 获取最大文件数量。 /// int MaxFileCount { get; } /// /// 获取文件信息。 /// /// 要获取文件信息的文件名称。 /// 获取的文件信息。 FileInfo GetFileInfo(string name); /// /// 获取所有文件信息。 /// /// 获取的所有文件信息。 FileInfo[] GetAllFileInfos(); /// /// 获取所有文件信息。 /// /// 获取的所有文件信息。 void GetAllFileInfos(List results); /// /// 检查是否存在指定文件。 /// /// 要检查的文件名称。 /// 是否存在指定文件。 bool HasFile(string name); /// /// 读取指定文件。 /// /// 要读取的文件名称。 /// 存储读取文件内容的二进制流。 byte[] ReadFile(string name); /// /// 读取指定文件。 /// /// 要读取的文件名称。 /// 存储读取文件内容的二进制流。 /// 实际读取了多少字节。 int ReadFile(string name, byte[] buffer); /// /// 读取指定文件。 /// /// 要读取的文件名称。 /// 存储读取文件内容的二进制流。 /// 存储读取文件内容的二进制流的起始位置。 /// 实际读取了多少字节。 int ReadFile(string name, byte[] buffer, int startIndex); /// /// 读取指定文件。 /// /// 要读取的文件名称。 /// 存储读取文件内容的二进制流。 /// 存储读取文件内容的二进制流的起始位置。 /// 存储读取文件内容的二进制流的长度。 /// 实际读取了多少字节。 int ReadFile(string name, byte[] buffer, int startIndex, int length); /// /// 读取指定文件。 /// /// 要读取的文件名称。 /// 存储读取文件内容的二进制流。 /// 实际读取了多少字节。 int ReadFile(string name, Stream stream); /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的长度。 /// 存储读取文件片段内容的二进制流。 byte[] ReadFileSegment(string name, int length); /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的偏移。 /// 要读取片段的长度。 /// 存储读取文件片段内容的二进制流。 byte[] ReadFileSegment(string name, int offset, int length); /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 存储读取文件片段内容的二进制流。 /// 实际读取了多少字节。 int ReadFileSegment(string name, byte[] buffer); /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 存储读取文件片段内容的二进制流。 /// 要读取片段的长度。 /// 实际读取了多少字节。 int ReadFileSegment(string name, byte[] buffer, int length); /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 存储读取文件片段内容的二进制流。 /// 存储读取文件片段内容的二进制流的起始位置。 /// 要读取片段的长度。 /// 实际读取了多少字节。 int ReadFileSegment(string name, byte[] buffer, int startIndex, int length); /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的偏移。 /// 存储读取文件片段内容的二进制流。 /// 实际读取了多少字节。 int ReadFileSegment(string name, int offset, byte[] buffer); /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的偏移。 /// 存储读取文件片段内容的二进制流。 /// 要读取片段的长度。 /// 实际读取了多少字节。 int ReadFileSegment(string name, int offset, byte[] buffer, int length); /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的偏移。 /// 存储读取文件片段内容的二进制流。 /// 存储读取文件片段内容的二进制流的起始位置。 /// 要读取片段的长度。 /// 实际读取了多少字节。 int ReadFileSegment(string name, int offset, byte[] buffer, int startIndex, int length); /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 存储读取文件片段内容的二进制流。 /// 要读取片段的长度。 /// 实际读取了多少字节。 int ReadFileSegment(string name, Stream stream, int length); /// /// 读取指定文件的指定片段。 /// /// 要读取片段的文件名称。 /// 要读取片段的偏移。 /// 存储读取文件片段内容的二进制流。 /// 要读取片段的长度。 /// 实际读取了多少字节。 int ReadFileSegment(string name, int offset, Stream stream, int length); /// /// 写入指定文件。 /// /// 要写入的文件名称。 /// 存储写入文件内容的二进制流。 /// 是否写入指定文件成功。 bool WriteFile(string name, byte[] buffer); /// /// 写入指定文件。 /// /// 要写入的文件名称。 /// 存储写入文件内容的二进制流。 /// 存储写入文件内容的二进制流的起始位置。 /// 是否写入指定文件成功。 bool WriteFile(string name, byte[] buffer, int startIndex); /// /// 写入指定文件。 /// /// 要写入的文件名称。 /// 存储写入文件内容的二进制流。 /// 存储写入文件内容的二进制流的起始位置。 /// 存储写入文件内容的二进制流的长度。 /// 是否写入指定文件成功。 bool WriteFile(string name, byte[] buffer, int startIndex, int length); /// /// 写入指定文件。 /// /// 要写入的文件名称。 /// 存储写入文件内容的二进制流。 /// 是否写入指定文件成功。 bool WriteFile(string name, Stream stream); /// /// 写入指定文件。 /// /// 要写入的文件名称。 /// 存储写入文件内容的文件路径。 /// 是否写入指定文件成功。 bool WriteFile(string name, string filePath); /// /// 将指定文件另存为物理文件。 /// /// 要另存为的文件名称。 /// 存储写入文件内容的文件路径。 /// 是否将指定文件另存为物理文件成功。 bool SaveAsFile(string name, string filePath); /// /// 重命名指定文件。 /// /// 要重命名的文件名称。 /// 重命名后的文件名称。 /// 是否重命名指定文件成功。 bool RenameFile(string oldName, string newName); /// /// 删除指定文件。 /// /// 要删除的文件名称。 /// 是否删除指定文件成功。 bool DeleteFile(string name); } } ================================================ FILE: GameFramework/FileSystem/IFileSystemHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.FileSystem { /// /// 文件系统辅助器接口。 /// public interface IFileSystemHelper { /// /// 创建文件系统流。 /// /// 要加载的文件系统的完整路径。 /// 要加载的文件系统的访问方式。 /// 是否创建新的文件系统流。 /// 创建的文件系统流。 FileSystemStream CreateFileSystemStream(string fullPath, FileSystemAccess access, bool createNew); } } ================================================ FILE: GameFramework/FileSystem/IFileSystemManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.FileSystem { /// /// 文件系统管理器。 /// public interface IFileSystemManager { /// /// 获取文件系统数量。 /// int Count { get; } /// /// 设置文件系统辅助器。 /// /// 文件系统辅助器。 void SetFileSystemHelper(IFileSystemHelper fileSystemHelper); /// /// 检查是否存在文件系统。 /// /// 要检查的文件系统的完整路径。 /// 是否存在文件系统。 bool HasFileSystem(string fullPath); /// /// 获取文件系统。 /// /// 要获取的文件系统的完整路径。 /// 获取的文件系统。 IFileSystem GetFileSystem(string fullPath); /// /// 创建文件系统。 /// /// 要创建的文件系统的完整路径。 /// 要创建的文件系统的访问方式。 /// 要创建的文件系统的最大文件数量。 /// 要创建的文件系统的最大块数据数量。 /// 创建的文件系统。 IFileSystem CreateFileSystem(string fullPath, FileSystemAccess access, int maxFileCount, int maxBlockCount); /// /// 加载文件系统。 /// /// 要加载的文件系统的完整路径。 /// 要加载的文件系统的访问方式。 /// 加载的文件系统。 IFileSystem LoadFileSystem(string fullPath, FileSystemAccess access); /// /// 销毁文件系统。 /// /// 要销毁的文件系统。 /// 是否删除文件系统对应的物理文件。 void DestroyFileSystem(IFileSystem fileSystem, bool deletePhysicalFile); /// /// 获取所有文件系统集合。 /// /// 获取的所有文件系统集合。 IFileSystem[] GetAllFileSystems(); /// /// 获取所有文件系统集合。 /// /// 获取的所有文件系统集合。 void GetAllFileSystems(List results); } } ================================================ FILE: GameFramework/Fsm/Fsm.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Fsm { /// /// 有限状态机。 /// /// 有限状态机持有者类型。 internal sealed class Fsm : FsmBase, IReference, IFsm where T : class { private T m_Owner; private readonly Dictionary> m_States; private Dictionary m_Datas; private FsmState m_CurrentState; private float m_CurrentStateTime; private bool m_IsDestroyed; /// /// 初始化有限状态机的新实例。 /// public Fsm() { m_Owner = null; m_States = new Dictionary>(); m_Datas = null; m_CurrentState = null; m_CurrentStateTime = 0f; m_IsDestroyed = true; } /// /// 获取有限状态机持有者。 /// public T Owner { get { return m_Owner; } } /// /// 获取有限状态机持有者类型。 /// public override Type OwnerType { get { return typeof(T); } } /// /// 获取有限状态机中状态的数量。 /// public override int FsmStateCount { get { return m_States.Count; } } /// /// 获取有限状态机是否正在运行。 /// public override bool IsRunning { get { return m_CurrentState != null; } } /// /// 获取有限状态机是否被销毁。 /// public override bool IsDestroyed { get { return m_IsDestroyed; } } /// /// 获取当前有限状态机状态。 /// public FsmState CurrentState { get { return m_CurrentState; } } /// /// 获取当前有限状态机状态名称。 /// public override string CurrentStateName { get { return m_CurrentState != null ? m_CurrentState.GetType().FullName : null; } } /// /// 获取当前有限状态机状态持续时间。 /// public override float CurrentStateTime { get { return m_CurrentStateTime; } } /// /// 创建有限状态机。 /// /// 有限状态机名称。 /// 有限状态机持有者。 /// 有限状态机状态集合。 /// 创建的有限状态机。 public static Fsm Create(string name, T owner, params FsmState[] states) { if (owner == null) { throw new GameFrameworkException("FSM owner is invalid."); } if (states == null || states.Length < 1) { throw new GameFrameworkException("FSM states is invalid."); } Fsm fsm = ReferencePool.Acquire>(); fsm.Name = name; fsm.m_Owner = owner; fsm.m_IsDestroyed = false; foreach (FsmState state in states) { if (state == null) { throw new GameFrameworkException("FSM states is invalid."); } Type stateType = state.GetType(); if (fsm.m_States.ContainsKey(stateType)) { throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name), stateType.FullName)); } fsm.m_States.Add(stateType, state); state.OnInit(fsm); } return fsm; } /// /// 创建有限状态机。 /// /// 有限状态机名称。 /// 有限状态机持有者。 /// 有限状态机状态集合。 /// 创建的有限状态机。 public static Fsm Create(string name, T owner, List> states) { if (owner == null) { throw new GameFrameworkException("FSM owner is invalid."); } if (states == null || states.Count < 1) { throw new GameFrameworkException("FSM states is invalid."); } Fsm fsm = ReferencePool.Acquire>(); fsm.Name = name; fsm.m_Owner = owner; fsm.m_IsDestroyed = false; foreach (FsmState state in states) { if (state == null) { throw new GameFrameworkException("FSM states is invalid."); } Type stateType = state.GetType(); if (fsm.m_States.ContainsKey(stateType)) { throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name), stateType.FullName)); } fsm.m_States.Add(stateType, state); state.OnInit(fsm); } return fsm; } /// /// 清理有限状态机。 /// public void Clear() { if (m_CurrentState != null) { m_CurrentState.OnLeave(this, true); } foreach (KeyValuePair> state in m_States) { state.Value.OnDestroy(this); } Name = null; m_Owner = null; m_States.Clear(); if (m_Datas != null) { foreach (KeyValuePair data in m_Datas) { if (data.Value == null) { continue; } ReferencePool.Release(data.Value); } m_Datas.Clear(); } m_CurrentState = null; m_CurrentStateTime = 0f; m_IsDestroyed = true; } /// /// 开始有限状态机。 /// /// 要开始的有限状态机状态类型。 public void Start() where TState : FsmState { if (IsRunning) { throw new GameFrameworkException("FSM is running, can not start again."); } FsmState state = GetState(); if (state == null) { throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not start state '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), typeof(TState).FullName)); } m_CurrentStateTime = 0f; m_CurrentState = state; m_CurrentState.OnEnter(this); } /// /// 开始有限状态机。 /// /// 要开始的有限状态机状态类型。 public void Start(Type stateType) { if (IsRunning) { throw new GameFrameworkException("FSM is running, can not start again."); } if (stateType == null) { throw new GameFrameworkException("State type is invalid."); } if (!typeof(FsmState).IsAssignableFrom(stateType)) { throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName)); } FsmState state = GetState(stateType); if (state == null) { throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not start state '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), stateType.FullName)); } m_CurrentStateTime = 0f; m_CurrentState = state; m_CurrentState.OnEnter(this); } /// /// 是否存在有限状态机状态。 /// /// 要检查的有限状态机状态类型。 /// 是否存在有限状态机状态。 public bool HasState() where TState : FsmState { return m_States.ContainsKey(typeof(TState)); } /// /// 是否存在有限状态机状态。 /// /// 要检查的有限状态机状态类型。 /// 是否存在有限状态机状态。 public bool HasState(Type stateType) { if (stateType == null) { throw new GameFrameworkException("State type is invalid."); } if (!typeof(FsmState).IsAssignableFrom(stateType)) { throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName)); } return m_States.ContainsKey(stateType); } /// /// 获取有限状态机状态。 /// /// 要获取的有限状态机状态类型。 /// 要获取的有限状态机状态。 public TState GetState() where TState : FsmState { FsmState state = null; if (m_States.TryGetValue(typeof(TState), out state)) { return (TState)state; } return null; } /// /// 获取有限状态机状态。 /// /// 要获取的有限状态机状态类型。 /// 要获取的有限状态机状态。 public FsmState GetState(Type stateType) { if (stateType == null) { throw new GameFrameworkException("State type is invalid."); } if (!typeof(FsmState).IsAssignableFrom(stateType)) { throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName)); } FsmState state = null; if (m_States.TryGetValue(stateType, out state)) { return state; } return null; } /// /// 获取有限状态机的所有状态。 /// /// 有限状态机的所有状态。 public FsmState[] GetAllStates() { int index = 0; FsmState[] results = new FsmState[m_States.Count]; foreach (KeyValuePair> state in m_States) { results[index++] = state.Value; } return results; } /// /// 获取有限状态机的所有状态。 /// /// 有限状态机的所有状态。 public void GetAllStates(List> results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair> state in m_States) { results.Add(state.Value); } } /// /// 是否存在有限状态机数据。 /// /// 有限状态机数据名称。 /// 有限状态机数据是否存在。 public bool HasData(string name) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Data name is invalid."); } if (m_Datas == null) { return false; } return m_Datas.ContainsKey(name); } /// /// 获取有限状态机数据。 /// /// 要获取的有限状态机数据的类型。 /// 有限状态机数据名称。 /// 要获取的有限状态机数据。 public TData GetData(string name) where TData : Variable { return (TData)GetData(name); } /// /// 获取有限状态机数据。 /// /// 有限状态机数据名称。 /// 要获取的有限状态机数据。 public Variable GetData(string name) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Data name is invalid."); } if (m_Datas == null) { return null; } Variable data = null; if (m_Datas.TryGetValue(name, out data)) { return data; } return null; } /// /// 设置有限状态机数据。 /// /// 要设置的有限状态机数据的类型。 /// 有限状态机数据名称。 /// 要设置的有限状态机数据。 public void SetData(string name, TData data) where TData : Variable { SetData(name, (Variable)data); } /// /// 设置有限状态机数据。 /// /// 有限状态机数据名称。 /// 要设置的有限状态机数据。 public void SetData(string name, Variable data) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Data name is invalid."); } if (m_Datas == null) { m_Datas = new Dictionary(StringComparer.Ordinal); } Variable oldData = GetData(name); if (oldData != null) { ReferencePool.Release(oldData); } m_Datas[name] = data; } /// /// 移除有限状态机数据。 /// /// 有限状态机数据名称。 /// 是否移除有限状态机数据成功。 public bool RemoveData(string name) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Data name is invalid."); } if (m_Datas == null) { return false; } Variable oldData = GetData(name); if (oldData != null) { ReferencePool.Release(oldData); } return m_Datas.Remove(name); } /// /// 有限状态机轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { if (m_CurrentState == null) { return; } m_CurrentStateTime += elapseSeconds; m_CurrentState.OnUpdate(this, elapseSeconds, realElapseSeconds); } /// /// 关闭并清理有限状态机。 /// internal override void Shutdown() { ReferencePool.Release(this); } /// /// 切换当前有限状态机状态。 /// /// 要切换到的有限状态机状态类型。 internal void ChangeState() where TState : FsmState { ChangeState(typeof(TState)); } /// /// 切换当前有限状态机状态。 /// /// 要切换到的有限状态机状态类型。 internal void ChangeState(Type stateType) { if (m_CurrentState == null) { throw new GameFrameworkException("Current state is invalid."); } FsmState state = GetState(stateType); if (state == null) { throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not change state to '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), stateType.FullName)); } m_CurrentState.OnLeave(this, false); m_CurrentStateTime = 0f; m_CurrentState = state; m_CurrentState.OnEnter(this); } } } ================================================ FILE: GameFramework/Fsm/FsmBase.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.Fsm { /// /// 有限状态机基类。 /// public abstract class FsmBase { private string m_Name; /// /// 初始化有限状态机基类的新实例。 /// public FsmBase() { m_Name = string.Empty; } /// /// 获取有限状态机名称。 /// public string Name { get { return m_Name; } protected set { m_Name = value ?? string.Empty; } } /// /// 获取有限状态机完整名称。 /// public string FullName { get { return new TypeNamePair(OwnerType, m_Name).ToString(); } } /// /// 获取有限状态机持有者类型。 /// public abstract Type OwnerType { get; } /// /// 获取有限状态机中状态的数量。 /// public abstract int FsmStateCount { get; } /// /// 获取有限状态机是否正在运行。 /// public abstract bool IsRunning { get; } /// /// 获取有限状态机是否被销毁。 /// public abstract bool IsDestroyed { get; } /// /// 获取当前有限状态机状态名称。 /// public abstract string CurrentStateName { get; } /// /// 获取当前有限状态机状态持续时间。 /// public abstract float CurrentStateTime { get; } /// /// 有限状态机轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 当前已流逝时间,以秒为单位。 internal abstract void Update(float elapseSeconds, float realElapseSeconds); /// /// 关闭并清理有限状态机。 /// internal abstract void Shutdown(); } } ================================================ FILE: GameFramework/Fsm/FsmManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Fsm { /// /// 有限状态机管理器。 /// internal sealed class FsmManager : GameFrameworkModule, IFsmManager { private readonly Dictionary m_Fsms; private readonly List m_TempFsms; /// /// 初始化有限状态机管理器的新实例。 /// public FsmManager() { m_Fsms = new Dictionary(); m_TempFsms = new List(); } /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal override int Priority { get { return 1; } } /// /// 获取有限状态机数量。 /// public int Count { get { return m_Fsms.Count; } } /// /// 有限状态机管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { m_TempFsms.Clear(); if (m_Fsms.Count <= 0) { return; } foreach (KeyValuePair fsm in m_Fsms) { m_TempFsms.Add(fsm.Value); } foreach (FsmBase fsm in m_TempFsms) { if (fsm.IsDestroyed) { continue; } fsm.Update(elapseSeconds, realElapseSeconds); } } /// /// 关闭并清理有限状态机管理器。 /// internal override void Shutdown() { foreach (KeyValuePair fsm in m_Fsms) { fsm.Value.Shutdown(); } m_Fsms.Clear(); m_TempFsms.Clear(); } /// /// 检查是否存在有限状态机。 /// /// 有限状态机持有者类型。 /// 是否存在有限状态机。 public bool HasFsm() where T : class { return InternalHasFsm(new TypeNamePair(typeof(T))); } /// /// 检查是否存在有限状态机。 /// /// 有限状态机持有者类型。 /// 是否存在有限状态机。 public bool HasFsm(Type ownerType) { if (ownerType == null) { throw new GameFrameworkException("Owner type is invalid."); } return InternalHasFsm(new TypeNamePair(ownerType)); } /// /// 检查是否存在有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 是否存在有限状态机。 public bool HasFsm(string name) where T : class { return InternalHasFsm(new TypeNamePair(typeof(T), name)); } /// /// 检查是否存在有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 是否存在有限状态机。 public bool HasFsm(Type ownerType, string name) { if (ownerType == null) { throw new GameFrameworkException("Owner type is invalid."); } return InternalHasFsm(new TypeNamePair(ownerType, name)); } /// /// 获取有限状态机。 /// /// 有限状态机持有者类型。 /// 要获取的有限状态机。 public IFsm GetFsm() where T : class { return (IFsm)InternalGetFsm(new TypeNamePair(typeof(T))); } /// /// 获取有限状态机。 /// /// 有限状态机持有者类型。 /// 要获取的有限状态机。 public FsmBase GetFsm(Type ownerType) { if (ownerType == null) { throw new GameFrameworkException("Owner type is invalid."); } return InternalGetFsm(new TypeNamePair(ownerType)); } /// /// 获取有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 要获取的有限状态机。 public IFsm GetFsm(string name) where T : class { return (IFsm)InternalGetFsm(new TypeNamePair(typeof(T), name)); } /// /// 获取有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 要获取的有限状态机。 public FsmBase GetFsm(Type ownerType, string name) { if (ownerType == null) { throw new GameFrameworkException("Owner type is invalid."); } return InternalGetFsm(new TypeNamePair(ownerType, name)); } /// /// 获取所有有限状态机。 /// /// 所有有限状态机。 public FsmBase[] GetAllFsms() { int index = 0; FsmBase[] results = new FsmBase[m_Fsms.Count]; foreach (KeyValuePair fsm in m_Fsms) { results[index++] = fsm.Value; } return results; } /// /// 获取所有有限状态机。 /// /// 所有有限状态机。 public void GetAllFsms(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair fsm in m_Fsms) { results.Add(fsm.Value); } } /// /// 创建有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机持有者。 /// 有限状态机状态集合。 /// 要创建的有限状态机。 public IFsm CreateFsm(T owner, params FsmState[] states) where T : class { return CreateFsm(string.Empty, owner, states); } /// /// 创建有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 有限状态机持有者。 /// 有限状态机状态集合。 /// 要创建的有限状态机。 public IFsm CreateFsm(string name, T owner, params FsmState[] states) where T : class { TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name); if (HasFsm(name)) { throw new GameFrameworkException(Utility.Text.Format("Already exist FSM '{0}'.", typeNamePair)); } Fsm fsm = Fsm.Create(name, owner, states); m_Fsms.Add(typeNamePair, fsm); return fsm; } /// /// 创建有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机持有者。 /// 有限状态机状态集合。 /// 要创建的有限状态机。 public IFsm CreateFsm(T owner, List> states) where T : class { return CreateFsm(string.Empty, owner, states); } /// /// 创建有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 有限状态机持有者。 /// 有限状态机状态集合。 /// 要创建的有限状态机。 public IFsm CreateFsm(string name, T owner, List> states) where T : class { TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name); if (HasFsm(name)) { throw new GameFrameworkException(Utility.Text.Format("Already exist FSM '{0}'.", typeNamePair)); } Fsm fsm = Fsm.Create(name, owner, states); m_Fsms.Add(typeNamePair, fsm); return fsm; } /// /// 销毁有限状态机。 /// /// 有限状态机持有者类型。 /// 是否销毁有限状态机成功。 public bool DestroyFsm() where T : class { return InternalDestroyFsm(new TypeNamePair(typeof(T))); } /// /// 销毁有限状态机。 /// /// 有限状态机持有者类型。 /// 是否销毁有限状态机成功。 public bool DestroyFsm(Type ownerType) { if (ownerType == null) { throw new GameFrameworkException("Owner type is invalid."); } return InternalDestroyFsm(new TypeNamePair(ownerType)); } /// /// 销毁有限状态机。 /// /// 有限状态机持有者类型。 /// 要销毁的有限状态机名称。 /// 是否销毁有限状态机成功。 public bool DestroyFsm(string name) where T : class { return InternalDestroyFsm(new TypeNamePair(typeof(T), name)); } /// /// 销毁有限状态机。 /// /// 有限状态机持有者类型。 /// 要销毁的有限状态机名称。 /// 是否销毁有限状态机成功。 public bool DestroyFsm(Type ownerType, string name) { if (ownerType == null) { throw new GameFrameworkException("Owner type is invalid."); } return InternalDestroyFsm(new TypeNamePair(ownerType, name)); } /// /// 销毁有限状态机。 /// /// 有限状态机持有者类型。 /// 要销毁的有限状态机。 /// 是否销毁有限状态机成功。 public bool DestroyFsm(IFsm fsm) where T : class { if (fsm == null) { throw new GameFrameworkException("FSM is invalid."); } return InternalDestroyFsm(new TypeNamePair(typeof(T), fsm.Name)); } /// /// 销毁有限状态机。 /// /// 要销毁的有限状态机。 /// 是否销毁有限状态机成功。 public bool DestroyFsm(FsmBase fsm) { if (fsm == null) { throw new GameFrameworkException("FSM is invalid."); } return InternalDestroyFsm(new TypeNamePair(fsm.OwnerType, fsm.Name)); } private bool InternalHasFsm(TypeNamePair typeNamePair) { return m_Fsms.ContainsKey(typeNamePair); } private FsmBase InternalGetFsm(TypeNamePair typeNamePair) { FsmBase fsm = null; if (m_Fsms.TryGetValue(typeNamePair, out fsm)) { return fsm; } return null; } private bool InternalDestroyFsm(TypeNamePair typeNamePair) { FsmBase fsm = null; if (m_Fsms.TryGetValue(typeNamePair, out fsm)) { fsm.Shutdown(); return m_Fsms.Remove(typeNamePair); } return false; } } } ================================================ FILE: GameFramework/Fsm/FsmState.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.Fsm { /// /// 有限状态机状态基类。 /// /// 有限状态机持有者类型。 public abstract class FsmState where T : class { /// /// 初始化有限状态机状态基类的新实例。 /// public FsmState() { } /// /// 有限状态机状态初始化时调用。 /// /// 有限状态机引用。 protected internal virtual void OnInit(IFsm fsm) { } /// /// 有限状态机状态进入时调用。 /// /// 有限状态机引用。 protected internal virtual void OnEnter(IFsm fsm) { } /// /// 有限状态机状态轮询时调用。 /// /// 有限状态机引用。 /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 protected internal virtual void OnUpdate(IFsm fsm, float elapseSeconds, float realElapseSeconds) { } /// /// 有限状态机状态离开时调用。 /// /// 有限状态机引用。 /// 是否是关闭有限状态机时触发。 protected internal virtual void OnLeave(IFsm fsm, bool isShutdown) { } /// /// 有限状态机状态销毁时调用。 /// /// 有限状态机引用。 protected internal virtual void OnDestroy(IFsm fsm) { } /// /// 切换当前有限状态机状态。 /// /// 要切换到的有限状态机状态类型。 /// 有限状态机引用。 protected void ChangeState(IFsm fsm) where TState : FsmState { Fsm fsmImplement = (Fsm)fsm; if (fsmImplement == null) { throw new GameFrameworkException("FSM is invalid."); } fsmImplement.ChangeState(); } /// /// 切换当前有限状态机状态。 /// /// 有限状态机引用。 /// 要切换到的有限状态机状态类型。 protected void ChangeState(IFsm fsm, Type stateType) { Fsm fsmImplement = (Fsm)fsm; if (fsmImplement == null) { throw new GameFrameworkException("FSM is invalid."); } if (stateType == null) { throw new GameFrameworkException("State type is invalid."); } if (!typeof(FsmState).IsAssignableFrom(stateType)) { throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName)); } fsmImplement.ChangeState(stateType); } } } ================================================ FILE: GameFramework/Fsm/IFsm.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Fsm { /// /// 有限状态机接口。 /// /// 有限状态机持有者类型。 public interface IFsm where T : class { /// /// 获取有限状态机名称。 /// string Name { get; } /// /// 获取有限状态机完整名称。 /// string FullName { get; } /// /// 获取有限状态机持有者。 /// T Owner { get; } /// /// 获取有限状态机中状态的数量。 /// int FsmStateCount { get; } /// /// 获取有限状态机是否正在运行。 /// bool IsRunning { get; } /// /// 获取有限状态机是否被销毁。 /// bool IsDestroyed { get; } /// /// 获取当前有限状态机状态。 /// FsmState CurrentState { get; } /// /// 获取当前有限状态机状态持续时间。 /// float CurrentStateTime { get; } /// /// 开始有限状态机。 /// /// 要开始的有限状态机状态类型。 void Start() where TState : FsmState; /// /// 开始有限状态机。 /// /// 要开始的有限状态机状态类型。 void Start(Type stateType); /// /// 是否存在有限状态机状态。 /// /// 要检查的有限状态机状态类型。 /// 是否存在有限状态机状态。 bool HasState() where TState : FsmState; /// /// 是否存在有限状态机状态。 /// /// 要检查的有限状态机状态类型。 /// 是否存在有限状态机状态。 bool HasState(Type stateType); /// /// 获取有限状态机状态。 /// /// 要获取的有限状态机状态类型。 /// 要获取的有限状态机状态。 TState GetState() where TState : FsmState; /// /// 获取有限状态机状态。 /// /// 要获取的有限状态机状态类型。 /// 要获取的有限状态机状态。 FsmState GetState(Type stateType); /// /// 获取有限状态机的所有状态。 /// /// 有限状态机的所有状态。 FsmState[] GetAllStates(); /// /// 获取有限状态机的所有状态。 /// /// 有限状态机的所有状态。 void GetAllStates(List> results); /// /// 是否存在有限状态机数据。 /// /// 有限状态机数据名称。 /// 有限状态机数据是否存在。 bool HasData(string name); /// /// 获取有限状态机数据。 /// /// 要获取的有限状态机数据的类型。 /// 有限状态机数据名称。 /// 要获取的有限状态机数据。 TData GetData(string name) where TData : Variable; /// /// 获取有限状态机数据。 /// /// 有限状态机数据名称。 /// 要获取的有限状态机数据。 Variable GetData(string name); /// /// 设置有限状态机数据。 /// /// 要设置的有限状态机数据的类型。 /// 有限状态机数据名称。 /// 要设置的有限状态机数据。 void SetData(string name, TData data) where TData : Variable; /// /// 设置有限状态机数据。 /// /// 有限状态机数据名称。 /// 要设置的有限状态机数据。 void SetData(string name, Variable data); /// /// 移除有限状态机数据。 /// /// 有限状态机数据名称。 /// 是否移除有限状态机数据成功。 bool RemoveData(string name); } } ================================================ FILE: GameFramework/Fsm/IFsmManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Fsm { /// /// 有限状态机管理器。 /// public interface IFsmManager { /// /// 获取有限状态机数量。 /// int Count { get; } /// /// 检查是否存在有限状态机。 /// /// 有限状态机持有者类型。 /// 是否存在有限状态机。 bool HasFsm() where T : class; /// /// 检查是否存在有限状态机。 /// /// 有限状态机持有者类型。 /// 是否存在有限状态机。 bool HasFsm(Type ownerType); /// /// 检查是否存在有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 是否存在有限状态机。 bool HasFsm(string name) where T : class; /// /// 检查是否存在有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 是否存在有限状态机。 bool HasFsm(Type ownerType, string name); /// /// 获取有限状态机。 /// /// 有限状态机持有者类型。 /// 要获取的有限状态机。 IFsm GetFsm() where T : class; /// /// 获取有限状态机。 /// /// 有限状态机持有者类型。 /// 要获取的有限状态机。 FsmBase GetFsm(Type ownerType); /// /// 获取有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 要获取的有限状态机。 IFsm GetFsm(string name) where T : class; /// /// 获取有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 要获取的有限状态机。 FsmBase GetFsm(Type ownerType, string name); /// /// 获取所有有限状态机。 /// /// 所有有限状态机。 FsmBase[] GetAllFsms(); /// /// 获取所有有限状态机。 /// /// 所有有限状态机。 void GetAllFsms(List results); /// /// 创建有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机持有者。 /// 有限状态机状态集合。 /// 要创建的有限状态机。 IFsm CreateFsm(T owner, params FsmState[] states) where T : class; /// /// 创建有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 有限状态机持有者。 /// 有限状态机状态集合。 /// 要创建的有限状态机。 IFsm CreateFsm(string name, T owner, params FsmState[] states) where T : class; /// /// 创建有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机持有者。 /// 有限状态机状态集合。 /// 要创建的有限状态机。 IFsm CreateFsm(T owner, List> states) where T : class; /// /// 创建有限状态机。 /// /// 有限状态机持有者类型。 /// 有限状态机名称。 /// 有限状态机持有者。 /// 有限状态机状态集合。 /// 要创建的有限状态机。 IFsm CreateFsm(string name, T owner, List> states) where T : class; /// /// 销毁有限状态机。 /// /// 有限状态机持有者类型。 /// 是否销毁有限状态机成功。 bool DestroyFsm() where T : class; /// /// 销毁有限状态机。 /// /// 有限状态机持有者类型。 /// 是否销毁有限状态机成功。 bool DestroyFsm(Type ownerType); /// /// 销毁有限状态机。 /// /// 有限状态机持有者类型。 /// 要销毁的有限状态机名称。 /// 是否销毁有限状态机成功。 bool DestroyFsm(string name) where T : class; /// /// 销毁有限状态机。 /// /// 有限状态机持有者类型。 /// 要销毁的有限状态机名称。 /// 是否销毁有限状态机成功。 bool DestroyFsm(Type ownerType, string name); /// /// 销毁有限状态机。 /// /// 有限状态机持有者类型。 /// 要销毁的有限状态机。 /// 是否销毁有限状态机成功。 bool DestroyFsm(IFsm fsm) where T : class; /// /// 销毁有限状态机。 /// /// 要销毁的有限状态机。 /// 是否销毁有限状态机成功。 bool DestroyFsm(FsmBase fsm); } } ================================================ FILE: GameFramework/GameFramework.csproj ================================================  Debug AnyCPU {109D7F39-79AB-4862-9F73-0B8C638930C6} Library Properties GameFramework GameFramework v3.5 512 true true full false bin\Debug\ DEBUG;TRACE prompt 4 bin\Debug\GameFramework.xml true true pdbonly true bin\Release\ TRACE prompt 4 bin\Release\GameFramework.xml true true ================================================ FILE: GameFramework/Localization/ILocalizationHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Localization { /// /// 本地化辅助器接口。 /// public interface ILocalizationHelper { /// /// 获取系统语言。 /// Language SystemLanguage { get; } } } ================================================ FILE: GameFramework/Localization/ILocalizationManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; namespace GameFramework.Localization { /// /// 本地化管理器接口。 /// public interface ILocalizationManager : IDataProvider { /// /// 获取或设置本地化语言。 /// Language Language { get; set; } /// /// 获取系统语言。 /// Language SystemLanguage { get; } /// /// 获取字典数量。 /// int DictionaryCount { get; } /// /// 获取缓冲二进制流的大小。 /// int CachedBytesSize { get; } /// /// 设置资源管理器。 /// /// 资源管理器。 void SetResourceManager(IResourceManager resourceManager); /// /// 设置本地化数据提供者辅助器。 /// /// 本地化数据提供者辅助器。 void SetDataProviderHelper(IDataProviderHelper dataProviderHelper); /// /// 设置本地化辅助器。 /// /// 本地化辅助器。 void SetLocalizationHelper(ILocalizationHelper localizationHelper); /// /// 确保二进制流缓存分配足够大小的内存并缓存。 /// /// 要确保二进制流缓存分配内存的大小。 void EnsureCachedBytesSize(int ensureSize); /// /// 释放缓存的二进制流。 /// void FreeCachedBytes(); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典主键。 /// 要获取的字典内容字符串。 string GetString(string key); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数的类型。 /// 字典主键。 /// 字典参数。 /// 要获取的字典内容字符串。 string GetString(string key, T arg); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典参数 12 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 字典参数 12。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典参数 12 的类型。 /// 字典参数 13 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 字典参数 12。 /// 字典参数 13。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典参数 12 的类型。 /// 字典参数 13 的类型。 /// 字典参数 14 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 字典参数 12。 /// 字典参数 13。 /// 字典参数 14。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典参数 12 的类型。 /// 字典参数 13 的类型。 /// 字典参数 14 的类型。 /// 字典参数 15 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 字典参数 12。 /// 字典参数 13。 /// 字典参数 14。 /// 字典参数 15。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典参数 12 的类型。 /// 字典参数 13 的类型。 /// 字典参数 14 的类型。 /// 字典参数 15 的类型。 /// 字典参数 16 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 字典参数 12。 /// 字典参数 13。 /// 字典参数 14。 /// 字典参数 15。 /// 字典参数 16。 /// 要获取的字典内容字符串。 string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); /// /// 是否存在字典。 /// /// 字典主键。 /// 是否存在字典。 bool HasRawString(string key); /// /// 根据字典主键获取字典值。 /// /// 字典主键。 /// 字典值。 string GetRawString(string key); /// /// 增加字典。 /// /// 字典主键。 /// 字典内容。 /// 是否增加字典成功。 bool AddRawString(string key, string value); /// /// 移除字典。 /// /// 字典主键。 /// 是否移除字典成功。 bool RemoveRawString(string key); /// /// 清空所有字典。 /// void RemoveAllRawStrings(); } } ================================================ FILE: GameFramework/Localization/Language.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Localization { /// /// 本地化语言。 /// public enum Language : byte { /// /// 未指定。 /// Unspecified = 0, /// /// 南非荷兰语。 /// Afrikaans, /// /// 阿尔巴尼亚语。 /// Albanian, /// /// 阿拉伯语。 /// Arabic, /// /// 巴斯克语。 /// Basque, /// /// 白俄罗斯语。 /// Belarusian, /// /// 保加利亚语。 /// Bulgarian, /// /// 加泰罗尼亚语。 /// Catalan, /// /// 简体中文。 /// ChineseSimplified, /// /// 繁体中文。 /// ChineseTraditional, /// /// 克罗地亚语。 /// Croatian, /// /// 捷克语。 /// Czech, /// /// 丹麦语。 /// Danish, /// /// 荷兰语。 /// Dutch, /// /// 英语。 /// English, /// /// 爱沙尼亚语。 /// Estonian, /// /// 法罗语。 /// Faroese, /// /// 芬兰语。 /// Finnish, /// /// 法语。 /// French, /// /// 格鲁吉亚语。 /// Georgian, /// /// 德语。 /// German, /// /// 希腊语。 /// Greek, /// /// 希伯来语。 /// Hebrew, /// /// 匈牙利语。 /// Hungarian, /// /// 冰岛语。 /// Icelandic, /// /// 印尼语。 /// Indonesian, /// /// 意大利语。 /// Italian, /// /// 日语。 /// Japanese, /// /// 韩语。 /// Korean, /// /// 拉脱维亚语。 /// Latvian, /// /// 立陶宛语。 /// Lithuanian, /// /// 马其顿语。 /// Macedonian, /// /// 马拉雅拉姆语。 /// Malayalam, /// /// 挪威语。 /// Norwegian, /// /// 波斯语。 /// Persian, /// /// 波兰语。 /// Polish, /// /// 巴西葡萄牙语。 /// PortugueseBrazil, /// /// 葡萄牙语。 /// PortuguesePortugal, /// /// 罗马尼亚语。 /// Romanian, /// /// 俄语。 /// Russian, /// /// 塞尔维亚克罗地亚语。 /// SerboCroatian, /// /// 塞尔维亚西里尔语。 /// SerbianCyrillic, /// /// 塞尔维亚拉丁语。 /// SerbianLatin, /// /// 斯洛伐克语。 /// Slovak, /// /// 斯洛文尼亚语。 /// Slovenian, /// /// 西班牙语。 /// Spanish, /// /// 瑞典语。 /// Swedish, /// /// 泰语。 /// Thai, /// /// 土耳其语。 /// Turkish, /// /// 乌克兰语。 /// Ukrainian, /// /// 越南语。 /// Vietnamese } } ================================================ FILE: GameFramework/Localization/LocalizationManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.Localization { /// /// 本地化管理器。 /// internal sealed partial class LocalizationManager : GameFrameworkModule, ILocalizationManager { private readonly Dictionary m_Dictionary; private readonly DataProvider m_DataProvider; private ILocalizationHelper m_LocalizationHelper; private Language m_Language; /// /// 初始化本地化管理器的新实例。 /// public LocalizationManager() { m_Dictionary = new Dictionary(StringComparer.Ordinal); m_DataProvider = new DataProvider(this); m_LocalizationHelper = null; m_Language = Language.Unspecified; } /// /// 获取或设置本地化语言。 /// public Language Language { get { return m_Language; } set { if (value == Language.Unspecified) { throw new GameFrameworkException("Language is invalid."); } m_Language = value; } } /// /// 获取系统语言。 /// public Language SystemLanguage { get { if (m_LocalizationHelper == null) { throw new GameFrameworkException("You must set localization helper first."); } return m_LocalizationHelper.SystemLanguage; } } /// /// 获取字典数量。 /// public int DictionaryCount { get { return m_Dictionary.Count; } } /// /// 获取缓冲二进制流的大小。 /// public int CachedBytesSize { get { return DataProvider.CachedBytesSize; } } /// /// 读取字典成功事件。 /// public event EventHandler ReadDataSuccess { add { m_DataProvider.ReadDataSuccess += value; } remove { m_DataProvider.ReadDataSuccess -= value; } } /// /// 读取字典失败事件。 /// public event EventHandler ReadDataFailure { add { m_DataProvider.ReadDataFailure += value; } remove { m_DataProvider.ReadDataFailure -= value; } } /// /// 读取字典更新事件。 /// public event EventHandler ReadDataUpdate { add { m_DataProvider.ReadDataUpdate += value; } remove { m_DataProvider.ReadDataUpdate -= value; } } /// /// 读取字典时加载依赖资源事件。 /// public event EventHandler ReadDataDependencyAsset { add { m_DataProvider.ReadDataDependencyAsset += value; } remove { m_DataProvider.ReadDataDependencyAsset -= value; } } /// /// 本地化管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { } /// /// 关闭并清理本地化管理器。 /// internal override void Shutdown() { } /// /// 设置资源管理器。 /// /// 资源管理器。 public void SetResourceManager(IResourceManager resourceManager) { m_DataProvider.SetResourceManager(resourceManager); } /// /// 设置本地化数据提供者辅助器。 /// /// 本地化数据提供者辅助器。 public void SetDataProviderHelper(IDataProviderHelper dataProviderHelper) { m_DataProvider.SetDataProviderHelper(dataProviderHelper); } /// /// 设置本地化辅助器。 /// /// 本地化辅助器。 public void SetLocalizationHelper(ILocalizationHelper localizationHelper) { if (localizationHelper == null) { throw new GameFrameworkException("Localization helper is invalid."); } m_LocalizationHelper = localizationHelper; } /// /// 确保二进制流缓存分配足够大小的内存并缓存。 /// /// 要确保二进制流缓存分配内存的大小。 public void EnsureCachedBytesSize(int ensureSize) { DataProvider.EnsureCachedBytesSize(ensureSize); } /// /// 释放缓存的二进制流。 /// public void FreeCachedBytes() { DataProvider.FreeCachedBytes(); } /// /// 读取字典。 /// /// 字典资源名称。 public void ReadData(string dictionaryAssetName) { m_DataProvider.ReadData(dictionaryAssetName); } /// /// 读取字典。 /// /// 字典资源名称。 /// 加载字典资源的优先级。 public void ReadData(string dictionaryAssetName, int priority) { m_DataProvider.ReadData(dictionaryAssetName, priority); } /// /// 读取字典。 /// /// 字典资源名称。 /// 用户自定义数据。 public void ReadData(string dictionaryAssetName, object userData) { m_DataProvider.ReadData(dictionaryAssetName, userData); } /// /// 读取字典。 /// /// 字典资源名称。 /// 加载字典资源的优先级。 /// 用户自定义数据。 public void ReadData(string dictionaryAssetName, int priority, object userData) { m_DataProvider.ReadData(dictionaryAssetName, priority, userData); } /// /// 解析字典。 /// /// 要解析的字典字符串。 /// 是否解析字典成功。 public bool ParseData(string dictionaryString) { return m_DataProvider.ParseData(dictionaryString); } /// /// 解析字典。 /// /// 要解析的字典字符串。 /// 用户自定义数据。 /// 是否解析字典成功。 public bool ParseData(string dictionaryString, object userData) { return m_DataProvider.ParseData(dictionaryString, userData); } /// /// 解析字典。 /// /// 要解析的字典二进制流。 /// 是否解析字典成功。 public bool ParseData(byte[] dictionaryBytes) { return m_DataProvider.ParseData(dictionaryBytes); } /// /// 解析字典。 /// /// 要解析的字典二进制流。 /// 用户自定义数据。 /// 是否解析字典成功。 public bool ParseData(byte[] dictionaryBytes, object userData) { return m_DataProvider.ParseData(dictionaryBytes, userData); } /// /// 解析字典。 /// /// 要解析的字典二进制流。 /// 字典二进制流的起始位置。 /// 字典二进制流的长度。 /// 是否解析字典成功。 public bool ParseData(byte[] dictionaryBytes, int startIndex, int length) { return m_DataProvider.ParseData(dictionaryBytes, startIndex, length); } /// /// 解析字典。 /// /// 要解析的字典二进制流。 /// 字典二进制流的起始位置。 /// 字典二进制流的长度。 /// 用户自定义数据。 /// 是否解析字典成功。 public bool ParseData(byte[] dictionaryBytes, int startIndex, int length, object userData) { return m_DataProvider.ParseData(dictionaryBytes, startIndex, length, userData); } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典主键。 /// 要获取的字典内容字符串。 public string GetString(string key) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } return value; } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数的类型。 /// 字典主键。 /// 字典参数。 /// 要获取的字典内容字符串。 public string GetString(string key, T arg) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3}", key, value, arg, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4}", key, value, arg1, arg2, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5}", key, value, arg1, arg2, arg3, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6}", key, value, arg1, arg2, arg3, arg4, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7}", key, value, arg1, arg2, arg3, arg4, arg5, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8}", key, value, arg1, arg2, arg3, arg4, arg5, arg6, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}", key, value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10}", key, value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11}", key, value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12}", key, value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13}", key, value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典参数 12 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 字典参数 12。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14}", key, value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典参数 12 的类型。 /// 字典参数 13 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 字典参数 12。 /// 字典参数 13。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); } catch (Exception exception) { return Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}", key, value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典参数 12 的类型。 /// 字典参数 13 的类型。 /// 字典参数 14 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 字典参数 12。 /// 字典参数 13。 /// 字典参数 14。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); } catch (Exception exception) { string args = Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13}", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); return Utility.Text.Format("{0},{1},{2},{3}", key, value, args, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典参数 12 的类型。 /// 字典参数 13 的类型。 /// 字典参数 14 的类型。 /// 字典参数 15 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 字典参数 12。 /// 字典参数 13。 /// 字典参数 14。 /// 字典参数 15。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); } catch (Exception exception) { string args = Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14}", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); return Utility.Text.Format("{0},{1},{2},{3}", key, value, args, exception); } } /// /// 根据字典主键获取字典内容字符串。 /// /// 字典参数 1 的类型。 /// 字典参数 2 的类型。 /// 字典参数 3 的类型。 /// 字典参数 4 的类型。 /// 字典参数 5 的类型。 /// 字典参数 6 的类型。 /// 字典参数 7 的类型。 /// 字典参数 8 的类型。 /// 字典参数 9 的类型。 /// 字典参数 10 的类型。 /// 字典参数 11 的类型。 /// 字典参数 12 的类型。 /// 字典参数 13 的类型。 /// 字典参数 14 的类型。 /// 字典参数 15 的类型。 /// 字典参数 16 的类型。 /// 字典主键。 /// 字典参数 1。 /// 字典参数 2。 /// 字典参数 3。 /// 字典参数 4。 /// 字典参数 5。 /// 字典参数 6。 /// 字典参数 7。 /// 字典参数 8。 /// 字典参数 9。 /// 字典参数 10。 /// 字典参数 11。 /// 字典参数 12。 /// 字典参数 13。 /// 字典参数 14。 /// 字典参数 15。 /// 字典参数 16。 /// 要获取的字典内容字符串。 public string GetString(string key, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) { string value = GetRawString(key); if (value == null) { return Utility.Text.Format("{0}", key); } try { return Utility.Text.Format(value, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); } catch (Exception exception) { string args = Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); return Utility.Text.Format("{0},{1},{2},{3}", key, value, args, exception); } } /// /// 是否存在字典。 /// /// 字典主键。 /// 是否存在字典。 public bool HasRawString(string key) { if (string.IsNullOrEmpty(key)) { throw new GameFrameworkException("Key is invalid."); } return m_Dictionary.ContainsKey(key); } /// /// 根据字典主键获取字典值。 /// /// 字典主键。 /// 字典值。 public string GetRawString(string key) { if (string.IsNullOrEmpty(key)) { throw new GameFrameworkException("Key is invalid."); } string value = null; if (m_Dictionary.TryGetValue(key, out value)) { return value; } return null; } /// /// 增加字典。 /// /// 字典主键。 /// 字典内容。 /// 是否增加字典成功。 public bool AddRawString(string key, string value) { if (string.IsNullOrEmpty(key)) { throw new GameFrameworkException("Key is invalid."); } if (m_Dictionary.ContainsKey(key)) { return false; } m_Dictionary.Add(key, value ?? string.Empty); return true; } /// /// 移除字典。 /// /// 字典主键。 /// 是否移除字典成功。 public bool RemoveRawString(string key) { if (string.IsNullOrEmpty(key)) { throw new GameFrameworkException("Key is invalid."); } return m_Dictionary.Remove(key); } /// /// 清空所有字典。 /// public void RemoveAllRawStrings() { m_Dictionary.Clear(); } } } ================================================ FILE: GameFramework/Network/AddressFamily.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { /// /// 网络地址类型。 /// public enum AddressFamily : byte { /// /// 未知。 /// Unknown = 0, /// /// IP 版本 4。 /// IPv4, /// /// IP 版本 6。 /// IPv6 } } ================================================ FILE: GameFramework/Network/INetworkChannel.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Net; using System.Net.Sockets; namespace GameFramework.Network { /// /// 网络频道接口。 /// public interface INetworkChannel { /// /// 获取网络频道名称。 /// string Name { get; } /// /// 获取网络频道所使用的 Socket。 /// Socket Socket { get; } /// /// 获取是否已连接。 /// bool Connected { get; } /// /// 获取网络服务类型。 /// ServiceType ServiceType { get; } /// /// 获取网络地址类型。 /// AddressFamily AddressFamily { get; } /// /// 获取要发送的消息包数量。 /// int SendPacketCount { get; } /// /// 获取累计发送的消息包数量。 /// int SentPacketCount { get; } /// /// 获取已接收未处理的消息包数量。 /// int ReceivePacketCount { get; } /// /// 获取累计已接收的消息包数量。 /// int ReceivedPacketCount { get; } /// /// 获取或设置当收到消息包时是否重置心跳流逝时间。 /// bool ResetHeartBeatElapseSecondsWhenReceivePacket { get; set; } /// /// 获取丢失心跳的次数。 /// int MissHeartBeatCount { get; } /// /// 获取或设置心跳间隔时长,以秒为单位。 /// float HeartBeatInterval { get; set; } /// /// 获取心跳等待时长,以秒为单位。 /// float HeartBeatElapseSeconds { get; } /// /// 注册网络消息包处理函数。 /// /// 要注册的网络消息包处理函数。 void RegisterHandler(IPacketHandler handler); /// /// 设置默认事件处理函数。 /// /// 要设置的默认事件处理函数。 void SetDefaultHandler(EventHandler handler); /// /// 连接到远程主机。 /// /// 远程主机的 IP 地址。 /// 远程主机的端口号。 void Connect(IPAddress ipAddress, int port); /// /// 连接到远程主机。 /// /// 远程主机的 IP 地址。 /// 远程主机的端口号。 /// 用户自定义数据。 void Connect(IPAddress ipAddress, int port, object userData); /// /// 关闭网络频道。 /// void Close(); /// /// 向远程主机发送消息包。 /// /// 消息包类型。 /// 要发送的消息包。 void Send(T packet) where T : Packet; } } ================================================ FILE: GameFramework/Network/INetworkChannelHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.IO; namespace GameFramework.Network { /// /// 网络频道辅助器接口。 /// public interface INetworkChannelHelper { /// /// 获取消息包头长度。 /// int PacketHeaderLength { get; } /// /// 初始化网络频道辅助器。 /// /// 网络频道。 void Initialize(INetworkChannel networkChannel); /// /// 关闭并清理网络频道辅助器。 /// void Shutdown(); /// /// 准备进行连接。 /// void PrepareForConnecting(); /// /// 发送心跳消息包。 /// /// 是否发送心跳消息包成功。 bool SendHeartBeat(); /// /// 序列化消息包。 /// /// 消息包类型。 /// 要序列化的消息包。 /// 要序列化的目标流。 /// 是否序列化成功。 bool Serialize(T packet, Stream destination) where T : Packet; /// /// 反序列化消息包头。 /// /// 要反序列化的来源流。 /// 用户自定义错误数据。 /// 反序列化后的消息包头。 IPacketHeader DeserializePacketHeader(Stream source, out object customErrorData); /// /// 反序列化消息包。 /// /// 消息包头。 /// 要反序列化的来源流。 /// 用户自定义错误数据。 /// 反序列化后的消息包。 Packet DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData); } } ================================================ FILE: GameFramework/Network/INetworkManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Network { /// /// 网络管理器接口。 /// public interface INetworkManager { /// /// 获取网络频道数量。 /// int NetworkChannelCount { get; } /// /// 网络连接成功事件。 /// event EventHandler NetworkConnected; /// /// 网络连接关闭事件。 /// event EventHandler NetworkClosed; /// /// 网络心跳包丢失事件。 /// event EventHandler NetworkMissHeartBeat; /// /// 网络错误事件。 /// event EventHandler NetworkError; /// /// 用户自定义网络错误事件。 /// event EventHandler NetworkCustomError; /// /// 检查是否存在网络频道。 /// /// 网络频道名称。 /// 是否存在网络频道。 bool HasNetworkChannel(string name); /// /// 获取网络频道。 /// /// 网络频道名称。 /// 要获取的网络频道。 INetworkChannel GetNetworkChannel(string name); /// /// 获取所有网络频道。 /// /// 所有网络频道。 INetworkChannel[] GetAllNetworkChannels(); /// /// 获取所有网络频道。 /// /// 所有网络频道。 void GetAllNetworkChannels(List results); /// /// 创建网络频道。 /// /// 网络频道名称。 /// 网络服务类型。 /// 网络频道辅助器。 /// 要创建的网络频道。 INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType, INetworkChannelHelper networkChannelHelper); /// /// 销毁网络频道。 /// /// 网络频道名称。 /// 是否销毁网络频道成功。 bool DestroyNetworkChannel(string name); } } ================================================ FILE: GameFramework/Network/IPacketHandler.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { /// /// 网络消息包处理器接口。 /// public interface IPacketHandler { /// /// 获取网络消息包协议编号。 /// int Id { get; } /// /// 网络消息包处理函数。 /// /// 网络消息包源。 /// 网络消息包内容。 void Handle(object sender, Packet packet); } } ================================================ FILE: GameFramework/Network/IPacketHeader.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { /// /// 网络消息包头接口。 /// public interface IPacketHeader { /// /// 获取网络消息包长度。 /// int PacketLength { get; } } } ================================================ FILE: GameFramework/Network/NetworkClosedEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { /// /// 网络连接关闭事件。 /// public sealed class NetworkClosedEventArgs : GameFrameworkEventArgs { /// /// 初始化网络连接关闭事件的新实例。 /// public NetworkClosedEventArgs() { NetworkChannel = null; } /// /// 获取网络频道。 /// public INetworkChannel NetworkChannel { get; private set; } /// /// 创建网络连接关闭事件。 /// /// 网络频道。 /// 创建的网络连接关闭事件。 public static NetworkClosedEventArgs Create(INetworkChannel networkChannel) { NetworkClosedEventArgs networkClosedEventArgs = ReferencePool.Acquire(); networkClosedEventArgs.NetworkChannel = networkChannel; return networkClosedEventArgs; } /// /// 清理网络连接关闭事件。 /// public override void Clear() { NetworkChannel = null; } } } ================================================ FILE: GameFramework/Network/NetworkConnectedEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { /// /// 网络连接成功事件。 /// public sealed class NetworkConnectedEventArgs : GameFrameworkEventArgs { /// /// 初始化网络连接成功事件的新实例。 /// public NetworkConnectedEventArgs() { NetworkChannel = null; UserData = null; } /// /// 获取网络频道。 /// public INetworkChannel NetworkChannel { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建网络连接成功事件。 /// /// 网络频道。 /// 用户自定义数据。 /// 创建的网络连接成功事件。 public static NetworkConnectedEventArgs Create(INetworkChannel networkChannel, object userData) { NetworkConnectedEventArgs networkConnectedEventArgs = ReferencePool.Acquire(); networkConnectedEventArgs.NetworkChannel = networkChannel; networkConnectedEventArgs.UserData = userData; return networkConnectedEventArgs; } /// /// 清理网络连接成功事件。 /// public override void Clear() { NetworkChannel = null; UserData = null; } } } ================================================ FILE: GameFramework/Network/NetworkCustomErrorEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { /// /// 用户自定义网络错误事件。 /// public sealed class NetworkCustomErrorEventArgs : GameFrameworkEventArgs { /// /// 初始化用户自定义网络错误事件的新实例。 /// public NetworkCustomErrorEventArgs() { NetworkChannel = null; CustomErrorData = null; } /// /// 获取网络频道。 /// public INetworkChannel NetworkChannel { get; private set; } /// /// 获取用户自定义错误数据。 /// public object CustomErrorData { get; private set; } /// /// 创建用户自定义网络错误事件。 /// /// 网络频道。 /// 用户自定义错误数据。 /// 创建的用户自定义网络错误事件。 public static NetworkCustomErrorEventArgs Create(INetworkChannel networkChannel, object customErrorData) { NetworkCustomErrorEventArgs networkCustomErrorEventArgs = ReferencePool.Acquire(); networkCustomErrorEventArgs.NetworkChannel = networkChannel; networkCustomErrorEventArgs.CustomErrorData = customErrorData; return networkCustomErrorEventArgs; } /// /// 清理用户自定义网络错误事件。 /// public override void Clear() { NetworkChannel = null; CustomErrorData = null; } } } ================================================ FILE: GameFramework/Network/NetworkErrorCode.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { /// /// 网络错误码。 /// public enum NetworkErrorCode : byte { /// /// 未知错误。 /// Unknown = 0, /// /// 地址族错误。 /// AddressFamilyError, /// /// Socket 错误。 /// SocketError, /// /// 连接错误。 /// ConnectError, /// /// 发送错误。 /// SendError, /// /// 接收错误。 /// ReceiveError, /// /// 序列化错误。 /// SerializeError, /// /// 反序列化消息包头错误。 /// DeserializePacketHeaderError, /// /// 反序列化消息包错误。 /// DeserializePacketError } } ================================================ FILE: GameFramework/Network/NetworkErrorEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Net.Sockets; namespace GameFramework.Network { /// /// 网络错误事件。 /// public sealed class NetworkErrorEventArgs : GameFrameworkEventArgs { /// /// 初始化网络错误事件的新实例。 /// public NetworkErrorEventArgs() { NetworkChannel = null; ErrorCode = NetworkErrorCode.Unknown; SocketErrorCode = SocketError.Success; ErrorMessage = null; } /// /// 获取网络频道。 /// public INetworkChannel NetworkChannel { get; private set; } /// /// 获取错误码。 /// public NetworkErrorCode ErrorCode { get; private set; } /// /// 获取 Socket 错误码。 /// public SocketError SocketErrorCode { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 创建网络错误事件。 /// /// 网络频道。 /// 错误码。 /// Socket 错误码。 /// 错误信息。 /// 创建的网络错误事件。 public static NetworkErrorEventArgs Create(INetworkChannel networkChannel, NetworkErrorCode errorCode, SocketError socketErrorCode, string errorMessage) { NetworkErrorEventArgs networkErrorEventArgs = ReferencePool.Acquire(); networkErrorEventArgs.NetworkChannel = networkChannel; networkErrorEventArgs.ErrorCode = errorCode; networkErrorEventArgs.SocketErrorCode = socketErrorCode; networkErrorEventArgs.ErrorMessage = errorMessage; return networkErrorEventArgs; } /// /// 清理网络错误事件。 /// public override void Clear() { NetworkChannel = null; ErrorCode = NetworkErrorCode.Unknown; SocketErrorCode = SocketError.Success; ErrorMessage = null; } } } ================================================ FILE: GameFramework/Network/NetworkManager.ConnectState.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Net.Sockets; namespace GameFramework.Network { internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager { private sealed class ConnectState { private readonly Socket m_Socket; private readonly object m_UserData; public ConnectState(Socket socket, object userData) { m_Socket = socket; m_UserData = userData; } public Socket Socket { get { return m_Socket; } } public object UserData { get { return m_UserData; } } } } } ================================================ FILE: GameFramework/Network/NetworkManager.HeartBeatState.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager { private sealed class HeartBeatState { private float m_HeartBeatElapseSeconds; private int m_MissHeartBeatCount; public HeartBeatState() { m_HeartBeatElapseSeconds = 0f; m_MissHeartBeatCount = 0; } public float HeartBeatElapseSeconds { get { return m_HeartBeatElapseSeconds; } set { m_HeartBeatElapseSeconds = value; } } public int MissHeartBeatCount { get { return m_MissHeartBeatCount; } set { m_MissHeartBeatCount = value; } } public void Reset(bool resetHeartBeatElapseSeconds) { if (resetHeartBeatElapseSeconds) { m_HeartBeatElapseSeconds = 0f; } m_MissHeartBeatCount = 0; } } } } ================================================ FILE: GameFramework/Network/NetworkManager.NetworkChannelBase.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; namespace GameFramework.Network { internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager { /// /// 网络频道基类。 /// private abstract class NetworkChannelBase : INetworkChannel, IDisposable { private const float DefaultHeartBeatInterval = 30f; private readonly string m_Name; protected readonly Queue m_SendPacketPool; protected readonly EventPool m_ReceivePacketPool; protected readonly INetworkChannelHelper m_NetworkChannelHelper; protected AddressFamily m_AddressFamily; protected bool m_ResetHeartBeatElapseSecondsWhenReceivePacket; protected float m_HeartBeatInterval; protected Socket m_Socket; protected readonly SendState m_SendState; protected readonly ReceiveState m_ReceiveState; protected readonly HeartBeatState m_HeartBeatState; protected int m_SentPacketCount; protected int m_ReceivedPacketCount; protected bool m_Active; private bool m_Disposed; public GameFrameworkAction NetworkChannelConnected; public GameFrameworkAction NetworkChannelClosed; public GameFrameworkAction NetworkChannelMissHeartBeat; public GameFrameworkAction NetworkChannelError; public GameFrameworkAction NetworkChannelCustomError; /// /// 初始化网络频道基类的新实例。 /// /// 网络频道名称。 /// 网络频道辅助器。 public NetworkChannelBase(string name, INetworkChannelHelper networkChannelHelper) { m_Name = name ?? string.Empty; m_SendPacketPool = new Queue(); m_ReceivePacketPool = new EventPool(EventPoolMode.Default); m_NetworkChannelHelper = networkChannelHelper; m_AddressFamily = AddressFamily.Unknown; m_ResetHeartBeatElapseSecondsWhenReceivePacket = false; m_HeartBeatInterval = DefaultHeartBeatInterval; m_Socket = null; m_SendState = new SendState(); m_ReceiveState = new ReceiveState(); m_HeartBeatState = new HeartBeatState(); m_SentPacketCount = 0; m_ReceivedPacketCount = 0; m_Active = false; m_Disposed = false; NetworkChannelConnected = null; NetworkChannelClosed = null; NetworkChannelMissHeartBeat = null; NetworkChannelError = null; NetworkChannelCustomError = null; networkChannelHelper.Initialize(this); } /// /// 获取网络频道名称。 /// public string Name { get { return m_Name; } } /// /// 获取网络频道所使用的 Socket。 /// public Socket Socket { get { return m_Socket; } } /// /// 获取是否已连接。 /// public bool Connected { get { if (m_Socket != null) { return m_Socket.Connected; } return false; } } /// /// 获取网络服务类型。 /// public abstract ServiceType ServiceType { get; } /// /// 获取网络地址类型。 /// public AddressFamily AddressFamily { get { return m_AddressFamily; } } /// /// 获取要发送的消息包数量。 /// public int SendPacketCount { get { return m_SendPacketPool.Count; } } /// /// 获取累计发送的消息包数量。 /// public int SentPacketCount { get { return m_SentPacketCount; } } /// /// 获取已接收未处理的消息包数量。 /// public int ReceivePacketCount { get { return m_ReceivePacketPool.EventCount; } } /// /// 获取累计已接收的消息包数量。 /// public int ReceivedPacketCount { get { return m_ReceivedPacketCount; } } /// /// 获取或设置当收到消息包时是否重置心跳流逝时间。 /// public bool ResetHeartBeatElapseSecondsWhenReceivePacket { get { return m_ResetHeartBeatElapseSecondsWhenReceivePacket; } set { m_ResetHeartBeatElapseSecondsWhenReceivePacket = value; } } /// /// 获取丢失心跳的次数。 /// public int MissHeartBeatCount { get { return m_HeartBeatState.MissHeartBeatCount; } } /// /// 获取或设置心跳间隔时长,以秒为单位。 /// public float HeartBeatInterval { get { return m_HeartBeatInterval; } set { m_HeartBeatInterval = value; } } /// /// 获取心跳等待时长,以秒为单位。 /// public float HeartBeatElapseSeconds { get { return m_HeartBeatState.HeartBeatElapseSeconds; } } /// /// 网络频道轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public virtual void Update(float elapseSeconds, float realElapseSeconds) { if (m_Socket == null || !m_Active) { return; } ProcessSend(); ProcessReceive(); if (m_Socket == null || !m_Active) { return; } m_ReceivePacketPool.Update(elapseSeconds, realElapseSeconds); if (m_HeartBeatInterval > 0f) { bool sendHeartBeat = false; int missHeartBeatCount = 0; lock (m_HeartBeatState) { if (m_Socket == null || !m_Active) { return; } m_HeartBeatState.HeartBeatElapseSeconds += realElapseSeconds; if (m_HeartBeatState.HeartBeatElapseSeconds >= m_HeartBeatInterval) { sendHeartBeat = true; missHeartBeatCount = m_HeartBeatState.MissHeartBeatCount; m_HeartBeatState.HeartBeatElapseSeconds = 0f; m_HeartBeatState.MissHeartBeatCount++; } } if (sendHeartBeat && m_NetworkChannelHelper.SendHeartBeat()) { if (missHeartBeatCount > 0 && NetworkChannelMissHeartBeat != null) { NetworkChannelMissHeartBeat(this, missHeartBeatCount); } } } } /// /// 关闭网络频道。 /// public virtual void Shutdown() { Close(); m_ReceivePacketPool.Shutdown(); m_NetworkChannelHelper.Shutdown(); } /// /// 注册网络消息包处理函数。 /// /// 要注册的网络消息包处理函数。 public void RegisterHandler(IPacketHandler handler) { if (handler == null) { throw new GameFrameworkException("Packet handler is invalid."); } m_ReceivePacketPool.Subscribe(handler.Id, handler.Handle); } /// /// 设置默认事件处理函数。 /// /// 要设置的默认事件处理函数。 public void SetDefaultHandler(EventHandler handler) { m_ReceivePacketPool.SetDefaultHandler(handler); } /// /// 连接到远程主机。 /// /// 远程主机的 IP 地址。 /// 远程主机的端口号。 public void Connect(IPAddress ipAddress, int port) { Connect(ipAddress, port, null); } /// /// 连接到远程主机。 /// /// 远程主机的 IP 地址。 /// 远程主机的端口号。 /// 用户自定义数据。 public virtual void Connect(IPAddress ipAddress, int port, object userData) { if (m_Socket != null) { Close(); m_Socket = null; } switch (ipAddress.AddressFamily) { case System.Net.Sockets.AddressFamily.InterNetwork: m_AddressFamily = AddressFamily.IPv4; break; case System.Net.Sockets.AddressFamily.InterNetworkV6: m_AddressFamily = AddressFamily.IPv6; break; default: string errorMessage = Utility.Text.Format("Not supported address family '{0}'.", ipAddress.AddressFamily); if (NetworkChannelError != null) { NetworkChannelError(this, NetworkErrorCode.AddressFamilyError, SocketError.Success, errorMessage); return; } throw new GameFrameworkException(errorMessage); } m_SendState.Reset(); m_ReceiveState.PrepareForPacketHeader(m_NetworkChannelHelper.PacketHeaderLength); } /// /// 关闭连接并释放所有相关资源。 /// public void Close() { lock (this) { if (m_Socket == null) { return; } m_Active = false; try { m_Socket.Shutdown(SocketShutdown.Both); } catch { } finally { m_Socket.Close(); m_Socket = null; if (NetworkChannelClosed != null) { NetworkChannelClosed(this); } } m_SentPacketCount = 0; m_ReceivedPacketCount = 0; lock (m_SendPacketPool) { m_SendPacketPool.Clear(); } m_ReceivePacketPool.Clear(); lock (m_HeartBeatState) { m_HeartBeatState.Reset(true); } } } /// /// 向远程主机发送消息包。 /// /// 消息包类型。 /// 要发送的消息包。 public void Send(T packet) where T : Packet { if (m_Socket == null) { string errorMessage = "You must connect first."; if (NetworkChannelError != null) { NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage); return; } throw new GameFrameworkException(errorMessage); } if (!m_Active) { string errorMessage = "Socket is not active."; if (NetworkChannelError != null) { NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage); return; } throw new GameFrameworkException(errorMessage); } if (packet == null) { string errorMessage = "Packet is invalid."; if (NetworkChannelError != null) { NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage); return; } throw new GameFrameworkException(errorMessage); } lock (m_SendPacketPool) { m_SendPacketPool.Enqueue(packet); } } /// /// 释放资源。 /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// 释放资源。 /// /// 释放资源标记。 private void Dispose(bool disposing) { if (m_Disposed) { return; } if (disposing) { Close(); m_SendState.Dispose(); m_ReceiveState.Dispose(); } m_Disposed = true; } protected virtual bool ProcessSend() { if (m_SendState.Stream.Length > 0 || m_SendPacketPool.Count <= 0) { return false; } while (m_SendPacketPool.Count > 0) { Packet packet = null; lock (m_SendPacketPool) { packet = m_SendPacketPool.Dequeue(); } bool serializeResult = false; try { serializeResult = m_NetworkChannelHelper.Serialize(packet, m_SendState.Stream); } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.SerializeError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return false; } throw; } if (!serializeResult) { string errorMessage = "Serialized packet failure."; if (NetworkChannelError != null) { NetworkChannelError(this, NetworkErrorCode.SerializeError, SocketError.Success, errorMessage); return false; } throw new GameFrameworkException(errorMessage); } } m_SendState.Stream.Position = 0L; return true; } protected virtual void ProcessReceive() { } protected virtual bool ProcessPacketHeader() { try { object customErrorData = null; IPacketHeader packetHeader = m_NetworkChannelHelper.DeserializePacketHeader(m_ReceiveState.Stream, out customErrorData); if (customErrorData != null && NetworkChannelCustomError != null) { NetworkChannelCustomError(this, customErrorData); } if (packetHeader == null) { string errorMessage = "Packet header is invalid."; if (NetworkChannelError != null) { NetworkChannelError(this, NetworkErrorCode.DeserializePacketHeaderError, SocketError.Success, errorMessage); return false; } throw new GameFrameworkException(errorMessage); } m_ReceiveState.PrepareForPacket(packetHeader); if (packetHeader.PacketLength <= 0) { bool processSuccess = ProcessPacket(); m_ReceivedPacketCount++; return processSuccess; } } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.DeserializePacketHeaderError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return false; } throw; } return true; } protected virtual bool ProcessPacket() { lock (m_HeartBeatState) { m_HeartBeatState.Reset(m_ResetHeartBeatElapseSecondsWhenReceivePacket); } try { object customErrorData = null; Packet packet = m_NetworkChannelHelper.DeserializePacket(m_ReceiveState.PacketHeader, m_ReceiveState.Stream, out customErrorData); if (customErrorData != null && NetworkChannelCustomError != null) { NetworkChannelCustomError(this, customErrorData); } if (packet != null) { m_ReceivePacketPool.Fire(this, packet); } m_ReceiveState.PrepareForPacketHeader(m_NetworkChannelHelper.PacketHeaderLength); } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.DeserializePacketError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return false; } throw; } return true; } } } } ================================================ FILE: GameFramework/Network/NetworkManager.ReceiveState.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.IO; namespace GameFramework.Network { internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager { private sealed class ReceiveState : IDisposable { private const int DefaultBufferLength = 1024 * 64; private MemoryStream m_Stream; private IPacketHeader m_PacketHeader; private bool m_Disposed; public ReceiveState() { m_Stream = new MemoryStream(DefaultBufferLength); m_PacketHeader = null; m_Disposed = false; } public MemoryStream Stream { get { return m_Stream; } } public IPacketHeader PacketHeader { get { return m_PacketHeader; } } public void PrepareForPacketHeader(int packetHeaderLength) { Reset(packetHeaderLength, null); } public void PrepareForPacket(IPacketHeader packetHeader) { if (packetHeader == null) { throw new GameFrameworkException("Packet header is invalid."); } Reset(packetHeader.PacketLength, packetHeader); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (m_Disposed) { return; } if (disposing) { if (m_Stream != null) { m_Stream.Dispose(); m_Stream = null; } } m_Disposed = true; } private void Reset(int targetLength, IPacketHeader packetHeader) { if (targetLength < 0) { throw new GameFrameworkException("Target length is invalid."); } m_Stream.Position = 0L; m_Stream.SetLength(targetLength); m_PacketHeader = packetHeader; } } } } ================================================ FILE: GameFramework/Network/NetworkManager.SendState.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.IO; namespace GameFramework.Network { internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager { private sealed class SendState : IDisposable { private const int DefaultBufferLength = 1024 * 64; private MemoryStream m_Stream; private bool m_Disposed; public SendState() { m_Stream = new MemoryStream(DefaultBufferLength); m_Disposed = false; } public MemoryStream Stream { get { return m_Stream; } } public void Reset() { m_Stream.Position = 0L; m_Stream.SetLength(0L); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (m_Disposed) { return; } if (disposing) { if (m_Stream != null) { m_Stream.Dispose(); m_Stream = null; } } m_Disposed = true; } } } } ================================================ FILE: GameFramework/Network/NetworkManager.TcpNetworkChannel.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Net; using System.Net.Sockets; namespace GameFramework.Network { internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager { /// /// TCP 网络频道。 /// private sealed class TcpNetworkChannel : NetworkChannelBase { private readonly AsyncCallback m_ConnectCallback; private readonly AsyncCallback m_SendCallback; private readonly AsyncCallback m_ReceiveCallback; /// /// 初始化网络频道的新实例。 /// /// 网络频道名称。 /// 网络频道辅助器。 public TcpNetworkChannel(string name, INetworkChannelHelper networkChannelHelper) : base(name, networkChannelHelper) { m_ConnectCallback = ConnectCallback; m_SendCallback = SendCallback; m_ReceiveCallback = ReceiveCallback; } /// /// 获取网络服务类型。 /// public override ServiceType ServiceType { get { return ServiceType.Tcp; } } /// /// 连接到远程主机。 /// /// 远程主机的 IP 地址。 /// 远程主机的端口号。 /// 用户自定义数据。 public override void Connect(IPAddress ipAddress, int port, object userData) { base.Connect(ipAddress, port, userData); m_Socket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); if (m_Socket == null) { string errorMessage = "Initialize network channel failure."; if (NetworkChannelError != null) { NetworkChannelError(this, NetworkErrorCode.SocketError, SocketError.Success, errorMessage); return; } throw new GameFrameworkException(errorMessage); } m_NetworkChannelHelper.PrepareForConnecting(); ConnectAsync(ipAddress, port, userData); } protected override bool ProcessSend() { if (base.ProcessSend()) { SendAsync(); return true; } return false; } private void ConnectAsync(IPAddress ipAddress, int port, object userData) { try { m_Socket.BeginConnect(ipAddress, port, m_ConnectCallback, new ConnectState(m_Socket, userData)); } catch (Exception exception) { if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return; } throw; } } private void ConnectCallback(IAsyncResult ar) { ConnectState socketUserData = (ConnectState)ar.AsyncState; try { socketUserData.Socket.EndConnect(ar); } catch (ObjectDisposedException) { return; } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return; } throw; } m_SentPacketCount = 0; m_ReceivedPacketCount = 0; lock (m_SendPacketPool) { m_SendPacketPool.Clear(); } m_ReceivePacketPool.Clear(); lock (m_HeartBeatState) { m_HeartBeatState.Reset(true); } if (NetworkChannelConnected != null) { NetworkChannelConnected(this, socketUserData.UserData); } m_Active = true; ReceiveAsync(); } private void SendAsync() { try { m_Socket.BeginSend(m_SendState.Stream.GetBuffer(), (int)m_SendState.Stream.Position, (int)(m_SendState.Stream.Length - m_SendState.Stream.Position), SocketFlags.None, m_SendCallback, m_Socket); } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.SendError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return; } throw; } } private void SendCallback(IAsyncResult ar) { Socket socket = (Socket)ar.AsyncState; if (!socket.Connected) { return; } int bytesSent = 0; try { bytesSent = socket.EndSend(ar); } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.SendError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return; } throw; } m_SendState.Stream.Position += bytesSent; if (m_SendState.Stream.Position < m_SendState.Stream.Length) { SendAsync(); return; } m_SentPacketCount++; m_SendState.Reset(); } private void ReceiveAsync() { try { m_Socket.BeginReceive(m_ReceiveState.Stream.GetBuffer(), (int)m_ReceiveState.Stream.Position, (int)(m_ReceiveState.Stream.Length - m_ReceiveState.Stream.Position), SocketFlags.None, m_ReceiveCallback, m_Socket); } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.ReceiveError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return; } throw; } } private void ReceiveCallback(IAsyncResult ar) { Socket socket = (Socket)ar.AsyncState; if (!socket.Connected) { return; } int bytesReceived = 0; try { bytesReceived = socket.EndReceive(ar); } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.ReceiveError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return; } throw; } if (bytesReceived <= 0) { Close(); return; } m_ReceiveState.Stream.Position += bytesReceived; if (m_ReceiveState.Stream.Position < m_ReceiveState.Stream.Length) { ReceiveAsync(); return; } m_ReceiveState.Stream.Position = 0L; bool processSuccess = false; if (m_ReceiveState.PacketHeader != null) { processSuccess = ProcessPacket(); m_ReceivedPacketCount++; } else { processSuccess = ProcessPacketHeader(); } if (processSuccess) { ReceiveAsync(); return; } } } } } ================================================ FILE: GameFramework/Network/NetworkManager.TcpWithSyncReceiveNetworkChannel.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Net; using System.Net.Sockets; namespace GameFramework.Network { internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager { /// /// 使用同步接收的 TCP 网络频道。 /// private sealed class TcpWithSyncReceiveNetworkChannel : NetworkChannelBase { private readonly AsyncCallback m_ConnectCallback; private readonly AsyncCallback m_SendCallback; /// /// 初始化网络频道的新实例。 /// /// 网络频道名称。 /// 网络频道辅助器。 public TcpWithSyncReceiveNetworkChannel(string name, INetworkChannelHelper networkChannelHelper) : base(name, networkChannelHelper) { m_ConnectCallback = ConnectCallback; m_SendCallback = SendCallback; } /// /// 获取网络服务类型。 /// public override ServiceType ServiceType { get { return ServiceType.TcpWithSyncReceive; } } /// /// 连接到远程主机。 /// /// 远程主机的 IP 地址。 /// 远程主机的端口号。 /// 用户自定义数据。 public override void Connect(IPAddress ipAddress, int port, object userData) { base.Connect(ipAddress, port, userData); m_Socket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); if (m_Socket == null) { string errorMessage = "Initialize network channel failure."; if (NetworkChannelError != null) { NetworkChannelError(this, NetworkErrorCode.SocketError, SocketError.Success, errorMessage); return; } throw new GameFrameworkException(errorMessage); } m_NetworkChannelHelper.PrepareForConnecting(); ConnectAsync(ipAddress, port, userData); } protected override bool ProcessSend() { if (base.ProcessSend()) { SendAsync(); return true; } return false; } protected override void ProcessReceive() { base.ProcessReceive(); while (m_Socket.Available > 0) { if (!ReceiveSync()) { break; } } } private void ConnectAsync(IPAddress ipAddress, int port, object userData) { try { m_Socket.BeginConnect(ipAddress, port, m_ConnectCallback, new ConnectState(m_Socket, userData)); } catch (Exception exception) { if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return; } throw; } } private void ConnectCallback(IAsyncResult ar) { ConnectState socketUserData = (ConnectState)ar.AsyncState; try { socketUserData.Socket.EndConnect(ar); } catch (ObjectDisposedException) { return; } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.ConnectError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return; } throw; } m_SentPacketCount = 0; m_ReceivedPacketCount = 0; lock (m_SendPacketPool) { m_SendPacketPool.Clear(); } m_ReceivePacketPool.Clear(); lock (m_HeartBeatState) { m_HeartBeatState.Reset(true); } if (NetworkChannelConnected != null) { NetworkChannelConnected(this, socketUserData.UserData); } m_Active = true; } private void SendAsync() { try { m_Socket.BeginSend(m_SendState.Stream.GetBuffer(), (int)m_SendState.Stream.Position, (int)(m_SendState.Stream.Length - m_SendState.Stream.Position), SocketFlags.None, m_SendCallback, m_Socket); } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.SendError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return; } throw; } } private void SendCallback(IAsyncResult ar) { Socket socket = (Socket)ar.AsyncState; if (!socket.Connected) { return; } int bytesSent = 0; try { bytesSent = socket.EndSend(ar); } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.SendError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return; } throw; } m_SendState.Stream.Position += bytesSent; if (m_SendState.Stream.Position < m_SendState.Stream.Length) { SendAsync(); return; } m_SentPacketCount++; m_SendState.Reset(); } private bool ReceiveSync() { try { int bytesReceived = m_Socket.Receive(m_ReceiveState.Stream.GetBuffer(), (int)m_ReceiveState.Stream.Position, (int)(m_ReceiveState.Stream.Length - m_ReceiveState.Stream.Position), SocketFlags.None); if (bytesReceived <= 0) { Close(); return false; } m_ReceiveState.Stream.Position += bytesReceived; if (m_ReceiveState.Stream.Position < m_ReceiveState.Stream.Length) { return false; } m_ReceiveState.Stream.Position = 0L; bool processSuccess = false; if (m_ReceiveState.PacketHeader != null) { processSuccess = ProcessPacket(); m_ReceivedPacketCount++; } else { processSuccess = ProcessPacketHeader(); } return processSuccess; } catch (Exception exception) { m_Active = false; if (NetworkChannelError != null) { SocketException socketException = exception as SocketException; NetworkChannelError(this, NetworkErrorCode.ReceiveError, socketException != null ? socketException.SocketErrorCode : SocketError.Success, exception.ToString()); return false; } throw; } } } } } ================================================ FILE: GameFramework/Network/NetworkManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; using System.Net.Sockets; namespace GameFramework.Network { /// /// 网络管理器。 /// internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager { private readonly Dictionary m_NetworkChannels; private EventHandler m_NetworkConnectedEventHandler; private EventHandler m_NetworkClosedEventHandler; private EventHandler m_NetworkMissHeartBeatEventHandler; private EventHandler m_NetworkErrorEventHandler; private EventHandler m_NetworkCustomErrorEventHandler; /// /// 初始化网络管理器的新实例。 /// public NetworkManager() { m_NetworkChannels = new Dictionary(StringComparer.Ordinal); m_NetworkConnectedEventHandler = null; m_NetworkClosedEventHandler = null; m_NetworkMissHeartBeatEventHandler = null; m_NetworkErrorEventHandler = null; m_NetworkCustomErrorEventHandler = null; } /// /// 获取网络频道数量。 /// public int NetworkChannelCount { get { return m_NetworkChannels.Count; } } /// /// 网络连接成功事件。 /// public event EventHandler NetworkConnected { add { m_NetworkConnectedEventHandler += value; } remove { m_NetworkConnectedEventHandler -= value; } } /// /// 网络连接关闭事件。 /// public event EventHandler NetworkClosed { add { m_NetworkClosedEventHandler += value; } remove { m_NetworkClosedEventHandler -= value; } } /// /// 网络心跳包丢失事件。 /// public event EventHandler NetworkMissHeartBeat { add { m_NetworkMissHeartBeatEventHandler += value; } remove { m_NetworkMissHeartBeatEventHandler -= value; } } /// /// 网络错误事件。 /// public event EventHandler NetworkError { add { m_NetworkErrorEventHandler += value; } remove { m_NetworkErrorEventHandler -= value; } } /// /// 用户自定义网络错误事件。 /// public event EventHandler NetworkCustomError { add { m_NetworkCustomErrorEventHandler += value; } remove { m_NetworkCustomErrorEventHandler -= value; } } /// /// 网络管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { foreach (KeyValuePair networkChannel in m_NetworkChannels) { networkChannel.Value.Update(elapseSeconds, realElapseSeconds); } } /// /// 关闭并清理网络管理器。 /// internal override void Shutdown() { foreach (KeyValuePair networkChannel in m_NetworkChannels) { NetworkChannelBase networkChannelBase = networkChannel.Value; networkChannelBase.NetworkChannelConnected -= OnNetworkChannelConnected; networkChannelBase.NetworkChannelClosed -= OnNetworkChannelClosed; networkChannelBase.NetworkChannelMissHeartBeat -= OnNetworkChannelMissHeartBeat; networkChannelBase.NetworkChannelError -= OnNetworkChannelError; networkChannelBase.NetworkChannelCustomError -= OnNetworkChannelCustomError; networkChannelBase.Shutdown(); } m_NetworkChannels.Clear(); } /// /// 检查是否存在网络频道。 /// /// 网络频道名称。 /// 是否存在网络频道。 public bool HasNetworkChannel(string name) { return m_NetworkChannels.ContainsKey(name ?? string.Empty); } /// /// 获取网络频道。 /// /// 网络频道名称。 /// 要获取的网络频道。 public INetworkChannel GetNetworkChannel(string name) { NetworkChannelBase networkChannel = null; if (m_NetworkChannels.TryGetValue(name ?? string.Empty, out networkChannel)) { return networkChannel; } return null; } /// /// 获取所有网络频道。 /// /// 所有网络频道。 public INetworkChannel[] GetAllNetworkChannels() { int index = 0; INetworkChannel[] results = new INetworkChannel[m_NetworkChannels.Count]; foreach (KeyValuePair networkChannel in m_NetworkChannels) { results[index++] = networkChannel.Value; } return results; } /// /// 获取所有网络频道。 /// /// 所有网络频道。 public void GetAllNetworkChannels(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair networkChannel in m_NetworkChannels) { results.Add(networkChannel.Value); } } /// /// 创建网络频道。 /// /// 网络频道名称。 /// 网络服务类型。 /// 网络频道辅助器。 /// 要创建的网络频道。 public INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType, INetworkChannelHelper networkChannelHelper) { if (networkChannelHelper == null) { throw new GameFrameworkException("Network channel helper is invalid."); } if (networkChannelHelper.PacketHeaderLength < 0) { throw new GameFrameworkException("Packet header length is invalid."); } if (HasNetworkChannel(name)) { throw new GameFrameworkException(Utility.Text.Format("Already exist network channel '{0}'.", name ?? string.Empty)); } NetworkChannelBase networkChannel = null; switch (serviceType) { case ServiceType.Tcp: networkChannel = new TcpNetworkChannel(name, networkChannelHelper); break; case ServiceType.TcpWithSyncReceive: networkChannel = new TcpWithSyncReceiveNetworkChannel(name, networkChannelHelper); break; default: throw new GameFrameworkException(Utility.Text.Format("Not supported service type '{0}'.", serviceType)); } networkChannel.NetworkChannelConnected += OnNetworkChannelConnected; networkChannel.NetworkChannelClosed += OnNetworkChannelClosed; networkChannel.NetworkChannelMissHeartBeat += OnNetworkChannelMissHeartBeat; networkChannel.NetworkChannelError += OnNetworkChannelError; networkChannel.NetworkChannelCustomError += OnNetworkChannelCustomError; m_NetworkChannels.Add(name, networkChannel); return networkChannel; } /// /// 销毁网络频道。 /// /// 网络频道名称。 /// 是否销毁网络频道成功。 public bool DestroyNetworkChannel(string name) { NetworkChannelBase networkChannel = null; if (m_NetworkChannels.TryGetValue(name ?? string.Empty, out networkChannel)) { networkChannel.NetworkChannelConnected -= OnNetworkChannelConnected; networkChannel.NetworkChannelClosed -= OnNetworkChannelClosed; networkChannel.NetworkChannelMissHeartBeat -= OnNetworkChannelMissHeartBeat; networkChannel.NetworkChannelError -= OnNetworkChannelError; networkChannel.NetworkChannelCustomError -= OnNetworkChannelCustomError; networkChannel.Shutdown(); return m_NetworkChannels.Remove(name); } return false; } private void OnNetworkChannelConnected(NetworkChannelBase networkChannel, object userData) { if (m_NetworkConnectedEventHandler != null) { lock (m_NetworkConnectedEventHandler) { NetworkConnectedEventArgs networkConnectedEventArgs = NetworkConnectedEventArgs.Create(networkChannel, userData); m_NetworkConnectedEventHandler(this, networkConnectedEventArgs); ReferencePool.Release(networkConnectedEventArgs); } } } private void OnNetworkChannelClosed(NetworkChannelBase networkChannel) { if (m_NetworkClosedEventHandler != null) { lock (m_NetworkClosedEventHandler) { NetworkClosedEventArgs networkClosedEventArgs = NetworkClosedEventArgs.Create(networkChannel); m_NetworkClosedEventHandler(this, networkClosedEventArgs); ReferencePool.Release(networkClosedEventArgs); } } } private void OnNetworkChannelMissHeartBeat(NetworkChannelBase networkChannel, int missHeartBeatCount) { if (m_NetworkMissHeartBeatEventHandler != null) { lock (m_NetworkMissHeartBeatEventHandler) { NetworkMissHeartBeatEventArgs networkMissHeartBeatEventArgs = NetworkMissHeartBeatEventArgs.Create(networkChannel, missHeartBeatCount); m_NetworkMissHeartBeatEventHandler(this, networkMissHeartBeatEventArgs); ReferencePool.Release(networkMissHeartBeatEventArgs); } } } private void OnNetworkChannelError(NetworkChannelBase networkChannel, NetworkErrorCode errorCode, SocketError socketErrorCode, string errorMessage) { if (m_NetworkErrorEventHandler != null) { lock (m_NetworkErrorEventHandler) { NetworkErrorEventArgs networkErrorEventArgs = NetworkErrorEventArgs.Create(networkChannel, errorCode, socketErrorCode, errorMessage); m_NetworkErrorEventHandler(this, networkErrorEventArgs); ReferencePool.Release(networkErrorEventArgs); } } } private void OnNetworkChannelCustomError(NetworkChannelBase networkChannel, object customErrorData) { if (m_NetworkCustomErrorEventHandler != null) { lock (m_NetworkCustomErrorEventHandler) { NetworkCustomErrorEventArgs networkCustomErrorEventArgs = NetworkCustomErrorEventArgs.Create(networkChannel, customErrorData); m_NetworkCustomErrorEventHandler(this, networkCustomErrorEventArgs); ReferencePool.Release(networkCustomErrorEventArgs); } } } } } ================================================ FILE: GameFramework/Network/NetworkMissHeartBeatEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { /// /// 网络心跳包丢失事件。 /// public sealed class NetworkMissHeartBeatEventArgs : GameFrameworkEventArgs { /// /// 初始化网络心跳包丢失事件的新实例。 /// public NetworkMissHeartBeatEventArgs() { NetworkChannel = null; MissCount = 0; } /// /// 获取网络频道。 /// public INetworkChannel NetworkChannel { get; private set; } /// /// 获取心跳包已丢失次数。 /// public int MissCount { get; private set; } /// /// 创建网络心跳包丢失事件。 /// /// 网络频道。 /// 心跳包已丢失次数。 /// 创建的网络心跳包丢失事件。 public static NetworkMissHeartBeatEventArgs Create(INetworkChannel networkChannel, int missCount) { NetworkMissHeartBeatEventArgs networkMissHeartBeatEventArgs = ReferencePool.Acquire(); networkMissHeartBeatEventArgs.NetworkChannel = networkChannel; networkMissHeartBeatEventArgs.MissCount = missCount; return networkMissHeartBeatEventArgs; } /// /// 清理网络心跳包丢失事件。 /// public override void Clear() { NetworkChannel = null; MissCount = 0; } } } ================================================ FILE: GameFramework/Network/Packet.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { /// /// 网络消息包基类。 /// public abstract class Packet : BaseEventArgs { } } ================================================ FILE: GameFramework/Network/ServiceType.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Network { /// /// 网络服务类型。 /// public enum ServiceType : byte { /// /// TCP 网络服务。 /// Tcp = 0, /// /// 使用同步接收的 TCP 网络服务。 /// TcpWithSyncReceive } } ================================================ FILE: GameFramework/ObjectPool/IObjectPool.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.ObjectPool { /// /// 对象池接口。 /// /// 对象类型。 public interface IObjectPool where T : ObjectBase { /// /// 获取对象池名称。 /// string Name { get; } /// /// 获取对象池完整名称。 /// string FullName { get; } /// /// 获取对象池对象类型。 /// Type ObjectType { get; } /// /// 获取对象池中对象的数量。 /// int Count { get; } /// /// 获取对象池中能被释放的对象的数量。 /// int CanReleaseCount { get; } /// /// 获取是否允许对象被多次获取。 /// bool AllowMultiSpawn { get; } /// /// 获取或设置对象池自动释放可释放对象的间隔秒数。 /// float AutoReleaseInterval { get; set; } /// /// 获取或设置对象池的容量。 /// int Capacity { get; set; } /// /// 获取或设置对象池对象过期秒数。 /// float ExpireTime { get; set; } /// /// 获取或设置对象池的优先级。 /// int Priority { get; set; } /// /// 创建对象。 /// /// 对象。 /// 对象是否已被获取。 void Register(T obj, bool spawned); /// /// 检查对象。 /// /// 要检查的对象是否存在。 bool CanSpawn(); /// /// 检查对象。 /// /// 对象名称。 /// 要检查的对象是否存在。 bool CanSpawn(string name); /// /// 获取对象。 /// /// 要获取的对象。 T Spawn(); /// /// 获取对象。 /// /// 对象名称。 /// 要获取的对象。 T Spawn(string name); /// /// 回收对象。 /// /// 要回收的对象。 void Unspawn(T obj); /// /// 回收对象。 /// /// 要回收的对象。 void Unspawn(object target); /// /// 设置对象是否被加锁。 /// /// 要设置被加锁的对象。 /// 是否被加锁。 void SetLocked(T obj, bool locked); /// /// 设置对象是否被加锁。 /// /// 要设置被加锁的对象。 /// 是否被加锁。 void SetLocked(object target, bool locked); /// /// 设置对象的优先级。 /// /// 要设置优先级的对象。 /// 优先级。 void SetPriority(T obj, int priority); /// /// 设置对象的优先级。 /// /// 要设置优先级的对象。 /// 优先级。 void SetPriority(object target, int priority); /// /// 释放对象。 /// /// 要释放的对象。 /// 释放对象是否成功。 bool ReleaseObject(T obj); /// /// 释放对象。 /// /// 要释放的对象。 /// 释放对象是否成功。 bool ReleaseObject(object target); /// /// 释放对象池中的可释放对象。 /// void Release(); /// /// 释放对象池中的可释放对象。 /// /// 尝试释放对象数量。 void Release(int toReleaseCount); /// /// 释放对象池中的可释放对象。 /// /// 释放对象筛选函数。 void Release(ReleaseObjectFilterCallback releaseObjectFilterCallback); /// /// 释放对象池中的可释放对象。 /// /// 尝试释放对象数量。 /// 释放对象筛选函数。 void Release(int toReleaseCount, ReleaseObjectFilterCallback releaseObjectFilterCallback); /// /// 释放对象池中的所有未使用对象。 /// void ReleaseAllUnused(); } } ================================================ FILE: GameFramework/ObjectPool/IObjectPoolManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.ObjectPool { /// /// 对象池管理器。 /// public interface IObjectPoolManager { /// /// 获取对象池数量。 /// int Count { get; } /// /// 检查是否存在对象池。 /// /// 对象类型。 /// 是否存在对象池。 bool HasObjectPool() where T : ObjectBase; /// /// 检查是否存在对象池。 /// /// 对象类型。 /// 是否存在对象池。 bool HasObjectPool(Type objectType); /// /// 检查是否存在对象池。 /// /// 对象类型。 /// 对象池名称。 /// 是否存在对象池。 bool HasObjectPool(string name) where T : ObjectBase; /// /// 检查是否存在对象池。 /// /// 对象类型。 /// 对象池名称。 /// 是否存在对象池。 bool HasObjectPool(Type objectType, string name); /// /// 检查是否存在对象池。 /// /// 要检查的条件。 /// 是否存在对象池。 bool HasObjectPool(Predicate condition); /// /// 获取对象池。 /// /// 对象类型。 /// 要获取的对象池。 IObjectPool GetObjectPool() where T : ObjectBase; /// /// 获取对象池。 /// /// 对象类型。 /// 要获取的对象池。 ObjectPoolBase GetObjectPool(Type objectType); /// /// 获取对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要获取的对象池。 IObjectPool GetObjectPool(string name) where T : ObjectBase; /// /// 获取对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要获取的对象池。 ObjectPoolBase GetObjectPool(Type objectType, string name); /// /// 获取对象池。 /// /// 要检查的条件。 /// 要获取的对象池。 ObjectPoolBase GetObjectPool(Predicate condition); /// /// 获取对象池。 /// /// 要检查的条件。 /// 要获取的对象池。 ObjectPoolBase[] GetObjectPools(Predicate condition); /// /// 获取对象池。 /// /// 要检查的条件。 /// 要获取的对象池。 void GetObjectPools(Predicate condition, List results); /// /// 获取所有对象池。 /// /// 所有对象池。 ObjectPoolBase[] GetAllObjectPools(); /// /// 获取所有对象池。 /// /// 所有对象池。 void GetAllObjectPools(List results); /// /// 获取所有对象池。 /// /// 是否根据对象池的优先级排序。 /// 所有对象池。 ObjectPoolBase[] GetAllObjectPools(bool sort); /// /// 获取所有对象池。 /// /// 是否根据对象池的优先级排序。 /// 所有对象池。 void GetAllObjectPools(bool sort, List results); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool() where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(string name) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(int capacity) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(float expireTime) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(string name, int capacity) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(int capacity, int priority) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, int priority); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(float expireTime, int priority) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime, int priority); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, int priority); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime, int priority); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority); /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池自动释放可释放对象的间隔秒数。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 IObjectPool CreateSingleSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase; /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池自动释放可释放对象的间隔秒数。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool() where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(string name) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(int capacity) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(float expireTime) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(string name, int capacity) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(int capacity, int priority) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, int priority); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(float expireTime, int priority) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime, int priority); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, int priority); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime, int priority); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority); /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池自动释放可释放对象的间隔秒数。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 IObjectPool CreateMultiSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase; /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池自动释放可释放对象的间隔秒数。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority); /// /// 销毁对象池。 /// /// 对象类型。 /// 是否销毁对象池成功。 bool DestroyObjectPool() where T : ObjectBase; /// /// 销毁对象池。 /// /// 对象类型。 /// 是否销毁对象池成功。 bool DestroyObjectPool(Type objectType); /// /// 销毁对象池。 /// /// 对象类型。 /// 要销毁的对象池名称。 /// 是否销毁对象池成功。 bool DestroyObjectPool(string name) where T : ObjectBase; /// /// 销毁对象池。 /// /// 对象类型。 /// 要销毁的对象池名称。 /// 是否销毁对象池成功。 bool DestroyObjectPool(Type objectType, string name); /// /// 销毁对象池。 /// /// 对象类型。 /// 要销毁的对象池。 /// 是否销毁对象池成功。 bool DestroyObjectPool(IObjectPool objectPool) where T : ObjectBase; /// /// 销毁对象池。 /// /// 要销毁的对象池。 /// 是否销毁对象池成功。 bool DestroyObjectPool(ObjectPoolBase objectPool); /// /// 释放对象池中的可释放对象。 /// void Release(); /// /// 释放对象池中的所有未使用对象。 /// void ReleaseAllUnused(); } } ================================================ FILE: GameFramework/ObjectPool/ObjectBase.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.ObjectPool { /// /// 对象基类。 /// public abstract class ObjectBase : IReference { private string m_Name; private object m_Target; private bool m_Locked; private int m_Priority; private DateTime m_LastUseTime; /// /// 初始化对象基类的新实例。 /// public ObjectBase() { m_Name = null; m_Target = null; m_Locked = false; m_Priority = 0; m_LastUseTime = default(DateTime); } /// /// 获取对象名称。 /// public string Name { get { return m_Name; } } /// /// 获取对象。 /// public object Target { get { return m_Target; } } /// /// 获取或设置对象是否被加锁。 /// public bool Locked { get { return m_Locked; } set { m_Locked = value; } } /// /// 获取或设置对象的优先级。 /// public int Priority { get { return m_Priority; } set { m_Priority = value; } } /// /// 获取自定义释放检查标记。 /// public virtual bool CustomCanReleaseFlag { get { return true; } } /// /// 获取对象上次使用时间。 /// public DateTime LastUseTime { get { return m_LastUseTime; } internal set { m_LastUseTime = value; } } /// /// 初始化对象基类。 /// /// 对象。 protected void Initialize(object target) { Initialize(null, target, false, 0); } /// /// 初始化对象基类。 /// /// 对象名称。 /// 对象。 protected void Initialize(string name, object target) { Initialize(name, target, false, 0); } /// /// 初始化对象基类。 /// /// 对象名称。 /// 对象。 /// 对象是否被加锁。 protected void Initialize(string name, object target, bool locked) { Initialize(name, target, locked, 0); } /// /// 初始化对象基类。 /// /// 对象名称。 /// 对象。 /// 对象的优先级。 protected void Initialize(string name, object target, int priority) { Initialize(name, target, false, priority); } /// /// 初始化对象基类。 /// /// 对象名称。 /// 对象。 /// 对象是否被加锁。 /// 对象的优先级。 protected void Initialize(string name, object target, bool locked, int priority) { if (target == null) { throw new GameFrameworkException(Utility.Text.Format("Target '{0}' is invalid.", name)); } m_Name = name ?? string.Empty; m_Target = target; m_Locked = locked; m_Priority = priority; m_LastUseTime = DateTime.UtcNow; } /// /// 清理对象基类。 /// public virtual void Clear() { m_Name = null; m_Target = null; m_Locked = false; m_Priority = 0; m_LastUseTime = default(DateTime); } /// /// 获取对象时的事件。 /// protected internal virtual void OnSpawn() { } /// /// 回收对象时的事件。 /// protected internal virtual void OnUnspawn() { } /// /// 释放对象。 /// /// 是否是关闭对象池时触发。 protected internal abstract void Release(bool isShutdown); } } ================================================ FILE: GameFramework/ObjectPool/ObjectInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Runtime.InteropServices; namespace GameFramework.ObjectPool { /// /// 对象信息。 /// [StructLayout(LayoutKind.Auto)] public struct ObjectInfo { private readonly string m_Name; private readonly bool m_Locked; private readonly bool m_CustomCanReleaseFlag; private readonly int m_Priority; private readonly DateTime m_LastUseTime; private readonly int m_SpawnCount; /// /// 初始化对象信息的新实例。 /// /// 对象名称。 /// 对象是否被加锁。 /// 对象自定义释放检查标记。 /// 对象的优先级。 /// 对象上次使用时间。 /// 对象的获取计数。 public ObjectInfo(string name, bool locked, bool customCanReleaseFlag, int priority, DateTime lastUseTime, int spawnCount) { m_Name = name; m_Locked = locked; m_CustomCanReleaseFlag = customCanReleaseFlag; m_Priority = priority; m_LastUseTime = lastUseTime; m_SpawnCount = spawnCount; } /// /// 获取对象名称。 /// public string Name { get { return m_Name; } } /// /// 获取对象是否被加锁。 /// public bool Locked { get { return m_Locked; } } /// /// 获取对象自定义释放检查标记。 /// public bool CustomCanReleaseFlag { get { return m_CustomCanReleaseFlag; } } /// /// 获取对象的优先级。 /// public int Priority { get { return m_Priority; } } /// /// 获取对象上次使用时间。 /// public DateTime LastUseTime { get { return m_LastUseTime; } } /// /// 获取对象是否正在使用。 /// public bool IsInUse { get { return m_SpawnCount > 0; } } /// /// 获取对象的获取计数。 /// public int SpawnCount { get { return m_SpawnCount; } } } } ================================================ FILE: GameFramework/ObjectPool/ObjectPoolBase.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.ObjectPool { /// /// 对象池基类。 /// public abstract class ObjectPoolBase { private readonly string m_Name; /// /// 初始化对象池基类的新实例。 /// public ObjectPoolBase() : this(null) { } /// /// 初始化对象池基类的新实例。 /// /// 对象池名称。 public ObjectPoolBase(string name) { m_Name = name ?? string.Empty; } /// /// 获取对象池名称。 /// public string Name { get { return m_Name; } } /// /// 获取对象池完整名称。 /// public string FullName { get { return new TypeNamePair(ObjectType, m_Name).ToString(); } } /// /// 获取对象池对象类型。 /// public abstract Type ObjectType { get; } /// /// 获取对象池中对象的数量。 /// public abstract int Count { get; } /// /// 获取对象池中能被释放的对象的数量。 /// public abstract int CanReleaseCount { get; } /// /// 获取是否允许对象被多次获取。 /// public abstract bool AllowMultiSpawn { get; } /// /// 获取或设置对象池自动释放可释放对象的间隔秒数。 /// public abstract float AutoReleaseInterval { get; set; } /// /// 获取或设置对象池的容量。 /// public abstract int Capacity { get; set; } /// /// 获取或设置对象池对象过期秒数。 /// public abstract float ExpireTime { get; set; } /// /// 获取或设置对象池的优先级。 /// public abstract int Priority { get; set; } /// /// 释放对象池中的可释放对象。 /// public abstract void Release(); /// /// 释放对象池中的可释放对象。 /// /// 尝试释放对象数量。 public abstract void Release(int toReleaseCount); /// /// 释放对象池中的所有未使用对象。 /// public abstract void ReleaseAllUnused(); /// /// 获取所有对象信息。 /// /// 所有对象信息。 public abstract ObjectInfo[] GetAllObjectInfos(); internal abstract void Update(float elapseSeconds, float realElapseSeconds); internal abstract void Shutdown(); } } ================================================ FILE: GameFramework/ObjectPool/ObjectPoolManager.Object.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.ObjectPool { internal sealed partial class ObjectPoolManager : GameFrameworkModule, IObjectPoolManager { /// /// 内部对象。 /// /// 对象类型。 private sealed class Object : IReference where T : ObjectBase { private T m_Object; private int m_SpawnCount; /// /// 初始化内部对象的新实例。 /// public Object() { m_Object = null; m_SpawnCount = 0; } /// /// 获取对象名称。 /// public string Name { get { return m_Object.Name; } } /// /// 获取对象是否被加锁。 /// public bool Locked { get { return m_Object.Locked; } internal set { m_Object.Locked = value; } } /// /// 获取对象的优先级。 /// public int Priority { get { return m_Object.Priority; } internal set { m_Object.Priority = value; } } /// /// 获取自定义释放检查标记。 /// public bool CustomCanReleaseFlag { get { return m_Object.CustomCanReleaseFlag; } } /// /// 获取对象上次使用时间。 /// public DateTime LastUseTime { get { return m_Object.LastUseTime; } } /// /// 获取对象是否正在使用。 /// public bool IsInUse { get { return m_SpawnCount > 0; } } /// /// 获取对象的获取计数。 /// public int SpawnCount { get { return m_SpawnCount; } } /// /// 创建内部对象。 /// /// 对象。 /// 对象是否已被获取。 /// 创建的内部对象。 public static Object Create(T obj, bool spawned) { if (obj == null) { throw new GameFrameworkException("Object is invalid."); } Object internalObject = ReferencePool.Acquire>(); internalObject.m_Object = obj; internalObject.m_SpawnCount = spawned ? 1 : 0; if (spawned) { obj.OnSpawn(); } return internalObject; } /// /// 清理内部对象。 /// public void Clear() { m_Object = null; m_SpawnCount = 0; } /// /// 查看对象。 /// /// 对象。 public T Peek() { return m_Object; } /// /// 获取对象。 /// /// 对象。 public T Spawn() { m_SpawnCount++; m_Object.LastUseTime = DateTime.UtcNow; m_Object.OnSpawn(); return m_Object; } /// /// 回收对象。 /// public void Unspawn() { m_Object.OnUnspawn(); m_Object.LastUseTime = DateTime.UtcNow; m_SpawnCount--; if (m_SpawnCount < 0) { throw new GameFrameworkException(Utility.Text.Format("Object '{0}' spawn count is less than 0.", Name)); } } /// /// 释放对象。 /// /// 是否是关闭对象池时触发。 public void Release(bool isShutdown) { m_Object.Release(isShutdown); ReferencePool.Release(m_Object); } } } } ================================================ FILE: GameFramework/ObjectPool/ObjectPoolManager.ObjectPool.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.ObjectPool { internal sealed partial class ObjectPoolManager : GameFrameworkModule, IObjectPoolManager { /// /// 对象池。 /// /// 对象类型。 private sealed class ObjectPool : ObjectPoolBase, IObjectPool where T : ObjectBase { private readonly GameFrameworkMultiDictionary> m_Objects; private readonly Dictionary> m_ObjectMap; private readonly ReleaseObjectFilterCallback m_DefaultReleaseObjectFilterCallback; private readonly List m_CachedCanReleaseObjects; private readonly List m_CachedToReleaseObjects; private readonly bool m_AllowMultiSpawn; private float m_AutoReleaseInterval; private int m_Capacity; private float m_ExpireTime; private int m_Priority; private float m_AutoReleaseTime; /// /// 初始化对象池的新实例。 /// /// 对象池名称。 /// 是否允许对象被多次获取。 /// 对象池自动释放可释放对象的间隔秒数。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 public ObjectPool(string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, float expireTime, int priority) : base(name) { m_Objects = new GameFrameworkMultiDictionary>(); m_ObjectMap = new Dictionary>(); m_DefaultReleaseObjectFilterCallback = DefaultReleaseObjectFilterCallback; m_CachedCanReleaseObjects = new List(); m_CachedToReleaseObjects = new List(); m_AllowMultiSpawn = allowMultiSpawn; m_AutoReleaseInterval = autoReleaseInterval; Capacity = capacity; ExpireTime = expireTime; m_Priority = priority; m_AutoReleaseTime = 0f; } /// /// 获取对象池对象类型。 /// public override Type ObjectType { get { return typeof(T); } } /// /// 获取对象池中对象的数量。 /// public override int Count { get { return m_ObjectMap.Count; } } /// /// 获取对象池中能被释放的对象的数量。 /// public override int CanReleaseCount { get { GetCanReleaseObjects(m_CachedCanReleaseObjects); return m_CachedCanReleaseObjects.Count; } } /// /// 获取是否允许对象被多次获取。 /// public override bool AllowMultiSpawn { get { return m_AllowMultiSpawn; } } /// /// 获取或设置对象池自动释放可释放对象的间隔秒数。 /// public override float AutoReleaseInterval { get { return m_AutoReleaseInterval; } set { m_AutoReleaseInterval = value; } } /// /// 获取或设置对象池的容量。 /// public override int Capacity { get { return m_Capacity; } set { if (value < 0) { throw new GameFrameworkException("Capacity is invalid."); } if (m_Capacity == value) { return; } m_Capacity = value; Release(); } } /// /// 获取或设置对象池对象过期秒数。 /// public override float ExpireTime { get { return m_ExpireTime; } set { if (value < 0f) { throw new GameFrameworkException("ExpireTime is invalid."); } if (ExpireTime == value) { return; } m_ExpireTime = value; Release(); } } /// /// 获取或设置对象池的优先级。 /// public override int Priority { get { return m_Priority; } set { m_Priority = value; } } /// /// 创建对象。 /// /// 对象。 /// 对象是否已被获取。 public void Register(T obj, bool spawned) { if (obj == null) { throw new GameFrameworkException("Object is invalid."); } Object internalObject = Object.Create(obj, spawned); m_Objects.Add(obj.Name, internalObject); m_ObjectMap.Add(obj.Target, internalObject); if (Count > m_Capacity) { Release(); } } /// /// 检查对象。 /// /// 要检查的对象是否存在。 public bool CanSpawn() { return CanSpawn(string.Empty); } /// /// 检查对象。 /// /// 对象名称。 /// 要检查的对象是否存在。 public bool CanSpawn(string name) { if (name == null) { throw new GameFrameworkException("Name is invalid."); } GameFrameworkLinkedListRange> objectRange = default(GameFrameworkLinkedListRange>); if (m_Objects.TryGetValue(name, out objectRange)) { foreach (Object internalObject in objectRange) { if (m_AllowMultiSpawn || !internalObject.IsInUse) { return true; } } } return false; } /// /// 获取对象。 /// /// 要获取的对象。 public T Spawn() { return Spawn(string.Empty); } /// /// 获取对象。 /// /// 对象名称。 /// 要获取的对象。 public T Spawn(string name) { if (name == null) { throw new GameFrameworkException("Name is invalid."); } GameFrameworkLinkedListRange> objectRange = default(GameFrameworkLinkedListRange>); if (m_Objects.TryGetValue(name, out objectRange)) { foreach (Object internalObject in objectRange) { if (m_AllowMultiSpawn || !internalObject.IsInUse) { return internalObject.Spawn(); } } } return null; } /// /// 回收对象。 /// /// 要回收的对象。 public void Unspawn(T obj) { if (obj == null) { throw new GameFrameworkException("Object is invalid."); } Unspawn(obj.Target); } /// /// 回收对象。 /// /// 要回收的对象。 public void Unspawn(object target) { if (target == null) { throw new GameFrameworkException("Target is invalid."); } Object internalObject = GetObject(target); if (internalObject != null) { internalObject.Unspawn(); if (Count > m_Capacity && internalObject.SpawnCount <= 0) { Release(); } } else { throw new GameFrameworkException(Utility.Text.Format("Can not find target in object pool '{0}', target type is '{1}', target value is '{2}'.", new TypeNamePair(typeof(T), Name), target.GetType().FullName, target)); } } /// /// 设置对象是否被加锁。 /// /// 要设置被加锁的对象。 /// 是否被加锁。 public void SetLocked(T obj, bool locked) { if (obj == null) { throw new GameFrameworkException("Object is invalid."); } SetLocked(obj.Target, locked); } /// /// 设置对象是否被加锁。 /// /// 要设置被加锁的对象。 /// 是否被加锁。 public void SetLocked(object target, bool locked) { if (target == null) { throw new GameFrameworkException("Target is invalid."); } Object internalObject = GetObject(target); if (internalObject != null) { internalObject.Locked = locked; } else { throw new GameFrameworkException(Utility.Text.Format("Can not find target in object pool '{0}', target type is '{1}', target value is '{2}'.", new TypeNamePair(typeof(T), Name), target.GetType().FullName, target)); } } /// /// 设置对象的优先级。 /// /// 要设置优先级的对象。 /// 优先级。 public void SetPriority(T obj, int priority) { if (obj == null) { throw new GameFrameworkException("Object is invalid."); } SetPriority(obj.Target, priority); } /// /// 设置对象的优先级。 /// /// 要设置优先级的对象。 /// 优先级。 public void SetPriority(object target, int priority) { if (target == null) { throw new GameFrameworkException("Target is invalid."); } Object internalObject = GetObject(target); if (internalObject != null) { internalObject.Priority = priority; } else { throw new GameFrameworkException(Utility.Text.Format("Can not find target in object pool '{0}', target type is '{1}', target value is '{2}'.", new TypeNamePair(typeof(T), Name), target.GetType().FullName, target)); } } /// /// 释放对象。 /// /// 要释放的对象。 /// 释放对象是否成功。 public bool ReleaseObject(T obj) { if (obj == null) { throw new GameFrameworkException("Object is invalid."); } return ReleaseObject(obj.Target); } /// /// 释放对象。 /// /// 要释放的对象。 /// 释放对象是否成功。 public bool ReleaseObject(object target) { if (target == null) { throw new GameFrameworkException("Target is invalid."); } Object internalObject = GetObject(target); if (internalObject == null) { return false; } if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag) { return false; } m_Objects.Remove(internalObject.Name, internalObject); m_ObjectMap.Remove(internalObject.Peek().Target); internalObject.Release(false); ReferencePool.Release(internalObject); return true; } /// /// 释放对象池中的可释放对象。 /// public override void Release() { Release(Count - m_Capacity, m_DefaultReleaseObjectFilterCallback); } /// /// 释放对象池中的可释放对象。 /// /// 尝试释放对象数量。 public override void Release(int toReleaseCount) { Release(toReleaseCount, m_DefaultReleaseObjectFilterCallback); } /// /// 释放对象池中的可释放对象。 /// /// 释放对象筛选函数。 public void Release(ReleaseObjectFilterCallback releaseObjectFilterCallback) { Release(Count - m_Capacity, releaseObjectFilterCallback); } /// /// 释放对象池中的可释放对象。 /// /// 尝试释放对象数量。 /// 释放对象筛选函数。 public void Release(int toReleaseCount, ReleaseObjectFilterCallback releaseObjectFilterCallback) { if (releaseObjectFilterCallback == null) { throw new GameFrameworkException("Release object filter callback is invalid."); } if (toReleaseCount < 0) { toReleaseCount = 0; } DateTime expireTime = DateTime.MinValue; if (m_ExpireTime < float.MaxValue) { expireTime = DateTime.UtcNow.AddSeconds(-m_ExpireTime); } m_AutoReleaseTime = 0f; GetCanReleaseObjects(m_CachedCanReleaseObjects); List toReleaseObjects = releaseObjectFilterCallback(m_CachedCanReleaseObjects, toReleaseCount, expireTime); if (toReleaseObjects == null || toReleaseObjects.Count <= 0) { return; } foreach (T toReleaseObject in toReleaseObjects) { ReleaseObject(toReleaseObject); } } /// /// 释放对象池中的所有未使用对象。 /// public override void ReleaseAllUnused() { m_AutoReleaseTime = 0f; GetCanReleaseObjects(m_CachedCanReleaseObjects); foreach (T toReleaseObject in m_CachedCanReleaseObjects) { ReleaseObject(toReleaseObject); } } /// /// 获取所有对象信息。 /// /// 所有对象信息。 public override ObjectInfo[] GetAllObjectInfos() { List results = new List(); foreach (KeyValuePair>> objectRanges in m_Objects) { foreach (Object internalObject in objectRanges.Value) { results.Add(new ObjectInfo(internalObject.Name, internalObject.Locked, internalObject.CustomCanReleaseFlag, internalObject.Priority, internalObject.LastUseTime, internalObject.SpawnCount)); } } return results.ToArray(); } internal override void Update(float elapseSeconds, float realElapseSeconds) { m_AutoReleaseTime += realElapseSeconds; if (m_AutoReleaseTime < m_AutoReleaseInterval) { return; } Release(); } internal override void Shutdown() { foreach (KeyValuePair> objectInMap in m_ObjectMap) { objectInMap.Value.Release(true); ReferencePool.Release(objectInMap.Value); } m_Objects.Clear(); m_ObjectMap.Clear(); m_CachedCanReleaseObjects.Clear(); m_CachedToReleaseObjects.Clear(); } private Object GetObject(object target) { if (target == null) { throw new GameFrameworkException("Target is invalid."); } Object internalObject = null; if (m_ObjectMap.TryGetValue(target, out internalObject)) { return internalObject; } return null; } private void GetCanReleaseObjects(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair> objectInMap in m_ObjectMap) { Object internalObject = objectInMap.Value; if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag) { continue; } results.Add(internalObject.Peek()); } } private List DefaultReleaseObjectFilterCallback(List candidateObjects, int toReleaseCount, DateTime expireTime) { m_CachedToReleaseObjects.Clear(); if (expireTime > DateTime.MinValue) { for (int i = candidateObjects.Count - 1; i >= 0; i--) { if (candidateObjects[i].LastUseTime <= expireTime) { m_CachedToReleaseObjects.Add(candidateObjects[i]); candidateObjects.RemoveAt(i); continue; } } toReleaseCount -= m_CachedToReleaseObjects.Count; } for (int i = 0; toReleaseCount > 0 && i < candidateObjects.Count; i++) { for (int j = i + 1; j < candidateObjects.Count; j++) { if (candidateObjects[i].Priority > candidateObjects[j].Priority || candidateObjects[i].Priority == candidateObjects[j].Priority && candidateObjects[i].LastUseTime > candidateObjects[j].LastUseTime) { T temp = candidateObjects[i]; candidateObjects[i] = candidateObjects[j]; candidateObjects[j] = temp; } } m_CachedToReleaseObjects.Add(candidateObjects[i]); toReleaseCount--; } return m_CachedToReleaseObjects; } } } } ================================================ FILE: GameFramework/ObjectPool/ObjectPoolManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.ObjectPool { /// /// 对象池管理器。 /// internal sealed partial class ObjectPoolManager : GameFrameworkModule, IObjectPoolManager { private const int DefaultCapacity = int.MaxValue; private const float DefaultExpireTime = float.MaxValue; private const int DefaultPriority = 0; private readonly Dictionary m_ObjectPools; private readonly List m_CachedAllObjectPools; private readonly Comparison m_ObjectPoolComparer; /// /// 初始化对象池管理器的新实例。 /// public ObjectPoolManager() { m_ObjectPools = new Dictionary(); m_CachedAllObjectPools = new List(); m_ObjectPoolComparer = ObjectPoolComparer; } /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal override int Priority { get { return 6; } } /// /// 获取对象池数量。 /// public int Count { get { return m_ObjectPools.Count; } } /// /// 对象池管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { foreach (KeyValuePair objectPool in m_ObjectPools) { objectPool.Value.Update(elapseSeconds, realElapseSeconds); } } /// /// 关闭并清理对象池管理器。 /// internal override void Shutdown() { foreach (KeyValuePair objectPool in m_ObjectPools) { objectPool.Value.Shutdown(); } m_ObjectPools.Clear(); m_CachedAllObjectPools.Clear(); } /// /// 检查是否存在对象池。 /// /// 对象类型。 /// 是否存在对象池。 public bool HasObjectPool() where T : ObjectBase { return InternalHasObjectPool(new TypeNamePair(typeof(T))); } /// /// 检查是否存在对象池。 /// /// 对象类型。 /// 是否存在对象池。 public bool HasObjectPool(Type objectType) { if (objectType == null) { throw new GameFrameworkException("Object type is invalid."); } if (!typeof(ObjectBase).IsAssignableFrom(objectType)) { throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); } return InternalHasObjectPool(new TypeNamePair(objectType)); } /// /// 检查是否存在对象池。 /// /// 对象类型。 /// 对象池名称。 /// 是否存在对象池。 public bool HasObjectPool(string name) where T : ObjectBase { return InternalHasObjectPool(new TypeNamePair(typeof(T), name)); } /// /// 检查是否存在对象池。 /// /// 对象类型。 /// 对象池名称。 /// 是否存在对象池。 public bool HasObjectPool(Type objectType, string name) { if (objectType == null) { throw new GameFrameworkException("Object type is invalid."); } if (!typeof(ObjectBase).IsAssignableFrom(objectType)) { throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); } return InternalHasObjectPool(new TypeNamePair(objectType, name)); } /// /// 检查是否存在对象池。 /// /// 要检查的条件。 /// 是否存在对象池。 public bool HasObjectPool(Predicate condition) { if (condition == null) { throw new GameFrameworkException("Condition is invalid."); } foreach (KeyValuePair objectPool in m_ObjectPools) { if (condition(objectPool.Value)) { return true; } } return false; } /// /// 获取对象池。 /// /// 对象类型。 /// 要获取的对象池。 public IObjectPool GetObjectPool() where T : ObjectBase { return (IObjectPool)InternalGetObjectPool(new TypeNamePair(typeof(T))); } /// /// 获取对象池。 /// /// 对象类型。 /// 要获取的对象池。 public ObjectPoolBase GetObjectPool(Type objectType) { if (objectType == null) { throw new GameFrameworkException("Object type is invalid."); } if (!typeof(ObjectBase).IsAssignableFrom(objectType)) { throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); } return InternalGetObjectPool(new TypeNamePair(objectType)); } /// /// 获取对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要获取的对象池。 public IObjectPool GetObjectPool(string name) where T : ObjectBase { return (IObjectPool)InternalGetObjectPool(new TypeNamePair(typeof(T), name)); } /// /// 获取对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要获取的对象池。 public ObjectPoolBase GetObjectPool(Type objectType, string name) { if (objectType == null) { throw new GameFrameworkException("Object type is invalid."); } if (!typeof(ObjectBase).IsAssignableFrom(objectType)) { throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); } return InternalGetObjectPool(new TypeNamePair(objectType, name)); } /// /// 获取对象池。 /// /// 要检查的条件。 /// 要获取的对象池。 public ObjectPoolBase GetObjectPool(Predicate condition) { if (condition == null) { throw new GameFrameworkException("Condition is invalid."); } foreach (KeyValuePair objectPool in m_ObjectPools) { if (condition(objectPool.Value)) { return objectPool.Value; } } return null; } /// /// 获取对象池。 /// /// 要检查的条件。 /// 要获取的对象池。 public ObjectPoolBase[] GetObjectPools(Predicate condition) { if (condition == null) { throw new GameFrameworkException("Condition is invalid."); } List results = new List(); foreach (KeyValuePair objectPool in m_ObjectPools) { if (condition(objectPool.Value)) { results.Add(objectPool.Value); } } return results.ToArray(); } /// /// 获取对象池。 /// /// 要检查的条件。 /// 要获取的对象池。 public void GetObjectPools(Predicate condition, List results) { if (condition == null) { throw new GameFrameworkException("Condition is invalid."); } if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair objectPool in m_ObjectPools) { if (condition(objectPool.Value)) { results.Add(objectPool.Value); } } } /// /// 获取所有对象池。 /// /// 所有对象池。 public ObjectPoolBase[] GetAllObjectPools() { return GetAllObjectPools(false); } /// /// 获取所有对象池。 /// /// 所有对象池。 public void GetAllObjectPools(List results) { GetAllObjectPools(false, results); } /// /// 获取所有对象池。 /// /// 是否根据对象池的优先级排序。 /// 所有对象池。 public ObjectPoolBase[] GetAllObjectPools(bool sort) { if (sort) { List results = new List(); foreach (KeyValuePair objectPool in m_ObjectPools) { results.Add(objectPool.Value); } results.Sort(m_ObjectPoolComparer); return results.ToArray(); } else { int index = 0; ObjectPoolBase[] results = new ObjectPoolBase[m_ObjectPools.Count]; foreach (KeyValuePair objectPool in m_ObjectPools) { results[index++] = objectPool.Value; } return results; } } /// /// 获取所有对象池。 /// /// 是否根据对象池的优先级排序。 /// 所有对象池。 public void GetAllObjectPools(bool sort, List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair objectPool in m_ObjectPools) { results.Add(objectPool.Value); } if (sort) { results.Sort(m_ObjectPoolComparer); } } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool() where T : ObjectBase { return InternalCreateObjectPool(string.Empty, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType) { return InternalCreateObjectPool(objectType, string.Empty, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(string name) where T : ObjectBase { return InternalCreateObjectPool(name, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name) { return InternalCreateObjectPool(objectType, name, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(int capacity) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity) { return InternalCreateObjectPool(objectType, string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(float expireTime) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime) { return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity) where T : ObjectBase { return InternalCreateObjectPool(name, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity) { return InternalCreateObjectPool(objectType, name, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime) where T : ObjectBase { return InternalCreateObjectPool(name, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime) { return InternalCreateObjectPool(objectType, name, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, false, expireTime, capacity, expireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime) { return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, capacity, expireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(int capacity, int priority) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, int priority) { return InternalCreateObjectPool(objectType, string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(float expireTime, int priority) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, false, expireTime, DefaultCapacity, expireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime, int priority) { return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, DefaultCapacity, expireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase { return InternalCreateObjectPool(name, false, expireTime, capacity, expireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime) { return InternalCreateObjectPool(objectType, name, false, expireTime, capacity, expireTime, DefaultPriority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase { return InternalCreateObjectPool(name, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, int priority) { return InternalCreateObjectPool(objectType, name, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase { return InternalCreateObjectPool(name, false, expireTime, DefaultCapacity, expireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime, int priority) { return InternalCreateObjectPool(objectType, name, false, expireTime, DefaultCapacity, expireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, false, expireTime, capacity, expireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority) { return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, capacity, expireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase { return InternalCreateObjectPool(name, false, expireTime, capacity, expireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority) { return InternalCreateObjectPool(objectType, name, false, expireTime, capacity, expireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池自动释放可释放对象的间隔秒数。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public IObjectPool CreateSingleSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase { return InternalCreateObjectPool(name, false, autoReleaseInterval, capacity, expireTime, priority); } /// /// 创建允许单次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池自动释放可释放对象的间隔秒数。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许单次获取的对象池。 public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority) { return InternalCreateObjectPool(objectType, name, false, autoReleaseInterval, capacity, expireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool() where T : ObjectBase { return InternalCreateObjectPool(string.Empty, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType) { return InternalCreateObjectPool(objectType, string.Empty, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(string name) where T : ObjectBase { return InternalCreateObjectPool(name, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name) { return InternalCreateObjectPool(objectType, name, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(int capacity) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity) { return InternalCreateObjectPool(objectType, string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(float expireTime) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime) { return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity) where T : ObjectBase { return InternalCreateObjectPool(name, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity) { return InternalCreateObjectPool(objectType, name, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime) where T : ObjectBase { return InternalCreateObjectPool(name, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime) { return InternalCreateObjectPool(objectType, name, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, true, expireTime, capacity, expireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime) { return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, capacity, expireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(int capacity, int priority) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, int priority) { return InternalCreateObjectPool(objectType, string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(float expireTime, int priority) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, true, expireTime, DefaultCapacity, expireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime, int priority) { return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, DefaultCapacity, expireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase { return InternalCreateObjectPool(name, true, expireTime, capacity, expireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime) { return InternalCreateObjectPool(objectType, name, true, expireTime, capacity, expireTime, DefaultPriority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase { return InternalCreateObjectPool(name, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, int priority) { return InternalCreateObjectPool(objectType, name, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase { return InternalCreateObjectPool(name, true, expireTime, DefaultCapacity, expireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime, int priority) { return InternalCreateObjectPool(objectType, name, true, expireTime, DefaultCapacity, expireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase { return InternalCreateObjectPool(string.Empty, true, expireTime, capacity, expireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority) { return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, capacity, expireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase { return InternalCreateObjectPool(name, true, expireTime, capacity, expireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority) { return InternalCreateObjectPool(objectType, name, true, expireTime, capacity, expireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池自动释放可释放对象的间隔秒数。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public IObjectPool CreateMultiSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase { return InternalCreateObjectPool(name, true, autoReleaseInterval, capacity, expireTime, priority); } /// /// 创建允许多次获取的对象池。 /// /// 对象类型。 /// 对象池名称。 /// 对象池自动释放可释放对象的间隔秒数。 /// 对象池的容量。 /// 对象池对象过期秒数。 /// 对象池的优先级。 /// 要创建的允许多次获取的对象池。 public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority) { return InternalCreateObjectPool(objectType, name, true, autoReleaseInterval, capacity, expireTime, priority); } /// /// 销毁对象池。 /// /// 对象类型。 /// 是否销毁对象池成功。 public bool DestroyObjectPool() where T : ObjectBase { return InternalDestroyObjectPool(new TypeNamePair(typeof(T))); } /// /// 销毁对象池。 /// /// 对象类型。 /// 是否销毁对象池成功。 public bool DestroyObjectPool(Type objectType) { if (objectType == null) { throw new GameFrameworkException("Object type is invalid."); } if (!typeof(ObjectBase).IsAssignableFrom(objectType)) { throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); } return InternalDestroyObjectPool(new TypeNamePair(objectType)); } /// /// 销毁对象池。 /// /// 对象类型。 /// 要销毁的对象池名称。 /// 是否销毁对象池成功。 public bool DestroyObjectPool(string name) where T : ObjectBase { return InternalDestroyObjectPool(new TypeNamePair(typeof(T), name)); } /// /// 销毁对象池。 /// /// 对象类型。 /// 要销毁的对象池名称。 /// 是否销毁对象池成功。 public bool DestroyObjectPool(Type objectType, string name) { if (objectType == null) { throw new GameFrameworkException("Object type is invalid."); } if (!typeof(ObjectBase).IsAssignableFrom(objectType)) { throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); } return InternalDestroyObjectPool(new TypeNamePair(objectType, name)); } /// /// 销毁对象池。 /// /// 对象类型。 /// 要销毁的对象池。 /// 是否销毁对象池成功。 public bool DestroyObjectPool(IObjectPool objectPool) where T : ObjectBase { if (objectPool == null) { throw new GameFrameworkException("Object pool is invalid."); } return InternalDestroyObjectPool(new TypeNamePair(typeof(T), objectPool.Name)); } /// /// 销毁对象池。 /// /// 要销毁的对象池。 /// 是否销毁对象池成功。 public bool DestroyObjectPool(ObjectPoolBase objectPool) { if (objectPool == null) { throw new GameFrameworkException("Object pool is invalid."); } return InternalDestroyObjectPool(new TypeNamePair(objectPool.ObjectType, objectPool.Name)); } /// /// 释放对象池中的可释放对象。 /// public void Release() { GetAllObjectPools(true, m_CachedAllObjectPools); foreach (ObjectPoolBase objectPool in m_CachedAllObjectPools) { objectPool.Release(); } } /// /// 释放对象池中的所有未使用对象。 /// public void ReleaseAllUnused() { GetAllObjectPools(true, m_CachedAllObjectPools); foreach (ObjectPoolBase objectPool in m_CachedAllObjectPools) { objectPool.ReleaseAllUnused(); } } private bool InternalHasObjectPool(TypeNamePair typeNamePair) { return m_ObjectPools.ContainsKey(typeNamePair); } private ObjectPoolBase InternalGetObjectPool(TypeNamePair typeNamePair) { ObjectPoolBase objectPool = null; if (m_ObjectPools.TryGetValue(typeNamePair, out objectPool)) { return objectPool; } return null; } private IObjectPool InternalCreateObjectPool(string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase { TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name); if (HasObjectPool(name)) { throw new GameFrameworkException(Utility.Text.Format("Already exist object pool '{0}'.", typeNamePair)); } ObjectPool objectPool = new ObjectPool(name, allowMultiSpawn, autoReleaseInterval, capacity, expireTime, priority); m_ObjectPools.Add(typeNamePair, objectPool); return objectPool; } private ObjectPoolBase InternalCreateObjectPool(Type objectType, string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, float expireTime, int priority) { if (objectType == null) { throw new GameFrameworkException("Object type is invalid."); } if (!typeof(ObjectBase).IsAssignableFrom(objectType)) { throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); } TypeNamePair typeNamePair = new TypeNamePair(objectType, name); if (HasObjectPool(objectType, name)) { throw new GameFrameworkException(Utility.Text.Format("Already exist object pool '{0}'.", typeNamePair)); } Type objectPoolType = typeof(ObjectPool<>).MakeGenericType(objectType); ObjectPoolBase objectPool = (ObjectPoolBase)Activator.CreateInstance(objectPoolType, name, allowMultiSpawn, autoReleaseInterval, capacity, expireTime, priority); m_ObjectPools.Add(typeNamePair, objectPool); return objectPool; } private bool InternalDestroyObjectPool(TypeNamePair typeNamePair) { ObjectPoolBase objectPool = null; if (m_ObjectPools.TryGetValue(typeNamePair, out objectPool)) { objectPool.Shutdown(); return m_ObjectPools.Remove(typeNamePair); } return false; } private static int ObjectPoolComparer(ObjectPoolBase a, ObjectPoolBase b) { return a.Priority.CompareTo(b.Priority); } } } ================================================ FILE: GameFramework/ObjectPool/ReleaseObjectFilterCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.ObjectPool { /// /// 释放对象筛选函数。 /// /// 对象类型。 /// 要筛选的对象集合。 /// 需要释放的对象数量。 /// 对象过期参考时间。 /// 经筛选需要释放的对象集合。 public delegate List ReleaseObjectFilterCallback(List candidateObjects, int toReleaseCount, DateTime expireTime) where T : ObjectBase; } ================================================ FILE: GameFramework/Procedure/IProcedureManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Fsm; using System; namespace GameFramework.Procedure { /// /// 流程管理器接口。 /// public interface IProcedureManager { /// /// 获取当前流程。 /// ProcedureBase CurrentProcedure { get; } /// /// 获取当前流程持续时间。 /// float CurrentProcedureTime { get; } /// /// 初始化流程管理器。 /// /// 有限状态机管理器。 /// 流程管理器包含的流程。 void Initialize(IFsmManager fsmManager, params ProcedureBase[] procedures); /// /// 开始流程。 /// /// 要开始的流程类型。 void StartProcedure() where T : ProcedureBase; /// /// 开始流程。 /// /// 要开始的流程类型。 void StartProcedure(Type procedureType); /// /// 是否存在流程。 /// /// 要检查的流程类型。 /// 是否存在流程。 bool HasProcedure() where T : ProcedureBase; /// /// 是否存在流程。 /// /// 要检查的流程类型。 /// 是否存在流程。 bool HasProcedure(Type procedureType); /// /// 获取流程。 /// /// 要获取的流程类型。 /// 要获取的流程。 ProcedureBase GetProcedure() where T : ProcedureBase; /// /// 获取流程。 /// /// 要获取的流程类型。 /// 要获取的流程。 ProcedureBase GetProcedure(Type procedureType); } } ================================================ FILE: GameFramework/Procedure/ProcedureBase.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Fsm; using ProcedureOwner = GameFramework.Fsm.IFsm; namespace GameFramework.Procedure { /// /// 流程基类。 /// public abstract class ProcedureBase : FsmState { /// /// 状态初始化时调用。 /// /// 流程持有者。 protected internal override void OnInit(ProcedureOwner procedureOwner) { base.OnInit(procedureOwner); } /// /// 进入状态时调用。 /// /// 流程持有者。 protected internal override void OnEnter(ProcedureOwner procedureOwner) { base.OnEnter(procedureOwner); } /// /// 状态轮询时调用。 /// /// 流程持有者。 /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 protected internal override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds) { base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds); } /// /// 离开状态时调用。 /// /// 流程持有者。 /// 是否是关闭状态机时触发。 protected internal override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown) { base.OnLeave(procedureOwner, isShutdown); } /// /// 状态销毁时调用。 /// /// 流程持有者。 protected internal override void OnDestroy(ProcedureOwner procedureOwner) { base.OnDestroy(procedureOwner); } } } ================================================ FILE: GameFramework/Procedure/ProcedureManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Fsm; using System; namespace GameFramework.Procedure { /// /// 流程管理器。 /// internal sealed class ProcedureManager : GameFrameworkModule, IProcedureManager { private IFsmManager m_FsmManager; private IFsm m_ProcedureFsm; /// /// 初始化流程管理器的新实例。 /// public ProcedureManager() { m_FsmManager = null; m_ProcedureFsm = null; } /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal override int Priority { get { return -2; } } /// /// 获取当前流程。 /// public ProcedureBase CurrentProcedure { get { if (m_ProcedureFsm == null) { throw new GameFrameworkException("You must initialize procedure first."); } return (ProcedureBase)m_ProcedureFsm.CurrentState; } } /// /// 获取当前流程持续时间。 /// public float CurrentProcedureTime { get { if (m_ProcedureFsm == null) { throw new GameFrameworkException("You must initialize procedure first."); } return m_ProcedureFsm.CurrentStateTime; } } /// /// 流程管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { } /// /// 关闭并清理流程管理器。 /// internal override void Shutdown() { if (m_FsmManager != null) { if (m_ProcedureFsm != null) { m_FsmManager.DestroyFsm(m_ProcedureFsm); m_ProcedureFsm = null; } m_FsmManager = null; } } /// /// 初始化流程管理器。 /// /// 有限状态机管理器。 /// 流程管理器包含的流程。 public void Initialize(IFsmManager fsmManager, params ProcedureBase[] procedures) { if (fsmManager == null) { throw new GameFrameworkException("FSM manager is invalid."); } m_FsmManager = fsmManager; m_ProcedureFsm = m_FsmManager.CreateFsm(this, procedures); } /// /// 开始流程。 /// /// 要开始的流程类型。 public void StartProcedure() where T : ProcedureBase { if (m_ProcedureFsm == null) { throw new GameFrameworkException("You must initialize procedure first."); } m_ProcedureFsm.Start(); } /// /// 开始流程。 /// /// 要开始的流程类型。 public void StartProcedure(Type procedureType) { if (m_ProcedureFsm == null) { throw new GameFrameworkException("You must initialize procedure first."); } m_ProcedureFsm.Start(procedureType); } /// /// 是否存在流程。 /// /// 要检查的流程类型。 /// 是否存在流程。 public bool HasProcedure() where T : ProcedureBase { if (m_ProcedureFsm == null) { throw new GameFrameworkException("You must initialize procedure first."); } return m_ProcedureFsm.HasState(); } /// /// 是否存在流程。 /// /// 要检查的流程类型。 /// 是否存在流程。 public bool HasProcedure(Type procedureType) { if (m_ProcedureFsm == null) { throw new GameFrameworkException("You must initialize procedure first."); } return m_ProcedureFsm.HasState(procedureType); } /// /// 获取流程。 /// /// 要获取的流程类型。 /// 要获取的流程。 public ProcedureBase GetProcedure() where T : ProcedureBase { if (m_ProcedureFsm == null) { throw new GameFrameworkException("You must initialize procedure first."); } return m_ProcedureFsm.GetState(); } /// /// 获取流程。 /// /// 要获取的流程类型。 /// 要获取的流程。 public ProcedureBase GetProcedure(Type procedureType) { if (m_ProcedureFsm == null) { throw new GameFrameworkException("You must initialize procedure first."); } return (ProcedureBase)m_ProcedureFsm.GetState(procedureType); } } } ================================================ FILE: GameFramework/Properties/AssemblyInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // 有关程序集的一般信息由以下控制。更改这些特性值可修改与程序集关联的信息。 [assembly: AssemblyTitle("Game Framework")] [assembly: AssemblyDescription("Game Framework")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jiang Yin")] [assembly: AssemblyProduct("Game Framework")] [assembly: AssemblyCopyright("Copyright © 2013-2021 Jiang Yin")] [assembly: AssemblyTrademark("Copyright © 2013-2021 Jiang Yin")] [assembly: AssemblyCulture("")] // 将 ComVisible 设置为 false 将使此程序集中的类型对 COM 组件不可见。 // 如果需要从 COM 访问此程序集中的类型,请将此类型的 ComVisible 特性设置为 true。 [assembly: ComVisible(false)] // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID。 [assembly: Guid("109d7f39-79ab-4862-9f73-0b8c638930c6")] // 程序集的版本信息由下列四个值组成: // // 主版本 // 次版本 // 生成号 // 修订号 // // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,方法是按如下所示使用“*”: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("0.0.0.0")] [assembly: AssemblyFileVersion("0.0.0.0")] ================================================ FILE: GameFramework/Resource/ApplyResourcesCompleteCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 使用可更新模式并应用资源包资源完成时的回调函数。 /// /// 应用的资源包路径。 /// 应用资源包资源结果,全部成功为 true,否则为 false。 public delegate void ApplyResourcesCompleteCallback(string resourcePackPath, bool result); } ================================================ FILE: GameFramework/Resource/CheckResourcesCompleteCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 使用可更新模式并检查资源完成时的回调函数。 /// /// 已移动的资源数量。 /// 已移除的资源数量。 /// 可更新的资源数量。 /// 可更新的资源总大小。 /// 可更新的压缩后总大小。 public delegate void CheckResourcesCompleteCallback(int movedCount, int removedCount, int updateCount, long updateTotalLength, long updateTotalCompressedLength); } ================================================ FILE: GameFramework/Resource/CheckVersionListResult.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 检查版本资源列表结果。 /// public enum CheckVersionListResult : byte { /// /// 已经是最新的。 /// Updated = 0, /// /// 需要更新。 /// NeedUpdate } } ================================================ FILE: GameFramework/Resource/Constant.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源相关常量。 /// internal static class Constant { /// /// 默认资源加载优先级。 /// internal const int DefaultPriority = 0; } } ================================================ FILE: GameFramework/Resource/DecryptResourceCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 解密资源回调函数。 /// /// 要解密的资源二进制流。 /// 解密二进制流的起始位置。 /// 解密二进制流的长度。 /// 资源名称。 /// 变体名称。 /// 扩展名称。 /// 资源是否在只读区。 /// 文件系统名称。 /// 资源加载方式。 /// 资源大小。 /// 资源哈希值。 public delegate void DecryptResourceCallback(byte[] bytes, int startIndex, int count, string name, string variant, string extension, bool storageInReadOnly, string fileSystem, byte loadType, int length, int hashCode); } ================================================ FILE: GameFramework/Resource/HasAssetResult.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 检查资源是否存在的结果。 /// public enum HasAssetResult : byte { /// /// 资源不存在。 /// NotExist = 0, /// /// 资源尚未准备完毕。 /// NotReady, /// /// 存在资源且存储在磁盘上。 /// AssetOnDisk, /// /// 存在资源且存储在文件系统里。 /// AssetOnFileSystem, /// /// 存在二进制资源且存储在磁盘上。 /// BinaryOnDisk, /// /// 存在二进制资源且存储在文件系统里。 /// BinaryOnFileSystem } } ================================================ FILE: GameFramework/Resource/ILoadResourceAgentHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.FileSystem; using System; namespace GameFramework.Resource { /// /// 加载资源代理辅助器接口。 /// public interface ILoadResourceAgentHelper { /// /// 加载资源代理辅助器异步加载资源更新事件。 /// event EventHandler LoadResourceAgentHelperUpdate; /// /// 加载资源代理辅助器异步读取资源文件完成事件。 /// event EventHandler LoadResourceAgentHelperReadFileComplete; /// /// 加载资源代理辅助器异步读取资源二进制流完成事件。 /// event EventHandler LoadResourceAgentHelperReadBytesComplete; /// /// 加载资源代理辅助器异步将资源二进制流转换为加载对象完成事件。 /// event EventHandler LoadResourceAgentHelperParseBytesComplete; /// /// 加载资源代理辅助器异步加载资源完成事件。 /// event EventHandler LoadResourceAgentHelperLoadComplete; /// /// 加载资源代理辅助器错误事件。 /// event EventHandler LoadResourceAgentHelperError; /// /// 通过加载资源代理辅助器开始异步读取资源文件。 /// /// 要加载资源的完整路径名。 void ReadFile(string fullPath); /// /// 通过加载资源代理辅助器开始异步读取资源文件。 /// /// 要加载资源的文件系统。 /// 要加载资源的名称。 void ReadFile(IFileSystem fileSystem, string name); /// /// 通过加载资源代理辅助器开始异步读取资源二进制流。 /// /// 要加载资源的完整路径名。 void ReadBytes(string fullPath); /// /// 通过加载资源代理辅助器开始异步读取资源二进制流。 /// /// 要加载资源的文件系统。 /// 要加载资源的名称。 void ReadBytes(IFileSystem fileSystem, string name); /// /// 通过加载资源代理辅助器开始异步将资源二进制流转换为加载对象。 /// /// 要加载资源的二进制流。 void ParseBytes(byte[] bytes); /// /// 通过加载资源代理辅助器开始异步加载资源。 /// /// 资源。 /// 要加载的资源名称。 /// 要加载资源的类型。 /// 要加载的资源是否是场景。 void LoadAsset(object resource, string assetName, Type assetType, bool isScene); /// /// 重置加载资源代理辅助器。 /// void Reset(); } } ================================================ FILE: GameFramework/Resource/IResourceGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.Resource { /// /// 资源组接口。 /// public interface IResourceGroup { /// /// 获取资源组名称。 /// string Name { get; } /// /// 获取资源组是否准备完毕。 /// bool Ready { get; } /// /// 获取资源组包含资源数量。 /// int TotalCount { get; } /// /// 获取资源组中已准备完成资源数量。 /// int ReadyCount { get; } /// /// 获取资源组包含资源的总大小。 /// long TotalLength { get; } /// /// 获取资源组包含资源压缩后的总大小。 /// long TotalCompressedLength { get; } /// /// 获取资源组中已准备完成资源的总大小。 /// long ReadyLength { get; } /// /// 获取资源组中已准备完成资源压缩后的总大小。 /// long ReadyCompressedLength { get; } /// /// 获取资源组的完成进度。 /// float Progress { get; } /// /// 获取资源组包含的资源名称列表。 /// /// 资源组包含的资源名称列表。 string[] GetResourceNames(); /// /// 获取资源组包含的资源名称列表。 /// /// 资源组包含的资源名称列表。 void GetResourceNames(List results); } } ================================================ FILE: GameFramework/Resource/IResourceGroupCollection.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.Resource { /// /// 资源组集合接口。 /// public interface IResourceGroupCollection { /// /// 获取资源组集合是否准备完毕。 /// bool Ready { get; } /// /// 获取资源组集合包含资源数量。 /// int TotalCount { get; } /// /// 获取资源组集合中已准备完成资源数量。 /// int ReadyCount { get; } /// /// 获取资源组集合包含资源的总大小。 /// long TotalLength { get; } /// /// 获取资源组集合包含资源压缩后的总大小。 /// long TotalCompressedLength { get; } /// /// 获取资源组集合中已准备完成资源的总大小。 /// long ReadyLength { get; } /// /// 获取资源组集合中已准备完成资源压缩后的总大小。 /// long ReadyCompressedLength { get; } /// /// 获取资源组集合的完成进度。 /// float Progress { get; } /// /// 获取资源组集合包含的资源组列表。 /// /// 资源组包含的资源名称列表。 IResourceGroup[] GetResourceGroups(); /// /// 获取资源组集合包含的资源名称列表。 /// /// 资源组包含的资源名称列表。 string[] GetResourceNames(); /// /// 获取资源组集合包含的资源名称列表。 /// /// 资源组包含的资源名称列表。 void GetResourceNames(List results); } } ================================================ FILE: GameFramework/Resource/IResourceHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源辅助器接口。 /// public interface IResourceHelper { /// /// 直接从指定文件路径加载数据流。 /// /// 文件路径。 /// 加载数据流回调函数集。 /// 用户自定义数据。 void LoadBytes(string fileUri, LoadBytesCallbacks loadBytesCallbacks, object userData); /// /// 卸载场景。 /// /// 场景资源名称。 /// 卸载场景回调函数集。 /// 用户自定义数据。 void UnloadScene(string sceneAssetName, UnloadSceneCallbacks unloadSceneCallbacks, object userData); /// /// 释放资源。 /// /// 要释放的资源。 void Release(object objectToRelease); } } ================================================ FILE: GameFramework/Resource/IResourceManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Download; using GameFramework.FileSystem; using GameFramework.ObjectPool; using System; using System.Collections.Generic; namespace GameFramework.Resource { /// /// 资源管理器接口。 /// public interface IResourceManager { /// /// 获取资源只读区路径。 /// string ReadOnlyPath { get; } /// /// 获取资源读写区路径。 /// string ReadWritePath { get; } /// /// 获取资源模式。 /// ResourceMode ResourceMode { get; } /// /// 获取当前变体。 /// string CurrentVariant { get; } /// /// 获取单机模式版本资源列表序列化器。 /// PackageVersionListSerializer PackageVersionListSerializer { get; } /// /// 获取可更新模式版本资源列表序列化器。 /// UpdatableVersionListSerializer UpdatableVersionListSerializer { get; } /// /// 获取本地只读区版本资源列表序列化器。 /// ReadOnlyVersionListSerializer ReadOnlyVersionListSerializer { get; } /// /// 获取本地读写区版本资源列表序列化器。 /// ReadWriteVersionListSerializer ReadWriteVersionListSerializer { get; } /// /// 获取资源包版本资源列表序列化器。 /// ResourcePackVersionListSerializer ResourcePackVersionListSerializer { get; } /// /// 获取当前资源适用的游戏版本号。 /// string ApplicableGameVersion { get; } /// /// 获取当前内部资源版本号。 /// int InternalResourceVersion { get; } /// /// 获取资源数量。 /// int AssetCount { get; } /// /// 获取资源数量。 /// int ResourceCount { get; } /// /// 获取资源组数量。 /// int ResourceGroupCount { get; } /// /// 获取或设置资源更新下载地址。 /// string UpdatePrefixUri { get; set; } /// /// 获取或设置每更新多少字节的资源,重新生成一次版本资源列表。 /// int GenerateReadWriteVersionListLength { get; set; } /// /// 获取正在应用的资源包路径。 /// string ApplyingResourcePackPath { get; } /// /// 获取等待应用资源数量。 /// int ApplyWaitingCount { get; } /// /// 获取或设置资源更新重试次数。 /// int UpdateRetryCount { get; set; } /// /// 获取正在更新的资源组。 /// IResourceGroup UpdatingResourceGroup { get; } /// /// 获取等待更新资源数量。 /// int UpdateWaitingCount { get; } /// /// 获取使用时下载的等待更新资源数量。 /// int UpdateWaitingWhilePlayingCount { get; } /// /// 获取候选更新资源数量。 /// int UpdateCandidateCount { get; } /// /// 获取加载资源代理总数量。 /// int LoadTotalAgentCount { get; } /// /// 获取可用加载资源代理数量。 /// int LoadFreeAgentCount { get; } /// /// 获取工作中加载资源代理数量。 /// int LoadWorkingAgentCount { get; } /// /// 获取等待加载资源任务数量。 /// int LoadWaitingTaskCount { get; } /// /// 获取或设置资源对象池自动释放可释放对象的间隔秒数。 /// float AssetAutoReleaseInterval { get; set; } /// /// 获取或设置资源对象池的容量。 /// int AssetCapacity { get; set; } /// /// 获取或设置资源对象池对象过期秒数。 /// float AssetExpireTime { get; set; } /// /// 获取或设置资源对象池的优先级。 /// int AssetPriority { get; set; } /// /// 获取或设置资源对象池自动释放可释放对象的间隔秒数。 /// float ResourceAutoReleaseInterval { get; set; } /// /// 获取或设置资源对象池的容量。 /// int ResourceCapacity { get; set; } /// /// 获取或设置资源对象池对象过期秒数。 /// float ResourceExpireTime { get; set; } /// /// 获取或设置资源对象池的优先级。 /// int ResourcePriority { get; set; } /// /// 资源校验开始事件。 /// event EventHandler ResourceVerifyStart; /// /// 资源校验成功事件。 /// event EventHandler ResourceVerifySuccess; /// /// 资源校验失败事件。 /// event EventHandler ResourceVerifyFailure; /// /// 资源应用开始事件。 /// event EventHandler ResourceApplyStart; /// /// 资源应用成功事件。 /// event EventHandler ResourceApplySuccess; /// /// 资源应用失败事件。 /// event EventHandler ResourceApplyFailure; /// /// 资源更新开始事件。 /// event EventHandler ResourceUpdateStart; /// /// 资源更新改变事件。 /// event EventHandler ResourceUpdateChanged; /// /// 资源更新成功事件。 /// event EventHandler ResourceUpdateSuccess; /// /// 资源更新失败事件。 /// event EventHandler ResourceUpdateFailure; /// /// 资源更新全部完成事件。 /// event EventHandler ResourceUpdateAllComplete; /// /// 设置资源只读区路径。 /// /// 资源只读区路径。 void SetReadOnlyPath(string readOnlyPath); /// /// 设置资源读写区路径。 /// /// 资源读写区路径。 void SetReadWritePath(string readWritePath); /// /// 设置资源模式。 /// /// 资源模式。 void SetResourceMode(ResourceMode resourceMode); /// /// 设置当前变体。 /// /// 当前变体。 void SetCurrentVariant(string currentVariant); /// /// 设置对象池管理器。 /// /// 对象池管理器。 void SetObjectPoolManager(IObjectPoolManager objectPoolManager); /// /// 设置文件系统管理器。 /// /// 文件系统管理器。 void SetFileSystemManager(IFileSystemManager fileSystemManager); /// /// 设置下载管理器。 /// /// 下载管理器。 void SetDownloadManager(IDownloadManager downloadManager); /// /// 设置解密资源回调函数。 /// /// 要设置的解密资源回调函数。 /// 如果不设置,将使用默认的解密资源回调函数。 void SetDecryptResourceCallback(DecryptResourceCallback decryptResourceCallback); /// /// 设置资源辅助器。 /// /// 资源辅助器。 void SetResourceHelper(IResourceHelper resourceHelper); /// /// 增加加载资源代理辅助器。 /// /// 要增加的加载资源代理辅助器。 void AddLoadResourceAgentHelper(ILoadResourceAgentHelper loadResourceAgentHelper); /// /// 使用单机模式并初始化资源。 /// /// 使用单机模式并初始化资源完成时的回调函数。 void InitResources(InitResourcesCompleteCallback initResourcesCompleteCallback); /// /// 使用可更新模式并检查版本资源列表。 /// /// 最新的内部资源版本号。 /// 检查版本资源列表结果。 CheckVersionListResult CheckVersionList(int latestInternalResourceVersion); /// /// 使用可更新模式并更新版本资源列表。 /// /// 版本资源列表大小。 /// 版本资源列表哈希值。 /// 版本资源列表压缩后大小。 /// 版本资源列表压缩后哈希值。 /// 版本资源列表更新回调函数集。 void UpdateVersionList(int versionListLength, int versionListHashCode, int versionListCompressedLength, int versionListCompressedHashCode, UpdateVersionListCallbacks updateVersionListCallbacks); /// /// 使用可更新模式并校验资源。 /// /// 每帧至少校验资源的大小,以字节为单位。 /// 使用可更新模式并校验资源完成时的回调函数。 void VerifyResources(int verifyResourceLengthPerFrame, VerifyResourcesCompleteCallback verifyResourcesCompleteCallback); /// /// 使用可更新模式并检查资源。 /// /// 是否忽略处理其它变体的资源,若不忽略,将会移除其它变体的资源。 /// 使用可更新模式并检查资源完成时的回调函数。 void CheckResources(bool ignoreOtherVariant, CheckResourcesCompleteCallback checkResourcesCompleteCallback); /// /// 使用可更新模式并应用资源包资源。 /// /// 要应用的资源包路径。 /// 使用可更新模式并应用资源包资源完成时的回调函数。 void ApplyResources(string resourcePackPath, ApplyResourcesCompleteCallback applyResourcesCompleteCallback); /// /// 使用可更新模式并更新所有资源。 /// /// 使用可更新模式并更新默认资源组完成时的回调函数。 void UpdateResources(UpdateResourcesCompleteCallback updateResourcesCompleteCallback); /// /// 使用可更新模式并更新指定资源组的资源。 /// /// 要更新的资源组名称。 /// 使用可更新模式并更新指定资源组完成时的回调函数。 void UpdateResources(string resourceGroupName, UpdateResourcesCompleteCallback updateResourcesCompleteCallback); /// /// 停止更新资源。 /// void StopUpdateResources(); /// /// 校验资源包。 /// /// 要校验的资源包路径。 /// 是否校验资源包成功。 bool VerifyResourcePack(string resourcePackPath); /// /// 获取所有加载资源任务的信息。 /// /// 所有加载资源任务的信息。 TaskInfo[] GetAllLoadAssetInfos(); /// /// 获取所有加载资源任务的信息。 /// /// 所有加载资源任务的信息。 void GetAllLoadAssetInfos(List results); /// /// 检查资源是否存在。 /// /// 要检查资源的名称。 /// 检查资源是否存在的结果。 HasAssetResult HasAsset(string assetName); /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 加载资源回调函数集。 void LoadAsset(string assetName, LoadAssetCallbacks loadAssetCallbacks); /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 要加载资源的类型。 /// 加载资源回调函数集。 void LoadAsset(string assetName, Type assetType, LoadAssetCallbacks loadAssetCallbacks); /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 加载资源的优先级。 /// 加载资源回调函数集。 void LoadAsset(string assetName, int priority, LoadAssetCallbacks loadAssetCallbacks); /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 加载资源回调函数集。 /// 用户自定义数据。 void LoadAsset(string assetName, LoadAssetCallbacks loadAssetCallbacks, object userData); /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 要加载资源的类型。 /// 加载资源的优先级。 /// 加载资源回调函数集。 void LoadAsset(string assetName, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks); /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 要加载资源的类型。 /// 加载资源回调函数集。 /// 用户自定义数据。 void LoadAsset(string assetName, Type assetType, LoadAssetCallbacks loadAssetCallbacks, object userData); /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 加载资源的优先级。 /// 加载资源回调函数集。 /// 用户自定义数据。 void LoadAsset(string assetName, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData); /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 要加载资源的类型。 /// 加载资源的优先级。 /// 加载资源回调函数集。 /// 用户自定义数据。 void LoadAsset(string assetName, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData); /// /// 卸载资源。 /// /// 要卸载的资源。 void UnloadAsset(object asset); /// /// 异步加载场景。 /// /// 要加载场景资源的名称。 /// 加载场景回调函数集。 void LoadScene(string sceneAssetName, LoadSceneCallbacks loadSceneCallbacks); /// /// 异步加载场景。 /// /// 要加载场景资源的名称。 /// 加载场景资源的优先级。 /// 加载场景回调函数集。 void LoadScene(string sceneAssetName, int priority, LoadSceneCallbacks loadSceneCallbacks); /// /// 异步加载场景。 /// /// 要加载场景资源的名称。 /// 加载场景回调函数集。 /// 用户自定义数据。 void LoadScene(string sceneAssetName, LoadSceneCallbacks loadSceneCallbacks, object userData); /// /// 异步加载场景。 /// /// 要加载场景资源的名称。 /// 加载场景资源的优先级。 /// 加载场景回调函数集。 /// 用户自定义数据。 void LoadScene(string sceneAssetName, int priority, LoadSceneCallbacks loadSceneCallbacks, object userData); /// /// 异步卸载场景。 /// /// 要卸载场景资源的名称。 /// 卸载场景回调函数集。 void UnloadScene(string sceneAssetName, UnloadSceneCallbacks unloadSceneCallbacks); /// /// 异步卸载场景。 /// /// 要卸载场景资源的名称。 /// 卸载场景回调函数集。 /// 用户自定义数据。 void UnloadScene(string sceneAssetName, UnloadSceneCallbacks unloadSceneCallbacks, object userData); /// /// 获取二进制资源的实际路径。 /// /// 要获取实际路径的二进制资源的名称。 /// 二进制资源的实际路径。 /// 此方法仅适用于二进制资源存储在磁盘(而非文件系统)中的情况。若二进制资源存储在文件系统中时,返回值将始终为空。 string GetBinaryPath(string binaryAssetName); /// /// 获取二进制资源的实际路径。 /// /// 要获取实际路径的二进制资源的名称。 /// 二进制资源是否存储在只读区中。 /// 二进制资源是否存储在文件系统中。 /// 二进制资源或存储二进制资源的文件系统,相对于只读区或者读写区的相对路径。 /// 若二进制资源存储在文件系统中,则指示二进制资源在文件系统中的名称,否则此参数返回空。 /// 是否获取二进制资源的实际路径成功。 bool GetBinaryPath(string binaryAssetName, out bool storageInReadOnly, out bool storageInFileSystem, out string relativePath, out string fileName); /// /// 获取二进制资源的长度。 /// /// 要获取长度的二进制资源的名称。 /// 二进制资源的长度。 int GetBinaryLength(string binaryAssetName); /// /// 异步加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 加载二进制资源回调函数集。 void LoadBinary(string binaryAssetName, LoadBinaryCallbacks loadBinaryCallbacks); /// /// 异步加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 加载二进制资源回调函数集。 /// 用户自定义数据。 void LoadBinary(string binaryAssetName, LoadBinaryCallbacks loadBinaryCallbacks, object userData); /// /// 从文件系统中加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 存储加载二进制资源的二进制流。 byte[] LoadBinaryFromFileSystem(string binaryAssetName); /// /// 从文件系统中加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 存储加载二进制资源的二进制流。 /// 实际加载了多少字节。 int LoadBinaryFromFileSystem(string binaryAssetName, byte[] buffer); /// /// 从文件系统中加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 存储加载二进制资源的二进制流。 /// 存储加载二进制资源的二进制流的起始位置。 /// 实际加载了多少字节。 int LoadBinaryFromFileSystem(string binaryAssetName, byte[] buffer, int startIndex); /// /// 从文件系统中加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 存储加载二进制资源的二进制流。 /// 存储加载二进制资源的二进制流的起始位置。 /// 存储加载二进制资源的二进制流的长度。 /// 实际加载了多少字节。 int LoadBinaryFromFileSystem(string binaryAssetName, byte[] buffer, int startIndex, int length); /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的长度。 /// 存储加载二进制资源片段内容的二进制流。 byte[] LoadBinarySegmentFromFileSystem(string binaryAssetName, int length); /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的偏移。 /// 要加载片段的长度。 /// 存储加载二进制资源片段内容的二进制流。 byte[] LoadBinarySegmentFromFileSystem(string binaryAssetName, int offset, int length); /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 存储加载二进制资源片段内容的二进制流。 /// 实际加载了多少字节。 int LoadBinarySegmentFromFileSystem(string binaryAssetName, byte[] buffer); /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 存储加载二进制资源片段内容的二进制流。 /// 要加载片段的长度。 /// 实际加载了多少字节。 int LoadBinarySegmentFromFileSystem(string binaryAssetName, byte[] buffer, int length); /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 存储加载二进制资源片段内容的二进制流。 /// 存储加载二进制资源片段内容的二进制流的起始位置。 /// 要加载片段的长度。 /// 实际加载了多少字节。 int LoadBinarySegmentFromFileSystem(string binaryAssetName, byte[] buffer, int startIndex, int length); /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的偏移。 /// 存储加载二进制资源片段内容的二进制流。 /// 实际加载了多少字节。 int LoadBinarySegmentFromFileSystem(string binaryAssetName, int offset, byte[] buffer); /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的偏移。 /// 存储加载二进制资源片段内容的二进制流。 /// 要加载片段的长度。 /// 实际加载了多少字节。 int LoadBinarySegmentFromFileSystem(string binaryAssetName, int offset, byte[] buffer, int length); /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的偏移。 /// 存储加载二进制资源片段内容的二进制流。 /// 存储加载二进制资源片段内容的二进制流的起始位置。 /// 要加载片段的长度。 /// 实际加载了多少字节。 int LoadBinarySegmentFromFileSystem(string binaryAssetName, int offset, byte[] buffer, int startIndex, int length); /// /// 检查资源组是否存在。 /// /// 要检查资源组的名称。 /// 资源组是否存在。 bool HasResourceGroup(string resourceGroupName); /// /// 获取默认资源组。 /// /// 默认资源组。 IResourceGroup GetResourceGroup(); /// /// 获取资源组。 /// /// 要获取的资源组名称。 /// 要获取的资源组。 IResourceGroup GetResourceGroup(string resourceGroupName); /// /// 获取所有资源组。 /// /// 所有资源组。 IResourceGroup[] GetAllResourceGroups(); /// /// 获取所有资源组。 /// /// 所有资源组。 void GetAllResourceGroups(List results); /// /// 获取资源组集合。 /// /// 要获取的资源组名称的集合。 /// 要获取的资源组集合。 IResourceGroupCollection GetResourceGroupCollection(params string[] resourceGroupNames); /// /// 获取资源组集合。 /// /// 要获取的资源组名称的集合。 /// 要获取的资源组集合。 IResourceGroupCollection GetResourceGroupCollection(List resourceGroupNames); } } ================================================ FILE: GameFramework/Resource/InitResourcesCompleteCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 使用单机模式并初始化资源完成时的回调函数。 /// public delegate void InitResourcesCompleteCallback(); } ================================================ FILE: GameFramework/Resource/LoadAssetCallbacks.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源回调函数集。 /// public sealed class LoadAssetCallbacks { private readonly LoadAssetSuccessCallback m_LoadAssetSuccessCallback; private readonly LoadAssetFailureCallback m_LoadAssetFailureCallback; private readonly LoadAssetUpdateCallback m_LoadAssetUpdateCallback; private readonly LoadAssetDependencyAssetCallback m_LoadAssetDependencyAssetCallback; /// /// 初始化加载资源回调函数集的新实例。 /// /// 加载资源成功回调函数。 public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback) : this(loadAssetSuccessCallback, null, null, null) { } /// /// 初始化加载资源回调函数集的新实例。 /// /// 加载资源成功回调函数。 /// 加载资源失败回调函数。 public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback, LoadAssetFailureCallback loadAssetFailureCallback) : this(loadAssetSuccessCallback, loadAssetFailureCallback, null, null) { } /// /// 初始化加载资源回调函数集的新实例。 /// /// 加载资源成功回调函数。 /// 加载资源更新回调函数。 public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback, LoadAssetUpdateCallback loadAssetUpdateCallback) : this(loadAssetSuccessCallback, null, loadAssetUpdateCallback, null) { } /// /// 初始化加载资源回调函数集的新实例。 /// /// 加载资源成功回调函数。 /// 加载资源时加载依赖资源回调函数。 public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback, LoadAssetDependencyAssetCallback loadAssetDependencyAssetCallback) : this(loadAssetSuccessCallback, null, null, loadAssetDependencyAssetCallback) { } /// /// 初始化加载资源回调函数集的新实例。 /// /// 加载资源成功回调函数。 /// 加载资源失败回调函数。 /// 加载资源更新回调函数。 public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback, LoadAssetFailureCallback loadAssetFailureCallback, LoadAssetUpdateCallback loadAssetUpdateCallback) : this(loadAssetSuccessCallback, loadAssetFailureCallback, loadAssetUpdateCallback, null) { } /// /// 初始化加载资源回调函数集的新实例。 /// /// 加载资源成功回调函数。 /// 加载资源失败回调函数。 /// 加载资源时加载依赖资源回调函数。 public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback, LoadAssetFailureCallback loadAssetFailureCallback, LoadAssetDependencyAssetCallback loadAssetDependencyAssetCallback) : this(loadAssetSuccessCallback, loadAssetFailureCallback, null, loadAssetDependencyAssetCallback) { } /// /// 初始化加载资源回调函数集的新实例。 /// /// 加载资源成功回调函数。 /// 加载资源失败回调函数。 /// 加载资源更新回调函数。 /// 加载资源时加载依赖资源回调函数。 public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback, LoadAssetFailureCallback loadAssetFailureCallback, LoadAssetUpdateCallback loadAssetUpdateCallback, LoadAssetDependencyAssetCallback loadAssetDependencyAssetCallback) { if (loadAssetSuccessCallback == null) { throw new GameFrameworkException("Load asset success callback is invalid."); } m_LoadAssetSuccessCallback = loadAssetSuccessCallback; m_LoadAssetFailureCallback = loadAssetFailureCallback; m_LoadAssetUpdateCallback = loadAssetUpdateCallback; m_LoadAssetDependencyAssetCallback = loadAssetDependencyAssetCallback; } /// /// 获取加载资源成功回调函数。 /// public LoadAssetSuccessCallback LoadAssetSuccessCallback { get { return m_LoadAssetSuccessCallback; } } /// /// 获取加载资源失败回调函数。 /// public LoadAssetFailureCallback LoadAssetFailureCallback { get { return m_LoadAssetFailureCallback; } } /// /// 获取加载资源更新回调函数。 /// public LoadAssetUpdateCallback LoadAssetUpdateCallback { get { return m_LoadAssetUpdateCallback; } } /// /// 获取加载资源时加载依赖资源回调函数。 /// public LoadAssetDependencyAssetCallback LoadAssetDependencyAssetCallback { get { return m_LoadAssetDependencyAssetCallback; } } } } ================================================ FILE: GameFramework/Resource/LoadAssetDependencyAssetCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源时加载依赖资源回调函数。 /// /// 要加载的资源名称。 /// 被加载的依赖资源名称。 /// 当前已加载依赖资源数量。 /// 总共加载依赖资源数量。 /// 用户自定义数据。 public delegate void LoadAssetDependencyAssetCallback(string assetName, string dependencyAssetName, int loadedCount, int totalCount, object userData); } ================================================ FILE: GameFramework/Resource/LoadAssetFailureCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源失败回调函数。 /// /// 要加载的资源名称。 /// 加载资源状态。 /// 错误信息。 /// 用户自定义数据。 public delegate void LoadAssetFailureCallback(string assetName, LoadResourceStatus status, string errorMessage, object userData); } ================================================ FILE: GameFramework/Resource/LoadAssetSuccessCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源成功回调函数。 /// /// 要加载的资源名称。 /// 已加载的资源。 /// 加载持续时间。 /// 用户自定义数据。 public delegate void LoadAssetSuccessCallback(string assetName, object asset, float duration, object userData); } ================================================ FILE: GameFramework/Resource/LoadAssetUpdateCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源更新回调函数。 /// /// 要加载的资源名称。 /// 加载资源进度。 /// 用户自定义数据。 public delegate void LoadAssetUpdateCallback(string assetName, float progress, object userData); } ================================================ FILE: GameFramework/Resource/LoadBinaryCallbacks.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载二进制资源回调函数集。 /// public sealed class LoadBinaryCallbacks { private readonly LoadBinarySuccessCallback m_LoadBinarySuccessCallback; private readonly LoadBinaryFailureCallback m_LoadBinaryFailureCallback; /// /// 初始化加载二进制资源回调函数集的新实例。 /// /// 加载二进制资源成功回调函数。 public LoadBinaryCallbacks(LoadBinarySuccessCallback loadBinarySuccessCallback) : this(loadBinarySuccessCallback, null) { } /// /// 初始化加载二进制资源回调函数集的新实例。 /// /// 加载二进制资源成功回调函数。 /// 加载二进制资源失败回调函数。 public LoadBinaryCallbacks(LoadBinarySuccessCallback loadBinarySuccessCallback, LoadBinaryFailureCallback loadBinaryFailureCallback) { if (loadBinarySuccessCallback == null) { throw new GameFrameworkException("Load binary success callback is invalid."); } m_LoadBinarySuccessCallback = loadBinarySuccessCallback; m_LoadBinaryFailureCallback = loadBinaryFailureCallback; } /// /// 获取加载二进制资源成功回调函数。 /// public LoadBinarySuccessCallback LoadBinarySuccessCallback { get { return m_LoadBinarySuccessCallback; } } /// /// 获取加载二进制资源失败回调函数。 /// public LoadBinaryFailureCallback LoadBinaryFailureCallback { get { return m_LoadBinaryFailureCallback; } } } } ================================================ FILE: GameFramework/Resource/LoadBinaryFailureCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载二进制资源失败回调函数。 /// /// 要加载的二进制资源名称。 /// 加载二进制资源状态。 /// 错误信息。 /// 用户自定义数据。 public delegate void LoadBinaryFailureCallback(string binaryAssetName, LoadResourceStatus status, string errorMessage, object userData); } ================================================ FILE: GameFramework/Resource/LoadBinarySuccessCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载二进制资源成功回调函数。 /// /// 要加载的二进制资源名称。 /// 已加载的二进制资源。 /// 加载持续时间。 /// 用户自定义数据。 public delegate void LoadBinarySuccessCallback(string binaryAssetName, byte[] binaryBytes, float duration, object userData); } ================================================ FILE: GameFramework/Resource/LoadBytesCallbacks.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载数据流回调函数集。 /// public sealed class LoadBytesCallbacks { private readonly LoadBytesSuccessCallback m_LoadBytesSuccessCallback; private readonly LoadBytesFailureCallback m_LoadBytesFailureCallback; /// /// 初始化加载数据流回调函数集的新实例。 /// /// 加载数据流成功回调函数。 public LoadBytesCallbacks(LoadBytesSuccessCallback loadBinarySuccessCallback) : this(loadBinarySuccessCallback, null) { } /// /// 初始化加载数据流回调函数集的新实例。 /// /// 加载数据流成功回调函数。 /// 加载数据流失败回调函数。 public LoadBytesCallbacks(LoadBytesSuccessCallback loadBytesSuccessCallback, LoadBytesFailureCallback loadBytesFailureCallback) { if (loadBytesSuccessCallback == null) { throw new GameFrameworkException("Load bytes success callback is invalid."); } m_LoadBytesSuccessCallback = loadBytesSuccessCallback; m_LoadBytesFailureCallback = loadBytesFailureCallback; } /// /// 获取加载数据流成功回调函数。 /// public LoadBytesSuccessCallback LoadBytesSuccessCallback { get { return m_LoadBytesSuccessCallback; } } /// /// 获取加载数据流失败回调函数。 /// public LoadBytesFailureCallback LoadBytesFailureCallback { get { return m_LoadBytesFailureCallback; } } } } ================================================ FILE: GameFramework/Resource/LoadBytesFailureCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载数据流失败回调函数。 /// /// 文件路径。 /// 错误信息。 /// 用户自定义数据。 public delegate void LoadBytesFailureCallback(string fileUri, string errorMessage, object userData); } ================================================ FILE: GameFramework/Resource/LoadBytesSuccessCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载数据流成功回调函数。 /// /// 文件路径。 /// 数据流。 /// 加载持续时间。 /// 用户自定义数据。 public delegate void LoadBytesSuccessCallback(string fileUri, byte[] bytes, float duration, object userData); } ================================================ FILE: GameFramework/Resource/LoadResourceAgentHelperErrorEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源代理辅助器错误事件。 /// public sealed class LoadResourceAgentHelperErrorEventArgs : GameFrameworkEventArgs { /// /// 初始化加载资源代理辅助器错误事件的新实例。 /// public LoadResourceAgentHelperErrorEventArgs() { Status = LoadResourceStatus.Success; ErrorMessage = null; } /// /// 获取加载资源状态。 /// public LoadResourceStatus Status { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 创建加载资源代理辅助器错误事件。 /// /// 加载资源状态。 /// 错误信息。 /// 创建的加载资源代理辅助器错误事件。 public static LoadResourceAgentHelperErrorEventArgs Create(LoadResourceStatus status, string errorMessage) { LoadResourceAgentHelperErrorEventArgs loadResourceAgentHelperErrorEventArgs = ReferencePool.Acquire(); loadResourceAgentHelperErrorEventArgs.Status = status; loadResourceAgentHelperErrorEventArgs.ErrorMessage = errorMessage; return loadResourceAgentHelperErrorEventArgs; } /// /// 清理加载资源代理辅助器错误事件。 /// public override void Clear() { Status = LoadResourceStatus.Success; ErrorMessage = null; } } } ================================================ FILE: GameFramework/Resource/LoadResourceAgentHelperLoadCompleteEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源代理辅助器异步加载资源完成事件。 /// public sealed class LoadResourceAgentHelperLoadCompleteEventArgs : GameFrameworkEventArgs { /// /// 初始化加载资源代理辅助器异步加载资源完成事件的新实例。 /// public LoadResourceAgentHelperLoadCompleteEventArgs() { Asset = null; } /// /// 获取加载的资源。 /// public object Asset { get; private set; } /// /// 创建加载资源代理辅助器异步加载资源完成事件。 /// /// 加载的资源。 /// 创建的加载资源代理辅助器异步加载资源完成事件。 public static LoadResourceAgentHelperLoadCompleteEventArgs Create(object asset) { LoadResourceAgentHelperLoadCompleteEventArgs loadResourceAgentHelperLoadCompleteEventArgs = ReferencePool.Acquire(); loadResourceAgentHelperLoadCompleteEventArgs.Asset = asset; return loadResourceAgentHelperLoadCompleteEventArgs; } /// /// 清理加载资源代理辅助器异步加载资源完成事件。 /// public override void Clear() { Asset = null; } } } ================================================ FILE: GameFramework/Resource/LoadResourceAgentHelperParseBytesCompleteEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源代理辅助器异步将资源二进制流转换为加载对象完成事件。 /// public sealed class LoadResourceAgentHelperParseBytesCompleteEventArgs : GameFrameworkEventArgs { /// /// 初始化加载资源代理辅助器异步将资源二进制流转换为加载对象完成事件的新实例。 /// public LoadResourceAgentHelperParseBytesCompleteEventArgs() { Resource = null; } /// /// 获取加载对象。 /// public object Resource { get; private set; } /// /// 创建加载资源代理辅助器异步将资源二进制流转换为加载对象完成事件。 /// /// 资源对象。 /// 创建的加载资源代理辅助器异步将资源二进制流转换为加载对象完成事件。 public static LoadResourceAgentHelperParseBytesCompleteEventArgs Create(object resource) { LoadResourceAgentHelperParseBytesCompleteEventArgs loadResourceAgentHelperParseBytesCompleteEventArgs = ReferencePool.Acquire(); loadResourceAgentHelperParseBytesCompleteEventArgs.Resource = resource; return loadResourceAgentHelperParseBytesCompleteEventArgs; } /// /// 清理加载资源代理辅助器异步将资源二进制流转换为加载对象完成事件。 /// public override void Clear() { Resource = null; } } } ================================================ FILE: GameFramework/Resource/LoadResourceAgentHelperReadBytesCompleteEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源代理辅助器异步读取资源二进制流完成事件。 /// public sealed class LoadResourceAgentHelperReadBytesCompleteEventArgs : GameFrameworkEventArgs { private byte[] m_Bytes; /// /// 初始化加载资源代理辅助器异步读取资源二进制流完成事件的新实例。 /// public LoadResourceAgentHelperReadBytesCompleteEventArgs() { m_Bytes = null; } /// /// 创建加载资源代理辅助器异步读取资源二进制流完成事件。 /// /// 资源的二进制流。 /// 创建的加载资源代理辅助器异步读取资源二进制流完成事件。 public static LoadResourceAgentHelperReadBytesCompleteEventArgs Create(byte[] bytes) { LoadResourceAgentHelperReadBytesCompleteEventArgs loadResourceAgentHelperReadBytesCompleteEventArgs = ReferencePool.Acquire(); loadResourceAgentHelperReadBytesCompleteEventArgs.m_Bytes = bytes; return loadResourceAgentHelperReadBytesCompleteEventArgs; } /// /// 清理加载资源代理辅助器异步读取资源二进制流完成事件。 /// public override void Clear() { m_Bytes = null; } /// /// 获取资源的二进制流。 /// /// 资源的二进制流。 public byte[] GetBytes() { return m_Bytes; } } } ================================================ FILE: GameFramework/Resource/LoadResourceAgentHelperReadFileCompleteEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源代理辅助器异步将资源文件转换为加载对象完成事件。 /// public sealed class LoadResourceAgentHelperReadFileCompleteEventArgs : GameFrameworkEventArgs { /// /// 初始化加载资源代理辅助器异步将资源文件转换为加载对象完成事件的新实例。 /// public LoadResourceAgentHelperReadFileCompleteEventArgs() { Resource = null; } /// /// 获取加载对象。 /// public object Resource { get; private set; } /// /// 创建加载资源代理辅助器异步将资源文件转换为加载对象完成事件。 /// /// 资源对象。 /// 创建的加载资源代理辅助器异步将资源文件转换为加载对象完成事件。 public static LoadResourceAgentHelperReadFileCompleteEventArgs Create(object resource) { LoadResourceAgentHelperReadFileCompleteEventArgs loadResourceAgentHelperReadFileCompleteEventArgs = ReferencePool.Acquire(); loadResourceAgentHelperReadFileCompleteEventArgs.Resource = resource; return loadResourceAgentHelperReadFileCompleteEventArgs; } /// /// 清理加载资源代理辅助器异步将资源文件转换为加载对象完成事件。 /// public override void Clear() { Resource = null; } } } ================================================ FILE: GameFramework/Resource/LoadResourceAgentHelperUpdateEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源代理辅助器更新事件。 /// public sealed class LoadResourceAgentHelperUpdateEventArgs : GameFrameworkEventArgs { /// /// 初始化加载资源代理辅助器更新事件的新实例。 /// public LoadResourceAgentHelperUpdateEventArgs() { Type = LoadResourceProgress.Unknown; Progress = 0f; } /// /// 获取进度类型。 /// public LoadResourceProgress Type { get; private set; } /// /// 获取进度。 /// public float Progress { get; private set; } /// /// 创建加载资源代理辅助器更新事件。 /// /// 进度类型。 /// 进度。 /// 创建的加载资源代理辅助器更新事件。 public static LoadResourceAgentHelperUpdateEventArgs Create(LoadResourceProgress type, float progress) { LoadResourceAgentHelperUpdateEventArgs loadResourceAgentHelperUpdateEventArgs = ReferencePool.Acquire(); loadResourceAgentHelperUpdateEventArgs.Type = type; loadResourceAgentHelperUpdateEventArgs.Progress = progress; return loadResourceAgentHelperUpdateEventArgs; } /// /// 清理加载资源代理辅助器更新事件。 /// public override void Clear() { Type = LoadResourceProgress.Unknown; Progress = 0f; } } } ================================================ FILE: GameFramework/Resource/LoadResourceProgress.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源进度类型。 /// public enum LoadResourceProgress : byte { /// /// 未知类型。 /// Unknown = 0, /// /// 读取资源包。 /// ReadResource, /// /// 加载资源包。 /// LoadResource, /// /// 加载资源。 /// LoadAsset, /// /// 加载场景。 /// LoadScene } } ================================================ FILE: GameFramework/Resource/LoadResourceStatus.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载资源状态。 /// public enum LoadResourceStatus : byte { /// /// 加载资源完成。 /// Success = 0, /// /// 资源不存在。 /// NotExist, /// /// 资源尚未准备完毕。 /// NotReady, /// /// 依赖资源错误。 /// DependencyError, /// /// 资源类型错误。 /// TypeError, /// /// 加载资源错误。 /// AssetError } } ================================================ FILE: GameFramework/Resource/LoadSceneCallbacks.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载场景回调函数集。 /// public sealed class LoadSceneCallbacks { private readonly LoadSceneSuccessCallback m_LoadSceneSuccessCallback; private readonly LoadSceneFailureCallback m_LoadSceneFailureCallback; private readonly LoadSceneUpdateCallback m_LoadSceneUpdateCallback; private readonly LoadSceneDependencyAssetCallback m_LoadSceneDependencyAssetCallback; /// /// 初始化加载场景回调函数集的新实例。 /// /// 加载场景成功回调函数。 public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback) : this(loadSceneSuccessCallback, null, null, null) { } /// /// 初始化加载场景回调函数集的新实例。 /// /// 加载场景成功回调函数。 /// 加载场景失败回调函数。 public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback, LoadSceneFailureCallback loadSceneFailureCallback) : this(loadSceneSuccessCallback, loadSceneFailureCallback, null, null) { } /// /// 初始化加载场景回调函数集的新实例。 /// /// 加载场景成功回调函数。 /// 加载场景更新回调函数。 public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback, LoadSceneUpdateCallback loadSceneUpdateCallback) : this(loadSceneSuccessCallback, null, loadSceneUpdateCallback, null) { } /// /// 初始化加载场景回调函数集的新实例。 /// /// 加载场景成功回调函数。 /// 加载场景时加载依赖资源回调函数。 public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback, LoadSceneDependencyAssetCallback loadSceneDependencyAssetCallback) : this(loadSceneSuccessCallback, null, null, loadSceneDependencyAssetCallback) { } /// /// 初始化加载场景回调函数集的新实例。 /// /// 加载场景成功回调函数。 /// 加载场景失败回调函数。 /// 加载场景更新回调函数。 public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback, LoadSceneFailureCallback loadSceneFailureCallback, LoadSceneUpdateCallback loadSceneUpdateCallback) : this(loadSceneSuccessCallback, loadSceneFailureCallback, loadSceneUpdateCallback, null) { } /// /// 初始化加载场景回调函数集的新实例。 /// /// 加载场景成功回调函数。 /// 加载场景失败回调函数。 /// 加载场景时加载依赖资源回调函数。 public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback, LoadSceneFailureCallback loadSceneFailureCallback, LoadSceneDependencyAssetCallback loadSceneDependencyAssetCallback) : this(loadSceneSuccessCallback, loadSceneFailureCallback, null, loadSceneDependencyAssetCallback) { } /// /// 初始化加载场景回调函数集的新实例。 /// /// 加载场景成功回调函数。 /// 加载场景失败回调函数。 /// 加载场景更新回调函数。 /// 加载场景时加载依赖资源回调函数。 public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback, LoadSceneFailureCallback loadSceneFailureCallback, LoadSceneUpdateCallback loadSceneUpdateCallback, LoadSceneDependencyAssetCallback loadSceneDependencyAssetCallback) { if (loadSceneSuccessCallback == null) { throw new GameFrameworkException("Load scene success callback is invalid."); } m_LoadSceneSuccessCallback = loadSceneSuccessCallback; m_LoadSceneFailureCallback = loadSceneFailureCallback; m_LoadSceneUpdateCallback = loadSceneUpdateCallback; m_LoadSceneDependencyAssetCallback = loadSceneDependencyAssetCallback; } /// /// 获取加载场景成功回调函数。 /// public LoadSceneSuccessCallback LoadSceneSuccessCallback { get { return m_LoadSceneSuccessCallback; } } /// /// 获取加载场景失败回调函数。 /// public LoadSceneFailureCallback LoadSceneFailureCallback { get { return m_LoadSceneFailureCallback; } } /// /// 获取加载场景更新回调函数。 /// public LoadSceneUpdateCallback LoadSceneUpdateCallback { get { return m_LoadSceneUpdateCallback; } } /// /// 获取加载场景时加载依赖资源回调函数。 /// public LoadSceneDependencyAssetCallback LoadSceneDependencyAssetCallback { get { return m_LoadSceneDependencyAssetCallback; } } } } ================================================ FILE: GameFramework/Resource/LoadSceneDependencyAssetCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载场景时加载依赖资源回调函数。 /// /// 要加载的场景资源名称。 /// 被加载的依赖资源名称。 /// 当前已加载依赖资源数量。 /// 总共加载依赖资源数量。 /// 用户自定义数据。 public delegate void LoadSceneDependencyAssetCallback(string sceneAssetName, string dependencyAssetName, int loadedCount, int totalCount, object userData); } ================================================ FILE: GameFramework/Resource/LoadSceneFailureCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载场景失败回调函数。 /// /// 要加载的场景资源名称。 /// 加载场景状态。 /// 错误信息。 /// 用户自定义数据。 public delegate void LoadSceneFailureCallback(string sceneAssetName, LoadResourceStatus status, string errorMessage, object userData); } ================================================ FILE: GameFramework/Resource/LoadSceneSuccessCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载场景成功回调函数。 /// /// 要加载的场景资源名称。 /// 加载持续时间。 /// 用户自定义数据。 public delegate void LoadSceneSuccessCallback(string sceneAssetName, float duration, object userData); } ================================================ FILE: GameFramework/Resource/LoadSceneUpdateCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 加载场景更新回调函数。 /// /// 要加载的场景资源名称。 /// 加载场景进度。 /// 用户自定义数据。 public delegate void LoadSceneUpdateCallback(string sceneAssetName, float progress, object userData); } ================================================ FILE: GameFramework/Resource/LocalVersionList.FileSystem.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct LocalVersionList { /// /// 文件系统。 /// [StructLayout(LayoutKind.Auto)] public struct FileSystem { private static readonly int[] EmptyIntArray = new int[] { }; private readonly string m_Name; private readonly int[] m_ResourceIndexes; /// /// 初始化文件系统的新实例。 /// /// 文件系统名称。 /// 文件系统包含的资源索引集合。 public FileSystem(string name, int[] resourceIndexes) { if (name == null) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_ResourceIndexes = resourceIndexes ?? EmptyIntArray; } /// /// 获取文件系统名称。 /// public string Name { get { return m_Name; } } /// /// 获取文件系统包含的资源索引集合。 /// /// 文件系统包含的资源索引集合。 public int[] GetResourceIndexes() { return m_ResourceIndexes; } } } } ================================================ FILE: GameFramework/Resource/LocalVersionList.Resource.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct LocalVersionList { /// /// 资源。 /// [StructLayout(LayoutKind.Auto)] public struct Resource { private readonly string m_Name; private readonly string m_Variant; private readonly string m_Extension; private readonly byte m_LoadType; private readonly int m_Length; private readonly int m_HashCode; /// /// 初始化资源的新实例。 /// /// 资源名称。 /// 资源变体名称。 /// 资源扩展名称。 /// 资源加载方式。 /// 资源长度。 /// 资源哈希值。 public Resource(string name, string variant, string extension, byte loadType, int length, int hashCode) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_Variant = variant; m_Extension = extension; m_LoadType = loadType; m_Length = length; m_HashCode = hashCode; } /// /// 获取资源名称。 /// public string Name { get { return m_Name; } } /// /// 获取资源变体名称。 /// public string Variant { get { return m_Variant; } } /// /// 获取资源扩展名称。 /// public string Extension { get { return m_Extension; } } /// /// 获取资源加载方式。 /// public byte LoadType { get { return m_LoadType; } } /// /// 获取资源长度。 /// public int Length { get { return m_Length; } } /// /// 获取资源哈希值。 /// public int HashCode { get { return m_HashCode; } } } } } ================================================ FILE: GameFramework/Resource/LocalVersionList.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { /// /// 本地版本资源列表。 /// [StructLayout(LayoutKind.Auto)] public partial struct LocalVersionList { private static readonly Resource[] EmptyResourceArray = new Resource[] { }; private static readonly FileSystem[] EmptyFileSystemArray = new FileSystem[] { }; private readonly bool m_IsValid; private readonly Resource[] m_Resources; private readonly FileSystem[] m_FileSystems; /// /// 初始化本地版本资源列表的新实例。 /// /// 包含的资源集合。 /// 包含的文件系统集合。 public LocalVersionList(Resource[] resources, FileSystem[] fileSystems) { m_IsValid = true; m_Resources = resources ?? EmptyResourceArray; m_FileSystems = fileSystems ?? EmptyFileSystemArray; } /// /// 获取本地版本资源列表是否有效。 /// public bool IsValid { get { return m_IsValid; } } /// /// 获取包含的资源集合。 /// /// 包含的资源集合。 public Resource[] GetResources() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Resources; } /// /// 获取包含的文件系统集合。 /// /// 包含的文件系统集合。 public FileSystem[] GetFileSystems() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_FileSystems; } } } ================================================ FILE: GameFramework/Resource/PackageVersionList.Asset.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct PackageVersionList { /// /// 资源。 /// [StructLayout(LayoutKind.Auto)] public struct Asset { private static readonly int[] EmptyIntArray = new int[] { }; private readonly string m_Name; private readonly int[] m_DependencyAssetIndexes; /// /// 初始化资源的新实例。 /// /// 资源名称。 /// 资源包含的依赖资源索引集合。 public Asset(string name, int[] dependencyAssetIndexes) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_DependencyAssetIndexes = dependencyAssetIndexes ?? EmptyIntArray; } /// /// 获取资源名称。 /// public string Name { get { return m_Name; } } /// /// 获取资源包含的依赖资源索引集合。 /// /// 资源包含的依赖资源索引集合。 public int[] GetDependencyAssetIndexes() { return m_DependencyAssetIndexes; } } } } ================================================ FILE: GameFramework/Resource/PackageVersionList.FileSystem.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct PackageVersionList { /// /// 文件系统。 /// [StructLayout(LayoutKind.Auto)] public struct FileSystem { private static readonly int[] EmptyIntArray = new int[] { }; private readonly string m_Name; private readonly int[] m_ResourceIndexes; /// /// 初始化文件系统的新实例。 /// /// 文件系统名称。 /// 文件系统包含的资源索引集合。 public FileSystem(string name, int[] resourceIndexes) { if (name == null) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_ResourceIndexes = resourceIndexes ?? EmptyIntArray; } /// /// 获取文件系统名称。 /// public string Name { get { return m_Name; } } /// /// 获取文件系统包含的资源索引集合。 /// /// 文件系统包含的资源索引集合。 public int[] GetResourceIndexes() { return m_ResourceIndexes; } } } } ================================================ FILE: GameFramework/Resource/PackageVersionList.Resource.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct PackageVersionList { /// /// 资源。 /// [StructLayout(LayoutKind.Auto)] public struct Resource { private static readonly int[] EmptyIntArray = new int[] { }; private readonly string m_Name; private readonly string m_Variant; private readonly string m_Extension; private readonly byte m_LoadType; private readonly int m_Length; private readonly int m_HashCode; private readonly int[] m_AssetIndexes; /// /// 初始化资源的新实例。 /// /// 资源名称。 /// 资源变体名称。 /// 资源扩展名称。 /// 资源加载方式。 /// 资源长度。 /// 资源哈希值。 /// 资源包含的资源索引集合。 public Resource(string name, string variant, string extension, byte loadType, int length, int hashCode, int[] assetIndexes) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_Variant = variant; m_Extension = extension; m_LoadType = loadType; m_Length = length; m_HashCode = hashCode; m_AssetIndexes = assetIndexes ?? EmptyIntArray; } /// /// 获取资源名称。 /// public string Name { get { return m_Name; } } /// /// 获取资源变体名称。 /// public string Variant { get { return m_Variant; } } /// /// 获取资源扩展名称。 /// public string Extension { get { return m_Extension; } } /// /// 获取资源加载方式。 /// public byte LoadType { get { return m_LoadType; } } /// /// 获取资源长度。 /// public int Length { get { return m_Length; } } /// /// 获取资源哈希值。 /// public int HashCode { get { return m_HashCode; } } /// /// 获取资源包含的资源索引集合。 /// /// 资源包含的资源索引集合。 public int[] GetAssetIndexes() { return m_AssetIndexes; } } } } ================================================ FILE: GameFramework/Resource/PackageVersionList.ResourceGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct PackageVersionList { /// /// 资源组。 /// [StructLayout(LayoutKind.Auto)] public struct ResourceGroup { private static readonly int[] EmptyIntArray = new int[] { }; private readonly string m_Name; private readonly int[] m_ResourceIndexes; /// /// 初始化资源组的新实例。 /// /// 资源组名称。 /// 资源组包含的资源索引集合。 public ResourceGroup(string name, int[] resourceIndexes) { if (name == null) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_ResourceIndexes = resourceIndexes ?? EmptyIntArray; } /// /// 获取资源组名称。 /// public string Name { get { return m_Name; } } /// /// 获取资源组包含的资源索引集合。 /// /// 资源组包含的资源索引集合。 public int[] GetResourceIndexes() { return m_ResourceIndexes; } } } } ================================================ FILE: GameFramework/Resource/PackageVersionList.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { /// /// 单机模式版本资源列表。 /// [StructLayout(LayoutKind.Auto)] public partial struct PackageVersionList { private static readonly Asset[] EmptyAssetArray = new Asset[] { }; private static readonly Resource[] EmptyResourceArray = new Resource[] { }; private static readonly FileSystem[] EmptyFileSystemArray = new FileSystem[] { }; private static readonly ResourceGroup[] EmptyResourceGroupArray = new ResourceGroup[] { }; private readonly bool m_IsValid; private readonly string m_ApplicableGameVersion; private readonly int m_InternalResourceVersion; private readonly Asset[] m_Assets; private readonly Resource[] m_Resources; private readonly FileSystem[] m_FileSystems; private readonly ResourceGroup[] m_ResourceGroups; /// /// 初始化单机模式版本资源列表的新实例。 /// /// 适配的游戏版本号。 /// 内部资源版本号。 /// 包含的资源集合。 /// 包含的资源集合。 /// 包含的文件系统集合。 /// 包含的资源组集合。 public PackageVersionList(string applicableGameVersion, int internalResourceVersion, Asset[] assets, Resource[] resources, FileSystem[] fileSystems, ResourceGroup[] resourceGroups) { m_IsValid = true; m_ApplicableGameVersion = applicableGameVersion; m_InternalResourceVersion = internalResourceVersion; m_Assets = assets ?? EmptyAssetArray; m_Resources = resources ?? EmptyResourceArray; m_FileSystems = fileSystems ?? EmptyFileSystemArray; m_ResourceGroups = resourceGroups ?? EmptyResourceGroupArray; } /// /// 获取单机模式版本资源列表是否有效。 /// public bool IsValid { get { return m_IsValid; } } /// /// 获取适配的游戏版本号。 /// public string ApplicableGameVersion { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_ApplicableGameVersion; } } /// /// 获取内部资源版本号。 /// public int InternalResourceVersion { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_InternalResourceVersion; } } /// /// 获取包含的资源集合。 /// /// 包含的资源集合。 public Asset[] GetAssets() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Assets; } /// /// 获取包含的资源集合。 /// /// 包含的资源集合。 public Resource[] GetResources() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Resources; } /// /// 获取包含的文件系统集合。 /// /// 包含的文件系统集合。 public FileSystem[] GetFileSystems() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_FileSystems; } /// /// 获取包含的资源组集合。 /// /// 包含的资源组集合。 public ResourceGroup[] GetResourceGroups() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_ResourceGroups; } } } ================================================ FILE: GameFramework/Resource/PackageVersionListSerializer.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 单机模式版本资源列表序列化器。 /// public sealed class PackageVersionListSerializer : GameFrameworkSerializer { private static readonly byte[] Header = new byte[] { (byte)'G', (byte)'F', (byte)'P' }; /// /// 初始化单机模式版本资源列表序列化器的新实例。 /// public PackageVersionListSerializer() { } /// /// 获取单机模式版本资源列表头标识。 /// /// 单机模式版本资源列表头标识。 protected override byte[] GetHeader() { return Header; } } } ================================================ FILE: GameFramework/Resource/ReadOnlyVersionListSerializer.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 本地只读区版本资源列表序列化器。 /// public sealed class ReadOnlyVersionListSerializer : GameFrameworkSerializer { private static readonly byte[] Header = new byte[] { (byte)'G', (byte)'F', (byte)'R' }; /// /// 初始化本地只读区版本资源列表序列化器的新实例。 /// public ReadOnlyVersionListSerializer() { } /// /// 获取本地只读区版本资源列表头标识。 /// /// 本地只读区版本资源列表头标识。 protected override byte[] GetHeader() { return Header; } } } ================================================ FILE: GameFramework/Resource/ReadWriteVersionListSerializer.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 本地读写区版本资源列表序列化器。 /// public sealed class ReadWriteVersionListSerializer : GameFrameworkSerializer { private static readonly byte[] Header = new byte[] { (byte)'G', (byte)'F', (byte)'W' }; /// /// 初始化本地读写区版本资源列表序列化器的新实例。 /// public ReadWriteVersionListSerializer() { } /// /// 获取本地读写区版本资源列表头标识。 /// /// 本地读写区版本资源列表头标识。 protected override byte[] GetHeader() { return Header; } } } ================================================ FILE: GameFramework/Resource/ResourceApplyFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源应用失败事件。 /// public sealed class ResourceApplyFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化资源应用失败事件的新实例。 /// public ResourceApplyFailureEventArgs() { Name = null; ResourcePackPath = null; ErrorMessage = null; } /// /// 获取资源名称。 /// public string Name { get; private set; } /// /// 获取资源包路径。 /// public string ResourcePackPath { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 创建资源应用失败事件。 /// /// 资源名称。 /// 资源包路径。 /// 错误信息。 /// 创建的资源应用失败事件。 public static ResourceApplyFailureEventArgs Create(string name, string resourcePackPath, string errorMessage) { ResourceApplyFailureEventArgs resourceApplyFailureEventArgs = ReferencePool.Acquire(); resourceApplyFailureEventArgs.Name = name; resourceApplyFailureEventArgs.ResourcePackPath = resourcePackPath; resourceApplyFailureEventArgs.ErrorMessage = errorMessage; return resourceApplyFailureEventArgs; } /// /// 清理资源应用失败事件。 /// public override void Clear() { Name = null; ResourcePackPath = null; ErrorMessage = null; } } } ================================================ FILE: GameFramework/Resource/ResourceApplyStartEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源应用开始事件。 /// public sealed class ResourceApplyStartEventArgs : GameFrameworkEventArgs { /// /// 初始化资源应用开始事件的新实例。 /// public ResourceApplyStartEventArgs() { ResourcePackPath = null; Count = 0; TotalLength = 0L; } /// /// 获取资源包路径。 /// public string ResourcePackPath { get; private set; } /// /// 获取要应用资源的数量。 /// public int Count { get; private set; } /// /// 获取要应用资源的总大小。 /// public long TotalLength { get; private set; } /// /// 创建资源应用开始事件。 /// /// 资源包路径。 /// 要应用资源的数量。 /// 要应用资源的总大小。 /// 创建的资源应用开始事件。 public static ResourceApplyStartEventArgs Create(string resourcePackPath, int count, long totalLength) { ResourceApplyStartEventArgs resourceApplyStartEventArgs = ReferencePool.Acquire(); resourceApplyStartEventArgs.ResourcePackPath = resourcePackPath; resourceApplyStartEventArgs.Count = count; resourceApplyStartEventArgs.TotalLength = totalLength; return resourceApplyStartEventArgs; } /// /// 清理资源应用开始事件。 /// public override void Clear() { ResourcePackPath = null; Count = 0; TotalLength = 0L; } } } ================================================ FILE: GameFramework/Resource/ResourceApplySuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源应用成功事件。 /// public sealed class ResourceApplySuccessEventArgs : GameFrameworkEventArgs { /// /// 初始化资源应用成功事件的新实例。 /// public ResourceApplySuccessEventArgs() { Name = null; ApplyPath = null; ResourcePackPath = null; Length = 0; CompressedLength = 0; } /// /// 获取资源名称。 /// public string Name { get; private set; } /// /// 获取资源应用后存放路径。 /// public string ApplyPath { get; private set; } /// /// 获取资源包路径。 /// public string ResourcePackPath { get; private set; } /// /// 获取资源大小。 /// public int Length { get; private set; } /// /// 获取压缩后大小。 /// public int CompressedLength { get; private set; } /// /// 创建资源应用成功事件。 /// /// 资源名称。 /// 资源应用后存放路径。 /// 资源包路径。 /// 资源大小。 /// 压缩后大小。 /// 创建的资源应用成功事件。 public static ResourceApplySuccessEventArgs Create(string name, string applyPath, string resourcePackPath, int length, int compressedLength) { ResourceApplySuccessEventArgs resourceApplySuccessEventArgs = ReferencePool.Acquire(); resourceApplySuccessEventArgs.Name = name; resourceApplySuccessEventArgs.ApplyPath = applyPath; resourceApplySuccessEventArgs.ResourcePackPath = resourcePackPath; resourceApplySuccessEventArgs.Length = length; resourceApplySuccessEventArgs.CompressedLength = compressedLength; return resourceApplySuccessEventArgs; } /// /// 清理资源应用成功事件。 /// public override void Clear() { Name = null; ApplyPath = null; ResourcePackPath = null; Length = 0; CompressedLength = 0; } } } ================================================ FILE: GameFramework/Resource/ResourceManager.AssetInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源信息。 /// private sealed class AssetInfo { private readonly string m_AssetName; private readonly ResourceName m_ResourceName; private readonly string[] m_DependencyAssetNames; /// /// 初始化资源信息的新实例。 /// /// 资源名称。 /// 所在资源名称。 /// 依赖资源名称。 public AssetInfo(string assetName, ResourceName resourceName, string[] dependencyAssetNames) { m_AssetName = assetName; m_ResourceName = resourceName; m_DependencyAssetNames = dependencyAssetNames; } /// /// 获取资源名称。 /// public string AssetName { get { return m_AssetName; } } /// /// 获取所在资源名称。 /// public ResourceName ResourceName { get { return m_ResourceName; } } /// /// 获取依赖资源名称。 /// /// 依赖资源名称。 public string[] GetDependencyAssetNames() { return m_DependencyAssetNames; } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.LoadType.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源加载方式类型。 /// private enum LoadType : byte { /// /// 使用文件方式加载。 /// LoadFromFile = 0, /// /// 使用内存方式加载。 /// LoadFromMemory, /// /// 使用内存快速解密方式加载。 /// LoadFromMemoryAndQuickDecrypt, /// /// 使用内存解密方式加载。 /// LoadFromMemoryAndDecrypt, /// /// 使用二进制方式加载。 /// LoadFromBinary, /// /// 使用二进制快速解密方式加载。 /// LoadFromBinaryAndQuickDecrypt, /// /// 使用二进制解密方式加载。 /// LoadFromBinaryAndDecrypt } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ReadWriteResourceInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { [StructLayout(LayoutKind.Auto)] private struct ReadWriteResourceInfo { private readonly string m_FileSystemName; private readonly LoadType m_LoadType; private readonly int m_Length; private readonly int m_HashCode; public ReadWriteResourceInfo(string fileSystemName, LoadType loadType, int length, int hashCode) { m_FileSystemName = fileSystemName; m_LoadType = loadType; m_Length = length; m_HashCode = hashCode; } public bool UseFileSystem { get { return !string.IsNullOrEmpty(m_FileSystemName); } } public string FileSystemName { get { return m_FileSystemName; } } public LoadType LoadType { get { return m_LoadType; } } public int Length { get { return m_Length; } } public int HashCode { get { return m_HashCode; } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceChecker.CheckInfo.CheckStatus.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceChecker { private sealed partial class CheckInfo { /// /// 资源检查状态。 /// public enum CheckStatus : byte { /// /// 资源状态未知。 /// Unknown = 0, /// /// 资源存在且已存放于只读区中。 /// StorageInReadOnly, /// /// 资源存在且已存放于读写区中。 /// StorageInReadWrite, /// /// 资源不适用于当前变体。 /// Unavailable, /// /// 资源需要更新。 /// Update, /// /// 资源已废弃。 /// Disuse } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceChecker.CheckInfo.LocalVersionInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceChecker { private sealed partial class CheckInfo { /// /// 本地资源状态信息。 /// [StructLayout(LayoutKind.Auto)] private struct LocalVersionInfo { private readonly bool m_Exist; private readonly string m_FileSystemName; private readonly LoadType m_LoadType; private readonly int m_Length; private readonly int m_HashCode; public LocalVersionInfo(string fileSystemName, LoadType loadType, int length, int hashCode) { m_Exist = true; m_FileSystemName = fileSystemName; m_LoadType = loadType; m_Length = length; m_HashCode = hashCode; } public bool Exist { get { return m_Exist; } } public bool UseFileSystem { get { return !string.IsNullOrEmpty(m_FileSystemName); } } public string FileSystemName { get { return m_FileSystemName; } } public LoadType LoadType { get { return m_LoadType; } } public int Length { get { return m_Length; } } public int HashCode { get { return m_HashCode; } } } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceChecker.CheckInfo.RemoteVersionInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceChecker { private sealed partial class CheckInfo { /// /// 远程资源状态信息。 /// [StructLayout(LayoutKind.Auto)] private struct RemoteVersionInfo { private readonly bool m_Exist; private readonly string m_FileSystemName; private readonly LoadType m_LoadType; private readonly int m_Length; private readonly int m_HashCode; private readonly int m_CompressedLength; private readonly int m_CompressedHashCode; public RemoteVersionInfo(string fileSystemName, LoadType loadType, int length, int hashCode, int compressedLength, int compressedHashCode) { m_Exist = true; m_FileSystemName = fileSystemName; m_LoadType = loadType; m_Length = length; m_HashCode = hashCode; m_CompressedLength = compressedLength; m_CompressedHashCode = compressedHashCode; } public bool Exist { get { return m_Exist; } } public bool UseFileSystem { get { return !string.IsNullOrEmpty(m_FileSystemName); } } public string FileSystemName { get { return m_FileSystemName; } } public LoadType LoadType { get { return m_LoadType; } } public int Length { get { return m_Length; } } public int HashCode { get { return m_HashCode; } } public int CompressedLength { get { return m_CompressedLength; } } public int CompressedHashCode { get { return m_CompressedHashCode; } } } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceChecker.CheckInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceChecker { /// /// 资源检查信息。 /// private sealed partial class CheckInfo { private readonly ResourceName m_ResourceName; private CheckStatus m_Status; private bool m_NeedRemove; private bool m_NeedMoveToDisk; private bool m_NeedMoveToFileSystem; private RemoteVersionInfo m_VersionInfo; private LocalVersionInfo m_ReadOnlyInfo; private LocalVersionInfo m_ReadWriteInfo; private string m_CachedFileSystemName; /// /// 初始化资源检查信息的新实例。 /// /// 资源名称。 public CheckInfo(ResourceName resourceName) { m_ResourceName = resourceName; m_Status = CheckStatus.Unknown; m_NeedRemove = false; m_NeedMoveToDisk = false; m_NeedMoveToFileSystem = false; m_VersionInfo = default(RemoteVersionInfo); m_ReadOnlyInfo = default(LocalVersionInfo); m_ReadWriteInfo = default(LocalVersionInfo); m_CachedFileSystemName = null; } /// /// 获取资源名称。 /// public ResourceName ResourceName { get { return m_ResourceName; } } /// /// 获取资源检查状态。 /// public CheckStatus Status { get { return m_Status; } } /// /// 获取是否需要移除读写区的资源。 /// public bool NeedRemove { get { return m_NeedRemove; } } /// /// 获取是否需要将读写区的资源移动到磁盘。 /// public bool NeedMoveToDisk { get { return m_NeedMoveToDisk; } } /// /// 获取是否需要将读写区的资源移动到文件系统。 /// public bool NeedMoveToFileSystem { get { return m_NeedMoveToFileSystem; } } /// /// 获取资源所在的文件系统名称。 /// public string FileSystemName { get { return m_VersionInfo.FileSystemName; } } /// /// 获取资源是否使用文件系统。 /// public bool ReadWriteUseFileSystem { get { return m_ReadWriteInfo.UseFileSystem; } } /// /// 获取读写资源所在的文件系统名称。 /// public string ReadWriteFileSystemName { get { return m_ReadWriteInfo.FileSystemName; } } /// /// 获取资源加载方式。 /// public LoadType LoadType { get { return m_VersionInfo.LoadType; } } /// /// 获取资源大小。 /// public int Length { get { return m_VersionInfo.Length; } } /// /// 获取资源哈希值。 /// public int HashCode { get { return m_VersionInfo.HashCode; } } /// /// 获取压缩后大小。 /// public int CompressedLength { get { return m_VersionInfo.CompressedLength; } } /// /// 获取压缩后哈希值。 /// public int CompressedHashCode { get { return m_VersionInfo.CompressedHashCode; } } /// /// 临时缓存资源所在的文件系统名称。 /// /// 资源所在的文件系统名称。 public void SetCachedFileSystemName(string fileSystemName) { m_CachedFileSystemName = fileSystemName; } /// /// 设置资源在版本中的信息。 /// /// 资源加载方式。 /// 资源大小。 /// 资源哈希值。 /// 压缩后大小。 /// 压缩后哈希值。 public void SetVersionInfo(LoadType loadType, int length, int hashCode, int compressedLength, int compressedHashCode) { if (m_VersionInfo.Exist) { throw new GameFrameworkException(Utility.Text.Format("You must set version info of '{0}' only once.", m_ResourceName.FullName)); } m_VersionInfo = new RemoteVersionInfo(m_CachedFileSystemName, loadType, length, hashCode, compressedLength, compressedHashCode); m_CachedFileSystemName = null; } /// /// 设置资源在只读区中的信息。 /// /// 资源加载方式。 /// 资源大小。 /// 资源哈希值。 public void SetReadOnlyInfo(LoadType loadType, int length, int hashCode) { if (m_ReadOnlyInfo.Exist) { throw new GameFrameworkException(Utility.Text.Format("You must set read-only info of '{0}' only once.", m_ResourceName.FullName)); } m_ReadOnlyInfo = new LocalVersionInfo(m_CachedFileSystemName, loadType, length, hashCode); m_CachedFileSystemName = null; } /// /// 设置资源在读写区中的信息。 /// /// 资源加载方式。 /// 资源大小。 /// 资源哈希值。 public void SetReadWriteInfo(LoadType loadType, int length, int hashCode) { if (m_ReadWriteInfo.Exist) { throw new GameFrameworkException(Utility.Text.Format("You must set read-write info of '{0}' only once.", m_ResourceName.FullName)); } m_ReadWriteInfo = new LocalVersionInfo(m_CachedFileSystemName, loadType, length, hashCode); m_CachedFileSystemName = null; } /// /// 刷新资源信息状态。 /// /// 当前变体。 /// 是否忽略处理其它变体的资源,若不忽略则移除。 public void RefreshStatus(string currentVariant, bool ignoreOtherVariant) { if (!m_VersionInfo.Exist) { m_Status = CheckStatus.Disuse; m_NeedRemove = m_ReadWriteInfo.Exist; return; } if (m_ResourceName.Variant == null || m_ResourceName.Variant == currentVariant) { if (m_ReadOnlyInfo.Exist && m_ReadOnlyInfo.FileSystemName == m_VersionInfo.FileSystemName && m_ReadOnlyInfo.LoadType == m_VersionInfo.LoadType && m_ReadOnlyInfo.Length == m_VersionInfo.Length && m_ReadOnlyInfo.HashCode == m_VersionInfo.HashCode) { m_Status = CheckStatus.StorageInReadOnly; m_NeedRemove = m_ReadWriteInfo.Exist; } else if (m_ReadWriteInfo.Exist && m_ReadWriteInfo.LoadType == m_VersionInfo.LoadType && m_ReadWriteInfo.Length == m_VersionInfo.Length && m_ReadWriteInfo.HashCode == m_VersionInfo.HashCode) { bool differentFileSystem = m_ReadWriteInfo.FileSystemName != m_VersionInfo.FileSystemName; m_Status = CheckStatus.StorageInReadWrite; m_NeedMoveToDisk = m_ReadWriteInfo.UseFileSystem && differentFileSystem; m_NeedMoveToFileSystem = m_VersionInfo.UseFileSystem && differentFileSystem; } else { m_Status = CheckStatus.Update; m_NeedRemove = m_ReadWriteInfo.Exist; } } else { m_Status = CheckStatus.Unavailable; m_NeedRemove = !ignoreOtherVariant && m_ReadWriteInfo.Exist; } } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceChecker.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.FileSystem; using System; using System.Collections.Generic; using System.IO; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源检查器。 /// private sealed partial class ResourceChecker { private readonly ResourceManager m_ResourceManager; private readonly Dictionary m_CheckInfos; private string m_CurrentVariant; private bool m_IgnoreOtherVariant; private bool m_UpdatableVersionListReady; private bool m_ReadOnlyVersionListReady; private bool m_ReadWriteVersionListReady; public GameFrameworkAction ResourceNeedUpdate; public GameFrameworkAction ResourceCheckComplete; /// /// 初始化资源检查器的新实例。 /// /// 资源管理器。 public ResourceChecker(ResourceManager resourceManager) { m_ResourceManager = resourceManager; m_CheckInfos = new Dictionary(); m_CurrentVariant = null; m_IgnoreOtherVariant = false; m_UpdatableVersionListReady = false; m_ReadOnlyVersionListReady = false; m_ReadWriteVersionListReady = false; ResourceNeedUpdate = null; ResourceCheckComplete = null; } /// /// 关闭并清理资源检查器。 /// public void Shutdown() { m_CheckInfos.Clear(); } /// /// 检查资源。 /// /// 当前使用的变体。 /// 是否忽略处理其它变体的资源,若不忽略,将会移除其它变体的资源。 public void CheckResources(string currentVariant, bool ignoreOtherVariant) { if (m_ResourceManager.m_ResourceHelper == null) { throw new GameFrameworkException("Resource helper is invalid."); } if (string.IsNullOrEmpty(m_ResourceManager.m_ReadOnlyPath)) { throw new GameFrameworkException("Read-only path is invalid."); } if (string.IsNullOrEmpty(m_ResourceManager.m_ReadWritePath)) { throw new GameFrameworkException("Read-write path is invalid."); } m_CurrentVariant = currentVariant; m_IgnoreOtherVariant = ignoreOtherVariant; m_ResourceManager.m_ResourceHelper.LoadBytes(Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_ReadWritePath, RemoteVersionListFileName)), new LoadBytesCallbacks(OnLoadUpdatableVersionListSuccess, OnLoadUpdatableVersionListFailure), null); m_ResourceManager.m_ResourceHelper.LoadBytes(Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_ReadOnlyPath, LocalVersionListFileName)), new LoadBytesCallbacks(OnLoadReadOnlyVersionListSuccess, OnLoadReadOnlyVersionListFailure), null); m_ResourceManager.m_ResourceHelper.LoadBytes(Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_ReadWritePath, LocalVersionListFileName)), new LoadBytesCallbacks(OnLoadReadWriteVersionListSuccess, OnLoadReadWriteVersionListFailure), null); } private void SetCachedFileSystemName(ResourceName resourceName, string fileSystemName) { GetOrAddCheckInfo(resourceName).SetCachedFileSystemName(fileSystemName); } private void SetVersionInfo(ResourceName resourceName, LoadType loadType, int length, int hashCode, int compressedLength, int compressedHashCode) { GetOrAddCheckInfo(resourceName).SetVersionInfo(loadType, length, hashCode, compressedLength, compressedHashCode); } private void SetReadOnlyInfo(ResourceName resourceName, LoadType loadType, int length, int hashCode) { GetOrAddCheckInfo(resourceName).SetReadOnlyInfo(loadType, length, hashCode); } private void SetReadWriteInfo(ResourceName resourceName, LoadType loadType, int length, int hashCode) { GetOrAddCheckInfo(resourceName).SetReadWriteInfo(loadType, length, hashCode); } private CheckInfo GetOrAddCheckInfo(ResourceName resourceName) { CheckInfo checkInfo = null; if (m_CheckInfos.TryGetValue(resourceName, out checkInfo)) { return checkInfo; } checkInfo = new CheckInfo(resourceName); m_CheckInfos.Add(checkInfo.ResourceName, checkInfo); return checkInfo; } private void RefreshCheckInfoStatus() { if (!m_UpdatableVersionListReady || !m_ReadOnlyVersionListReady || !m_ReadWriteVersionListReady) { return; } int movedCount = 0; int removedCount = 0; int updateCount = 0; long updateTotalLength = 0L; long updateTotalCompressedLength = 0L; foreach (KeyValuePair checkInfo in m_CheckInfos) { CheckInfo ci = checkInfo.Value; ci.RefreshStatus(m_CurrentVariant, m_IgnoreOtherVariant); if (ci.Status == CheckInfo.CheckStatus.StorageInReadOnly) { m_ResourceManager.m_ResourceInfos.Add(ci.ResourceName, new ResourceInfo(ci.ResourceName, ci.FileSystemName, ci.LoadType, ci.Length, ci.HashCode, ci.CompressedLength, true, true)); } else if (ci.Status == CheckInfo.CheckStatus.StorageInReadWrite) { if (ci.NeedMoveToDisk || ci.NeedMoveToFileSystem) { movedCount++; string resourceFullName = ci.ResourceName.FullName; string resourcePath = Utility.Path.GetRegularPath(Path.Combine(m_ResourceManager.m_ReadWritePath, resourceFullName)); if (ci.NeedMoveToDisk) { IFileSystem fileSystem = m_ResourceManager.GetFileSystem(ci.ReadWriteFileSystemName, false); if (!fileSystem.SaveAsFile(resourceFullName, resourcePath)) { throw new GameFrameworkException(Utility.Text.Format("Save as file '{0}' to '{1}' from file system '{2}' error.", resourceFullName, resourcePath, fileSystem.FullPath)); } fileSystem.DeleteFile(resourceFullName); } if (ci.NeedMoveToFileSystem) { IFileSystem fileSystem = m_ResourceManager.GetFileSystem(ci.FileSystemName, false); if (!fileSystem.WriteFile(resourceFullName, resourcePath)) { throw new GameFrameworkException(Utility.Text.Format("Write resource '{0}' to file system '{1}' error.", resourceFullName, fileSystem.FullPath)); } if (File.Exists(resourcePath)) { File.Delete(resourcePath); } } } m_ResourceManager.m_ResourceInfos.Add(ci.ResourceName, new ResourceInfo(ci.ResourceName, ci.FileSystemName, ci.LoadType, ci.Length, ci.HashCode, ci.CompressedLength, false, true)); m_ResourceManager.m_ReadWriteResourceInfos.Add(ci.ResourceName, new ReadWriteResourceInfo(ci.FileSystemName, ci.LoadType, ci.Length, ci.HashCode)); } else if (ci.Status == CheckInfo.CheckStatus.Update) { m_ResourceManager.m_ResourceInfos.Add(ci.ResourceName, new ResourceInfo(ci.ResourceName, ci.FileSystemName, ci.LoadType, ci.Length, ci.HashCode, ci.CompressedLength, false, false)); updateCount++; updateTotalLength += ci.Length; updateTotalCompressedLength += ci.CompressedLength; if (ResourceNeedUpdate != null) { ResourceNeedUpdate(ci.ResourceName, ci.FileSystemName, ci.LoadType, ci.Length, ci.HashCode, ci.CompressedLength, ci.CompressedHashCode); } } else if (ci.Status == CheckInfo.CheckStatus.Unavailable || ci.Status == CheckInfo.CheckStatus.Disuse) { // Do nothing. } else { throw new GameFrameworkException(Utility.Text.Format("Check resources '{0}' error with unknown status.", ci.ResourceName.FullName)); } if (ci.NeedRemove) { removedCount++; if (ci.ReadWriteUseFileSystem) { IFileSystem fileSystem = m_ResourceManager.GetFileSystem(ci.ReadWriteFileSystemName, false); fileSystem.DeleteFile(ci.ResourceName.FullName); } else { string resourcePath = Utility.Path.GetRegularPath(Path.Combine(m_ResourceManager.m_ReadWritePath, ci.ResourceName.FullName)); if (File.Exists(resourcePath)) { File.Delete(resourcePath); } } } } if (movedCount > 0 || removedCount > 0) { RemoveEmptyFileSystems(); Utility.Path.RemoveEmptyDirectory(m_ResourceManager.m_ReadWritePath); } if (ResourceCheckComplete != null) { ResourceCheckComplete(movedCount, removedCount, updateCount, updateTotalLength, updateTotalCompressedLength); } } private void RemoveEmptyFileSystems() { List removedFileSystemNames = null; foreach (KeyValuePair fileSystem in m_ResourceManager.m_ReadWriteFileSystems) { if (fileSystem.Value.FileCount <= 0) { if (removedFileSystemNames == null) { removedFileSystemNames = new List(); } m_ResourceManager.m_FileSystemManager.DestroyFileSystem(fileSystem.Value, true); removedFileSystemNames.Add(fileSystem.Key); } } if (removedFileSystemNames != null) { foreach (string removedFileSystemName in removedFileSystemNames) { m_ResourceManager.m_ReadWriteFileSystems.Remove(removedFileSystemName); } } } private void OnLoadUpdatableVersionListSuccess(string fileUri, byte[] bytes, float duration, object userData) { if (m_UpdatableVersionListReady) { throw new GameFrameworkException("Updatable version list has been parsed."); } MemoryStream memoryStream = null; try { memoryStream = new MemoryStream(bytes, false); UpdatableVersionList versionList = m_ResourceManager.m_UpdatableVersionListSerializer.Deserialize(memoryStream); if (!versionList.IsValid) { throw new GameFrameworkException("Deserialize updatable version list failure."); } UpdatableVersionList.Asset[] assets = versionList.GetAssets(); UpdatableVersionList.Resource[] resources = versionList.GetResources(); UpdatableVersionList.FileSystem[] fileSystems = versionList.GetFileSystems(); UpdatableVersionList.ResourceGroup[] resourceGroups = versionList.GetResourceGroups(); m_ResourceManager.m_ApplicableGameVersion = versionList.ApplicableGameVersion; m_ResourceManager.m_InternalResourceVersion = versionList.InternalResourceVersion; m_ResourceManager.m_AssetInfos = new Dictionary(assets.Length, StringComparer.Ordinal); m_ResourceManager.m_ResourceInfos = new Dictionary(resources.Length, new ResourceNameComparer()); m_ResourceManager.m_ReadWriteResourceInfos = new SortedDictionary(new ResourceNameComparer()); ResourceGroup defaultResourceGroup = m_ResourceManager.GetOrAddResourceGroup(string.Empty); foreach (UpdatableVersionList.FileSystem fileSystem in fileSystems) { int[] resourceIndexes = fileSystem.GetResourceIndexes(); foreach (int resourceIndex in resourceIndexes) { UpdatableVersionList.Resource resource = resources[resourceIndex]; if (resource.Variant != null && resource.Variant != m_CurrentVariant) { continue; } SetCachedFileSystemName(new ResourceName(resource.Name, resource.Variant, resource.Extension), fileSystem.Name); } } foreach (UpdatableVersionList.Resource resource in resources) { if (resource.Variant != null && resource.Variant != m_CurrentVariant) { continue; } ResourceName resourceName = new ResourceName(resource.Name, resource.Variant, resource.Extension); int[] assetIndexes = resource.GetAssetIndexes(); foreach (int assetIndex in assetIndexes) { UpdatableVersionList.Asset asset = assets[assetIndex]; int[] dependencyAssetIndexes = asset.GetDependencyAssetIndexes(); int index = 0; string[] dependencyAssetNames = new string[dependencyAssetIndexes.Length]; foreach (int dependencyAssetIndex in dependencyAssetIndexes) { dependencyAssetNames[index++] = assets[dependencyAssetIndex].Name; } m_ResourceManager.m_AssetInfos.Add(asset.Name, new AssetInfo(asset.Name, resourceName, dependencyAssetNames)); } SetVersionInfo(resourceName, (LoadType)resource.LoadType, resource.Length, resource.HashCode, resource.CompressedLength, resource.CompressedHashCode); defaultResourceGroup.AddResource(resourceName, resource.Length, resource.CompressedLength); } foreach (UpdatableVersionList.ResourceGroup resourceGroup in resourceGroups) { ResourceGroup group = m_ResourceManager.GetOrAddResourceGroup(resourceGroup.Name); int[] resourceIndexes = resourceGroup.GetResourceIndexes(); foreach (int resourceIndex in resourceIndexes) { UpdatableVersionList.Resource resource = resources[resourceIndex]; if (resource.Variant != null && resource.Variant != m_CurrentVariant) { continue; } group.AddResource(new ResourceName(resource.Name, resource.Variant, resource.Extension), resource.Length, resource.CompressedLength); } } m_UpdatableVersionListReady = true; RefreshCheckInfoStatus(); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Utility.Text.Format("Parse updatable version list exception '{0}'.", exception), exception); } finally { if (memoryStream != null) { memoryStream.Dispose(); memoryStream = null; } } } private void OnLoadUpdatableVersionListFailure(string fileUri, string errorMessage, object userData) { throw new GameFrameworkException(Utility.Text.Format("Updatable version list '{0}' is invalid, error message is '{1}'.", fileUri, string.IsNullOrEmpty(errorMessage) ? "" : errorMessage)); } private void OnLoadReadOnlyVersionListSuccess(string fileUri, byte[] bytes, float duration, object userData) { if (m_ReadOnlyVersionListReady) { throw new GameFrameworkException("Read-only version list has been parsed."); } MemoryStream memoryStream = null; try { memoryStream = new MemoryStream(bytes, false); LocalVersionList versionList = m_ResourceManager.m_ReadOnlyVersionListSerializer.Deserialize(memoryStream); if (!versionList.IsValid) { throw new GameFrameworkException("Deserialize read-only version list failure."); } LocalVersionList.Resource[] resources = versionList.GetResources(); LocalVersionList.FileSystem[] fileSystems = versionList.GetFileSystems(); foreach (LocalVersionList.FileSystem fileSystem in fileSystems) { int[] resourceIndexes = fileSystem.GetResourceIndexes(); foreach (int resourceIndex in resourceIndexes) { LocalVersionList.Resource resource = resources[resourceIndex]; SetCachedFileSystemName(new ResourceName(resource.Name, resource.Variant, resource.Extension), fileSystem.Name); } } foreach (LocalVersionList.Resource resource in resources) { SetReadOnlyInfo(new ResourceName(resource.Name, resource.Variant, resource.Extension), (LoadType)resource.LoadType, resource.Length, resource.HashCode); } m_ReadOnlyVersionListReady = true; RefreshCheckInfoStatus(); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Utility.Text.Format("Parse read-only version list exception '{0}'.", exception), exception); } finally { if (memoryStream != null) { memoryStream.Dispose(); memoryStream = null; } } } private void OnLoadReadOnlyVersionListFailure(string fileUri, string errorMessage, object userData) { if (m_ReadOnlyVersionListReady) { throw new GameFrameworkException("Read-only version list has been parsed."); } m_ReadOnlyVersionListReady = true; RefreshCheckInfoStatus(); } private void OnLoadReadWriteVersionListSuccess(string fileUri, byte[] bytes, float duration, object userData) { if (m_ReadWriteVersionListReady) { throw new GameFrameworkException("Read-write version list has been parsed."); } MemoryStream memoryStream = null; try { memoryStream = new MemoryStream(bytes, false); LocalVersionList versionList = m_ResourceManager.m_ReadWriteVersionListSerializer.Deserialize(memoryStream); if (!versionList.IsValid) { throw new GameFrameworkException("Deserialize read-write version list failure."); } LocalVersionList.Resource[] resources = versionList.GetResources(); LocalVersionList.FileSystem[] fileSystems = versionList.GetFileSystems(); foreach (LocalVersionList.FileSystem fileSystem in fileSystems) { int[] resourceIndexes = fileSystem.GetResourceIndexes(); foreach (int resourceIndex in resourceIndexes) { LocalVersionList.Resource resource = resources[resourceIndex]; SetCachedFileSystemName(new ResourceName(resource.Name, resource.Variant, resource.Extension), fileSystem.Name); } } foreach (LocalVersionList.Resource resource in resources) { SetReadWriteInfo(new ResourceName(resource.Name, resource.Variant, resource.Extension), (LoadType)resource.LoadType, resource.Length, resource.HashCode); } m_ReadWriteVersionListReady = true; RefreshCheckInfoStatus(); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Utility.Text.Format("Parse read-write version list exception '{0}'.", exception), exception); } finally { if (memoryStream != null) { memoryStream.Dispose(); memoryStream = null; } } } private void OnLoadReadWriteVersionListFailure(string fileUri, string errorMessage, object userData) { if (m_ReadWriteVersionListReady) { throw new GameFrameworkException("Read-write version list has been parsed."); } m_ReadWriteVersionListReady = true; RefreshCheckInfoStatus(); } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源组。 /// private sealed class ResourceGroup : IResourceGroup { private readonly string m_Name; private readonly Dictionary m_ResourceInfos; private readonly HashSet m_ResourceNames; private long m_TotalLength; private long m_TotalCompressedLength; /// /// 初始化资源组的新实例。 /// /// 资源组名称。 /// 资源信息引用。 public ResourceGroup(string name, Dictionary resourceInfos) { if (name == null) { throw new GameFrameworkException("Name is invalid."); } if (resourceInfos == null) { throw new GameFrameworkException("Resource infos is invalid."); } m_Name = name; m_ResourceInfos = resourceInfos; m_ResourceNames = new HashSet(); } /// /// 获取资源组名称。 /// public string Name { get { return m_Name; } } /// /// 获取资源组是否准备完毕。 /// public bool Ready { get { return ReadyCount >= TotalCount; } } /// /// 获取资源组包含资源数量。 /// public int TotalCount { get { return m_ResourceNames.Count; } } /// /// 获取资源组中已准备完成资源数量。 /// public int ReadyCount { get { int readyCount = 0; foreach (ResourceName resourceName in m_ResourceNames) { ResourceInfo resourceInfo = null; if (m_ResourceInfos.TryGetValue(resourceName, out resourceInfo) && resourceInfo.Ready) { readyCount++; } } return readyCount; } } /// /// 获取资源组包含资源的总大小。 /// public long TotalLength { get { return m_TotalLength; } } /// /// 获取资源组包含资源压缩后的总大小。 /// public long TotalCompressedLength { get { return m_TotalCompressedLength; } } /// /// 获取资源组中已准备完成资源的总大小。 /// public long ReadyLength { get { long readyLength = 0L; foreach (ResourceName resourceName in m_ResourceNames) { ResourceInfo resourceInfo = null; if (m_ResourceInfos.TryGetValue(resourceName, out resourceInfo) && resourceInfo.Ready) { readyLength += resourceInfo.Length; } } return readyLength; } } /// /// 获取资源组中已准备完成资源压缩后的总大小。 /// public long ReadyCompressedLength { get { long readyCompressedLength = 0L; foreach (ResourceName resourceName in m_ResourceNames) { ResourceInfo resourceInfo = null; if (m_ResourceInfos.TryGetValue(resourceName, out resourceInfo) && resourceInfo.Ready) { readyCompressedLength += resourceInfo.CompressedLength; } } return readyCompressedLength; } } /// /// 获取资源组的完成进度。 /// public float Progress { get { return m_TotalLength > 0L ? (float)ReadyLength / m_TotalLength : 1f; } } /// /// 获取资源组包含的资源名称列表。 /// /// 资源组包含的资源名称列表。 public string[] GetResourceNames() { int index = 0; string[] resourceNames = new string[m_ResourceNames.Count]; foreach (ResourceName resourceName in m_ResourceNames) { resourceNames[index++] = resourceName.FullName; } return resourceNames; } /// /// 获取资源组包含的资源名称列表。 /// /// 资源组包含的资源名称列表。 public void GetResourceNames(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (ResourceName resourceName in m_ResourceNames) { results.Add(resourceName.FullName); } } /// /// 获取资源组包含的资源名称列表。 /// /// 资源组包含的资源名称列表。 public ResourceName[] InternalGetResourceNames() { int index = 0; ResourceName[] resourceNames = new ResourceName[m_ResourceNames.Count]; foreach (ResourceName resourceName in m_ResourceNames) { resourceNames[index++] = resourceName; } return resourceNames; } /// /// 获取资源组包含的资源名称列表。 /// /// 资源组包含的资源名称列表。 public void InternalGetResourceNames(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (ResourceName resourceName in m_ResourceNames) { results.Add(resourceName); } } /// /// 检查指定资源是否属于资源组。 /// /// 要检查的资源的名称。 /// 指定资源是否属于资源组。 public bool HasResource(ResourceName resourceName) { return m_ResourceNames.Contains(resourceName); } /// /// 向资源组中增加资源。 /// /// 资源名称。 /// 资源大小。 /// 资源压缩后的大小。 public void AddResource(ResourceName resourceName, int length, int compressedLength) { m_ResourceNames.Add(resourceName); m_TotalLength += length; m_TotalCompressedLength += compressedLength; } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceGroupCollection.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源组集合。 /// private sealed class ResourceGroupCollection : IResourceGroupCollection { private readonly ResourceGroup[] m_ResourceGroups; private readonly Dictionary m_ResourceInfos; private readonly HashSet m_ResourceNames; private long m_TotalLength; private long m_TotalCompressedLength; /// /// 初始化资源组集合的新实例。 /// /// 资源组集合。 /// 资源信息引用。 public ResourceGroupCollection(ResourceGroup[] resourceGroups, Dictionary resourceInfos) { if (resourceGroups == null || resourceGroups.Length < 1) { throw new GameFrameworkException("Resource groups is invalid."); } if (resourceInfos == null) { throw new GameFrameworkException("Resource infos is invalid."); } int lastIndex = resourceGroups.Length - 1; for (int i = 0; i < lastIndex; i++) { if (resourceGroups[i] == null) { throw new GameFrameworkException(Utility.Text.Format("Resource group index '{0}' is invalid.", i)); } for (int j = i + 1; j < resourceGroups.Length; j++) { if (resourceGroups[i] == resourceGroups[j]) { throw new GameFrameworkException(Utility.Text.Format("Resource group '{0}' duplicated.", resourceGroups[i].Name)); } } } if (resourceGroups[lastIndex] == null) { throw new GameFrameworkException(Utility.Text.Format("Resource group index '{0}' is invalid.", lastIndex)); } m_ResourceGroups = resourceGroups; m_ResourceInfos = resourceInfos; m_ResourceNames = new HashSet(); m_TotalLength = 0L; m_TotalCompressedLength = 0L; List cachedResourceNames = new List(); foreach (ResourceGroup resourceGroup in m_ResourceGroups) { resourceGroup.InternalGetResourceNames(cachedResourceNames); foreach (ResourceName resourceName in cachedResourceNames) { ResourceInfo resourceInfo = null; if (!m_ResourceInfos.TryGetValue(resourceName, out resourceInfo)) { throw new GameFrameworkException(Utility.Text.Format("Resource info '{0}' is invalid.", resourceName.FullName)); } if (m_ResourceNames.Add(resourceName)) { m_TotalLength += resourceInfo.Length; m_TotalCompressedLength += resourceInfo.CompressedLength; } } } } /// /// 获取资源组集合是否准备完毕。 /// public bool Ready { get { return ReadyCount >= TotalCount; } } /// /// 获取资源组集合包含资源数量。 /// public int TotalCount { get { return m_ResourceNames.Count; } } /// /// 获取资源组集合中已准备完成资源数量。 /// public int ReadyCount { get { int readyCount = 0; foreach (ResourceName resourceName in m_ResourceNames) { ResourceInfo resourceInfo = null; if (m_ResourceInfos.TryGetValue(resourceName, out resourceInfo) && resourceInfo.Ready) { readyCount++; } } return readyCount; } } /// /// 获取资源组集合包含资源的总大小。 /// public long TotalLength { get { return m_TotalLength; } } /// /// 获取资源组集合包含资源压缩后的总大小。 /// public long TotalCompressedLength { get { return m_TotalCompressedLength; } } /// /// 获取资源组集合中已准备完成资源的总大小。 /// public long ReadyLength { get { long readyLength = 0L; foreach (ResourceName resourceName in m_ResourceNames) { ResourceInfo resourceInfo = null; if (m_ResourceInfos.TryGetValue(resourceName, out resourceInfo) && resourceInfo.Ready) { readyLength += resourceInfo.Length; } } return readyLength; } } /// /// 获取资源组集合中已准备完成资源压缩后的总大小。 /// public long ReadyCompressedLength { get { long readyCompressedLength = 0L; foreach (ResourceName resourceName in m_ResourceNames) { ResourceInfo resourceInfo = null; if (m_ResourceInfos.TryGetValue(resourceName, out resourceInfo) && resourceInfo.Ready) { readyCompressedLength += resourceInfo.CompressedLength; } } return readyCompressedLength; } } /// /// 获取资源组集合的完成进度。 /// public float Progress { get { return m_TotalLength > 0L ? (float)ReadyLength / m_TotalLength : 1f; } } /// /// 获取资源组集合包含的资源组列表。 /// /// 资源组包含的资源名称列表。 public IResourceGroup[] GetResourceGroups() { return m_ResourceGroups; } /// /// 获取资源组集合包含的资源名称列表。 /// /// 资源组包含的资源名称列表。 public string[] GetResourceNames() { int index = 0; string[] resourceNames = new string[m_ResourceNames.Count]; foreach (ResourceName resourceName in m_ResourceNames) { resourceNames[index++] = resourceName.FullName; } return resourceNames; } /// /// 获取资源组集合包含的资源名称列表。 /// /// 资源组包含的资源名称列表。 public void GetResourceNames(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (ResourceName resourceName in m_ResourceNames) { results.Add(resourceName.FullName); } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源信息。 /// private sealed class ResourceInfo { private readonly ResourceName m_ResourceName; private readonly string m_FileSystemName; private readonly LoadType m_LoadType; private readonly int m_Length; private readonly int m_HashCode; private readonly int m_CompressedLength; private readonly bool m_StorageInReadOnly; private bool m_Ready; /// /// 初始化资源信息的新实例。 /// /// 资源名称。 /// 文件系统名称。 /// 资源加载方式。 /// 资源大小。 /// 资源哈希值。 /// 压缩后资源大小。 /// 资源是否在只读区。 /// 资源是否准备完毕。 public ResourceInfo(ResourceName resourceName, string fileSystemName, LoadType loadType, int length, int hashCode, int compressedLength, bool storageInReadOnly, bool ready) { m_ResourceName = resourceName; m_FileSystemName = fileSystemName; m_LoadType = loadType; m_Length = length; m_HashCode = hashCode; m_CompressedLength = compressedLength; m_StorageInReadOnly = storageInReadOnly; m_Ready = ready; } /// /// 获取资源名称。 /// public ResourceName ResourceName { get { return m_ResourceName; } } /// /// 获取资源是否使用文件系统。 /// public bool UseFileSystem { get { return !string.IsNullOrEmpty(m_FileSystemName); } } /// /// 获取文件系统名称。 /// public string FileSystemName { get { return m_FileSystemName; } } /// /// 获取资源是否通过二进制方式加载。 /// public bool IsLoadFromBinary { get { return m_LoadType == LoadType.LoadFromBinary || m_LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || m_LoadType == LoadType.LoadFromBinaryAndDecrypt; } } /// /// 获取资源加载方式。 /// public LoadType LoadType { get { return m_LoadType; } } /// /// 获取资源大小。 /// public int Length { get { return m_Length; } } /// /// 获取资源哈希值。 /// public int HashCode { get { return m_HashCode; } } /// /// 获取压缩后资源大小。 /// public int CompressedLength { get { return m_CompressedLength; } } /// /// 获取资源是否在只读区。 /// public bool StorageInReadOnly { get { return m_StorageInReadOnly; } } /// /// 获取资源是否准备完毕。 /// public bool Ready { get { return m_Ready; } } /// /// 标记资源准备完毕。 /// public void MarkReady() { m_Ready = true; } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceIniter.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; using System.IO; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源初始化器。 /// private sealed class ResourceIniter { private readonly ResourceManager m_ResourceManager; private readonly Dictionary m_CachedFileSystemNames; private string m_CurrentVariant; public GameFrameworkAction ResourceInitComplete; /// /// 初始化资源初始化器的新实例。 /// /// 资源管理器。 public ResourceIniter(ResourceManager resourceManager) { m_ResourceManager = resourceManager; m_CachedFileSystemNames = new Dictionary(); m_CurrentVariant = null; ResourceInitComplete = null; } /// /// 关闭并清理资源初始化器。 /// public void Shutdown() { } /// /// 初始化资源。 /// public void InitResources(string currentVariant) { m_CurrentVariant = currentVariant; if (m_ResourceManager.m_ResourceHelper == null) { throw new GameFrameworkException("Resource helper is invalid."); } if (string.IsNullOrEmpty(m_ResourceManager.m_ReadOnlyPath)) { throw new GameFrameworkException("Read-only path is invalid."); } m_ResourceManager.m_ResourceHelper.LoadBytes(Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_ReadOnlyPath, RemoteVersionListFileName)), new LoadBytesCallbacks(OnLoadPackageVersionListSuccess, OnLoadPackageVersionListFailure), null); } private void OnLoadPackageVersionListSuccess(string fileUri, byte[] bytes, float duration, object userData) { MemoryStream memoryStream = null; try { memoryStream = new MemoryStream(bytes, false); PackageVersionList versionList = m_ResourceManager.m_PackageVersionListSerializer.Deserialize(memoryStream); if (!versionList.IsValid) { throw new GameFrameworkException("Deserialize package version list failure."); } PackageVersionList.Asset[] assets = versionList.GetAssets(); PackageVersionList.Resource[] resources = versionList.GetResources(); PackageVersionList.FileSystem[] fileSystems = versionList.GetFileSystems(); PackageVersionList.ResourceGroup[] resourceGroups = versionList.GetResourceGroups(); m_ResourceManager.m_ApplicableGameVersion = versionList.ApplicableGameVersion; m_ResourceManager.m_InternalResourceVersion = versionList.InternalResourceVersion; m_ResourceManager.m_AssetInfos = new Dictionary(assets.Length, StringComparer.Ordinal); m_ResourceManager.m_ResourceInfos = new Dictionary(resources.Length, new ResourceNameComparer()); ResourceGroup defaultResourceGroup = m_ResourceManager.GetOrAddResourceGroup(string.Empty); foreach (PackageVersionList.FileSystem fileSystem in fileSystems) { int[] resourceIndexes = fileSystem.GetResourceIndexes(); foreach (int resourceIndex in resourceIndexes) { PackageVersionList.Resource resource = resources[resourceIndex]; if (resource.Variant != null && resource.Variant != m_CurrentVariant) { continue; } m_CachedFileSystemNames.Add(new ResourceName(resource.Name, resource.Variant, resource.Extension), fileSystem.Name); } } foreach (PackageVersionList.Resource resource in resources) { if (resource.Variant != null && resource.Variant != m_CurrentVariant) { continue; } ResourceName resourceName = new ResourceName(resource.Name, resource.Variant, resource.Extension); int[] assetIndexes = resource.GetAssetIndexes(); foreach (int assetIndex in assetIndexes) { PackageVersionList.Asset asset = assets[assetIndex]; int[] dependencyAssetIndexes = asset.GetDependencyAssetIndexes(); int index = 0; string[] dependencyAssetNames = new string[dependencyAssetIndexes.Length]; foreach (int dependencyAssetIndex in dependencyAssetIndexes) { dependencyAssetNames[index++] = assets[dependencyAssetIndex].Name; } m_ResourceManager.m_AssetInfos.Add(asset.Name, new AssetInfo(asset.Name, resourceName, dependencyAssetNames)); } string fileSystemName = null; if (!m_CachedFileSystemNames.TryGetValue(resourceName, out fileSystemName)) { fileSystemName = null; } m_ResourceManager.m_ResourceInfos.Add(resourceName, new ResourceInfo(resourceName, fileSystemName, (LoadType)resource.LoadType, resource.Length, resource.HashCode, resource.Length, true, true)); defaultResourceGroup.AddResource(resourceName, resource.Length, resource.Length); } foreach (PackageVersionList.ResourceGroup resourceGroup in resourceGroups) { ResourceGroup group = m_ResourceManager.GetOrAddResourceGroup(resourceGroup.Name); int[] resourceIndexes = resourceGroup.GetResourceIndexes(); foreach (int resourceIndex in resourceIndexes) { PackageVersionList.Resource resource = resources[resourceIndex]; if (resource.Variant != null && resource.Variant != m_CurrentVariant) { continue; } group.AddResource(new ResourceName(resource.Name, resource.Variant, resource.Extension), resource.Length, resource.Length); } } ResourceInitComplete(); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Utility.Text.Format("Parse package version list exception '{0}'.", exception), exception); } finally { m_CachedFileSystemNames.Clear(); if (memoryStream != null) { memoryStream.Dispose(); memoryStream = null; } } } private void OnLoadPackageVersionListFailure(string fileUri, string errorMessage, object userData) { throw new GameFrameworkException(Utility.Text.Format("Package version list '{0}' is invalid, error message is '{1}'.", fileUri, string.IsNullOrEmpty(errorMessage) ? "" : errorMessage)); } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceLoader.AssetObject.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.ObjectPool; using System.Collections.Generic; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceLoader { /// /// 资源对象。 /// private sealed class AssetObject : ObjectBase { private List m_DependencyAssets; private object m_Resource; private IResourceHelper m_ResourceHelper; private ResourceLoader m_ResourceLoader; public AssetObject() { m_DependencyAssets = new List(); m_Resource = null; m_ResourceHelper = null; m_ResourceLoader = null; } public override bool CustomCanReleaseFlag { get { int targetReferenceCount = 0; m_ResourceLoader.m_AssetDependencyCount.TryGetValue(Target, out targetReferenceCount); return base.CustomCanReleaseFlag && targetReferenceCount <= 0; } } public static AssetObject Create(string name, object target, List dependencyAssets, object resource, IResourceHelper resourceHelper, ResourceLoader resourceLoader) { if (dependencyAssets == null) { throw new GameFrameworkException("Dependency assets is invalid."); } if (resource == null) { throw new GameFrameworkException("Resource is invalid."); } if (resourceHelper == null) { throw new GameFrameworkException("Resource helper is invalid."); } if (resourceLoader == null) { throw new GameFrameworkException("Resource loader is invalid."); } AssetObject assetObject = ReferencePool.Acquire(); assetObject.Initialize(name, target); assetObject.m_DependencyAssets.AddRange(dependencyAssets); assetObject.m_Resource = resource; assetObject.m_ResourceHelper = resourceHelper; assetObject.m_ResourceLoader = resourceLoader; foreach (object dependencyAsset in dependencyAssets) { int referenceCount = 0; if (resourceLoader.m_AssetDependencyCount.TryGetValue(dependencyAsset, out referenceCount)) { resourceLoader.m_AssetDependencyCount[dependencyAsset] = referenceCount + 1; } else { resourceLoader.m_AssetDependencyCount.Add(dependencyAsset, 1); } } return assetObject; } public override void Clear() { base.Clear(); m_DependencyAssets.Clear(); m_Resource = null; m_ResourceHelper = null; m_ResourceLoader = null; } protected internal override void OnUnspawn() { base.OnUnspawn(); foreach (object dependencyAsset in m_DependencyAssets) { m_ResourceLoader.m_AssetPool.Unspawn(dependencyAsset); } } protected internal override void Release(bool isShutdown) { if (!isShutdown) { int targetReferenceCount = 0; if (m_ResourceLoader.m_AssetDependencyCount.TryGetValue(Target, out targetReferenceCount) && targetReferenceCount > 0) { throw new GameFrameworkException(Utility.Text.Format("Asset target '{0}' reference count is '{1}' larger than 0.", Name, targetReferenceCount)); } foreach (object dependencyAsset in m_DependencyAssets) { int referenceCount = 0; if (m_ResourceLoader.m_AssetDependencyCount.TryGetValue(dependencyAsset, out referenceCount)) { m_ResourceLoader.m_AssetDependencyCount[dependencyAsset] = referenceCount - 1; } else { throw new GameFrameworkException(Utility.Text.Format("Asset target '{0}' dependency asset reference count is invalid.", Name)); } } m_ResourceLoader.m_ResourcePool.Unspawn(m_Resource); } m_ResourceLoader.m_AssetDependencyCount.Remove(Target); m_ResourceLoader.m_AssetToResourceMap.Remove(Target); m_ResourceHelper.Release(Target); } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceLoader.LoadAssetTask.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceLoader { private sealed class LoadAssetTask : LoadResourceTaskBase { private LoadAssetCallbacks m_LoadAssetCallbacks; public LoadAssetTask() { m_LoadAssetCallbacks = null; } public override bool IsScene { get { return false; } } public static LoadAssetTask Create(string assetName, Type assetType, int priority, ResourceInfo resourceInfo, string[] dependencyAssetNames, LoadAssetCallbacks loadAssetCallbacks, object userData) { LoadAssetTask loadAssetTask = ReferencePool.Acquire(); loadAssetTask.Initialize(assetName, assetType, priority, resourceInfo, dependencyAssetNames, userData); loadAssetTask.m_LoadAssetCallbacks = loadAssetCallbacks; return loadAssetTask; } public override void Clear() { base.Clear(); m_LoadAssetCallbacks = null; } public override void OnLoadAssetSuccess(LoadResourceAgent agent, object asset, float duration) { base.OnLoadAssetSuccess(agent, asset, duration); if (m_LoadAssetCallbacks.LoadAssetSuccessCallback != null) { m_LoadAssetCallbacks.LoadAssetSuccessCallback(AssetName, asset, duration, UserData); } } public override void OnLoadAssetFailure(LoadResourceAgent agent, LoadResourceStatus status, string errorMessage) { base.OnLoadAssetFailure(agent, status, errorMessage); if (m_LoadAssetCallbacks.LoadAssetFailureCallback != null) { m_LoadAssetCallbacks.LoadAssetFailureCallback(AssetName, status, errorMessage, UserData); } } public override void OnLoadAssetUpdate(LoadResourceAgent agent, LoadResourceProgress type, float progress) { base.OnLoadAssetUpdate(agent, type, progress); if (type == LoadResourceProgress.LoadAsset) { if (m_LoadAssetCallbacks.LoadAssetUpdateCallback != null) { m_LoadAssetCallbacks.LoadAssetUpdateCallback(AssetName, progress, UserData); } } } public override void OnLoadDependencyAsset(LoadResourceAgent agent, string dependencyAssetName, object dependencyAsset) { base.OnLoadDependencyAsset(agent, dependencyAssetName, dependencyAsset); if (m_LoadAssetCallbacks.LoadAssetDependencyAssetCallback != null) { m_LoadAssetCallbacks.LoadAssetDependencyAssetCallback(AssetName, dependencyAssetName, LoadedDependencyAssetCount, TotalDependencyAssetCount, UserData); } } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceLoader.LoadBinaryInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceLoader { private sealed class LoadBinaryInfo : IReference { private string m_BinaryAssetName; private ResourceInfo m_ResourceInfo; private LoadBinaryCallbacks m_LoadBinaryCallbacks; private object m_UserData; public LoadBinaryInfo() { m_BinaryAssetName = null; m_ResourceInfo = null; m_LoadBinaryCallbacks = null; m_UserData = null; } public string BinaryAssetName { get { return m_BinaryAssetName; } } public ResourceInfo ResourceInfo { get { return m_ResourceInfo; } } public LoadBinaryCallbacks LoadBinaryCallbacks { get { return m_LoadBinaryCallbacks; } } public object UserData { get { return m_UserData; } } public static LoadBinaryInfo Create(string binaryAssetName, ResourceInfo resourceInfo, LoadBinaryCallbacks loadBinaryCallbacks, object userData) { LoadBinaryInfo loadBinaryInfo = ReferencePool.Acquire(); loadBinaryInfo.m_BinaryAssetName = binaryAssetName; loadBinaryInfo.m_ResourceInfo = resourceInfo; loadBinaryInfo.m_LoadBinaryCallbacks = loadBinaryCallbacks; loadBinaryInfo.m_UserData = userData; return loadBinaryInfo; } public void Clear() { m_BinaryAssetName = null; m_ResourceInfo = null; m_LoadBinaryCallbacks = null; m_UserData = null; } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceLoader.LoadDependencyAssetTask.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceLoader { private sealed class LoadDependencyAssetTask : LoadResourceTaskBase { private LoadResourceTaskBase m_MainTask; public LoadDependencyAssetTask() { m_MainTask = null; } public override bool IsScene { get { return false; } } public static LoadDependencyAssetTask Create(string assetName, int priority, ResourceInfo resourceInfo, string[] dependencyAssetNames, LoadResourceTaskBase mainTask, object userData) { LoadDependencyAssetTask loadDependencyAssetTask = ReferencePool.Acquire(); loadDependencyAssetTask.Initialize(assetName, null, priority, resourceInfo, dependencyAssetNames, userData); loadDependencyAssetTask.m_MainTask = mainTask; loadDependencyAssetTask.m_MainTask.TotalDependencyAssetCount++; return loadDependencyAssetTask; } public override void Clear() { base.Clear(); m_MainTask = null; } public override void OnLoadAssetSuccess(LoadResourceAgent agent, object asset, float duration) { base.OnLoadAssetSuccess(agent, asset, duration); m_MainTask.OnLoadDependencyAsset(agent, AssetName, asset); } public override void OnLoadAssetFailure(LoadResourceAgent agent, LoadResourceStatus status, string errorMessage) { base.OnLoadAssetFailure(agent, status, errorMessage); m_MainTask.OnLoadAssetFailure(agent, LoadResourceStatus.DependencyError, Utility.Text.Format("Can not load dependency asset '{0}', internal status '{1}', internal error message '{2}'.", AssetName, status, errorMessage)); } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceLoader.LoadResourceAgent.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.FileSystem; using System; using System.Collections.Generic; using System.IO; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceLoader { /// /// 加载资源代理。 /// private sealed partial class LoadResourceAgent : ITaskAgent { private static readonly Dictionary s_CachedResourceNames = new Dictionary(StringComparer.Ordinal); private static readonly HashSet s_LoadingAssetNames = new HashSet(StringComparer.Ordinal); private static readonly HashSet s_LoadingResourceNames = new HashSet(StringComparer.Ordinal); private readonly ILoadResourceAgentHelper m_Helper; private readonly IResourceHelper m_ResourceHelper; private readonly ResourceLoader m_ResourceLoader; private readonly string m_ReadOnlyPath; private readonly string m_ReadWritePath; private readonly DecryptResourceCallback m_DecryptResourceCallback; private LoadResourceTaskBase m_Task; /// /// 初始化加载资源代理的新实例。 /// /// 加载资源代理辅助器。 /// 资源辅助器。 /// 加载资源器。 /// 资源只读区路径。 /// 资源读写区路径。 /// 解密资源回调函数。 public LoadResourceAgent(ILoadResourceAgentHelper loadResourceAgentHelper, IResourceHelper resourceHelper, ResourceLoader resourceLoader, string readOnlyPath, string readWritePath, DecryptResourceCallback decryptResourceCallback) { if (loadResourceAgentHelper == null) { throw new GameFrameworkException("Load resource agent helper is invalid."); } if (resourceHelper == null) { throw new GameFrameworkException("Resource helper is invalid."); } if (resourceLoader == null) { throw new GameFrameworkException("Resource loader is invalid."); } if (decryptResourceCallback == null) { throw new GameFrameworkException("Decrypt resource callback is invalid."); } m_Helper = loadResourceAgentHelper; m_ResourceHelper = resourceHelper; m_ResourceLoader = resourceLoader; m_ReadOnlyPath = readOnlyPath; m_ReadWritePath = readWritePath; m_DecryptResourceCallback = decryptResourceCallback; m_Task = null; } public ILoadResourceAgentHelper Helper { get { return m_Helper; } } /// /// 获取加载资源任务。 /// public LoadResourceTaskBase Task { get { return m_Task; } } /// /// 初始化加载资源代理。 /// public void Initialize() { m_Helper.LoadResourceAgentHelperUpdate += OnLoadResourceAgentHelperUpdate; m_Helper.LoadResourceAgentHelperReadFileComplete += OnLoadResourceAgentHelperReadFileComplete; m_Helper.LoadResourceAgentHelperReadBytesComplete += OnLoadResourceAgentHelperReadBytesComplete; m_Helper.LoadResourceAgentHelperParseBytesComplete += OnLoadResourceAgentHelperParseBytesComplete; m_Helper.LoadResourceAgentHelperLoadComplete += OnLoadResourceAgentHelperLoadComplete; m_Helper.LoadResourceAgentHelperError += OnLoadResourceAgentHelperError; } /// /// 加载资源代理轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void Update(float elapseSeconds, float realElapseSeconds) { } /// /// 关闭并清理加载资源代理。 /// public void Shutdown() { Reset(); m_Helper.LoadResourceAgentHelperUpdate -= OnLoadResourceAgentHelperUpdate; m_Helper.LoadResourceAgentHelperReadFileComplete -= OnLoadResourceAgentHelperReadFileComplete; m_Helper.LoadResourceAgentHelperReadBytesComplete -= OnLoadResourceAgentHelperReadBytesComplete; m_Helper.LoadResourceAgentHelperParseBytesComplete -= OnLoadResourceAgentHelperParseBytesComplete; m_Helper.LoadResourceAgentHelperLoadComplete -= OnLoadResourceAgentHelperLoadComplete; m_Helper.LoadResourceAgentHelperError -= OnLoadResourceAgentHelperError; } public static void Clear() { s_CachedResourceNames.Clear(); s_LoadingAssetNames.Clear(); s_LoadingResourceNames.Clear(); } /// /// 开始处理加载资源任务。 /// /// 要处理的加载资源任务。 /// 开始处理任务的状态。 public StartTaskStatus Start(LoadResourceTaskBase task) { if (task == null) { throw new GameFrameworkException("Task is invalid."); } m_Task = task; m_Task.StartTime = DateTime.UtcNow; ResourceInfo resourceInfo = m_Task.ResourceInfo; if (!resourceInfo.Ready) { m_Task.StartTime = default(DateTime); return StartTaskStatus.HasToWait; } if (IsAssetLoading(m_Task.AssetName)) { m_Task.StartTime = default(DateTime); return StartTaskStatus.HasToWait; } if (!m_Task.IsScene) { AssetObject assetObject = m_ResourceLoader.m_AssetPool.Spawn(m_Task.AssetName); if (assetObject != null) { OnAssetObjectReady(assetObject); return StartTaskStatus.Done; } } foreach (string dependencyAssetName in m_Task.GetDependencyAssetNames()) { if (!m_ResourceLoader.m_AssetPool.CanSpawn(dependencyAssetName)) { m_Task.StartTime = default(DateTime); return StartTaskStatus.HasToWait; } } string resourceName = resourceInfo.ResourceName.Name; if (IsResourceLoading(resourceName)) { m_Task.StartTime = default(DateTime); return StartTaskStatus.HasToWait; } s_LoadingAssetNames.Add(m_Task.AssetName); ResourceObject resourceObject = m_ResourceLoader.m_ResourcePool.Spawn(resourceName); if (resourceObject != null) { OnResourceObjectReady(resourceObject); return StartTaskStatus.CanResume; } s_LoadingResourceNames.Add(resourceName); string fullPath = null; if (!s_CachedResourceNames.TryGetValue(resourceName, out fullPath)) { fullPath = Utility.Path.GetRegularPath(Path.Combine(resourceInfo.StorageInReadOnly ? m_ReadOnlyPath : m_ReadWritePath, resourceInfo.UseFileSystem ? resourceInfo.FileSystemName : resourceInfo.ResourceName.FullName)); s_CachedResourceNames.Add(resourceName, fullPath); } if (resourceInfo.LoadType == LoadType.LoadFromFile) { if (resourceInfo.UseFileSystem) { IFileSystem fileSystem = m_ResourceLoader.m_ResourceManager.GetFileSystem(resourceInfo.FileSystemName, resourceInfo.StorageInReadOnly); m_Helper.ReadFile(fileSystem, resourceInfo.ResourceName.FullName); } else { m_Helper.ReadFile(fullPath); } } else if (resourceInfo.LoadType == LoadType.LoadFromMemory || resourceInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt) { if (resourceInfo.UseFileSystem) { IFileSystem fileSystem = m_ResourceLoader.m_ResourceManager.GetFileSystem(resourceInfo.FileSystemName, resourceInfo.StorageInReadOnly); m_Helper.ReadBytes(fileSystem, resourceInfo.ResourceName.FullName); } else { m_Helper.ReadBytes(fullPath); } } else { throw new GameFrameworkException(Utility.Text.Format("Resource load type '{0}' is not supported.", resourceInfo.LoadType)); } return StartTaskStatus.CanResume; } /// /// 重置加载资源代理。 /// public void Reset() { m_Helper.Reset(); m_Task = null; } private static bool IsAssetLoading(string assetName) { return s_LoadingAssetNames.Contains(assetName); } private static bool IsResourceLoading(string resourceName) { return s_LoadingResourceNames.Contains(resourceName); } private void OnAssetObjectReady(AssetObject assetObject) { m_Helper.Reset(); object asset = assetObject.Target; if (m_Task.IsScene) { m_ResourceLoader.m_SceneToAssetMap.Add(m_Task.AssetName, asset); } m_Task.OnLoadAssetSuccess(this, asset, (float)(DateTime.UtcNow - m_Task.StartTime).TotalSeconds); m_Task.Done = true; } private void OnResourceObjectReady(ResourceObject resourceObject) { m_Task.LoadMain(this, resourceObject); } private void OnError(LoadResourceStatus status, string errorMessage) { m_Helper.Reset(); m_Task.OnLoadAssetFailure(this, status, errorMessage); s_LoadingAssetNames.Remove(m_Task.AssetName); s_LoadingResourceNames.Remove(m_Task.ResourceInfo.ResourceName.Name); m_Task.Done = true; } private void OnLoadResourceAgentHelperUpdate(object sender, LoadResourceAgentHelperUpdateEventArgs e) { m_Task.OnLoadAssetUpdate(this, e.Type, e.Progress); } private void OnLoadResourceAgentHelperReadFileComplete(object sender, LoadResourceAgentHelperReadFileCompleteEventArgs e) { ResourceObject resourceObject = ResourceObject.Create(m_Task.ResourceInfo.ResourceName.Name, e.Resource, m_ResourceHelper, m_ResourceLoader); m_ResourceLoader.m_ResourcePool.Register(resourceObject, true); s_LoadingResourceNames.Remove(m_Task.ResourceInfo.ResourceName.Name); OnResourceObjectReady(resourceObject); } private void OnLoadResourceAgentHelperReadBytesComplete(object sender, LoadResourceAgentHelperReadBytesCompleteEventArgs e) { byte[] bytes = e.GetBytes(); ResourceInfo resourceInfo = m_Task.ResourceInfo; if (resourceInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt) { m_DecryptResourceCallback(bytes, 0, bytes.Length, resourceInfo.ResourceName.Name, resourceInfo.ResourceName.Variant, resourceInfo.ResourceName.Extension, resourceInfo.StorageInReadOnly, resourceInfo.FileSystemName, (byte)resourceInfo.LoadType, resourceInfo.Length, resourceInfo.HashCode); } m_Helper.ParseBytes(bytes); } private void OnLoadResourceAgentHelperParseBytesComplete(object sender, LoadResourceAgentHelperParseBytesCompleteEventArgs e) { ResourceObject resourceObject = ResourceObject.Create(m_Task.ResourceInfo.ResourceName.Name, e.Resource, m_ResourceHelper, m_ResourceLoader); m_ResourceLoader.m_ResourcePool.Register(resourceObject, true); s_LoadingResourceNames.Remove(m_Task.ResourceInfo.ResourceName.Name); OnResourceObjectReady(resourceObject); } private void OnLoadResourceAgentHelperLoadComplete(object sender, LoadResourceAgentHelperLoadCompleteEventArgs e) { AssetObject assetObject = null; if (m_Task.IsScene) { assetObject = m_ResourceLoader.m_AssetPool.Spawn(m_Task.AssetName); } if (assetObject == null) { List dependencyAssets = m_Task.GetDependencyAssets(); assetObject = AssetObject.Create(m_Task.AssetName, e.Asset, dependencyAssets, m_Task.ResourceObject.Target, m_ResourceHelper, m_ResourceLoader); m_ResourceLoader.m_AssetPool.Register(assetObject, true); m_ResourceLoader.m_AssetToResourceMap.Add(e.Asset, m_Task.ResourceObject.Target); foreach (object dependencyAsset in dependencyAssets) { object dependencyResource = null; if (m_ResourceLoader.m_AssetToResourceMap.TryGetValue(dependencyAsset, out dependencyResource)) { m_Task.ResourceObject.AddDependencyResource(dependencyResource); } else { throw new GameFrameworkException("Can not find dependency resource."); } } } s_LoadingAssetNames.Remove(m_Task.AssetName); OnAssetObjectReady(assetObject); } private void OnLoadResourceAgentHelperError(object sender, LoadResourceAgentHelperErrorEventArgs e) { OnError(e.Status, e.ErrorMessage); } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceLoader.LoadResourceTaskBase.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceLoader { private abstract class LoadResourceTaskBase : TaskBase { private static int s_Serial = 0; private string m_AssetName; private Type m_AssetType; private ResourceInfo m_ResourceInfo; private string[] m_DependencyAssetNames; private readonly List m_DependencyAssets; private ResourceObject m_ResourceObject; private DateTime m_StartTime; private int m_TotalDependencyAssetCount; public LoadResourceTaskBase() { m_AssetName = null; m_AssetType = null; m_ResourceInfo = null; m_DependencyAssetNames = null; m_DependencyAssets = new List(); m_ResourceObject = null; m_StartTime = default(DateTime); m_TotalDependencyAssetCount = 0; } public string AssetName { get { return m_AssetName; } } public Type AssetType { get { return m_AssetType; } } public ResourceInfo ResourceInfo { get { return m_ResourceInfo; } } public ResourceObject ResourceObject { get { return m_ResourceObject; } } public abstract bool IsScene { get; } public DateTime StartTime { get { return m_StartTime; } set { m_StartTime = value; } } public int LoadedDependencyAssetCount { get { return m_DependencyAssets.Count; } } public int TotalDependencyAssetCount { get { return m_TotalDependencyAssetCount; } set { m_TotalDependencyAssetCount = value; } } public override string Description { get { return m_AssetName; } } public override void Clear() { base.Clear(); m_AssetName = null; m_AssetType = null; m_ResourceInfo = null; m_DependencyAssetNames = null; m_DependencyAssets.Clear(); m_ResourceObject = null; m_StartTime = default(DateTime); m_TotalDependencyAssetCount = 0; } public string[] GetDependencyAssetNames() { return m_DependencyAssetNames; } public List GetDependencyAssets() { return m_DependencyAssets; } public void LoadMain(LoadResourceAgent agent, ResourceObject resourceObject) { m_ResourceObject = resourceObject; agent.Helper.LoadAsset(resourceObject.Target, AssetName, AssetType, IsScene); } public virtual void OnLoadAssetSuccess(LoadResourceAgent agent, object asset, float duration) { } public virtual void OnLoadAssetFailure(LoadResourceAgent agent, LoadResourceStatus status, string errorMessage) { } public virtual void OnLoadAssetUpdate(LoadResourceAgent agent, LoadResourceProgress type, float progress) { } public virtual void OnLoadDependencyAsset(LoadResourceAgent agent, string dependencyAssetName, object dependencyAsset) { m_DependencyAssets.Add(dependencyAsset); } protected void Initialize(string assetName, Type assetType, int priority, ResourceInfo resourceInfo, string[] dependencyAssetNames, object userData) { Initialize(++s_Serial, null, priority, userData); m_AssetName = assetName; m_AssetType = assetType; m_ResourceInfo = resourceInfo; m_DependencyAssetNames = dependencyAssetNames; } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceLoader.LoadSceneTask.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceLoader { private sealed class LoadSceneTask : LoadResourceTaskBase { private LoadSceneCallbacks m_LoadSceneCallbacks; public LoadSceneTask() { m_LoadSceneCallbacks = null; } public override bool IsScene { get { return true; } } public static LoadSceneTask Create(string sceneAssetName, int priority, ResourceInfo resourceInfo, string[] dependencyAssetNames, LoadSceneCallbacks loadSceneCallbacks, object userData) { LoadSceneTask loadSceneTask = ReferencePool.Acquire(); loadSceneTask.Initialize(sceneAssetName, null, priority, resourceInfo, dependencyAssetNames, userData); loadSceneTask.m_LoadSceneCallbacks = loadSceneCallbacks; return loadSceneTask; } public override void Clear() { base.Clear(); m_LoadSceneCallbacks = null; } public override void OnLoadAssetSuccess(LoadResourceAgent agent, object asset, float duration) { base.OnLoadAssetSuccess(agent, asset, duration); if (m_LoadSceneCallbacks.LoadSceneSuccessCallback != null) { m_LoadSceneCallbacks.LoadSceneSuccessCallback(AssetName, duration, UserData); } } public override void OnLoadAssetFailure(LoadResourceAgent agent, LoadResourceStatus status, string errorMessage) { base.OnLoadAssetFailure(agent, status, errorMessage); if (m_LoadSceneCallbacks.LoadSceneFailureCallback != null) { m_LoadSceneCallbacks.LoadSceneFailureCallback(AssetName, status, errorMessage, UserData); } } public override void OnLoadAssetUpdate(LoadResourceAgent agent, LoadResourceProgress type, float progress) { base.OnLoadAssetUpdate(agent, type, progress); if (type == LoadResourceProgress.LoadScene) { if (m_LoadSceneCallbacks.LoadSceneUpdateCallback != null) { m_LoadSceneCallbacks.LoadSceneUpdateCallback(AssetName, progress, UserData); } } } public override void OnLoadDependencyAsset(LoadResourceAgent agent, string dependencyAssetName, object dependencyAsset) { base.OnLoadDependencyAsset(agent, dependencyAssetName, dependencyAsset); if (m_LoadSceneCallbacks.LoadSceneDependencyAssetCallback != null) { m_LoadSceneCallbacks.LoadSceneDependencyAssetCallback(AssetName, dependencyAssetName, LoadedDependencyAssetCount, TotalDependencyAssetCount, UserData); } } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceLoader.ResourceObject.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.ObjectPool; using System.Collections.Generic; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceLoader { /// /// 资源对象。 /// private sealed class ResourceObject : ObjectBase { private List m_DependencyResources; private IResourceHelper m_ResourceHelper; private ResourceLoader m_ResourceLoader; public ResourceObject() { m_DependencyResources = new List(); m_ResourceHelper = null; m_ResourceLoader = null; } public override bool CustomCanReleaseFlag { get { int targetReferenceCount = 0; m_ResourceLoader.m_ResourceDependencyCount.TryGetValue(Target, out targetReferenceCount); return base.CustomCanReleaseFlag && targetReferenceCount <= 0; } } public static ResourceObject Create(string name, object target, IResourceHelper resourceHelper, ResourceLoader resourceLoader) { if (resourceHelper == null) { throw new GameFrameworkException("Resource helper is invalid."); } if (resourceLoader == null) { throw new GameFrameworkException("Resource loader is invalid."); } ResourceObject resourceObject = ReferencePool.Acquire(); resourceObject.Initialize(name, target); resourceObject.m_ResourceHelper = resourceHelper; resourceObject.m_ResourceLoader = resourceLoader; return resourceObject; } public override void Clear() { base.Clear(); m_DependencyResources.Clear(); m_ResourceHelper = null; m_ResourceLoader = null; } public void AddDependencyResource(object dependencyResource) { if (Target == dependencyResource) { return; } if (m_DependencyResources.Contains(dependencyResource)) { return; } m_DependencyResources.Add(dependencyResource); int referenceCount = 0; if (m_ResourceLoader.m_ResourceDependencyCount.TryGetValue(dependencyResource, out referenceCount)) { m_ResourceLoader.m_ResourceDependencyCount[dependencyResource] = referenceCount + 1; } else { m_ResourceLoader.m_ResourceDependencyCount.Add(dependencyResource, 1); } } protected internal override void Release(bool isShutdown) { if (!isShutdown) { int targetReferenceCount = 0; if (m_ResourceLoader.m_ResourceDependencyCount.TryGetValue(Target, out targetReferenceCount) && targetReferenceCount > 0) { throw new GameFrameworkException(Utility.Text.Format("Resource target '{0}' reference count is '{1}' larger than 0.", Name, targetReferenceCount)); } foreach (object dependencyResource in m_DependencyResources) { int referenceCount = 0; if (m_ResourceLoader.m_ResourceDependencyCount.TryGetValue(dependencyResource, out referenceCount)) { m_ResourceLoader.m_ResourceDependencyCount[dependencyResource] = referenceCount - 1; } else { throw new GameFrameworkException(Utility.Text.Format("Resource target '{0}' dependency asset reference count is invalid.", Name)); } } } m_ResourceLoader.m_ResourceDependencyCount.Remove(Target); m_ResourceHelper.Release(Target); } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceLoader.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.FileSystem; using GameFramework.ObjectPool; using System; using System.Collections.Generic; using System.IO; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 加载资源器。 /// private sealed partial class ResourceLoader { private const int CachedHashBytesLength = 4; private readonly ResourceManager m_ResourceManager; private readonly TaskPool m_TaskPool; private readonly Dictionary m_AssetDependencyCount; private readonly Dictionary m_ResourceDependencyCount; private readonly Dictionary m_AssetToResourceMap; private readonly Dictionary m_SceneToAssetMap; private readonly LoadBytesCallbacks m_LoadBytesCallbacks; private readonly byte[] m_CachedHashBytes; private IObjectPool m_AssetPool; private IObjectPool m_ResourcePool; /// /// 初始化加载资源器的新实例。 /// /// 资源管理器。 public ResourceLoader(ResourceManager resourceManager) { m_ResourceManager = resourceManager; m_TaskPool = new TaskPool(); m_AssetDependencyCount = new Dictionary(); m_ResourceDependencyCount = new Dictionary(); m_AssetToResourceMap = new Dictionary(); m_SceneToAssetMap = new Dictionary(StringComparer.Ordinal); m_LoadBytesCallbacks = new LoadBytesCallbacks(OnLoadBinarySuccess, OnLoadBinaryFailure); m_CachedHashBytes = new byte[CachedHashBytesLength]; m_AssetPool = null; m_ResourcePool = null; } /// /// 获取加载资源代理总数量。 /// public int TotalAgentCount { get { return m_TaskPool.TotalAgentCount; } } /// /// 获取可用加载资源代理数量。 /// public int FreeAgentCount { get { return m_TaskPool.FreeAgentCount; } } /// /// 获取工作中加载资源代理数量。 /// public int WorkingAgentCount { get { return m_TaskPool.WorkingAgentCount; } } /// /// 获取等待加载资源任务数量。 /// public int WaitingTaskCount { get { return m_TaskPool.WaitingTaskCount; } } /// /// 获取或设置资源对象池自动释放可释放对象的间隔秒数。 /// public float AssetAutoReleaseInterval { get { return m_AssetPool.AutoReleaseInterval; } set { m_AssetPool.AutoReleaseInterval = value; } } /// /// 获取或设置资源对象池的容量。 /// public int AssetCapacity { get { return m_AssetPool.Capacity; } set { m_AssetPool.Capacity = value; } } /// /// 获取或设置资源对象池对象过期秒数。 /// public float AssetExpireTime { get { return m_AssetPool.ExpireTime; } set { m_AssetPool.ExpireTime = value; } } /// /// 获取或设置资源对象池的优先级。 /// public int AssetPriority { get { return m_AssetPool.Priority; } set { m_AssetPool.Priority = value; } } /// /// 获取或设置资源对象池自动释放可释放对象的间隔秒数。 /// public float ResourceAutoReleaseInterval { get { return m_ResourcePool.AutoReleaseInterval; } set { m_ResourcePool.AutoReleaseInterval = value; } } /// /// 获取或设置资源对象池的容量。 /// public int ResourceCapacity { get { return m_ResourcePool.Capacity; } set { m_ResourcePool.Capacity = value; } } /// /// 获取或设置资源对象池对象过期秒数。 /// public float ResourceExpireTime { get { return m_ResourcePool.ExpireTime; } set { m_ResourcePool.ExpireTime = value; } } /// /// 获取或设置资源对象池的优先级。 /// public int ResourcePriority { get { return m_ResourcePool.Priority; } set { m_ResourcePool.Priority = value; } } /// /// 加载资源器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void Update(float elapseSeconds, float realElapseSeconds) { m_TaskPool.Update(elapseSeconds, realElapseSeconds); } /// /// 关闭并清理加载资源器。 /// public void Shutdown() { m_TaskPool.Shutdown(); m_AssetDependencyCount.Clear(); m_ResourceDependencyCount.Clear(); m_AssetToResourceMap.Clear(); m_SceneToAssetMap.Clear(); LoadResourceAgent.Clear(); } /// /// 设置对象池管理器。 /// /// 对象池管理器。 public void SetObjectPoolManager(IObjectPoolManager objectPoolManager) { m_AssetPool = objectPoolManager.CreateMultiSpawnObjectPool("Asset Pool"); m_ResourcePool = objectPoolManager.CreateMultiSpawnObjectPool("Resource Pool"); } /// /// 增加加载资源代理辅助器。 /// /// 要增加的加载资源代理辅助器。 /// 资源辅助器。 /// 资源只读区路径。 /// 资源读写区路径。 /// 要设置的解密资源回调函数。 public void AddLoadResourceAgentHelper(ILoadResourceAgentHelper loadResourceAgentHelper, IResourceHelper resourceHelper, string readOnlyPath, string readWritePath, DecryptResourceCallback decryptResourceCallback) { if (m_AssetPool == null || m_ResourcePool == null) { throw new GameFrameworkException("You must set object pool manager first."); } LoadResourceAgent agent = new LoadResourceAgent(loadResourceAgentHelper, resourceHelper, this, readOnlyPath, readWritePath, decryptResourceCallback ?? DefaultDecryptResourceCallback); m_TaskPool.AddAgent(agent); } /// /// 检查资源是否存在。 /// /// 要检查资源的名称。 /// 检查资源是否存在的结果。 public HasAssetResult HasAsset(string assetName) { ResourceInfo resourceInfo = GetResourceInfo(assetName); if (resourceInfo == null) { return HasAssetResult.NotExist; } if (!resourceInfo.Ready && m_ResourceManager.m_ResourceMode != ResourceMode.UpdatableWhilePlaying) { return HasAssetResult.NotReady; } if (resourceInfo.UseFileSystem) { return resourceInfo.IsLoadFromBinary ? HasAssetResult.BinaryOnFileSystem : HasAssetResult.AssetOnFileSystem; } else { return resourceInfo.IsLoadFromBinary ? HasAssetResult.BinaryOnDisk : HasAssetResult.AssetOnDisk; } } /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 要加载资源的类型。 /// 加载资源的优先级。 /// 加载资源回调函数集。 /// 用户自定义数据。 public void LoadAsset(string assetName, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData) { ResourceInfo resourceInfo = null; string[] dependencyAssetNames = null; if (!CheckAsset(assetName, out resourceInfo, out dependencyAssetNames)) { string errorMessage = Utility.Text.Format("Can not load asset '{0}'.", assetName); if (loadAssetCallbacks.LoadAssetFailureCallback != null) { loadAssetCallbacks.LoadAssetFailureCallback(assetName, resourceInfo != null && !resourceInfo.Ready ? LoadResourceStatus.NotReady : LoadResourceStatus.NotExist, errorMessage, userData); return; } throw new GameFrameworkException(errorMessage); } if (resourceInfo.IsLoadFromBinary) { string errorMessage = Utility.Text.Format("Can not load asset '{0}' which is a binary asset.", assetName); if (loadAssetCallbacks.LoadAssetFailureCallback != null) { loadAssetCallbacks.LoadAssetFailureCallback(assetName, LoadResourceStatus.TypeError, errorMessage, userData); return; } throw new GameFrameworkException(errorMessage); } LoadAssetTask mainTask = LoadAssetTask.Create(assetName, assetType, priority, resourceInfo, dependencyAssetNames, loadAssetCallbacks, userData); foreach (string dependencyAssetName in dependencyAssetNames) { if (!LoadDependencyAsset(dependencyAssetName, priority, mainTask, userData)) { string errorMessage = Utility.Text.Format("Can not load dependency asset '{0}' when load asset '{1}'.", dependencyAssetName, assetName); if (loadAssetCallbacks.LoadAssetFailureCallback != null) { loadAssetCallbacks.LoadAssetFailureCallback(assetName, LoadResourceStatus.DependencyError, errorMessage, userData); return; } throw new GameFrameworkException(errorMessage); } } m_TaskPool.AddTask(mainTask); if (!resourceInfo.Ready) { m_ResourceManager.UpdateResource(resourceInfo.ResourceName); } } /// /// 卸载资源。 /// /// 要卸载的资源。 public void UnloadAsset(object asset) { m_AssetPool.Unspawn(asset); } /// /// 异步加载场景。 /// /// 要加载场景资源的名称。 /// 加载场景资源的优先级。 /// 加载场景回调函数集。 /// 用户自定义数据。 public void LoadScene(string sceneAssetName, int priority, LoadSceneCallbacks loadSceneCallbacks, object userData) { ResourceInfo resourceInfo = null; string[] dependencyAssetNames = null; if (!CheckAsset(sceneAssetName, out resourceInfo, out dependencyAssetNames)) { string errorMessage = Utility.Text.Format("Can not load scene '{0}'.", sceneAssetName); if (loadSceneCallbacks.LoadSceneFailureCallback != null) { loadSceneCallbacks.LoadSceneFailureCallback(sceneAssetName, resourceInfo != null && !resourceInfo.Ready ? LoadResourceStatus.NotReady : LoadResourceStatus.NotExist, errorMessage, userData); return; } throw new GameFrameworkException(errorMessage); } if (resourceInfo.IsLoadFromBinary) { string errorMessage = Utility.Text.Format("Can not load scene asset '{0}' which is a binary asset.", sceneAssetName); if (loadSceneCallbacks.LoadSceneFailureCallback != null) { loadSceneCallbacks.LoadSceneFailureCallback(sceneAssetName, LoadResourceStatus.TypeError, errorMessage, userData); return; } throw new GameFrameworkException(errorMessage); } LoadSceneTask mainTask = LoadSceneTask.Create(sceneAssetName, priority, resourceInfo, dependencyAssetNames, loadSceneCallbacks, userData); foreach (string dependencyAssetName in dependencyAssetNames) { if (!LoadDependencyAsset(dependencyAssetName, priority, mainTask, userData)) { string errorMessage = Utility.Text.Format("Can not load dependency asset '{0}' when load scene '{1}'.", dependencyAssetName, sceneAssetName); if (loadSceneCallbacks.LoadSceneFailureCallback != null) { loadSceneCallbacks.LoadSceneFailureCallback(sceneAssetName, LoadResourceStatus.DependencyError, errorMessage, userData); return; } throw new GameFrameworkException(errorMessage); } } m_TaskPool.AddTask(mainTask); if (!resourceInfo.Ready) { m_ResourceManager.UpdateResource(resourceInfo.ResourceName); } } /// /// 异步卸载场景。 /// /// 要卸载场景资源的名称。 /// 卸载场景回调函数集。 /// 用户自定义数据。 public void UnloadScene(string sceneAssetName, UnloadSceneCallbacks unloadSceneCallbacks, object userData) { if (m_ResourceManager.m_ResourceHelper == null) { throw new GameFrameworkException("You must set resource helper first."); } object asset = null; if (m_SceneToAssetMap.TryGetValue(sceneAssetName, out asset)) { m_SceneToAssetMap.Remove(sceneAssetName); m_AssetPool.Unspawn(asset); m_AssetPool.ReleaseObject(asset); } else { throw new GameFrameworkException(Utility.Text.Format("Can not find asset of scene '{0}'.", sceneAssetName)); } m_ResourceManager.m_ResourceHelper.UnloadScene(sceneAssetName, unloadSceneCallbacks, userData); } /// /// 获取二进制资源的实际路径。 /// /// 要获取实际路径的二进制资源的名称。 /// 二进制资源的实际路径。 /// 此方法仅适用于二进制资源存储在磁盘(而非文件系统)中的情况。若二进制资源存储在文件系统中时,返回值将始终为空。 public string GetBinaryPath(string binaryAssetName) { ResourceInfo resourceInfo = GetResourceInfo(binaryAssetName); if (resourceInfo == null) { return null; } if (!resourceInfo.Ready) { return null; } if (!resourceInfo.IsLoadFromBinary) { return null; } if (resourceInfo.UseFileSystem) { return null; } return Utility.Path.GetRegularPath(Path.Combine(resourceInfo.StorageInReadOnly ? m_ResourceManager.m_ReadOnlyPath : m_ResourceManager.m_ReadWritePath, resourceInfo.ResourceName.FullName)); } /// /// 获取二进制资源的实际路径。 /// /// 要获取实际路径的二进制资源的名称。 /// 二进制资源是否存储在只读区中。 /// 二进制资源是否存储在文件系统中。 /// 二进制资源或存储二进制资源的文件系统,相对于只读区或者读写区的相对路径。 /// 若二进制资源存储在文件系统中,则指示二进制资源在文件系统中的名称,否则此参数返回空。 /// 是否获取二进制资源的实际路径成功。 public bool GetBinaryPath(string binaryAssetName, out bool storageInReadOnly, out bool storageInFileSystem, out string relativePath, out string fileName) { storageInReadOnly = false; storageInFileSystem = false; relativePath = null; fileName = null; ResourceInfo resourceInfo = GetResourceInfo(binaryAssetName); if (resourceInfo == null) { return false; } if (!resourceInfo.Ready) { return false; } if (!resourceInfo.IsLoadFromBinary) { return false; } storageInReadOnly = resourceInfo.StorageInReadOnly; if (resourceInfo.UseFileSystem) { storageInFileSystem = true; relativePath = Utility.Text.Format("{0}.{1}", resourceInfo.FileSystemName, DefaultExtension); fileName = resourceInfo.ResourceName.FullName; } else { relativePath = resourceInfo.ResourceName.FullName; } return true; } /// /// 获取二进制资源的长度。 /// /// 要获取长度的二进制资源的名称。 /// 二进制资源的长度。 public int GetBinaryLength(string binaryAssetName) { ResourceInfo resourceInfo = GetResourceInfo(binaryAssetName); if (resourceInfo == null) { return -1; } if (!resourceInfo.Ready) { return -1; } if (!resourceInfo.IsLoadFromBinary) { return -1; } return resourceInfo.Length; } /// /// 异步加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 加载二进制资源回调函数集。 /// 用户自定义数据。 public void LoadBinary(string binaryAssetName, LoadBinaryCallbacks loadBinaryCallbacks, object userData) { ResourceInfo resourceInfo = GetResourceInfo(binaryAssetName); if (resourceInfo == null) { string errorMessage = Utility.Text.Format("Can not load binary '{0}' which is not exist.", binaryAssetName); if (loadBinaryCallbacks.LoadBinaryFailureCallback != null) { loadBinaryCallbacks.LoadBinaryFailureCallback(binaryAssetName, LoadResourceStatus.NotExist, errorMessage, userData); return; } throw new GameFrameworkException(errorMessage); } if (!resourceInfo.Ready) { string errorMessage = Utility.Text.Format("Can not load binary '{0}' which is not ready.", binaryAssetName); if (loadBinaryCallbacks.LoadBinaryFailureCallback != null) { loadBinaryCallbacks.LoadBinaryFailureCallback(binaryAssetName, LoadResourceStatus.NotReady, errorMessage, userData); return; } throw new GameFrameworkException(errorMessage); } if (!resourceInfo.IsLoadFromBinary) { string errorMessage = Utility.Text.Format("Can not load binary '{0}' which is not a binary asset.", binaryAssetName); if (loadBinaryCallbacks.LoadBinaryFailureCallback != null) { loadBinaryCallbacks.LoadBinaryFailureCallback(binaryAssetName, LoadResourceStatus.TypeError, errorMessage, userData); return; } throw new GameFrameworkException(errorMessage); } if (resourceInfo.UseFileSystem) { loadBinaryCallbacks.LoadBinarySuccessCallback(binaryAssetName, LoadBinaryFromFileSystem(binaryAssetName), 0f, userData); } else { string path = Utility.Path.GetRemotePath(Path.Combine(resourceInfo.StorageInReadOnly ? m_ResourceManager.m_ReadOnlyPath : m_ResourceManager.m_ReadWritePath, resourceInfo.ResourceName.FullName)); m_ResourceManager.m_ResourceHelper.LoadBytes(path, m_LoadBytesCallbacks, LoadBinaryInfo.Create(binaryAssetName, resourceInfo, loadBinaryCallbacks, userData)); } } /// /// 从文件系统中加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 存储加载二进制资源的二进制流。 public byte[] LoadBinaryFromFileSystem(string binaryAssetName) { ResourceInfo resourceInfo = GetResourceInfo(binaryAssetName); if (resourceInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not exist.", binaryAssetName)); } if (!resourceInfo.Ready) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not ready.", binaryAssetName)); } if (!resourceInfo.IsLoadFromBinary) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not a binary asset.", binaryAssetName)); } if (!resourceInfo.UseFileSystem) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not use file system.", binaryAssetName)); } IFileSystem fileSystem = m_ResourceManager.GetFileSystem(resourceInfo.FileSystemName, resourceInfo.StorageInReadOnly); byte[] bytes = fileSystem.ReadFile(resourceInfo.ResourceName.FullName); if (bytes == null) { return null; } if (resourceInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { DecryptResourceCallback decryptResourceCallback = m_ResourceManager.m_DecryptResourceCallback ?? DefaultDecryptResourceCallback; decryptResourceCallback(bytes, 0, bytes.Length, resourceInfo.ResourceName.Name, resourceInfo.ResourceName.Variant, resourceInfo.ResourceName.Extension, resourceInfo.StorageInReadOnly, resourceInfo.FileSystemName, (byte)resourceInfo.LoadType, resourceInfo.Length, resourceInfo.HashCode); } return bytes; } /// /// 从文件系统中加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 存储加载二进制资源的二进制流。 /// 存储加载二进制资源的二进制流的起始位置。 /// 存储加载二进制资源的二进制流的长度。 /// 实际加载了多少字节。 public int LoadBinaryFromFileSystem(string binaryAssetName, byte[] buffer, int startIndex, int length) { ResourceInfo resourceInfo = GetResourceInfo(binaryAssetName); if (resourceInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not exist.", binaryAssetName)); } if (!resourceInfo.Ready) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not ready.", binaryAssetName)); } if (!resourceInfo.IsLoadFromBinary) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not a binary asset.", binaryAssetName)); } if (!resourceInfo.UseFileSystem) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not use file system.", binaryAssetName)); } IFileSystem fileSystem = m_ResourceManager.GetFileSystem(resourceInfo.FileSystemName, resourceInfo.StorageInReadOnly); int bytesRead = fileSystem.ReadFile(resourceInfo.ResourceName.FullName, buffer, startIndex, length); if (resourceInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { DecryptResourceCallback decryptResourceCallback = m_ResourceManager.m_DecryptResourceCallback ?? DefaultDecryptResourceCallback; decryptResourceCallback(buffer, startIndex, bytesRead, resourceInfo.ResourceName.Name, resourceInfo.ResourceName.Variant, resourceInfo.ResourceName.Extension, resourceInfo.StorageInReadOnly, resourceInfo.FileSystemName, (byte)resourceInfo.LoadType, resourceInfo.Length, resourceInfo.HashCode); } return bytesRead; } /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的偏移。 /// 要加载片段的长度。 /// 存储加载二进制资源片段内容的二进制流。 public byte[] LoadBinarySegmentFromFileSystem(string binaryAssetName, int offset, int length) { ResourceInfo resourceInfo = GetResourceInfo(binaryAssetName); if (resourceInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not exist.", binaryAssetName)); } if (!resourceInfo.Ready) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not ready.", binaryAssetName)); } if (!resourceInfo.IsLoadFromBinary) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not a binary asset.", binaryAssetName)); } if (!resourceInfo.UseFileSystem) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not use file system.", binaryAssetName)); } IFileSystem fileSystem = m_ResourceManager.GetFileSystem(resourceInfo.FileSystemName, resourceInfo.StorageInReadOnly); byte[] bytes = fileSystem.ReadFileSegment(resourceInfo.ResourceName.FullName, offset, length); if (bytes == null) { return null; } if (resourceInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { DecryptResourceCallback decryptResourceCallback = m_ResourceManager.m_DecryptResourceCallback ?? DefaultDecryptResourceCallback; decryptResourceCallback(bytes, 0, bytes.Length, resourceInfo.ResourceName.Name, resourceInfo.ResourceName.Variant, resourceInfo.ResourceName.Extension, resourceInfo.StorageInReadOnly, resourceInfo.FileSystemName, (byte)resourceInfo.LoadType, resourceInfo.Length, resourceInfo.HashCode); } return bytes; } /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的偏移。 /// 存储加载二进制资源片段内容的二进制流。 /// 存储加载二进制资源片段内容的二进制流的起始位置。 /// 要加载片段的长度。 /// 实际加载了多少字节。 public int LoadBinarySegmentFromFileSystem(string binaryAssetName, int offset, byte[] buffer, int startIndex, int length) { ResourceInfo resourceInfo = GetResourceInfo(binaryAssetName); if (resourceInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not exist.", binaryAssetName)); } if (!resourceInfo.Ready) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not ready.", binaryAssetName)); } if (!resourceInfo.IsLoadFromBinary) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not a binary asset.", binaryAssetName)); } if (!resourceInfo.UseFileSystem) { throw new GameFrameworkException(Utility.Text.Format("Can not load binary '{0}' from file system which is not use file system.", binaryAssetName)); } IFileSystem fileSystem = m_ResourceManager.GetFileSystem(resourceInfo.FileSystemName, resourceInfo.StorageInReadOnly); int bytesRead = fileSystem.ReadFileSegment(resourceInfo.ResourceName.FullName, offset, buffer, startIndex, length); if (resourceInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { DecryptResourceCallback decryptResourceCallback = m_ResourceManager.m_DecryptResourceCallback ?? DefaultDecryptResourceCallback; decryptResourceCallback(buffer, startIndex, bytesRead, resourceInfo.ResourceName.Name, resourceInfo.ResourceName.Variant, resourceInfo.ResourceName.Extension, resourceInfo.StorageInReadOnly, resourceInfo.FileSystemName, (byte)resourceInfo.LoadType, resourceInfo.Length, resourceInfo.HashCode); } return bytesRead; } /// /// 获取所有加载资源任务的信息。 /// /// 所有加载资源任务的信息。 public TaskInfo[] GetAllLoadAssetInfos() { return m_TaskPool.GetAllTaskInfos(); } /// /// 获取所有加载资源任务的信息。 /// /// 所有加载资源任务的信息。 public void GetAllLoadAssetInfos(List results) { m_TaskPool.GetAllTaskInfos(results); } private bool LoadDependencyAsset(string assetName, int priority, LoadResourceTaskBase mainTask, object userData) { if (mainTask == null) { throw new GameFrameworkException("Main task is invalid."); } ResourceInfo resourceInfo = null; string[] dependencyAssetNames = null; if (!CheckAsset(assetName, out resourceInfo, out dependencyAssetNames)) { return false; } if (resourceInfo.IsLoadFromBinary) { return false; } LoadDependencyAssetTask dependencyTask = LoadDependencyAssetTask.Create(assetName, priority, resourceInfo, dependencyAssetNames, mainTask, userData); foreach (string dependencyAssetName in dependencyAssetNames) { if (!LoadDependencyAsset(dependencyAssetName, priority, dependencyTask, userData)) { return false; } } m_TaskPool.AddTask(dependencyTask); if (!resourceInfo.Ready) { m_ResourceManager.UpdateResource(resourceInfo.ResourceName); } return true; } private ResourceInfo GetResourceInfo(string assetName) { if (string.IsNullOrEmpty(assetName)) { return null; } AssetInfo assetInfo = m_ResourceManager.GetAssetInfo(assetName); if (assetInfo == null) { return null; } return m_ResourceManager.GetResourceInfo(assetInfo.ResourceName); } private bool CheckAsset(string assetName, out ResourceInfo resourceInfo, out string[] dependencyAssetNames) { resourceInfo = null; dependencyAssetNames = null; if (string.IsNullOrEmpty(assetName)) { return false; } AssetInfo assetInfo = m_ResourceManager.GetAssetInfo(assetName); if (assetInfo == null) { return false; } resourceInfo = m_ResourceManager.GetResourceInfo(assetInfo.ResourceName); if (resourceInfo == null) { return false; } dependencyAssetNames = assetInfo.GetDependencyAssetNames(); return m_ResourceManager.m_ResourceMode == ResourceMode.UpdatableWhilePlaying ? true : resourceInfo.Ready; } private void DefaultDecryptResourceCallback(byte[] bytes, int startIndex, int count, string name, string variant, string extension, bool storageInReadOnly, string fileSystem, byte loadType, int length, int hashCode) { Utility.Converter.GetBytes(hashCode, m_CachedHashBytes); switch ((LoadType)loadType) { case LoadType.LoadFromMemoryAndQuickDecrypt: case LoadType.LoadFromBinaryAndQuickDecrypt: Utility.Encryption.GetQuickSelfXorBytes(bytes, m_CachedHashBytes); break; case LoadType.LoadFromMemoryAndDecrypt: case LoadType.LoadFromBinaryAndDecrypt: Utility.Encryption.GetSelfXorBytes(bytes, m_CachedHashBytes); break; default: throw new GameFrameworkException("Not supported load type when decrypt resource."); } Array.Clear(m_CachedHashBytes, 0, CachedHashBytesLength); } private void OnLoadBinarySuccess(string fileUri, byte[] bytes, float duration, object userData) { LoadBinaryInfo loadBinaryInfo = (LoadBinaryInfo)userData; if (loadBinaryInfo == null) { throw new GameFrameworkException("Load binary info is invalid."); } ResourceInfo resourceInfo = loadBinaryInfo.ResourceInfo; if (resourceInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { DecryptResourceCallback decryptResourceCallback = m_ResourceManager.m_DecryptResourceCallback ?? DefaultDecryptResourceCallback; decryptResourceCallback(bytes, 0, bytes.Length, resourceInfo.ResourceName.Name, resourceInfo.ResourceName.Variant, resourceInfo.ResourceName.Extension, resourceInfo.StorageInReadOnly, resourceInfo.FileSystemName, (byte)resourceInfo.LoadType, resourceInfo.Length, resourceInfo.HashCode); } loadBinaryInfo.LoadBinaryCallbacks.LoadBinarySuccessCallback(loadBinaryInfo.BinaryAssetName, bytes, duration, loadBinaryInfo.UserData); ReferencePool.Release(loadBinaryInfo); } private void OnLoadBinaryFailure(string fileUri, string errorMessage, object userData) { LoadBinaryInfo loadBinaryInfo = (LoadBinaryInfo)userData; if (loadBinaryInfo == null) { throw new GameFrameworkException("Load binary info is invalid."); } if (loadBinaryInfo.LoadBinaryCallbacks.LoadBinaryFailureCallback != null) { loadBinaryInfo.LoadBinaryCallbacks.LoadBinaryFailureCallback(loadBinaryInfo.BinaryAssetName, LoadResourceStatus.AssetError, errorMessage, loadBinaryInfo.UserData); } ReferencePool.Release(loadBinaryInfo); } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceName.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; using System.Runtime.InteropServices; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源名称。 /// [StructLayout(LayoutKind.Auto)] private struct ResourceName : IComparable, IComparable, IEquatable { private static readonly Dictionary s_ResourceFullNames = new Dictionary(); private readonly string m_Name; private readonly string m_Variant; private readonly string m_Extension; /// /// 初始化资源名称的新实例。 /// /// 资源名称。 /// 变体名称。 /// 扩展名称。 public ResourceName(string name, string variant, string extension) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Resource name is invalid."); } if (string.IsNullOrEmpty(extension)) { throw new GameFrameworkException("Resource extension is invalid."); } m_Name = name; m_Variant = variant; m_Extension = extension; } /// /// 获取资源名称。 /// public string Name { get { return m_Name; } } /// /// 获取变体名称。 /// public string Variant { get { return m_Variant; } } /// /// 获取扩展名称。 /// public string Extension { get { return m_Extension; } } public string FullName { get { string fullName = null; if (s_ResourceFullNames.TryGetValue(this, out fullName)) { return fullName; } fullName = m_Variant != null ? Utility.Text.Format("{0}.{1}.{2}", m_Name, m_Variant, m_Extension) : Utility.Text.Format("{0}.{1}", m_Name, m_Extension); s_ResourceFullNames.Add(this, fullName); return fullName; } } public override string ToString() { return FullName; } public override int GetHashCode() { if (m_Variant == null) { return m_Name.GetHashCode() ^ m_Extension.GetHashCode(); } return m_Name.GetHashCode() ^ m_Variant.GetHashCode() ^ m_Extension.GetHashCode(); } public override bool Equals(object obj) { return (obj is ResourceName) && Equals((ResourceName)obj); } public bool Equals(ResourceName value) { return string.Equals(m_Name, value.m_Name, StringComparison.Ordinal) && string.Equals(m_Variant, value.m_Variant, StringComparison.Ordinal) && string.Equals(m_Extension, value.m_Extension, StringComparison.Ordinal); } public static bool operator ==(ResourceName a, ResourceName b) { return a.Equals(b); } public static bool operator !=(ResourceName a, ResourceName b) { return !(a == b); } public int CompareTo(object value) { if (value == null) { return 1; } if (!(value is ResourceName)) { throw new GameFrameworkException("Type of value is invalid."); } return CompareTo((ResourceName)value); } public int CompareTo(ResourceName resourceName) { int result = string.CompareOrdinal(m_Name, resourceName.m_Name); if (result != 0) { return result; } result = string.CompareOrdinal(m_Variant, resourceName.m_Variant); if (result != 0) { return result; } return string.CompareOrdinal(m_Extension, resourceName.m_Extension); } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceNameComparer.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源名称比较器。 /// private sealed class ResourceNameComparer : IComparer, IEqualityComparer { public int Compare(ResourceName x, ResourceName y) { return x.CompareTo(y); } public bool Equals(ResourceName x, ResourceName y) { return x.Equals(y); } public int GetHashCode(ResourceName obj) { return obj.GetHashCode(); } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceUpdater.ApplyInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceUpdater { /// /// 资源应用信息。 /// [StructLayout(LayoutKind.Auto)] private struct ApplyInfo { private readonly ResourceName m_ResourceName; private readonly string m_FileSystemName; private readonly LoadType m_LoadType; private readonly long m_Offset; private readonly int m_Length; private readonly int m_HashCode; private readonly int m_CompressedLength; private readonly int m_CompressedHashCode; private readonly string m_ResourcePath; /// /// 初始化资源应用信息的新实例。 /// /// 资源名称。 /// 资源所在的文件系统名称。 /// 资源加载方式。 /// 资源偏移。 /// 资源大小。 /// 资源哈希值。 /// 压缩后大小。 /// 压缩后哈希值。 /// 资源路径。 public ApplyInfo(ResourceName resourceName, string fileSystemName, LoadType loadType, long offset, int length, int hashCode, int compressedLength, int compressedHashCode, string resourcePath) { m_ResourceName = resourceName; m_FileSystemName = fileSystemName; m_LoadType = loadType; m_Offset = offset; m_Length = length; m_HashCode = hashCode; m_CompressedLength = compressedLength; m_CompressedHashCode = compressedHashCode; m_ResourcePath = resourcePath; } /// /// 获取资源名称。 /// public ResourceName ResourceName { get { return m_ResourceName; } } /// /// 获取资源是否使用文件系统。 /// public bool UseFileSystem { get { return !string.IsNullOrEmpty(m_FileSystemName); } } /// /// 获取资源所在的文件系统名称。 /// public string FileSystemName { get { return m_FileSystemName; } } /// /// 获取资源加载方式。 /// public LoadType LoadType { get { return m_LoadType; } } /// /// 获取资源偏移。 /// public long Offset { get { return m_Offset; } } /// /// 获取资源大小。 /// public int Length { get { return m_Length; } } /// /// 获取资源哈希值。 /// public int HashCode { get { return m_HashCode; } } /// /// 获取压缩后大小。 /// public int CompressedLength { get { return m_CompressedLength; } } /// /// 获取压缩后哈希值。 /// public int CompressedHashCode { get { return m_CompressedHashCode; } } /// /// 获取资源路径。 /// public string ResourcePath { get { return m_ResourcePath; } } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceUpdater.UpdateInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceUpdater { /// /// 资源更新信息。 /// private sealed class UpdateInfo { private readonly ResourceName m_ResourceName; private readonly string m_FileSystemName; private readonly LoadType m_LoadType; private readonly int m_Length; private readonly int m_HashCode; private readonly int m_CompressedLength; private readonly int m_CompressedHashCode; private readonly string m_ResourcePath; private bool m_Downloading; private int m_RetryCount; /// /// 初始化资源更新信息的新实例。 /// /// 资源名称。 /// 资源所在的文件系统名称。 /// 资源加载方式。 /// 资源大小。 /// 资源哈希值。 /// 压缩后大小。 /// 压缩后哈希值。 /// 资源路径。 public UpdateInfo(ResourceName resourceName, string fileSystemName, LoadType loadType, int length, int hashCode, int compressedLength, int compressedHashCode, string resourcePath) { m_ResourceName = resourceName; m_FileSystemName = fileSystemName; m_LoadType = loadType; m_Length = length; m_HashCode = hashCode; m_CompressedLength = compressedLength; m_CompressedHashCode = compressedHashCode; m_ResourcePath = resourcePath; m_Downloading = false; m_RetryCount = 0; } /// /// 获取资源名称。 /// public ResourceName ResourceName { get { return m_ResourceName; } } /// /// 获取资源是否使用文件系统。 /// public bool UseFileSystem { get { return !string.IsNullOrEmpty(m_FileSystemName); } } /// /// 获取资源所在的文件系统名称。 /// public string FileSystemName { get { return m_FileSystemName; } } /// /// 获取资源加载方式。 /// public LoadType LoadType { get { return m_LoadType; } } /// /// 获取资源大小。 /// public int Length { get { return m_Length; } } /// /// 获取资源哈希值。 /// public int HashCode { get { return m_HashCode; } } /// /// 获取压缩后大小。 /// public int CompressedLength { get { return m_CompressedLength; } } /// /// 获取压缩后哈希值。 /// public int CompressedHashCode { get { return m_CompressedHashCode; } } /// /// 获取资源路径。 /// public string ResourcePath { get { return m_ResourcePath; } } /// /// 获取或设置下载状态。 /// public bool Downloading { get { return m_Downloading; } set { m_Downloading = value; } } /// /// 获取或设置已重试次数。 /// public int RetryCount { get { return m_RetryCount; } set { m_RetryCount = value; } } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceUpdater.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Download; using GameFramework.FileSystem; using System; using System.Collections.Generic; using System.IO; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源更新器。 /// private sealed partial class ResourceUpdater { private const int CachedHashBytesLength = 4; private const int CachedBytesLength = 0x1000; private readonly ResourceManager m_ResourceManager; private readonly Queue m_ApplyWaitingInfo; private readonly List m_UpdateWaitingInfo; private readonly HashSet m_UpdateWaitingInfoWhilePlaying; private readonly Dictionary m_UpdateCandidateInfo; private readonly SortedDictionary> m_CachedFileSystemsForGenerateReadWriteVersionList; private readonly List m_CachedResourceNames; private readonly byte[] m_CachedHashBytes; private readonly byte[] m_CachedBytes; private IDownloadManager m_DownloadManager; private bool m_CheckResourcesComplete; private string m_ApplyingResourcePackPath; private FileStream m_ApplyingResourcePackStream; private ResourceGroup m_UpdatingResourceGroup; private int m_GenerateReadWriteVersionListLength; private int m_CurrentGenerateReadWriteVersionListLength; private int m_UpdateRetryCount; private bool m_FailureFlag; private string m_ReadWriteVersionListFileName; private string m_ReadWriteVersionListTempFileName; public GameFrameworkAction ResourceApplyStart; public GameFrameworkAction ResourceApplySuccess; public GameFrameworkAction ResourceApplyFailure; public GameFrameworkAction ResourceApplyComplete; public GameFrameworkAction ResourceUpdateStart; public GameFrameworkAction ResourceUpdateChanged; public GameFrameworkAction ResourceUpdateSuccess; public GameFrameworkAction ResourceUpdateFailure; public GameFrameworkAction ResourceUpdateComplete; public GameFrameworkAction ResourceUpdateAllComplete; /// /// 初始化资源更新器的新实例。 /// /// 资源管理器。 public ResourceUpdater(ResourceManager resourceManager) { m_ResourceManager = resourceManager; m_ApplyWaitingInfo = new Queue(); m_UpdateWaitingInfo = new List(); m_UpdateWaitingInfoWhilePlaying = new HashSet(); m_UpdateCandidateInfo = new Dictionary(); m_CachedFileSystemsForGenerateReadWriteVersionList = new SortedDictionary>(StringComparer.Ordinal); m_CachedResourceNames = new List(); m_CachedHashBytes = new byte[CachedHashBytesLength]; m_CachedBytes = new byte[CachedBytesLength]; m_DownloadManager = null; m_CheckResourcesComplete = false; m_ApplyingResourcePackPath = null; m_ApplyingResourcePackStream = null; m_UpdatingResourceGroup = null; m_GenerateReadWriteVersionListLength = 0; m_CurrentGenerateReadWriteVersionListLength = 0; m_UpdateRetryCount = 3; m_FailureFlag = false; m_ReadWriteVersionListFileName = Utility.Path.GetRegularPath(Path.Combine(m_ResourceManager.m_ReadWritePath, LocalVersionListFileName)); m_ReadWriteVersionListTempFileName = Utility.Text.Format("{0}.{1}", m_ReadWriteVersionListFileName, TempExtension); ResourceApplyStart = null; ResourceApplySuccess = null; ResourceApplyFailure = null; ResourceApplyComplete = null; ResourceUpdateStart = null; ResourceUpdateChanged = null; ResourceUpdateSuccess = null; ResourceUpdateFailure = null; ResourceUpdateComplete = null; ResourceUpdateAllComplete = null; } /// /// 获取或设置每更新多少字节的资源,重新生成一次版本资源列表。 /// public int GenerateReadWriteVersionListLength { get { return m_GenerateReadWriteVersionListLength; } set { m_GenerateReadWriteVersionListLength = value; } } /// /// 获取正在应用的资源包路径。 /// public string ApplyingResourcePackPath { get { return m_ApplyingResourcePackPath; } } /// /// 获取等待应用资源数量。 /// public int ApplyWaitingCount { get { return m_ApplyWaitingInfo.Count; } } /// /// 获取或设置资源更新重试次数。 /// public int UpdateRetryCount { get { return m_UpdateRetryCount; } set { m_UpdateRetryCount = value; } } /// /// 获取正在更新的资源组。 /// public IResourceGroup UpdatingResourceGroup { get { return m_UpdatingResourceGroup; } } /// /// 获取等待更新资源数量。 /// public int UpdateWaitingCount { get { return m_UpdateWaitingInfo.Count; } } /// /// 获取使用时下载的等待更新资源数量。 /// public int UpdateWaitingWhilePlayingCount { get { return m_UpdateWaitingInfoWhilePlaying.Count; } } /// /// 获取候选更新资源数量。 /// public int UpdateCandidateCount { get { return m_UpdateCandidateInfo.Count; } } /// /// 资源更新器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void Update(float elapseSeconds, float realElapseSeconds) { if (m_ApplyingResourcePackStream != null) { while (m_ApplyWaitingInfo.Count > 0) { ApplyInfo applyInfo = m_ApplyWaitingInfo.Dequeue(); if (ApplyResource(applyInfo)) { return; } } Array.Clear(m_CachedBytes, 0, CachedBytesLength); string resourcePackPath = m_ApplyingResourcePackPath; m_ApplyingResourcePackPath = null; m_ApplyingResourcePackStream.Dispose(); m_ApplyingResourcePackStream = null; if (ResourceApplyComplete != null) { ResourceApplyComplete(resourcePackPath, !m_FailureFlag); } if (m_UpdateCandidateInfo.Count <= 0 && ResourceUpdateAllComplete != null) { ResourceUpdateAllComplete(); } return; } if (m_UpdateWaitingInfo.Count > 0) { int freeCount = m_DownloadManager.FreeAgentCount - m_DownloadManager.WaitingTaskCount; if (freeCount > 0) { for (int i = 0, count = 0; i < m_UpdateWaitingInfo.Count && count < freeCount; i++) { if (DownloadResource(m_UpdateWaitingInfo[i])) { count++; } } } return; } } /// /// 关闭并清理资源更新器。 /// public void Shutdown() { if (m_DownloadManager != null) { m_DownloadManager.DownloadStart -= OnDownloadStart; m_DownloadManager.DownloadUpdate -= OnDownloadUpdate; m_DownloadManager.DownloadSuccess -= OnDownloadSuccess; m_DownloadManager.DownloadFailure -= OnDownloadFailure; } m_UpdateWaitingInfo.Clear(); m_UpdateCandidateInfo.Clear(); m_CachedFileSystemsForGenerateReadWriteVersionList.Clear(); } /// /// 设置下载管理器。 /// /// 下载管理器。 public void SetDownloadManager(IDownloadManager downloadManager) { if (downloadManager == null) { throw new GameFrameworkException("Download manager is invalid."); } m_DownloadManager = downloadManager; m_DownloadManager.DownloadStart += OnDownloadStart; m_DownloadManager.DownloadUpdate += OnDownloadUpdate; m_DownloadManager.DownloadSuccess += OnDownloadSuccess; m_DownloadManager.DownloadFailure += OnDownloadFailure; } /// /// 增加资源更新。 /// /// 资源名称。 /// 资源所在的文件系统名称。 /// 资源加载方式。 /// 资源大小。 /// 资源哈希值。 /// 压缩后大小。 /// 压缩后哈希值。 /// 资源路径。 public void AddResourceUpdate(ResourceName resourceName, string fileSystemName, LoadType loadType, int length, int hashCode, int compressedLength, int compressedHashCode, string resourcePath) { m_UpdateCandidateInfo.Add(resourceName, new UpdateInfo(resourceName, fileSystemName, loadType, length, hashCode, compressedLength, compressedHashCode, resourcePath)); } /// /// 检查资源完成。 /// /// 是否需要生成读写区版本资源列表。 public void CheckResourceComplete(bool needGenerateReadWriteVersionList) { m_CheckResourcesComplete = true; if (needGenerateReadWriteVersionList) { GenerateReadWriteVersionList(); } } /// /// 应用指定资源包的资源。 /// /// 要应用的资源包路径。 public void ApplyResources(string resourcePackPath) { if (!m_CheckResourcesComplete) { throw new GameFrameworkException("You must check resources complete first."); } if (m_ApplyingResourcePackStream != null) { throw new GameFrameworkException(Utility.Text.Format("There is already a resource pack '{0}' being applied.", m_ApplyingResourcePackPath)); } if (m_UpdatingResourceGroup != null) { throw new GameFrameworkException(Utility.Text.Format("There is already a resource group '{0}' being updated.", m_UpdatingResourceGroup.Name)); } if (m_UpdateWaitingInfoWhilePlaying.Count > 0) { throw new GameFrameworkException("There are already some resources being updated while playing."); } try { long length = 0L; ResourcePackVersionList versionList = default(ResourcePackVersionList); using (FileStream fileStream = new FileStream(resourcePackPath, FileMode.Open, FileAccess.Read)) { length = fileStream.Length; versionList = m_ResourceManager.m_ResourcePackVersionListSerializer.Deserialize(fileStream); } if (!versionList.IsValid) { throw new GameFrameworkException("Deserialize resource pack version list failure."); } if (versionList.Offset + versionList.Length != length) { throw new GameFrameworkException("Resource pack length is invalid."); } m_ApplyingResourcePackPath = resourcePackPath; m_ApplyingResourcePackStream = new FileStream(resourcePackPath, FileMode.Open, FileAccess.Read); m_ApplyingResourcePackStream.Position = versionList.Offset; m_FailureFlag = false; long totalLength = 0L; ResourcePackVersionList.Resource[] resources = versionList.GetResources(); foreach (ResourcePackVersionList.Resource resource in resources) { ResourceName resourceName = new ResourceName(resource.Name, resource.Variant, resource.Extension); UpdateInfo updateInfo = null; if (!m_UpdateCandidateInfo.TryGetValue(resourceName, out updateInfo)) { continue; } if (updateInfo.LoadType == (LoadType)resource.LoadType && updateInfo.Length == resource.Length && updateInfo.HashCode == resource.HashCode) { totalLength += resource.Length; m_ApplyWaitingInfo.Enqueue(new ApplyInfo(resourceName, updateInfo.FileSystemName, (LoadType)resource.LoadType, resource.Offset, resource.Length, resource.HashCode, resource.CompressedLength, resource.CompressedHashCode, updateInfo.ResourcePath)); } } if (ResourceApplyStart != null) { ResourceApplyStart(m_ApplyingResourcePackPath, m_ApplyWaitingInfo.Count, totalLength); } } catch (Exception exception) { if (m_ApplyingResourcePackStream != null) { m_ApplyingResourcePackStream.Dispose(); m_ApplyingResourcePackStream = null; } throw new GameFrameworkException(Utility.Text.Format("Apply resources '{0}' with exception '{1}'.", resourcePackPath, exception), exception); } } /// /// 更新指定资源组的资源。 /// /// 要更新的资源组。 public void UpdateResources(ResourceGroup resourceGroup) { if (m_DownloadManager == null) { throw new GameFrameworkException("You must set download manager first."); } if (!m_CheckResourcesComplete) { throw new GameFrameworkException("You must check resources complete first."); } if (m_ApplyingResourcePackStream != null) { throw new GameFrameworkException(Utility.Text.Format("There is already a resource pack '{0}' being applied.", m_ApplyingResourcePackPath)); } if (m_UpdatingResourceGroup != null) { throw new GameFrameworkException(Utility.Text.Format("There is already a resource group '{0}' being updated.", m_UpdatingResourceGroup.Name)); } if (string.IsNullOrEmpty(resourceGroup.Name)) { foreach (KeyValuePair updateInfo in m_UpdateCandidateInfo) { m_UpdateWaitingInfo.Add(updateInfo.Value); } } else { resourceGroup.InternalGetResourceNames(m_CachedResourceNames); foreach (ResourceName resourceName in m_CachedResourceNames) { UpdateInfo updateInfo = null; if (!m_UpdateCandidateInfo.TryGetValue(resourceName, out updateInfo)) { continue; } m_UpdateWaitingInfo.Add(updateInfo); } m_CachedResourceNames.Clear(); } m_UpdatingResourceGroup = resourceGroup; m_FailureFlag = false; } /// /// 停止更新资源。 /// public void StopUpdateResources() { if (m_DownloadManager == null) { throw new GameFrameworkException("You must set download manager first."); } if (!m_CheckResourcesComplete) { throw new GameFrameworkException("You must check resources complete first."); } if (m_ApplyingResourcePackStream != null) { throw new GameFrameworkException(Utility.Text.Format("There is already a resource pack '{0}' being applied.", m_ApplyingResourcePackPath)); } if (m_UpdatingResourceGroup == null) { throw new GameFrameworkException("There is no resource group being updated."); } m_UpdateWaitingInfo.Clear(); m_UpdatingResourceGroup = null; } /// /// 更新指定资源。 /// /// 要更新的资源名称。 public void UpdateResource(ResourceName resourceName) { if (m_DownloadManager == null) { throw new GameFrameworkException("You must set download manager first."); } if (!m_CheckResourcesComplete) { throw new GameFrameworkException("You must check resources complete first."); } if (m_ApplyingResourcePackStream != null) { throw new GameFrameworkException(Utility.Text.Format("There is already a resource pack '{0}' being applied.", m_ApplyingResourcePackPath)); } UpdateInfo updateInfo = null; if (m_UpdateCandidateInfo.TryGetValue(resourceName, out updateInfo) && m_UpdateWaitingInfoWhilePlaying.Add(updateInfo)) { DownloadResource(updateInfo); } } private bool ApplyResource(ApplyInfo applyInfo) { long position = m_ApplyingResourcePackStream.Position; try { bool compressed = applyInfo.Length != applyInfo.CompressedLength || applyInfo.HashCode != applyInfo.CompressedHashCode; int bytesRead = 0; int bytesLeft = applyInfo.CompressedLength; string directory = Path.GetDirectoryName(applyInfo.ResourcePath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } m_ApplyingResourcePackStream.Position += applyInfo.Offset; using (FileStream fileStream = new FileStream(applyInfo.ResourcePath, FileMode.Create, FileAccess.ReadWrite)) { while ((bytesRead = m_ApplyingResourcePackStream.Read(m_CachedBytes, 0, bytesLeft < CachedBytesLength ? bytesLeft : CachedBytesLength)) > 0) { bytesLeft -= bytesRead; fileStream.Write(m_CachedBytes, 0, bytesRead); } if (compressed) { fileStream.Position = 0L; int hashCode = Utility.Verifier.GetCrc32(fileStream); if (hashCode != applyInfo.CompressedHashCode) { if (ResourceApplyFailure != null) { string errorMessage = Utility.Text.Format("Resource compressed hash code error, need '{0}', applied '{1}'.", applyInfo.CompressedHashCode, hashCode); ResourceApplyFailure(applyInfo.ResourceName, m_ApplyingResourcePackPath, errorMessage); } m_FailureFlag = true; return false; } fileStream.Position = 0L; m_ResourceManager.PrepareCachedStream(); if (!Utility.Compression.Decompress(fileStream, m_ResourceManager.m_CachedStream)) { if (ResourceApplyFailure != null) { string errorMessage = Utility.Text.Format("Unable to decompress resource '{0}'.", applyInfo.ResourcePath); ResourceApplyFailure(applyInfo.ResourceName, m_ApplyingResourcePackPath, errorMessage); } m_FailureFlag = true; return false; } fileStream.Position = 0L; fileStream.SetLength(0L); fileStream.Write(m_ResourceManager.m_CachedStream.GetBuffer(), 0, (int)m_ResourceManager.m_CachedStream.Length); } else { int hashCode = 0; fileStream.Position = 0L; if (applyInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || applyInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt || applyInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || applyInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { Utility.Converter.GetBytes(applyInfo.HashCode, m_CachedHashBytes); if (applyInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || applyInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt) { hashCode = Utility.Verifier.GetCrc32(fileStream, m_CachedHashBytes, Utility.Encryption.QuickEncryptLength); } else if (applyInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt || applyInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { hashCode = Utility.Verifier.GetCrc32(fileStream, m_CachedHashBytes, applyInfo.Length); } Array.Clear(m_CachedHashBytes, 0, CachedHashBytesLength); } else { hashCode = Utility.Verifier.GetCrc32(fileStream); } if (hashCode != applyInfo.HashCode) { if (ResourceApplyFailure != null) { string errorMessage = Utility.Text.Format("Resource hash code error, need '{0}', applied '{1}'.", applyInfo.HashCode, hashCode); ResourceApplyFailure(applyInfo.ResourceName, m_ApplyingResourcePackPath, errorMessage); } m_FailureFlag = true; return false; } } } if (applyInfo.UseFileSystem) { IFileSystem fileSystem = m_ResourceManager.GetFileSystem(applyInfo.FileSystemName, false); bool retVal = fileSystem.WriteFile(applyInfo.ResourceName.FullName, applyInfo.ResourcePath); if (File.Exists(applyInfo.ResourcePath)) { File.Delete(applyInfo.ResourcePath); } if (!retVal) { if (ResourceApplyFailure != null) { string errorMessage = Utility.Text.Format("Unable to write resource '{0}' to file system '{1}'.", applyInfo.ResourcePath, applyInfo.FileSystemName); ResourceApplyFailure(applyInfo.ResourceName, m_ApplyingResourcePackPath, errorMessage); } m_FailureFlag = true; return false; } } string downloadingResource = Utility.Text.Format("{0}.download", applyInfo.ResourcePath); if (File.Exists(downloadingResource)) { File.Delete(downloadingResource); } m_UpdateCandidateInfo.Remove(applyInfo.ResourceName); m_ResourceManager.m_ResourceInfos[applyInfo.ResourceName].MarkReady(); m_ResourceManager.m_ReadWriteResourceInfos.Add(applyInfo.ResourceName, new ReadWriteResourceInfo(applyInfo.FileSystemName, applyInfo.LoadType, applyInfo.Length, applyInfo.HashCode)); if (ResourceApplySuccess != null) { ResourceApplySuccess(applyInfo.ResourceName, applyInfo.ResourcePath, m_ApplyingResourcePackPath, applyInfo.Length, applyInfo.CompressedLength); } m_CurrentGenerateReadWriteVersionListLength += applyInfo.CompressedLength; if (m_ApplyWaitingInfo.Count <= 0 || m_CurrentGenerateReadWriteVersionListLength >= m_GenerateReadWriteVersionListLength) { GenerateReadWriteVersionList(); return true; } return false; } catch (Exception exception) { if (ResourceApplyFailure != null) { ResourceApplyFailure(applyInfo.ResourceName, m_ApplyingResourcePackPath, exception.ToString()); } m_FailureFlag = true; return false; } finally { m_ApplyingResourcePackStream.Position = position; } } private bool DownloadResource(UpdateInfo updateInfo) { if (updateInfo.Downloading) { return false; } updateInfo.Downloading = true; string resourceFullNameWithCrc32 = updateInfo.ResourceName.Variant != null ? Utility.Text.Format("{0}.{1}.{2:x8}.{3}", updateInfo.ResourceName.Name, updateInfo.ResourceName.Variant, updateInfo.HashCode, DefaultExtension) : Utility.Text.Format("{0}.{1:x8}.{2}", updateInfo.ResourceName.Name, updateInfo.HashCode, DefaultExtension); m_DownloadManager.AddDownload(updateInfo.ResourcePath, Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_UpdatePrefixUri, resourceFullNameWithCrc32)), updateInfo); return true; } private void GenerateReadWriteVersionList() { FileStream fileStream = null; try { fileStream = new FileStream(m_ReadWriteVersionListTempFileName, FileMode.Create, FileAccess.Write); LocalVersionList.Resource[] resources = m_ResourceManager.m_ReadWriteResourceInfos.Count > 0 ? new LocalVersionList.Resource[m_ResourceManager.m_ReadWriteResourceInfos.Count] : null; if (resources != null) { int index = 0; foreach (KeyValuePair i in m_ResourceManager.m_ReadWriteResourceInfos) { ResourceName resourceName = i.Key; ReadWriteResourceInfo resourceInfo = i.Value; resources[index] = new LocalVersionList.Resource(resourceName.Name, resourceName.Variant, resourceName.Extension, (byte)resourceInfo.LoadType, resourceInfo.Length, resourceInfo.HashCode); if (resourceInfo.UseFileSystem) { List resourceIndexes = null; if (!m_CachedFileSystemsForGenerateReadWriteVersionList.TryGetValue(resourceInfo.FileSystemName, out resourceIndexes)) { resourceIndexes = new List(); m_CachedFileSystemsForGenerateReadWriteVersionList.Add(resourceInfo.FileSystemName, resourceIndexes); } resourceIndexes.Add(index); } index++; } } LocalVersionList.FileSystem[] fileSystems = m_CachedFileSystemsForGenerateReadWriteVersionList.Count > 0 ? new LocalVersionList.FileSystem[m_CachedFileSystemsForGenerateReadWriteVersionList.Count] : null; if (fileSystems != null) { int index = 0; foreach (KeyValuePair> i in m_CachedFileSystemsForGenerateReadWriteVersionList) { fileSystems[index++] = new LocalVersionList.FileSystem(i.Key, i.Value.ToArray()); i.Value.Clear(); } } LocalVersionList versionList = new LocalVersionList(resources, fileSystems); if (!m_ResourceManager.m_ReadWriteVersionListSerializer.Serialize(fileStream, versionList)) { throw new GameFrameworkException("Serialize read-write version list failure."); } if (fileStream != null) { fileStream.Dispose(); fileStream = null; } } catch (Exception exception) { if (fileStream != null) { fileStream.Dispose(); fileStream = null; } if (File.Exists(m_ReadWriteVersionListTempFileName)) { File.Delete(m_ReadWriteVersionListTempFileName); } throw new GameFrameworkException(Utility.Text.Format("Generate read-write version list exception '{0}'.", exception), exception); } if (File.Exists(m_ReadWriteVersionListFileName)) { File.Delete(m_ReadWriteVersionListFileName); } File.Move(m_ReadWriteVersionListTempFileName, m_ReadWriteVersionListFileName); m_CurrentGenerateReadWriteVersionListLength = 0; } private void OnDownloadStart(object sender, DownloadStartEventArgs e) { UpdateInfo updateInfo = e.UserData as UpdateInfo; if (updateInfo == null) { return; } if (m_DownloadManager == null) { throw new GameFrameworkException("You must set download manager first."); } if (e.CurrentLength > int.MaxValue) { throw new GameFrameworkException(Utility.Text.Format("File '{0}' is too large.", e.DownloadPath)); } if (ResourceUpdateStart != null) { ResourceUpdateStart(updateInfo.ResourceName, e.DownloadPath, e.DownloadUri, (int)e.CurrentLength, updateInfo.CompressedLength, updateInfo.RetryCount); } } private void OnDownloadUpdate(object sender, DownloadUpdateEventArgs e) { UpdateInfo updateInfo = e.UserData as UpdateInfo; if (updateInfo == null) { return; } if (m_DownloadManager == null) { throw new GameFrameworkException("You must set download manager first."); } if (e.CurrentLength > updateInfo.CompressedLength) { m_DownloadManager.RemoveDownload(e.SerialId); string downloadFile = Utility.Text.Format("{0}.download", e.DownloadPath); if (File.Exists(downloadFile)) { File.Delete(downloadFile); } string errorMessage = Utility.Text.Format("When download update, downloaded length is larger than compressed length, need '{0}', downloaded '{1}'.", updateInfo.CompressedLength, e.CurrentLength); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } if (ResourceUpdateChanged != null) { ResourceUpdateChanged(updateInfo.ResourceName, e.DownloadPath, e.DownloadUri, (int)e.CurrentLength, updateInfo.CompressedLength); } } private void OnDownloadSuccess(object sender, DownloadSuccessEventArgs e) { UpdateInfo updateInfo = e.UserData as UpdateInfo; if (updateInfo == null) { return; } try { using (FileStream fileStream = new FileStream(e.DownloadPath, FileMode.Open, FileAccess.ReadWrite)) { bool compressed = updateInfo.Length != updateInfo.CompressedLength || updateInfo.HashCode != updateInfo.CompressedHashCode; int length = (int)fileStream.Length; if (length != updateInfo.CompressedLength) { fileStream.Close(); string errorMessage = Utility.Text.Format("Resource compressed length error, need '{0}', downloaded '{1}'.", updateInfo.CompressedLength, length); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } if (compressed) { fileStream.Position = 0L; int hashCode = Utility.Verifier.GetCrc32(fileStream); if (hashCode != updateInfo.CompressedHashCode) { fileStream.Close(); string errorMessage = Utility.Text.Format("Resource compressed hash code error, need '{0}', downloaded '{1}'.", updateInfo.CompressedHashCode, hashCode); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } fileStream.Position = 0L; m_ResourceManager.PrepareCachedStream(); if (!Utility.Compression.Decompress(fileStream, m_ResourceManager.m_CachedStream)) { fileStream.Close(); string errorMessage = Utility.Text.Format("Unable to decompress resource '{0}'.", e.DownloadPath); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } int uncompressedLength = (int)m_ResourceManager.m_CachedStream.Length; if (uncompressedLength != updateInfo.Length) { fileStream.Close(); string errorMessage = Utility.Text.Format("Resource length error, need '{0}', downloaded '{1}'.", updateInfo.Length, uncompressedLength); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } fileStream.Position = 0L; fileStream.SetLength(0L); fileStream.Write(m_ResourceManager.m_CachedStream.GetBuffer(), 0, uncompressedLength); } else { int hashCode = 0; fileStream.Position = 0L; if (updateInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || updateInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt || updateInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || updateInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { Utility.Converter.GetBytes(updateInfo.HashCode, m_CachedHashBytes); if (updateInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || updateInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt) { hashCode = Utility.Verifier.GetCrc32(fileStream, m_CachedHashBytes, Utility.Encryption.QuickEncryptLength); } else if (updateInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt || updateInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { hashCode = Utility.Verifier.GetCrc32(fileStream, m_CachedHashBytes, length); } Array.Clear(m_CachedHashBytes, 0, CachedHashBytesLength); } else { hashCode = Utility.Verifier.GetCrc32(fileStream); } if (hashCode != updateInfo.HashCode) { fileStream.Close(); string errorMessage = Utility.Text.Format("Resource hash code error, need '{0}', downloaded '{1}'.", updateInfo.HashCode, hashCode); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } } } if (updateInfo.UseFileSystem) { IFileSystem fileSystem = m_ResourceManager.GetFileSystem(updateInfo.FileSystemName, false); bool retVal = fileSystem.WriteFile(updateInfo.ResourceName.FullName, updateInfo.ResourcePath); if (File.Exists(updateInfo.ResourcePath)) { File.Delete(updateInfo.ResourcePath); } if (!retVal) { string errorMessage = Utility.Text.Format("Write resource to file system '{0}' error.", fileSystem.FullPath); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } } m_UpdateCandidateInfo.Remove(updateInfo.ResourceName); m_UpdateWaitingInfo.Remove(updateInfo); m_UpdateWaitingInfoWhilePlaying.Remove(updateInfo); m_ResourceManager.m_ResourceInfos[updateInfo.ResourceName].MarkReady(); m_ResourceManager.m_ReadWriteResourceInfos.Add(updateInfo.ResourceName, new ReadWriteResourceInfo(updateInfo.FileSystemName, updateInfo.LoadType, updateInfo.Length, updateInfo.HashCode)); if (ResourceUpdateSuccess != null) { ResourceUpdateSuccess(updateInfo.ResourceName, e.DownloadPath, e.DownloadUri, updateInfo.Length, updateInfo.CompressedLength); } m_CurrentGenerateReadWriteVersionListLength += updateInfo.CompressedLength; if (m_UpdateCandidateInfo.Count <= 0 || m_UpdateWaitingInfo.Count + m_UpdateWaitingInfoWhilePlaying.Count <= 0 || m_CurrentGenerateReadWriteVersionListLength >= m_GenerateReadWriteVersionListLength) { GenerateReadWriteVersionList(); } if (m_UpdatingResourceGroup != null && m_UpdateWaitingInfo.Count <= 0) { ResourceGroup updatingResourceGroup = m_UpdatingResourceGroup; m_UpdatingResourceGroup = null; if (ResourceUpdateComplete != null) { ResourceUpdateComplete(updatingResourceGroup, !m_FailureFlag); } } if (m_UpdateCandidateInfo.Count <= 0 && ResourceUpdateAllComplete != null) { ResourceUpdateAllComplete(); } } catch (Exception exception) { string errorMessage = Utility.Text.Format("Update resource '{0}' with error message '{1}'.", e.DownloadPath, exception); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); } } private void OnDownloadFailure(object sender, DownloadFailureEventArgs e) { UpdateInfo updateInfo = e.UserData as UpdateInfo; if (updateInfo == null) { return; } if (File.Exists(e.DownloadPath)) { File.Delete(e.DownloadPath); } if (ResourceUpdateFailure != null) { ResourceUpdateFailure(updateInfo.ResourceName, e.DownloadUri, updateInfo.RetryCount, m_UpdateRetryCount, e.ErrorMessage); } if (updateInfo.RetryCount < m_UpdateRetryCount) { updateInfo.Downloading = false; updateInfo.RetryCount++; if (m_UpdateWaitingInfoWhilePlaying.Contains(updateInfo)) { DownloadResource(updateInfo); } } else { m_FailureFlag = true; updateInfo.Downloading = false; updateInfo.RetryCount = 0; m_UpdateWaitingInfo.Remove(updateInfo); m_UpdateWaitingInfoWhilePlaying.Remove(updateInfo); } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceVerifier.VerifyInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private sealed partial class ResourceVerifier { /// /// 资源校验信息。 /// private struct VerifyInfo { private readonly ResourceName m_ResourceName; private readonly string m_FileSystemName; private readonly LoadType m_LoadType; private readonly int m_Length; private readonly int m_HashCode; /// /// 初始化资源校验信息的新实例。 /// /// 资源名称。 /// 资源所在的文件系统名称。 /// 资源加载方式。 /// 资源大小。 /// 资源哈希值。 public VerifyInfo(ResourceName resourceName, string fileSystemName, LoadType loadType, int length, int hashCode) { m_ResourceName = resourceName; m_FileSystemName = fileSystemName; m_LoadType = loadType; m_Length = length; m_HashCode = hashCode; } /// /// 获取资源名称。 /// public ResourceName ResourceName { get { return m_ResourceName; } } /// /// 获取资源是否使用文件系统。 /// public bool UseFileSystem { get { return !string.IsNullOrEmpty(m_FileSystemName); } } /// /// 获取资源所在的文件系统名称。 /// public string FileSystemName { get { return m_FileSystemName; } } /// /// 获取资源加载方式。 /// public LoadType LoadType { get { return m_LoadType; } } /// /// 获取资源大小。 /// public int Length { get { return m_Length; } } /// /// 获取资源哈希值。 /// public int HashCode { get { return m_HashCode; } } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.ResourceVerifier.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.FileSystem; using System; using System.Collections.Generic; using System.IO; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 资源校验器。 /// private sealed partial class ResourceVerifier { private const int CachedHashBytesLength = 4; private readonly ResourceManager m_ResourceManager; private readonly List m_VerifyInfos; private readonly byte[] m_CachedHashBytes; private bool m_LoadReadWriteVersionListComplete; private int m_VerifyResourceLengthPerFrame; private int m_VerifyResourceIndex; private bool m_FailureFlag; public GameFrameworkAction ResourceVerifyStart; public GameFrameworkAction ResourceVerifySuccess; public GameFrameworkAction ResourceVerifyFailure; public GameFrameworkAction ResourceVerifyComplete; /// /// 初始化资源校验器的新实例。 /// /// 资源管理器。 public ResourceVerifier(ResourceManager resourceManager) { m_ResourceManager = resourceManager; m_VerifyInfos = new List(); m_CachedHashBytes = new byte[CachedHashBytesLength]; m_LoadReadWriteVersionListComplete = false; m_VerifyResourceLengthPerFrame = 0; m_VerifyResourceIndex = 0; m_FailureFlag = false; ResourceVerifyStart = null; ResourceVerifySuccess = null; ResourceVerifyFailure = null; ResourceVerifyComplete = null; } /// /// 资源校验器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void Update(float elapseSeconds, float realElapseSeconds) { if (!m_LoadReadWriteVersionListComplete) { return; } int length = 0; while (m_VerifyResourceIndex < m_VerifyInfos.Count) { VerifyInfo verifyInfo = m_VerifyInfos[m_VerifyResourceIndex]; length += verifyInfo.Length; if (VerifyResource(verifyInfo)) { m_VerifyResourceIndex++; if (ResourceVerifySuccess != null) { ResourceVerifySuccess(verifyInfo.ResourceName, verifyInfo.Length); } } else { m_FailureFlag = true; m_VerifyInfos.RemoveAt(m_VerifyResourceIndex); if (ResourceVerifyFailure != null) { ResourceVerifyFailure(verifyInfo.ResourceName); } } if (length >= m_VerifyResourceLengthPerFrame) { return; } } m_LoadReadWriteVersionListComplete = false; if (m_FailureFlag) { GenerateReadWriteVersionList(); } if (ResourceVerifyComplete != null) { ResourceVerifyComplete(!m_FailureFlag); } } /// /// 关闭并清理资源校验器。 /// public void Shutdown() { m_VerifyInfos.Clear(); m_LoadReadWriteVersionListComplete = false; m_VerifyResourceLengthPerFrame = 0; m_VerifyResourceIndex = 0; m_FailureFlag = false; } /// /// 校验资源。 /// /// 每帧至少校验资源的大小,以字节为单位。 public void VerifyResources(int verifyResourceLengthPerFrame) { if (verifyResourceLengthPerFrame < 0) { throw new GameFrameworkException("Verify resource count per frame is invalid."); } if (m_ResourceManager.m_ResourceHelper == null) { throw new GameFrameworkException("Resource helper is invalid."); } if (string.IsNullOrEmpty(m_ResourceManager.m_ReadWritePath)) { throw new GameFrameworkException("Read-write path is invalid."); } m_VerifyResourceLengthPerFrame = verifyResourceLengthPerFrame; m_ResourceManager.m_ResourceHelper.LoadBytes(Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_ReadWritePath, LocalVersionListFileName)), new LoadBytesCallbacks(OnLoadReadWriteVersionListSuccess, OnLoadReadWriteVersionListFailure), null); } private bool VerifyResource(VerifyInfo verifyInfo) { if (verifyInfo.UseFileSystem) { IFileSystem fileSystem = m_ResourceManager.GetFileSystem(verifyInfo.FileSystemName, false); string fileName = verifyInfo.ResourceName.FullName; FileSystem.FileInfo fileInfo = fileSystem.GetFileInfo(fileName); if (!fileInfo.IsValid) { return false; } int length = fileInfo.Length; if (length == verifyInfo.Length) { m_ResourceManager.PrepareCachedStream(); fileSystem.ReadFile(fileName, m_ResourceManager.m_CachedStream); m_ResourceManager.m_CachedStream.Position = 0L; int hashCode = 0; if (verifyInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || verifyInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt || verifyInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || verifyInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { Utility.Converter.GetBytes(verifyInfo.HashCode, m_CachedHashBytes); if (verifyInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || verifyInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt) { hashCode = Utility.Verifier.GetCrc32(m_ResourceManager.m_CachedStream, m_CachedHashBytes, Utility.Encryption.QuickEncryptLength); } else if (verifyInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt || verifyInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { hashCode = Utility.Verifier.GetCrc32(m_ResourceManager.m_CachedStream, m_CachedHashBytes, length); } Array.Clear(m_CachedHashBytes, 0, CachedHashBytesLength); } else { hashCode = Utility.Verifier.GetCrc32(m_ResourceManager.m_CachedStream); } if (hashCode == verifyInfo.HashCode) { return true; } } fileSystem.DeleteFile(fileName); return false; } else { string resourcePath = Utility.Path.GetRegularPath(Path.Combine(m_ResourceManager.ReadWritePath, verifyInfo.ResourceName.FullName)); if (!File.Exists(resourcePath)) { return false; } using (FileStream fileStream = new FileStream(resourcePath, FileMode.Open, FileAccess.Read)) { int length = (int)fileStream.Length; if (length == verifyInfo.Length) { int hashCode = 0; if (verifyInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || verifyInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt || verifyInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || verifyInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { Utility.Converter.GetBytes(verifyInfo.HashCode, m_CachedHashBytes); if (verifyInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || verifyInfo.LoadType == LoadType.LoadFromBinaryAndQuickDecrypt) { hashCode = Utility.Verifier.GetCrc32(fileStream, m_CachedHashBytes, Utility.Encryption.QuickEncryptLength); } else if (verifyInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt || verifyInfo.LoadType == LoadType.LoadFromBinaryAndDecrypt) { hashCode = Utility.Verifier.GetCrc32(fileStream, m_CachedHashBytes, length); } Array.Clear(m_CachedHashBytes, 0, CachedHashBytesLength); } else { hashCode = Utility.Verifier.GetCrc32(fileStream); } if (hashCode == verifyInfo.HashCode) { return true; } } } File.Delete(resourcePath); return false; } } private void GenerateReadWriteVersionList() { string readWriteVersionListFileName = Utility.Path.GetRegularPath(Path.Combine(m_ResourceManager.m_ReadWritePath, LocalVersionListFileName)); string readWriteVersionListTempFileName = Utility.Text.Format("{0}.{1}", readWriteVersionListFileName, TempExtension); SortedDictionary> cachedFileSystemsForGenerateReadWriteVersionList = new SortedDictionary>(StringComparer.Ordinal); FileStream fileStream = null; try { fileStream = new FileStream(readWriteVersionListTempFileName, FileMode.Create, FileAccess.Write); LocalVersionList.Resource[] resources = m_VerifyInfos.Count > 0 ? new LocalVersionList.Resource[m_VerifyInfos.Count] : null; if (resources != null) { int index = 0; foreach (VerifyInfo i in m_VerifyInfos) { resources[index] = new LocalVersionList.Resource(i.ResourceName.Name, i.ResourceName.Variant, i.ResourceName.Extension, (byte)i.LoadType, i.Length, i.HashCode); if (i.UseFileSystem) { List resourceIndexes = null; if (!cachedFileSystemsForGenerateReadWriteVersionList.TryGetValue(i.FileSystemName, out resourceIndexes)) { resourceIndexes = new List(); cachedFileSystemsForGenerateReadWriteVersionList.Add(i.FileSystemName, resourceIndexes); } resourceIndexes.Add(index); } index++; } } LocalVersionList.FileSystem[] fileSystems = cachedFileSystemsForGenerateReadWriteVersionList.Count > 0 ? new LocalVersionList.FileSystem[cachedFileSystemsForGenerateReadWriteVersionList.Count] : null; if (fileSystems != null) { int index = 0; foreach (KeyValuePair> i in cachedFileSystemsForGenerateReadWriteVersionList) { fileSystems[index++] = new LocalVersionList.FileSystem(i.Key, i.Value.ToArray()); i.Value.Clear(); } } LocalVersionList versionList = new LocalVersionList(resources, fileSystems); if (!m_ResourceManager.m_ReadWriteVersionListSerializer.Serialize(fileStream, versionList)) { throw new GameFrameworkException("Serialize read-write version list failure."); } if (fileStream != null) { fileStream.Dispose(); fileStream = null; } } catch (Exception exception) { if (fileStream != null) { fileStream.Dispose(); fileStream = null; } if (File.Exists(readWriteVersionListTempFileName)) { File.Delete(readWriteVersionListTempFileName); } throw new GameFrameworkException(Utility.Text.Format("Generate read-write version list exception '{0}'.", exception), exception); } if (File.Exists(readWriteVersionListFileName)) { File.Delete(readWriteVersionListFileName); } File.Move(readWriteVersionListTempFileName, readWriteVersionListFileName); } private void OnLoadReadWriteVersionListSuccess(string fileUri, byte[] bytes, float duration, object userData) { MemoryStream memoryStream = null; try { memoryStream = new MemoryStream(bytes, false); LocalVersionList versionList = m_ResourceManager.m_ReadWriteVersionListSerializer.Deserialize(memoryStream); if (!versionList.IsValid) { throw new GameFrameworkException("Deserialize read write version list failure."); } LocalVersionList.Resource[] resources = versionList.GetResources(); LocalVersionList.FileSystem[] fileSystems = versionList.GetFileSystems(); Dictionary resourceInFileSystemNames = new Dictionary(); foreach (LocalVersionList.FileSystem fileSystem in fileSystems) { int[] resourceIndexes = fileSystem.GetResourceIndexes(); foreach (int resourceIndex in resourceIndexes) { LocalVersionList.Resource resource = resources[resourceIndex]; resourceInFileSystemNames.Add(new ResourceName(resource.Name, resource.Variant, resource.Extension), fileSystem.Name); } } long totalLength = 0L; foreach (LocalVersionList.Resource resource in resources) { ResourceName resourceName = new ResourceName(resource.Name, resource.Variant, resource.Extension); string fileSystemName = null; resourceInFileSystemNames.TryGetValue(resourceName, out fileSystemName); totalLength += resource.Length; m_VerifyInfos.Add(new VerifyInfo(resourceName, fileSystemName, (LoadType)resource.LoadType, resource.Length, resource.HashCode)); } m_LoadReadWriteVersionListComplete = true; if (ResourceVerifyStart != null) { ResourceVerifyStart(m_VerifyInfos.Count, totalLength); } } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Utility.Text.Format("Parse read-write version list exception '{0}'.", exception), exception); } finally { if (memoryStream != null) { memoryStream.Dispose(); memoryStream = null; } } } private void OnLoadReadWriteVersionListFailure(string fileUri, string errorMessage, object userData) { if (ResourceVerifyComplete != null) { ResourceVerifyComplete(true); } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.VersionListProcessor.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Download; using System; using System.IO; namespace GameFramework.Resource { internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { /// /// 版本资源列表处理器。 /// private sealed class VersionListProcessor { private readonly ResourceManager m_ResourceManager; private IDownloadManager m_DownloadManager; private int m_VersionListLength; private int m_VersionListHashCode; private int m_VersionListCompressedLength; private int m_VersionListCompressedHashCode; public GameFrameworkAction VersionListUpdateSuccess; public GameFrameworkAction VersionListUpdateFailure; /// /// 初始化版本资源列表处理器的新实例。 /// /// 资源管理器。 public VersionListProcessor(ResourceManager resourceManager) { m_ResourceManager = resourceManager; m_DownloadManager = null; m_VersionListLength = 0; m_VersionListHashCode = 0; m_VersionListCompressedLength = 0; m_VersionListCompressedHashCode = 0; VersionListUpdateSuccess = null; VersionListUpdateFailure = null; } /// /// 关闭并清理版本资源列表处理器。 /// public void Shutdown() { if (m_DownloadManager != null) { m_DownloadManager.DownloadSuccess -= OnDownloadSuccess; m_DownloadManager.DownloadFailure -= OnDownloadFailure; } } /// /// 设置下载管理器。 /// /// 下载管理器。 public void SetDownloadManager(IDownloadManager downloadManager) { if (downloadManager == null) { throw new GameFrameworkException("Download manager is invalid."); } m_DownloadManager = downloadManager; m_DownloadManager.DownloadSuccess += OnDownloadSuccess; m_DownloadManager.DownloadFailure += OnDownloadFailure; } /// /// 检查版本资源列表。 /// /// 最新的内部资源版本号。 /// 检查版本资源列表结果。 public CheckVersionListResult CheckVersionList(int latestInternalResourceVersion) { if (string.IsNullOrEmpty(m_ResourceManager.m_ReadWritePath)) { throw new GameFrameworkException("Read-write path is invalid."); } string versionListFileName = Utility.Path.GetRegularPath(Path.Combine(m_ResourceManager.m_ReadWritePath, RemoteVersionListFileName)); if (!File.Exists(versionListFileName)) { return CheckVersionListResult.NeedUpdate; } int internalResourceVersion = 0; FileStream fileStream = null; try { fileStream = new FileStream(versionListFileName, FileMode.Open, FileAccess.Read); object internalResourceVersionObject = null; if (!m_ResourceManager.m_UpdatableVersionListSerializer.TryGetValue(fileStream, "InternalResourceVersion", out internalResourceVersionObject)) { return CheckVersionListResult.NeedUpdate; } internalResourceVersion = (int)internalResourceVersionObject; } catch { return CheckVersionListResult.NeedUpdate; } finally { if (fileStream != null) { fileStream.Dispose(); fileStream = null; } } if (internalResourceVersion != latestInternalResourceVersion) { return CheckVersionListResult.NeedUpdate; } return CheckVersionListResult.Updated; } /// /// 更新版本资源列表。 /// /// 版本资源列表大小。 /// 版本资源列表哈希值。 /// 版本资源列表压缩后大小。 /// 版本资源列表压缩后哈希值。 public void UpdateVersionList(int versionListLength, int versionListHashCode, int versionListCompressedLength, int versionListCompressedHashCode) { if (m_DownloadManager == null) { throw new GameFrameworkException("You must set download manager first."); } m_VersionListLength = versionListLength; m_VersionListHashCode = versionListHashCode; m_VersionListCompressedLength = versionListCompressedLength; m_VersionListCompressedHashCode = versionListCompressedHashCode; string localVersionListFilePath = Utility.Path.GetRegularPath(Path.Combine(m_ResourceManager.m_ReadWritePath, RemoteVersionListFileName)); int dotPosition = RemoteVersionListFileName.LastIndexOf('.'); string latestVersionListFullNameWithCrc32 = Utility.Text.Format("{0}.{2:x8}.{1}", RemoteVersionListFileName.Substring(0, dotPosition), RemoteVersionListFileName.Substring(dotPosition + 1), m_VersionListHashCode); m_DownloadManager.AddDownload(localVersionListFilePath, Utility.Path.GetRemotePath(Path.Combine(m_ResourceManager.m_UpdatePrefixUri, latestVersionListFullNameWithCrc32)), this); } private void OnDownloadSuccess(object sender, DownloadSuccessEventArgs e) { VersionListProcessor versionListProcessor = e.UserData as VersionListProcessor; if (versionListProcessor == null || versionListProcessor != this) { return; } try { using (FileStream fileStream = new FileStream(e.DownloadPath, FileMode.Open, FileAccess.ReadWrite)) { int length = (int)fileStream.Length; if (length != m_VersionListCompressedLength) { fileStream.Close(); string errorMessage = Utility.Text.Format("Latest version list compressed length error, need '{0}', downloaded '{1}'.", m_VersionListCompressedLength, length); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } fileStream.Position = 0L; int hashCode = Utility.Verifier.GetCrc32(fileStream); if (hashCode != m_VersionListCompressedHashCode) { fileStream.Close(); string errorMessage = Utility.Text.Format("Latest version list compressed hash code error, need '{0}', downloaded '{1}'.", m_VersionListCompressedHashCode, hashCode); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } fileStream.Position = 0L; m_ResourceManager.PrepareCachedStream(); if (!Utility.Compression.Decompress(fileStream, m_ResourceManager.m_CachedStream)) { fileStream.Close(); string errorMessage = Utility.Text.Format("Unable to decompress latest version list '{0}'.", e.DownloadPath); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } int uncompressedLength = (int)m_ResourceManager.m_CachedStream.Length; if (uncompressedLength != m_VersionListLength) { fileStream.Close(); string errorMessage = Utility.Text.Format("Latest version list length error, need '{0}', downloaded '{1}'.", m_VersionListLength, uncompressedLength); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); return; } fileStream.Position = 0L; fileStream.SetLength(0L); fileStream.Write(m_ResourceManager.m_CachedStream.GetBuffer(), 0, uncompressedLength); } if (VersionListUpdateSuccess != null) { VersionListUpdateSuccess(e.DownloadPath, e.DownloadUri); } } catch (Exception exception) { string errorMessage = Utility.Text.Format("Update latest version list '{0}' with error message '{1}'.", e.DownloadPath, exception); DownloadFailureEventArgs downloadFailureEventArgs = DownloadFailureEventArgs.Create(e.SerialId, e.DownloadPath, e.DownloadUri, errorMessage, e.UserData); OnDownloadFailure(this, downloadFailureEventArgs); ReferencePool.Release(downloadFailureEventArgs); } } private void OnDownloadFailure(object sender, DownloadFailureEventArgs e) { VersionListProcessor versionListProcessor = e.UserData as VersionListProcessor; if (versionListProcessor == null || versionListProcessor != this) { return; } if (File.Exists(e.DownloadPath)) { File.Delete(e.DownloadPath); } if (VersionListUpdateFailure != null) { VersionListUpdateFailure(e.DownloadUri, e.ErrorMessage); } } } } } ================================================ FILE: GameFramework/Resource/ResourceManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Download; using GameFramework.FileSystem; using GameFramework.ObjectPool; using System; using System.Collections.Generic; using System.IO; namespace GameFramework.Resource { /// /// 资源管理器。 /// internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager { private const string RemoteVersionListFileName = "GameFrameworkVersion.dat"; private const string LocalVersionListFileName = "GameFrameworkList.dat"; private const string DefaultExtension = "dat"; private const string TempExtension = "tmp"; private const int FileSystemMaxFileCount = 1024 * 16; private const int FileSystemMaxBlockCount = 1024 * 256; private Dictionary m_AssetInfos; private Dictionary m_ResourceInfos; private SortedDictionary m_ReadWriteResourceInfos; private readonly Dictionary m_ReadOnlyFileSystems; private readonly Dictionary m_ReadWriteFileSystems; private readonly Dictionary m_ResourceGroups; private PackageVersionListSerializer m_PackageVersionListSerializer; private UpdatableVersionListSerializer m_UpdatableVersionListSerializer; private ReadOnlyVersionListSerializer m_ReadOnlyVersionListSerializer; private ReadWriteVersionListSerializer m_ReadWriteVersionListSerializer; private ResourcePackVersionListSerializer m_ResourcePackVersionListSerializer; private IFileSystemManager m_FileSystemManager; private ResourceIniter m_ResourceIniter; private VersionListProcessor m_VersionListProcessor; private ResourceVerifier m_ResourceVerifier; private ResourceChecker m_ResourceChecker; private ResourceUpdater m_ResourceUpdater; private ResourceLoader m_ResourceLoader; private IResourceHelper m_ResourceHelper; private string m_ReadOnlyPath; private string m_ReadWritePath; private ResourceMode m_ResourceMode; private bool m_RefuseSetFlag; private string m_CurrentVariant; private string m_UpdatePrefixUri; private string m_ApplicableGameVersion; private int m_InternalResourceVersion; private MemoryStream m_CachedStream; private DecryptResourceCallback m_DecryptResourceCallback; private InitResourcesCompleteCallback m_InitResourcesCompleteCallback; private UpdateVersionListCallbacks m_UpdateVersionListCallbacks; private VerifyResourcesCompleteCallback m_VerifyResourcesCompleteCallback; private CheckResourcesCompleteCallback m_CheckResourcesCompleteCallback; private ApplyResourcesCompleteCallback m_ApplyResourcesCompleteCallback; private UpdateResourcesCompleteCallback m_UpdateResourcesCompleteCallback; private EventHandler m_ResourceVerifyStartEventHandler; private EventHandler m_ResourceVerifySuccessEventHandler; private EventHandler m_ResourceVerifyFailureEventHandler; private EventHandler m_ResourceApplyStartEventHandler; private EventHandler m_ResourceApplySuccessEventHandler; private EventHandler m_ResourceApplyFailureEventHandler; private EventHandler m_ResourceUpdateStartEventHandler; private EventHandler m_ResourceUpdateChangedEventHandler; private EventHandler m_ResourceUpdateSuccessEventHandler; private EventHandler m_ResourceUpdateFailureEventHandler; private EventHandler m_ResourceUpdateAllCompleteEventHandler; /// /// 初始化资源管理器的新实例。 /// public ResourceManager() { m_AssetInfos = null; m_ResourceInfos = null; m_ReadWriteResourceInfos = null; m_ReadOnlyFileSystems = new Dictionary(StringComparer.Ordinal); m_ReadWriteFileSystems = new Dictionary(StringComparer.Ordinal); m_ResourceGroups = new Dictionary(StringComparer.Ordinal); m_PackageVersionListSerializer = null; m_UpdatableVersionListSerializer = null; m_ReadOnlyVersionListSerializer = null; m_ReadWriteVersionListSerializer = null; m_ResourcePackVersionListSerializer = null; m_ResourceIniter = null; m_VersionListProcessor = null; m_ResourceVerifier = null; m_ResourceChecker = null; m_ResourceUpdater = null; m_ResourceLoader = new ResourceLoader(this); m_ResourceHelper = null; m_ReadOnlyPath = null; m_ReadWritePath = null; m_ResourceMode = ResourceMode.Unspecified; m_RefuseSetFlag = false; m_CurrentVariant = null; m_UpdatePrefixUri = null; m_ApplicableGameVersion = null; m_InternalResourceVersion = 0; m_CachedStream = null; m_DecryptResourceCallback = null; m_InitResourcesCompleteCallback = null; m_UpdateVersionListCallbacks = null; m_VerifyResourcesCompleteCallback = null; m_CheckResourcesCompleteCallback = null; m_ApplyResourcesCompleteCallback = null; m_UpdateResourcesCompleteCallback = null; m_ResourceVerifySuccessEventHandler = null; m_ResourceVerifyFailureEventHandler = null; m_ResourceApplySuccessEventHandler = null; m_ResourceApplyFailureEventHandler = null; m_ResourceUpdateStartEventHandler = null; m_ResourceUpdateChangedEventHandler = null; m_ResourceUpdateSuccessEventHandler = null; m_ResourceUpdateFailureEventHandler = null; m_ResourceUpdateAllCompleteEventHandler = null; } /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal override int Priority { get { return 3; } } /// /// 获取资源只读区路径。 /// public string ReadOnlyPath { get { return m_ReadOnlyPath; } } /// /// 获取资源读写区路径。 /// public string ReadWritePath { get { return m_ReadWritePath; } } /// /// 获取资源模式。 /// public ResourceMode ResourceMode { get { return m_ResourceMode; } } /// /// 获取当前变体。 /// public string CurrentVariant { get { return m_CurrentVariant; } } /// /// 获取单机模式版本资源列表序列化器。 /// public PackageVersionListSerializer PackageVersionListSerializer { get { return m_PackageVersionListSerializer; } } /// /// 获取可更新模式版本资源列表序列化器。 /// public UpdatableVersionListSerializer UpdatableVersionListSerializer { get { return m_UpdatableVersionListSerializer; } } /// /// 获取本地只读区版本资源列表序列化器。 /// public ReadOnlyVersionListSerializer ReadOnlyVersionListSerializer { get { return m_ReadOnlyVersionListSerializer; } } /// /// 获取本地读写区版本资源列表序列化器。 /// public ReadWriteVersionListSerializer ReadWriteVersionListSerializer { get { return m_ReadWriteVersionListSerializer; } } /// /// 获取资源包版本资源列表序列化器。 /// public ResourcePackVersionListSerializer ResourcePackVersionListSerializer { get { return m_ResourcePackVersionListSerializer; } } /// /// 获取当前资源适用的游戏版本号。 /// public string ApplicableGameVersion { get { return m_ApplicableGameVersion; } } /// /// 获取当前内部资源版本号。 /// public int InternalResourceVersion { get { return m_InternalResourceVersion; } } /// /// 获取资源数量。 /// public int AssetCount { get { return m_AssetInfos != null ? m_AssetInfos.Count : 0; } } /// /// 获取资源数量。 /// public int ResourceCount { get { return m_ResourceInfos != null ? m_ResourceInfos.Count : 0; } } /// /// 获取资源组数量。 /// public int ResourceGroupCount { get { return m_ResourceGroups.Count; } } /// /// 获取或设置资源更新下载地址前缀。 /// public string UpdatePrefixUri { get { return m_UpdatePrefixUri; } set { m_UpdatePrefixUri = value; } } /// /// 获取或设置每更新多少字节的资源,重新生成一次版本资源列表。 /// public int GenerateReadWriteVersionListLength { get { return m_ResourceUpdater != null ? m_ResourceUpdater.GenerateReadWriteVersionListLength : 0; } set { if (m_ResourceUpdater == null) { throw new GameFrameworkException("You can not use GenerateReadWriteVersionListLength at this time."); } m_ResourceUpdater.GenerateReadWriteVersionListLength = value; } } /// /// 获取正在应用的资源包路径。 /// public string ApplyingResourcePackPath { get { return m_ResourceUpdater != null ? m_ResourceUpdater.ApplyingResourcePackPath : null; } } /// /// 获取等待应用资源数量。 /// public int ApplyWaitingCount { get { return m_ResourceUpdater != null ? m_ResourceUpdater.ApplyWaitingCount : 0; } } /// /// 获取或设置资源更新重试次数。 /// public int UpdateRetryCount { get { return m_ResourceUpdater != null ? m_ResourceUpdater.UpdateRetryCount : 0; } set { if (m_ResourceUpdater == null) { throw new GameFrameworkException("You can not use UpdateRetryCount at this time."); } m_ResourceUpdater.UpdateRetryCount = value; } } /// /// 获取正在更新的资源组。 /// public IResourceGroup UpdatingResourceGroup { get { return m_ResourceUpdater != null ? m_ResourceUpdater.UpdatingResourceGroup : null; } } /// /// 获取等待更新资源数量。 /// public int UpdateWaitingCount { get { return m_ResourceUpdater != null ? m_ResourceUpdater.UpdateWaitingCount : 0; } } /// /// 获取使用时下载的等待更新资源数量。 /// public int UpdateWaitingWhilePlayingCount { get { return m_ResourceUpdater != null ? m_ResourceUpdater.UpdateWaitingWhilePlayingCount : 0; } } /// /// 获取候选更新资源数量。 /// public int UpdateCandidateCount { get { return m_ResourceUpdater != null ? m_ResourceUpdater.UpdateCandidateCount : 0; } } /// /// 获取加载资源代理总数量。 /// public int LoadTotalAgentCount { get { return m_ResourceLoader.TotalAgentCount; } } /// /// 获取可用加载资源代理数量。 /// public int LoadFreeAgentCount { get { return m_ResourceLoader.FreeAgentCount; } } /// /// 获取工作中加载资源代理数量。 /// public int LoadWorkingAgentCount { get { return m_ResourceLoader.WorkingAgentCount; } } /// /// 获取等待加载资源任务数量。 /// public int LoadWaitingTaskCount { get { return m_ResourceLoader.WaitingTaskCount; } } /// /// 获取或设置资源对象池自动释放可释放对象的间隔秒数。 /// public float AssetAutoReleaseInterval { get { return m_ResourceLoader.AssetAutoReleaseInterval; } set { m_ResourceLoader.AssetAutoReleaseInterval = value; } } /// /// 获取或设置资源对象池的容量。 /// public int AssetCapacity { get { return m_ResourceLoader.AssetCapacity; } set { m_ResourceLoader.AssetCapacity = value; } } /// /// 获取或设置资源对象池对象过期秒数。 /// public float AssetExpireTime { get { return m_ResourceLoader.AssetExpireTime; } set { m_ResourceLoader.AssetExpireTime = value; } } /// /// 获取或设置资源对象池的优先级。 /// public int AssetPriority { get { return m_ResourceLoader.AssetPriority; } set { m_ResourceLoader.AssetPriority = value; } } /// /// 获取或设置资源对象池自动释放可释放对象的间隔秒数。 /// public float ResourceAutoReleaseInterval { get { return m_ResourceLoader.ResourceAutoReleaseInterval; } set { m_ResourceLoader.ResourceAutoReleaseInterval = value; } } /// /// 获取或设置资源对象池的容量。 /// public int ResourceCapacity { get { return m_ResourceLoader.ResourceCapacity; } set { m_ResourceLoader.ResourceCapacity = value; } } /// /// 获取或设置资源对象池对象过期秒数。 /// public float ResourceExpireTime { get { return m_ResourceLoader.ResourceExpireTime; } set { m_ResourceLoader.ResourceExpireTime = value; } } /// /// 获取或设置资源对象池的优先级。 /// public int ResourcePriority { get { return m_ResourceLoader.ResourcePriority; } set { m_ResourceLoader.ResourcePriority = value; } } /// /// 资源校验开始事件。 /// public event EventHandler ResourceVerifyStart { add { m_ResourceVerifyStartEventHandler += value; } remove { m_ResourceVerifyStartEventHandler -= value; } } /// /// 资源校验成功事件。 /// public event EventHandler ResourceVerifySuccess { add { m_ResourceVerifySuccessEventHandler += value; } remove { m_ResourceVerifySuccessEventHandler -= value; } } /// /// 资源校验失败事件。 /// public event EventHandler ResourceVerifyFailure { add { m_ResourceVerifyFailureEventHandler += value; } remove { m_ResourceVerifyFailureEventHandler -= value; } } /// /// 资源应用开始事件。 /// public event EventHandler ResourceApplyStart { add { m_ResourceApplyStartEventHandler += value; } remove { m_ResourceApplyStartEventHandler -= value; } } /// /// 资源应用成功事件。 /// public event EventHandler ResourceApplySuccess { add { m_ResourceApplySuccessEventHandler += value; } remove { m_ResourceApplySuccessEventHandler -= value; } } /// /// 资源应用失败事件。 /// public event EventHandler ResourceApplyFailure { add { m_ResourceApplyFailureEventHandler += value; } remove { m_ResourceApplyFailureEventHandler -= value; } } /// /// 资源更新开始事件。 /// public event EventHandler ResourceUpdateStart { add { m_ResourceUpdateStartEventHandler += value; } remove { m_ResourceUpdateStartEventHandler -= value; } } /// /// 资源更新改变事件。 /// public event EventHandler ResourceUpdateChanged { add { m_ResourceUpdateChangedEventHandler += value; } remove { m_ResourceUpdateChangedEventHandler -= value; } } /// /// 资源更新成功事件。 /// public event EventHandler ResourceUpdateSuccess { add { m_ResourceUpdateSuccessEventHandler += value; } remove { m_ResourceUpdateSuccessEventHandler -= value; } } /// /// 资源更新失败事件。 /// public event EventHandler ResourceUpdateFailure { add { m_ResourceUpdateFailureEventHandler += value; } remove { m_ResourceUpdateFailureEventHandler -= value; } } /// /// 资源更新全部完成事件。 /// public event EventHandler ResourceUpdateAllComplete { add { m_ResourceUpdateAllCompleteEventHandler += value; } remove { m_ResourceUpdateAllCompleteEventHandler -= value; } } /// /// 资源管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { if (m_ResourceVerifier != null) { m_ResourceVerifier.Update(elapseSeconds, realElapseSeconds); return; } if (m_ResourceUpdater != null) { m_ResourceUpdater.Update(elapseSeconds, realElapseSeconds); } m_ResourceLoader.Update(elapseSeconds, realElapseSeconds); } /// /// 关闭并清理资源管理器。 /// internal override void Shutdown() { if (m_ResourceIniter != null) { m_ResourceIniter.Shutdown(); m_ResourceIniter = null; } if (m_VersionListProcessor != null) { m_VersionListProcessor.VersionListUpdateSuccess -= OnVersionListProcessorUpdateSuccess; m_VersionListProcessor.VersionListUpdateFailure -= OnVersionListProcessorUpdateFailure; m_VersionListProcessor.Shutdown(); m_VersionListProcessor = null; } if (m_ResourceVerifier != null) { m_ResourceVerifier.ResourceVerifyStart -= OnVerifierResourceVerifyStart; m_ResourceVerifier.ResourceVerifySuccess -= OnVerifierResourceVerifySuccess; m_ResourceVerifier.ResourceVerifyFailure -= OnVerifierResourceVerifyFailure; m_ResourceVerifier.ResourceVerifyComplete -= OnVerifierResourceVerifyComplete; m_ResourceVerifier.Shutdown(); m_ResourceVerifier = null; } if (m_ResourceChecker != null) { m_ResourceChecker.ResourceNeedUpdate -= OnCheckerResourceNeedUpdate; m_ResourceChecker.ResourceCheckComplete -= OnCheckerResourceCheckComplete; m_ResourceChecker.Shutdown(); m_ResourceChecker = null; } if (m_ResourceUpdater != null) { m_ResourceUpdater.ResourceApplyStart -= OnUpdaterResourceApplyStart; m_ResourceUpdater.ResourceApplySuccess -= OnUpdaterResourceApplySuccess; m_ResourceUpdater.ResourceApplyFailure -= OnUpdaterResourceApplyFailure; m_ResourceUpdater.ResourceApplyComplete -= OnUpdaterResourceApplyComplete; m_ResourceUpdater.ResourceUpdateStart -= OnUpdaterResourceUpdateStart; m_ResourceUpdater.ResourceUpdateChanged -= OnUpdaterResourceUpdateChanged; m_ResourceUpdater.ResourceUpdateSuccess -= OnUpdaterResourceUpdateSuccess; m_ResourceUpdater.ResourceUpdateFailure -= OnUpdaterResourceUpdateFailure; m_ResourceUpdater.ResourceUpdateComplete -= OnUpdaterResourceUpdateComplete; m_ResourceUpdater.ResourceUpdateAllComplete -= OnUpdaterResourceUpdateAllComplete; m_ResourceUpdater.Shutdown(); m_ResourceUpdater = null; if (m_ReadWriteResourceInfos != null) { m_ReadWriteResourceInfos.Clear(); m_ReadWriteResourceInfos = null; } FreeCachedStream(); } if (m_ResourceLoader != null) { m_ResourceLoader.Shutdown(); m_ResourceLoader = null; } if (m_AssetInfos != null) { m_AssetInfos.Clear(); m_AssetInfos = null; } if (m_ResourceInfos != null) { m_ResourceInfos.Clear(); m_ResourceInfos = null; } m_ReadOnlyFileSystems.Clear(); m_ReadWriteFileSystems.Clear(); m_ResourceGroups.Clear(); } /// /// 设置资源只读区路径。 /// /// 资源只读区路径。 public void SetReadOnlyPath(string readOnlyPath) { if (string.IsNullOrEmpty(readOnlyPath)) { throw new GameFrameworkException("Read-only path is invalid."); } if (m_RefuseSetFlag) { throw new GameFrameworkException("You can not set read-only path at this time."); } if (m_ResourceLoader.TotalAgentCount > 0) { throw new GameFrameworkException("You must set read-only path before add load resource agent helper."); } m_ReadOnlyPath = readOnlyPath; } /// /// 设置资源读写区路径。 /// /// 资源读写区路径。 public void SetReadWritePath(string readWritePath) { if (string.IsNullOrEmpty(readWritePath)) { throw new GameFrameworkException("Read-write path is invalid."); } if (m_RefuseSetFlag) { throw new GameFrameworkException("You can not set read-write path at this time."); } if (m_ResourceLoader.TotalAgentCount > 0) { throw new GameFrameworkException("You must set read-write path before add load resource agent helper."); } m_ReadWritePath = readWritePath; } /// /// 设置资源模式。 /// /// 资源模式。 public void SetResourceMode(ResourceMode resourceMode) { if (resourceMode == ResourceMode.Unspecified) { throw new GameFrameworkException("Resource mode is invalid."); } if (m_RefuseSetFlag) { throw new GameFrameworkException("You can not set resource mode at this time."); } if (m_ResourceMode == ResourceMode.Unspecified) { m_ResourceMode = resourceMode; if (m_ResourceMode == ResourceMode.Package) { m_PackageVersionListSerializer = new PackageVersionListSerializer(); m_ResourceIniter = new ResourceIniter(this); m_ResourceIniter.ResourceInitComplete += OnIniterResourceInitComplete; } else if (m_ResourceMode == ResourceMode.Updatable || m_ResourceMode == ResourceMode.UpdatableWhilePlaying) { m_UpdatableVersionListSerializer = new UpdatableVersionListSerializer(); m_ReadOnlyVersionListSerializer = new ReadOnlyVersionListSerializer(); m_ReadWriteVersionListSerializer = new ReadWriteVersionListSerializer(); m_ResourcePackVersionListSerializer = new ResourcePackVersionListSerializer(); m_VersionListProcessor = new VersionListProcessor(this); m_VersionListProcessor.VersionListUpdateSuccess += OnVersionListProcessorUpdateSuccess; m_VersionListProcessor.VersionListUpdateFailure += OnVersionListProcessorUpdateFailure; m_ResourceChecker = new ResourceChecker(this); m_ResourceChecker.ResourceNeedUpdate += OnCheckerResourceNeedUpdate; m_ResourceChecker.ResourceCheckComplete += OnCheckerResourceCheckComplete; m_ResourceUpdater = new ResourceUpdater(this); m_ResourceUpdater.ResourceApplyStart += OnUpdaterResourceApplyStart; m_ResourceUpdater.ResourceApplySuccess += OnUpdaterResourceApplySuccess; m_ResourceUpdater.ResourceApplyFailure += OnUpdaterResourceApplyFailure; m_ResourceUpdater.ResourceApplyComplete += OnUpdaterResourceApplyComplete; m_ResourceUpdater.ResourceUpdateStart += OnUpdaterResourceUpdateStart; m_ResourceUpdater.ResourceUpdateChanged += OnUpdaterResourceUpdateChanged; m_ResourceUpdater.ResourceUpdateSuccess += OnUpdaterResourceUpdateSuccess; m_ResourceUpdater.ResourceUpdateFailure += OnUpdaterResourceUpdateFailure; m_ResourceUpdater.ResourceUpdateComplete += OnUpdaterResourceUpdateComplete; m_ResourceUpdater.ResourceUpdateAllComplete += OnUpdaterResourceUpdateAllComplete; } } else if (m_ResourceMode != resourceMode) { throw new GameFrameworkException("You can not change resource mode at this time."); } } /// /// 设置当前变体。 /// /// 当前变体。 public void SetCurrentVariant(string currentVariant) { if (m_RefuseSetFlag) { throw new GameFrameworkException("You can not set current variant at this time."); } m_CurrentVariant = currentVariant; } /// /// 设置对象池管理器。 /// /// 对象池管理器。 public void SetObjectPoolManager(IObjectPoolManager objectPoolManager) { if (objectPoolManager == null) { throw new GameFrameworkException("Object pool manager is invalid."); } m_ResourceLoader.SetObjectPoolManager(objectPoolManager); } /// /// 设置文件系统管理器。 /// /// 文件系统管理器。 public void SetFileSystemManager(IFileSystemManager fileSystemManager) { if (fileSystemManager == null) { throw new GameFrameworkException("File system manager is invalid."); } m_FileSystemManager = fileSystemManager; } /// /// 设置下载管理器。 /// /// 下载管理器。 public void SetDownloadManager(IDownloadManager downloadManager) { if (downloadManager == null) { throw new GameFrameworkException("Download manager is invalid."); } if (m_VersionListProcessor != null) { m_VersionListProcessor.SetDownloadManager(downloadManager); } if (m_ResourceUpdater != null) { m_ResourceUpdater.SetDownloadManager(downloadManager); } } /// /// 设置解密资源回调函数。 /// /// 要设置的解密资源回调函数。 /// 如果不设置,将使用默认的解密资源回调函数。 public void SetDecryptResourceCallback(DecryptResourceCallback decryptResourceCallback) { if (m_ResourceLoader.TotalAgentCount > 0) { throw new GameFrameworkException("You must set decrypt resource callback before add load resource agent helper."); } m_DecryptResourceCallback = decryptResourceCallback; } /// /// 设置资源辅助器。 /// /// 资源辅助器。 public void SetResourceHelper(IResourceHelper resourceHelper) { if (resourceHelper == null) { throw new GameFrameworkException("Resource helper is invalid."); } if (m_ResourceLoader.TotalAgentCount > 0) { throw new GameFrameworkException("You must set resource helper before add load resource agent helper."); } m_ResourceHelper = resourceHelper; } /// /// 增加加载资源代理辅助器。 /// /// 要增加的加载资源代理辅助器。 public void AddLoadResourceAgentHelper(ILoadResourceAgentHelper loadResourceAgentHelper) { if (m_ResourceHelper == null) { throw new GameFrameworkException("Resource helper is invalid."); } if (string.IsNullOrEmpty(m_ReadOnlyPath)) { throw new GameFrameworkException("Read-only path is invalid."); } if (string.IsNullOrEmpty(m_ReadWritePath)) { throw new GameFrameworkException("Read-write path is invalid."); } m_ResourceLoader.AddLoadResourceAgentHelper(loadResourceAgentHelper, m_ResourceHelper, m_ReadOnlyPath, m_ReadWritePath, m_DecryptResourceCallback); } /// /// 使用单机模式并初始化资源。 /// /// 使用单机模式并初始化资源完成时的回调函数。 public void InitResources(InitResourcesCompleteCallback initResourcesCompleteCallback) { if (initResourcesCompleteCallback == null) { throw new GameFrameworkException("Init resources complete callback is invalid."); } if (m_ResourceMode == ResourceMode.Unspecified) { throw new GameFrameworkException("You must set resource mode first."); } if (m_ResourceMode != ResourceMode.Package) { throw new GameFrameworkException("You can not use InitResources without package resource mode."); } if (m_ResourceIniter == null) { throw new GameFrameworkException("You can not use InitResources at this time."); } m_RefuseSetFlag = true; m_InitResourcesCompleteCallback = initResourcesCompleteCallback; m_ResourceIniter.InitResources(m_CurrentVariant); } /// /// 使用可更新模式并检查版本资源列表。 /// /// 最新的内部资源版本号。 /// 检查版本资源列表结果。 public CheckVersionListResult CheckVersionList(int latestInternalResourceVersion) { if (m_ResourceMode == ResourceMode.Unspecified) { throw new GameFrameworkException("You must set resource mode first."); } if (m_ResourceMode != ResourceMode.Updatable && m_ResourceMode != ResourceMode.UpdatableWhilePlaying) { throw new GameFrameworkException("You can not use CheckVersionList without updatable resource mode."); } if (m_VersionListProcessor == null) { throw new GameFrameworkException("You can not use CheckVersionList at this time."); } return m_VersionListProcessor.CheckVersionList(latestInternalResourceVersion); } /// /// 使用可更新模式并更新版本资源列表。 /// /// 版本资源列表大小。 /// 版本资源列表哈希值。 /// 版本资源列表压缩后大小。 /// 版本资源列表压缩后哈希值。 /// 版本资源列表更新回调函数集。 public void UpdateVersionList(int versionListLength, int versionListHashCode, int versionListCompressedLength, int versionListCompressedHashCode, UpdateVersionListCallbacks updateVersionListCallbacks) { if (updateVersionListCallbacks == null) { throw new GameFrameworkException("Update version list callbacks is invalid."); } if (m_ResourceMode == ResourceMode.Unspecified) { throw new GameFrameworkException("You must set resource mode first."); } if (m_ResourceMode != ResourceMode.Updatable && m_ResourceMode != ResourceMode.UpdatableWhilePlaying) { throw new GameFrameworkException("You can not use UpdateVersionList without updatable resource mode."); } if (m_VersionListProcessor == null) { throw new GameFrameworkException("You can not use UpdateVersionList at this time."); } m_UpdateVersionListCallbacks = updateVersionListCallbacks; m_VersionListProcessor.UpdateVersionList(versionListLength, versionListHashCode, versionListCompressedLength, versionListCompressedHashCode); } /// /// 使用可更新模式并校验资源。 /// /// 每帧至少校验资源的大小,以字节为单位。 /// 使用可更新模式并校验资源完成时的回调函数。 public void VerifyResources(int verifyResourceLengthPerFrame, VerifyResourcesCompleteCallback verifyResourcesCompleteCallback) { if (verifyResourcesCompleteCallback == null) { throw new GameFrameworkException("Verify resources complete callback is invalid."); } if (m_ResourceMode == ResourceMode.Unspecified) { throw new GameFrameworkException("You must set resource mode first."); } if (m_ResourceMode != ResourceMode.Updatable && m_ResourceMode != ResourceMode.UpdatableWhilePlaying) { throw new GameFrameworkException("You can not use VerifyResources without updatable resource mode."); } if (m_RefuseSetFlag) { throw new GameFrameworkException("You can not verify resources at this time."); } m_ResourceVerifier = new ResourceVerifier(this); m_ResourceVerifier.ResourceVerifyStart += OnVerifierResourceVerifyStart; m_ResourceVerifier.ResourceVerifySuccess += OnVerifierResourceVerifySuccess; m_ResourceVerifier.ResourceVerifyFailure += OnVerifierResourceVerifyFailure; m_ResourceVerifier.ResourceVerifyComplete += OnVerifierResourceVerifyComplete; m_VerifyResourcesCompleteCallback = verifyResourcesCompleteCallback; m_ResourceVerifier.VerifyResources(verifyResourceLengthPerFrame); } /// /// 使用可更新模式并检查资源。 /// /// 是否忽略处理其它变体的资源,若不忽略,将会移除其它变体的资源。 /// 使用可更新模式并检查资源完成时的回调函数。 public void CheckResources(bool ignoreOtherVariant, CheckResourcesCompleteCallback checkResourcesCompleteCallback) { if (checkResourcesCompleteCallback == null) { throw new GameFrameworkException("Check resources complete callback is invalid."); } if (m_ResourceMode == ResourceMode.Unspecified) { throw new GameFrameworkException("You must set resource mode first."); } if (m_ResourceMode != ResourceMode.Updatable && m_ResourceMode != ResourceMode.UpdatableWhilePlaying) { throw new GameFrameworkException("You can not use CheckResources without updatable resource mode."); } if (m_ResourceChecker == null) { throw new GameFrameworkException("You can not use CheckResources at this time."); } m_RefuseSetFlag = true; m_CheckResourcesCompleteCallback = checkResourcesCompleteCallback; m_ResourceChecker.CheckResources(m_CurrentVariant, ignoreOtherVariant); } /// /// 使用可更新模式并应用资源包资源。 /// /// 要应用的资源包路径。 /// 使用可更新模式并应用资源包资源完成时的回调函数。 public void ApplyResources(string resourcePackPath, ApplyResourcesCompleteCallback applyResourcesCompleteCallback) { if (string.IsNullOrEmpty(resourcePackPath)) { throw new GameFrameworkException("Resource pack path is invalid."); } if (!File.Exists(resourcePackPath)) { throw new GameFrameworkException(Utility.Text.Format("Resource pack '{0}' is not exist.", resourcePackPath)); } if (applyResourcesCompleteCallback == null) { throw new GameFrameworkException("Apply resources complete callback is invalid."); } if (m_ResourceMode == ResourceMode.Unspecified) { throw new GameFrameworkException("You must set resource mode first."); } if (m_ResourceMode != ResourceMode.Updatable && m_ResourceMode != ResourceMode.UpdatableWhilePlaying) { throw new GameFrameworkException("You can not use ApplyResources without updatable resource mode."); } if (m_ResourceUpdater == null) { throw new GameFrameworkException("You can not use ApplyResources at this time."); } m_ApplyResourcesCompleteCallback = applyResourcesCompleteCallback; m_ResourceUpdater.ApplyResources(resourcePackPath); } /// /// 使用可更新模式并更新所有资源。 /// /// 使用可更新模式并更新默认资源组完成时的回调函数。 public void UpdateResources(UpdateResourcesCompleteCallback updateResourcesCompleteCallback) { UpdateResources(string.Empty, updateResourcesCompleteCallback); } /// /// 使用可更新模式并更新指定资源组的资源。 /// /// 要更新的资源组名称。 /// 使用可更新模式并更新指定资源组完成时的回调函数。 public void UpdateResources(string resourceGroupName, UpdateResourcesCompleteCallback updateResourcesCompleteCallback) { if (updateResourcesCompleteCallback == null) { throw new GameFrameworkException("Update resources complete callback is invalid."); } if (m_ResourceMode == ResourceMode.Unspecified) { throw new GameFrameworkException("You must set resource mode first."); } if (m_ResourceMode != ResourceMode.Updatable && m_ResourceMode != ResourceMode.UpdatableWhilePlaying) { throw new GameFrameworkException("You can not use UpdateResources without updatable resource mode."); } if (m_ResourceUpdater == null) { throw new GameFrameworkException("You can not use UpdateResources at this time."); } ResourceGroup resourceGroup = (ResourceGroup)GetResourceGroup(resourceGroupName); if (resourceGroup == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find resource group '{0}'.", resourceGroupName)); } m_UpdateResourcesCompleteCallback = updateResourcesCompleteCallback; m_ResourceUpdater.UpdateResources(resourceGroup); } /// /// 停止更新资源。 /// public void StopUpdateResources() { if (m_ResourceMode == ResourceMode.Unspecified) { throw new GameFrameworkException("You must set resource mode first."); } if (m_ResourceMode != ResourceMode.Updatable && m_ResourceMode != ResourceMode.UpdatableWhilePlaying) { throw new GameFrameworkException("You can not use StopUpdateResources without updatable resource mode."); } if (m_ResourceUpdater == null) { throw new GameFrameworkException("You can not use StopUpdateResources at this time."); } m_ResourceUpdater.StopUpdateResources(); m_UpdateResourcesCompleteCallback = null; } /// /// 校验资源包。 /// /// 要校验的资源包路径。 /// 是否校验资源包成功。 public bool VerifyResourcePack(string resourcePackPath) { if (string.IsNullOrEmpty(resourcePackPath)) { throw new GameFrameworkException("Resource pack path is invalid."); } if (!File.Exists(resourcePackPath)) { throw new GameFrameworkException(Utility.Text.Format("Resource pack '{0}' is not exist.", resourcePackPath)); } if (m_ResourceMode == ResourceMode.Unspecified) { throw new GameFrameworkException("You must set resource mode first."); } if (m_ResourceMode != ResourceMode.Updatable && m_ResourceMode != ResourceMode.UpdatableWhilePlaying) { throw new GameFrameworkException("You can not use VerifyResourcePack without updatable resource mode."); } if (m_ResourcePackVersionListSerializer == null) { throw new GameFrameworkException("You can not use VerifyResourcePack at this time."); } try { long length = 0L; ResourcePackVersionList versionList = default(ResourcePackVersionList); using (FileStream fileStream = new FileStream(resourcePackPath, FileMode.Open, FileAccess.Read)) { length = fileStream.Length; versionList = m_ResourcePackVersionListSerializer.Deserialize(fileStream); } if (!versionList.IsValid) { return false; } if (versionList.Offset + versionList.Length != length) { return false; } int hashCode = 0; using (FileStream fileStream = new FileStream(resourcePackPath, FileMode.Open, FileAccess.Read)) { fileStream.Position = versionList.Offset; hashCode = Utility.Verifier.GetCrc32(fileStream); } if (versionList.HashCode != hashCode) { return false; } return true; } catch { return false; } } /// /// 获取所有加载资源任务的信息。 /// /// 所有加载资源任务的信息。 public TaskInfo[] GetAllLoadAssetInfos() { return m_ResourceLoader.GetAllLoadAssetInfos(); } /// /// 获取所有加载资源任务的信息。 /// /// 所有加载资源任务的信息。 public void GetAllLoadAssetInfos(List results) { m_ResourceLoader.GetAllLoadAssetInfos(results); } /// /// 检查资源是否存在。 /// /// 要检查资源的名称。 /// 检查资源是否存在的结果。 public HasAssetResult HasAsset(string assetName) { if (string.IsNullOrEmpty(assetName)) { throw new GameFrameworkException("Asset name is invalid."); } return m_ResourceLoader.HasAsset(assetName); } /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 加载资源回调函数集。 public void LoadAsset(string assetName, LoadAssetCallbacks loadAssetCallbacks) { if (string.IsNullOrEmpty(assetName)) { throw new GameFrameworkException("Asset name is invalid."); } if (loadAssetCallbacks == null) { throw new GameFrameworkException("Load asset callbacks is invalid."); } m_ResourceLoader.LoadAsset(assetName, null, Constant.DefaultPriority, loadAssetCallbacks, null); } /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 要加载资源的类型。 /// 加载资源回调函数集。 public void LoadAsset(string assetName, Type assetType, LoadAssetCallbacks loadAssetCallbacks) { if (string.IsNullOrEmpty(assetName)) { throw new GameFrameworkException("Asset name is invalid."); } if (loadAssetCallbacks == null) { throw new GameFrameworkException("Load asset callbacks is invalid."); } m_ResourceLoader.LoadAsset(assetName, assetType, Constant.DefaultPriority, loadAssetCallbacks, null); } /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 加载资源的优先级。 /// 加载资源回调函数集。 public void LoadAsset(string assetName, int priority, LoadAssetCallbacks loadAssetCallbacks) { if (string.IsNullOrEmpty(assetName)) { throw new GameFrameworkException("Asset name is invalid."); } if (loadAssetCallbacks == null) { throw new GameFrameworkException("Load asset callbacks is invalid."); } m_ResourceLoader.LoadAsset(assetName, null, priority, loadAssetCallbacks, null); } /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 加载资源回调函数集。 /// 用户自定义数据。 public void LoadAsset(string assetName, LoadAssetCallbacks loadAssetCallbacks, object userData) { if (string.IsNullOrEmpty(assetName)) { throw new GameFrameworkException("Asset name is invalid."); } if (loadAssetCallbacks == null) { throw new GameFrameworkException("Load asset callbacks is invalid."); } m_ResourceLoader.LoadAsset(assetName, null, Constant.DefaultPriority, loadAssetCallbacks, userData); } /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 要加载资源的类型。 /// 加载资源的优先级。 /// 加载资源回调函数集。 public void LoadAsset(string assetName, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks) { if (string.IsNullOrEmpty(assetName)) { throw new GameFrameworkException("Asset name is invalid."); } if (loadAssetCallbacks == null) { throw new GameFrameworkException("Load asset callbacks is invalid."); } m_ResourceLoader.LoadAsset(assetName, assetType, priority, loadAssetCallbacks, null); } /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 要加载资源的类型。 /// 加载资源回调函数集。 /// 用户自定义数据。 public void LoadAsset(string assetName, Type assetType, LoadAssetCallbacks loadAssetCallbacks, object userData) { if (string.IsNullOrEmpty(assetName)) { throw new GameFrameworkException("Asset name is invalid."); } if (loadAssetCallbacks == null) { throw new GameFrameworkException("Load asset callbacks is invalid."); } m_ResourceLoader.LoadAsset(assetName, assetType, Constant.DefaultPriority, loadAssetCallbacks, userData); } /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 加载资源的优先级。 /// 加载资源回调函数集。 /// 用户自定义数据。 public void LoadAsset(string assetName, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData) { if (string.IsNullOrEmpty(assetName)) { throw new GameFrameworkException("Asset name is invalid."); } if (loadAssetCallbacks == null) { throw new GameFrameworkException("Load asset callbacks is invalid."); } m_ResourceLoader.LoadAsset(assetName, null, priority, loadAssetCallbacks, userData); } /// /// 异步加载资源。 /// /// 要加载资源的名称。 /// 要加载资源的类型。 /// 加载资源的优先级。 /// 加载资源回调函数集。 /// 用户自定义数据。 public void LoadAsset(string assetName, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData) { if (string.IsNullOrEmpty(assetName)) { throw new GameFrameworkException("Asset name is invalid."); } if (loadAssetCallbacks == null) { throw new GameFrameworkException("Load asset callbacks is invalid."); } m_ResourceLoader.LoadAsset(assetName, assetType, priority, loadAssetCallbacks, userData); } /// /// 卸载资源。 /// /// 要卸载的资源。 public void UnloadAsset(object asset) { if (asset == null) { throw new GameFrameworkException("Asset is invalid."); } if (m_ResourceLoader == null) { return; } m_ResourceLoader.UnloadAsset(asset); } /// /// 异步加载场景。 /// /// 要加载场景资源的名称。 /// 加载场景回调函数集。 public void LoadScene(string sceneAssetName, LoadSceneCallbacks loadSceneCallbacks) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } if (loadSceneCallbacks == null) { throw new GameFrameworkException("Load scene callbacks is invalid."); } m_ResourceLoader.LoadScene(sceneAssetName, Constant.DefaultPriority, loadSceneCallbacks, null); } /// /// 异步加载场景。 /// /// 要加载场景资源的名称。 /// 加载场景资源的优先级。 /// 加载场景回调函数集。 public void LoadScene(string sceneAssetName, int priority, LoadSceneCallbacks loadSceneCallbacks) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } if (loadSceneCallbacks == null) { throw new GameFrameworkException("Load scene callbacks is invalid."); } m_ResourceLoader.LoadScene(sceneAssetName, priority, loadSceneCallbacks, null); } /// /// 异步加载场景。 /// /// 要加载场景资源的名称。 /// 加载场景回调函数集。 /// 用户自定义数据。 public void LoadScene(string sceneAssetName, LoadSceneCallbacks loadSceneCallbacks, object userData) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } if (loadSceneCallbacks == null) { throw new GameFrameworkException("Load scene callbacks is invalid."); } m_ResourceLoader.LoadScene(sceneAssetName, Constant.DefaultPriority, loadSceneCallbacks, userData); } /// /// 异步加载场景。 /// /// 要加载场景资源的名称。 /// 加载场景资源的优先级。 /// 加载场景回调函数集。 /// 用户自定义数据。 public void LoadScene(string sceneAssetName, int priority, LoadSceneCallbacks loadSceneCallbacks, object userData) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } if (loadSceneCallbacks == null) { throw new GameFrameworkException("Load scene callbacks is invalid."); } m_ResourceLoader.LoadScene(sceneAssetName, priority, loadSceneCallbacks, userData); } /// /// 异步卸载场景。 /// /// 要卸载场景资源的名称。 /// 卸载场景回调函数集。 public void UnloadScene(string sceneAssetName, UnloadSceneCallbacks unloadSceneCallbacks) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } if (unloadSceneCallbacks == null) { throw new GameFrameworkException("Unload scene callbacks is invalid."); } m_ResourceLoader.UnloadScene(sceneAssetName, unloadSceneCallbacks, null); } /// /// 异步卸载场景。 /// /// 要卸载场景资源的名称。 /// 卸载场景回调函数集。 /// 用户自定义数据。 public void UnloadScene(string sceneAssetName, UnloadSceneCallbacks unloadSceneCallbacks, object userData) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } if (unloadSceneCallbacks == null) { throw new GameFrameworkException("Unload scene callbacks is invalid."); } m_ResourceLoader.UnloadScene(sceneAssetName, unloadSceneCallbacks, userData); } /// /// 获取二进制资源的实际路径。 /// /// 要获取实际路径的二进制资源的名称。 /// 二进制资源的实际路径。 /// 此方法仅适用于二进制资源存储在磁盘(而非文件系统)中的情况。若二进制资源存储在文件系统中时,返回值将始终为空。 public string GetBinaryPath(string binaryAssetName) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } return m_ResourceLoader.GetBinaryPath(binaryAssetName); } /// /// 获取二进制资源的实际路径。 /// /// 要获取实际路径的二进制资源的名称。 /// 二进制资源是否存储在只读区中。 /// 二进制资源是否存储在文件系统中。 /// 二进制资源或存储二进制资源的文件系统,相对于只读区或者读写区的相对路径。 /// 若二进制资源存储在文件系统中,则指示二进制资源在文件系统中的名称,否则此参数返回空。 /// 是否获取二进制资源的实际路径成功。 public bool GetBinaryPath(string binaryAssetName, out bool storageInReadOnly, out bool storageInFileSystem, out string relativePath, out string fileName) { return m_ResourceLoader.GetBinaryPath(binaryAssetName, out storageInReadOnly, out storageInFileSystem, out relativePath, out fileName); } /// /// 获取二进制资源的长度。 /// /// 要获取长度的二进制资源的名称。 /// 二进制资源的长度。 public int GetBinaryLength(string binaryAssetName) { return m_ResourceLoader.GetBinaryLength(binaryAssetName); } /// /// 异步加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 加载二进制资源回调函数集。 public void LoadBinary(string binaryAssetName, LoadBinaryCallbacks loadBinaryCallbacks) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (loadBinaryCallbacks == null) { throw new GameFrameworkException("Load binary callbacks is invalid."); } m_ResourceLoader.LoadBinary(binaryAssetName, loadBinaryCallbacks, null); } /// /// 异步加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 加载二进制资源回调函数集。 /// 用户自定义数据。 public void LoadBinary(string binaryAssetName, LoadBinaryCallbacks loadBinaryCallbacks, object userData) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (loadBinaryCallbacks == null) { throw new GameFrameworkException("Load binary callbacks is invalid."); } m_ResourceLoader.LoadBinary(binaryAssetName, loadBinaryCallbacks, userData); } /// /// 从文件系统中加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 存储加载二进制资源的二进制流。 public byte[] LoadBinaryFromFileSystem(string binaryAssetName) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } return m_ResourceLoader.LoadBinaryFromFileSystem(binaryAssetName); } /// /// 从文件系统中加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 存储加载二进制资源的二进制流。 /// 实际加载了多少字节。 public int LoadBinaryFromFileSystem(string binaryAssetName, byte[] buffer) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return m_ResourceLoader.LoadBinaryFromFileSystem(binaryAssetName, buffer, 0, buffer.Length); } /// /// 从文件系统中加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 存储加载二进制资源的二进制流。 /// 存储加载二进制资源的二进制流的起始位置。 /// 实际加载了多少字节。 public int LoadBinaryFromFileSystem(string binaryAssetName, byte[] buffer, int startIndex) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return m_ResourceLoader.LoadBinaryFromFileSystem(binaryAssetName, buffer, startIndex, buffer.Length - startIndex); } /// /// 从文件系统中加载二进制资源。 /// /// 要加载二进制资源的名称。 /// 存储加载二进制资源的二进制流。 /// 存储加载二进制资源的二进制流的起始位置。 /// 存储加载二进制资源的二进制流的长度。 /// 实际加载了多少字节。 public int LoadBinaryFromFileSystem(string binaryAssetName, byte[] buffer, int startIndex, int length) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return m_ResourceLoader.LoadBinaryFromFileSystem(binaryAssetName, buffer, startIndex, length); } /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的长度。 /// 存储加载二进制资源片段内容的二进制流。 public byte[] LoadBinarySegmentFromFileSystem(string binaryAssetName, int length) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } return m_ResourceLoader.LoadBinarySegmentFromFileSystem(binaryAssetName, 0, length); } /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的偏移。 /// 要加载片段的长度。 /// 存储加载二进制资源片段内容的二进制流。 public byte[] LoadBinarySegmentFromFileSystem(string binaryAssetName, int offset, int length) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } return m_ResourceLoader.LoadBinarySegmentFromFileSystem(binaryAssetName, offset, length); } /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 存储加载二进制资源片段内容的二进制流。 /// 实际加载了多少字节。 public int LoadBinarySegmentFromFileSystem(string binaryAssetName, byte[] buffer) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return m_ResourceLoader.LoadBinarySegmentFromFileSystem(binaryAssetName, 0, buffer, 0, buffer.Length); } /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 存储加载二进制资源片段内容的二进制流。 /// 要加载片段的长度。 /// 实际加载了多少字节。 public int LoadBinarySegmentFromFileSystem(string binaryAssetName, byte[] buffer, int length) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return m_ResourceLoader.LoadBinarySegmentFromFileSystem(binaryAssetName, 0, buffer, 0, length); } /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 存储加载二进制资源片段内容的二进制流。 /// 存储加载二进制资源片段内容的二进制流的起始位置。 /// 要加载片段的长度。 /// 实际加载了多少字节。 public int LoadBinarySegmentFromFileSystem(string binaryAssetName, byte[] buffer, int startIndex, int length) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return m_ResourceLoader.LoadBinarySegmentFromFileSystem(binaryAssetName, 0, buffer, startIndex, length); } /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的偏移。 /// 存储加载二进制资源片段内容的二进制流。 /// 实际加载了多少字节。 public int LoadBinarySegmentFromFileSystem(string binaryAssetName, int offset, byte[] buffer) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return m_ResourceLoader.LoadBinarySegmentFromFileSystem(binaryAssetName, offset, buffer, 0, buffer.Length); } /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的偏移。 /// 存储加载二进制资源片段内容的二进制流。 /// 要加载片段的长度。 /// 实际加载了多少字节。 public int LoadBinarySegmentFromFileSystem(string binaryAssetName, int offset, byte[] buffer, int length) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return m_ResourceLoader.LoadBinarySegmentFromFileSystem(binaryAssetName, offset, buffer, 0, length); } /// /// 从文件系统中加载二进制资源的片段。 /// /// 要加载片段的二进制资源的名称。 /// 要加载片段的偏移。 /// 存储加载二进制资源片段内容的二进制流。 /// 存储加载二进制资源片段内容的二进制流的起始位置。 /// 要加载片段的长度。 /// 实际加载了多少字节。 public int LoadBinarySegmentFromFileSystem(string binaryAssetName, int offset, byte[] buffer, int startIndex, int length) { if (string.IsNullOrEmpty(binaryAssetName)) { throw new GameFrameworkException("Binary asset name is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } return m_ResourceLoader.LoadBinarySegmentFromFileSystem(binaryAssetName, offset, buffer, startIndex, length); } /// /// 检查资源组是否存在。 /// /// 要检查资源组的名称。 /// 资源组是否存在。 public bool HasResourceGroup(string resourceGroupName) { return m_ResourceGroups.ContainsKey(resourceGroupName ?? string.Empty); } /// /// 获取默认资源组。 /// /// 默认资源组。 public IResourceGroup GetResourceGroup() { return GetResourceGroup(string.Empty); } /// /// 获取资源组。 /// /// 要获取的资源组名称。 /// 要获取的资源组。 public IResourceGroup GetResourceGroup(string resourceGroupName) { ResourceGroup resourceGroup = null; if (m_ResourceGroups.TryGetValue(resourceGroupName ?? string.Empty, out resourceGroup)) { return resourceGroup; } return null; } /// /// 获取所有资源组。 /// /// 所有资源组。 public IResourceGroup[] GetAllResourceGroups() { int index = 0; IResourceGroup[] results = new IResourceGroup[m_ResourceGroups.Count]; foreach (KeyValuePair resourceGroup in m_ResourceGroups) { results[index++] = resourceGroup.Value; } return results; } /// /// 获取所有资源组。 /// /// 所有资源组。 public void GetAllResourceGroups(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair resourceGroup in m_ResourceGroups) { results.Add(resourceGroup.Value); } } /// /// 获取资源组集合。 /// /// 要获取的资源组名称的集合。 /// 要获取的资源组集合。 public IResourceGroupCollection GetResourceGroupCollection(params string[] resourceGroupNames) { if (resourceGroupNames == null || resourceGroupNames.Length < 1) { throw new GameFrameworkException("Resource group names is invalid."); } ResourceGroup[] resourceGroups = new ResourceGroup[resourceGroupNames.Length]; for (int i = 0; i < resourceGroupNames.Length; i++) { if (string.IsNullOrEmpty(resourceGroupNames[i])) { throw new GameFrameworkException("Resource group name is invalid."); } resourceGroups[i] = (ResourceGroup)GetResourceGroup(resourceGroupNames[i]); if (resourceGroups[i] == null) { throw new GameFrameworkException(Utility.Text.Format("Resource group '{0}' is not exist.", resourceGroupNames[i])); } } return new ResourceGroupCollection(resourceGroups, m_ResourceInfos); } /// /// 获取资源组集合。 /// /// 要获取的资源组名称的集合。 /// 要获取的资源组集合。 public IResourceGroupCollection GetResourceGroupCollection(List resourceGroupNames) { if (resourceGroupNames == null || resourceGroupNames.Count < 1) { throw new GameFrameworkException("Resource group names is invalid."); } ResourceGroup[] resourceGroups = new ResourceGroup[resourceGroupNames.Count]; for (int i = 0; i < resourceGroupNames.Count; i++) { if (string.IsNullOrEmpty(resourceGroupNames[i])) { throw new GameFrameworkException("Resource group name is invalid."); } resourceGroups[i] = (ResourceGroup)GetResourceGroup(resourceGroupNames[i]); if (resourceGroups[i] == null) { throw new GameFrameworkException(Utility.Text.Format("Resource group '{0}' is not exist.", resourceGroupNames[i])); } } return new ResourceGroupCollection(resourceGroups, m_ResourceInfos); } private void UpdateResource(ResourceName resourceName) { m_ResourceUpdater.UpdateResource(resourceName); } private ResourceGroup GetOrAddResourceGroup(string resourceGroupName) { if (resourceGroupName == null) { resourceGroupName = string.Empty; } ResourceGroup resourceGroup = null; if (!m_ResourceGroups.TryGetValue(resourceGroupName, out resourceGroup)) { resourceGroup = new ResourceGroup(resourceGroupName, m_ResourceInfos); m_ResourceGroups.Add(resourceGroupName, resourceGroup); } return resourceGroup; } private AssetInfo GetAssetInfo(string assetName) { if (string.IsNullOrEmpty(assetName)) { throw new GameFrameworkException("Asset name is invalid."); } if (m_AssetInfos == null) { return null; } AssetInfo assetInfo = null; if (m_AssetInfos.TryGetValue(assetName, out assetInfo)) { return assetInfo; } return null; } private ResourceInfo GetResourceInfo(ResourceName resourceName) { if (m_ResourceInfos == null) { return null; } ResourceInfo resourceInfo = null; if (m_ResourceInfos.TryGetValue(resourceName, out resourceInfo)) { return resourceInfo; } return null; } private IFileSystem GetFileSystem(string fileSystemName, bool storageInReadOnly) { if (string.IsNullOrEmpty(fileSystemName)) { throw new GameFrameworkException("File system name is invalid."); } IFileSystem fileSystem = null; if (storageInReadOnly) { if (!m_ReadOnlyFileSystems.TryGetValue(fileSystemName, out fileSystem)) { string fullPath = Utility.Path.GetRegularPath(Path.Combine(m_ReadOnlyPath, Utility.Text.Format("{0}.{1}", fileSystemName, DefaultExtension))); fileSystem = m_FileSystemManager.GetFileSystem(fullPath); if (fileSystem == null) { fileSystem = m_FileSystemManager.LoadFileSystem(fullPath, FileSystemAccess.Read); m_ReadOnlyFileSystems.Add(fileSystemName, fileSystem); } } } else { if (!m_ReadWriteFileSystems.TryGetValue(fileSystemName, out fileSystem)) { string fullPath = Utility.Path.GetRegularPath(Path.Combine(m_ReadWritePath, Utility.Text.Format("{0}.{1}", fileSystemName, DefaultExtension))); fileSystem = m_FileSystemManager.GetFileSystem(fullPath); if (fileSystem == null) { if (File.Exists(fullPath)) { fileSystem = m_FileSystemManager.LoadFileSystem(fullPath, FileSystemAccess.ReadWrite); } else { string directory = Path.GetDirectoryName(fullPath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } fileSystem = m_FileSystemManager.CreateFileSystem(fullPath, FileSystemAccess.ReadWrite, FileSystemMaxFileCount, FileSystemMaxBlockCount); } m_ReadWriteFileSystems.Add(fileSystemName, fileSystem); } } } return fileSystem; } private void PrepareCachedStream() { if (m_CachedStream == null) { m_CachedStream = new MemoryStream(); } m_CachedStream.Position = 0L; m_CachedStream.SetLength(0L); } private void FreeCachedStream() { if (m_CachedStream != null) { m_CachedStream.Dispose(); m_CachedStream = null; } } private void OnIniterResourceInitComplete() { m_ResourceIniter.ResourceInitComplete -= OnIniterResourceInitComplete; m_ResourceIniter.Shutdown(); m_ResourceIniter = null; m_InitResourcesCompleteCallback(); m_InitResourcesCompleteCallback = null; } private void OnVersionListProcessorUpdateSuccess(string downloadPath, string downloadUri) { m_UpdateVersionListCallbacks.UpdateVersionListSuccessCallback(downloadPath, downloadUri); } private void OnVersionListProcessorUpdateFailure(string downloadUri, string errorMessage) { if (m_UpdateVersionListCallbacks.UpdateVersionListFailureCallback != null) { m_UpdateVersionListCallbacks.UpdateVersionListFailureCallback(downloadUri, errorMessage); } } private void OnVerifierResourceVerifyStart(int count, long totalLength) { if (m_ResourceVerifyStartEventHandler != null) { ResourceVerifyStartEventArgs resourceVerifyStartEventArgs = ResourceVerifyStartEventArgs.Create(count, totalLength); m_ResourceVerifyStartEventHandler(this, resourceVerifyStartEventArgs); ReferencePool.Release(resourceVerifyStartEventArgs); } } private void OnVerifierResourceVerifySuccess(ResourceName resourceName, int length) { if (m_ResourceVerifySuccessEventHandler != null) { ResourceVerifySuccessEventArgs resourceVerifySuccessEventArgs = ResourceVerifySuccessEventArgs.Create(resourceName.FullName, length); m_ResourceVerifySuccessEventHandler(this, resourceVerifySuccessEventArgs); ReferencePool.Release(resourceVerifySuccessEventArgs); } } private void OnVerifierResourceVerifyFailure(ResourceName resourceName) { if (m_ResourceVerifyFailureEventHandler != null) { ResourceVerifyFailureEventArgs resourceVerifyFailureEventArgs = ResourceVerifyFailureEventArgs.Create(resourceName.FullName); m_ResourceVerifyFailureEventHandler(this, resourceVerifyFailureEventArgs); ReferencePool.Release(resourceVerifyFailureEventArgs); } } private void OnVerifierResourceVerifyComplete(bool result) { m_VerifyResourcesCompleteCallback(result); m_ResourceVerifier.ResourceVerifyStart -= OnVerifierResourceVerifyStart; m_ResourceVerifier.ResourceVerifySuccess -= OnVerifierResourceVerifySuccess; m_ResourceVerifier.ResourceVerifyFailure -= OnVerifierResourceVerifyFailure; m_ResourceVerifier.ResourceVerifyComplete -= OnVerifierResourceVerifyComplete; m_ResourceVerifier.Shutdown(); m_ResourceVerifier = null; } private void OnCheckerResourceNeedUpdate(ResourceName resourceName, string fileSystemName, LoadType loadType, int length, int hashCode, int compressedLength, int compressedHashCode) { m_ResourceUpdater.AddResourceUpdate(resourceName, fileSystemName, loadType, length, hashCode, compressedLength, compressedHashCode, Utility.Path.GetRegularPath(Path.Combine(m_ReadWritePath, resourceName.FullName))); } private void OnCheckerResourceCheckComplete(int movedCount, int removedCount, int updateCount, long updateTotalLength, long updateTotalCompressedLength) { m_VersionListProcessor.VersionListUpdateSuccess -= OnVersionListProcessorUpdateSuccess; m_VersionListProcessor.VersionListUpdateFailure -= OnVersionListProcessorUpdateFailure; m_VersionListProcessor.Shutdown(); m_VersionListProcessor = null; m_UpdateVersionListCallbacks = null; m_ResourceChecker.ResourceNeedUpdate -= OnCheckerResourceNeedUpdate; m_ResourceChecker.ResourceCheckComplete -= OnCheckerResourceCheckComplete; m_ResourceChecker.Shutdown(); m_ResourceChecker = null; m_ResourceUpdater.CheckResourceComplete(movedCount > 0 || removedCount > 0); if (updateCount <= 0) { m_ResourceUpdater.ResourceApplyStart -= OnUpdaterResourceApplyStart; m_ResourceUpdater.ResourceApplySuccess -= OnUpdaterResourceApplySuccess; m_ResourceUpdater.ResourceApplyFailure -= OnUpdaterResourceApplyFailure; m_ResourceUpdater.ResourceApplyComplete -= OnUpdaterResourceApplyComplete; m_ResourceUpdater.ResourceUpdateStart -= OnUpdaterResourceUpdateStart; m_ResourceUpdater.ResourceUpdateChanged -= OnUpdaterResourceUpdateChanged; m_ResourceUpdater.ResourceUpdateSuccess -= OnUpdaterResourceUpdateSuccess; m_ResourceUpdater.ResourceUpdateFailure -= OnUpdaterResourceUpdateFailure; m_ResourceUpdater.ResourceUpdateComplete -= OnUpdaterResourceUpdateComplete; m_ResourceUpdater.ResourceUpdateAllComplete -= OnUpdaterResourceUpdateAllComplete; m_ResourceUpdater.Shutdown(); m_ResourceUpdater = null; m_ReadWriteResourceInfos.Clear(); m_ReadWriteResourceInfos = null; FreeCachedStream(); } m_CheckResourcesCompleteCallback(movedCount, removedCount, updateCount, updateTotalLength, updateTotalCompressedLength); m_CheckResourcesCompleteCallback = null; } private void OnUpdaterResourceApplyStart(string resourcePackPath, int count, long totalLength) { if (m_ResourceApplyStartEventHandler != null) { ResourceApplyStartEventArgs resourceApplyStartEventArgs = ResourceApplyStartEventArgs.Create(resourcePackPath, count, totalLength); m_ResourceApplyStartEventHandler(this, resourceApplyStartEventArgs); ReferencePool.Release(resourceApplyStartEventArgs); } } private void OnUpdaterResourceApplySuccess(ResourceName resourceName, string applyPath, string resourcePackPath, int length, int compressedLength) { if (m_ResourceApplySuccessEventHandler != null) { ResourceApplySuccessEventArgs resourceApplySuccessEventArgs = ResourceApplySuccessEventArgs.Create(resourceName.FullName, applyPath, resourcePackPath, length, compressedLength); m_ResourceApplySuccessEventHandler(this, resourceApplySuccessEventArgs); ReferencePool.Release(resourceApplySuccessEventArgs); } } private void OnUpdaterResourceApplyFailure(ResourceName resourceName, string resourcePackPath, string errorMessage) { if (m_ResourceApplyFailureEventHandler != null) { ResourceApplyFailureEventArgs resourceApplyFailureEventArgs = ResourceApplyFailureEventArgs.Create(resourceName.FullName, resourcePackPath, errorMessage); m_ResourceApplyFailureEventHandler(this, resourceApplyFailureEventArgs); ReferencePool.Release(resourceApplyFailureEventArgs); } } private void OnUpdaterResourceApplyComplete(string resourcePackPath, bool result) { ApplyResourcesCompleteCallback applyResourcesCompleteCallback = m_ApplyResourcesCompleteCallback; m_ApplyResourcesCompleteCallback = null; applyResourcesCompleteCallback(resourcePackPath, result); } private void OnUpdaterResourceUpdateStart(ResourceName resourceName, string downloadPath, string downloadUri, int currentLength, int compressedLength, int retryCount) { if (m_ResourceUpdateStartEventHandler != null) { ResourceUpdateStartEventArgs resourceUpdateStartEventArgs = ResourceUpdateStartEventArgs.Create(resourceName.FullName, downloadPath, downloadUri, currentLength, compressedLength, retryCount); m_ResourceUpdateStartEventHandler(this, resourceUpdateStartEventArgs); ReferencePool.Release(resourceUpdateStartEventArgs); } } private void OnUpdaterResourceUpdateChanged(ResourceName resourceName, string downloadPath, string downloadUri, int currentLength, int compressedLength) { if (m_ResourceUpdateChangedEventHandler != null) { ResourceUpdateChangedEventArgs resourceUpdateChangedEventArgs = ResourceUpdateChangedEventArgs.Create(resourceName.FullName, downloadPath, downloadUri, currentLength, compressedLength); m_ResourceUpdateChangedEventHandler(this, resourceUpdateChangedEventArgs); ReferencePool.Release(resourceUpdateChangedEventArgs); } } private void OnUpdaterResourceUpdateSuccess(ResourceName resourceName, string downloadPath, string downloadUri, int length, int compressedLength) { if (m_ResourceUpdateSuccessEventHandler != null) { ResourceUpdateSuccessEventArgs resourceUpdateSuccessEventArgs = ResourceUpdateSuccessEventArgs.Create(resourceName.FullName, downloadPath, downloadUri, length, compressedLength); m_ResourceUpdateSuccessEventHandler(this, resourceUpdateSuccessEventArgs); ReferencePool.Release(resourceUpdateSuccessEventArgs); } } private void OnUpdaterResourceUpdateFailure(ResourceName resourceName, string downloadUri, int retryCount, int totalRetryCount, string errorMessage) { if (m_ResourceUpdateFailureEventHandler != null) { ResourceUpdateFailureEventArgs resourceUpdateFailureEventArgs = ResourceUpdateFailureEventArgs.Create(resourceName.FullName, downloadUri, retryCount, totalRetryCount, errorMessage); m_ResourceUpdateFailureEventHandler(this, resourceUpdateFailureEventArgs); ReferencePool.Release(resourceUpdateFailureEventArgs); } } private void OnUpdaterResourceUpdateComplete(ResourceGroup resourceGroup, bool result) { Utility.Path.RemoveEmptyDirectory(m_ReadWritePath); UpdateResourcesCompleteCallback updateResourcesCompleteCallback = m_UpdateResourcesCompleteCallback; m_UpdateResourcesCompleteCallback = null; updateResourcesCompleteCallback(resourceGroup, result); } private void OnUpdaterResourceUpdateAllComplete() { m_ResourceUpdater.ResourceApplyStart -= OnUpdaterResourceApplyStart; m_ResourceUpdater.ResourceApplySuccess -= OnUpdaterResourceApplySuccess; m_ResourceUpdater.ResourceApplyFailure -= OnUpdaterResourceApplyFailure; m_ResourceUpdater.ResourceApplyComplete -= OnUpdaterResourceApplyComplete; m_ResourceUpdater.ResourceUpdateStart -= OnUpdaterResourceUpdateStart; m_ResourceUpdater.ResourceUpdateChanged -= OnUpdaterResourceUpdateChanged; m_ResourceUpdater.ResourceUpdateSuccess -= OnUpdaterResourceUpdateSuccess; m_ResourceUpdater.ResourceUpdateFailure -= OnUpdaterResourceUpdateFailure; m_ResourceUpdater.ResourceUpdateComplete -= OnUpdaterResourceUpdateComplete; m_ResourceUpdater.ResourceUpdateAllComplete -= OnUpdaterResourceUpdateAllComplete; m_ResourceUpdater.Shutdown(); m_ResourceUpdater = null; m_ReadWriteResourceInfos.Clear(); m_ReadWriteResourceInfos = null; FreeCachedStream(); Utility.Path.RemoveEmptyDirectory(m_ReadWritePath); if (m_ResourceUpdateAllCompleteEventHandler != null) { ResourceUpdateAllCompleteEventArgs resourceUpdateAllCompleteEventArgs = ResourceUpdateAllCompleteEventArgs.Create(); m_ResourceUpdateAllCompleteEventHandler(this, resourceUpdateAllCompleteEventArgs); ReferencePool.Release(resourceUpdateAllCompleteEventArgs); } } } } ================================================ FILE: GameFramework/Resource/ResourceMode.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源模式。 /// public enum ResourceMode : byte { /// /// 未指定。 /// Unspecified = 0, /// /// 单机模式。 /// Package, /// /// 预下载的可更新模式。 /// Updatable, /// /// 使用时下载的可更新模式。 /// UpdatableWhilePlaying } } ================================================ FILE: GameFramework/Resource/ResourcePackVersionList.Resource.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct ResourcePackVersionList { /// /// 资源。 /// [StructLayout(LayoutKind.Auto)] public struct Resource { private readonly string m_Name; private readonly string m_Variant; private readonly string m_Extension; private readonly byte m_LoadType; private readonly long m_Offset; private readonly int m_Length; private readonly int m_HashCode; private readonly int m_CompressedLength; private readonly int m_CompressedHashCode; /// /// 初始化资源的新实例。 /// /// 资源名称。 /// 资源变体名称。 /// 资源扩展名称。 /// 资源加载方式。 /// 资源偏移。 /// 资源长度。 /// 资源哈希值。 /// 资源压缩后长度。 /// 资源压缩后哈希值。 public Resource(string name, string variant, string extension, byte loadType, long offset, int length, int hashCode, int compressedLength, int compressedHashCode) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_Variant = variant; m_Extension = extension; m_LoadType = loadType; m_Offset = offset; m_Length = length; m_HashCode = hashCode; m_CompressedLength = compressedLength; m_CompressedHashCode = compressedHashCode; } /// /// 获取资源名称。 /// public string Name { get { return m_Name; } } /// /// 获取资源变体名称。 /// public string Variant { get { return m_Variant; } } /// /// 获取资源扩展名称。 /// public string Extension { get { return m_Extension; } } /// /// 获取资源加载方式。 /// public byte LoadType { get { return m_LoadType; } } /// /// 获取资源偏移。 /// public long Offset { get { return m_Offset; } } /// /// 获取资源长度。 /// public int Length { get { return m_Length; } } /// /// 获取资源哈希值。 /// public int HashCode { get { return m_HashCode; } } /// /// 获取资源压缩后长度。 /// public int CompressedLength { get { return m_CompressedLength; } } /// /// 获取资源压缩后哈希值。 /// public int CompressedHashCode { get { return m_CompressedHashCode; } } } } } ================================================ FILE: GameFramework/Resource/ResourcePackVersionList.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { /// /// 资源包版本资源列表。 /// [StructLayout(LayoutKind.Auto)] public partial struct ResourcePackVersionList { private static readonly Resource[] EmptyResourceArray = new Resource[] { }; private readonly bool m_IsValid; private readonly int m_Offset; private readonly long m_Length; private readonly int m_HashCode; private readonly Resource[] m_Resources; /// /// 初始化资源包版本资源列表的新实例。 /// /// 资源数据偏移。 /// 资源数据长度。 /// 资源数据哈希值。 /// 包含的资源集合。 public ResourcePackVersionList(int offset, long length, int hashCode, Resource[] resources) { m_IsValid = true; m_Offset = offset; m_Length = length; m_HashCode = hashCode; m_Resources = resources ?? EmptyResourceArray; } /// /// 获取资源包版本资源列表是否有效。 /// public bool IsValid { get { return m_IsValid; } } /// /// 获取资源数据偏移。 /// public int Offset { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Offset; } } /// /// 获取资源数据长度。 /// public long Length { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Length; } } /// /// 获取资源数据哈希值。 /// public int HashCode { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_HashCode; } } /// /// 获取包含的资源集合。 /// /// 包含的资源集合。 public Resource[] GetResources() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Resources; } } } ================================================ FILE: GameFramework/Resource/ResourcePackVersionListSerializer.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源包版本资源列表序列化器。 /// public sealed class ResourcePackVersionListSerializer : GameFrameworkSerializer { private static readonly byte[] Header = new byte[] { (byte)'G', (byte)'F', (byte)'K' }; /// /// 初始化资源包版本资源列表序列化器的新实例。 /// public ResourcePackVersionListSerializer() { } /// /// 获取资源包版本资源列表头标识。 /// /// 资源包版本资源列表头标识。 protected override byte[] GetHeader() { return Header; } } } ================================================ FILE: GameFramework/Resource/ResourceUpdateAllCompleteEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源更新全部完成事件。 /// public sealed class ResourceUpdateAllCompleteEventArgs : GameFrameworkEventArgs { /// /// 初始化资源更新全部完成事件的新实例。 /// public ResourceUpdateAllCompleteEventArgs() { } /// /// 创建资源更新全部完成事件。 /// /// 创建的资源更新全部完成事件。 public static ResourceUpdateAllCompleteEventArgs Create() { return ReferencePool.Acquire(); } /// /// 清理资源更新全部完成事件。 /// public override void Clear() { } } } ================================================ FILE: GameFramework/Resource/ResourceUpdateChangedEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源更新改变事件。 /// public sealed class ResourceUpdateChangedEventArgs : GameFrameworkEventArgs { /// /// 初始化资源更新改变事件的新实例。 /// public ResourceUpdateChangedEventArgs() { Name = null; DownloadPath = null; DownloadUri = null; CurrentLength = 0; CompressedLength = 0; } /// /// 获取资源名称。 /// public string Name { get; private set; } /// /// 获取资源下载后存放路径。 /// public string DownloadPath { get; private set; } /// /// 获取下载地址。 /// public string DownloadUri { get; private set; } /// /// 获取当前下载大小。 /// public int CurrentLength { get; private set; } /// /// 获取压缩后大小。 /// public int CompressedLength { get; private set; } /// /// 创建资源更新改变事件。 /// /// 资源名称。 /// 资源下载后存放路径。 /// 资源下载地址。 /// 当前下载大小。 /// 压缩后大小。 /// 创建的资源更新改变事件。 public static ResourceUpdateChangedEventArgs Create(string name, string downloadPath, string downloadUri, int currentLength, int compressedLength) { ResourceUpdateChangedEventArgs resourceUpdateChangedEventArgs = ReferencePool.Acquire(); resourceUpdateChangedEventArgs.Name = name; resourceUpdateChangedEventArgs.DownloadPath = downloadPath; resourceUpdateChangedEventArgs.DownloadUri = downloadUri; resourceUpdateChangedEventArgs.CurrentLength = currentLength; resourceUpdateChangedEventArgs.CompressedLength = compressedLength; return resourceUpdateChangedEventArgs; } /// /// 清理资源更新改变事件。 /// public override void Clear() { Name = null; DownloadPath = null; DownloadUri = null; CurrentLength = 0; CompressedLength = 0; } } } ================================================ FILE: GameFramework/Resource/ResourceUpdateFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源更新失败事件。 /// public sealed class ResourceUpdateFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化资源更新失败事件的新实例。 /// public ResourceUpdateFailureEventArgs() { Name = null; DownloadUri = null; RetryCount = 0; TotalRetryCount = 0; ErrorMessage = null; } /// /// 获取资源名称。 /// public string Name { get; private set; } /// /// 获取下载地址。 /// public string DownloadUri { get; private set; } /// /// 获取已重试次数。 /// public int RetryCount { get; private set; } /// /// 获取设定的重试次数。 /// public int TotalRetryCount { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 创建资源更新失败事件。 /// /// 资源名称。 /// 下载地址。 /// 已重试次数。 /// 设定的重试次数。 /// 错误信息。 /// 创建的资源更新失败事件。 /// 当已重试次数达到设定的重试次数时,将不再重试。 public static ResourceUpdateFailureEventArgs Create(string name, string downloadUri, int retryCount, int totalRetryCount, string errorMessage) { ResourceUpdateFailureEventArgs resourceUpdateFailureEventArgs = ReferencePool.Acquire(); resourceUpdateFailureEventArgs.Name = name; resourceUpdateFailureEventArgs.DownloadUri = downloadUri; resourceUpdateFailureEventArgs.RetryCount = retryCount; resourceUpdateFailureEventArgs.TotalRetryCount = totalRetryCount; resourceUpdateFailureEventArgs.ErrorMessage = errorMessage; return resourceUpdateFailureEventArgs; } /// /// 清理资源更新失败事件。 /// public override void Clear() { Name = null; DownloadUri = null; RetryCount = 0; TotalRetryCount = 0; ErrorMessage = null; } } } ================================================ FILE: GameFramework/Resource/ResourceUpdateStartEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源更新开始事件。 /// public sealed class ResourceUpdateStartEventArgs : GameFrameworkEventArgs { /// /// 初始化资源更新开始事件的新实例。 /// public ResourceUpdateStartEventArgs() { Name = null; DownloadPath = null; DownloadUri = null; CurrentLength = 0; CompressedLength = 0; RetryCount = 0; } /// /// 获取资源名称。 /// public string Name { get; private set; } /// /// 获取资源下载后存放路径。 /// public string DownloadPath { get; private set; } /// /// 获取下载地址。 /// public string DownloadUri { get; private set; } /// /// 获取当前下载大小。 /// public int CurrentLength { get; private set; } /// /// 获取压缩后大小。 /// public int CompressedLength { get; private set; } /// /// 获取已重试下载次数。 /// public int RetryCount { get; private set; } /// /// 创建资源更新开始事件。 /// /// 资源名称。 /// 资源下载后存放路径。 /// 资源下载地址。 /// 当前下载大小。 /// 压缩后大小。 /// 已重试下载次数。 /// 创建的资源更新开始事件。 public static ResourceUpdateStartEventArgs Create(string name, string downloadPath, string downloadUri, int currentLength, int compressedLength, int retryCount) { ResourceUpdateStartEventArgs resourceUpdateStartEventArgs = ReferencePool.Acquire(); resourceUpdateStartEventArgs.Name = name; resourceUpdateStartEventArgs.DownloadPath = downloadPath; resourceUpdateStartEventArgs.DownloadUri = downloadUri; resourceUpdateStartEventArgs.CurrentLength = currentLength; resourceUpdateStartEventArgs.CompressedLength = compressedLength; resourceUpdateStartEventArgs.RetryCount = retryCount; return resourceUpdateStartEventArgs; } /// /// 清理资源更新开始事件。 /// public override void Clear() { Name = null; DownloadPath = null; DownloadUri = null; CurrentLength = 0; CompressedLength = 0; RetryCount = 0; } } } ================================================ FILE: GameFramework/Resource/ResourceUpdateSuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源更新成功事件。 /// public sealed class ResourceUpdateSuccessEventArgs : GameFrameworkEventArgs { /// /// 初始化资源更新成功事件的新实例。 /// public ResourceUpdateSuccessEventArgs() { Name = null; DownloadPath = null; DownloadUri = null; Length = 0; CompressedLength = 0; } /// /// 获取资源名称。 /// public string Name { get; private set; } /// /// 获取资源下载后存放路径。 /// public string DownloadPath { get; private set; } /// /// 获取下载地址。 /// public string DownloadUri { get; private set; } /// /// 获取资源大小。 /// public int Length { get; private set; } /// /// 获取压缩后大小。 /// public int CompressedLength { get; private set; } /// /// 创建资源更新成功事件。 /// /// 资源名称。 /// 资源下载后存放路径。 /// 资源下载地址。 /// 资源大小。 /// 压缩后大小。 /// 创建的资源更新成功事件。 public static ResourceUpdateSuccessEventArgs Create(string name, string downloadPath, string downloadUri, int length, int compressedLength) { ResourceUpdateSuccessEventArgs resourceUpdateSuccessEventArgs = ReferencePool.Acquire(); resourceUpdateSuccessEventArgs.Name = name; resourceUpdateSuccessEventArgs.DownloadPath = downloadPath; resourceUpdateSuccessEventArgs.DownloadUri = downloadUri; resourceUpdateSuccessEventArgs.Length = length; resourceUpdateSuccessEventArgs.CompressedLength = compressedLength; return resourceUpdateSuccessEventArgs; } /// /// 清理资源更新成功事件。 /// public override void Clear() { Name = null; DownloadPath = null; DownloadUri = null; Length = 0; CompressedLength = 0; } } } ================================================ FILE: GameFramework/Resource/ResourceVerifyFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源校验失败事件。 /// public sealed class ResourceVerifyFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化资源校验失败事件的新实例。 /// public ResourceVerifyFailureEventArgs() { Name = null; } /// /// 获取资源名称。 /// public string Name { get; private set; } /// /// 创建资源校验失败事件。 /// /// 资源名称。 /// 创建的资源校验失败事件。 public static ResourceVerifyFailureEventArgs Create(string name) { ResourceVerifyFailureEventArgs resourceVerifyFailureEventArgs = ReferencePool.Acquire(); resourceVerifyFailureEventArgs.Name = name; return resourceVerifyFailureEventArgs; } /// /// 清理资源校验失败事件。 /// public override void Clear() { Name = null; } } } ================================================ FILE: GameFramework/Resource/ResourceVerifyStartEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源校验开始事件。 /// public sealed class ResourceVerifyStartEventArgs : GameFrameworkEventArgs { /// /// 初始化资源校验开始事件的新实例。 /// public ResourceVerifyStartEventArgs() { Count = 0; TotalLength = 0L; } /// /// 获取要校验资源的数量。 /// public int Count { get; private set; } /// /// 获取要校验资源的总大小。 /// public long TotalLength { get; private set; } /// /// 创建资源校验开始事件。 /// /// 要校验资源的数量。 /// 要校验资源的总大小。 /// 创建的资源校验开始事件。 public static ResourceVerifyStartEventArgs Create(int count, long totalLength) { ResourceVerifyStartEventArgs resourceVerifyStartEventArgs = ReferencePool.Acquire(); resourceVerifyStartEventArgs.Count = count; resourceVerifyStartEventArgs.TotalLength = totalLength; return resourceVerifyStartEventArgs; } /// /// 清理资源校验开始事件。 /// public override void Clear() { Count = 0; TotalLength = 0L; } } } ================================================ FILE: GameFramework/Resource/ResourceVerifySuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 资源校验成功事件。 /// public sealed class ResourceVerifySuccessEventArgs : GameFrameworkEventArgs { /// /// 初始化资源校验成功事件的新实例。 /// public ResourceVerifySuccessEventArgs() { Name = null; Length = 0; } /// /// 获取资源名称。 /// public string Name { get; private set; } /// /// 获取资源大小。 /// public int Length { get; private set; } /// /// 创建资源校验成功事件。 /// /// 资源名称。 /// 资源大小。 /// 创建的资源校验成功事件。 public static ResourceVerifySuccessEventArgs Create(string name, int length) { ResourceVerifySuccessEventArgs resourceVerifySuccessEventArgs = ReferencePool.Acquire(); resourceVerifySuccessEventArgs.Name = name; resourceVerifySuccessEventArgs.Length = length; return resourceVerifySuccessEventArgs; } /// /// 清理资源校验成功事件。 /// public override void Clear() { Name = null; Length = 0; } } } ================================================ FILE: GameFramework/Resource/UnloadSceneCallbacks.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 卸载场景回调函数集。 /// public sealed class UnloadSceneCallbacks { private readonly UnloadSceneSuccessCallback m_UnloadSceneSuccessCallback; private readonly UnloadSceneFailureCallback m_UnloadSceneFailureCallback; /// /// 初始化卸载场景回调函数集的新实例。 /// /// 卸载场景成功回调函数。 public UnloadSceneCallbacks(UnloadSceneSuccessCallback unloadSceneSuccessCallback) : this(unloadSceneSuccessCallback, null) { } /// /// 初始化卸载场景回调函数集的新实例。 /// /// 卸载场景成功回调函数。 /// 卸载场景失败回调函数。 public UnloadSceneCallbacks(UnloadSceneSuccessCallback unloadSceneSuccessCallback, UnloadSceneFailureCallback unloadSceneFailureCallback) { if (unloadSceneSuccessCallback == null) { throw new GameFrameworkException("Unload scene success callback is invalid."); } m_UnloadSceneSuccessCallback = unloadSceneSuccessCallback; m_UnloadSceneFailureCallback = unloadSceneFailureCallback; } /// /// 获取卸载场景成功回调函数。 /// public UnloadSceneSuccessCallback UnloadSceneSuccessCallback { get { return m_UnloadSceneSuccessCallback; } } /// /// 获取卸载场景失败回调函数。 /// public UnloadSceneFailureCallback UnloadSceneFailureCallback { get { return m_UnloadSceneFailureCallback; } } } } ================================================ FILE: GameFramework/Resource/UnloadSceneFailureCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 卸载场景失败回调函数。 /// /// 要卸载的场景资源名称。 /// 用户自定义数据。 public delegate void UnloadSceneFailureCallback(string sceneAssetName, object userData); } ================================================ FILE: GameFramework/Resource/UnloadSceneSuccessCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 卸载场景成功回调函数。 /// /// 要卸载的场景资源名称。 /// 用户自定义数据。 public delegate void UnloadSceneSuccessCallback(string sceneAssetName, object userData); } ================================================ FILE: GameFramework/Resource/UpdatableVersionList.Asset.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct UpdatableVersionList { /// /// 资源。 /// [StructLayout(LayoutKind.Auto)] public struct Asset { private static readonly int[] EmptyIntArray = new int[] { }; private readonly string m_Name; private readonly int[] m_DependencyAssetIndexes; /// /// 初始化资源的新实例。 /// /// 资源名称。 /// 资源包含的依赖资源索引集合。 public Asset(string name, int[] dependencyAssetIndexes) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_DependencyAssetIndexes = dependencyAssetIndexes ?? EmptyIntArray; } /// /// 获取资源名称。 /// public string Name { get { return m_Name; } } /// /// 获取资源包含的依赖资源索引集合。 /// /// 资源包含的依赖资源索引集合。 public int[] GetDependencyAssetIndexes() { return m_DependencyAssetIndexes; } } } } ================================================ FILE: GameFramework/Resource/UpdatableVersionList.FileSystem.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct UpdatableVersionList { /// /// 文件系统。 /// [StructLayout(LayoutKind.Auto)] public struct FileSystem { private static readonly int[] EmptyIntArray = new int[] { }; private readonly string m_Name; private readonly int[] m_ResourceIndexes; /// /// 初始化文件系统的新实例。 /// /// 文件系统名称。 /// 文件系统包含的资源索引集合。 public FileSystem(string name, int[] resourceIndexes) { if (name == null) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_ResourceIndexes = resourceIndexes ?? EmptyIntArray; } /// /// 获取文件系统名称。 /// public string Name { get { return m_Name; } } /// /// 获取文件系统包含的资源索引集合。 /// /// 文件系统包含的资源索引集合。 public int[] GetResourceIndexes() { return m_ResourceIndexes; } } } } ================================================ FILE: GameFramework/Resource/UpdatableVersionList.Resource.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct UpdatableVersionList { /// /// 资源。 /// [StructLayout(LayoutKind.Auto)] public struct Resource { private static readonly int[] EmptyIntArray = new int[] { }; private readonly string m_Name; private readonly string m_Variant; private readonly string m_Extension; private readonly byte m_LoadType; private readonly int m_Length; private readonly int m_HashCode; private readonly int m_CompressedLength; private readonly int m_CompressedHashCode; private readonly int[] m_AssetIndexes; /// /// 初始化资源的新实例。 /// /// 资源名称。 /// 资源变体名称。 /// 资源扩展名称。 /// 资源加载方式。 /// 资源长度。 /// 资源哈希值。 /// 资源压缩后长度。 /// 资源压缩后哈希值。 /// 资源包含的资源索引集合。 public Resource(string name, string variant, string extension, byte loadType, int length, int hashCode, int compressedLength, int compressedHashCode, int[] assetIndexes) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_Variant = variant; m_Extension = extension; m_LoadType = loadType; m_Length = length; m_HashCode = hashCode; m_CompressedLength = compressedLength; m_CompressedHashCode = compressedHashCode; m_AssetIndexes = assetIndexes ?? EmptyIntArray; } /// /// 获取资源名称。 /// public string Name { get { return m_Name; } } /// /// 获取资源变体名称。 /// public string Variant { get { return m_Variant; } } /// /// 获取资源扩展名称。 /// public string Extension { get { return m_Extension; } } /// /// 获取资源加载方式。 /// public byte LoadType { get { return m_LoadType; } } /// /// 获取资源长度。 /// public int Length { get { return m_Length; } } /// /// 获取资源哈希值。 /// public int HashCode { get { return m_HashCode; } } /// /// 获取资源压缩后长度。 /// public int CompressedLength { get { return m_CompressedLength; } } /// /// 获取资源压缩后哈希值。 /// public int CompressedHashCode { get { return m_CompressedHashCode; } } /// /// 获取资源包含的资源索引集合。 /// /// 资源包含的资源索引集合。 public int[] GetAssetIndexes() { return m_AssetIndexes; } } } } ================================================ FILE: GameFramework/Resource/UpdatableVersionList.ResourceGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { public partial struct UpdatableVersionList { /// /// 资源组。 /// [StructLayout(LayoutKind.Auto)] public struct ResourceGroup { private static readonly int[] EmptyIntArray = new int[] { }; private readonly string m_Name; private readonly int[] m_ResourceIndexes; /// /// 初始化资源组的新实例。 /// /// 资源组名称。 /// 资源组包含的资源索引集合。 public ResourceGroup(string name, int[] resourceIndexes) { if (name == null) { throw new GameFrameworkException("Name is invalid."); } m_Name = name; m_ResourceIndexes = resourceIndexes ?? EmptyIntArray; } /// /// 获取资源组名称。 /// public string Name { get { return m_Name; } } /// /// 获取资源组包含的资源索引集合。 /// /// 资源组包含的资源索引集合。 public int[] GetResourceIndexes() { return m_ResourceIndexes; } } } } ================================================ FILE: GameFramework/Resource/UpdatableVersionList.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Runtime.InteropServices; namespace GameFramework.Resource { /// /// 可更新模式版本资源列表。 /// [StructLayout(LayoutKind.Auto)] public partial struct UpdatableVersionList { private static readonly Asset[] EmptyAssetArray = new Asset[] { }; private static readonly Resource[] EmptyResourceArray = new Resource[] { }; private static readonly FileSystem[] EmptyFileSystemArray = new FileSystem[] { }; private static readonly ResourceGroup[] EmptyResourceGroupArray = new ResourceGroup[] { }; private readonly bool m_IsValid; private readonly string m_ApplicableGameVersion; private readonly int m_InternalResourceVersion; private readonly Asset[] m_Assets; private readonly Resource[] m_Resources; private readonly FileSystem[] m_FileSystems; private readonly ResourceGroup[] m_ResourceGroups; /// /// 初始化可更新模式版本资源列表的新实例。 /// /// 适配的游戏版本号。 /// 内部资源版本号。 /// 包含的资源集合。 /// 包含的资源集合。 /// 包含的文件系统集合。 /// 包含的资源组集合。 public UpdatableVersionList(string applicableGameVersion, int internalResourceVersion, Asset[] assets, Resource[] resources, FileSystem[] fileSystems, ResourceGroup[] resourceGroups) { m_IsValid = true; m_ApplicableGameVersion = applicableGameVersion; m_InternalResourceVersion = internalResourceVersion; m_Assets = assets ?? EmptyAssetArray; m_Resources = resources ?? EmptyResourceArray; m_FileSystems = fileSystems ?? EmptyFileSystemArray; m_ResourceGroups = resourceGroups ?? EmptyResourceGroupArray; } /// /// 获取可更新模式版本资源列表是否有效。 /// public bool IsValid { get { return m_IsValid; } } /// /// 获取适配的游戏版本号。 /// public string ApplicableGameVersion { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_ApplicableGameVersion; } } /// /// 获取内部资源版本号。 /// public int InternalResourceVersion { get { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_InternalResourceVersion; } } /// /// 获取包含的资源集合。 /// /// 包含的资源集合。 public Asset[] GetAssets() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Assets; } /// /// 获取包含的资源集合。 /// /// 包含的资源集合。 public Resource[] GetResources() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_Resources; } /// /// 获取包含的文件系统集合。 /// /// 包含的文件系统集合。 public FileSystem[] GetFileSystems() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_FileSystems; } /// /// 获取包含的资源组集合。 /// /// 包含的资源组集合。 public ResourceGroup[] GetResourceGroups() { if (!m_IsValid) { throw new GameFrameworkException("Data is invalid."); } return m_ResourceGroups; } } } ================================================ FILE: GameFramework/Resource/UpdatableVersionListSerializer.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 可更新模式版本资源列表序列化器。 /// public sealed class UpdatableVersionListSerializer : GameFrameworkSerializer { private static readonly byte[] Header = new byte[] { (byte)'G', (byte)'F', (byte)'U' }; /// /// 初始化可更新模式版本资源列表序列化器的新实例。 /// public UpdatableVersionListSerializer() { } /// /// 获取可更新模式版本资源列表头标识。 /// /// 可更新模式版本资源列表头标识。 protected override byte[] GetHeader() { return Header; } } } ================================================ FILE: GameFramework/Resource/UpdateResourcesCompleteCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 使用可更新模式并更新指定资源组完成时的回调函数。 /// /// 更新的资源组。 /// 更新资源结果,全部成功为 true,否则为 false。 public delegate void UpdateResourcesCompleteCallback(IResourceGroup resourceGroup, bool result); } ================================================ FILE: GameFramework/Resource/UpdateVersionListCallbacks.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 版本资源列表更新回调函数集。 /// public sealed class UpdateVersionListCallbacks { private readonly UpdateVersionListSuccessCallback m_UpdateVersionListSuccessCallback; private readonly UpdateVersionListFailureCallback m_UpdateVersionListFailureCallback; /// /// 初始化版本资源列表更新回调函数集的新实例。 /// /// 版本资源列表更新成功回调函数。 public UpdateVersionListCallbacks(UpdateVersionListSuccessCallback updateVersionListSuccessCallback) : this(updateVersionListSuccessCallback, null) { } /// /// 初始化版本资源列表更新回调函数集的新实例。 /// /// 版本资源列表更新成功回调函数。 /// 版本资源列表更新失败回调函数。 public UpdateVersionListCallbacks(UpdateVersionListSuccessCallback updateVersionListSuccessCallback, UpdateVersionListFailureCallback updateVersionListFailureCallback) { if (updateVersionListSuccessCallback == null) { throw new GameFrameworkException("Update version list success callback is invalid."); } m_UpdateVersionListSuccessCallback = updateVersionListSuccessCallback; m_UpdateVersionListFailureCallback = updateVersionListFailureCallback; } /// /// 获取版本资源列表更新成功回调函数。 /// public UpdateVersionListSuccessCallback UpdateVersionListSuccessCallback { get { return m_UpdateVersionListSuccessCallback; } } /// /// 获取版本资源列表更新失败回调函数。 /// public UpdateVersionListFailureCallback UpdateVersionListFailureCallback { get { return m_UpdateVersionListFailureCallback; } } } } ================================================ FILE: GameFramework/Resource/UpdateVersionListFailureCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 版本资源列表更新失败回调函数。 /// /// 版本资源列表更新地址。 /// 错误信息。 public delegate void UpdateVersionListFailureCallback(string downloadUri, string errorMessage); } ================================================ FILE: GameFramework/Resource/UpdateVersionListSuccessCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 版本资源列表更新成功回调函数。 /// /// 版本资源列表更新后存放路径。 /// 版本资源列表更新地址。 public delegate void UpdateVersionListSuccessCallback(string downloadPath, string downloadUri); } ================================================ FILE: GameFramework/Resource/VerifyResourcesCompleteCallback.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Resource { /// /// 使用可更新模式并校验资源完成时的回调函数。 /// /// 校验资源结果,全部成功为 true,否则为 false。 public delegate void VerifyResourcesCompleteCallback(bool result); } ================================================ FILE: GameFramework/Scene/ISceneManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.Scene { /// /// 场景管理器接口。 /// public interface ISceneManager { /// /// 加载场景成功事件。 /// event EventHandler LoadSceneSuccess; /// /// 加载场景失败事件。 /// event EventHandler LoadSceneFailure; /// /// 加载场景更新事件。 /// event EventHandler LoadSceneUpdate; /// /// 加载场景时加载依赖资源事件。 /// event EventHandler LoadSceneDependencyAsset; /// /// 卸载场景成功事件。 /// event EventHandler UnloadSceneSuccess; /// /// 卸载场景失败事件。 /// event EventHandler UnloadSceneFailure; /// /// 设置资源管理器。 /// /// 资源管理器。 void SetResourceManager(IResourceManager resourceManager); /// /// 获取场景是否已加载。 /// /// 场景资源名称。 /// 场景是否已加载。 bool SceneIsLoaded(string sceneAssetName); /// /// 获取已加载场景的资源名称。 /// /// 已加载场景的资源名称。 string[] GetLoadedSceneAssetNames(); /// /// 获取已加载场景的资源名称。 /// /// 已加载场景的资源名称。 void GetLoadedSceneAssetNames(List results); /// /// 获取场景是否正在加载。 /// /// 场景资源名称。 /// 场景是否正在加载。 bool SceneIsLoading(string sceneAssetName); /// /// 获取正在加载场景的资源名称。 /// /// 正在加载场景的资源名称。 string[] GetLoadingSceneAssetNames(); /// /// 获取正在加载场景的资源名称。 /// /// 正在加载场景的资源名称。 void GetLoadingSceneAssetNames(List results); /// /// 获取场景是否正在卸载。 /// /// 场景资源名称。 /// 场景是否正在卸载。 bool SceneIsUnloading(string sceneAssetName); /// /// 获取正在卸载场景的资源名称。 /// /// 正在卸载场景的资源名称。 string[] GetUnloadingSceneAssetNames(); /// /// 获取正在卸载场景的资源名称。 /// /// 正在卸载场景的资源名称。 void GetUnloadingSceneAssetNames(List results); /// /// 检查场景资源是否存在。 /// /// 要检查场景资源的名称。 /// 场景资源是否存在。 bool HasScene(string sceneAssetName); /// /// 加载场景。 /// /// 场景资源名称。 void LoadScene(string sceneAssetName); /// /// 加载场景。 /// /// 场景资源名称。 /// 加载场景资源的优先级。 void LoadScene(string sceneAssetName, int priority); /// /// 加载场景。 /// /// 场景资源名称。 /// 用户自定义数据。 void LoadScene(string sceneAssetName, object userData); /// /// 加载场景。 /// /// 场景资源名称。 /// 加载场景资源的优先级。 /// 用户自定义数据。 void LoadScene(string sceneAssetName, int priority, object userData); /// /// 卸载场景。 /// /// 场景资源名称。 void UnloadScene(string sceneAssetName); /// /// 卸载场景。 /// /// 场景资源名称。 /// 用户自定义数据。 void UnloadScene(string sceneAssetName, object userData); } } ================================================ FILE: GameFramework/Scene/LoadSceneDependencyAssetEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Scene { /// /// 加载场景时加载依赖资源事件。 /// public sealed class LoadSceneDependencyAssetEventArgs : GameFrameworkEventArgs { /// /// 初始化加载场景时加载依赖资源事件的新实例。 /// public LoadSceneDependencyAssetEventArgs() { SceneAssetName = null; DependencyAssetName = null; LoadedCount = 0; TotalCount = 0; UserData = null; } /// /// 获取场景资源名称。 /// public string SceneAssetName { get; private set; } /// /// 获取被加载的依赖资源名称。 /// public string DependencyAssetName { get; private set; } /// /// 获取当前已加载依赖资源数量。 /// public int LoadedCount { get; private set; } /// /// 获取总共加载依赖资源数量。 /// public int TotalCount { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建场景时加载依赖资源事件。 /// /// 场景资源名称。 /// 被加载的依赖资源名称。 /// 当前已加载依赖资源数量。 /// 总共加载依赖资源数量。 /// 用户自定义数据。 /// 创建的场景时加载依赖资源事件。 public static LoadSceneDependencyAssetEventArgs Create(string sceneAssetName, string dependencyAssetName, int loadedCount, int totalCount, object userData) { LoadSceneDependencyAssetEventArgs loadSceneDependencyAssetEventArgs = ReferencePool.Acquire(); loadSceneDependencyAssetEventArgs.SceneAssetName = sceneAssetName; loadSceneDependencyAssetEventArgs.DependencyAssetName = dependencyAssetName; loadSceneDependencyAssetEventArgs.LoadedCount = loadedCount; loadSceneDependencyAssetEventArgs.TotalCount = totalCount; loadSceneDependencyAssetEventArgs.UserData = userData; return loadSceneDependencyAssetEventArgs; } /// /// 清理场景时加载依赖资源事件。 /// public override void Clear() { SceneAssetName = null; DependencyAssetName = null; LoadedCount = 0; TotalCount = 0; UserData = null; } } } ================================================ FILE: GameFramework/Scene/LoadSceneFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Scene { /// /// 加载场景失败事件。 /// public sealed class LoadSceneFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化加载场景失败事件的新实例。 /// public LoadSceneFailureEventArgs() { SceneAssetName = null; ErrorMessage = null; UserData = null; } /// /// 获取场景资源名称。 /// public string SceneAssetName { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建加载场景失败事件。 /// /// 场景资源名称。 /// 错误信息。 /// 用户自定义数据。 /// 创建的加载场景失败事件。 public static LoadSceneFailureEventArgs Create(string sceneAssetName, string errorMessage, object userData) { LoadSceneFailureEventArgs loadSceneFailureEventArgs = ReferencePool.Acquire(); loadSceneFailureEventArgs.SceneAssetName = sceneAssetName; loadSceneFailureEventArgs.ErrorMessage = errorMessage; loadSceneFailureEventArgs.UserData = userData; return loadSceneFailureEventArgs; } /// /// 清理加载场景失败事件。 /// public override void Clear() { SceneAssetName = null; ErrorMessage = null; UserData = null; } } } ================================================ FILE: GameFramework/Scene/LoadSceneSuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Scene { /// /// 加载场景成功事件。 /// public sealed class LoadSceneSuccessEventArgs : GameFrameworkEventArgs { /// /// 初始化加载场景成功事件的新实例。 /// public LoadSceneSuccessEventArgs() { SceneAssetName = null; Duration = 0f; UserData = null; } /// /// 获取场景资源名称。 /// public string SceneAssetName { get; private set; } /// /// 获取加载持续时间。 /// public float Duration { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建加载场景成功事件。 /// /// 场景资源名称。 /// 加载持续时间。 /// 用户自定义数据。 /// 创建的加载场景成功事件。 public static LoadSceneSuccessEventArgs Create(string sceneAssetName, float duration, object userData) { LoadSceneSuccessEventArgs loadSceneSuccessEventArgs = ReferencePool.Acquire(); loadSceneSuccessEventArgs.SceneAssetName = sceneAssetName; loadSceneSuccessEventArgs.Duration = duration; loadSceneSuccessEventArgs.UserData = userData; return loadSceneSuccessEventArgs; } /// /// 清理加载场景成功事件。 /// public override void Clear() { SceneAssetName = null; Duration = 0f; UserData = null; } } } ================================================ FILE: GameFramework/Scene/LoadSceneUpdateEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Scene { /// /// 加载场景更新事件。 /// public sealed class LoadSceneUpdateEventArgs : GameFrameworkEventArgs { /// /// 初始化加载场景更新事件的新实例。 /// public LoadSceneUpdateEventArgs() { SceneAssetName = null; Progress = 0f; UserData = null; } /// /// 获取场景资源名称。 /// public string SceneAssetName { get; private set; } /// /// 获取加载场景进度。 /// public float Progress { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建加载场景更新事件。 /// /// 场景资源名称。 /// 加载场景进度。 /// 用户自定义数据。 /// 创建的加载场景更新事件。 public static LoadSceneUpdateEventArgs Create(string sceneAssetName, float progress, object userData) { LoadSceneUpdateEventArgs loadSceneUpdateEventArgs = ReferencePool.Acquire(); loadSceneUpdateEventArgs.SceneAssetName = sceneAssetName; loadSceneUpdateEventArgs.Progress = progress; loadSceneUpdateEventArgs.UserData = userData; return loadSceneUpdateEventArgs; } /// /// 清理加载场景更新事件。 /// public override void Clear() { SceneAssetName = null; Progress = 0f; UserData = null; } } } ================================================ FILE: GameFramework/Scene/SceneManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.Scene { /// /// 场景管理器。 /// internal sealed class SceneManager : GameFrameworkModule, ISceneManager { private readonly List m_LoadedSceneAssetNames; private readonly List m_LoadingSceneAssetNames; private readonly List m_UnloadingSceneAssetNames; private readonly LoadSceneCallbacks m_LoadSceneCallbacks; private readonly UnloadSceneCallbacks m_UnloadSceneCallbacks; private IResourceManager m_ResourceManager; private EventHandler m_LoadSceneSuccessEventHandler; private EventHandler m_LoadSceneFailureEventHandler; private EventHandler m_LoadSceneUpdateEventHandler; private EventHandler m_LoadSceneDependencyAssetEventHandler; private EventHandler m_UnloadSceneSuccessEventHandler; private EventHandler m_UnloadSceneFailureEventHandler; /// /// 初始化场景管理器的新实例。 /// public SceneManager() { m_LoadedSceneAssetNames = new List(); m_LoadingSceneAssetNames = new List(); m_UnloadingSceneAssetNames = new List(); m_LoadSceneCallbacks = new LoadSceneCallbacks(LoadSceneSuccessCallback, LoadSceneFailureCallback, LoadSceneUpdateCallback, LoadSceneDependencyAssetCallback); m_UnloadSceneCallbacks = new UnloadSceneCallbacks(UnloadSceneSuccessCallback, UnloadSceneFailureCallback); m_ResourceManager = null; m_LoadSceneSuccessEventHandler = null; m_LoadSceneFailureEventHandler = null; m_LoadSceneUpdateEventHandler = null; m_LoadSceneDependencyAssetEventHandler = null; m_UnloadSceneSuccessEventHandler = null; m_UnloadSceneFailureEventHandler = null; } /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal override int Priority { get { return 2; } } /// /// 加载场景成功事件。 /// public event EventHandler LoadSceneSuccess { add { m_LoadSceneSuccessEventHandler += value; } remove { m_LoadSceneSuccessEventHandler -= value; } } /// /// 加载场景失败事件。 /// public event EventHandler LoadSceneFailure { add { m_LoadSceneFailureEventHandler += value; } remove { m_LoadSceneFailureEventHandler -= value; } } /// /// 加载场景更新事件。 /// public event EventHandler LoadSceneUpdate { add { m_LoadSceneUpdateEventHandler += value; } remove { m_LoadSceneUpdateEventHandler -= value; } } /// /// 加载场景时加载依赖资源事件。 /// public event EventHandler LoadSceneDependencyAsset { add { m_LoadSceneDependencyAssetEventHandler += value; } remove { m_LoadSceneDependencyAssetEventHandler -= value; } } /// /// 卸载场景成功事件。 /// public event EventHandler UnloadSceneSuccess { add { m_UnloadSceneSuccessEventHandler += value; } remove { m_UnloadSceneSuccessEventHandler -= value; } } /// /// 卸载场景失败事件。 /// public event EventHandler UnloadSceneFailure { add { m_UnloadSceneFailureEventHandler += value; } remove { m_UnloadSceneFailureEventHandler -= value; } } /// /// 场景管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { } /// /// 关闭并清理场景管理器。 /// internal override void Shutdown() { string[] loadedSceneAssetNames = m_LoadedSceneAssetNames.ToArray(); foreach (string loadedSceneAssetName in loadedSceneAssetNames) { if (SceneIsUnloading(loadedSceneAssetName)) { continue; } UnloadScene(loadedSceneAssetName); } m_LoadedSceneAssetNames.Clear(); m_LoadingSceneAssetNames.Clear(); m_UnloadingSceneAssetNames.Clear(); } /// /// 设置资源管理器。 /// /// 资源管理器。 public void SetResourceManager(IResourceManager resourceManager) { if (resourceManager == null) { throw new GameFrameworkException("Resource manager is invalid."); } m_ResourceManager = resourceManager; } /// /// 获取场景是否已加载。 /// /// 场景资源名称。 /// 场景是否已加载。 public bool SceneIsLoaded(string sceneAssetName) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } return m_LoadedSceneAssetNames.Contains(sceneAssetName); } /// /// 获取已加载场景的资源名称。 /// /// 已加载场景的资源名称。 public string[] GetLoadedSceneAssetNames() { return m_LoadedSceneAssetNames.ToArray(); } /// /// 获取已加载场景的资源名称。 /// /// 已加载场景的资源名称。 public void GetLoadedSceneAssetNames(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); results.AddRange(m_LoadedSceneAssetNames); } /// /// 获取场景是否正在加载。 /// /// 场景资源名称。 /// 场景是否正在加载。 public bool SceneIsLoading(string sceneAssetName) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } return m_LoadingSceneAssetNames.Contains(sceneAssetName); } /// /// 获取正在加载场景的资源名称。 /// /// 正在加载场景的资源名称。 public string[] GetLoadingSceneAssetNames() { return m_LoadingSceneAssetNames.ToArray(); } /// /// 获取正在加载场景的资源名称。 /// /// 正在加载场景的资源名称。 public void GetLoadingSceneAssetNames(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); results.AddRange(m_LoadingSceneAssetNames); } /// /// 获取场景是否正在卸载。 /// /// 场景资源名称。 /// 场景是否正在卸载。 public bool SceneIsUnloading(string sceneAssetName) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } return m_UnloadingSceneAssetNames.Contains(sceneAssetName); } /// /// 获取正在卸载场景的资源名称。 /// /// 正在卸载场景的资源名称。 public string[] GetUnloadingSceneAssetNames() { return m_UnloadingSceneAssetNames.ToArray(); } /// /// 获取正在卸载场景的资源名称。 /// /// 正在卸载场景的资源名称。 public void GetUnloadingSceneAssetNames(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); results.AddRange(m_UnloadingSceneAssetNames); } /// /// 检查场景资源是否存在。 /// /// 要检查场景资源的名称。 /// 场景资源是否存在。 public bool HasScene(string sceneAssetName) { return m_ResourceManager.HasAsset(sceneAssetName) != HasAssetResult.NotExist; } /// /// 加载场景。 /// /// 场景资源名称。 public void LoadScene(string sceneAssetName) { LoadScene(sceneAssetName, Constant.DefaultPriority, null); } /// /// 加载场景。 /// /// 场景资源名称。 /// 加载场景资源的优先级。 public void LoadScene(string sceneAssetName, int priority) { LoadScene(sceneAssetName, priority, null); } /// /// 加载场景。 /// /// 场景资源名称。 /// 用户自定义数据。 public void LoadScene(string sceneAssetName, object userData) { LoadScene(sceneAssetName, Constant.DefaultPriority, userData); } /// /// 加载场景。 /// /// 场景资源名称。 /// 加载场景资源的优先级。 /// 用户自定义数据。 public void LoadScene(string sceneAssetName, int priority, object userData) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } if (m_ResourceManager == null) { throw new GameFrameworkException("You must set resource manager first."); } if (SceneIsUnloading(sceneAssetName)) { throw new GameFrameworkException(Utility.Text.Format("Scene asset '{0}' is being unloaded.", sceneAssetName)); } if (SceneIsLoading(sceneAssetName)) { throw new GameFrameworkException(Utility.Text.Format("Scene asset '{0}' is being loaded.", sceneAssetName)); } if (SceneIsLoaded(sceneAssetName)) { throw new GameFrameworkException(Utility.Text.Format("Scene asset '{0}' is already loaded.", sceneAssetName)); } m_LoadingSceneAssetNames.Add(sceneAssetName); m_ResourceManager.LoadScene(sceneAssetName, priority, m_LoadSceneCallbacks, userData); } /// /// 卸载场景。 /// /// 场景资源名称。 public void UnloadScene(string sceneAssetName) { UnloadScene(sceneAssetName, null); } /// /// 卸载场景。 /// /// 场景资源名称。 /// 用户自定义数据。 public void UnloadScene(string sceneAssetName, object userData) { if (string.IsNullOrEmpty(sceneAssetName)) { throw new GameFrameworkException("Scene asset name is invalid."); } if (m_ResourceManager == null) { throw new GameFrameworkException("You must set resource manager first."); } if (SceneIsUnloading(sceneAssetName)) { throw new GameFrameworkException(Utility.Text.Format("Scene asset '{0}' is being unloaded.", sceneAssetName)); } if (SceneIsLoading(sceneAssetName)) { throw new GameFrameworkException(Utility.Text.Format("Scene asset '{0}' is being loaded.", sceneAssetName)); } if (!SceneIsLoaded(sceneAssetName)) { throw new GameFrameworkException(Utility.Text.Format("Scene asset '{0}' is not loaded yet.", sceneAssetName)); } m_UnloadingSceneAssetNames.Add(sceneAssetName); m_ResourceManager.UnloadScene(sceneAssetName, m_UnloadSceneCallbacks, userData); } private void LoadSceneSuccessCallback(string sceneAssetName, float duration, object userData) { m_LoadingSceneAssetNames.Remove(sceneAssetName); m_LoadedSceneAssetNames.Add(sceneAssetName); if (m_LoadSceneSuccessEventHandler != null) { LoadSceneSuccessEventArgs loadSceneSuccessEventArgs = LoadSceneSuccessEventArgs.Create(sceneAssetName, duration, userData); m_LoadSceneSuccessEventHandler(this, loadSceneSuccessEventArgs); ReferencePool.Release(loadSceneSuccessEventArgs); } } private void LoadSceneFailureCallback(string sceneAssetName, LoadResourceStatus status, string errorMessage, object userData) { m_LoadingSceneAssetNames.Remove(sceneAssetName); string appendErrorMessage = Utility.Text.Format("Load scene failure, scene asset name '{0}', status '{1}', error message '{2}'.", sceneAssetName, status, errorMessage); if (m_LoadSceneFailureEventHandler != null) { LoadSceneFailureEventArgs loadSceneFailureEventArgs = LoadSceneFailureEventArgs.Create(sceneAssetName, appendErrorMessage, userData); m_LoadSceneFailureEventHandler(this, loadSceneFailureEventArgs); ReferencePool.Release(loadSceneFailureEventArgs); return; } throw new GameFrameworkException(appendErrorMessage); } private void LoadSceneUpdateCallback(string sceneAssetName, float progress, object userData) { if (m_LoadSceneUpdateEventHandler != null) { LoadSceneUpdateEventArgs loadSceneUpdateEventArgs = LoadSceneUpdateEventArgs.Create(sceneAssetName, progress, userData); m_LoadSceneUpdateEventHandler(this, loadSceneUpdateEventArgs); ReferencePool.Release(loadSceneUpdateEventArgs); } } private void LoadSceneDependencyAssetCallback(string sceneAssetName, string dependencyAssetName, int loadedCount, int totalCount, object userData) { if (m_LoadSceneDependencyAssetEventHandler != null) { LoadSceneDependencyAssetEventArgs loadSceneDependencyAssetEventArgs = LoadSceneDependencyAssetEventArgs.Create(sceneAssetName, dependencyAssetName, loadedCount, totalCount, userData); m_LoadSceneDependencyAssetEventHandler(this, loadSceneDependencyAssetEventArgs); ReferencePool.Release(loadSceneDependencyAssetEventArgs); } } private void UnloadSceneSuccessCallback(string sceneAssetName, object userData) { m_UnloadingSceneAssetNames.Remove(sceneAssetName); m_LoadedSceneAssetNames.Remove(sceneAssetName); if (m_UnloadSceneSuccessEventHandler != null) { UnloadSceneSuccessEventArgs unloadSceneSuccessEventArgs = UnloadSceneSuccessEventArgs.Create(sceneAssetName, userData); m_UnloadSceneSuccessEventHandler(this, unloadSceneSuccessEventArgs); ReferencePool.Release(unloadSceneSuccessEventArgs); } } private void UnloadSceneFailureCallback(string sceneAssetName, object userData) { m_UnloadingSceneAssetNames.Remove(sceneAssetName); if (m_UnloadSceneFailureEventHandler != null) { UnloadSceneFailureEventArgs unloadSceneFailureEventArgs = UnloadSceneFailureEventArgs.Create(sceneAssetName, userData); m_UnloadSceneFailureEventHandler(this, unloadSceneFailureEventArgs); ReferencePool.Release(unloadSceneFailureEventArgs); return; } throw new GameFrameworkException(Utility.Text.Format("Unload scene failure, scene asset name '{0}'.", sceneAssetName)); } } } ================================================ FILE: GameFramework/Scene/UnloadSceneFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Scene { /// /// 卸载场景失败事件。 /// public sealed class UnloadSceneFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化卸载场景失败事件的新实例。 /// public UnloadSceneFailureEventArgs() { SceneAssetName = null; UserData = null; } /// /// 获取场景资源名称。 /// public string SceneAssetName { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建卸载场景失败事件。 /// /// 场景资源名称。 /// 用户自定义数据。 /// 创建的卸载场景失败事件。 public static UnloadSceneFailureEventArgs Create(string sceneAssetName, object userData) { UnloadSceneFailureEventArgs unloadSceneFailureEventArgs = ReferencePool.Acquire(); unloadSceneFailureEventArgs.SceneAssetName = sceneAssetName; unloadSceneFailureEventArgs.UserData = userData; return unloadSceneFailureEventArgs; } /// /// 清理卸载场景失败事件。 /// public override void Clear() { SceneAssetName = null; UserData = null; } } } ================================================ FILE: GameFramework/Scene/UnloadSceneSuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Scene { /// /// 卸载场景成功事件。 /// public sealed class UnloadSceneSuccessEventArgs : GameFrameworkEventArgs { /// /// 初始化卸载场景成功事件的新实例。 /// public UnloadSceneSuccessEventArgs() { SceneAssetName = null; UserData = null; } /// /// 获取场景资源名称。 /// public string SceneAssetName { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建卸载场景成功事件。 /// /// 场景资源名称。 /// 用户自定义数据。 /// 创建的卸载场景成功事件。 public static UnloadSceneSuccessEventArgs Create(string sceneAssetName, object userData) { UnloadSceneSuccessEventArgs unloadSceneSuccessEventArgs = ReferencePool.Acquire(); unloadSceneSuccessEventArgs.SceneAssetName = sceneAssetName; unloadSceneSuccessEventArgs.UserData = userData; return unloadSceneSuccessEventArgs; } /// /// 清理卸载场景成功事件。 /// public override void Clear() { SceneAssetName = null; UserData = null; } } } ================================================ FILE: GameFramework/Setting/ISettingHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Setting { /// /// 游戏配置辅助器接口。 /// public interface ISettingHelper { /// /// 获取游戏配置项数量。 /// int Count { get; } /// /// 加载游戏配置。 /// /// 是否加载游戏配置成功。 bool Load(); /// /// 保存游戏配置。 /// /// 是否保存游戏配置成功。 bool Save(); /// /// 获取所有游戏配置项的名称。 /// /// 所有游戏配置项的名称。 string[] GetAllSettingNames(); /// /// 获取所有游戏配置项的名称。 /// /// 所有游戏配置项的名称。 void GetAllSettingNames(List results); /// /// 检查是否存在指定游戏配置项。 /// /// 要检查游戏配置项的名称。 /// 指定的游戏配置项是否存在。 bool HasSetting(string settingName); /// /// 移除指定游戏配置项。 /// /// 要移除游戏配置项的名称。 /// 是否移除指定游戏配置项成功。 bool RemoveSetting(string settingName); /// /// 清空所有游戏配置项。 /// void RemoveAllSettings(); /// /// 从指定游戏配置项中读取布尔值。 /// /// 要获取游戏配置项的名称。 /// 读取的布尔值。 bool GetBool(string settingName); /// /// 从指定游戏配置项中读取布尔值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的布尔值。 bool GetBool(string settingName, bool defaultValue); /// /// 向指定游戏配置项写入布尔值。 /// /// 要写入游戏配置项的名称。 /// 要写入的布尔值。 void SetBool(string settingName, bool value); /// /// 从指定游戏配置项中读取整数值。 /// /// 要获取游戏配置项的名称。 /// 读取的整数值。 int GetInt(string settingName); /// /// 从指定游戏配置项中读取整数值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的整数值。 int GetInt(string settingName, int defaultValue); /// /// 向指定游戏配置项写入整数值。 /// /// 要写入游戏配置项的名称。 /// 要写入的整数值。 void SetInt(string settingName, int value); /// /// 从指定游戏配置项中读取浮点数值。 /// /// 要获取游戏配置项的名称。 /// 读取的浮点数值。 float GetFloat(string settingName); /// /// 从指定游戏配置项中读取浮点数值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的浮点数值。 float GetFloat(string settingName, float defaultValue); /// /// 向指定游戏配置项写入浮点数值。 /// /// 要写入游戏配置项的名称。 /// 要写入的浮点数值。 void SetFloat(string settingName, float value); /// /// 从指定游戏配置项中读取字符串值。 /// /// 要获取游戏配置项的名称。 /// 读取的字符串值。 string GetString(string settingName); /// /// 从指定游戏配置项中读取字符串值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的字符串值。 string GetString(string settingName, string defaultValue); /// /// 向指定游戏配置项写入字符串值。 /// /// 要写入游戏配置项的名称。 /// 要写入的字符串值。 void SetString(string settingName, string value); /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 读取的对象。 T GetObject(string settingName); /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 读取的对象。 object GetObject(Type objectType, string settingName); /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认对象。 /// 读取的对象。 T GetObject(string settingName, T defaultObj); /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认对象。 /// 读取的对象。 object GetObject(Type objectType, string settingName, object defaultObj); /// /// 向指定游戏配置项写入对象。 /// /// 要写入对象的类型。 /// 要写入游戏配置项的名称。 /// 要写入的对象。 void SetObject(string settingName, T obj); /// /// 向指定游戏配置项写入对象。 /// /// 要写入游戏配置项的名称。 /// 要写入的对象。 void SetObject(string settingName, object obj); } } ================================================ FILE: GameFramework/Setting/ISettingManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Setting { /// /// 游戏配置管理器接口。 /// public interface ISettingManager { /// /// 获取游戏配置项数量。 /// int Count { get; } /// /// 设置游戏配置辅助器。 /// /// 游戏配置辅助器。 void SetSettingHelper(ISettingHelper settingHelper); /// /// 加载游戏配置。 /// /// 是否加载游戏配置成功。 bool Load(); /// /// 保存游戏配置。 /// /// 是否保存游戏配置成功。 bool Save(); /// /// 获取所有游戏配置项的名称。 /// /// 所有游戏配置项的名称。 string[] GetAllSettingNames(); /// /// 获取所有游戏配置项的名称。 /// /// 所有游戏配置项的名称。 void GetAllSettingNames(List results); /// /// 检查是否存在指定游戏配置项。 /// /// 要检查游戏配置项的名称。 /// 指定的游戏配置项是否存在。 bool HasSetting(string settingName); /// /// 移除指定游戏配置项。 /// /// 要移除游戏配置项的名称。 /// 是否移除指定游戏配置项成功。 bool RemoveSetting(string settingName); /// /// 清空所有游戏配置项。 /// void RemoveAllSettings(); /// /// 从指定游戏配置项中读取布尔值。 /// /// 要获取游戏配置项的名称。 /// 读取的布尔值。 bool GetBool(string settingName); /// /// 从指定游戏配置项中读取布尔值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的布尔值。 bool GetBool(string settingName, bool defaultValue); /// /// 向指定游戏配置项写入布尔值。 /// /// 要写入游戏配置项的名称。 /// 要写入的布尔值。 void SetBool(string settingName, bool value); /// /// 从指定游戏配置项中读取整数值。 /// /// 要获取游戏配置项的名称。 /// 读取的整数值。 int GetInt(string settingName); /// /// 从指定游戏配置项中读取整数值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的整数值。 int GetInt(string settingName, int defaultValue); /// /// 向指定游戏配置项写入整数值。 /// /// 要写入游戏配置项的名称。 /// 要写入的整数值。 void SetInt(string settingName, int value); /// /// 从指定游戏配置项中读取浮点数值。 /// /// 要获取游戏配置项的名称。 /// 读取的浮点数值。 float GetFloat(string settingName); /// /// 从指定游戏配置项中读取浮点数值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的浮点数值。 float GetFloat(string settingName, float defaultValue); /// /// 向指定游戏配置项写入浮点数值。 /// /// 要写入游戏配置项的名称。 /// 要写入的浮点数值。 void SetFloat(string settingName, float value); /// /// 从指定游戏配置项中读取字符串值。 /// /// 要获取游戏配置项的名称。 /// 读取的字符串值。 string GetString(string settingName); /// /// 从指定游戏配置项中读取字符串值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的字符串值。 string GetString(string settingName, string defaultValue); /// /// 向指定游戏配置项写入字符串值。 /// /// 要写入游戏配置项的名称。 /// 要写入的字符串值。 void SetString(string settingName, string value); /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 读取的对象。 T GetObject(string settingName); /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 读取的对象。 object GetObject(Type objectType, string settingName); /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认对象。 /// 读取的对象。 T GetObject(string settingName, T defaultObj); /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认对象。 /// 读取的对象。 object GetObject(Type objectType, string settingName, object defaultObj); /// /// 向指定游戏配置项写入对象。 /// /// 要写入对象的类型。 /// 要写入游戏配置项的名称。 /// 要写入的对象。 void SetObject(string settingName, T obj); /// /// 向指定游戏配置项写入对象。 /// /// 要写入游戏配置项的名称。 /// 要写入的对象。 void SetObject(string settingName, object obj); } } ================================================ FILE: GameFramework/Setting/SettingManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.Setting { /// /// 游戏配置管理器。 /// internal sealed class SettingManager : GameFrameworkModule, ISettingManager { private ISettingHelper m_SettingHelper; /// /// 初始化游戏配置管理器的新实例。 /// public SettingManager() { m_SettingHelper = null; } /// /// 获取游戏配置项数量。 /// public int Count { get { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } return m_SettingHelper.Count; } } /// /// 游戏配置管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { } /// /// 关闭并清理游戏配置管理器。 /// internal override void Shutdown() { Save(); } /// /// 设置游戏配置辅助器。 /// /// 游戏配置辅助器。 public void SetSettingHelper(ISettingHelper settingHelper) { if (settingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } m_SettingHelper = settingHelper; } /// /// 加载游戏配置。 /// /// 是否加载游戏配置成功。 public bool Load() { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } return m_SettingHelper.Load(); } /// /// 保存游戏配置。 /// /// 是否保存游戏配置成功。 public bool Save() { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } return m_SettingHelper.Save(); } /// /// 获取所有游戏配置项的名称。 /// /// 所有游戏配置项的名称。 public string[] GetAllSettingNames() { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } return m_SettingHelper.GetAllSettingNames(); } /// /// 获取所有游戏配置项的名称。 /// /// 所有游戏配置项的名称。 public void GetAllSettingNames(List results) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } m_SettingHelper.GetAllSettingNames(results); } /// /// 检查是否存在指定游戏配置项。 /// /// 要检查游戏配置项的名称。 /// 指定的游戏配置项是否存在。 public bool HasSetting(string settingName) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.HasSetting(settingName); } /// /// 移除指定游戏配置项。 /// /// 要移除游戏配置项的名称。 /// 是否移除指定游戏配置项成功。 public bool RemoveSetting(string settingName) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.RemoveSetting(settingName); } /// /// 清空所有游戏配置项。 /// public void RemoveAllSettings() { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } m_SettingHelper.RemoveAllSettings(); } /// /// 从指定游戏配置项中读取布尔值。 /// /// 要获取游戏配置项的名称。 /// 读取的布尔值。 public bool GetBool(string settingName) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetBool(settingName); } /// /// 从指定游戏配置项中读取布尔值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的布尔值。 public bool GetBool(string settingName, bool defaultValue) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetBool(settingName, defaultValue); } /// /// 向指定游戏配置项写入布尔值。 /// /// 要写入游戏配置项的名称。 /// 要写入的布尔值。 public void SetBool(string settingName, bool value) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } m_SettingHelper.SetBool(settingName, value); } /// /// 从指定游戏配置项中读取整数值。 /// /// 要获取游戏配置项的名称。 /// 读取的整数值。 public int GetInt(string settingName) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetInt(settingName); } /// /// 从指定游戏配置项中读取整数值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的整数值。 public int GetInt(string settingName, int defaultValue) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetInt(settingName, defaultValue); } /// /// 向指定游戏配置项写入整数值。 /// /// 要写入游戏配置项的名称。 /// 要写入的整数值。 public void SetInt(string settingName, int value) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } m_SettingHelper.SetInt(settingName, value); } /// /// 从指定游戏配置项中读取浮点数值。 /// /// 要获取游戏配置项的名称。 /// 读取的浮点数值。 public float GetFloat(string settingName) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetFloat(settingName); } /// /// 从指定游戏配置项中读取浮点数值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的浮点数值。 public float GetFloat(string settingName, float defaultValue) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetFloat(settingName, defaultValue); } /// /// 向指定游戏配置项写入浮点数值。 /// /// 要写入游戏配置项的名称。 /// 要写入的浮点数值。 public void SetFloat(string settingName, float value) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } m_SettingHelper.SetFloat(settingName, value); } /// /// 从指定游戏配置项中读取字符串值。 /// /// 要获取游戏配置项的名称。 /// 读取的字符串值。 public string GetString(string settingName) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetString(settingName); } /// /// 从指定游戏配置项中读取字符串值。 /// /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认值。 /// 读取的字符串值。 public string GetString(string settingName, string defaultValue) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetString(settingName, defaultValue); } /// /// 向指定游戏配置项写入字符串值。 /// /// 要写入游戏配置项的名称。 /// 要写入的字符串值。 public void SetString(string settingName, string value) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } m_SettingHelper.SetString(settingName, value); } /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 读取的对象。 public T GetObject(string settingName) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetObject(settingName); } /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 读取的对象。 public object GetObject(Type objectType, string settingName) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (objectType == null) { throw new GameFrameworkException("Object type is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetObject(objectType, settingName); } /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认对象。 /// 读取的对象。 public T GetObject(string settingName, T defaultObj) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetObject(settingName, defaultObj); } /// /// 从指定游戏配置项中读取对象。 /// /// 要读取对象的类型。 /// 要获取游戏配置项的名称。 /// 当指定的游戏配置项不存在时,返回此默认对象。 /// 读取的对象。 public object GetObject(Type objectType, string settingName, object defaultObj) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (objectType == null) { throw new GameFrameworkException("Object type is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } return m_SettingHelper.GetObject(objectType, settingName, defaultObj); } /// /// 向指定游戏配置项写入对象。 /// /// 要写入对象的类型。 /// 要写入游戏配置项的名称。 /// 要写入的对象。 public void SetObject(string settingName, T obj) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } m_SettingHelper.SetObject(settingName, obj); } /// /// 向指定游戏配置项写入对象。 /// /// 要写入游戏配置项的名称。 /// 要写入的对象。 public void SetObject(string settingName, object obj) { if (m_SettingHelper == null) { throw new GameFrameworkException("Setting helper is invalid."); } if (string.IsNullOrEmpty(settingName)) { throw new GameFrameworkException("Setting name is invalid."); } m_SettingHelper.SetObject(settingName, obj); } } } ================================================ FILE: GameFramework/Sound/Constant.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 声音相关常量。 /// internal static class Constant { internal const float DefaultTime = 0f; internal const bool DefaultMute = false; internal const bool DefaultLoop = false; internal const int DefaultPriority = 0; internal const float DefaultVolume = 1f; internal const float DefaultFadeInSeconds = 0f; internal const float DefaultFadeOutSeconds = 0f; internal const float DefaultPitch = 1f; internal const float DefaultPanStereo = 0f; internal const float DefaultSpatialBlend = 0f; internal const float DefaultMaxDistance = 100f; internal const float DefaultDopplerLevel = 1f; } } ================================================ FILE: GameFramework/Sound/ISoundAgent.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 声音代理接口。 /// public interface ISoundAgent { /// /// 获取所在的声音组。 /// ISoundGroup SoundGroup { get; } /// /// 获取声音的序列编号。 /// int SerialId { get; } /// /// 获取当前是否正在播放。 /// bool IsPlaying { get; } /// /// 获取声音长度。 /// float Length { get; } /// /// 获取或设置播放位置。 /// float Time { get; set; } /// /// 获取或设置是否静音。 /// bool Mute { get; } /// /// 获取或设置在声音组内是否静音。 /// bool MuteInSoundGroup { get; set; } /// /// 获取或设置是否循环播放。 /// bool Loop { get; set; } /// /// 获取或设置声音优先级。 /// int Priority { get; set; } /// /// 获取音量大小。 /// float Volume { get; } /// /// 获取或设置在声音组内音量大小。 /// float VolumeInSoundGroup { get; set; } /// /// 获取或设置声音音调。 /// float Pitch { get; set; } /// /// 获取或设置声音立体声声相。 /// float PanStereo { get; set; } /// /// 获取或设置声音空间混合量。 /// float SpatialBlend { get; set; } /// /// 获取或设置声音最大距离。 /// float MaxDistance { get; set; } /// /// 获取或设置声音多普勒等级。 /// float DopplerLevel { get; set; } /// /// 获取声音代理辅助器。 /// ISoundAgentHelper Helper { get; } /// /// 播放声音。 /// void Play(); /// /// 播放声音。 /// /// 声音淡入时间,以秒为单位。 void Play(float fadeInSeconds); /// /// 停止播放声音。 /// void Stop(); /// /// 停止播放声音。 /// /// 声音淡出时间,以秒为单位。 void Stop(float fadeOutSeconds); /// /// 暂停播放声音。 /// void Pause(); /// /// 暂停播放声音。 /// /// 声音淡出时间,以秒为单位。 void Pause(float fadeOutSeconds); /// /// 恢复播放声音。 /// void Resume(); /// /// 恢复播放声音。 /// /// 声音淡入时间,以秒为单位。 void Resume(float fadeInSeconds); /// /// 重置声音代理。 /// void Reset(); } } ================================================ FILE: GameFramework/Sound/ISoundAgentHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.Sound { /// /// 声音代理辅助器接口。 /// public interface ISoundAgentHelper { /// /// 获取当前是否正在播放。 /// bool IsPlaying { get; } /// /// 获取声音长度。 /// float Length { get; } /// /// 获取或设置播放位置。 /// float Time { get; set; } /// /// 获取或设置是否静音。 /// bool Mute { get; set; } /// /// 获取或设置是否循环播放。 /// bool Loop { get; set; } /// /// 获取或设置声音优先级。 /// int Priority { get; set; } /// /// 获取或设置音量大小。 /// float Volume { get; set; } /// /// 获取或设置声音音调。 /// float Pitch { get; set; } /// /// 获取或设置声音立体声声相。 /// float PanStereo { get; set; } /// /// 获取或设置声音空间混合量。 /// float SpatialBlend { get; set; } /// /// 获取或设置声音最大距离。 /// float MaxDistance { get; set; } /// /// 获取或设置声音多普勒等级。 /// float DopplerLevel { get; set; } /// /// 重置声音代理事件。 /// event EventHandler ResetSoundAgent; /// /// 播放声音。 /// /// 声音淡入时间,以秒为单位。 void Play(float fadeInSeconds); /// /// 停止播放声音。 /// /// 声音淡出时间,以秒为单位。 void Stop(float fadeOutSeconds); /// /// 暂停播放声音。 /// /// 声音淡出时间,以秒为单位。 void Pause(float fadeOutSeconds); /// /// 恢复播放声音。 /// /// 声音淡入时间,以秒为单位。 void Resume(float fadeInSeconds); /// /// 重置声音代理辅助器。 /// void Reset(); /// /// 设置声音资源。 /// /// 声音资源。 /// 是否设置声音资源成功。 bool SetSoundAsset(object soundAsset); } } ================================================ FILE: GameFramework/Sound/ISoundGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 声音组接口。 /// public interface ISoundGroup { /// /// 获取声音组名称。 /// string Name { get; } /// /// 获取声音代理数。 /// int SoundAgentCount { get; } /// /// 获取或设置声音组中的声音是否避免被同优先级声音替换。 /// bool AvoidBeingReplacedBySamePriority { get; set; } /// /// 获取或设置声音组静音。 /// bool Mute { get; set; } /// /// 获取或设置声音组音量。 /// float Volume { get; set; } /// /// 获取声音组辅助器。 /// ISoundGroupHelper Helper { get; } /// /// 停止所有已加载的声音。 /// void StopAllLoadedSounds(); /// /// 停止所有已加载的声音。 /// /// 声音淡出时间,以秒为单位。 void StopAllLoadedSounds(float fadeOutSeconds); } } ================================================ FILE: GameFramework/Sound/ISoundGroupHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 声音组辅助器接口。 /// public interface ISoundGroupHelper { } } ================================================ FILE: GameFramework/Sound/ISoundHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 声音辅助器接口。 /// public interface ISoundHelper { /// /// 释放声音资源。 /// /// 要释放的声音资源。 void ReleaseSoundAsset(object soundAsset); } } ================================================ FILE: GameFramework/Sound/ISoundManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.Sound { /// /// 声音管理器接口。 /// public interface ISoundManager { /// /// 获取声音组数量。 /// int SoundGroupCount { get; } /// /// 播放声音成功事件。 /// event EventHandler PlaySoundSuccess; /// /// 播放声音失败事件。 /// event EventHandler PlaySoundFailure; /// /// 播放声音更新事件。 /// event EventHandler PlaySoundUpdate; /// /// 播放声音时加载依赖资源事件。 /// event EventHandler PlaySoundDependencyAsset; /// /// 设置资源管理器。 /// /// 资源管理器。 void SetResourceManager(IResourceManager resourceManager); /// /// 设置声音辅助器。 /// /// 声音辅助器。 void SetSoundHelper(ISoundHelper soundHelper); /// /// 是否存在指定声音组。 /// /// 声音组名称。 /// 指定声音组是否存在。 bool HasSoundGroup(string soundGroupName); /// /// 获取指定声音组。 /// /// 声音组名称。 /// 要获取的声音组。 ISoundGroup GetSoundGroup(string soundGroupName); /// /// 获取所有声音组。 /// /// 所有声音组。 ISoundGroup[] GetAllSoundGroups(); /// /// 获取所有声音组。 /// /// 所有声音组。 void GetAllSoundGroups(List results); /// /// 增加声音组。 /// /// 声音组名称。 /// 声音组辅助器。 /// 是否增加声音组成功。 bool AddSoundGroup(string soundGroupName, ISoundGroupHelper soundGroupHelper); /// /// 增加声音组。 /// /// 声音组名称。 /// 声音组中的声音是否避免被同优先级声音替换。 /// 声音组是否静音。 /// 声音组音量。 /// 声音组辅助器。 /// 是否增加声音组成功。 bool AddSoundGroup(string soundGroupName, bool soundGroupAvoidBeingReplacedBySamePriority, bool soundGroupMute, float soundGroupVolume, ISoundGroupHelper soundGroupHelper); /// /// 增加声音代理辅助器。 /// /// 声音组名称。 /// 要增加的声音代理辅助器。 void AddSoundAgentHelper(string soundGroupName, ISoundAgentHelper soundAgentHelper); /// /// 获取所有正在加载声音的序列编号。 /// /// 所有正在加载声音的序列编号。 int[] GetAllLoadingSoundSerialIds(); /// /// 获取所有正在加载声音的序列编号。 /// /// 所有正在加载声音的序列编号。 void GetAllLoadingSoundSerialIds(List results); /// /// 是否正在加载声音。 /// /// 声音序列编号。 /// 是否正在加载声音。 bool IsLoadingSound(int serialId); /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 声音的序列编号。 int PlaySound(string soundAssetName, string soundGroupName); /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 加载声音资源的优先级。 /// 声音的序列编号。 int PlaySound(string soundAssetName, string soundGroupName, int priority); /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 播放声音参数。 /// 声音的序列编号。 int PlaySound(string soundAssetName, string soundGroupName, PlaySoundParams playSoundParams); /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 用户自定义数据。 /// 声音的序列编号。 int PlaySound(string soundAssetName, string soundGroupName, object userData); /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 加载声音资源的优先级。 /// 播放声音参数。 /// 声音的序列编号。 int PlaySound(string soundAssetName, string soundGroupName, int priority, PlaySoundParams playSoundParams); /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 加载声音资源的优先级。 /// 用户自定义数据。 /// 声音的序列编号。 int PlaySound(string soundAssetName, string soundGroupName, int priority, object userData); /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 播放声音参数。 /// 用户自定义数据。 /// 声音的序列编号。 int PlaySound(string soundAssetName, string soundGroupName, PlaySoundParams playSoundParams, object userData); /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 加载声音资源的优先级。 /// 播放声音参数。 /// 用户自定义数据。 /// 声音的序列编号。 int PlaySound(string soundAssetName, string soundGroupName, int priority, PlaySoundParams playSoundParams, object userData); /// /// 停止播放声音。 /// /// 要停止播放声音的序列编号。 /// 是否停止播放声音成功。 bool StopSound(int serialId); /// /// 停止播放声音。 /// /// 要停止播放声音的序列编号。 /// 声音淡出时间,以秒为单位。 /// 是否停止播放声音成功。 bool StopSound(int serialId, float fadeOutSeconds); /// /// 停止所有已加载的声音。 /// void StopAllLoadedSounds(); /// /// 停止所有已加载的声音。 /// /// 声音淡出时间,以秒为单位。 void StopAllLoadedSounds(float fadeOutSeconds); /// /// 停止所有正在加载的声音。 /// void StopAllLoadingSounds(); /// /// 暂停播放声音。 /// /// 要暂停播放声音的序列编号。 void PauseSound(int serialId); /// /// 暂停播放声音。 /// /// 要暂停播放声音的序列编号。 /// 声音淡出时间,以秒为单位。 void PauseSound(int serialId, float fadeOutSeconds); /// /// 恢复播放声音。 /// /// 要恢复播放声音的序列编号。 void ResumeSound(int serialId); /// /// 恢复播放声音。 /// /// 要恢复播放声音的序列编号。 /// 声音淡入时间,以秒为单位。 void ResumeSound(int serialId, float fadeInSeconds); } } ================================================ FILE: GameFramework/Sound/PlaySoundDependencyAssetEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 播放声音时加载依赖资源事件。 /// public sealed class PlaySoundDependencyAssetEventArgs : GameFrameworkEventArgs { /// /// 初始化播放声音时加载依赖资源事件的新实例。 /// public PlaySoundDependencyAssetEventArgs() { SerialId = 0; SoundAssetName = null; SoundGroupName = null; PlaySoundParams = null; DependencyAssetName = null; LoadedCount = 0; TotalCount = 0; UserData = null; } /// /// 获取声音的序列编号。 /// public int SerialId { get; private set; } /// /// 获取声音资源名称。 /// public string SoundAssetName { get; private set; } /// /// 获取声音组名称。 /// public string SoundGroupName { get; private set; } /// /// 获取播放声音参数。 /// public PlaySoundParams PlaySoundParams { get; private set; } /// /// 获取被加载的依赖资源名称。 /// public string DependencyAssetName { get; private set; } /// /// 获取当前已加载依赖资源数量。 /// public int LoadedCount { get; private set; } /// /// 获取总共加载依赖资源数量。 /// public int TotalCount { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建播放声音时加载依赖资源事件。 /// /// 声音的序列编号。 /// 声音资源名称。 /// 声音组名称。 /// 播放声音参数。 /// 被加载的依赖资源名称。 /// 当前已加载依赖资源数量。 /// 总共加载依赖资源数量。 /// 用户自定义数据。 /// 创建的播放声音时加载依赖资源事件。 public static PlaySoundDependencyAssetEventArgs Create(int serialId, string soundAssetName, string soundGroupName, PlaySoundParams playSoundParams, string dependencyAssetName, int loadedCount, int totalCount, object userData) { PlaySoundDependencyAssetEventArgs playSoundDependencyAssetEventArgs = ReferencePool.Acquire(); playSoundDependencyAssetEventArgs.SerialId = serialId; playSoundDependencyAssetEventArgs.SoundAssetName = soundAssetName; playSoundDependencyAssetEventArgs.SoundGroupName = soundGroupName; playSoundDependencyAssetEventArgs.PlaySoundParams = playSoundParams; playSoundDependencyAssetEventArgs.DependencyAssetName = dependencyAssetName; playSoundDependencyAssetEventArgs.LoadedCount = loadedCount; playSoundDependencyAssetEventArgs.TotalCount = totalCount; playSoundDependencyAssetEventArgs.UserData = userData; return playSoundDependencyAssetEventArgs; } /// /// 清理播放声音时加载依赖资源事件。 /// public override void Clear() { SerialId = 0; SoundAssetName = null; SoundGroupName = null; PlaySoundParams = null; DependencyAssetName = null; LoadedCount = 0; TotalCount = 0; UserData = null; } } } ================================================ FILE: GameFramework/Sound/PlaySoundErrorCode.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 播放声音错误码。 /// public enum PlaySoundErrorCode : byte { /// /// 未知错误。 /// Unknown = 0, /// /// 声音组不存在。 /// SoundGroupNotExist, /// /// 声音组没有声音代理。 /// SoundGroupHasNoAgent, /// /// 加载资源失败。 /// LoadAssetFailure, /// /// 播放声音因优先级低被忽略。 /// IgnoredDueToLowPriority, /// /// 设置声音资源失败。 /// SetSoundAssetFailure } } ================================================ FILE: GameFramework/Sound/PlaySoundFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 播放声音失败事件。 /// public sealed class PlaySoundFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化播放声音失败事件的新实例。 /// public PlaySoundFailureEventArgs() { SerialId = 0; SoundAssetName = null; SoundGroupName = null; PlaySoundParams = null; ErrorCode = PlaySoundErrorCode.Unknown; ErrorMessage = null; UserData = null; } /// /// 获取声音的序列编号。 /// public int SerialId { get; private set; } /// /// 获取声音资源名称。 /// public string SoundAssetName { get; private set; } /// /// 获取声音组名称。 /// public string SoundGroupName { get; private set; } /// /// 获取播放声音参数。 /// public PlaySoundParams PlaySoundParams { get; private set; } /// /// 获取错误码。 /// public PlaySoundErrorCode ErrorCode { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建播放声音失败事件。 /// /// 声音的序列编号。 /// 声音资源名称。 /// 声音组名称。 /// 播放声音参数。 /// 错误码。 /// 错误信息。 /// 用户自定义数据。 /// 创建的播放声音失败事件。 public static PlaySoundFailureEventArgs Create(int serialId, string soundAssetName, string soundGroupName, PlaySoundParams playSoundParams, PlaySoundErrorCode errorCode, string errorMessage, object userData) { PlaySoundFailureEventArgs playSoundFailureEventArgs = ReferencePool.Acquire(); playSoundFailureEventArgs.SerialId = serialId; playSoundFailureEventArgs.SoundAssetName = soundAssetName; playSoundFailureEventArgs.SoundGroupName = soundGroupName; playSoundFailureEventArgs.PlaySoundParams = playSoundParams; playSoundFailureEventArgs.ErrorCode = errorCode; playSoundFailureEventArgs.ErrorMessage = errorMessage; playSoundFailureEventArgs.UserData = userData; return playSoundFailureEventArgs; } /// /// 清理播放声音失败事件。 /// public override void Clear() { SerialId = 0; SoundAssetName = null; SoundGroupName = null; PlaySoundParams = null; ErrorCode = PlaySoundErrorCode.Unknown; ErrorMessage = null; UserData = null; } } } ================================================ FILE: GameFramework/Sound/PlaySoundParams.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 播放声音参数。 /// public sealed class PlaySoundParams : IReference { private bool m_Referenced; private float m_Time; private bool m_MuteInSoundGroup; private bool m_Loop; private int m_Priority; private float m_VolumeInSoundGroup; private float m_FadeInSeconds; private float m_Pitch; private float m_PanStereo; private float m_SpatialBlend; private float m_MaxDistance; private float m_DopplerLevel; /// /// 初始化播放声音参数的新实例。 /// public PlaySoundParams() { m_Referenced = false; m_Time = Constant.DefaultTime; m_MuteInSoundGroup = Constant.DefaultMute; m_Loop = Constant.DefaultLoop; m_Priority = Constant.DefaultPriority; m_VolumeInSoundGroup = Constant.DefaultVolume; m_FadeInSeconds = Constant.DefaultFadeInSeconds; m_Pitch = Constant.DefaultPitch; m_PanStereo = Constant.DefaultPanStereo; m_SpatialBlend = Constant.DefaultSpatialBlend; m_MaxDistance = Constant.DefaultMaxDistance; m_DopplerLevel = Constant.DefaultDopplerLevel; } /// /// 获取或设置播放位置。 /// public float Time { get { return m_Time; } set { m_Time = value; } } /// /// 获取或设置在声音组内是否静音。 /// public bool MuteInSoundGroup { get { return m_MuteInSoundGroup; } set { m_MuteInSoundGroup = value; } } /// /// 获取或设置是否循环播放。 /// public bool Loop { get { return m_Loop; } set { m_Loop = value; } } /// /// 获取或设置声音优先级。 /// public int Priority { get { return m_Priority; } set { m_Priority = value; } } /// /// 获取或设置在声音组内音量大小。 /// public float VolumeInSoundGroup { get { return m_VolumeInSoundGroup; } set { m_VolumeInSoundGroup = value; } } /// /// 获取或设置声音淡入时间,以秒为单位。 /// public float FadeInSeconds { get { return m_FadeInSeconds; } set { m_FadeInSeconds = value; } } /// /// 获取或设置声音音调。 /// public float Pitch { get { return m_Pitch; } set { m_Pitch = value; } } /// /// 获取或设置声音立体声声相。 /// public float PanStereo { get { return m_PanStereo; } set { m_PanStereo = value; } } /// /// 获取或设置声音空间混合量。 /// public float SpatialBlend { get { return m_SpatialBlend; } set { m_SpatialBlend = value; } } /// /// 获取或设置声音最大距离。 /// public float MaxDistance { get { return m_MaxDistance; } set { m_MaxDistance = value; } } /// /// 获取或设置声音多普勒等级。 /// public float DopplerLevel { get { return m_DopplerLevel; } set { m_DopplerLevel = value; } } internal bool Referenced { get { return m_Referenced; } } /// /// 创建播放声音参数。 /// /// 创建的播放声音参数。 public static PlaySoundParams Create() { PlaySoundParams playSoundParams = ReferencePool.Acquire(); playSoundParams.m_Referenced = true; return playSoundParams; } /// /// 清理播放声音参数。 /// public void Clear() { m_Time = Constant.DefaultTime; m_MuteInSoundGroup = Constant.DefaultMute; m_Loop = Constant.DefaultLoop; m_Priority = Constant.DefaultPriority; m_VolumeInSoundGroup = Constant.DefaultVolume; m_FadeInSeconds = Constant.DefaultFadeInSeconds; m_Pitch = Constant.DefaultPitch; m_PanStereo = Constant.DefaultPanStereo; m_SpatialBlend = Constant.DefaultSpatialBlend; m_MaxDistance = Constant.DefaultMaxDistance; m_DopplerLevel = Constant.DefaultDopplerLevel; } } } ================================================ FILE: GameFramework/Sound/PlaySoundSuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 播放声音成功事件。 /// public sealed class PlaySoundSuccessEventArgs : GameFrameworkEventArgs { /// /// 初始化播放声音成功事件的新实例。 /// public PlaySoundSuccessEventArgs() { SerialId = 0; SoundAssetName = null; SoundAgent = null; Duration = 0f; UserData = null; } /// /// 获取声音的序列编号。 /// public int SerialId { get; private set; } /// /// 获取声音资源名称。 /// public string SoundAssetName { get; private set; } /// /// 获取用于播放的声音代理。 /// public ISoundAgent SoundAgent { get; private set; } /// /// 获取加载持续时间。 /// public float Duration { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建播放声音成功事件。 /// /// 声音的序列编号。 /// 声音资源名称。 /// 用于播放的声音代理。 /// 加载持续时间。 /// 用户自定义数据。 /// 创建的播放声音成功事件。 public static PlaySoundSuccessEventArgs Create(int serialId, string soundAssetName, ISoundAgent soundAgent, float duration, object userData) { PlaySoundSuccessEventArgs playSoundSuccessEventArgs = ReferencePool.Acquire(); playSoundSuccessEventArgs.SerialId = serialId; playSoundSuccessEventArgs.SoundAssetName = soundAssetName; playSoundSuccessEventArgs.SoundAgent = soundAgent; playSoundSuccessEventArgs.Duration = duration; playSoundSuccessEventArgs.UserData = userData; return playSoundSuccessEventArgs; } /// /// 清理播放声音成功事件。 /// public override void Clear() { SerialId = 0; SoundAssetName = null; SoundAgent = null; Duration = 0f; UserData = null; } } } ================================================ FILE: GameFramework/Sound/PlaySoundUpdateEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 播放声音更新事件。 /// public sealed class PlaySoundUpdateEventArgs : GameFrameworkEventArgs { /// /// 初始化播放声音更新事件的新实例。 /// public PlaySoundUpdateEventArgs() { SerialId = 0; SoundAssetName = null; SoundGroupName = null; PlaySoundParams = null; Progress = 0f; UserData = null; } /// /// 获取声音的序列编号。 /// public int SerialId { get; private set; } /// /// 获取声音资源名称。 /// public string SoundAssetName { get; private set; } /// /// 获取声音组名称。 /// public string SoundGroupName { get; private set; } /// /// 获取播放声音参数。 /// public PlaySoundParams PlaySoundParams { get; private set; } /// /// 获取加载声音进度。 /// public float Progress { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建播放声音更新事件。 /// /// 声音的序列编号。 /// 声音资源名称。 /// 声音组名称。 /// 播放声音参数。 /// 加载声音进度。 /// 用户自定义数据。 /// 创建的播放声音更新事件。 public static PlaySoundUpdateEventArgs Create(int serialId, string soundAssetName, string soundGroupName, PlaySoundParams playSoundParams, float progress, object userData) { PlaySoundUpdateEventArgs playSoundUpdateEventArgs = ReferencePool.Acquire(); playSoundUpdateEventArgs.SerialId = serialId; playSoundUpdateEventArgs.SoundAssetName = soundAssetName; playSoundUpdateEventArgs.SoundGroupName = soundGroupName; playSoundUpdateEventArgs.PlaySoundParams = playSoundParams; playSoundUpdateEventArgs.Progress = progress; playSoundUpdateEventArgs.UserData = userData; return playSoundUpdateEventArgs; } /// /// 清理播放声音更新事件。 /// public override void Clear() { SerialId = 0; SoundAssetName = null; SoundGroupName = null; PlaySoundParams = null; Progress = 0f; UserData = null; } } } ================================================ FILE: GameFramework/Sound/ResetSoundAgentEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { /// /// 重置声音代理事件。 /// public sealed class ResetSoundAgentEventArgs : GameFrameworkEventArgs { /// /// 初始化重置声音代理事件的新实例。 /// public ResetSoundAgentEventArgs() { } /// /// 创建重置声音代理事件。 /// /// 创建的重置声音代理事件。 public static ResetSoundAgentEventArgs Create() { ResetSoundAgentEventArgs resetSoundAgentEventArgs = ReferencePool.Acquire(); return resetSoundAgentEventArgs; } /// /// 清理重置声音代理事件。 /// public override void Clear() { } } } ================================================ FILE: GameFramework/Sound/SoundManager.PlaySoundInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.Sound { internal sealed partial class SoundManager : GameFrameworkModule, ISoundManager { private sealed class PlaySoundInfo : IReference { private int m_SerialId; private SoundGroup m_SoundGroup; private PlaySoundParams m_PlaySoundParams; private object m_UserData; public PlaySoundInfo() { m_SerialId = 0; m_SoundGroup = null; m_PlaySoundParams = null; m_UserData = null; } public int SerialId { get { return m_SerialId; } } public SoundGroup SoundGroup { get { return m_SoundGroup; } } public PlaySoundParams PlaySoundParams { get { return m_PlaySoundParams; } } public object UserData { get { return m_UserData; } } public static PlaySoundInfo Create(int serialId, SoundGroup soundGroup, PlaySoundParams playSoundParams, object userData) { PlaySoundInfo playSoundInfo = ReferencePool.Acquire(); playSoundInfo.m_SerialId = serialId; playSoundInfo.m_SoundGroup = soundGroup; playSoundInfo.m_PlaySoundParams = playSoundParams; playSoundInfo.m_UserData = userData; return playSoundInfo; } public void Clear() { m_SerialId = 0; m_SoundGroup = null; m_PlaySoundParams = null; m_UserData = null; } } } } ================================================ FILE: GameFramework/Sound/SoundManager.SoundAgent.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.Sound { internal sealed partial class SoundManager : GameFrameworkModule, ISoundManager { /// /// 声音代理。 /// private sealed class SoundAgent : ISoundAgent { private readonly SoundGroup m_SoundGroup; private readonly ISoundHelper m_SoundHelper; private readonly ISoundAgentHelper m_SoundAgentHelper; private int m_SerialId; private object m_SoundAsset; private DateTime m_SetSoundAssetTime; private bool m_MuteInSoundGroup; private float m_VolumeInSoundGroup; /// /// 初始化声音代理的新实例。 /// /// 所在的声音组。 /// 声音辅助器接口。 /// 声音代理辅助器接口。 public SoundAgent(SoundGroup soundGroup, ISoundHelper soundHelper, ISoundAgentHelper soundAgentHelper) { if (soundGroup == null) { throw new GameFrameworkException("Sound group is invalid."); } if (soundHelper == null) { throw new GameFrameworkException("Sound helper is invalid."); } if (soundAgentHelper == null) { throw new GameFrameworkException("Sound agent helper is invalid."); } m_SoundGroup = soundGroup; m_SoundHelper = soundHelper; m_SoundAgentHelper = soundAgentHelper; m_SoundAgentHelper.ResetSoundAgent += OnResetSoundAgent; m_SerialId = 0; m_SoundAsset = null; Reset(); } /// /// 获取所在的声音组。 /// public ISoundGroup SoundGroup { get { return m_SoundGroup; } } /// /// 获取或设置声音的序列编号。 /// public int SerialId { get { return m_SerialId; } set { m_SerialId = value; } } /// /// 获取当前是否正在播放。 /// public bool IsPlaying { get { return m_SoundAgentHelper.IsPlaying; } } /// /// 获取声音长度。 /// public float Length { get { return m_SoundAgentHelper.Length; } } /// /// 获取或设置播放位置。 /// public float Time { get { return m_SoundAgentHelper.Time; } set { m_SoundAgentHelper.Time = value; } } /// /// 获取是否静音。 /// public bool Mute { get { return m_SoundAgentHelper.Mute; } } /// /// 获取或设置在声音组内是否静音。 /// public bool MuteInSoundGroup { get { return m_MuteInSoundGroup; } set { m_MuteInSoundGroup = value; RefreshMute(); } } /// /// 获取或设置是否循环播放。 /// public bool Loop { get { return m_SoundAgentHelper.Loop; } set { m_SoundAgentHelper.Loop = value; } } /// /// 获取或设置声音优先级。 /// public int Priority { get { return m_SoundAgentHelper.Priority; } set { m_SoundAgentHelper.Priority = value; } } /// /// 获取音量大小。 /// public float Volume { get { return m_SoundAgentHelper.Volume; } } /// /// 获取或设置在声音组内音量大小。 /// public float VolumeInSoundGroup { get { return m_VolumeInSoundGroup; } set { m_VolumeInSoundGroup = value; RefreshVolume(); } } /// /// 获取或设置声音音调。 /// public float Pitch { get { return m_SoundAgentHelper.Pitch; } set { m_SoundAgentHelper.Pitch = value; } } /// /// 获取或设置声音立体声声相。 /// public float PanStereo { get { return m_SoundAgentHelper.PanStereo; } set { m_SoundAgentHelper.PanStereo = value; } } /// /// 获取或设置声音空间混合量。 /// public float SpatialBlend { get { return m_SoundAgentHelper.SpatialBlend; } set { m_SoundAgentHelper.SpatialBlend = value; } } /// /// 获取或设置声音最大距离。 /// public float MaxDistance { get { return m_SoundAgentHelper.MaxDistance; } set { m_SoundAgentHelper.MaxDistance = value; } } /// /// 获取或设置声音多普勒等级。 /// public float DopplerLevel { get { return m_SoundAgentHelper.DopplerLevel; } set { m_SoundAgentHelper.DopplerLevel = value; } } /// /// 获取声音代理辅助器。 /// public ISoundAgentHelper Helper { get { return m_SoundAgentHelper; } } /// /// 获取声音创建时间。 /// internal DateTime SetSoundAssetTime { get { return m_SetSoundAssetTime; } } /// /// 播放声音。 /// public void Play() { m_SoundAgentHelper.Play(Constant.DefaultFadeInSeconds); } /// /// 播放声音。 /// /// 声音淡入时间,以秒为单位。 public void Play(float fadeInSeconds) { m_SoundAgentHelper.Play(fadeInSeconds); } /// /// 停止播放声音。 /// public void Stop() { m_SoundAgentHelper.Stop(Constant.DefaultFadeOutSeconds); } /// /// 停止播放声音。 /// /// 声音淡出时间,以秒为单位。 public void Stop(float fadeOutSeconds) { m_SoundAgentHelper.Stop(fadeOutSeconds); } /// /// 暂停播放声音。 /// public void Pause() { m_SoundAgentHelper.Pause(Constant.DefaultFadeOutSeconds); } /// /// 暂停播放声音。 /// /// 声音淡出时间,以秒为单位。 public void Pause(float fadeOutSeconds) { m_SoundAgentHelper.Pause(fadeOutSeconds); } /// /// 恢复播放声音。 /// public void Resume() { m_SoundAgentHelper.Resume(Constant.DefaultFadeInSeconds); } /// /// 恢复播放声音。 /// /// 声音淡入时间,以秒为单位。 public void Resume(float fadeInSeconds) { m_SoundAgentHelper.Resume(fadeInSeconds); } /// /// 重置声音代理。 /// public void Reset() { if (m_SoundAsset != null) { m_SoundHelper.ReleaseSoundAsset(m_SoundAsset); m_SoundAsset = null; } m_SetSoundAssetTime = DateTime.MinValue; Time = Constant.DefaultTime; MuteInSoundGroup = Constant.DefaultMute; Loop = Constant.DefaultLoop; Priority = Constant.DefaultPriority; VolumeInSoundGroup = Constant.DefaultVolume; Pitch = Constant.DefaultPitch; PanStereo = Constant.DefaultPanStereo; SpatialBlend = Constant.DefaultSpatialBlend; MaxDistance = Constant.DefaultMaxDistance; DopplerLevel = Constant.DefaultDopplerLevel; m_SoundAgentHelper.Reset(); } internal bool SetSoundAsset(object soundAsset) { Reset(); m_SoundAsset = soundAsset; m_SetSoundAssetTime = DateTime.UtcNow; return m_SoundAgentHelper.SetSoundAsset(soundAsset); } internal void RefreshMute() { m_SoundAgentHelper.Mute = m_SoundGroup.Mute || m_MuteInSoundGroup; } internal void RefreshVolume() { m_SoundAgentHelper.Volume = m_SoundGroup.Volume * m_VolumeInSoundGroup; } private void OnResetSoundAgent(object sender, ResetSoundAgentEventArgs e) { Reset(); } } } } ================================================ FILE: GameFramework/Sound/SoundManager.SoundGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.Sound { internal sealed partial class SoundManager : GameFrameworkModule, ISoundManager { /// /// 声音组。 /// private sealed class SoundGroup : ISoundGroup { private readonly string m_Name; private readonly ISoundGroupHelper m_SoundGroupHelper; private readonly List m_SoundAgents; private bool m_AvoidBeingReplacedBySamePriority; private bool m_Mute; private float m_Volume; /// /// 初始化声音组的新实例。 /// /// 声音组名称。 /// 声音组辅助器。 public SoundGroup(string name, ISoundGroupHelper soundGroupHelper) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("Sound group name is invalid."); } if (soundGroupHelper == null) { throw new GameFrameworkException("Sound group helper is invalid."); } m_Name = name; m_SoundGroupHelper = soundGroupHelper; m_SoundAgents = new List(); } /// /// 获取声音组名称。 /// public string Name { get { return m_Name; } } /// /// 获取声音代理数。 /// public int SoundAgentCount { get { return m_SoundAgents.Count; } } /// /// 获取或设置声音组中的声音是否避免被同优先级声音替换。 /// public bool AvoidBeingReplacedBySamePriority { get { return m_AvoidBeingReplacedBySamePriority; } set { m_AvoidBeingReplacedBySamePriority = value; } } /// /// 获取或设置声音组静音。 /// public bool Mute { get { return m_Mute; } set { m_Mute = value; foreach (SoundAgent soundAgent in m_SoundAgents) { soundAgent.RefreshMute(); } } } /// /// 获取或设置声音组音量。 /// public float Volume { get { return m_Volume; } set { m_Volume = value; foreach (SoundAgent soundAgent in m_SoundAgents) { soundAgent.RefreshVolume(); } } } /// /// 获取声音组辅助器。 /// public ISoundGroupHelper Helper { get { return m_SoundGroupHelper; } } /// /// 增加声音代理辅助器。 /// /// 声音辅助器接口。 /// 要增加的声音代理辅助器。 public void AddSoundAgentHelper(ISoundHelper soundHelper, ISoundAgentHelper soundAgentHelper) { m_SoundAgents.Add(new SoundAgent(this, soundHelper, soundAgentHelper)); } /// /// 播放声音。 /// /// 声音的序列编号。 /// 声音资源。 /// 播放声音参数。 /// 错误码。 /// 用于播放的声音代理。 public ISoundAgent PlaySound(int serialId, object soundAsset, PlaySoundParams playSoundParams, out PlaySoundErrorCode? errorCode) { errorCode = null; SoundAgent candidateAgent = null; foreach (SoundAgent soundAgent in m_SoundAgents) { if (!soundAgent.IsPlaying) { candidateAgent = soundAgent; break; } if (soundAgent.Priority < playSoundParams.Priority) { if (candidateAgent == null || soundAgent.Priority < candidateAgent.Priority) { candidateAgent = soundAgent; } } else if (!m_AvoidBeingReplacedBySamePriority && soundAgent.Priority == playSoundParams.Priority) { if (candidateAgent == null || soundAgent.SetSoundAssetTime < candidateAgent.SetSoundAssetTime) { candidateAgent = soundAgent; } } } if (candidateAgent == null) { errorCode = PlaySoundErrorCode.IgnoredDueToLowPriority; return null; } if (!candidateAgent.SetSoundAsset(soundAsset)) { errorCode = PlaySoundErrorCode.SetSoundAssetFailure; return null; } candidateAgent.SerialId = serialId; candidateAgent.Time = playSoundParams.Time; candidateAgent.MuteInSoundGroup = playSoundParams.MuteInSoundGroup; candidateAgent.Loop = playSoundParams.Loop; candidateAgent.Priority = playSoundParams.Priority; candidateAgent.VolumeInSoundGroup = playSoundParams.VolumeInSoundGroup; candidateAgent.Pitch = playSoundParams.Pitch; candidateAgent.PanStereo = playSoundParams.PanStereo; candidateAgent.SpatialBlend = playSoundParams.SpatialBlend; candidateAgent.MaxDistance = playSoundParams.MaxDistance; candidateAgent.DopplerLevel = playSoundParams.DopplerLevel; candidateAgent.Play(playSoundParams.FadeInSeconds); return candidateAgent; } /// /// 停止播放声音。 /// /// 要停止播放声音的序列编号。 /// 声音淡出时间,以秒为单位。 /// 是否停止播放声音成功。 public bool StopSound(int serialId, float fadeOutSeconds) { foreach (SoundAgent soundAgent in m_SoundAgents) { if (soundAgent.SerialId != serialId) { continue; } soundAgent.Stop(fadeOutSeconds); return true; } return false; } /// /// 暂停播放声音。 /// /// 要暂停播放声音的序列编号。 /// 声音淡出时间,以秒为单位。 /// 是否暂停播放声音成功。 public bool PauseSound(int serialId, float fadeOutSeconds) { foreach (SoundAgent soundAgent in m_SoundAgents) { if (soundAgent.SerialId != serialId) { continue; } soundAgent.Pause(fadeOutSeconds); return true; } return false; } /// /// 恢复播放声音。 /// /// 要恢复播放声音的序列编号。 /// 声音淡入时间,以秒为单位。 /// 是否恢复播放声音成功。 public bool ResumeSound(int serialId, float fadeInSeconds) { foreach (SoundAgent soundAgent in m_SoundAgents) { if (soundAgent.SerialId != serialId) { continue; } soundAgent.Resume(fadeInSeconds); return true; } return false; } /// /// 停止所有已加载的声音。 /// public void StopAllLoadedSounds() { foreach (SoundAgent soundAgent in m_SoundAgents) { if (soundAgent.IsPlaying) { soundAgent.Stop(); } } } /// /// 停止所有已加载的声音。 /// /// 声音淡出时间,以秒为单位。 public void StopAllLoadedSounds(float fadeOutSeconds) { foreach (SoundAgent soundAgent in m_SoundAgents) { if (soundAgent.IsPlaying) { soundAgent.Stop(fadeOutSeconds); } } } } } } ================================================ FILE: GameFramework/Sound/SoundManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.Sound { /// /// 声音管理器。 /// internal sealed partial class SoundManager : GameFrameworkModule, ISoundManager { private readonly Dictionary m_SoundGroups; private readonly List m_SoundsBeingLoaded; private readonly HashSet m_SoundsToReleaseOnLoad; private readonly LoadAssetCallbacks m_LoadAssetCallbacks; private IResourceManager m_ResourceManager; private ISoundHelper m_SoundHelper; private int m_Serial; private EventHandler m_PlaySoundSuccessEventHandler; private EventHandler m_PlaySoundFailureEventHandler; private EventHandler m_PlaySoundUpdateEventHandler; private EventHandler m_PlaySoundDependencyAssetEventHandler; /// /// 初始化声音管理器的新实例。 /// public SoundManager() { m_SoundGroups = new Dictionary(StringComparer.Ordinal); m_SoundsBeingLoaded = new List(); m_SoundsToReleaseOnLoad = new HashSet(); m_LoadAssetCallbacks = new LoadAssetCallbacks(LoadAssetSuccessCallback, LoadAssetFailureCallback, LoadAssetUpdateCallback, LoadAssetDependencyAssetCallback); m_ResourceManager = null; m_SoundHelper = null; m_Serial = 0; m_PlaySoundSuccessEventHandler = null; m_PlaySoundFailureEventHandler = null; m_PlaySoundUpdateEventHandler = null; m_PlaySoundDependencyAssetEventHandler = null; } /// /// 获取声音组数量。 /// public int SoundGroupCount { get { return m_SoundGroups.Count; } } /// /// 播放声音成功事件。 /// public event EventHandler PlaySoundSuccess { add { m_PlaySoundSuccessEventHandler += value; } remove { m_PlaySoundSuccessEventHandler -= value; } } /// /// 播放声音失败事件。 /// public event EventHandler PlaySoundFailure { add { m_PlaySoundFailureEventHandler += value; } remove { m_PlaySoundFailureEventHandler -= value; } } /// /// 播放声音更新事件。 /// public event EventHandler PlaySoundUpdate { add { m_PlaySoundUpdateEventHandler += value; } remove { m_PlaySoundUpdateEventHandler -= value; } } /// /// 播放声音时加载依赖资源事件。 /// public event EventHandler PlaySoundDependencyAsset { add { m_PlaySoundDependencyAssetEventHandler += value; } remove { m_PlaySoundDependencyAssetEventHandler -= value; } } /// /// 声音管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { } /// /// 关闭并清理声音管理器。 /// internal override void Shutdown() { StopAllLoadedSounds(); m_SoundGroups.Clear(); m_SoundsBeingLoaded.Clear(); m_SoundsToReleaseOnLoad.Clear(); } /// /// 设置资源管理器。 /// /// 资源管理器。 public void SetResourceManager(IResourceManager resourceManager) { if (resourceManager == null) { throw new GameFrameworkException("Resource manager is invalid."); } m_ResourceManager = resourceManager; } /// /// 设置声音辅助器。 /// /// 声音辅助器。 public void SetSoundHelper(ISoundHelper soundHelper) { if (soundHelper == null) { throw new GameFrameworkException("Sound helper is invalid."); } m_SoundHelper = soundHelper; } /// /// 是否存在指定声音组。 /// /// 声音组名称。 /// 指定声音组是否存在。 public bool HasSoundGroup(string soundGroupName) { if (string.IsNullOrEmpty(soundGroupName)) { throw new GameFrameworkException("Sound group name is invalid."); } return m_SoundGroups.ContainsKey(soundGroupName); } /// /// 获取指定声音组。 /// /// 声音组名称。 /// 要获取的声音组。 public ISoundGroup GetSoundGroup(string soundGroupName) { if (string.IsNullOrEmpty(soundGroupName)) { throw new GameFrameworkException("Sound group name is invalid."); } SoundGroup soundGroup = null; if (m_SoundGroups.TryGetValue(soundGroupName, out soundGroup)) { return soundGroup; } return null; } /// /// 获取所有声音组。 /// /// 所有声音组。 public ISoundGroup[] GetAllSoundGroups() { int index = 0; ISoundGroup[] results = new ISoundGroup[m_SoundGroups.Count]; foreach (KeyValuePair soundGroup in m_SoundGroups) { results[index++] = soundGroup.Value; } return results; } /// /// 获取所有声音组。 /// /// 所有声音组。 public void GetAllSoundGroups(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair soundGroup in m_SoundGroups) { results.Add(soundGroup.Value); } } /// /// 增加声音组。 /// /// 声音组名称。 /// 声音组辅助器。 /// 是否增加声音组成功。 public bool AddSoundGroup(string soundGroupName, ISoundGroupHelper soundGroupHelper) { return AddSoundGroup(soundGroupName, false, Constant.DefaultMute, Constant.DefaultVolume, soundGroupHelper); } /// /// 增加声音组。 /// /// 声音组名称。 /// 声音组中的声音是否避免被同优先级声音替换。 /// 声音组是否静音。 /// 声音组音量。 /// 声音组辅助器。 /// 是否增加声音组成功。 public bool AddSoundGroup(string soundGroupName, bool soundGroupAvoidBeingReplacedBySamePriority, bool soundGroupMute, float soundGroupVolume, ISoundGroupHelper soundGroupHelper) { if (string.IsNullOrEmpty(soundGroupName)) { throw new GameFrameworkException("Sound group name is invalid."); } if (soundGroupHelper == null) { throw new GameFrameworkException("Sound group helper is invalid."); } if (HasSoundGroup(soundGroupName)) { return false; } SoundGroup soundGroup = new SoundGroup(soundGroupName, soundGroupHelper) { AvoidBeingReplacedBySamePriority = soundGroupAvoidBeingReplacedBySamePriority, Mute = soundGroupMute, Volume = soundGroupVolume }; m_SoundGroups.Add(soundGroupName, soundGroup); return true; } /// /// 增加声音代理辅助器。 /// /// 声音组名称。 /// 要增加的声音代理辅助器。 public void AddSoundAgentHelper(string soundGroupName, ISoundAgentHelper soundAgentHelper) { if (m_SoundHelper == null) { throw new GameFrameworkException("You must set sound helper first."); } SoundGroup soundGroup = (SoundGroup)GetSoundGroup(soundGroupName); if (soundGroup == null) { throw new GameFrameworkException(Utility.Text.Format("Sound group '{0}' is not exist.", soundGroupName)); } soundGroup.AddSoundAgentHelper(m_SoundHelper, soundAgentHelper); } /// /// 获取所有正在加载声音的序列编号。 /// /// 所有正在加载声音的序列编号。 public int[] GetAllLoadingSoundSerialIds() { return m_SoundsBeingLoaded.ToArray(); } /// /// 获取所有正在加载声音的序列编号。 /// /// 所有正在加载声音的序列编号。 public void GetAllLoadingSoundSerialIds(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); results.AddRange(m_SoundsBeingLoaded); } /// /// 是否正在加载声音。 /// /// 声音序列编号。 /// 是否正在加载声音。 public bool IsLoadingSound(int serialId) { return m_SoundsBeingLoaded.Contains(serialId); } /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 声音的序列编号。 public int PlaySound(string soundAssetName, string soundGroupName) { return PlaySound(soundAssetName, soundGroupName, Resource.Constant.DefaultPriority, null, null); } /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 加载声音资源的优先级。 /// 声音的序列编号。 public int PlaySound(string soundAssetName, string soundGroupName, int priority) { return PlaySound(soundAssetName, soundGroupName, priority, null, null); } /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 播放声音参数。 /// 声音的序列编号。 public int PlaySound(string soundAssetName, string soundGroupName, PlaySoundParams playSoundParams) { return PlaySound(soundAssetName, soundGroupName, Resource.Constant.DefaultPriority, playSoundParams, null); } /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 用户自定义数据。 /// 声音的序列编号。 public int PlaySound(string soundAssetName, string soundGroupName, object userData) { return PlaySound(soundAssetName, soundGroupName, Resource.Constant.DefaultPriority, null, userData); } /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 加载声音资源的优先级。 /// 播放声音参数。 /// 声音的序列编号。 public int PlaySound(string soundAssetName, string soundGroupName, int priority, PlaySoundParams playSoundParams) { return PlaySound(soundAssetName, soundGroupName, priority, playSoundParams, null); } /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 加载声音资源的优先级。 /// 用户自定义数据。 /// 声音的序列编号。 public int PlaySound(string soundAssetName, string soundGroupName, int priority, object userData) { return PlaySound(soundAssetName, soundGroupName, priority, null, userData); } /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 播放声音参数。 /// 用户自定义数据。 /// 声音的序列编号。 public int PlaySound(string soundAssetName, string soundGroupName, PlaySoundParams playSoundParams, object userData) { return PlaySound(soundAssetName, soundGroupName, Resource.Constant.DefaultPriority, playSoundParams, userData); } /// /// 播放声音。 /// /// 声音资源名称。 /// 声音组名称。 /// 加载声音资源的优先级。 /// 播放声音参数。 /// 用户自定义数据。 /// 声音的序列编号。 public int PlaySound(string soundAssetName, string soundGroupName, int priority, PlaySoundParams playSoundParams, object userData) { if (m_ResourceManager == null) { throw new GameFrameworkException("You must set resource manager first."); } if (m_SoundHelper == null) { throw new GameFrameworkException("You must set sound helper first."); } if (playSoundParams == null) { playSoundParams = PlaySoundParams.Create(); } int serialId = ++m_Serial; PlaySoundErrorCode? errorCode = null; string errorMessage = null; SoundGroup soundGroup = (SoundGroup)GetSoundGroup(soundGroupName); if (soundGroup == null) { errorCode = PlaySoundErrorCode.SoundGroupNotExist; errorMessage = Utility.Text.Format("Sound group '{0}' is not exist.", soundGroupName); } else if (soundGroup.SoundAgentCount <= 0) { errorCode = PlaySoundErrorCode.SoundGroupHasNoAgent; errorMessage = Utility.Text.Format("Sound group '{0}' is have no sound agent.", soundGroupName); } if (errorCode.HasValue) { if (m_PlaySoundFailureEventHandler != null) { PlaySoundFailureEventArgs playSoundFailureEventArgs = PlaySoundFailureEventArgs.Create(serialId, soundAssetName, soundGroupName, playSoundParams, errorCode.Value, errorMessage, userData); m_PlaySoundFailureEventHandler(this, playSoundFailureEventArgs); ReferencePool.Release(playSoundFailureEventArgs); if (playSoundParams.Referenced) { ReferencePool.Release(playSoundParams); } return serialId; } throw new GameFrameworkException(errorMessage); } m_SoundsBeingLoaded.Add(serialId); m_ResourceManager.LoadAsset(soundAssetName, priority, m_LoadAssetCallbacks, PlaySoundInfo.Create(serialId, soundGroup, playSoundParams, userData)); return serialId; } /// /// 停止播放声音。 /// /// 要停止播放声音的序列编号。 /// 是否停止播放声音成功。 public bool StopSound(int serialId) { return StopSound(serialId, Constant.DefaultFadeOutSeconds); } /// /// 停止播放声音。 /// /// 要停止播放声音的序列编号。 /// 声音淡出时间,以秒为单位。 /// 是否停止播放声音成功。 public bool StopSound(int serialId, float fadeOutSeconds) { if (IsLoadingSound(serialId)) { m_SoundsToReleaseOnLoad.Add(serialId); m_SoundsBeingLoaded.Remove(serialId); return true; } foreach (KeyValuePair soundGroup in m_SoundGroups) { if (soundGroup.Value.StopSound(serialId, fadeOutSeconds)) { return true; } } return false; } /// /// 停止所有已加载的声音。 /// public void StopAllLoadedSounds() { StopAllLoadedSounds(Constant.DefaultFadeOutSeconds); } /// /// 停止所有已加载的声音。 /// /// 声音淡出时间,以秒为单位。 public void StopAllLoadedSounds(float fadeOutSeconds) { foreach (KeyValuePair soundGroup in m_SoundGroups) { soundGroup.Value.StopAllLoadedSounds(fadeOutSeconds); } } /// /// 停止所有正在加载的声音。 /// public void StopAllLoadingSounds() { foreach (int serialId in m_SoundsBeingLoaded) { m_SoundsToReleaseOnLoad.Add(serialId); } } /// /// 暂停播放声音。 /// /// 要暂停播放声音的序列编号。 public void PauseSound(int serialId) { PauseSound(serialId, Constant.DefaultFadeOutSeconds); } /// /// 暂停播放声音。 /// /// 要暂停播放声音的序列编号。 /// 声音淡出时间,以秒为单位。 public void PauseSound(int serialId, float fadeOutSeconds) { foreach (KeyValuePair soundGroup in m_SoundGroups) { if (soundGroup.Value.PauseSound(serialId, fadeOutSeconds)) { return; } } throw new GameFrameworkException(Utility.Text.Format("Can not find sound '{0}'.", serialId)); } /// /// 恢复播放声音。 /// /// 要恢复播放声音的序列编号。 public void ResumeSound(int serialId) { ResumeSound(serialId, Constant.DefaultFadeInSeconds); } /// /// 恢复播放声音。 /// /// 要恢复播放声音的序列编号。 /// 声音淡入时间,以秒为单位。 public void ResumeSound(int serialId, float fadeInSeconds) { foreach (KeyValuePair soundGroup in m_SoundGroups) { if (soundGroup.Value.ResumeSound(serialId, fadeInSeconds)) { return; } } throw new GameFrameworkException(Utility.Text.Format("Can not find sound '{0}'.", serialId)); } private void LoadAssetSuccessCallback(string soundAssetName, object soundAsset, float duration, object userData) { PlaySoundInfo playSoundInfo = (PlaySoundInfo)userData; if (playSoundInfo == null) { throw new GameFrameworkException("Play sound info is invalid."); } if (m_SoundsToReleaseOnLoad.Contains(playSoundInfo.SerialId)) { m_SoundsToReleaseOnLoad.Remove(playSoundInfo.SerialId); if (playSoundInfo.PlaySoundParams.Referenced) { ReferencePool.Release(playSoundInfo.PlaySoundParams); } ReferencePool.Release(playSoundInfo); m_SoundHelper.ReleaseSoundAsset(soundAsset); return; } m_SoundsBeingLoaded.Remove(playSoundInfo.SerialId); PlaySoundErrorCode? errorCode = null; ISoundAgent soundAgent = playSoundInfo.SoundGroup.PlaySound(playSoundInfo.SerialId, soundAsset, playSoundInfo.PlaySoundParams, out errorCode); if (soundAgent != null) { if (m_PlaySoundSuccessEventHandler != null) { PlaySoundSuccessEventArgs playSoundSuccessEventArgs = PlaySoundSuccessEventArgs.Create(playSoundInfo.SerialId, soundAssetName, soundAgent, duration, playSoundInfo.UserData); m_PlaySoundSuccessEventHandler(this, playSoundSuccessEventArgs); ReferencePool.Release(playSoundSuccessEventArgs); } if (playSoundInfo.PlaySoundParams.Referenced) { ReferencePool.Release(playSoundInfo.PlaySoundParams); } ReferencePool.Release(playSoundInfo); return; } m_SoundsToReleaseOnLoad.Remove(playSoundInfo.SerialId); m_SoundHelper.ReleaseSoundAsset(soundAsset); string errorMessage = Utility.Text.Format("Sound group '{0}' play sound '{1}' failure.", playSoundInfo.SoundGroup.Name, soundAssetName); if (m_PlaySoundFailureEventHandler != null) { PlaySoundFailureEventArgs playSoundFailureEventArgs = PlaySoundFailureEventArgs.Create(playSoundInfo.SerialId, soundAssetName, playSoundInfo.SoundGroup.Name, playSoundInfo.PlaySoundParams, errorCode.Value, errorMessage, playSoundInfo.UserData); m_PlaySoundFailureEventHandler(this, playSoundFailureEventArgs); ReferencePool.Release(playSoundFailureEventArgs); if (playSoundInfo.PlaySoundParams.Referenced) { ReferencePool.Release(playSoundInfo.PlaySoundParams); } ReferencePool.Release(playSoundInfo); return; } if (playSoundInfo.PlaySoundParams.Referenced) { ReferencePool.Release(playSoundInfo.PlaySoundParams); } ReferencePool.Release(playSoundInfo); throw new GameFrameworkException(errorMessage); } private void LoadAssetFailureCallback(string soundAssetName, LoadResourceStatus status, string errorMessage, object userData) { PlaySoundInfo playSoundInfo = (PlaySoundInfo)userData; if (playSoundInfo == null) { throw new GameFrameworkException("Play sound info is invalid."); } if (m_SoundsToReleaseOnLoad.Contains(playSoundInfo.SerialId)) { m_SoundsToReleaseOnLoad.Remove(playSoundInfo.SerialId); if (playSoundInfo.PlaySoundParams.Referenced) { ReferencePool.Release(playSoundInfo.PlaySoundParams); } return; } m_SoundsBeingLoaded.Remove(playSoundInfo.SerialId); string appendErrorMessage = Utility.Text.Format("Load sound failure, asset name '{0}', status '{1}', error message '{2}'.", soundAssetName, status, errorMessage); if (m_PlaySoundFailureEventHandler != null) { PlaySoundFailureEventArgs playSoundFailureEventArgs = PlaySoundFailureEventArgs.Create(playSoundInfo.SerialId, soundAssetName, playSoundInfo.SoundGroup.Name, playSoundInfo.PlaySoundParams, PlaySoundErrorCode.LoadAssetFailure, appendErrorMessage, playSoundInfo.UserData); m_PlaySoundFailureEventHandler(this, playSoundFailureEventArgs); ReferencePool.Release(playSoundFailureEventArgs); if (playSoundInfo.PlaySoundParams.Referenced) { ReferencePool.Release(playSoundInfo.PlaySoundParams); } return; } throw new GameFrameworkException(appendErrorMessage); } private void LoadAssetUpdateCallback(string soundAssetName, float progress, object userData) { PlaySoundInfo playSoundInfo = (PlaySoundInfo)userData; if (playSoundInfo == null) { throw new GameFrameworkException("Play sound info is invalid."); } if (m_PlaySoundUpdateEventHandler != null) { PlaySoundUpdateEventArgs playSoundUpdateEventArgs = PlaySoundUpdateEventArgs.Create(playSoundInfo.SerialId, soundAssetName, playSoundInfo.SoundGroup.Name, playSoundInfo.PlaySoundParams, progress, playSoundInfo.UserData); m_PlaySoundUpdateEventHandler(this, playSoundUpdateEventArgs); ReferencePool.Release(playSoundUpdateEventArgs); } } private void LoadAssetDependencyAssetCallback(string soundAssetName, string dependencyAssetName, int loadedCount, int totalCount, object userData) { PlaySoundInfo playSoundInfo = (PlaySoundInfo)userData; if (playSoundInfo == null) { throw new GameFrameworkException("Play sound info is invalid."); } if (m_PlaySoundDependencyAssetEventHandler != null) { PlaySoundDependencyAssetEventArgs playSoundDependencyAssetEventArgs = PlaySoundDependencyAssetEventArgs.Create(playSoundInfo.SerialId, soundAssetName, playSoundInfo.SoundGroup.Name, playSoundInfo.PlaySoundParams, dependencyAssetName, loadedCount, totalCount, playSoundInfo.UserData); m_PlaySoundDependencyAssetEventHandler(this, playSoundDependencyAssetEventArgs); ReferencePool.Release(playSoundDependencyAssetEventArgs); } } } } ================================================ FILE: GameFramework/UI/CloseUIFormCompleteEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.UI { /// /// 关闭界面完成事件。 /// public sealed class CloseUIFormCompleteEventArgs : GameFrameworkEventArgs { /// /// 初始化关闭界面完成事件的新实例。 /// public CloseUIFormCompleteEventArgs() { SerialId = 0; UIFormAssetName = null; UIGroup = null; UserData = null; } /// /// 获取界面序列编号。 /// public int SerialId { get; private set; } /// /// 获取界面资源名称。 /// public string UIFormAssetName { get; private set; } /// /// 获取界面所属的界面组。 /// public IUIGroup UIGroup { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建关闭界面完成事件。 /// /// 界面序列编号。 /// 界面资源名称。 /// 界面所属的界面组。 /// 用户自定义数据。 /// 创建的关闭界面完成事件。 public static CloseUIFormCompleteEventArgs Create(int serialId, string uiFormAssetName, IUIGroup uiGroup, object userData) { CloseUIFormCompleteEventArgs closeUIFormCompleteEventArgs = ReferencePool.Acquire(); closeUIFormCompleteEventArgs.SerialId = serialId; closeUIFormCompleteEventArgs.UIFormAssetName = uiFormAssetName; closeUIFormCompleteEventArgs.UIGroup = uiGroup; closeUIFormCompleteEventArgs.UserData = userData; return closeUIFormCompleteEventArgs; } /// /// 清理关闭界面完成事件。 /// public override void Clear() { SerialId = 0; UIFormAssetName = null; UIGroup = null; UserData = null; } } } ================================================ FILE: GameFramework/UI/IUIForm.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.UI { /// /// 界面接口。 /// public interface IUIForm { /// /// 获取界面序列编号。 /// int SerialId { get; } /// /// 获取界面资源名称。 /// string UIFormAssetName { get; } /// /// 获取界面实例。 /// object Handle { get; } /// /// 获取界面所属的界面组。 /// IUIGroup UIGroup { get; } /// /// 获取界面在界面组中的深度。 /// int DepthInUIGroup { get; } /// /// 获取是否暂停被覆盖的界面。 /// bool PauseCoveredUIForm { get; } /// /// 初始化界面。 /// /// 界面序列编号。 /// 界面资源名称。 /// 界面所属的界面组。 /// 是否暂停被覆盖的界面。 /// 是否是新实例。 /// 用户自定义数据。 void OnInit(int serialId, string uiFormAssetName, IUIGroup uiGroup, bool pauseCoveredUIForm, bool isNewInstance, object userData); /// /// 界面回收。 /// void OnRecycle(); /// /// 界面打开。 /// /// 用户自定义数据。 void OnOpen(object userData); /// /// 界面关闭。 /// /// 是否是关闭界面管理器时触发。 /// 用户自定义数据。 void OnClose(bool isShutdown, object userData); /// /// 界面暂停。 /// void OnPause(); /// /// 界面暂停恢复。 /// void OnResume(); /// /// 界面遮挡。 /// void OnCover(); /// /// 界面遮挡恢复。 /// void OnReveal(); /// /// 界面激活。 /// /// 用户自定义数据。 void OnRefocus(object userData); /// /// 界面轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 void OnUpdate(float elapseSeconds, float realElapseSeconds); /// /// 界面深度改变。 /// /// 界面组深度。 /// 界面在界面组中的深度。 void OnDepthChanged(int uiGroupDepth, int depthInUIGroup); } } ================================================ FILE: GameFramework/UI/IUIFormHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.UI { /// /// 界面辅助器接口。 /// public interface IUIFormHelper { /// /// 实例化界面。 /// /// 要实例化的界面资源。 /// 实例化后的界面。 object InstantiateUIForm(object uiFormAsset); /// /// 创建界面。 /// /// 界面实例。 /// 界面所属的界面组。 /// 用户自定义数据。 /// 界面。 IUIForm CreateUIForm(object uiFormInstance, IUIGroup uiGroup, object userData); /// /// 释放界面。 /// /// 要释放的界面资源。 /// 要释放的界面实例。 void ReleaseUIForm(object uiFormAsset, object uiFormInstance); } } ================================================ FILE: GameFramework/UI/IUIGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.UI { /// /// 界面组接口。 /// public interface IUIGroup { /// /// 获取界面组名称。 /// string Name { get; } /// /// 获取或设置界面组深度。 /// int Depth { get; set; } /// /// 获取或设置界面组是否暂停。 /// bool Pause { get; set; } /// /// 获取界面组中界面数量。 /// int UIFormCount { get; } /// /// 获取当前界面。 /// IUIForm CurrentUIForm { get; } /// /// 获取界面组辅助器。 /// IUIGroupHelper Helper { get; } /// /// 界面组中是否存在界面。 /// /// 界面序列编号。 /// 界面组中是否存在界面。 bool HasUIForm(int serialId); /// /// 界面组中是否存在界面。 /// /// 界面资源名称。 /// 界面组中是否存在界面。 bool HasUIForm(string uiFormAssetName); /// /// 从界面组中获取界面。 /// /// 界面序列编号。 /// 要获取的界面。 IUIForm GetUIForm(int serialId); /// /// 从界面组中获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 IUIForm GetUIForm(string uiFormAssetName); /// /// 从界面组中获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 IUIForm[] GetUIForms(string uiFormAssetName); /// /// 从界面组中获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 void GetUIForms(string uiFormAssetName, List results); /// /// 从界面组中获取所有界面。 /// /// 界面组中的所有界面。 IUIForm[] GetAllUIForms(); /// /// 从界面组中获取所有界面。 /// /// 界面组中的所有界面。 void GetAllUIForms(List results); } } ================================================ FILE: GameFramework/UI/IUIGroupHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.UI { /// /// 界面组辅助器接口。 /// public interface IUIGroupHelper { /// /// 设置界面组深度。 /// /// 界面组深度。 void SetDepth(int depth); } } ================================================ FILE: GameFramework/UI/IUIManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.ObjectPool; using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.UI { /// /// 界面管理器接口。 /// public interface IUIManager { /// /// 获取界面组数量。 /// int UIGroupCount { get; } /// /// 获取或设置界面实例对象池自动释放可释放对象的间隔秒数。 /// float InstanceAutoReleaseInterval { get; set; } /// /// 获取或设置界面实例对象池的容量。 /// int InstanceCapacity { get; set; } /// /// 获取或设置界面实例对象池对象过期秒数。 /// float InstanceExpireTime { get; set; } /// /// 获取或设置界面实例对象池的优先级。 /// int InstancePriority { get; set; } /// /// 打开界面成功事件。 /// event EventHandler OpenUIFormSuccess; /// /// 打开界面失败事件。 /// event EventHandler OpenUIFormFailure; /// /// 打开界面更新事件。 /// event EventHandler OpenUIFormUpdate; /// /// 打开界面时加载依赖资源事件。 /// event EventHandler OpenUIFormDependencyAsset; /// /// 关闭界面完成事件。 /// event EventHandler CloseUIFormComplete; /// /// 设置对象池管理器。 /// /// 对象池管理器。 void SetObjectPoolManager(IObjectPoolManager objectPoolManager); /// /// 设置资源管理器。 /// /// 资源管理器。 void SetResourceManager(IResourceManager resourceManager); /// /// 设置界面辅助器。 /// /// 界面辅助器。 void SetUIFormHelper(IUIFormHelper uiFormHelper); /// /// 是否存在界面组。 /// /// 界面组名称。 /// 是否存在界面组。 bool HasUIGroup(string uiGroupName); /// /// 获取界面组。 /// /// 界面组名称。 /// 要获取的界面组。 IUIGroup GetUIGroup(string uiGroupName); /// /// 获取所有界面组。 /// /// 所有界面组。 IUIGroup[] GetAllUIGroups(); /// /// 获取所有界面组。 /// /// 所有界面组。 void GetAllUIGroups(List results); /// /// 增加界面组。 /// /// 界面组名称。 /// 界面组辅助器。 /// 是否增加界面组成功。 bool AddUIGroup(string uiGroupName, IUIGroupHelper uiGroupHelper); /// /// 增加界面组。 /// /// 界面组名称。 /// 界面组深度。 /// 界面组辅助器。 /// 是否增加界面组成功。 bool AddUIGroup(string uiGroupName, int uiGroupDepth, IUIGroupHelper uiGroupHelper); /// /// 是否存在界面。 /// /// 界面序列编号。 /// 是否存在界面。 bool HasUIForm(int serialId); /// /// 是否存在界面。 /// /// 界面资源名称。 /// 是否存在界面。 bool HasUIForm(string uiFormAssetName); /// /// 获取界面。 /// /// 界面序列编号。 /// 要获取的界面。 IUIForm GetUIForm(int serialId); /// /// 获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 IUIForm GetUIForm(string uiFormAssetName); /// /// 获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 IUIForm[] GetUIForms(string uiFormAssetName); /// /// 获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 void GetUIForms(string uiFormAssetName, List results); /// /// 获取所有已加载的界面。 /// /// 所有已加载的界面。 IUIForm[] GetAllLoadedUIForms(); /// /// 获取所有已加载的界面。 /// /// 所有已加载的界面。 void GetAllLoadedUIForms(List results); /// /// 获取所有正在加载界面的序列编号。 /// /// 所有正在加载界面的序列编号。 int[] GetAllLoadingUIFormSerialIds(); /// /// 获取所有正在加载界面的序列编号。 /// /// 所有正在加载界面的序列编号。 void GetAllLoadingUIFormSerialIds(List results); /// /// 是否正在加载界面。 /// /// 界面序列编号。 /// 是否正在加载界面。 bool IsLoadingUIForm(int serialId); /// /// 是否正在加载界面。 /// /// 界面资源名称。 /// 是否正在加载界面。 bool IsLoadingUIForm(string uiFormAssetName); /// /// 是否是合法的界面。 /// /// 界面。 /// 界面是否合法。 bool IsValidUIForm(IUIForm uiForm); /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 界面的序列编号。 int OpenUIForm(string uiFormAssetName, string uiGroupName); /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 加载界面资源的优先级。 /// 界面的序列编号。 int OpenUIForm(string uiFormAssetName, string uiGroupName, int priority); /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 是否暂停被覆盖的界面。 /// 界面的序列编号。 int OpenUIForm(string uiFormAssetName, string uiGroupName, bool pauseCoveredUIForm); /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 用户自定义数据。 /// 界面的序列编号。 int OpenUIForm(string uiFormAssetName, string uiGroupName, object userData); /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 加载界面资源的优先级。 /// 是否暂停被覆盖的界面。 /// 界面的序列编号。 int OpenUIForm(string uiFormAssetName, string uiGroupName, int priority, bool pauseCoveredUIForm); /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 加载界面资源的优先级。 /// 用户自定义数据。 /// 界面的序列编号。 int OpenUIForm(string uiFormAssetName, string uiGroupName, int priority, object userData); /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 是否暂停被覆盖的界面。 /// 用户自定义数据。 /// 界面的序列编号。 int OpenUIForm(string uiFormAssetName, string uiGroupName, bool pauseCoveredUIForm, object userData); /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 加载界面资源的优先级。 /// 是否暂停被覆盖的界面。 /// 用户自定义数据。 /// 界面的序列编号。 int OpenUIForm(string uiFormAssetName, string uiGroupName, int priority, bool pauseCoveredUIForm, object userData); /// /// 关闭界面。 /// /// 要关闭界面的序列编号。 void CloseUIForm(int serialId); /// /// 关闭界面。 /// /// 要关闭界面的序列编号。 /// 用户自定义数据。 void CloseUIForm(int serialId, object userData); /// /// 关闭界面。 /// /// 要关闭的界面。 void CloseUIForm(IUIForm uiForm); /// /// 关闭界面。 /// /// 要关闭的界面。 /// 用户自定义数据。 void CloseUIForm(IUIForm uiForm, object userData); /// /// 关闭所有已加载的界面。 /// void CloseAllLoadedUIForms(); /// /// 关闭所有已加载的界面。 /// /// 用户自定义数据。 void CloseAllLoadedUIForms(object userData); /// /// 关闭所有正在加载的界面。 /// void CloseAllLoadingUIForms(); /// /// 激活界面。 /// /// 要激活的界面。 void RefocusUIForm(IUIForm uiForm); /// /// 激活界面。 /// /// 要激活的界面。 /// 用户自定义数据。 void RefocusUIForm(IUIForm uiForm, object userData); /// /// 设置界面实例是否被加锁。 /// /// 要设置是否被加锁的界面实例。 /// 界面实例是否被加锁。 void SetUIFormInstanceLocked(object uiFormInstance, bool locked); /// /// 设置界面实例的优先级。 /// /// 要设置优先级的界面实例。 /// 界面实例优先级。 void SetUIFormInstancePriority(object uiFormInstance, int priority); } } ================================================ FILE: GameFramework/UI/OpenUIFormDependencyAssetEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.UI { /// /// 打开界面时加载依赖资源事件。 /// public sealed class OpenUIFormDependencyAssetEventArgs : GameFrameworkEventArgs { /// /// 初始化打开界面时加载依赖资源事件的新实例。 /// public OpenUIFormDependencyAssetEventArgs() { SerialId = 0; UIFormAssetName = null; UIGroupName = null; PauseCoveredUIForm = false; DependencyAssetName = null; LoadedCount = 0; TotalCount = 0; UserData = null; } /// /// 获取界面序列编号。 /// public int SerialId { get; private set; } /// /// 获取界面资源名称。 /// public string UIFormAssetName { get; private set; } /// /// 获取界面组名称。 /// public string UIGroupName { get; private set; } /// /// 获取是否暂停被覆盖的界面。 /// public bool PauseCoveredUIForm { get; private set; } /// /// 获取被加载的依赖资源名称。 /// public string DependencyAssetName { get; private set; } /// /// 获取当前已加载依赖资源数量。 /// public int LoadedCount { get; private set; } /// /// 获取总共加载依赖资源数量。 /// public int TotalCount { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建打开界面时加载依赖资源事件。 /// /// 界面序列编号。 /// 界面资源名称。 /// 界面组名称。 /// 是否暂停被覆盖的界面。 /// 被加载的依赖资源名称。 /// 当前已加载依赖资源数量。 /// 总共加载依赖资源数量。 /// 用户自定义数据。 /// 创建的打开界面时加载依赖资源事件。 public static OpenUIFormDependencyAssetEventArgs Create(int serialId, string uiFormAssetName, string uiGroupName, bool pauseCoveredUIForm, string dependencyAssetName, int loadedCount, int totalCount, object userData) { OpenUIFormDependencyAssetEventArgs openUIFormDependencyAssetEventArgs = ReferencePool.Acquire(); openUIFormDependencyAssetEventArgs.SerialId = serialId; openUIFormDependencyAssetEventArgs.UIFormAssetName = uiFormAssetName; openUIFormDependencyAssetEventArgs.UIGroupName = uiGroupName; openUIFormDependencyAssetEventArgs.PauseCoveredUIForm = pauseCoveredUIForm; openUIFormDependencyAssetEventArgs.DependencyAssetName = dependencyAssetName; openUIFormDependencyAssetEventArgs.LoadedCount = loadedCount; openUIFormDependencyAssetEventArgs.TotalCount = totalCount; openUIFormDependencyAssetEventArgs.UserData = userData; return openUIFormDependencyAssetEventArgs; } /// /// 清理打开界面时加载依赖资源事件。 /// public override void Clear() { SerialId = 0; UIFormAssetName = null; UIGroupName = null; PauseCoveredUIForm = false; DependencyAssetName = null; LoadedCount = 0; TotalCount = 0; UserData = null; } } } ================================================ FILE: GameFramework/UI/OpenUIFormFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.UI { /// /// 打开界面失败事件。 /// public sealed class OpenUIFormFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化打开界面失败事件的新实例。 /// public OpenUIFormFailureEventArgs() { SerialId = 0; UIFormAssetName = null; UIGroupName = null; PauseCoveredUIForm = false; ErrorMessage = null; UserData = null; } /// /// 获取界面序列编号。 /// public int SerialId { get; private set; } /// /// 获取界面资源名称。 /// public string UIFormAssetName { get; private set; } /// /// 获取界面组名称。 /// public string UIGroupName { get; private set; } /// /// 获取是否暂停被覆盖的界面。 /// public bool PauseCoveredUIForm { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建打开界面失败事件。 /// /// 界面序列编号。 /// 界面资源名称。 /// 界面组名称。 /// 是否暂停被覆盖的界面。 /// 错误信息。 /// 用户自定义数据。 /// 创建的打开界面失败事件。 public static OpenUIFormFailureEventArgs Create(int serialId, string uiFormAssetName, string uiGroupName, bool pauseCoveredUIForm, string errorMessage, object userData) { OpenUIFormFailureEventArgs openUIFormFailureEventArgs = ReferencePool.Acquire(); openUIFormFailureEventArgs.SerialId = serialId; openUIFormFailureEventArgs.UIFormAssetName = uiFormAssetName; openUIFormFailureEventArgs.UIGroupName = uiGroupName; openUIFormFailureEventArgs.PauseCoveredUIForm = pauseCoveredUIForm; openUIFormFailureEventArgs.ErrorMessage = errorMessage; openUIFormFailureEventArgs.UserData = userData; return openUIFormFailureEventArgs; } /// /// 清理打开界面失败事件。 /// public override void Clear() { SerialId = 0; UIFormAssetName = null; UIGroupName = null; PauseCoveredUIForm = false; ErrorMessage = null; UserData = null; } } } ================================================ FILE: GameFramework/UI/OpenUIFormSuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.UI { /// /// 打开界面成功事件。 /// public sealed class OpenUIFormSuccessEventArgs : GameFrameworkEventArgs { /// /// 初始化打开界面成功事件的新实例。 /// public OpenUIFormSuccessEventArgs() { UIForm = null; Duration = 0f; UserData = null; } /// /// 获取打开成功的界面。 /// public IUIForm UIForm { get; private set; } /// /// 获取加载持续时间。 /// public float Duration { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建打开界面成功事件。 /// /// 加载成功的界面。 /// 加载持续时间。 /// 用户自定义数据。 /// 创建的打开界面成功事件。 public static OpenUIFormSuccessEventArgs Create(IUIForm uiForm, float duration, object userData) { OpenUIFormSuccessEventArgs openUIFormSuccessEventArgs = ReferencePool.Acquire(); openUIFormSuccessEventArgs.UIForm = uiForm; openUIFormSuccessEventArgs.Duration = duration; openUIFormSuccessEventArgs.UserData = userData; return openUIFormSuccessEventArgs; } /// /// 清理打开界面成功事件。 /// public override void Clear() { UIForm = null; Duration = 0f; UserData = null; } } } ================================================ FILE: GameFramework/UI/OpenUIFormUpdateEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.UI { /// /// 打开界面更新事件。 /// public sealed class OpenUIFormUpdateEventArgs : GameFrameworkEventArgs { /// /// 初始化打开界面更新事件的新实例。 /// public OpenUIFormUpdateEventArgs() { SerialId = 0; UIFormAssetName = null; UIGroupName = null; PauseCoveredUIForm = false; Progress = 0f; UserData = null; } /// /// 获取界面序列编号。 /// public int SerialId { get; private set; } /// /// 获取界面资源名称。 /// public string UIFormAssetName { get; private set; } /// /// 获取界面组名称。 /// public string UIGroupName { get; private set; } /// /// 获取是否暂停被覆盖的界面。 /// public bool PauseCoveredUIForm { get; private set; } /// /// 获取打开界面进度。 /// public float Progress { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建打开界面更新事件。 /// /// 界面序列编号。 /// 界面资源名称。 /// 界面组名称。 /// 是否暂停被覆盖的界面。 /// 打开界面进度。 /// 用户自定义数据。 /// 创建的打开界面更新事件。 public static OpenUIFormUpdateEventArgs Create(int serialId, string uiFormAssetName, string uiGroupName, bool pauseCoveredUIForm, float progress, object userData) { OpenUIFormUpdateEventArgs openUIFormUpdateEventArgs = ReferencePool.Acquire(); openUIFormUpdateEventArgs.SerialId = serialId; openUIFormUpdateEventArgs.UIFormAssetName = uiFormAssetName; openUIFormUpdateEventArgs.UIGroupName = uiGroupName; openUIFormUpdateEventArgs.PauseCoveredUIForm = pauseCoveredUIForm; openUIFormUpdateEventArgs.Progress = progress; openUIFormUpdateEventArgs.UserData = userData; return openUIFormUpdateEventArgs; } /// /// 清理打开界面更新事件。 /// public override void Clear() { SerialId = 0; UIFormAssetName = null; UIGroupName = null; PauseCoveredUIForm = false; Progress = 0f; UserData = null; } } } ================================================ FILE: GameFramework/UI/UIManager.OpenUIFormInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.UI { internal sealed partial class UIManager : GameFrameworkModule, IUIManager { private sealed class OpenUIFormInfo : IReference { private int m_SerialId; private UIGroup m_UIGroup; private bool m_PauseCoveredUIForm; private object m_UserData; public OpenUIFormInfo() { m_SerialId = 0; m_UIGroup = null; m_PauseCoveredUIForm = false; m_UserData = null; } public int SerialId { get { return m_SerialId; } } public UIGroup UIGroup { get { return m_UIGroup; } } public bool PauseCoveredUIForm { get { return m_PauseCoveredUIForm; } } public object UserData { get { return m_UserData; } } public static OpenUIFormInfo Create(int serialId, UIGroup uiGroup, bool pauseCoveredUIForm, object userData) { OpenUIFormInfo openUIFormInfo = ReferencePool.Acquire(); openUIFormInfo.m_SerialId = serialId; openUIFormInfo.m_UIGroup = uiGroup; openUIFormInfo.m_PauseCoveredUIForm = pauseCoveredUIForm; openUIFormInfo.m_UserData = userData; return openUIFormInfo; } public void Clear() { m_SerialId = 0; m_UIGroup = null; m_PauseCoveredUIForm = false; m_UserData = null; } } } } ================================================ FILE: GameFramework/UI/UIManager.UIFormInstanceObject.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.ObjectPool; namespace GameFramework.UI { internal sealed partial class UIManager : GameFrameworkModule, IUIManager { /// /// 界面实例对象。 /// private sealed class UIFormInstanceObject : ObjectBase { private object m_UIFormAsset; private IUIFormHelper m_UIFormHelper; public UIFormInstanceObject() { m_UIFormAsset = null; m_UIFormHelper = null; } public static UIFormInstanceObject Create(string name, object uiFormAsset, object uiFormInstance, IUIFormHelper uiFormHelper) { if (uiFormAsset == null) { throw new GameFrameworkException("UI form asset is invalid."); } if (uiFormHelper == null) { throw new GameFrameworkException("UI form helper is invalid."); } UIFormInstanceObject uiFormInstanceObject = ReferencePool.Acquire(); uiFormInstanceObject.Initialize(name, uiFormInstance); uiFormInstanceObject.m_UIFormAsset = uiFormAsset; uiFormInstanceObject.m_UIFormHelper = uiFormHelper; return uiFormInstanceObject; } public override void Clear() { base.Clear(); m_UIFormAsset = null; m_UIFormHelper = null; } protected internal override void Release(bool isShutdown) { m_UIFormHelper.ReleaseUIForm(m_UIFormAsset, Target); } } } } ================================================ FILE: GameFramework/UI/UIManager.UIGroup.UIFormInfo.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.UI { internal sealed partial class UIManager : GameFrameworkModule, IUIManager { private sealed partial class UIGroup : IUIGroup { /// /// 界面组界面信息。 /// private sealed class UIFormInfo : IReference { private IUIForm m_UIForm; private bool m_Paused; private bool m_Covered; public UIFormInfo() { m_UIForm = null; m_Paused = false; m_Covered = false; } public IUIForm UIForm { get { return m_UIForm; } } public bool Paused { get { return m_Paused; } set { m_Paused = value; } } public bool Covered { get { return m_Covered; } set { m_Covered = value; } } public static UIFormInfo Create(IUIForm uiForm) { if (uiForm == null) { throw new GameFrameworkException("UI form is invalid."); } UIFormInfo uiFormInfo = ReferencePool.Acquire(); uiFormInfo.m_UIForm = uiForm; uiFormInfo.m_Paused = true; uiFormInfo.m_Covered = true; return uiFormInfo; } public void Clear() { m_UIForm = null; m_Paused = false; m_Covered = false; } } } } } ================================================ FILE: GameFramework/UI/UIManager.UIGroup.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.Collections.Generic; namespace GameFramework.UI { internal sealed partial class UIManager : GameFrameworkModule, IUIManager { /// /// 界面组。 /// private sealed partial class UIGroup : IUIGroup { private readonly string m_Name; private int m_Depth; private bool m_Pause; private readonly IUIGroupHelper m_UIGroupHelper; private readonly GameFrameworkLinkedList m_UIFormInfos; private LinkedListNode m_CachedNode; /// /// 初始化界面组的新实例。 /// /// 界面组名称。 /// 界面组深度。 /// 界面组辅助器。 public UIGroup(string name, int depth, IUIGroupHelper uiGroupHelper) { if (string.IsNullOrEmpty(name)) { throw new GameFrameworkException("UI group name is invalid."); } if (uiGroupHelper == null) { throw new GameFrameworkException("UI group helper is invalid."); } m_Name = name; m_Pause = false; m_UIGroupHelper = uiGroupHelper; m_UIFormInfos = new GameFrameworkLinkedList(); m_CachedNode = null; Depth = depth; } /// /// 获取界面组名称。 /// public string Name { get { return m_Name; } } /// /// 获取或设置界面组深度。 /// public int Depth { get { return m_Depth; } set { if (m_Depth == value) { return; } m_Depth = value; m_UIGroupHelper.SetDepth(m_Depth); Refresh(); } } /// /// 获取或设置界面组是否暂停。 /// public bool Pause { get { return m_Pause; } set { if (m_Pause == value) { return; } m_Pause = value; Refresh(); } } /// /// 获取界面组中界面数量。 /// public int UIFormCount { get { return m_UIFormInfos.Count; } } /// /// 获取当前界面。 /// public IUIForm CurrentUIForm { get { return m_UIFormInfos.First != null ? m_UIFormInfos.First.Value.UIForm : null; } } /// /// 获取界面组辅助器。 /// public IUIGroupHelper Helper { get { return m_UIGroupHelper; } } /// /// 界面组轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void Update(float elapseSeconds, float realElapseSeconds) { LinkedListNode current = m_UIFormInfos.First; while (current != null) { if (current.Value.Paused) { break; } m_CachedNode = current.Next; current.Value.UIForm.OnUpdate(elapseSeconds, realElapseSeconds); current = m_CachedNode; m_CachedNode = null; } } /// /// 界面组中是否存在界面。 /// /// 界面序列编号。 /// 界面组中是否存在界面。 public bool HasUIForm(int serialId) { foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { if (uiFormInfo.UIForm.SerialId == serialId) { return true; } } return false; } /// /// 界面组中是否存在界面。 /// /// 界面资源名称。 /// 界面组中是否存在界面。 public bool HasUIForm(string uiFormAssetName) { if (string.IsNullOrEmpty(uiFormAssetName)) { throw new GameFrameworkException("UI form asset name is invalid."); } foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { if (uiFormInfo.UIForm.UIFormAssetName == uiFormAssetName) { return true; } } return false; } /// /// 从界面组中获取界面。 /// /// 界面序列编号。 /// 要获取的界面。 public IUIForm GetUIForm(int serialId) { foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { if (uiFormInfo.UIForm.SerialId == serialId) { return uiFormInfo.UIForm; } } return null; } /// /// 从界面组中获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 public IUIForm GetUIForm(string uiFormAssetName) { if (string.IsNullOrEmpty(uiFormAssetName)) { throw new GameFrameworkException("UI form asset name is invalid."); } foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { if (uiFormInfo.UIForm.UIFormAssetName == uiFormAssetName) { return uiFormInfo.UIForm; } } return null; } /// /// 从界面组中获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 public IUIForm[] GetUIForms(string uiFormAssetName) { if (string.IsNullOrEmpty(uiFormAssetName)) { throw new GameFrameworkException("UI form asset name is invalid."); } List results = new List(); foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { if (uiFormInfo.UIForm.UIFormAssetName == uiFormAssetName) { results.Add(uiFormInfo.UIForm); } } return results.ToArray(); } /// /// 从界面组中获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 public void GetUIForms(string uiFormAssetName, List results) { if (string.IsNullOrEmpty(uiFormAssetName)) { throw new GameFrameworkException("UI form asset name is invalid."); } if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { if (uiFormInfo.UIForm.UIFormAssetName == uiFormAssetName) { results.Add(uiFormInfo.UIForm); } } } /// /// 从界面组中获取所有界面。 /// /// 界面组中的所有界面。 public IUIForm[] GetAllUIForms() { List results = new List(); foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { results.Add(uiFormInfo.UIForm); } return results.ToArray(); } /// /// 从界面组中获取所有界面。 /// /// 界面组中的所有界面。 public void GetAllUIForms(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { results.Add(uiFormInfo.UIForm); } } /// /// 往界面组增加界面。 /// /// 要增加的界面。 public void AddUIForm(IUIForm uiForm) { m_UIFormInfos.AddFirst(UIFormInfo.Create(uiForm)); } /// /// 从界面组移除界面。 /// /// 要移除的界面。 public void RemoveUIForm(IUIForm uiForm) { UIFormInfo uiFormInfo = GetUIFormInfo(uiForm); if (uiFormInfo == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find UI form info for serial id '{0}', UI form asset name is '{1}'.", uiForm.SerialId, uiForm.UIFormAssetName)); } if (!uiFormInfo.Covered) { uiFormInfo.Covered = true; uiForm.OnCover(); } if (!uiFormInfo.Paused) { uiFormInfo.Paused = true; uiForm.OnPause(); } if (m_CachedNode != null && m_CachedNode.Value.UIForm == uiForm) { m_CachedNode = m_CachedNode.Next; } if (!m_UIFormInfos.Remove(uiFormInfo)) { throw new GameFrameworkException(Utility.Text.Format("UI group '{0}' not exists specified UI form '[{1}]{2}'.", m_Name, uiForm.SerialId, uiForm.UIFormAssetName)); } ReferencePool.Release(uiFormInfo); } /// /// 激活界面。 /// /// 要激活的界面。 /// 用户自定义数据。 public void RefocusUIForm(IUIForm uiForm, object userData) { UIFormInfo uiFormInfo = GetUIFormInfo(uiForm); if (uiFormInfo == null) { throw new GameFrameworkException("Can not find UI form info."); } m_UIFormInfos.Remove(uiFormInfo); m_UIFormInfos.AddFirst(uiFormInfo); } /// /// 刷新界面组。 /// public void Refresh() { LinkedListNode current = m_UIFormInfos.First; bool pause = m_Pause; bool cover = false; int depth = UIFormCount; while (current != null && current.Value != null) { LinkedListNode next = current.Next; current.Value.UIForm.OnDepthChanged(Depth, depth--); if (current.Value == null) { return; } if (pause) { if (!current.Value.Covered) { current.Value.Covered = true; current.Value.UIForm.OnCover(); if (current.Value == null) { return; } } if (!current.Value.Paused) { current.Value.Paused = true; current.Value.UIForm.OnPause(); if (current.Value == null) { return; } } } else { if (current.Value.Paused) { current.Value.Paused = false; current.Value.UIForm.OnResume(); if (current.Value == null) { return; } } if (current.Value.UIForm.PauseCoveredUIForm) { pause = true; } if (cover) { if (!current.Value.Covered) { current.Value.Covered = true; current.Value.UIForm.OnCover(); if (current.Value == null) { return; } } } else { if (current.Value.Covered) { current.Value.Covered = false; current.Value.UIForm.OnReveal(); if (current.Value == null) { return; } } cover = true; } } current = next; } } internal void InternalGetUIForms(string uiFormAssetName, List results) { foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { if (uiFormInfo.UIForm.UIFormAssetName == uiFormAssetName) { results.Add(uiFormInfo.UIForm); } } } internal void InternalGetAllUIForms(List results) { foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { results.Add(uiFormInfo.UIForm); } } private UIFormInfo GetUIFormInfo(IUIForm uiForm) { if (uiForm == null) { throw new GameFrameworkException("UI form is invalid."); } foreach (UIFormInfo uiFormInfo in m_UIFormInfos) { if (uiFormInfo.UIForm == uiForm) { return uiFormInfo; } } return null; } } } } ================================================ FILE: GameFramework/UI/UIManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using GameFramework.ObjectPool; using GameFramework.Resource; using System; using System.Collections.Generic; namespace GameFramework.UI { /// /// 界面管理器。 /// internal sealed partial class UIManager : GameFrameworkModule, IUIManager { private readonly Dictionary m_UIGroups; private readonly Dictionary m_UIFormsBeingLoaded; private readonly HashSet m_UIFormsToReleaseOnLoad; private readonly Queue m_RecycleQueue; private readonly LoadAssetCallbacks m_LoadAssetCallbacks; private IObjectPoolManager m_ObjectPoolManager; private IResourceManager m_ResourceManager; private IObjectPool m_InstancePool; private IUIFormHelper m_UIFormHelper; private int m_Serial; private bool m_IsShutdown; private EventHandler m_OpenUIFormSuccessEventHandler; private EventHandler m_OpenUIFormFailureEventHandler; private EventHandler m_OpenUIFormUpdateEventHandler; private EventHandler m_OpenUIFormDependencyAssetEventHandler; private EventHandler m_CloseUIFormCompleteEventHandler; /// /// 初始化界面管理器的新实例。 /// public UIManager() { m_UIGroups = new Dictionary(StringComparer.Ordinal); m_UIFormsBeingLoaded = new Dictionary(); m_UIFormsToReleaseOnLoad = new HashSet(); m_RecycleQueue = new Queue(); m_LoadAssetCallbacks = new LoadAssetCallbacks(LoadAssetSuccessCallback, LoadAssetFailureCallback, LoadAssetUpdateCallback, LoadAssetDependencyAssetCallback); m_ObjectPoolManager = null; m_ResourceManager = null; m_InstancePool = null; m_UIFormHelper = null; m_Serial = 0; m_IsShutdown = false; m_OpenUIFormSuccessEventHandler = null; m_OpenUIFormFailureEventHandler = null; m_OpenUIFormUpdateEventHandler = null; m_OpenUIFormDependencyAssetEventHandler = null; m_CloseUIFormCompleteEventHandler = null; } /// /// 获取界面组数量。 /// public int UIGroupCount { get { return m_UIGroups.Count; } } /// /// 获取或设置界面实例对象池自动释放可释放对象的间隔秒数。 /// public float InstanceAutoReleaseInterval { get { return m_InstancePool.AutoReleaseInterval; } set { m_InstancePool.AutoReleaseInterval = value; } } /// /// 获取或设置界面实例对象池的容量。 /// public int InstanceCapacity { get { return m_InstancePool.Capacity; } set { m_InstancePool.Capacity = value; } } /// /// 获取或设置界面实例对象池对象过期秒数。 /// public float InstanceExpireTime { get { return m_InstancePool.ExpireTime; } set { m_InstancePool.ExpireTime = value; } } /// /// 获取或设置界面实例对象池的优先级。 /// public int InstancePriority { get { return m_InstancePool.Priority; } set { m_InstancePool.Priority = value; } } /// /// 打开界面成功事件。 /// public event EventHandler OpenUIFormSuccess { add { m_OpenUIFormSuccessEventHandler += value; } remove { m_OpenUIFormSuccessEventHandler -= value; } } /// /// 打开界面失败事件。 /// public event EventHandler OpenUIFormFailure { add { m_OpenUIFormFailureEventHandler += value; } remove { m_OpenUIFormFailureEventHandler -= value; } } /// /// 打开界面更新事件。 /// public event EventHandler OpenUIFormUpdate { add { m_OpenUIFormUpdateEventHandler += value; } remove { m_OpenUIFormUpdateEventHandler -= value; } } /// /// 打开界面时加载依赖资源事件。 /// public event EventHandler OpenUIFormDependencyAsset { add { m_OpenUIFormDependencyAssetEventHandler += value; } remove { m_OpenUIFormDependencyAssetEventHandler -= value; } } /// /// 关闭界面完成事件。 /// public event EventHandler CloseUIFormComplete { add { m_CloseUIFormCompleteEventHandler += value; } remove { m_CloseUIFormCompleteEventHandler -= value; } } /// /// 界面管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { while (m_RecycleQueue.Count > 0) { IUIForm uiForm = m_RecycleQueue.Dequeue(); uiForm.OnRecycle(); m_InstancePool.Unspawn(uiForm.Handle); } foreach (KeyValuePair uiGroup in m_UIGroups) { uiGroup.Value.Update(elapseSeconds, realElapseSeconds); } } /// /// 关闭并清理界面管理器。 /// internal override void Shutdown() { m_IsShutdown = true; CloseAllLoadedUIForms(); m_UIGroups.Clear(); m_UIFormsBeingLoaded.Clear(); m_UIFormsToReleaseOnLoad.Clear(); m_RecycleQueue.Clear(); } /// /// 设置对象池管理器。 /// /// 对象池管理器。 public void SetObjectPoolManager(IObjectPoolManager objectPoolManager) { if (objectPoolManager == null) { throw new GameFrameworkException("Object pool manager is invalid."); } m_ObjectPoolManager = objectPoolManager; m_InstancePool = m_ObjectPoolManager.CreateSingleSpawnObjectPool("UI Instance Pool"); } /// /// 设置资源管理器。 /// /// 资源管理器。 public void SetResourceManager(IResourceManager resourceManager) { if (resourceManager == null) { throw new GameFrameworkException("Resource manager is invalid."); } m_ResourceManager = resourceManager; } /// /// 设置界面辅助器。 /// /// 界面辅助器。 public void SetUIFormHelper(IUIFormHelper uiFormHelper) { if (uiFormHelper == null) { throw new GameFrameworkException("UI form helper is invalid."); } m_UIFormHelper = uiFormHelper; } /// /// 是否存在界面组。 /// /// 界面组名称。 /// 是否存在界面组。 public bool HasUIGroup(string uiGroupName) { if (string.IsNullOrEmpty(uiGroupName)) { throw new GameFrameworkException("UI group name is invalid."); } return m_UIGroups.ContainsKey(uiGroupName); } /// /// 获取界面组。 /// /// 界面组名称。 /// 要获取的界面组。 public IUIGroup GetUIGroup(string uiGroupName) { if (string.IsNullOrEmpty(uiGroupName)) { throw new GameFrameworkException("UI group name is invalid."); } UIGroup uiGroup = null; if (m_UIGroups.TryGetValue(uiGroupName, out uiGroup)) { return uiGroup; } return null; } /// /// 获取所有界面组。 /// /// 所有界面组。 public IUIGroup[] GetAllUIGroups() { int index = 0; IUIGroup[] results = new IUIGroup[m_UIGroups.Count]; foreach (KeyValuePair uiGroup in m_UIGroups) { results[index++] = uiGroup.Value; } return results; } /// /// 获取所有界面组。 /// /// 所有界面组。 public void GetAllUIGroups(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair uiGroup in m_UIGroups) { results.Add(uiGroup.Value); } } /// /// 增加界面组。 /// /// 界面组名称。 /// 界面组辅助器。 /// 是否增加界面组成功。 public bool AddUIGroup(string uiGroupName, IUIGroupHelper uiGroupHelper) { return AddUIGroup(uiGroupName, 0, uiGroupHelper); } /// /// 增加界面组。 /// /// 界面组名称。 /// 界面组深度。 /// 界面组辅助器。 /// 是否增加界面组成功。 public bool AddUIGroup(string uiGroupName, int uiGroupDepth, IUIGroupHelper uiGroupHelper) { if (string.IsNullOrEmpty(uiGroupName)) { throw new GameFrameworkException("UI group name is invalid."); } if (uiGroupHelper == null) { throw new GameFrameworkException("UI group helper is invalid."); } if (HasUIGroup(uiGroupName)) { return false; } m_UIGroups.Add(uiGroupName, new UIGroup(uiGroupName, uiGroupDepth, uiGroupHelper)); return true; } /// /// 是否存在界面。 /// /// 界面序列编号。 /// 是否存在界面。 public bool HasUIForm(int serialId) { foreach (KeyValuePair uiGroup in m_UIGroups) { if (uiGroup.Value.HasUIForm(serialId)) { return true; } } return false; } /// /// 是否存在界面。 /// /// 界面资源名称。 /// 是否存在界面。 public bool HasUIForm(string uiFormAssetName) { if (string.IsNullOrEmpty(uiFormAssetName)) { throw new GameFrameworkException("UI form asset name is invalid."); } foreach (KeyValuePair uiGroup in m_UIGroups) { if (uiGroup.Value.HasUIForm(uiFormAssetName)) { return true; } } return false; } /// /// 获取界面。 /// /// 界面序列编号。 /// 要获取的界面。 public IUIForm GetUIForm(int serialId) { foreach (KeyValuePair uiGroup in m_UIGroups) { IUIForm uiForm = uiGroup.Value.GetUIForm(serialId); if (uiForm != null) { return uiForm; } } return null; } /// /// 获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 public IUIForm GetUIForm(string uiFormAssetName) { if (string.IsNullOrEmpty(uiFormAssetName)) { throw new GameFrameworkException("UI form asset name is invalid."); } foreach (KeyValuePair uiGroup in m_UIGroups) { IUIForm uiForm = uiGroup.Value.GetUIForm(uiFormAssetName); if (uiForm != null) { return uiForm; } } return null; } /// /// 获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 public IUIForm[] GetUIForms(string uiFormAssetName) { if (string.IsNullOrEmpty(uiFormAssetName)) { throw new GameFrameworkException("UI form asset name is invalid."); } List results = new List(); foreach (KeyValuePair uiGroup in m_UIGroups) { results.AddRange(uiGroup.Value.GetUIForms(uiFormAssetName)); } return results.ToArray(); } /// /// 获取界面。 /// /// 界面资源名称。 /// 要获取的界面。 public void GetUIForms(string uiFormAssetName, List results) { if (string.IsNullOrEmpty(uiFormAssetName)) { throw new GameFrameworkException("UI form asset name is invalid."); } if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair uiGroup in m_UIGroups) { uiGroup.Value.InternalGetUIForms(uiFormAssetName, results); } } /// /// 获取所有已加载的界面。 /// /// 所有已加载的界面。 public IUIForm[] GetAllLoadedUIForms() { List results = new List(); foreach (KeyValuePair uiGroup in m_UIGroups) { results.AddRange(uiGroup.Value.GetAllUIForms()); } return results.ToArray(); } /// /// 获取所有已加载的界面。 /// /// 所有已加载的界面。 public void GetAllLoadedUIForms(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair uiGroup in m_UIGroups) { uiGroup.Value.InternalGetAllUIForms(results); } } /// /// 获取所有正在加载界面的序列编号。 /// /// 所有正在加载界面的序列编号。 public int[] GetAllLoadingUIFormSerialIds() { int index = 0; int[] results = new int[m_UIFormsBeingLoaded.Count]; foreach (KeyValuePair uiFormBeingLoaded in m_UIFormsBeingLoaded) { results[index++] = uiFormBeingLoaded.Key; } return results; } /// /// 获取所有正在加载界面的序列编号。 /// /// 所有正在加载界面的序列编号。 public void GetAllLoadingUIFormSerialIds(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (KeyValuePair uiFormBeingLoaded in m_UIFormsBeingLoaded) { results.Add(uiFormBeingLoaded.Key); } } /// /// 是否正在加载界面。 /// /// 界面序列编号。 /// 是否正在加载界面。 public bool IsLoadingUIForm(int serialId) { return m_UIFormsBeingLoaded.ContainsKey(serialId); } /// /// 是否正在加载界面。 /// /// 界面资源名称。 /// 是否正在加载界面。 public bool IsLoadingUIForm(string uiFormAssetName) { if (string.IsNullOrEmpty(uiFormAssetName)) { throw new GameFrameworkException("UI form asset name is invalid."); } return m_UIFormsBeingLoaded.ContainsValue(uiFormAssetName); } /// /// 是否是合法的界面。 /// /// 界面。 /// 界面是否合法。 public bool IsValidUIForm(IUIForm uiForm) { if (uiForm == null) { return false; } return HasUIForm(uiForm.SerialId); } /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 界面的序列编号。 public int OpenUIForm(string uiFormAssetName, string uiGroupName) { return OpenUIForm(uiFormAssetName, uiGroupName, Constant.DefaultPriority, false, null); } /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 加载界面资源的优先级。 /// 界面的序列编号。 public int OpenUIForm(string uiFormAssetName, string uiGroupName, int priority) { return OpenUIForm(uiFormAssetName, uiGroupName, priority, false, null); } /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 是否暂停被覆盖的界面。 /// 界面的序列编号。 public int OpenUIForm(string uiFormAssetName, string uiGroupName, bool pauseCoveredUIForm) { return OpenUIForm(uiFormAssetName, uiGroupName, Constant.DefaultPriority, pauseCoveredUIForm, null); } /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 用户自定义数据。 /// 界面的序列编号。 public int OpenUIForm(string uiFormAssetName, string uiGroupName, object userData) { return OpenUIForm(uiFormAssetName, uiGroupName, Constant.DefaultPriority, false, userData); } /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 加载界面资源的优先级。 /// 是否暂停被覆盖的界面。 /// 界面的序列编号。 public int OpenUIForm(string uiFormAssetName, string uiGroupName, int priority, bool pauseCoveredUIForm) { return OpenUIForm(uiFormAssetName, uiGroupName, priority, pauseCoveredUIForm, null); } /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 加载界面资源的优先级。 /// 用户自定义数据。 /// 界面的序列编号。 public int OpenUIForm(string uiFormAssetName, string uiGroupName, int priority, object userData) { return OpenUIForm(uiFormAssetName, uiGroupName, priority, false, userData); } /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 是否暂停被覆盖的界面。 /// 用户自定义数据。 /// 界面的序列编号。 public int OpenUIForm(string uiFormAssetName, string uiGroupName, bool pauseCoveredUIForm, object userData) { return OpenUIForm(uiFormAssetName, uiGroupName, Constant.DefaultPriority, pauseCoveredUIForm, userData); } /// /// 打开界面。 /// /// 界面资源名称。 /// 界面组名称。 /// 加载界面资源的优先级。 /// 是否暂停被覆盖的界面。 /// 用户自定义数据。 /// 界面的序列编号。 public int OpenUIForm(string uiFormAssetName, string uiGroupName, int priority, bool pauseCoveredUIForm, object userData) { if (m_ResourceManager == null) { throw new GameFrameworkException("You must set resource manager first."); } if (m_UIFormHelper == null) { throw new GameFrameworkException("You must set UI form helper first."); } if (string.IsNullOrEmpty(uiFormAssetName)) { throw new GameFrameworkException("UI form asset name is invalid."); } if (string.IsNullOrEmpty(uiGroupName)) { throw new GameFrameworkException("UI group name is invalid."); } UIGroup uiGroup = (UIGroup)GetUIGroup(uiGroupName); if (uiGroup == null) { throw new GameFrameworkException(Utility.Text.Format("UI group '{0}' is not exist.", uiGroupName)); } int serialId = ++m_Serial; UIFormInstanceObject uiFormInstanceObject = m_InstancePool.Spawn(uiFormAssetName); if (uiFormInstanceObject == null) { m_UIFormsBeingLoaded.Add(serialId, uiFormAssetName); m_ResourceManager.LoadAsset(uiFormAssetName, priority, m_LoadAssetCallbacks, OpenUIFormInfo.Create(serialId, uiGroup, pauseCoveredUIForm, userData)); } else { InternalOpenUIForm(serialId, uiFormAssetName, uiGroup, uiFormInstanceObject.Target, pauseCoveredUIForm, false, 0f, userData); } return serialId; } /// /// 关闭界面。 /// /// 要关闭界面的序列编号。 public void CloseUIForm(int serialId) { CloseUIForm(serialId, null); } /// /// 关闭界面。 /// /// 要关闭界面的序列编号。 /// 用户自定义数据。 public void CloseUIForm(int serialId, object userData) { if (IsLoadingUIForm(serialId)) { m_UIFormsToReleaseOnLoad.Add(serialId); m_UIFormsBeingLoaded.Remove(serialId); return; } IUIForm uiForm = GetUIForm(serialId); if (uiForm == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find UI form '{0}'.", serialId)); } CloseUIForm(uiForm, userData); } /// /// 关闭界面。 /// /// 要关闭的界面。 public void CloseUIForm(IUIForm uiForm) { CloseUIForm(uiForm, null); } /// /// 关闭界面。 /// /// 要关闭的界面。 /// 用户自定义数据。 public void CloseUIForm(IUIForm uiForm, object userData) { if (uiForm == null) { throw new GameFrameworkException("UI form is invalid."); } UIGroup uiGroup = (UIGroup)uiForm.UIGroup; if (uiGroup == null) { throw new GameFrameworkException("UI group is invalid."); } uiGroup.RemoveUIForm(uiForm); uiForm.OnClose(m_IsShutdown, userData); uiGroup.Refresh(); if (m_CloseUIFormCompleteEventHandler != null) { CloseUIFormCompleteEventArgs closeUIFormCompleteEventArgs = CloseUIFormCompleteEventArgs.Create(uiForm.SerialId, uiForm.UIFormAssetName, uiGroup, userData); m_CloseUIFormCompleteEventHandler(this, closeUIFormCompleteEventArgs); ReferencePool.Release(closeUIFormCompleteEventArgs); } m_RecycleQueue.Enqueue(uiForm); } /// /// 关闭所有已加载的界面。 /// public void CloseAllLoadedUIForms() { CloseAllLoadedUIForms(null); } /// /// 关闭所有已加载的界面。 /// /// 用户自定义数据。 public void CloseAllLoadedUIForms(object userData) { IUIForm[] uiForms = GetAllLoadedUIForms(); foreach (IUIForm uiForm in uiForms) { if (!HasUIForm(uiForm.SerialId)) { continue; } CloseUIForm(uiForm, userData); } } /// /// 关闭所有正在加载的界面。 /// public void CloseAllLoadingUIForms() { foreach (KeyValuePair uiFormBeingLoaded in m_UIFormsBeingLoaded) { m_UIFormsToReleaseOnLoad.Add(uiFormBeingLoaded.Key); } m_UIFormsBeingLoaded.Clear(); } /// /// 激活界面。 /// /// 要激活的界面。 public void RefocusUIForm(IUIForm uiForm) { RefocusUIForm(uiForm, null); } /// /// 激活界面。 /// /// 要激活的界面。 /// 用户自定义数据。 public void RefocusUIForm(IUIForm uiForm, object userData) { if (uiForm == null) { throw new GameFrameworkException("UI form is invalid."); } UIGroup uiGroup = (UIGroup)uiForm.UIGroup; if (uiGroup == null) { throw new GameFrameworkException("UI group is invalid."); } uiGroup.RefocusUIForm(uiForm, userData); uiGroup.Refresh(); uiForm.OnRefocus(userData); } /// /// 设置界面实例是否被加锁。 /// /// 要设置是否被加锁的界面实例。 /// 界面实例是否被加锁。 public void SetUIFormInstanceLocked(object uiFormInstance, bool locked) { if (uiFormInstance == null) { throw new GameFrameworkException("UI form instance is invalid."); } m_InstancePool.SetLocked(uiFormInstance, locked); } /// /// 设置界面实例的优先级。 /// /// 要设置优先级的界面实例。 /// 界面实例优先级。 public void SetUIFormInstancePriority(object uiFormInstance, int priority) { if (uiFormInstance == null) { throw new GameFrameworkException("UI form instance is invalid."); } m_InstancePool.SetPriority(uiFormInstance, priority); } private void InternalOpenUIForm(int serialId, string uiFormAssetName, UIGroup uiGroup, object uiFormInstance, bool pauseCoveredUIForm, bool isNewInstance, float duration, object userData) { try { IUIForm uiForm = m_UIFormHelper.CreateUIForm(uiFormInstance, uiGroup, userData); if (uiForm == null) { throw new GameFrameworkException("Can not create UI form in UI form helper."); } uiForm.OnInit(serialId, uiFormAssetName, uiGroup, pauseCoveredUIForm, isNewInstance, userData); uiGroup.AddUIForm(uiForm); uiForm.OnOpen(userData); uiGroup.Refresh(); if (m_OpenUIFormSuccessEventHandler != null) { OpenUIFormSuccessEventArgs openUIFormSuccessEventArgs = OpenUIFormSuccessEventArgs.Create(uiForm, duration, userData); m_OpenUIFormSuccessEventHandler(this, openUIFormSuccessEventArgs); ReferencePool.Release(openUIFormSuccessEventArgs); } } catch (Exception exception) { if (m_OpenUIFormFailureEventHandler != null) { OpenUIFormFailureEventArgs openUIFormFailureEventArgs = OpenUIFormFailureEventArgs.Create(serialId, uiFormAssetName, uiGroup.Name, pauseCoveredUIForm, exception.ToString(), userData); m_OpenUIFormFailureEventHandler(this, openUIFormFailureEventArgs); ReferencePool.Release(openUIFormFailureEventArgs); return; } throw; } } private void LoadAssetSuccessCallback(string uiFormAssetName, object uiFormAsset, float duration, object userData) { OpenUIFormInfo openUIFormInfo = (OpenUIFormInfo)userData; if (openUIFormInfo == null) { throw new GameFrameworkException("Open UI form info is invalid."); } if (m_UIFormsToReleaseOnLoad.Contains(openUIFormInfo.SerialId)) { m_UIFormsToReleaseOnLoad.Remove(openUIFormInfo.SerialId); ReferencePool.Release(openUIFormInfo); m_UIFormHelper.ReleaseUIForm(uiFormAsset, null); return; } m_UIFormsBeingLoaded.Remove(openUIFormInfo.SerialId); UIFormInstanceObject uiFormInstanceObject = UIFormInstanceObject.Create(uiFormAssetName, uiFormAsset, m_UIFormHelper.InstantiateUIForm(uiFormAsset), m_UIFormHelper); m_InstancePool.Register(uiFormInstanceObject, true); InternalOpenUIForm(openUIFormInfo.SerialId, uiFormAssetName, openUIFormInfo.UIGroup, uiFormInstanceObject.Target, openUIFormInfo.PauseCoveredUIForm, true, duration, openUIFormInfo.UserData); ReferencePool.Release(openUIFormInfo); } private void LoadAssetFailureCallback(string uiFormAssetName, LoadResourceStatus status, string errorMessage, object userData) { OpenUIFormInfo openUIFormInfo = (OpenUIFormInfo)userData; if (openUIFormInfo == null) { throw new GameFrameworkException("Open UI form info is invalid."); } if (m_UIFormsToReleaseOnLoad.Contains(openUIFormInfo.SerialId)) { m_UIFormsToReleaseOnLoad.Remove(openUIFormInfo.SerialId); return; } m_UIFormsBeingLoaded.Remove(openUIFormInfo.SerialId); string appendErrorMessage = Utility.Text.Format("Load UI form failure, asset name '{0}', status '{1}', error message '{2}'.", uiFormAssetName, status, errorMessage); if (m_OpenUIFormFailureEventHandler != null) { OpenUIFormFailureEventArgs openUIFormFailureEventArgs = OpenUIFormFailureEventArgs.Create(openUIFormInfo.SerialId, uiFormAssetName, openUIFormInfo.UIGroup.Name, openUIFormInfo.PauseCoveredUIForm, appendErrorMessage, openUIFormInfo.UserData); m_OpenUIFormFailureEventHandler(this, openUIFormFailureEventArgs); ReferencePool.Release(openUIFormFailureEventArgs); return; } throw new GameFrameworkException(appendErrorMessage); } private void LoadAssetUpdateCallback(string uiFormAssetName, float progress, object userData) { OpenUIFormInfo openUIFormInfo = (OpenUIFormInfo)userData; if (openUIFormInfo == null) { throw new GameFrameworkException("Open UI form info is invalid."); } if (m_OpenUIFormUpdateEventHandler != null) { OpenUIFormUpdateEventArgs openUIFormUpdateEventArgs = OpenUIFormUpdateEventArgs.Create(openUIFormInfo.SerialId, uiFormAssetName, openUIFormInfo.UIGroup.Name, openUIFormInfo.PauseCoveredUIForm, progress, openUIFormInfo.UserData); m_OpenUIFormUpdateEventHandler(this, openUIFormUpdateEventArgs); ReferencePool.Release(openUIFormUpdateEventArgs); } } private void LoadAssetDependencyAssetCallback(string uiFormAssetName, string dependencyAssetName, int loadedCount, int totalCount, object userData) { OpenUIFormInfo openUIFormInfo = (OpenUIFormInfo)userData; if (openUIFormInfo == null) { throw new GameFrameworkException("Open UI form info is invalid."); } if (m_OpenUIFormDependencyAssetEventHandler != null) { OpenUIFormDependencyAssetEventArgs openUIFormDependencyAssetEventArgs = OpenUIFormDependencyAssetEventArgs.Create(openUIFormInfo.SerialId, uiFormAssetName, openUIFormInfo.UIGroup.Name, openUIFormInfo.PauseCoveredUIForm, dependencyAssetName, loadedCount, totalCount, openUIFormInfo.UserData); m_OpenUIFormDependencyAssetEventHandler(this, openUIFormDependencyAssetEventArgs); ReferencePool.Release(openUIFormDependencyAssetEventArgs); } } } } ================================================ FILE: GameFramework/Utility/Utility.Assembly.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework { public static partial class Utility { /// /// 程序集相关的实用函数。 /// public static class Assembly { private static readonly System.Reflection.Assembly[] s_Assemblies = null; private static readonly Dictionary s_CachedTypes = new Dictionary(StringComparer.Ordinal); static Assembly() { s_Assemblies = AppDomain.CurrentDomain.GetAssemblies(); } /// /// 获取已加载的程序集。 /// /// 已加载的程序集。 public static System.Reflection.Assembly[] GetAssemblies() { return s_Assemblies; } /// /// 获取已加载的程序集中的所有类型。 /// /// 已加载的程序集中的所有类型。 public static Type[] GetTypes() { List results = new List(); foreach (System.Reflection.Assembly assembly in s_Assemblies) { results.AddRange(assembly.GetTypes()); } return results.ToArray(); } /// /// 获取已加载的程序集中的所有类型。 /// /// 已加载的程序集中的所有类型。 public static void GetTypes(List results) { if (results == null) { throw new GameFrameworkException("Results is invalid."); } results.Clear(); foreach (System.Reflection.Assembly assembly in s_Assemblies) { results.AddRange(assembly.GetTypes()); } } /// /// 获取已加载的程序集中的指定类型。 /// /// 要获取的类型名。 /// 已加载的程序集中的指定类型。 public static Type GetType(string typeName) { if (string.IsNullOrEmpty(typeName)) { throw new GameFrameworkException("Type name is invalid."); } Type type = null; if (s_CachedTypes.TryGetValue(typeName, out type)) { return type; } type = Type.GetType(typeName); if (type != null) { s_CachedTypes.Add(typeName, type); return type; } foreach (System.Reflection.Assembly assembly in s_Assemblies) { type = Type.GetType(Text.Format("{0}, {1}", typeName, assembly.FullName)); if (type != null) { s_CachedTypes.Add(typeName, type); return type; } } return null; } } } } ================================================ FILE: GameFramework/Utility/Utility.Compression.ICompressionHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.IO; namespace GameFramework { public static partial class Utility { public static partial class Compression { /// /// 压缩解压缩辅助器接口。 /// public interface ICompressionHelper { /// /// 压缩数据。 /// /// 要压缩的数据的二进制流。 /// 要压缩的数据的二进制流的偏移。 /// 要压缩的数据的二进制流的长度。 /// 压缩后的数据的二进制流。 /// 是否压缩数据成功。 bool Compress(byte[] bytes, int offset, int length, Stream compressedStream); /// /// 压缩数据。 /// /// 要压缩的数据的二进制流。 /// 压缩后的数据的二进制流。 /// 是否压缩数据成功。 bool Compress(Stream stream, Stream compressedStream); /// /// 解压缩数据。 /// /// 要解压缩的数据的二进制流。 /// 要解压缩的数据的二进制流的偏移。 /// 要解压缩的数据的二进制流的长度。 /// 解压缩后的数据的二进制流。 /// 是否解压缩数据成功。 bool Decompress(byte[] bytes, int offset, int length, Stream decompressedStream); /// /// 解压缩数据。 /// /// 要解压缩的数据的二进制流。 /// 解压缩后的数据的二进制流。 /// 是否解压缩数据成功。 bool Decompress(Stream stream, Stream decompressedStream); } } } } ================================================ FILE: GameFramework/Utility/Utility.Compression.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.IO; namespace GameFramework { public static partial class Utility { /// /// 压缩解压缩相关的实用函数。 /// public static partial class Compression { private static ICompressionHelper s_CompressionHelper = null; /// /// 设置压缩解压缩辅助器。 /// /// 要设置的压缩解压缩辅助器。 public static void SetCompressionHelper(ICompressionHelper compressionHelper) { s_CompressionHelper = compressionHelper; } /// /// 压缩数据。 /// /// 要压缩的数据的二进制流。 /// 压缩后的数据的二进制流。 public static byte[] Compress(byte[] bytes) { if (bytes == null) { throw new GameFrameworkException("Bytes is invalid."); } return Compress(bytes, 0, bytes.Length); } /// /// 压缩数据。 /// /// 要压缩的数据的二进制流。 /// 压缩后的数据的二进制流。 /// 是否压缩数据成功。 public static bool Compress(byte[] bytes, Stream compressedStream) { if (bytes == null) { throw new GameFrameworkException("Bytes is invalid."); } return Compress(bytes, 0, bytes.Length, compressedStream); } /// /// 压缩数据。 /// /// 要压缩的数据的二进制流。 /// 要压缩的数据的二进制流的偏移。 /// 要压缩的数据的二进制流的长度。 /// 压缩后的数据的二进制流。 public static byte[] Compress(byte[] bytes, int offset, int length) { using (MemoryStream compressedStream = new MemoryStream()) { if (Compress(bytes, offset, length, compressedStream)) { return compressedStream.ToArray(); } else { return null; } } } /// /// 压缩数据。 /// /// 要压缩的数据的二进制流。 /// 要压缩的数据的二进制流的偏移。 /// 要压缩的数据的二进制流的长度。 /// 压缩后的数据的二进制流。 /// 是否压缩数据成功。 public static bool Compress(byte[] bytes, int offset, int length, Stream compressedStream) { if (s_CompressionHelper == null) { throw new GameFrameworkException("Compressed helper is invalid."); } if (bytes == null) { throw new GameFrameworkException("Bytes is invalid."); } if (offset < 0 || length < 0 || offset + length > bytes.Length) { throw new GameFrameworkException("Offset or length is invalid."); } if (compressedStream == null) { throw new GameFrameworkException("Compressed stream is invalid."); } try { return s_CompressionHelper.Compress(bytes, offset, length, compressedStream); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Text.Format("Can not compress with exception '{0}'.", exception), exception); } } /// /// 压缩数据。 /// /// 要压缩的数据的二进制流。 /// 压缩后的数据的二进制流。 public static byte[] Compress(Stream stream) { using (MemoryStream compressedStream = new MemoryStream()) { if (Compress(stream, compressedStream)) { return compressedStream.ToArray(); } else { return null; } } } /// /// 压缩数据。 /// /// 要压缩的数据的二进制流。 /// 压缩后的数据的二进制流。 /// 是否压缩数据成功。 public static bool Compress(Stream stream, Stream compressedStream) { if (s_CompressionHelper == null) { throw new GameFrameworkException("Compressed helper is invalid."); } if (stream == null) { throw new GameFrameworkException("Stream is invalid."); } if (compressedStream == null) { throw new GameFrameworkException("Compressed stream is invalid."); } try { return s_CompressionHelper.Compress(stream, compressedStream); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Text.Format("Can not compress with exception '{0}'.", exception), exception); } } /// /// 解压缩数据。 /// /// 要解压缩的数据的二进制流。 /// 解压缩后的数据的二进制流。 public static byte[] Decompress(byte[] bytes) { if (bytes == null) { throw new GameFrameworkException("Bytes is invalid."); } return Decompress(bytes, 0, bytes.Length); } /// /// 解压缩数据。 /// /// 要解压缩的数据的二进制流。 /// 解压缩后的数据的二进制流。 /// 是否解压缩数据成功。 public static bool Decompress(byte[] bytes, Stream decompressedStream) { if (bytes == null) { throw new GameFrameworkException("Bytes is invalid."); } return Decompress(bytes, 0, bytes.Length, decompressedStream); } /// /// 解压缩数据。 /// /// 要解压缩的数据的二进制流。 /// 要解压缩的数据的二进制流的偏移。 /// 要解压缩的数据的二进制流的长度。 /// 解压缩后的数据的二进制流。 public static byte[] Decompress(byte[] bytes, int offset, int length) { using (MemoryStream decompressedStream = new MemoryStream()) { if (Decompress(bytes, offset, length, decompressedStream)) { return decompressedStream.ToArray(); } else { return null; } } } /// /// 解压缩数据。 /// /// 要解压缩的数据的二进制流。 /// 要解压缩的数据的二进制流的偏移。 /// 要解压缩的数据的二进制流的长度。 /// 解压缩后的数据的二进制流。 /// 是否解压缩数据成功。 public static bool Decompress(byte[] bytes, int offset, int length, Stream decompressedStream) { if (s_CompressionHelper == null) { throw new GameFrameworkException("Compressed helper is invalid."); } if (bytes == null) { throw new GameFrameworkException("Bytes is invalid."); } if (offset < 0 || length < 0 || offset + length > bytes.Length) { throw new GameFrameworkException("Offset or length is invalid."); } if (decompressedStream == null) { throw new GameFrameworkException("Decompressed stream is invalid."); } try { return s_CompressionHelper.Decompress(bytes, offset, length, decompressedStream); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Text.Format("Can not decompress with exception '{0}'.", exception), exception); } } /// /// 解压缩数据。 /// /// 要解压缩的数据的二进制流。 /// 是否解压缩数据成功。 public static byte[] Decompress(Stream stream) { using (MemoryStream decompressedStream = new MemoryStream()) { if (Decompress(stream, decompressedStream)) { return decompressedStream.ToArray(); } else { return null; } } } /// /// 解压缩数据。 /// /// 要解压缩的数据的二进制流。 /// 解压缩后的数据的二进制流。 /// 是否解压缩数据成功。 public static bool Decompress(Stream stream, Stream decompressedStream) { if (s_CompressionHelper == null) { throw new GameFrameworkException("Compressed helper is invalid."); } if (stream == null) { throw new GameFrameworkException("Stream is invalid."); } if (decompressedStream == null) { throw new GameFrameworkException("Decompressed stream is invalid."); } try { return s_CompressionHelper.Decompress(stream, decompressedStream); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Text.Format("Can not decompress with exception '{0}'.", exception), exception); } } } } } ================================================ FILE: GameFramework/Utility/Utility.Converter.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Text; namespace GameFramework { public static partial class Utility { /// /// 类型转换相关的实用函数。 /// public static class Converter { private const float InchesToCentimeters = 2.54f; // 1 inch = 2.54 cm private const float CentimetersToInches = 1f / InchesToCentimeters; // 1 cm = 0.3937 inches /// /// 获取数据在此计算机结构中存储时的字节顺序。 /// public static bool IsLittleEndian { get { return BitConverter.IsLittleEndian; } } /// /// 获取或设置屏幕每英寸点数。 /// public static float ScreenDpi { get; set; } /// /// 将像素转换为厘米。 /// /// 像素。 /// 厘米。 public static float GetCentimetersFromPixels(float pixels) { if (ScreenDpi <= 0) { throw new GameFrameworkException("You must set screen DPI first."); } return InchesToCentimeters * pixels / ScreenDpi; } /// /// 将厘米转换为像素。 /// /// 厘米。 /// 像素。 public static float GetPixelsFromCentimeters(float centimeters) { if (ScreenDpi <= 0) { throw new GameFrameworkException("You must set screen DPI first."); } return CentimetersToInches * centimeters * ScreenDpi; } /// /// 将像素转换为英寸。 /// /// 像素。 /// 英寸。 public static float GetInchesFromPixels(float pixels) { if (ScreenDpi <= 0) { throw new GameFrameworkException("You must set screen DPI first."); } return pixels / ScreenDpi; } /// /// 将英寸转换为像素。 /// /// 英寸。 /// 像素。 public static float GetPixelsFromInches(float inches) { if (ScreenDpi <= 0) { throw new GameFrameworkException("You must set screen DPI first."); } return inches * ScreenDpi; } /// /// 以字节数组的形式获取指定的布尔值。 /// /// 要转换的布尔值。 /// 用于存放结果的字节数组。 public static byte[] GetBytes(bool value) { byte[] buffer = new byte[1]; GetBytes(value, buffer, 0); return buffer; } /// /// 以字节数组的形式获取指定的布尔值。 /// /// 要转换的布尔值。 /// 用于存放结果的字节数组。 public static void GetBytes(bool value, byte[] buffer) { GetBytes(value, buffer, 0); } /// /// 以字节数组的形式获取指定的布尔值。 /// /// 要转换的布尔值。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 public static void GetBytes(bool value, byte[] buffer, int startIndex) { if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } if (startIndex < 0 || startIndex + 1 > buffer.Length) { throw new GameFrameworkException("Start index is invalid."); } buffer[startIndex] = value ? (byte)1 : (byte)0; } /// /// 返回由字节数组中首字节转换来的布尔值。 /// /// 字节数组。 /// 如果 value 中的首字节非零,则为 true,否则为 false。 public static bool GetBoolean(byte[] value) { return BitConverter.ToBoolean(value, 0); } /// /// 返回由字节数组中指定位置的一个字节转换来的布尔值。 /// /// 字节数组。 /// value 内的起始位置。 /// 如果 value 中指定位置的字节非零,则为 true,否则为 false。 public static bool GetBoolean(byte[] value, int startIndex) { return BitConverter.ToBoolean(value, startIndex); } /// /// 以字节数组的形式获取指定的 Unicode 字符值。 /// /// 要转换的字符。 /// 用于存放结果的字节数组。 public static byte[] GetBytes(char value) { byte[] buffer = new byte[2]; GetBytes((short)value, buffer, 0); return buffer; } /// /// 以字节数组的形式获取指定的 Unicode 字符值。 /// /// 要转换的字符。 /// 用于存放结果的字节数组。 public static void GetBytes(char value, byte[] buffer) { GetBytes((short)value, buffer, 0); } /// /// 以字节数组的形式获取指定的 Unicode 字符值。 /// /// 要转换的字符。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 public static void GetBytes(char value, byte[] buffer, int startIndex) { GetBytes((short)value, buffer, startIndex); } /// /// 返回由字节数组中前两个字节转换来的 Unicode 字符。 /// /// 字节数组。 /// 由两个字节构成的字符。 public static char GetChar(byte[] value) { return BitConverter.ToChar(value, 0); } /// /// 返回由字节数组中指定位置的两个字节转换来的 Unicode 字符。 /// /// 字节数组。 /// value 内的起始位置。 /// 由两个字节构成的字符。 public static char GetChar(byte[] value, int startIndex) { return BitConverter.ToChar(value, startIndex); } /// /// 以字节数组的形式获取指定的 16 位有符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static byte[] GetBytes(short value) { byte[] buffer = new byte[2]; GetBytes(value, buffer, 0); return buffer; } /// /// 以字节数组的形式获取指定的 16 位有符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static void GetBytes(short value, byte[] buffer) { GetBytes(value, buffer, 0); } /// /// 以字节数组的形式获取指定的 16 位有符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 public static unsafe void GetBytes(short value, byte[] buffer, int startIndex) { if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } if (startIndex < 0 || startIndex + 2 > buffer.Length) { throw new GameFrameworkException("Start index is invalid."); } fixed (byte* valueRef = buffer) { *(short*)(valueRef + startIndex) = value; } } /// /// 返回由字节数组中前两个字节转换来的 16 位有符号整数。 /// /// 字节数组。 /// 由两个字节构成的 16 位有符号整数。 public static short GetInt16(byte[] value) { return BitConverter.ToInt16(value, 0); } /// /// 返回由字节数组中指定位置的两个字节转换来的 16 位有符号整数。 /// /// 字节数组。 /// value 内的起始位置。 /// 由两个字节构成的 16 位有符号整数。 public static short GetInt16(byte[] value, int startIndex) { return BitConverter.ToInt16(value, startIndex); } /// /// 以字节数组的形式获取指定的 16 位无符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static byte[] GetBytes(ushort value) { byte[] buffer = new byte[2]; GetBytes((short)value, buffer, 0); return buffer; } /// /// 以字节数组的形式获取指定的 16 位无符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static void GetBytes(ushort value, byte[] buffer) { GetBytes((short)value, buffer, 0); } /// /// 以字节数组的形式获取指定的 16 位无符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 public static void GetBytes(ushort value, byte[] buffer, int startIndex) { GetBytes((short)value, buffer, startIndex); } /// /// 返回由字节数组中前两个字节转换来的 16 位无符号整数。 /// /// 字节数组。 /// 由两个字节构成的 16 位无符号整数。 public static ushort GetUInt16(byte[] value) { return BitConverter.ToUInt16(value, 0); } /// /// 返回由字节数组中指定位置的两个字节转换来的 16 位无符号整数。 /// /// 字节数组。 /// value 内的起始位置。 /// 由两个字节构成的 16 位无符号整数。 public static ushort GetUInt16(byte[] value, int startIndex) { return BitConverter.ToUInt16(value, startIndex); } /// /// 以字节数组的形式获取指定的 32 位有符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static byte[] GetBytes(int value) { byte[] buffer = new byte[4]; GetBytes(value, buffer, 0); return buffer; } /// /// 以字节数组的形式获取指定的 32 位有符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static void GetBytes(int value, byte[] buffer) { GetBytes(value, buffer, 0); } /// /// 以字节数组的形式获取指定的 32 位有符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 public static unsafe void GetBytes(int value, byte[] buffer, int startIndex) { if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } if (startIndex < 0 || startIndex + 4 > buffer.Length) { throw new GameFrameworkException("Start index is invalid."); } fixed (byte* valueRef = buffer) { *(int*)(valueRef + startIndex) = value; } } /// /// 返回由字节数组中前四个字节转换来的 32 位有符号整数。 /// /// 字节数组。 /// 由四个字节构成的 32 位有符号整数。 public static int GetInt32(byte[] value) { return BitConverter.ToInt32(value, 0); } /// /// 返回由字节数组中指定位置的四个字节转换来的 32 位有符号整数。 /// /// 字节数组。 /// value 内的起始位置。 /// 由四个字节构成的 32 位有符号整数。 public static int GetInt32(byte[] value, int startIndex) { return BitConverter.ToInt32(value, startIndex); } /// /// 以字节数组的形式获取指定的 32 位无符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static byte[] GetBytes(uint value) { byte[] buffer = new byte[4]; GetBytes((int)value, buffer, 0); return buffer; } /// /// 以字节数组的形式获取指定的 32 位无符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static void GetBytes(uint value, byte[] buffer) { GetBytes((int)value, buffer, 0); } /// /// 以字节数组的形式获取指定的 32 位无符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 public static void GetBytes(uint value, byte[] buffer, int startIndex) { GetBytes((int)value, buffer, startIndex); } /// /// 返回由字节数组中前四个字节转换来的 32 位无符号整数。 /// /// 字节数组。 /// 由四个字节构成的 32 位无符号整数。 public static uint GetUInt32(byte[] value) { return BitConverter.ToUInt32(value, 0); } /// /// 返回由字节数组中指定位置的四个字节转换来的 32 位无符号整数。 /// /// 字节数组。 /// value 内的起始位置。 /// 由四个字节构成的 32 位无符号整数。 public static uint GetUInt32(byte[] value, int startIndex) { return BitConverter.ToUInt32(value, startIndex); } /// /// 以字节数组的形式获取指定的 64 位有符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static byte[] GetBytes(long value) { byte[] buffer = new byte[8]; GetBytes(value, buffer, 0); return buffer; } /// /// 以字节数组的形式获取指定的 64 位有符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static void GetBytes(long value, byte[] buffer) { GetBytes(value, buffer, 0); } /// /// 以字节数组的形式获取指定的 64 位有符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 public static unsafe void GetBytes(long value, byte[] buffer, int startIndex) { if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } if (startIndex < 0 || startIndex + 8 > buffer.Length) { throw new GameFrameworkException("Start index is invalid."); } fixed (byte* valueRef = buffer) { *(long*)(valueRef + startIndex) = value; } } /// /// 返回由字节数组中前八个字节转换来的 64 位有符号整数。 /// /// 字节数组。 /// 由八个字节构成的 64 位有符号整数。 public static long GetInt64(byte[] value) { return BitConverter.ToInt64(value, 0); } /// /// 返回由字节数组中指定位置的八个字节转换来的 64 位有符号整数。 /// /// 字节数组。 /// value 内的起始位置。 /// 由八个字节构成的 64 位有符号整数。 public static long GetInt64(byte[] value, int startIndex) { return BitConverter.ToInt64(value, startIndex); } /// /// 以字节数组的形式获取指定的 64 位无符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static byte[] GetBytes(ulong value) { byte[] buffer = new byte[8]; GetBytes((long)value, buffer, 0); return buffer; } /// /// 以字节数组的形式获取指定的 64 位无符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static void GetBytes(ulong value, byte[] buffer) { GetBytes((long)value, buffer, 0); } /// /// 以字节数组的形式获取指定的 64 位无符号整数值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 public static void GetBytes(ulong value, byte[] buffer, int startIndex) { GetBytes((long)value, buffer, startIndex); } /// /// 返回由字节数组中前八个字节转换来的 64 位无符号整数。 /// /// 字节数组。 /// 由八个字节构成的 64 位无符号整数。 public static ulong GetUInt64(byte[] value) { return BitConverter.ToUInt64(value, 0); } /// /// 返回由字节数组中指定位置的八个字节转换来的 64 位无符号整数。 /// /// 字节数组。 /// value 内的起始位置。 /// 由八个字节构成的 64 位无符号整数。 public static ulong GetUInt64(byte[] value, int startIndex) { return BitConverter.ToUInt64(value, startIndex); } /// /// 以字节数组的形式获取指定的单精度浮点值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static unsafe byte[] GetBytes(float value) { byte[] buffer = new byte[4]; GetBytes(*(int*)&value, buffer, 0); return buffer; } /// /// 以字节数组的形式获取指定的单精度浮点值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static unsafe void GetBytes(float value, byte[] buffer) { GetBytes(*(int*)&value, buffer, 0); } /// /// 以字节数组的形式获取指定的单精度浮点值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 public static unsafe void GetBytes(float value, byte[] buffer, int startIndex) { GetBytes(*(int*)&value, buffer, startIndex); } /// /// 返回由字节数组中前四个字节转换来的单精度浮点数。 /// /// 字节数组。 /// 由四个字节构成的单精度浮点数。 public static float GetSingle(byte[] value) { return BitConverter.ToSingle(value, 0); } /// /// 返回由字节数组中指定位置的四个字节转换来的单精度浮点数。 /// /// 字节数组。 /// value 内的起始位置。 /// 由四个字节构成的单精度浮点数。 public static float GetSingle(byte[] value, int startIndex) { return BitConverter.ToSingle(value, startIndex); } /// /// 以字节数组的形式获取指定的双精度浮点值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static unsafe byte[] GetBytes(double value) { byte[] buffer = new byte[8]; GetBytes(*(long*)&value, buffer, 0); return buffer; } /// /// 以字节数组的形式获取指定的双精度浮点值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 public static unsafe void GetBytes(double value, byte[] buffer) { GetBytes(*(long*)&value, buffer, 0); } /// /// 以字节数组的形式获取指定的双精度浮点值。 /// /// 要转换的数字。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 public static unsafe void GetBytes(double value, byte[] buffer, int startIndex) { GetBytes(*(long*)&value, buffer, startIndex); } /// /// 返回由字节数组中前八个字节转换来的双精度浮点数。 /// /// 字节数组。 /// 由八个字节构成的双精度浮点数。 public static double GetDouble(byte[] value) { return BitConverter.ToDouble(value, 0); } /// /// 返回由字节数组中指定位置的八个字节转换来的双精度浮点数。 /// /// 字节数组。 /// value 内的起始位置。 /// 由八个字节构成的双精度浮点数。 public static double GetDouble(byte[] value, int startIndex) { return BitConverter.ToDouble(value, startIndex); } /// /// 以字节数组的形式获取 UTF-8 编码的字符串。 /// /// 要转换的字符串。 /// 用于存放结果的字节数组。 public static byte[] GetBytes(string value) { return GetBytes(value, Encoding.UTF8); } /// /// 以字节数组的形式获取 UTF-8 编码的字符串。 /// /// 要转换的字符串。 /// 用于存放结果的字节数组。 /// buffer 内实际填充了多少字节。 public static int GetBytes(string value, byte[] buffer) { return GetBytes(value, Encoding.UTF8, buffer, 0); } /// /// 以字节数组的形式获取 UTF-8 编码的字符串。 /// /// 要转换的字符串。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 /// buffer 内实际填充了多少字节。 public static int GetBytes(string value, byte[] buffer, int startIndex) { return GetBytes(value, Encoding.UTF8, buffer, startIndex); } /// /// 以字节数组的形式获取指定编码的字符串。 /// /// 要转换的字符串。 /// 要使用的编码。 /// 用于存放结果的字节数组。 public static byte[] GetBytes(string value, Encoding encoding) { if (value == null) { throw new GameFrameworkException("Value is invalid."); } if (encoding == null) { throw new GameFrameworkException("Encoding is invalid."); } return encoding.GetBytes(value); } /// /// 以字节数组的形式获取指定编码的字符串。 /// /// 要转换的字符串。 /// 要使用的编码。 /// 用于存放结果的字节数组。 /// buffer 内实际填充了多少字节。 public static int GetBytes(string value, Encoding encoding, byte[] buffer) { return GetBytes(value, encoding, buffer, 0); } /// /// 以字节数组的形式获取指定编码的字符串。 /// /// 要转换的字符串。 /// 要使用的编码。 /// 用于存放结果的字节数组。 /// buffer 内的起始位置。 /// buffer 内实际填充了多少字节。 public static int GetBytes(string value, Encoding encoding, byte[] buffer, int startIndex) { if (value == null) { throw new GameFrameworkException("Value is invalid."); } if (encoding == null) { throw new GameFrameworkException("Encoding is invalid."); } return encoding.GetBytes(value, 0, value.Length, buffer, startIndex); } /// /// 返回由字节数组使用 UTF-8 编码转换成的字符串。 /// /// 字节数组。 /// 转换后的字符串。 public static string GetString(byte[] value) { return GetString(value, Encoding.UTF8); } /// /// 返回由字节数组使用指定编码转换成的字符串。 /// /// 字节数组。 /// 要使用的编码。 /// 转换后的字符串。 public static string GetString(byte[] value, Encoding encoding) { if (value == null) { throw new GameFrameworkException("Value is invalid."); } if (encoding == null) { throw new GameFrameworkException("Encoding is invalid."); } return encoding.GetString(value); } /// /// 返回由字节数组使用 UTF-8 编码转换成的字符串。 /// /// 字节数组。 /// value 内的起始位置。 /// 长度。 /// 转换后的字符串。 public static string GetString(byte[] value, int startIndex, int length) { return GetString(value, startIndex, length, Encoding.UTF8); } /// /// 返回由字节数组使用指定编码转换成的字符串。 /// /// 字节数组。 /// value 内的起始位置。 /// 长度。 /// 要使用的编码。 /// 转换后的字符串。 public static string GetString(byte[] value, int startIndex, int length, Encoding encoding) { if (value == null) { throw new GameFrameworkException("Value is invalid."); } if (encoding == null) { throw new GameFrameworkException("Encoding is invalid."); } return encoding.GetString(value, startIndex, length); } } } } ================================================ FILE: GameFramework/Utility/Utility.Encryption.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework { public static partial class Utility { /// /// 加密解密相关的实用函数。 /// public static class Encryption { internal const int QuickEncryptLength = 220; /// /// 将 bytes 使用 code 做异或运算的快速版本。 /// /// 原始二进制流。 /// 异或二进制流。 /// 异或后的二进制流。 public static byte[] GetQuickXorBytes(byte[] bytes, byte[] code) { return GetXorBytes(bytes, 0, QuickEncryptLength, code); } /// /// 将 bytes 使用 code 做异或运算的快速版本。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。 /// /// 原始及异或后的二进制流。 /// 异或二进制流。 public static void GetQuickSelfXorBytes(byte[] bytes, byte[] code) { GetSelfXorBytes(bytes, 0, QuickEncryptLength, code); } /// /// 将 bytes 使用 code 做异或运算。 /// /// 原始二进制流。 /// 异或二进制流。 /// 异或后的二进制流。 public static byte[] GetXorBytes(byte[] bytes, byte[] code) { if (bytes == null) { return null; } return GetXorBytes(bytes, 0, bytes.Length, code); } /// /// 将 bytes 使用 code 做异或运算。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。 /// /// 原始及异或后的二进制流。 /// 异或二进制流。 public static void GetSelfXorBytes(byte[] bytes, byte[] code) { if (bytes == null) { return; } GetSelfXorBytes(bytes, 0, bytes.Length, code); } /// /// 将 bytes 使用 code 做异或运算。 /// /// 原始二进制流。 /// 异或计算的开始位置。 /// 异或计算长度,若小于 0,则计算整个二进制流。 /// 异或二进制流。 /// 异或后的二进制流。 public static byte[] GetXorBytes(byte[] bytes, int startIndex, int length, byte[] code) { if (bytes == null) { return null; } int bytesLength = bytes.Length; byte[] results = new byte[bytesLength]; Array.Copy(bytes, 0, results, 0, bytesLength); GetSelfXorBytes(results, startIndex, length, code); return results; } /// /// 将 bytes 使用 code 做异或运算。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。 /// /// 原始及异或后的二进制流。 /// 异或计算的开始位置。 /// 异或计算长度。 /// 异或二进制流。 public static void GetSelfXorBytes(byte[] bytes, int startIndex, int length, byte[] code) { if (bytes == null) { return; } if (code == null) { throw new GameFrameworkException("Code is invalid."); } int codeLength = code.Length; if (codeLength <= 0) { throw new GameFrameworkException("Code length is invalid."); } if (startIndex < 0 || length < 0 || startIndex + length > bytes.Length) { throw new GameFrameworkException("Start index or length is invalid."); } int codeIndex = startIndex % codeLength; for (int i = startIndex; i < length; i++) { bytes[i] ^= code[codeIndex++]; codeIndex %= codeLength; } } } } } ================================================ FILE: GameFramework/Utility/Utility.Json.IJsonHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework { public static partial class Utility { public static partial class Json { /// /// JSON 辅助器接口。 /// public interface IJsonHelper { /// /// 将对象序列化为 JSON 字符串。 /// /// 要序列化的对象。 /// 序列化后的 JSON 字符串。 string ToJson(object obj); /// /// 将 JSON 字符串反序列化为对象。 /// /// 对象类型。 /// 要反序列化的 JSON 字符串。 /// 反序列化后的对象。 T ToObject(string json); /// /// 将 JSON 字符串反序列化为对象。 /// /// 对象类型。 /// 要反序列化的 JSON 字符串。 /// 反序列化后的对象。 object ToObject(Type objectType, string json); } } } } ================================================ FILE: GameFramework/Utility/Utility.Json.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework { public static partial class Utility { /// /// JSON 相关的实用函数。 /// public static partial class Json { private static IJsonHelper s_JsonHelper = null; /// /// 设置 JSON 辅助器。 /// /// 要设置的 JSON 辅助器。 public static void SetJsonHelper(IJsonHelper jsonHelper) { s_JsonHelper = jsonHelper; } /// /// 将对象序列化为 JSON 字符串。 /// /// 要序列化的对象。 /// 序列化后的 JSON 字符串。 public static string ToJson(object obj) { if (s_JsonHelper == null) { throw new GameFrameworkException("JSON helper is invalid."); } try { return s_JsonHelper.ToJson(obj); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Text.Format("Can not convert to JSON with exception '{0}'.", exception), exception); } } /// /// 将 JSON 字符串反序列化为对象。 /// /// 对象类型。 /// 要反序列化的 JSON 字符串。 /// 反序列化后的对象。 public static T ToObject(string json) { if (s_JsonHelper == null) { throw new GameFrameworkException("JSON helper is invalid."); } try { return s_JsonHelper.ToObject(json); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Text.Format("Can not convert to object with exception '{0}'.", exception), exception); } } /// /// 将 JSON 字符串反序列化为对象。 /// /// 对象类型。 /// 要反序列化的 JSON 字符串。 /// 反序列化后的对象。 public static object ToObject(Type objectType, string json) { if (s_JsonHelper == null) { throw new GameFrameworkException("JSON helper is invalid."); } if (objectType == null) { throw new GameFrameworkException("Object type is invalid."); } try { return s_JsonHelper.ToObject(objectType, json); } catch (Exception exception) { if (exception is GameFrameworkException) { throw; } throw new GameFrameworkException(Text.Format("Can not convert to object with exception '{0}'.", exception), exception); } } } } } ================================================ FILE: GameFramework/Utility/Utility.Marshal.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework { public static partial class Utility { /// /// Marshal 相关的实用函数。 /// public static class Marshal { private const int BlockSize = 1024 * 4; private static IntPtr s_CachedHGlobalPtr = IntPtr.Zero; private static int s_CachedHGlobalSize = 0; /// /// 获取缓存的从进程的非托管内存中分配的内存的大小。 /// public static int CachedHGlobalSize { get { return s_CachedHGlobalSize; } } /// /// 确保从进程的非托管内存中分配足够大小的内存并缓存。 /// /// 要确保从进程的非托管内存中分配内存的大小。 public static void EnsureCachedHGlobalSize(int ensureSize) { if (ensureSize < 0) { throw new GameFrameworkException("Ensure size is invalid."); } if (s_CachedHGlobalPtr == IntPtr.Zero || s_CachedHGlobalSize < ensureSize) { FreeCachedHGlobal(); int size = (ensureSize - 1 + BlockSize) / BlockSize * BlockSize; s_CachedHGlobalPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size); s_CachedHGlobalSize = size; } } /// /// 释放缓存的从进程的非托管内存中分配的内存。 /// public static void FreeCachedHGlobal() { if (s_CachedHGlobalPtr != IntPtr.Zero) { System.Runtime.InteropServices.Marshal.FreeHGlobal(s_CachedHGlobalPtr); s_CachedHGlobalPtr = IntPtr.Zero; s_CachedHGlobalSize = 0; } } /// /// 将数据从对象转换为二进制流。 /// /// 要转换的对象的类型。 /// 要转换的对象。 /// 存储转换结果的二进制流。 public static byte[] StructureToBytes(T structure) { return StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T))); } /// /// 将数据从对象转换为二进制流。 /// /// 要转换的对象的类型。 /// 要转换的对象。 /// 要转换的对象的大小。 /// 存储转换结果的二进制流。 internal static byte[] StructureToBytes(T structure, int structureSize) { if (structureSize < 0) { throw new GameFrameworkException("Structure size is invalid."); } EnsureCachedHGlobalSize(structureSize); System.Runtime.InteropServices.Marshal.StructureToPtr(structure, s_CachedHGlobalPtr, true); byte[] result = new byte[structureSize]; System.Runtime.InteropServices.Marshal.Copy(s_CachedHGlobalPtr, result, 0, structureSize); return result; } /// /// 将数据从对象转换为二进制流。 /// /// 要转换的对象的类型。 /// 要转换的对象。 /// 存储转换结果的二进制流。 public static void StructureToBytes(T structure, byte[] result) { StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, 0); } /// /// 将数据从对象转换为二进制流。 /// /// 要转换的对象的类型。 /// 要转换的对象。 /// 要转换的对象的大小。 /// 存储转换结果的二进制流。 internal static void StructureToBytes(T structure, int structureSize, byte[] result) { StructureToBytes(structure, structureSize, result, 0); } /// /// 将数据从对象转换为二进制流。 /// /// 要转换的对象的类型。 /// 要转换的对象。 /// 存储转换结果的二进制流。 /// 写入存储转换结果的二进制流的起始位置。 public static void StructureToBytes(T structure, byte[] result, int startIndex) { StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, startIndex); } /// /// 将数据从对象转换为二进制流。 /// /// 要转换的对象的类型。 /// 要转换的对象。 /// 要转换的对象的大小。 /// 存储转换结果的二进制流。 /// 写入存储转换结果的二进制流的起始位置。 internal static void StructureToBytes(T structure, int structureSize, byte[] result, int startIndex) { if (structureSize < 0) { throw new GameFrameworkException("Structure size is invalid."); } if (result == null) { throw new GameFrameworkException("Result is invalid."); } if (startIndex < 0) { throw new GameFrameworkException("Start index is invalid."); } if (startIndex + structureSize > result.Length) { throw new GameFrameworkException("Result length is not enough."); } EnsureCachedHGlobalSize(structureSize); System.Runtime.InteropServices.Marshal.StructureToPtr(structure, s_CachedHGlobalPtr, true); System.Runtime.InteropServices.Marshal.Copy(s_CachedHGlobalPtr, result, startIndex, structureSize); } /// /// 将数据从二进制流转换为对象。 /// /// 要转换的对象的类型。 /// 要转换的二进制流。 /// 存储转换结果的对象。 public static T BytesToStructure(byte[] buffer) { return BytesToStructure(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, 0); } /// /// 将数据从二进制流转换为对象。 /// /// 要转换的对象的类型。 /// 要转换的二进制流。 /// 读取要转换的二进制流的起始位置。 /// 存储转换结果的对象。 public static T BytesToStructure(byte[] buffer, int startIndex) { return BytesToStructure(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, startIndex); } /// /// 将数据从二进制流转换为对象。 /// /// 要转换的对象的类型。 /// 要转换的对象的大小。 /// 要转换的二进制流。 /// 存储转换结果的对象。 internal static T BytesToStructure(int structureSize, byte[] buffer) { return BytesToStructure(structureSize, buffer, 0); } /// /// 将数据从二进制流转换为对象。 /// /// 要转换的对象的类型。 /// 要转换的对象的大小。 /// 要转换的二进制流。 /// 读取要转换的二进制流的起始位置。 /// 存储转换结果的对象。 internal static T BytesToStructure(int structureSize, byte[] buffer, int startIndex) { if (structureSize < 0) { throw new GameFrameworkException("Structure size is invalid."); } if (buffer == null) { throw new GameFrameworkException("Buffer is invalid."); } if (startIndex < 0) { throw new GameFrameworkException("Start index is invalid."); } if (startIndex + structureSize > buffer.Length) { throw new GameFrameworkException("Buffer length is not enough."); } EnsureCachedHGlobalSize(structureSize); System.Runtime.InteropServices.Marshal.Copy(buffer, startIndex, s_CachedHGlobalPtr, structureSize); return (T)System.Runtime.InteropServices.Marshal.PtrToStructure(s_CachedHGlobalPtr, typeof(T)); } } } } ================================================ FILE: GameFramework/Utility/Utility.Path.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System.IO; namespace GameFramework { public static partial class Utility { /// /// 路径相关的实用函数。 /// public static class Path { /// /// 获取规范的路径。 /// /// 要规范的路径。 /// 规范的路径。 public static string GetRegularPath(string path) { if (path == null) { return null; } return path.Replace('\\', '/'); } /// /// 获取远程格式的路径(带有file:// 或 http:// 前缀)。 /// /// 原始路径。 /// 远程格式路径。 public static string GetRemotePath(string path) { string regularPath = GetRegularPath(path); if (regularPath == null) { return null; } return regularPath.Contains("://") ? regularPath : ("file:///" + regularPath).Replace("file:////", "file:///"); } /// /// 移除空文件夹。 /// /// 要处理的文件夹名称。 /// 是否移除空文件夹成功。 public static bool RemoveEmptyDirectory(string directoryName) { if (string.IsNullOrEmpty(directoryName)) { throw new GameFrameworkException("Directory name is invalid."); } try { if (!Directory.Exists(directoryName)) { return false; } // 不使用 SearchOption.AllDirectories,以便于在可能产生异常的环境下删除尽可能多的目录 string[] subDirectoryNames = Directory.GetDirectories(directoryName, "*"); int subDirectoryCount = subDirectoryNames.Length; foreach (string subDirectoryName in subDirectoryNames) { if (RemoveEmptyDirectory(subDirectoryName)) { subDirectoryCount--; } } if (subDirectoryCount > 0) { return false; } if (Directory.GetFiles(directoryName, "*").Length > 0) { return false; } Directory.Delete(directoryName); return true; } catch { return false; } } } } } ================================================ FILE: GameFramework/Utility/Utility.Random.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework { public static partial class Utility { /// /// 随机相关的实用函数。 /// public static class Random { private static System.Random s_Random = new System.Random((int)DateTime.UtcNow.Ticks); /// /// 设置随机数种子。 /// /// 随机数种子。 public static void SetSeed(int seed) { s_Random = new System.Random(seed); } /// /// 返回非负随机数。 /// /// 大于等于零且小于 System.Int32.MaxValue 的 32 位带符号整数。 public static int GetRandom() { return s_Random.Next(); } /// /// 返回一个小于所指定最大值的非负随机数。 /// /// 要生成的随机数的上界(随机数不能取该上界值)。maxValue 必须大于等于零。 /// 大于等于零且小于 maxValue 的 32 位带符号整数,即:返回值的范围通常包括零但不包括 maxValue。不过,如果 maxValue 等于零,则返回 maxValue。 public static int GetRandom(int maxValue) { return s_Random.Next(maxValue); } /// /// 返回一个指定范围内的随机数。 /// /// 返回的随机数的下界(随机数可取该下界值)。 /// 返回的随机数的上界(随机数不能取该上界值)。maxValue 必须大于等于 minValue。 /// 一个大于等于 minValue 且小于 maxValue 的 32 位带符号整数,即:返回的值范围包括 minValue 但不包括 maxValue。如果 minValue 等于 maxValue,则返回 minValue。 public static int GetRandom(int minValue, int maxValue) { return s_Random.Next(minValue, maxValue); } /// /// 返回一个介于 0.0 和 1.0 之间的随机数。 /// /// 大于等于 0.0 并且小于 1.0 的双精度浮点数。 public static double GetRandomDouble() { return s_Random.NextDouble(); } /// /// 用随机数填充指定字节数组的元素。 /// /// 包含随机数的字节数组。 public static void GetRandomBytes(byte[] buffer) { s_Random.NextBytes(buffer); } } } } ================================================ FILE: GameFramework/Utility/Utility.Text.ITextHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { public static partial class Utility { public static partial class Text { /// /// 字符辅助器接口。 /// public interface ITextHelper { /// /// 获取格式化字符串。 /// /// 字符串参数的类型。 /// 字符串格式。 /// 字符串参数。 /// 格式化后的字符串。 string Format(string format, T arg); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串参数 12 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 字符串参数 12。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串参数 12 的类型。 /// 字符串参数 13 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 字符串参数 12。 /// 字符串参数 13。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串参数 12 的类型。 /// 字符串参数 13 的类型。 /// 字符串参数 14 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 字符串参数 12。 /// 字符串参数 13。 /// 字符串参数 14。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串参数 12 的类型。 /// 字符串参数 13 的类型。 /// 字符串参数 14 的类型。 /// 字符串参数 15 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 字符串参数 12。 /// 字符串参数 13。 /// 字符串参数 14。 /// 字符串参数 15。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串参数 12 的类型。 /// 字符串参数 13 的类型。 /// 字符串参数 14 的类型。 /// 字符串参数 15 的类型。 /// 字符串参数 16 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 字符串参数 12。 /// 字符串参数 13。 /// 字符串参数 14。 /// 字符串参数 15。 /// 字符串参数 16。 /// 格式化后的字符串。 string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); } } } } ================================================ FILE: GameFramework/Utility/Utility.Text.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { public static partial class Utility { /// /// 字符相关的实用函数。 /// public static partial class Text { private static ITextHelper s_TextHelper = null; /// /// 设置字符辅助器。 /// /// 要设置的字符辅助器。 public static void SetTextHelper(ITextHelper textHelper) { s_TextHelper = textHelper; } /// /// 获取格式化字符串。 /// /// 字符串参数的类型。 /// 字符串格式。 /// 字符串参数。 /// 格式化后的字符串。 public static string Format(string format, T arg) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg); } return s_TextHelper.Format(format, arg); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2); } return s_TextHelper.Format(format, arg1, arg2); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3); } return s_TextHelper.Format(format, arg1, arg2, arg3); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串参数 12 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 字符串参数 12。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串参数 12 的类型。 /// 字符串参数 13 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 字符串参数 12。 /// 字符串参数 13。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串参数 12 的类型。 /// 字符串参数 13 的类型。 /// 字符串参数 14 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 字符串参数 12。 /// 字符串参数 13。 /// 字符串参数 14。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串参数 12 的类型。 /// 字符串参数 13 的类型。 /// 字符串参数 14 的类型。 /// 字符串参数 15 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 字符串参数 12。 /// 字符串参数 13。 /// 字符串参数 14。 /// 字符串参数 15。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); } /// /// 获取格式化字符串。 /// /// 字符串参数 1 的类型。 /// 字符串参数 2 的类型。 /// 字符串参数 3 的类型。 /// 字符串参数 4 的类型。 /// 字符串参数 5 的类型。 /// 字符串参数 6 的类型。 /// 字符串参数 7 的类型。 /// 字符串参数 8 的类型。 /// 字符串参数 9 的类型。 /// 字符串参数 10 的类型。 /// 字符串参数 11 的类型。 /// 字符串参数 12 的类型。 /// 字符串参数 13 的类型。 /// 字符串参数 14 的类型。 /// 字符串参数 15 的类型。 /// 字符串参数 16 的类型。 /// 字符串格式。 /// 字符串参数 1。 /// 字符串参数 2。 /// 字符串参数 3。 /// 字符串参数 4。 /// 字符串参数 5。 /// 字符串参数 6。 /// 字符串参数 7。 /// 字符串参数 8。 /// 字符串参数 9。 /// 字符串参数 10。 /// 字符串参数 11。 /// 字符串参数 12。 /// 字符串参数 13。 /// 字符串参数 14。 /// 字符串参数 15。 /// 字符串参数 16。 /// 格式化后的字符串。 public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) { if (format == null) { throw new GameFrameworkException("Format is invalid."); } if (s_TextHelper == null) { return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); } return s_TextHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); } } } } ================================================ FILE: GameFramework/Utility/Utility.Verifier.Crc32.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { public static partial class Utility { public static partial class Verifier { /// /// CRC32 算法。 /// private sealed class Crc32 { private const int TableLength = 256; private const uint DefaultPolynomial = 0xedb88320; private const uint DefaultSeed = 0xffffffff; private readonly uint m_Seed; private readonly uint[] m_Table; private uint m_Hash; public Crc32() : this(DefaultPolynomial, DefaultSeed) { } public Crc32(uint polynomial, uint seed) { m_Seed = seed; m_Table = InitializeTable(polynomial); m_Hash = seed; } public void Initialize() { m_Hash = m_Seed; } public void HashCore(byte[] bytes, int offset, int length) { m_Hash = CalculateHash(m_Table, m_Hash, bytes, offset, length); } public uint HashFinal() { return ~m_Hash; } private static uint CalculateHash(uint[] table, uint value, byte[] bytes, int offset, int length) { int last = offset + length; for (int i = offset; i < last; i++) { unchecked { value = (value >> 8) ^ table[bytes[i] ^ value & 0xff]; } } return value; } private static uint[] InitializeTable(uint polynomial) { uint[] table = new uint[TableLength]; for (int i = 0; i < TableLength; i++) { uint entry = (uint)i; for (int j = 0; j < 8; j++) { if ((entry & 1) == 1) { entry = (entry >> 1) ^ polynomial; } else { entry >>= 1; } } table[i] = entry; } return table; } } } } } ================================================ FILE: GameFramework/Utility/Utility.Verifier.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.IO; namespace GameFramework { public static partial class Utility { /// /// 校验相关的实用函数。 /// public static partial class Verifier { private const int CachedBytesLength = 0x1000; private static readonly byte[] s_CachedBytes = new byte[CachedBytesLength]; private static readonly Crc32 s_Algorithm = new Crc32(); /// /// 计算二进制流的 CRC32。 /// /// 指定的二进制流。 /// 计算后的 CRC32。 public static int GetCrc32(byte[] bytes) { if (bytes == null) { throw new GameFrameworkException("Bytes is invalid."); } return GetCrc32(bytes, 0, bytes.Length); } /// /// 计算二进制流的 CRC32。 /// /// 指定的二进制流。 /// 二进制流的偏移。 /// 二进制流的长度。 /// 计算后的 CRC32。 public static int GetCrc32(byte[] bytes, int offset, int length) { if (bytes == null) { throw new GameFrameworkException("Bytes is invalid."); } if (offset < 0 || length < 0 || offset + length > bytes.Length) { throw new GameFrameworkException("Offset or length is invalid."); } s_Algorithm.HashCore(bytes, offset, length); int result = (int)s_Algorithm.HashFinal(); s_Algorithm.Initialize(); return result; } /// /// 计算二进制流的 CRC32。 /// /// 指定的二进制流。 /// 计算后的 CRC32。 public static int GetCrc32(Stream stream) { if (stream == null) { throw new GameFrameworkException("Stream is invalid."); } while (true) { int bytesRead = stream.Read(s_CachedBytes, 0, CachedBytesLength); if (bytesRead > 0) { s_Algorithm.HashCore(s_CachedBytes, 0, bytesRead); } else { break; } } int result = (int)s_Algorithm.HashFinal(); s_Algorithm.Initialize(); Array.Clear(s_CachedBytes, 0, CachedBytesLength); return result; } /// /// 获取 CRC32 数值的二进制数组。 /// /// CRC32 数值。 /// CRC32 数值的二进制数组。 public static byte[] GetCrc32Bytes(int crc32) { return new byte[] { (byte)((crc32 >> 24) & 0xff), (byte)((crc32 >> 16) & 0xff), (byte)((crc32 >> 8) & 0xff), (byte)(crc32 & 0xff) }; } /// /// 获取 CRC32 数值的二进制数组。 /// /// CRC32 数值。 /// 要存放结果的数组。 public static void GetCrc32Bytes(int crc32, byte[] bytes) { GetCrc32Bytes(crc32, bytes, 0); } /// /// 获取 CRC32 数值的二进制数组。 /// /// CRC32 数值。 /// 要存放结果的数组。 /// CRC32 数值的二进制数组在结果数组内的起始位置。 public static void GetCrc32Bytes(int crc32, byte[] bytes, int offset) { if (bytes == null) { throw new GameFrameworkException("Result is invalid."); } if (offset < 0 || offset + 4 > bytes.Length) { throw new GameFrameworkException("Offset or length is invalid."); } bytes[offset] = (byte)((crc32 >> 24) & 0xff); bytes[offset + 1] = (byte)((crc32 >> 16) & 0xff); bytes[offset + 2] = (byte)((crc32 >> 8) & 0xff); bytes[offset + 3] = (byte)(crc32 & 0xff); } internal static int GetCrc32(Stream stream, byte[] code, int length) { if (stream == null) { throw new GameFrameworkException("Stream is invalid."); } if (code == null) { throw new GameFrameworkException("Code is invalid."); } int codeLength = code.Length; if (codeLength <= 0) { throw new GameFrameworkException("Code length is invalid."); } int bytesLength = (int)stream.Length; if (length < 0 || length > bytesLength) { length = bytesLength; } int codeIndex = 0; while (true) { int bytesRead = stream.Read(s_CachedBytes, 0, CachedBytesLength); if (bytesRead > 0) { if (length > 0) { for (int i = 0; i < bytesRead && i < length; i++) { s_CachedBytes[i] ^= code[codeIndex++]; codeIndex %= codeLength; } length -= bytesRead; } s_Algorithm.HashCore(s_CachedBytes, 0, bytesRead); } else { break; } } int result = (int)s_Algorithm.HashFinal(); s_Algorithm.Initialize(); Array.Clear(s_CachedBytes, 0, CachedBytesLength); return result; } } } } ================================================ FILE: GameFramework/Utility/Utility.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework { /// /// 实用函数集。 /// public static partial class Utility { } } ================================================ FILE: GameFramework/WebRequest/Constant.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.WebRequest { /// /// Web 请求相关常量。 /// internal static class Constant { /// /// 默认 Web 请求任务优先级。 /// internal const int DefaultPriority = 0; } } ================================================ FILE: GameFramework/WebRequest/IWebRequestAgentHelper.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; namespace GameFramework.WebRequest { /// /// Web 请求代理辅助器接口。 /// public interface IWebRequestAgentHelper { /// /// Web 请求代理辅助器完成事件。 /// event EventHandler WebRequestAgentHelperComplete; /// /// Web 请求代理辅助器错误事件。 /// event EventHandler WebRequestAgentHelperError; /// /// 通过 Web 请求代理辅助器发送 Web 请求。 /// /// Web 请求地址。 /// 用户自定义数据。 void Request(string webRequestUri, object userData); /// /// 通过 Web 请求代理辅助器发送 Web 请求。 /// /// Web 请求地址。 /// 要发送的数据流。 /// 用户自定义数据。 void Request(string webRequestUri, byte[] postData, object userData); /// /// 重置 Web 请求代理辅助器。 /// void Reset(); } } ================================================ FILE: GameFramework/WebRequest/IWebRequestManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.WebRequest { /// /// Web 请求管理器接口。 /// public interface IWebRequestManager { /// /// 获取 Web 请求代理总数量。 /// int TotalAgentCount { get; } /// /// 获取可用 Web 请求代理数量。 /// int FreeAgentCount { get; } /// /// 获取工作中 Web 请求代理数量。 /// int WorkingAgentCount { get; } /// /// 获取等待 Web 请求数量。 /// int WaitingTaskCount { get; } /// /// 获取或设置 Web 请求超时时长,以秒为单位。 /// float Timeout { get; set; } /// /// Web 请求开始事件。 /// event EventHandler WebRequestStart; /// /// Web 请求成功事件。 /// event EventHandler WebRequestSuccess; /// /// Web 请求失败事件。 /// event EventHandler WebRequestFailure; /// /// 增加 Web 请求代理辅助器。 /// /// 要增加的 Web 请求代理辅助器。 void AddWebRequestAgentHelper(IWebRequestAgentHelper webRequestAgentHelper); /// /// 根据 Web 请求任务的序列编号获取 Web 请求任务的信息。 /// /// 要获取信息的 Web 请求任务的序列编号。 /// Web 请求任务的信息。 TaskInfo GetWebRequestInfo(int serialId); /// /// 根据 Web 请求任务的标签获取 Web 请求任务的信息。 /// /// 要获取信息的 Web 请求任务的标签。 /// Web 请求任务的信息。 TaskInfo[] GetWebRequestInfos(string tag); /// /// 根据 Web 请求任务的标签获取 Web 请求任务的信息。 /// /// 要获取信息的 Web 请求任务的标签。 /// Web 请求任务的信息。 void GetAllWebRequestInfos(string tag, List results); /// /// 获取所有 Web 请求任务的信息。 /// /// 所有 Web 请求任务的信息。 TaskInfo[] GetAllWebRequestInfos(); /// /// 获取所有 Web 请求任务的信息。 /// /// 所有 Web 请求任务的信息。 void GetAllWebRequestInfos(List results); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, byte[] postData); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的标签。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, string tag); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的优先级。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, int priority); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, object userData); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的标签。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, byte[] postData, string tag); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的优先级。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, byte[] postData, int priority); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, byte[] postData, object userData); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的标签。 /// Web 请求任务的优先级。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, string tag, int priority); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的标签。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, string tag, object userData); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的优先级。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, int priority, object userData); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的标签。 /// Web 请求任务的优先级。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, byte[] postData, string tag, int priority); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的标签。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, byte[] postData, string tag, object userData); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的优先级。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, byte[] postData, int priority, object userData); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的标签。 /// Web 请求任务的优先级。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, string tag, int priority, object userData); /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的标签。 /// Web 请求任务的优先级。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 int AddWebRequest(string webRequestUri, byte[] postData, string tag, int priority, object userData); /// /// 根据 Web 请求任务的序列编号移除 Web 请求任务。 /// /// 要移除 Web 请求任务的序列编号。 /// 是否移除 Web 请求任务成功。 bool RemoveWebRequest(int serialId); /// /// 根据 Web 请求任务的标签移除 Web 请求任务。 /// /// 要移除 Web 请求任务的标签。 /// 移除 Web 请求任务的数量。 int RemoveWebRequests(string tag); /// /// 移除所有 Web 请求任务。 /// /// 移除 Web 请求任务的数量。 int RemoveAllWebRequests(); } } ================================================ FILE: GameFramework/WebRequest/WebRequestAgentHelperCompleteEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.WebRequest { /// /// Web 请求代理辅助器完成事件。 /// public sealed class WebRequestAgentHelperCompleteEventArgs : GameFrameworkEventArgs { private byte[] m_WebResponseBytes; /// /// 初始化 Web 请求代理辅助器完成事件的新实例。 /// public WebRequestAgentHelperCompleteEventArgs() { m_WebResponseBytes = null; } /// /// 创建 Web 请求代理辅助器完成事件。 /// /// Web 响应的数据流。 /// 创建的 Web 请求代理辅助器完成事件。 public static WebRequestAgentHelperCompleteEventArgs Create(byte[] webResponseBytes) { WebRequestAgentHelperCompleteEventArgs webRequestAgentHelperCompleteEventArgs = ReferencePool.Acquire(); webRequestAgentHelperCompleteEventArgs.m_WebResponseBytes = webResponseBytes; return webRequestAgentHelperCompleteEventArgs; } /// /// 清理 Web 请求代理辅助器完成事件。 /// public override void Clear() { m_WebResponseBytes = null; } /// /// 获取 Web 响应的数据流。 /// /// Web 响应的数据流。 public byte[] GetWebResponseBytes() { return m_WebResponseBytes; } } } ================================================ FILE: GameFramework/WebRequest/WebRequestAgentHelperErrorEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.WebRequest { /// /// Web 请求代理辅助器错误事件。 /// public sealed class WebRequestAgentHelperErrorEventArgs : GameFrameworkEventArgs { /// /// 初始化 Web 请求代理辅助器错误事件的新实例。 /// public WebRequestAgentHelperErrorEventArgs() { ErrorMessage = null; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 创建 Web 请求代理辅助器错误事件。 /// /// 错误信息。 /// 创建的 Web 请求代理辅助器错误事件。 public static WebRequestAgentHelperErrorEventArgs Create(string errorMessage) { WebRequestAgentHelperErrorEventArgs webRequestAgentHelperErrorEventArgs = ReferencePool.Acquire(); webRequestAgentHelperErrorEventArgs.ErrorMessage = errorMessage; return webRequestAgentHelperErrorEventArgs; } /// /// 清理 Web 请求代理辅助器错误事件。 /// public override void Clear() { ErrorMessage = null; } } } ================================================ FILE: GameFramework/WebRequest/WebRequestFailureEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.WebRequest { /// /// Web 请求失败事件。 /// public sealed class WebRequestFailureEventArgs : GameFrameworkEventArgs { /// /// 初始化 Web 请求失败事件的新实例。 /// public WebRequestFailureEventArgs() { SerialId = 0; WebRequestUri = null; ErrorMessage = null; UserData = null; } /// /// 获取 Web 请求任务的序列编号。 /// public int SerialId { get; private set; } /// /// 获取 Web 请求地址。 /// public string WebRequestUri { get; private set; } /// /// 获取错误信息。 /// public string ErrorMessage { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建 Web 请求失败事件。 /// /// Web 请求任务的序列编号。 /// Web 请求地址。 /// 错误信息。 /// 用户自定义数据。 /// 创建的 Web 请求失败事件。 public static WebRequestFailureEventArgs Create(int serialId, string webRequestUri, string errorMessage, object userData) { WebRequestFailureEventArgs webRequestFailureEventArgs = ReferencePool.Acquire(); webRequestFailureEventArgs.SerialId = serialId; webRequestFailureEventArgs.WebRequestUri = webRequestUri; webRequestFailureEventArgs.ErrorMessage = errorMessage; webRequestFailureEventArgs.UserData = userData; return webRequestFailureEventArgs; } /// /// 清理 Web 请求失败事件。 /// public override void Clear() { SerialId = 0; WebRequestUri = null; ErrorMessage = null; UserData = null; } } } ================================================ FILE: GameFramework/WebRequest/WebRequestManager.WebRequestAgent.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.WebRequest { internal sealed partial class WebRequestManager : GameFrameworkModule, IWebRequestManager { /// /// Web 请求代理。 /// private sealed class WebRequestAgent : ITaskAgent { private readonly IWebRequestAgentHelper m_Helper; private WebRequestTask m_Task; private float m_WaitTime; public GameFrameworkAction WebRequestAgentStart; public GameFrameworkAction WebRequestAgentSuccess; public GameFrameworkAction WebRequestAgentFailure; /// /// 初始化 Web 请求代理的新实例。 /// /// Web 请求代理辅助器。 public WebRequestAgent(IWebRequestAgentHelper webRequestAgentHelper) { if (webRequestAgentHelper == null) { throw new GameFrameworkException("Web request agent helper is invalid."); } m_Helper = webRequestAgentHelper; m_Task = null; m_WaitTime = 0f; WebRequestAgentStart = null; WebRequestAgentSuccess = null; WebRequestAgentFailure = null; } /// /// 获取 Web 请求任务。 /// public WebRequestTask Task { get { return m_Task; } } /// /// 获取已经等待时间。 /// public float WaitTime { get { return m_WaitTime; } } /// /// 初始化 Web 请求代理。 /// public void Initialize() { m_Helper.WebRequestAgentHelperComplete += OnWebRequestAgentHelperComplete; m_Helper.WebRequestAgentHelperError += OnWebRequestAgentHelperError; } /// /// Web 请求代理轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 public void Update(float elapseSeconds, float realElapseSeconds) { if (m_Task.Status == WebRequestTaskStatus.Doing) { m_WaitTime += realElapseSeconds; if (m_WaitTime >= m_Task.Timeout) { WebRequestAgentHelperErrorEventArgs webRequestAgentHelperErrorEventArgs = WebRequestAgentHelperErrorEventArgs.Create("Timeout"); OnWebRequestAgentHelperError(this, webRequestAgentHelperErrorEventArgs); ReferencePool.Release(webRequestAgentHelperErrorEventArgs); } } } /// /// 关闭并清理 Web 请求代理。 /// public void Shutdown() { Reset(); m_Helper.WebRequestAgentHelperComplete -= OnWebRequestAgentHelperComplete; m_Helper.WebRequestAgentHelperError -= OnWebRequestAgentHelperError; } /// /// 开始处理 Web 请求任务。 /// /// 要处理的 Web 请求任务。 /// 开始处理任务的状态。 public StartTaskStatus Start(WebRequestTask task) { if (task == null) { throw new GameFrameworkException("Task is invalid."); } m_Task = task; m_Task.Status = WebRequestTaskStatus.Doing; if (WebRequestAgentStart != null) { WebRequestAgentStart(this); } byte[] postData = m_Task.GetPostData(); if (postData == null) { m_Helper.Request(m_Task.WebRequestUri, m_Task.UserData); } else { m_Helper.Request(m_Task.WebRequestUri, postData, m_Task.UserData); } m_WaitTime = 0f; return StartTaskStatus.CanResume; } /// /// 重置 Web 请求代理。 /// public void Reset() { m_Helper.Reset(); m_Task = null; m_WaitTime = 0f; } private void OnWebRequestAgentHelperComplete(object sender, WebRequestAgentHelperCompleteEventArgs e) { m_Helper.Reset(); m_Task.Status = WebRequestTaskStatus.Done; if (WebRequestAgentSuccess != null) { WebRequestAgentSuccess(this, e.GetWebResponseBytes()); } m_Task.Done = true; } private void OnWebRequestAgentHelperError(object sender, WebRequestAgentHelperErrorEventArgs e) { m_Helper.Reset(); m_Task.Status = WebRequestTaskStatus.Error; if (WebRequestAgentFailure != null) { WebRequestAgentFailure(this, e.ErrorMessage); } m_Task.Done = true; } } } } ================================================ FILE: GameFramework/WebRequest/WebRequestManager.WebRequestTask.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.WebRequest { internal sealed partial class WebRequestManager : GameFrameworkModule, IWebRequestManager { /// /// Web 请求任务。 /// private sealed class WebRequestTask : TaskBase { private static int s_Serial = 0; private WebRequestTaskStatus m_Status; private string m_WebRequestUri; private byte[] m_PostData; private float m_Timeout; public WebRequestTask() { m_Status = WebRequestTaskStatus.Todo; m_WebRequestUri = null; m_PostData = null; m_Timeout = 0f; } /// /// 获取或设置 Web 请求任务的状态。 /// public WebRequestTaskStatus Status { get { return m_Status; } set { m_Status = value; } } /// /// 获取要发送的远程地址。 /// public string WebRequestUri { get { return m_WebRequestUri; } } /// /// 获取 Web 请求超时时长,以秒为单位。 /// public float Timeout { get { return m_Timeout; } } /// /// 获取 Web 请求任务的描述。 /// public override string Description { get { return m_WebRequestUri; } } /// /// 创建 Web 请求任务。 /// /// 要发送的远程地址。 /// 要发送的数据流。 /// Web 请求任务的标签。 /// Web 请求任务的优先级。 /// 下载超时时长,以秒为单位。 /// 用户自定义数据。 /// 创建的 Web 请求任务。 public static WebRequestTask Create(string webRequestUri, byte[] postData, string tag, int priority, float timeout, object userData) { WebRequestTask webRequestTask = ReferencePool.Acquire(); webRequestTask.Initialize(++s_Serial, tag, priority, userData); webRequestTask.m_WebRequestUri = webRequestUri; webRequestTask.m_PostData = postData; webRequestTask.m_Timeout = timeout; return webRequestTask; } /// /// 清理 Web 请求任务。 /// public override void Clear() { base.Clear(); m_Status = WebRequestTaskStatus.Todo; m_WebRequestUri = null; m_PostData = null; m_Timeout = 0f; } /// /// 获取要发送的数据流。 /// public byte[] GetPostData() { return m_PostData; } } } } ================================================ FILE: GameFramework/WebRequest/WebRequestManager.WebRequestTaskStatus.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.WebRequest { internal sealed partial class WebRequestManager : GameFrameworkModule, IWebRequestManager { /// /// Web 请求任务的状态。 /// private enum WebRequestTaskStatus : byte { /// /// 准备请求。 /// Todo = 0, /// /// 请求中。 /// Doing, /// /// 请求完成。 /// Done, /// /// 请求错误。 /// Error } } } ================================================ FILE: GameFramework/WebRequest/WebRequestManager.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ using System; using System.Collections.Generic; namespace GameFramework.WebRequest { /// /// Web 请求管理器。 /// internal sealed partial class WebRequestManager : GameFrameworkModule, IWebRequestManager { private readonly TaskPool m_TaskPool; private float m_Timeout; private EventHandler m_WebRequestStartEventHandler; private EventHandler m_WebRequestSuccessEventHandler; private EventHandler m_WebRequestFailureEventHandler; /// /// 初始化 Web 请求管理器的新实例。 /// public WebRequestManager() { m_TaskPool = new TaskPool(); m_Timeout = 30f; m_WebRequestStartEventHandler = null; m_WebRequestSuccessEventHandler = null; m_WebRequestFailureEventHandler = null; } /// /// 获取 Web 请求代理总数量。 /// public int TotalAgentCount { get { return m_TaskPool.TotalAgentCount; } } /// /// 获取可用 Web 请求代理数量。 /// public int FreeAgentCount { get { return m_TaskPool.FreeAgentCount; } } /// /// 获取工作中 Web 请求代理数量。 /// public int WorkingAgentCount { get { return m_TaskPool.WorkingAgentCount; } } /// /// 获取等待 Web 请求数量。 /// public int WaitingTaskCount { get { return m_TaskPool.WaitingTaskCount; } } /// /// 获取或设置 Web 请求超时时长,以秒为单位。 /// public float Timeout { get { return m_Timeout; } set { m_Timeout = value; } } /// /// Web 请求开始事件。 /// public event EventHandler WebRequestStart { add { m_WebRequestStartEventHandler += value; } remove { m_WebRequestStartEventHandler -= value; } } /// /// Web 请求成功事件。 /// public event EventHandler WebRequestSuccess { add { m_WebRequestSuccessEventHandler += value; } remove { m_WebRequestSuccessEventHandler -= value; } } /// /// Web 请求失败事件。 /// public event EventHandler WebRequestFailure { add { m_WebRequestFailureEventHandler += value; } remove { m_WebRequestFailureEventHandler -= value; } } /// /// Web 请求管理器轮询。 /// /// 逻辑流逝时间,以秒为单位。 /// 真实流逝时间,以秒为单位。 internal override void Update(float elapseSeconds, float realElapseSeconds) { m_TaskPool.Update(elapseSeconds, realElapseSeconds); } /// /// 关闭并清理 Web 请求管理器。 /// internal override void Shutdown() { m_TaskPool.Shutdown(); } /// /// 增加 Web 请求代理辅助器。 /// /// 要增加的 Web 请求代理辅助器。 public void AddWebRequestAgentHelper(IWebRequestAgentHelper webRequestAgentHelper) { WebRequestAgent agent = new WebRequestAgent(webRequestAgentHelper); agent.WebRequestAgentStart += OnWebRequestAgentStart; agent.WebRequestAgentSuccess += OnWebRequestAgentSuccess; agent.WebRequestAgentFailure += OnWebRequestAgentFailure; m_TaskPool.AddAgent(agent); } /// /// 根据 Web 请求任务的序列编号获取 Web 请求任务的信息。 /// /// 要获取信息的 Web 请求任务的序列编号。 /// Web 请求任务的信息。 public TaskInfo GetWebRequestInfo(int serialId) { return m_TaskPool.GetTaskInfo(serialId); } /// /// 根据 Web 请求任务的标签获取 Web 请求任务的信息。 /// /// 要获取信息的 Web 请求任务的标签。 /// Web 请求任务的信息。 public TaskInfo[] GetWebRequestInfos(string tag) { return m_TaskPool.GetTaskInfos(tag); } /// /// 根据 Web 请求任务的标签获取 Web 请求任务的信息。 /// /// 要获取信息的 Web 请求任务的标签。 /// Web 请求任务的信息。 public void GetAllWebRequestInfos(string tag, List results) { m_TaskPool.GetTaskInfos(tag, results); } /// /// 获取所有 Web 请求任务的信息。 /// /// 所有 Web 请求任务的信息。 public TaskInfo[] GetAllWebRequestInfos() { return m_TaskPool.GetAllTaskInfos(); } /// /// 获取所有 Web 请求任务的信息。 /// /// 所有 Web 请求任务的信息。 public void GetAllWebRequestInfos(List results) { m_TaskPool.GetAllTaskInfos(results); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri) { return AddWebRequest(webRequestUri, null, null, Constant.DefaultPriority, null); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, byte[] postData) { return AddWebRequest(webRequestUri, postData, null, Constant.DefaultPriority, null); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的标签。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, string tag) { return AddWebRequest(webRequestUri, null, tag, Constant.DefaultPriority, null); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的优先级。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, int priority) { return AddWebRequest(webRequestUri, null, null, priority, null); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, object userData) { return AddWebRequest(webRequestUri, null, null, Constant.DefaultPriority, userData); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的标签。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, byte[] postData, string tag) { return AddWebRequest(webRequestUri, postData, tag, Constant.DefaultPriority, null); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的优先级。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, byte[] postData, int priority) { return AddWebRequest(webRequestUri, postData, null, priority, null); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, byte[] postData, object userData) { return AddWebRequest(webRequestUri, postData, null, Constant.DefaultPriority, userData); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的标签。 /// Web 请求任务的优先级。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, string tag, int priority) { return AddWebRequest(webRequestUri, null, tag, priority, null); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的标签。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, string tag, object userData) { return AddWebRequest(webRequestUri, null, tag, Constant.DefaultPriority, userData); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的优先级。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, int priority, object userData) { return AddWebRequest(webRequestUri, null, null, priority, userData); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的标签。 /// Web 请求任务的优先级。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, byte[] postData, string tag, int priority) { return AddWebRequest(webRequestUri, postData, tag, priority, null); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的标签。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, byte[] postData, string tag, object userData) { return AddWebRequest(webRequestUri, postData, tag, Constant.DefaultPriority, userData); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的优先级。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, byte[] postData, int priority, object userData) { return AddWebRequest(webRequestUri, postData, null, priority, userData); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// Web 请求任务的标签。 /// Web 请求任务的优先级。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, string tag, int priority, object userData) { return AddWebRequest(webRequestUri, null, tag, priority, userData); } /// /// 增加 Web 请求任务。 /// /// Web 请求地址。 /// 要发送的数据流。 /// Web 请求任务的标签。 /// Web 请求任务的优先级。 /// 用户自定义数据。 /// 新增 Web 请求任务的序列编号。 public int AddWebRequest(string webRequestUri, byte[] postData, string tag, int priority, object userData) { if (string.IsNullOrEmpty(webRequestUri)) { throw new GameFrameworkException("Web request uri is invalid."); } if (TotalAgentCount <= 0) { throw new GameFrameworkException("You must add web request agent first."); } WebRequestTask webRequestTask = WebRequestTask.Create(webRequestUri, postData, tag, priority, m_Timeout, userData); m_TaskPool.AddTask(webRequestTask); return webRequestTask.SerialId; } /// /// 根据 Web 请求任务的序列编号移除 Web 请求任务。 /// /// 要移除 Web 请求任务的序列编号。 /// 是否移除 Web 请求任务成功。 public bool RemoveWebRequest(int serialId) { return m_TaskPool.RemoveTask(serialId); } /// /// 根据 Web 请求任务的标签移除 Web 请求任务。 /// /// 要移除 Web 请求任务的标签。 /// 移除 Web 请求任务的数量。 public int RemoveWebRequests(string tag) { return m_TaskPool.RemoveTasks(tag); } /// /// 移除所有 Web 请求任务。 /// /// 移除 Web 请求任务的数量。 public int RemoveAllWebRequests() { return m_TaskPool.RemoveAllTasks(); } private void OnWebRequestAgentStart(WebRequestAgent sender) { if (m_WebRequestStartEventHandler != null) { WebRequestStartEventArgs webRequestStartEventArgs = WebRequestStartEventArgs.Create(sender.Task.SerialId, sender.Task.WebRequestUri, sender.Task.UserData); m_WebRequestStartEventHandler(this, webRequestStartEventArgs); ReferencePool.Release(webRequestStartEventArgs); } } private void OnWebRequestAgentSuccess(WebRequestAgent sender, byte[] webResponseBytes) { if (m_WebRequestSuccessEventHandler != null) { WebRequestSuccessEventArgs webRequestSuccessEventArgs = WebRequestSuccessEventArgs.Create(sender.Task.SerialId, sender.Task.WebRequestUri, webResponseBytes, sender.Task.UserData); m_WebRequestSuccessEventHandler(this, webRequestSuccessEventArgs); ReferencePool.Release(webRequestSuccessEventArgs); } } private void OnWebRequestAgentFailure(WebRequestAgent sender, string errorMessage) { if (m_WebRequestFailureEventHandler != null) { WebRequestFailureEventArgs webRequestFailureEventArgs = WebRequestFailureEventArgs.Create(sender.Task.SerialId, sender.Task.WebRequestUri, errorMessage, sender.Task.UserData); m_WebRequestFailureEventHandler(this, webRequestFailureEventArgs); ReferencePool.Release(webRequestFailureEventArgs); } } } } ================================================ FILE: GameFramework/WebRequest/WebRequestStartEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.WebRequest { /// /// Web 请求开始事件。 /// public sealed class WebRequestStartEventArgs : GameFrameworkEventArgs { /// /// 初始化 Web 请求开始事件的新实例。 /// public WebRequestStartEventArgs() { SerialId = 0; WebRequestUri = null; UserData = null; } /// /// 获取 Web 请求任务的序列编号。 /// public int SerialId { get; private set; } /// /// 获取 Web 请求地址。 /// public string WebRequestUri { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建 Web 请求开始事件。 /// /// Web 请求任务的序列编号。 /// Web 请求地址。 /// 用户自定义数据。 /// 创建的 Web 请求开始事件。 public static WebRequestStartEventArgs Create(int serialId, string webRequestUri, object userData) { WebRequestStartEventArgs webRequestStartEventArgs = ReferencePool.Acquire(); webRequestStartEventArgs.SerialId = serialId; webRequestStartEventArgs.WebRequestUri = webRequestUri; webRequestStartEventArgs.UserData = userData; return webRequestStartEventArgs; } /// /// 清理 Web 请求开始事件。 /// public override void Clear() { SerialId = 0; WebRequestUri = null; UserData = null; } } } ================================================ FILE: GameFramework/WebRequest/WebRequestSuccessEventArgs.cs ================================================ //------------------------------------------------------------ // Game Framework // Copyright © 2013-2021 Jiang Yin. All rights reserved. // Homepage: https://gameframework.cn/ // Feedback: mailto:ellan@gameframework.cn //------------------------------------------------------------ namespace GameFramework.WebRequest { /// /// Web 请求成功事件。 /// public sealed class WebRequestSuccessEventArgs : GameFrameworkEventArgs { private byte[] m_WebResponseBytes; /// /// 初始化 Web 请求成功事件的新实例。 /// public WebRequestSuccessEventArgs() { SerialId = 0; WebRequestUri = null; m_WebResponseBytes = null; UserData = null; } /// /// 获取 Web 请求任务的序列编号。 /// public int SerialId { get; private set; } /// /// 获取 Web 请求地址。 /// public string WebRequestUri { get; private set; } /// /// 获取用户自定义数据。 /// public object UserData { get; private set; } /// /// 创建 Web 请求成功事件。 /// /// Web 请求任务的序列编号。 /// Web 请求地址。 /// Web 响应的数据流。 /// 用户自定义数据。 /// 创建的 Web 请求成功事件。 public static WebRequestSuccessEventArgs Create(int serialId, string webRequestUri, byte[] webResponseBytes, object userData) { WebRequestSuccessEventArgs webRequestSuccessEventArgs = ReferencePool.Acquire(); webRequestSuccessEventArgs.SerialId = serialId; webRequestSuccessEventArgs.WebRequestUri = webRequestUri; webRequestSuccessEventArgs.m_WebResponseBytes = webResponseBytes; webRequestSuccessEventArgs.UserData = userData; return webRequestSuccessEventArgs; } /// /// 清理 Web 请求成功事件。 /// public override void Clear() { SerialId = 0; WebRequestUri = null; m_WebResponseBytes = null; UserData = null; } /// /// 获取 Web 响应的数据流。 /// /// Web 响应的数据流。 public byte[] GetWebResponseBytes() { return m_WebResponseBytes; } } } ================================================ FILE: GameFramework.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28803.202 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFramework", "GameFramework\GameFramework.csproj", "{109D7F39-79AB-4862-9F73-0B8C638930C6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {109D7F39-79AB-4862-9F73-0B8C638930C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {109D7F39-79AB-4862-9F73-0B8C638930C6}.Debug|Any CPU.Build.0 = Debug|Any CPU {109D7F39-79AB-4862-9F73-0B8C638930C6}.Release|Any CPU.ActiveCfg = Release|Any CPU {109D7F39-79AB-4862-9F73-0B8C638930C6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C9FE37CC-C19B-4C35-A093-03578C567222} EndGlobalSection EndGlobal ================================================ FILE: LICENSE.md ================================================ MIT License Copyright (c) 2013-2021 Jiang Yin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ## HOMEPAGE - **English** - Coming soon. - **简体中文** - [https://gameframework.cn/](https://gameframework.cn/) - **QQ 讨论群** 216332935 --- ![Game Framework](https://gameframework.cn/image/gameframework.png) --- ## Game Framework 简介 Game Framework 是一个基于 Unity 引擎的游戏框架,主要对游戏开发过程中常用模块进行了封装,很大程度地规范开发过程、加快开发速度并保证产品质量。 在最新的 Game Framework 版本中,包含以下 19 个内置模块,后续我们还将开发更多的扩展模块供开发者使用。 1. **全局配置 (Config)** - 存储一些全局的只读的游戏配置,如玩家初始速度、游戏初始音量等。 2. **数据结点 (Data Node)** - 将任意类型的数据以树状结构的形式进行保存,用于管理游戏运行时的各种数据。 3. **数据表 (Data Table)** - 可以将游戏数据以表格(如 Microsoft Excel)的形式进行配置后,使用此模块使用这些数据表。数据表的格式是可以自定义的。 4. **调试器 (Debugger)** - 当游戏在 Unity 编辑器中运行或者以 Development 方式发布运行时,将出现调试器窗口,便于查看运行时日志、调试信息等。用户还可以方便地将自己的功能注册到调试器窗口上并使用。 5. **下载 (Download)** - 提供下载文件的功能,支持断点续传,并可指定允许几个下载器进行同时下载。更新资源时会主动调用此模块。 6. **实体 (Entity)** - 我们将游戏场景中,动态创建的一切物体定义为实体。此模块提供管理实体和实体组的功能,如显示隐藏实体、挂接实体(如挂接武器、坐骑,或者抓起另一个实体)等。实体使用结束后可以不立刻销毁,从而等待下一次重新使用。 7. **事件 (Event)** - 游戏逻辑监听、抛出事件的机制。Game Framework 中的很多模块在完成操作后都会抛出内置事件,监听这些事件将大大解除游戏逻辑之间的耦合。用户也可以定义自己的游戏逻辑事件。 8. **文件系统 (File System)** - 虚拟文件系统使用类似磁盘的概念对零散文件进行集中管理,优化资源加载时产生的内存分配,甚至可以对资源进行局部片段加载,这些都将极大提升资源加载时的性能。 9. **有限状态机 (FSM)** - 提供创建、使用和销毁有限状态机的功能,一些适用于有限状态机机制的游戏逻辑,使用此模块将是一个不错的选择。 10. **本地化 (Localization)** - 提供本地化功能,也就是我们平时所说的多语言。Game Framework 在本地化方面,不但支持文本的本地化,还支持任意资源的本地化,比如游戏中释放烟花特效也可以做出几个多国语言的版本,使得中文版里是“新年好”字样的特效,而英文版里是“Happy New Year”字样的特效。 11. **网络 (Network)** - 提供使用 Socket 长连接的功能,当前我们支持 TCP 协议,同时兼容 IPv4 和 IPv6 两个版本。用户可以同时建立多个连接与多个服务器同时进行通信,比如除了连接常规的游戏服务器,还可以连接语音聊天服务器。如果想接入 ProtoBuf 之类的协议库,只要派生自 Packet 类并实现自己的消息包类即可使用。 12. **对象池 (Object Pool)** - 提供对象缓存池的功能,避免频繁地创建和销毁各种游戏对象,提高游戏性能。除了 Game Framework 自身使用了对象池,用户还可以很方便地创建和管理自己的对象池。 13. **流程 (Procedure)** - 是贯穿游戏运行时整个生命周期的有限状态机。通过流程,将不同的游戏状态进行解耦将是一个非常好的习惯。对于网络游戏,你可能需要如检查资源流程、更新资源流程、检查服务器列表流程、选择服务器流程、登录服务器流程、创建角色流程等流程,而对于单机游戏,你可能需要在游戏选择菜单流程和游戏实际玩法流程之间做切换。如果想增加流程,只要派生自 ProcedureBase 类并实现自己的流程类即可使用。 14. **资源 (Resource)** - 为了保证玩家的体验,我们不推荐再使用同步的方式加载资源,由于 Game Framework 自身使用了一套完整的异步加载资源体系,因此只提供了异步加载资源的接口。不论简单的数据表、本地化字典,还是复杂的实体、场景、界面,我们都将使用异步加载。同时,Game Framework 提供了默认的内存管理策略(当然,你也可以定义自己的内存管理策略)。多数情况下,在使用 GameObject 的过程中,你甚至可以不需要自行进行 Instantiate 或者是 Destroy 操作。 15. **场景 (Scene)** - 提供场景管理的功能,可以同时加载多个场景,也可以随时卸载任何一个场景,从而很容易地实现场景的分部加载。 16. **配置 (Setting)** - 以键值对的形式存储玩家数据,对 UnityEngine.PlayerPrefs 进行封装,也可以将这些数据直接存储在磁盘上。 17. **声音 (Sound)** - 提供管理声音和声音组的功能,用户可以自定义一个声音的音量、是 2D 声音还是 3D 声音,甚至是直接绑定到某个实体上跟随实体移动。 18. **界面 (UI)** - 提供管理界面和界面组的功能,如显示隐藏界面、激活界面、改变界面层级等。不论是 Unity 内置的 uGUI 还是其它类型的 UI 插件(如 NGUI),只要派生自 UIFormLogic 类并实现自己的界面类即可使用。界面使用结束后可以不立刻销毁,从而等待下一次重新使用。 19. **Web 请求 (Web Request)** - 提供使用短连接的功能,可以用 Get 或者 Post 方法向服务器发送请求并获取响应数据,可指定允许几个 Web 请求器进行同时请求。 --- ## INTRODUCTION Game Framework is literally a game framework, based on Unity game engine. It encapsulates commonly used game modules during development, and, to a large degree, standardises the process, enhances the development speed and ensures the product quality. Game Framework provides the following 19 builtin modules, and more will be developed later for game developers to use. 1. **Config** - saves some global read-only game configurations, such as the player's initial speed, the initial volume of the game, etc. 2. **Data Node** - saves arbitrary types of data within tree structures in order to manage various data during game runtime. 3. **Data Table** - is intended to invoke game data in the form of pre-configured tables (such as Microsoft Excel sheets). The format of the tables can be customised. 4. **Debugger** - displays a debugger window when the game runs in the Unity Editor or in a development build, to facilitate the viewing of runtime logs and debug messages. The user can register their own features to the debugger windows and use them conveniently. 5. **Download** - provides the ability to download files. The user is free to set how many downloaders could be used simultaneously. 6. **Entity** - provides the ability to manage entities and groups of entities, where an entity is defined as any dynamically created objects in the game scene. It shows or hides entities, attach one entity to another (such as weapons, horses or snatching up another entity). Entities could avoid being destroyed instantly after use, and hence be recycled for reuse. 7. **Event** - gives the mechanism for the game logic to fire or observe events. Many modules in the Game Framework fires events after operations, and observing these events will largely decouple game logic modules. The user can define his own game logic events, too. 8. **File System** - the virtual file system, based on the concept of disks, manages scattered files in a centralized way, optimizes memory allocation when resources are loaded, and can even load segments of resources. These will drastically enhance the performance of resource loading. 9. **FSM** - provides the ability to create, use and destroy finite state machines. It’d be a good choice to use this module for some state-machine-like game logic. 10. **Localization** - provides the ability to localise the game. Game Framework not only supports the localisation of texts, but also assets of all kinds. For example, a firework effect in the game can be localised as various versions, so that the player will see a "新年好" - like effect in the Chinese version, while "Happy New Year" - like in the English version. 11. **Network** - provides socket connections where TCP is currently supported and both IPv4 and IPv6 are valid. The user can establish several connections to different servers at the same time. For example, the user can connect to a normal game server, and another server for voice chat. The 'Packet' class is ready for inheritance and implemented if the user wants to take use of protocol libraries such as ProtoBuf. 12. **Object Pool** - provides the ability to cache objects in pools. It avoids frequent creation and destruction operations of game objects, and hence improves the game performance. Game Framework itself uses object pools, and the user could conveniently create and manage his own pools. 13. **Procedure** - is in fact an FSM of the whole lifecycle of the game. It’d be a very good habit to decouple different game states via procedures. For a network game, you probably need procedures of checking resources, updating resources, checking the server list, selecting a server, logging in a server and creating avatars. For a standalone game, you perhaps need to switch between procedures of the menu and the real gameplay. The user could add procedures by simply subclassing and implementing the 'ProcedureBase' class. 14. **Resource** - provides only asynchronous interfaces to load resources. We don’t recommend synchronous approaches for better play experience, and Game Framework itself uses a complete system of asynchronous resource loading. We load everything asynchronously, including simple things like data tables and localisation texts, and complex things like entities, scenes and UIs. Meanwhile, Game Framework provides default strategies of memory management (and of course, you could define your own strategies). In most cases, you don't even need to call 'Instantiate' or 'Destroy' when using 'GameObject' instances. 15. **Scene** - provides features to manage scenes. It supports simultaneous loading of multiple scenes, and the user is allowed to unload a scene at any time. Therefore partial loading/unloading of scenes could be easily implemented. 16. **Setting** - stores player data in key-value pairs by either encapsulating UnityEngine.PlayerPrefs or by saving the data directly to the disk. 17. **Sound** - provides features to manage sounds and groups of sounds. The user could set the properties of an audio clip, such as the volume, whether the clip is 2D or 3D, and could even bind the clip to some entity to follow its position. 18. **UI** - provides features to manage user interfaces and groups of UIs, such as showing or hiding, activating or deactivating, and depth changing. No matter the user uses the builtin uGUI in Unity or other UI plugins (NGUI, for example), he only needs to subclass 'UIFormLogic' and implement his own UI logic. The UIs could avoid being destroyed instantly after use, and hence be recycled for reuse. 19. **Web Request** - provides features of short connections, supports GET and POST methods to send requests to the server and acquire the response data, and allows the user to send simultaneous requests to different servers.