GameFrameWork学习笔记(四)

一、序列化器

       除了事件以及回调以外还有序列化器。所有类型的序列化器都是继承了泛型抽象类GameFrameworkSerializer

public abstract class GameFrameworkSerializer<T>
    {
        private readonly Dictionary<byte, SerializeCallback> m_SerializeCallbacks;
        private readonly Dictionary<byte, DeserializeCallback> m_DeserializeCallbacks;
        private readonly Dictionary<byte, TryGetValueCallback> m_TryGetValueCallbacks;
        private byte m_LatestSerializeCallbackVersion;

        /// <summary>
        /// 初始化游戏框架序列化器基类的新实例。
        /// </summary>
        public GameFrameworkSerializer()
        {
            m_SerializeCallbacks = new Dictionary<byte, SerializeCallback>();
            m_DeserializeCallbacks = new Dictionary<byte, DeserializeCallback>();
            m_TryGetValueCallbacks = new Dictionary<byte, TryGetValueCallback>();
            m_LatestSerializeCallbackVersion = 0;
        }

        /// <summary>
        /// 序列化回调函数。
        /// </summary>
        /// <param name="stream">目标流。</param>
        /// <param name="data">要序列化的数据。</param>
        /// <returns>是否序列化数据成功。</returns>
        public delegate bool SerializeCallback(Stream stream, T data);

        /// <summary>
        /// 反序列化回调函数。
        /// </summary>
        /// <param name="stream">指定流。</param>
        /// <returns>反序列化的数据。</returns>
        public delegate T DeserializeCallback(Stream stream);

        /// <summary>
        /// 尝试从指定流获取指定键的值回调函数。
        /// </summary>
        /// <param name="stream">指定流。</param>
        /// <param name="key">指定键。</param>
        /// <param name="value">指定键的值。</param>
        /// <returns>是否从指定流获取指定键的值成功。</returns>
        public delegate bool TryGetValueCallback(Stream stream, string key, out object value);

        /// <summary>
        /// 注册序列化回调函数。
        /// </summary>
        /// <param name="version">序列化回调函数的版本。</param>
        /// <param name="callback">序列化回调函数。</param>
        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;
            }
        }

        /// <summary>
        /// 注册反序列化回调函数。
        /// </summary>
        /// <param name="version">反序列化回调函数的版本。</param>
        /// <param name="callback">反序列化回调函数。</param>
        public void RegisterDeserializeCallback(byte version, DeserializeCallback callback)
        {
            if (callback == null)
            {
                throw new GameFrameworkException("Deserialize callback is invalid.");
            }

            m_DeserializeCallbacks[version] = callback;
        }

        /// <summary>
        /// 注册尝试从指定流获取指定键的值回调函数。
        /// </summary>
        /// <param name="version">尝试从指定流获取指定键的值回调函数的版本。</param>
        /// <param name="callback">尝试从指定流获取指定键的值回调函数。</param>
        public void RegisterTryGetValueCallback(byte version, TryGetValueCallback callback)
        {
            if (callback == null)
            {
                throw new GameFrameworkException("Try get value callback is invalid.");
            }

            m_TryGetValueCallbacks[version] = callback;
        }

        /// <summary>
        /// 序列化数据到目标流中。
        /// </summary>
        /// <param name="stream">目标流。</param>
        /// <param name="data">要序列化的数据。</param>
        /// <returns>是否序列化数据成功。</returns>
        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);
        }

        /// <summary>
        /// 序列化数据到目标流中。
        /// </summary>
        /// <param name="stream">目标流。</param>
        /// <param name="data">要序列化的数据。</param>
        /// <param name="version">序列化回调函数的版本。</param>
        /// <returns>是否序列化数据成功。</returns>
        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.ToString()));
            }

            return callback(stream, data);
        }

        /// <summary>
        /// 从指定流反序列化数据。
        /// </summary>
        /// <param name="stream">指定流。</param>
        /// <returns>反序列化的数据。</returns>
        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]).ToString(), ((char)header[1]).ToString(), ((char)header[2]).ToString(),
                    ((char)header0).ToString(), ((char)header1).ToString(), ((char)header2).ToString()));
            }

            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.ToString()));
            }

            return callback(stream);
        }

        /// <summary>
        /// 尝试从指定流获取指定键的值。
        /// </summary>
        /// <param name="stream">指定流。</param>
        /// <param name="key">指定键。</param>
        /// <param name="value">指定键的值。</param>
        /// <returns>是否从指定流获取指定键的值成功。</returns>
        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);
        }

        /// <summary>
        /// 获取数据头标识。
        /// </summary>
        /// <returns>数据头标识。</returns>
        protected abstract byte[] GetHeader();
    }

       这个类结构上比较简单就不说了,需要注意的一点是框架里不同版本具有不同的序列化方法,而版本是通过byte字段标志的。

