Giter Site home page Giter Site logo

saitinghu / htframework Goto Github PK

View Code? Open in Web Editor NEW
644.0 14.0 101.0 4.1 MB

Unity HTFramework, a rapid development framework of client to the unity.

License: MIT License

C# 99.67% ShaderLab 0.30% HLSL 0.04%
unity unity-htframework fsm aop hotfix objectpool unity3d unity3d-framework ugui csharp

htframework's Introduction

image

license version supported

Unity HTFramework

HTFramework是基于Unity的一个快速开发框架,集需求模块化、代码重用性、实用便捷性、功能高内聚、统一编码规范、可扩展性、可维护性、可通用性、可插拨性为一体,并提供持续维护、升级。

环境

  • Unity版本:2022.3.17。

  • .NET API版本:.NET Framework。

编码规范

模块简介

  • AspectTrack - 根据AOP**架构的一个面向切面的程序代码追踪模块,它可以跟踪每一个方法的调用,在调用前阻断该方法,亦或是更改其传入的实参,更改其返回值等!可以用于调用日志打印,系统运行监控等需求。

  • Audio - 项目中所有音频的管理器,提供统一的接口用来播放、暂停、停止各种音频资源。

  • Controller - 封装了主角控制、主摄像机控制等,简化了大量重复代码。

  • Coroutiner - 协程调度器,通过协程调度器启动的协程,将会处于调度器的监控中,可以通过CoroutinerTracker追踪面板查看协程的运行状态、运行耗时,可重启、终止任意协程。

  • CustomModule - 框架内置了多个常用的模块,如果想要添加自己的模块,通过CustomModule添加自定义模块即可,自定义模块拥有与内置模块完全一样的生命周期。

  • DataSet - 自定义数据集,任何需要存储数据的地方都可以定义为自定义数据集,包括预制的配置文件、运行时生成的动态数据、从后台拉取的各种数据等。

  • Debug - Debug模块自带Debugger运行时调试器,可以监控一些常规数据与软件运行环境,或是进行一些高级的操作,比如检索场景所有游戏对象(等效于编辑器内Hierarchy窗口的功能),检索游戏对象的所有组件(等效于编辑器内Inspector窗口的功能)。

  • ECS - 实体-组件-系统,此ECS非Unity的ECS,并不一定会带来性能的提升,只是基于ECS的**,建立在Unity现有的组件模式之上,以ECS模式进行开发可以避开项目后期繁重的继承链,提升开发速度和质量、以及项目稳定性。

  • Entity - 实体管理器,除去UI以外,场景中的其余可见物体都应该抽象为Entity,在Entity之上配合FSM一起管理逻辑,将是一个不错的搭配。

  • Event - 可以将一切操作定义为具体的全局事件,通过订阅事件、抛出事件以驱动整个业务逻辑。

  • Exception - 异常处理者,当程序任何部位发生未知、未捕获的异常时,他会在这里被截获,并写入日志文件,同时支持在异常发生时打开指定程序(仅在PC平台),或者在异常发生时回馈日志到指定邮箱。

  • FSM - 模拟一切可以抽象为有限状态机结构的业务逻辑,类似于角色动画、怪物AI、任意有独立逻辑的个体等。

  • Hotfix - 以C#反射实现的轻量级热更新框架,开发非常方便,新项目只需要拉取框架源码后,一键即可创建热更新环境,之后便可以用C#正常开发,目前已支持在热更新库中动态修复外界的任何方法,无需重新发布项目。

  • Input - 将任意输入都定义为虚拟输入,再由Input模块统一调用,将是跨平台输入的最优解决方案。

  • Instruction - 指令系统,可在运行时编译并执行任意指令代码,达到最快速度修补程序的功能。

  • Main - 框架主模块,提供访问其他模块的快捷接口,还支持快捷设置脚本定义、指定全局主要数据类、设置项目授权、以及配置全局参数等。

  • Network - 网络客户端模块,以单个通信管道为单位,每个管道均支持TCP/UDP等协议,可以为每个管道定义通信消息格式,基本能胜任一些常见的通信环境。

  • ObjectPool - 专用于GameObject类型的对象池,可以复用任意GameObject对象,以达到减少系统在频繁创建和删除对象时的开销。

  • Procedure - 流程是框架的核心模块,也是最基本的模块,他贯穿整个框架的始终,从框架的生命周期开始,到生命周期结束,都会在流程间完成,同时,他又是一个强化版的有限状态机,当在多个流程间切换直至最终流程时,便代表整个系统的结束。

  • ReferencePool - 可用于任意引用类型(除GameObject)的对象池,可以复用任意引用类型对象,以达到减少系统在频繁创建和删除对象时的开销。

  • Resource - 资源加载管理器,主要用于动态加载资源(只支持异步加载),在加载中或加载完成后都可以进行自定义操作,现在主要支持Resource直接加载和AssetBundle加载,比如,UI模块就会自动调用资源管理器加载UI实体。

  • StepMaster - 步骤编辑器,严格来说,StepEditor只是框架的一个内置工具,他最开始的用途是用来解决一系列冗长的线性任务,为了实现可视化和降低后期改动的复杂度,当然,也可以用作流程控制器。

  • TaskMaster - 任务编辑器,可以自定义任务点,设置任务达成条件,多个任务点组成一个任务内容,使用一系列任务内容完成角色扮演的设计。

  • UI - 用于管理全局的UI实体,以省去手动创建UI实例、销毁UI实例等一系列操作,他可以在非常方便且省去不必要的开销优势下,让你条例清晰的组织和管控好任何复杂的UI结构。

  • Utility - 框架实用工具,包括一些批处理工具及编辑器工具。

  • WebRequest - 网络请求模块,主要用于与web服务器通信,比如请求某一网络链接或服务器接口,获得回复或下载网络上的资源。

  • AI【可选模块】 - AI相关模块,比如A*寻路以及各种人工智能模块。

  • ILHotfix【可选模块】 - 基于ILRuntime实现的跨平台热更新框架,开发非常方便,新项目只需要拉取框架源码及本模块,一键即可创建热更新环境,之后便可以正常开发。

  • XLua【可选模块】 - 本模块旨在结合XLua与框架的资源加载策略,快速实现热更流程,并优化了开发环境,使得开发人员可以最低成本的投入到Lua业务开发。

  • GameComponent【可选模块】 - 游戏组件模块,本模块整合了多个游戏开发过程中可能会涉及到的子系统或组件,包括但不仅限于文件系统、本地化系统、新手引导系统、时间系统、AVG2D系统、FTG2D系统、RPG2D系统等,且各个系统或组件均为可插拨式,可一键移除不需要的系统或组件,或再次一键导入。