二、资源

       先是大概理解了下虚拟文件系统(结果还是没有完全搞懂),还有事件和序列化辅助工具,终于要回到原来的方向上了。展开Resource文件夹,映入眼帘的是一大推脚本,看起来挺吓人的,但是稍微看下文件名就会发现大多数都是回调。整理一下以后发现资源这块内容还是比较多的。从命名上看,ResourceManager主要分为三部分:资源检查器(ResourceManager.ReourceChecker)、资源加载器(ResourceManager.ReourceLoader)和资源更新器(ResourceManager.ReourceUpdater)。资源也被分成了三类:本地版本资源、单机模式版本资源和可更新模式版本资源。
       先看下不同版本的资源有什么区别。

    /// <summary>
    /// 本地版本资源列表。
    /// </summary>
    [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;

        /// <summary>
        /// 初始化本地版本资源列表的新实例。
        /// </summary>
        /// <param name="resources">包含的资源集合。</param>
        /// <param name="fileSystems">包含的文件系统集合。</param>
        public LocalVersionList(Resource[] resources, FileSystem[] fileSystems)
        {
            m_IsValid = true;
            m_Resources = resources ?? EmptyResourceArray;
            m_FileSystems = fileSystems ?? EmptyFileSystemArray;
        }

        /// <summary>
        /// 获取本地版本资源列表是否有效。
        /// </summary>
        public bool IsValid
        {
            get
            {
                return m_IsValid;
            }
        }

        /// <summary>
        /// 获取包含的资源集合。
        /// </summary>
        /// <returns>包含的资源集合。</returns>
        public Resource[] GetResources()
        {
            return m_Resources;
        }

        /// <summary>
        /// 获取包含的文件系统集合。
        /// </summary>
        /// <returns>包含的文件系统集合。</returns>
        public FileSystem[] GetFileSystems()
        {
            return m_FileSystems;
        }
    }

       这个结构体里面存的是本地版本的资源和文件系统。注意,这里的资源和文件系统指的并不是之前介绍的那个资源和文件系统,而是这个结构体里定义的两个子结构体。

    public partial struct LocalVersionList
    {
        /// <summary>
        /// 文件系统。
        /// </summary>
        [StructLayout(LayoutKind.Auto)]
        public struct FileSystem
        {
            private static readonly int[] EmptyIntArray = new int[] { };

            private readonly string m_Name;
            private readonly int[] m_ResourceIndexes;

            /// <summary>
            /// 初始化文件系统的新实例。
            /// </summary>
            /// <param name="name">文件系统名称。</param>
            /// <param name="resourceIndexes">文件系统包含的资源索引集合。</param>
            public FileSystem(string name, int[] resourceIndexes)
            {
                if (name == null)
                {
                    throw new GameFrameworkException("Name is invalid.");
                }

                m_Name = name;
                m_ResourceIndexes = resourceIndexes ?? EmptyIntArray;
            }

            /// <summary>
            /// 获取文件系统名称。
            /// </summary>
            public string Name
            {
                get
                {
                    return m_Name;
                }
            }

            /// <summary>
            /// 获取文件系统包含的资源索引集合。
            /// </summary>
            /// <returns>文件系统包含的资源索引集合。</returns>
            public int[] GetResourceIndexes()
            {
                return m_ResourceIndexes;
            }
        }
    }
    public partial struct LocalVersionList
    {
        /// <summary>
        /// 资源。
        /// </summary>
        [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;

            /// <summary>
            /// 初始化资源的新实例。
            /// </summary>
            /// <param name="name">资源名称。</param>
            /// <param name="variant">资源变体名称。</param>
            /// <param name="extension">资源扩展名称。</param>
            /// <param name="loadType">资源加载方式。</param>
            /// <param name="length">资源长度。</param>
            /// <param name="hashCode">资源哈希值。</param>
            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;
            }

            /// <summary>
            /// 获取资源名称。
            /// </summary>
            public string Name
            {
                get { return m_Name; }
            }

            /// <summary>
            /// 获取资源变体名称。
            /// </summary>
            public string Variant
            {
                get { return m_Variant; }
            }

            /// <summary>
            /// 获取资源扩展名称。
            /// </summary>
            public string Extension
            {
                get { return m_Extension; }
            }

            /// <summary>
            /// 获取资源加载方式。
            /// </summary>
            public byte LoadType
            {
                get { return m_LoadType; }
            }

            /// <summary>
            /// 获取资源长度。
            /// </summary>
            public int Length
            {
                get { return m_Length; }
            }

            /// <summary>
            /// 获取资源哈希值。
            /// </summary>
            public int HashCode
            {
                get { return m_HashCode; }
            }
        }
    }

       同理,另外两个版本的存储结构也是这样的,不过是添加了ResourceGroup之类的辅助结构,就不细看了。接下来去ResourceManager里看看。先看一下ResourceManager.cs这个脚本(这个脚本太长了就不放上来了),看一下它定义的属性及字段。

        //配置文件相关的常量
        private const string RemoteVersionListFileName = "GameFrameworkVersion.dat";
        private const string LocalVersionListFileName = "GameFrameworkList.dat";
        private const string DefaultExtension = "dat";
        private const string BackupExtension = "bak";
        private const int FileSystemMaxFileCount = 1024 * 16;
        private const int FileSystemMaxBlockCount = 1024 * 256;

        //数据存储结构
        private Dictionary<string, AssetInfo> m_AssetInfos;
        private Dictionary<ResourceName, ResourceInfo> m_ResourceInfos;
        private SortedDictionary<ResourceName, ReadWriteResourceInfo> m_ReadWriteResourceInfos;
        private readonly Dictionary<string, IFileSystem> m_ReadOnlyFileSystems;
        private readonly Dictionary<string, IFileSystem> m_ReadWriteFileSystems;
        private readonly Dictionary<string, ResourceGroup> m_ResourceGroups;

        //不同版本资源列表的序列化器
        private PackageVersionListSerializer m_PackageVersionListSerializer;
        private UpdatableVersionListSerializer m_UpdatableVersionListSerializer;
        private ReadOnlyVersionListSerializer m_ReadOnlyVersionListSerializer;
        private ReadWriteVersionListSerializer m_ReadWriteVersionListSerializer;
        private ResourcePackVersionListSerializer m_ResourcePackVersionListSerializer;

        //需要用到的Manager
        private IFileSystemManager m_FileSystemManager;
        private ResourceIniter m_ResourceIniter;
        private VersionListProcessor m_VersionListProcessor;
        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_RefuseSetCurrentVariant;
        private string m_CurrentVariant;
        private string m_UpdatePrefixUri;
        private string m_ApplicableGameVersion;
        private int m_InternalResourceVersion;
        
        //加载资源相关的回调
        private MemoryStream m_DecompressCachedStream;
        private DecryptResourceCallback m_DecryptResourceCallback;
        private InitResourcesCompleteCallback m_InitResourcesCompleteCallback;
        private UpdateVersionListCallbacks m_UpdateVersionListCallbacks;
        private CheckResourcesCompleteCallback m_CheckResourcesCompleteCallback;
        private ApplyResourcesCompleteCallback m_ApplyResourcesCompleteCallback;
        private UpdateResourcesCompleteCallback m_UpdateResourcesCompleteCallback;
        private EventHandler<ResourceApplySuccessEventArgs> m_ResourceApplySuccessEventHandler;
        private EventHandler<ResourceApplyFailureEventArgs> m_ResourceApplyFailureEventHandler;
        private EventHandler<ResourceUpdateStartEventArgs> m_ResourceUpdateStartEventHandler;
        private EventHandler<ResourceUpdateChangedEventArgs> m_ResourceUpdateChangedEventHandler;
        private EventHandler<ResourceUpdateSuccessEventArgs> m_ResourceUpdateSuccessEventHandler;
        private EventHandler<ResourceUpdateFailureEventArgs> m_ResourceUpdateFailureEventHandler;

       通过这些变量,大概能猜到这个脚本里会包含哪些内容:按逻辑顺序会先通过解析配置文件来检查资源,更新资源、然后加载资源以及一些辅助方法。当然这些方法都是通过调用Manager实现的。
        关于变体,这里有个解释,说得挺浅显易懂的。
       检查器会读取资源列表,并把检查信息以CheckInfo的形式保存起来。

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;

                /// <summary>
                /// 初始化资源检查信息的新实例。
                /// </summary>
                /// <param name="resourceName">资源名称。</param>
                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;
                }

                /// <summary>
                /// 获取资源名称。
                /// </summary>
                public ResourceName ResourceName
                {
                    get
                    {
                        return m_ResourceName;
                    }
                }

                /// <summary>
                /// 获取资源检查状态。
                /// </summary>
                public CheckStatus Status
                {
                    get
                    {
                        return m_Status;
                    }
                }

                /// <summary>
                /// 获取是否需要移除读写区的资源。
                /// </summary>
                public bool NeedRemove
                {
                    get
                    {
                        return m_NeedRemove;
                    }
                }

                /// <summary>
                /// 获取是否需要将读写区的资源移动到磁盘。
                /// </summary>
                public bool NeedMoveToDisk
                {
                    get
                    {
                        return m_NeedMoveToDisk;
                    }
                }

                /// <summary>
                /// 获取是否需要将读写区的资源移动到文件系统。
                /// </summary>
                public bool NeedMoveToFileSystem
                {
                    get
                    {
                        return m_NeedMoveToFileSystem;
                    }
                }

                /// <summary>
                /// 获取资源所在的文件系统名称。
                /// </summary>
                public string FileSystemName
                {
                    get
                    {
                        return m_VersionInfo.FileSystemName;
                    }
                }

                /// <summary>
                /// 获取资源是否使用文件系统。
                /// </summary>
                public bool ReadWriteUseFileSystem
                {
                    get
                    {
                        return m_ReadWriteInfo.UseFileSystem;
                    }
                }

                /// <summary>
                /// 获取读写资源所在的文件系统名称。
                /// </summary>
                public string ReadWriteFileSystemName
                {
                    get
                    {
                        return m_ReadWriteInfo.FileSystemName;
                    }
                }

                /// <summary>
                /// 获取资源加载方式。
                /// </summary>
                public LoadType LoadType
                {
                    get
                    {
                        return m_VersionInfo.LoadType;
                    }
                }

                /// <summary>
                /// 获取资源大小。
                /// </summary>
                public int Length
                {
                    get
                    {
                        return m_VersionInfo.Length;
                    }
                }

                /// <summary>
                /// 获取资源哈希值。
                /// </summary>
                public int HashCode
                {
                    get
                    {
                        return m_VersionInfo.HashCode;
                    }
                }

                /// <summary>
                /// 获取压缩后大小。
                /// </summary>
                public int ZipLength
                {
                    get
                    {
                        return m_VersionInfo.ZipLength;
                    }
                }

                /// <summary>
                /// 获取压缩后哈希值。
                /// </summary>
                public int ZipHashCode
                {
                    get
                    {
                        return m_VersionInfo.ZipHashCode;
                    }
                }

                /// <summary>
                /// 临时缓存资源所在的文件系统名称。
                /// </summary>
                /// <param name="fileSystemName">资源所在的文件系统名称。</param>
                public void SetCachedFileSystemName(string fileSystemName)
                {
                    m_CachedFileSystemName = fileSystemName;
                }

                /// <summary>
                /// 设置资源在版本中的信息。
                /// </summary>
                /// <param name="loadType">资源加载方式。</param>
                /// <param name="length">资源大小。</param>
                /// <param name="hashCode">资源哈希值。</param>
                /// <param name="zipLength">压缩后大小。</param>
                /// <param name="zipHashCode">压缩后哈希值。</param>
                public void SetVersionInfo(LoadType loadType, int length, int hashCode, int zipLength, int zipHashCode)
                {
                    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, zipLength, zipHashCode);
                    m_CachedFileSystemName = null;
                }

                /// <summary>
                /// 设置资源在只读区中的信息。
                /// </summary>
                /// <param name="loadType">资源加载方式。</param>
                /// <param name="length">资源大小。</param>
                /// <param name="hashCode">资源哈希值。</param>
                public void SetReadOnlyInfo(LoadType loadType, int length, int hashCode)
                {
                    if (m_ReadOnlyInfo.Exist)
                    {
                        throw new GameFrameworkException(Utility.Text.Format("You must set readonly info of '{0}' only once.", m_ResourceName.FullName));
                    }

                    m_ReadOnlyInfo = new LocalVersionInfo(m_CachedFileSystemName, loadType, length, hashCode);
                    m_CachedFileSystemName = null;
                }

                /// <summary>
                /// 设置资源在读写区中的信息。
                /// </summary>
                /// <param name="loadType">资源加载方式。</param>
                /// <param name="length">资源大小。</param>
                /// <param name="hashCode">资源哈希值。</param>
                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;
                }

                /// <summary>
                /// 刷新资源信息状态。
                /// </summary>
                /// <param name="currentVariant">当前变体。</param>
                /// <param name="ignoreOtherVariant">是否忽略处理其它变体的资源,若不忽略则移除。</param>
                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;
                    }
                }
            }

       在资源更新器中,定义了UpdateInfo和ApplyInfo两个结构体来记录资源信息,然后会在update方法中对保存的数据进行轮询,如果有要处理的数据就进行下载/应用操作。至于加载器就会再复杂一些,不仅包含新定义的数据结构来存储信息,而且加载是通过代理调用Task进行加载的。
       这里要说明一下,这三部分各自对应一个流程,比如说检查器就对应ProcedureCheckResources流程,更新器对应ProcedureUpdateResources流程,而加载器对应的是ProcedurePreload流程。等到执行到相应的流程的时候,流程的OnEnter和Update方法会调用这些