内置工具

演示代码

注意事项

  • 1.框架中所有On开头的函数为生命周期函数或回调函数,均由框架呼叫,请勿手动调用。

  • 2.框架中的Procedure(流程)必须包含至少一个流程才能正确构建项目,而其他模块,如无需要,均可以不使用。

主要特性

  • 1.入口场景为一切的开始,也为一切的结束,整个游戏的生命周期都将在入口场景中完成,不建议使用多场景切换模式,如果确实需要使用,可以将其他场景打入AB包内加载。

  • 2.入口场景中只包含框架主模块(或其他自定义主模块、主控制器),其他任何东西都应该是动态加载的。

使用方法

  • 1.拉取框架到项目中的Assets文件夹下(Assets/HTFramework/),或以添加子模块的形式。

  • 2.在入口场景的层级(Hierarchy)视图点击右键,选择 HTFramework -> Main Environment(创建框架主环境),并删除入口场景其他的东西(除了框架的主要模块,其他任何东西都应该是动态加载的)。

  • 3.参阅各个模块的帮助文档,开始开发。

htframework's People

Contributors

ktdynamic avatar saitinghu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

htframework's Issues

UI Entity 会重复创建

当LoadPrefab时间较长时,在此期间多次调用Main.m_UI.OpenUI ,会产生多个 UIEntity

  /// <summary>
        /// 创建并打开UI实体
        /// </summary>
        /// <param name="uIResource">UI资源标记</param>
        /// <param name="uITypeName">UI逻辑类型</param>
        /// <param name="uILogic">UI逻辑类对象</param>
        /// <param name="uIParent">UI的父级</param>
        /// <param name="args">UI打开的参数</param>
        /// <returns>加载协程</returns>
        private Coroutine CreateOpenUIEntity(UIResourceAttribute uIResource, string uITypeName, UILogicBase uILogic, Transform uIParent, params object[] args)
        {
            if (uILogic.IsOpened)
                return null;

            if (!uILogic.IsCreated)
            {
                if (_defineUIAndEntitys.ContainsKey(uITypeName) && _defineUIAndEntitys[uITypeName] != null)
                {
                    uILogic.UIEntity = Main.Clone(_defineUIAndEntitys[uITypeName], uIParent);
                    uILogic.UIEntity.SetActive(true);
                    uILogic.OnInit();
                    uILogic.OnOpen(args);
                    PlaceTopUIEntity(uILogic as UILogicResident);
                    return null;
                }
                else
                {
                    return Main.m_Resource.LoadPrefab(new PrefabInfo(uIResource), uIParent, null, (obj) =>
                    {
                        uILogic.UIEntity = obj;
                        uILogic.UIEntity.SetActive(true);
                        uILogic.OnInit();
                        uILogic.OnOpen(args);
                        PlaceTopUIEntity(uILogic as UILogicResident);
                    }, true);
                }
            }
            else
            {
                uILogic.UIEntity.SetActive(true);
                uILogic.OnOpen(args);
                PlaceTopUIEntity(uILogic as UILogicResident);
                return null;
            }
        }