三、辅助器接口

       GameFramework框架中提供资源辅助器和加载资源代理辅助器的接口,这两个接口在框架内是没有实现的,应该是开放出来让开发者根据实际情况扩展的。接口写的很简洁,IResourceHelper里只有三个方法,不是很明白为什么会有个卸载场景的方法。

/// <summary>
    /// 资源辅助器接口。
    /// </summary>
    public interface IResourceHelper
    {
        /// <summary>
        /// 直接从指定文件路径加载数据流。
        /// </summary>
        /// <param name="fileUri">文件路径。</param>
        /// <param name="loadBytesCallbacks">加载数据流回调函数集。</param>
        /// <param name="userData">用户自定义数据。</param>
        void LoadBytes(string fileUri, LoadBytesCallbacks loadBytesCallbacks, object userData);

        /// <summary>
        /// 卸载场景。
        /// </summary>
        /// <param name="sceneAssetName">场景资源名称。</param>
        /// <param name="unloadSceneCallbacks">卸载场景回调函数集。</param>
        /// <param name="userData">用户自定义数据。</param>
        void UnloadScene(string sceneAssetName, UnloadSceneCallbacks unloadSceneCallbacks, object userData);

        /// <summary>
        /// 释放资源。
        /// </summary>
        /// <param name="objectToRelease">要释放的资源。</param>
        void Release(object objectToRelease);
    }

       ILoadResourceAgentHelper里从声明的事件就能看出加载资源的过程:通知更新->读取文件->读取二进制流->二进制流转换->加载完成。方法也基本上和这些步骤对应。

public interface ILoadResourceAgentHelper
    {
        /// <summary>
        /// 加载资源代理辅助器异步加载资源更新事件。
        /// </summary>
        event EventHandler<LoadResourceAgentHelperUpdateEventArgs> LoadResourceAgentHelperUpdate;

        /// <summary>
        /// 加载资源代理辅助器异步读取资源文件完成事件。
        /// </summary>
        event EventHandler<LoadResourceAgentHelperReadFileCompleteEventArgs> LoadResourceAgentHelperReadFileComplete;

        /// <summary>
        /// 加载资源代理辅助器异步读取资源二进制流完成事件。
        /// </summary>
        event EventHandler<LoadResourceAgentHelperReadBytesCompleteEventArgs> LoadResourceAgentHelperReadBytesComplete;

        /// <summary>
        /// 加载资源代理辅助器异步将资源二进制流转换为加载对象完成事件。
        /// </summary>
        event EventHandler<LoadResourceAgentHelperParseBytesCompleteEventArgs>
            LoadResourceAgentHelperParseBytesComplete;

        /// <summary>
        /// 加载资源代理辅助器异步加载资源完成事件。
        /// </summary>
        event EventHandler<LoadResourceAgentHelperLoadCompleteEventArgs> LoadResourceAgentHelperLoadComplete;

        /// <summary>
        /// 加载资源代理辅助器错误事件。
        /// </summary>
        event EventHandler<LoadResourceAgentHelperErrorEventArgs> LoadResourceAgentHelperError;

        /// <summary>
        /// 通过加载资源代理辅助器开始异步读取资源文件。
        /// </summary>
        /// <param name="fullPath">要加载资源的完整路径名。</param>
        void ReadFile(string fullPath);

        /// <summary>
        /// 通过加载资源代理辅助器开始异步读取资源文件。
        /// </summary>
        /// <param name="fileSystem">要加载资源的文件系统。</param>
        /// <param name="name">要加载资源的名称。</param>
        void ReadFile(IFileSystem fileSystem, string name);

        /// <summary>
        /// 通过加载资源代理辅助器开始异步读取资源二进制流。
        /// </summary>
        /// <param name="fullPath">要加载资源的完整路径名。</param>
        void ReadBytes(string fullPath);

        /// <summary>
        /// 通过加载资源代理辅助器开始异步读取资源二进制流。
        /// </summary>
        /// <param name="fileSystem">要加载资源的文件系统。</param>
        /// <param name="name">要加载资源的名称。</param>
        void ReadBytes(IFileSystem fileSystem, string name);

        /// <summary>
        /// 通过加载资源代理辅助器开始异步将资源二进制流转换为加载对象。
        /// </summary>
        /// <param name="bytes">要加载资源的二进制流。</param>
        void ParseBytes(byte[] bytes);

        /// <summary>
        /// 通过加载资源代理辅助器开始异步加载资源。
        /// </summary>
        /// <param name="resource">资源。</param>
        /// <param name="assetName">要加载的资源名称。</param>
        /// <param name="assetType">要加载资源的类型。</param>
        /// <param name="isScene">要加载的资源是否是场景。</param>
        void LoadAsset(object resource, string assetName, Type assetType, bool isScene);

        /// <summary>
        /// 重置加载资源代理辅助器。
        /// </summary>
        void Reset();
    }

       至于这两个接口的实现可以在UnityGameFramework中找到。在实现ILoadResourceAgentHelper的DefaultLoadResourceAgentHelper这个类里见到了把event 作为属性,赋值时不像普通属性那样使用get、set构造器而是addremove。实现的方法,不管是读取文件还是加载ab包(从方法中看到ab包被区分为场景资源与非场景资源)都是返回了一个异步请求。而读取二进制流比较特殊,未使用流加载的返回的是UnityWebRequest(这个类是能加载本地资源的)使用文件系统流加载的直接使用了加载完成事件。然后在update里会统一轮询各种请求并进行处理,其处理请求的方式还是使用各种事件
       对于EventHandler不是很熟悉,所以这里事件的用法在这里看的有些懵。Eventhandler本质上是个委托,(EventHandler的)原型是下面这样的

 /// <summary>表示当事件提供数据时将处理该事件的方法。</summary>
 /// <param name="sender">事件源。</param>
 /// <param name="e">包含事件数据的对象。</param>
 /// <typeparam name="TEventArgs">事件生成的事件数据的类型</typeparam>
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

       这两个接口命名挺像的,而且看方法好像也差不多,都是加载资源的。通过反向查找发现,资源辅助器是在检查器中被调用,用来加载存储版本资源列表的文件,而资源代理辅助器则是在更新器中被调用用来更新资源的。
       资源这块的内容感觉还是在细节上还是一头雾水,看到的大多是加载相关的,很少见到卸载相关的内容;而且配置文件那块的内容也还没看,所以不太清楚资源是怎么存放、映射的,所以不同版本资源列表相关的代码,看的也不是很懂;还有打包相关的内容貌似是写在编辑器模块里,所以也还没看。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值