我如果修改了打包方法,做了AB包加密,是否只能自己实现DefaultResourceHelper,无法实现加载进度条了?

我打AB包的时候做了Offset加密,官方的加载方式是

//第三个参数是Offset,这样就完成了解密并加载
AssetBundle assetBundle = AssetBundle.LoadFromFile(filePath, 0, 2);

但默认的资源加载助手采用的是UnityWebRequestAssetBundle.GetAssetBundle的实现方式
而这种方式不支持传入Offset参数进行解密加载

那我是否只能自己实现ResourceHelper,这样就无法使用加载进度条了

我在打ab包的时候勾选AppendHash,但是UI加载失败,因为ab包名加了hash值

我在打ab包的时候勾选AppendHash,但是UI加载失败,因为ab包名加了hash值,UI逻辑类标记的AssetBundleName好像没法加hash值,因为不确定这个值,我在用微信官方提供的转换小游戏工具,它的缓存机制需要ab包打包设置BuildAssetBundleOptions.AppendHashToAssetBundleName,这个我应该怎么处理好呢。

什么 是RealProxy ?有没demo 可以看看

Assets\HTFramework\RunTime\AspectTrack\Base\AspectProxyBase.cs(9,48): error CS0246: The type or namespace name 'RealProxy' could not be found (are you missing a using directive or an assembly reference?)

DefaultResourceHelper 能否将单线加载 改为并行资源加载

单线会导致整体资源加载时间变长,特别是在需要加载大量资源的情况下。这种串行加载的方式虽然可以避免一些并发加载的问题,但在游戏启动或运行过程中可能导致明显的延迟。

public IEnumerator LoadAssetAsync<T>(ResourceInfoBase info, HTFAction<float> onLoading, HTFAction<T> onLoadDone, bool isPrefab, Transform parent, bool isUI) where T : UnityEngine.Object
        {
            float beginTime = Time.realtimeSinceStartup;

            //单线加载,如果其他地方在加载资源,则等待
            if (_isLoading)
            {
                yield return _loadWait;
            }

            //轮到本线路加载资源
            _isLoading = true;

            //等待相关依赖资源的加载
            yield return LoadDependenciesAssetBundleAsync(info.AssetBundleName);

            float waitTime = Time.realtimeSinceStartup;

            UnityEngine.Object asset = null;

            if (LoadMode == ResourceLoadMode.Resource)
            {
                ResourceRequest request = Resources.LoadAsync<T>(info.ResourcePath);
                while (!request.isDone)
                {
                    onLoading?.Invoke(request.progress);
                    yield return null;
                }
                onLoading?.Invoke(1);
                asset = request.asset;
                if (asset)
                {
                    if (isPrefab)
                    {
                        asset = ClonePrefab(asset as GameObject, parent, isUI);
                    }
                }
                else
                {
                    throw new HTFrameworkException(HTFrameworkModule.Resource, $"加载资源失败:Resources文件夹中不存在资源 {info.ResourcePath}!");
                }
            }
            else
            {
#if UNITY_EDITOR
                if (IsEditorMode)
                {
                    onLoading?.Invoke(1);
                    yield return null;

                    asset = AssetDatabase.LoadAssetAtPath<T>(info.AssetPath);
                    if (asset)
                    {
                        if (isPrefab)
                        {
                            asset = ClonePrefab(asset as GameObject, parent, isUI);
                        }
                    }
                    else
                    {
                        throw new HTFrameworkException(HTFrameworkModule.Resource, $"加载资源失败:路径中不存在资源 {info.AssetPath}!");
                    }
                }
                else
                {
                    yield return LoadAssetBundleAsync(info.AssetBundleName, onLoading);

                    if (AssetBundles.ContainsKey(info.AssetBundleName))
                    {
                        asset = AssetBundles[info.AssetBundleName].LoadAsset<T>(info.AssetPath);
                        if (asset)
                        {
                            if (isPrefab)
                            {
                                asset = ClonePrefab(asset as GameObject, parent, isUI);
                            }
                        }
                        else
                        {
                            throw new HTFrameworkException(HTFrameworkModule.Resource, $"加载资源失败:AB包 {info.AssetBundleName} 中不存在资源 {info.AssetPath}!");
                        }
                    }
                }
#else
                yield return LoadAssetBundleAsync(info.AssetBundleName, onLoading);

                if (AssetBundles.ContainsKey(info.AssetBundleName))
                {
                    asset = AssetBundles[info.AssetBundleName].LoadAsset<T>(info.AssetPath);
                    if (asset)
                    {
                        if (isPrefab)
                        {
                            asset = ClonePrefab(asset as GameObject, parent, isUI);
                        }
                    }
                    else
                    {
                        throw new HTFrameworkException(HTFrameworkModule.Resource, $"加载资源失败:AB包 {info.AssetBundleName} 中不存在资源 {info.AssetPath}!");
                    }
                }
#endif
            }

            float endTime = Time.realtimeSinceStartup;

            Log.Info(string.Format("异步加载资源{0}[{1}模式]:\r\n{2}\r\n等待耗时:{3}秒  加载耗时:{4}秒"
                , asset ? "成功" : "失败"
                , LoadMode.ToString()
                , LoadMode == ResourceLoadMode.Resource ? info.GetResourceFullPath() : info.GetAssetBundleFullPath(AssetBundleRootPath)
                , waitTime - beginTime
                , endTime - waitTime));

            if (asset)
            {
                DataSetInfo dataSet = info as DataSetInfo;
                if (dataSet != null && dataSet.Data != null)
                {
                    asset.Cast<DataSetBase>().Fill(dataSet.Data);
                }

                onLoadDone?.Invoke(asset as T);
            }
            else
            {
                onLoadDone?.Invoke(null);
            }
            asset = null;

            //本线路加载资源结束
            _isLoading = false;
        }

加载AssetBundle好像有问题

isManifest=false时,调用了GetAssetBundleHash方法,报NullReferenceException
代码:
UnityWebRequest request = isManifest
? UnityWebRequestAssetBundle.GetAssetBundle(AssetBundleRootPath + assetBundleName)
: UnityWebRequestAssetBundle.GetAssetBundle(AssetBundleRootPath + assetBundleName,GetAssetBundleHash(assetBundleName))

缺少命名空间

先说一句这个项目太棒了,文档很详细!
但是导入unity 2020.1.14f的时候出现如下错误
Assets\HTFramework-master\RunTime\AspectTrack\Base\AspectProxyBase.cs(3,22): error CS0234: The type or namespace name 'Remoting' does not exist in the namespace 'System.Runtime' (are you missing an assembly reference?) Assets\HTFramework-master\RunTime\AspectTrack\Base\AspectProxyBase.cs(4,22): error CS0234: The type or namespace name 'Remoting' does not exist in the namespace 'System.Runtime' (are you missing an assembly reference?) Assets\HTFramework-master\RunTime\AspectTrack\Base\AspectProxyBase.cs(11,48): error CS0246: The type or namespace name 'RealProxy' could not be found (are you missing a using directive or an assembly reference?) Assets\HTFramework-master\RunTime\AspectTrack\Base\AspectProxyBase.cs(49,48): error CS0246: The type or namespace name 'IMessage' could not be found (are you missing a using directive or an assembly reference?) Assets\HTFramework-master\RunTime\AspectTrack\Base\AspectProxyBase.cs(49,32): error CS0246: The type or namespace name 'IMessage' could not be found (are you missing a using directive or an assembly reference?) Assets\HTFramework-master\RunTime\AspectTrack\Base\AspectProxyBase.cs(37,39): error CS0115: 'AspectProxyBase<T>.GetTransparentProxy()': no suitable method found to override Assets\HTFramework-master\RunTime\AspectTrack\Base\AspectProxyBase.cs(49,41): error CS0115: 'AspectProxyBase<T>.Invoke(IMessage)': no suitable method found to override

新建了一个MyDefaultResourceHelper,无法切换回DefaultResourceHelper了

我对新建了一个MyDefaultResourceHelper,在ResourceManager面板选择后正常使用

但当我想切换回DefaultResourceHelper时,一旦运行就自动变成MyDefaultResourceHelper了

无法正常切换使用

image

image

image

下图的切换逻辑有问题,点一次并会不更改_module.HelperType,需要再点一次
image

ProtocolChannelBase

      /// <summary>
        /// 发送消息(需要保持连接的协议)
        /// </summary>
        private void SendMessageNeedConnect()
        {
            while (_isEnableThread)
            {
                if (IsConnect && _isCanSend && _sendDataBuffer.Count > 0)
                {
                    int sendCount = Client.Send(_sendDataBuffer[0], _sendDataBuffer[0].Length, 0);
                    if (sendCount > 0)
                    {
                        _sendDataBuffer.RemoveAt(0);

                        Main.Current.QueueOnMainThread(() =>
                        {
                            SendMessageEvent?.Invoke(this);
                        });
                    }
                }
            }
        }

error

会出现_sendDataBuffer[0] 为空的情况

LoadSceneAsync add an AsyncOperation callback

//SceneInfo .cs
public sealed class SceneInfo : ResourceInfoBase
   {
       public LoadSceneMode LoadMode
       {
           get;
           protected set;
       }
       public SceneInfo(string assetBundleName, string assetPath, string sceneName,LoadSceneMode loadMode=LoadSceneMode.Additive) : base(assetBundleName, assetPath, sceneName)
       {
           LoadMode = loadMode;
       }
   }  
//DefaultResourceHelper.cs
public IEnumerator LoadSceneAsync(SceneInfo info,  HTFAction<float> loadingAction, HTFAction<AsyncOperation> loadedBundleAction,HTFAction loadDoneAction)
       {
           float beginTime = Time.realtimeSinceStartup;

           //单线加载,如果其他地方在加载资源,则等待
           if (_isLoading)
           {
               yield return _loadWait;
           }

           //轮到本线路加载资源
           _isLoading = true;

           //等待相关依赖资源的加载
           yield return LoadDependenciesAssetBundleAsync(info.AssetBundleName);

           float waitTime = Time.realtimeSinceStartup;

           if (LoadMode == ResourceLoadMode.Resource)
           {
               throw new HTFrameworkException(HTFrameworkModule.Resource, "加载场景失败:场景加载不允许使用Resource模式!");
           }
           else
           {
#if UNITY_EDITOR
               if (IsEditorMode)
               {
                   LoadSceneParameters parameters = new LoadSceneParameters()
                   {
                       loadSceneMode = LoadSceneMode.Additive,
                       localPhysicsMode = LocalPhysicsMode.None
                   };
                   yield return EditorSceneManager.LoadSceneAsyncInPlayMode(info.AssetPath, parameters);
               }
               else
               {
                   yield return LoadAssetBundleAsync(info.AssetBundleName, loadingAction);
                   var asyncOp = SceneManager.LoadSceneAsync(info.ResourcePath, info.LoadMode);
                   loadedBundleAction?.Invoke(asyncOp);
                   yield return asyncOp;
               }
#else
               yield return LoadAssetBundleAsync(info.AssetBundleName, loadingAction);
               var asyncOp = SceneManager.LoadSceneAsync(info.ResourcePath, info.LoadMode);
               loadedBundleAction?.Invoke(asyncOp);
               yield return asyncOp;
               // yield return SceneManager.LoadSceneAsync(info.ResourcePath, LoadSceneMode.Additive);
#endif
           }

           float endTime = Time.realtimeSinceStartup;

           Log.Info(string.Format("异步加载场景完成[{0}模式]:{1}\r\n等待耗时:{2}秒  加载耗时:{3}秒"
               , LoadMode.ToString()
               , info.ResourcePath
               , waitTime - beginTime
               , endTime - waitTime));

           loadDoneAction?.Invoke();

           //本线路加载资源结束
           _isLoading = false;
       }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.