/// <summary> /// 设置数据 /// </summary> /// <param name="name"></param> /// <param name="value"></param> virtual public void SetData(string name, object value, bool isTriggerCallback = true) { if (dataMap.ContainsKey(name)) { dataMap[name] = value; } else { BDebug.LogError("设置无效,无该数据:" + name); return; } //调用数据改变 if (isTriggerCallback) { List <Action <object> > actions = null; if (callbackMap.TryGetValue(name, out actions)) { foreach (var a in actions) { a(value); } } else { List <object> list = null; valueCacheMap.TryGetValue(name, out list); if (list == null) { list = new List <object>(); list.Add(value); valueCacheMap[name] = list; } else { list.Add(value); } } } }
/// <summary> /// 属性变动事件注册 /// </summary> /// <param name="name"></param> /// <param name="callback"></param> virtual public void AddListenerOnce(string name, Action <object> callback = null, bool isTriggerCacheData = false) { if (dataMap.ContainsKey(name) == false) { BDebug.LogError("无数据,提前监听:" + name); } // List <Action <object> > actions = null; if (onceCallbackMap.TryGetValue(name, out actions)) { actions.Add(callback); } else { actions = new List <Action <object> >(); actions.Add(callback); onceCallbackMap[name] = actions; } if (isTriggerCacheData) { List <object> list = null; this.valueCacheMap.TryGetValue(name, out list); if (list != null) { foreach (var value in list) { callback(value); } //置空 this.valueCacheMap[name] = new List <object>(); } } }
/// <summary> /// 后退 /// </summary> public void Back() { var uiIdex = HistoryList[curForwardBackUIIdx]; //说明列表发生了变化,重设到栈顶 if (curForwardBackUI != uiIdex) { curForwardBackUIIdx = HistoryList.Count - 1; curForwardBackUI = HistoryList[curForwardBackUIIdx]; } if (curForwardBackUIIdx > 0) { curForwardBackUIIdx++; curForwardBackUI = this.HistoryList[curForwardBackUIIdx]; this.ShowWindow(curForwardBackUI, isAddToHistory: false); } else { BDebug.LogError("已经是底部"); } }
//选择配置 static public void ONGUI_SelcectConfig() { if (Application.isPlaying) { return; } GUI.color = Color.green; var launcher = GameObject.FindObjectOfType <BDLauncher>(); if (launcher == null) { BDebug.LogError("场景上没找到BDLauncher"); return; } var curFilePath = AssetDatabase.GetAssetPath(launcher.ConfigText.GetInstanceID()); var direct = Path.GetDirectoryName(curFilePath); var fs = Directory.GetFiles(direct, "*.json", SearchOption.AllDirectories) .Select((s) => s.Replace("\\", "/")).ToList(); var configNames = fs.Select((s) => Path.GetFileName(s)).ToArray(); if (curSlectConfigIdx == -1) { curSlectConfigIdx = fs.FindIndex((s) => s == curFilePath); } curSlectConfigIdx = EditorGUILayout.Popup("选择配置:", curSlectConfigIdx, configNames); if (fs[curSlectConfigIdx] != curFilePath) { Debug.Log("选择配置:" + fs[curSlectConfigIdx]); var assetText = AssetDatabase.LoadAssetAtPath <TextAsset>(fs[curSlectConfigIdx]); launcher.ConfigText = assetText; //设置新的配置内容 var config = GameObject.FindObjectOfType <Config>(); config.SetNewConfig(assetText.text); } GUI.color = GUI.backgroundColor; }
/// <summary> /// 加载 /// 一般来说,主资源才需要load /// 依赖资源只要加载ab,会自动依赖 /// </summary> /// <param name="assetPath"></param> /// <param name="isMainAsset">是否需要返回加载资源</param> /// <param name="callback"></param> /// <returns></returns> IEnumerator IE_AsyncLoadAssetbundle(LoaderTaskData task, Action <LoadAssetState> callback) { //正在被加载中,放入后置队列 if (lockSet.Contains(task.AssetPath)) { callback(LoadAssetState.IsLoding); yield break; } //没被加载 if (!loder.AssetbundleMap.ContainsKey(task.AssetPath)) { AssetBundleCreateRequest ret = null; string fullpath = ""; lockSet.Add(task.AssetPath); //加锁 { fullpath = loder.FindAsset(task.AssetPath); ret = AssetBundle.LoadFromFileAsync(fullpath); yield return(ret); } lockSet.Remove(task.AssetPath); //解锁 //添加assetbundle if (ret.assetBundle != null) { loder.AddAssetBundle(task.AssetPath, ret.assetBundle); } else { callback(LoadAssetState.Fail); BDebug.LogError("ab资源为空:" + fullpath); yield break; } } callback(LoadAssetState.Success); }
/// <summary> /// 异步加载接口 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="assetLoadPath">api传入的加载路径,Runtime下的相对路径</param> /// <param name="callback"></param> /// <returns>异步任务id</returns> public int AsyncLoad <T>(string assetLoadPath, Action <T> callback) where T : UnityEngine.Object { var cacheObj = GetObjectFormCache(typeof(T), assetLoadPath); if (!cacheObj) { var loadTask = CreateAsyncLoadTask <T>(assetLoadPath); if (loadTask != null) { //添加完成回调 loadTask.GetAwaiter().OnCompleted(() => { if (!loadTask.IsCancel) { //回调 var obj = loadTask.GetResult <T>(); callback(obj); } }); //添加到任务队列 AddAsyncTaskGroup(loadTask); return(loadTask.Id); } else { BDebug.LogError("不存在资源:" + assetLoadPath); } } else { //返回缓存的数据 var obj = cacheObj as T; callback?.Invoke(obj); } return(-1); }
// Use this for initialization private void Awake() { Inst = this; this.gameObject.AddComponent <IEnumeratorTool>(); var debug = this.gameObject.GetComponent <BDebug>(); //游戏配置 if (this.ConfigText) { this.GameConfig = JsonMapper.ToObject <GameConfig>(this.ConfigText.text); } else { BDebug.LogError("GameConfig配置为null,请检查!"); } //日志打印 debug.IsLog = this.GameConfig.IsDebugLog; //添加不删除的组件 if (Application.isPlaying) { DontDestroyOnLoad(this); } }
/// <summary> /// 加载ab /// </summary> /// <param name="path"></param> /// <param name="callback"></param> private void AsyncLoadAssetBundle(string path, Action <bool> callback) { //ab存储的是asset下的相对目录 path = "assets/resource/runtime/" + path.ToLower() + "."; //寻找ab的后缀名 var mainAssetPath = GetExistPath(path); if (mainAssetPath != null) { //1.依赖资源 var res = manifest.Manifest.GetDirectDependencies(mainAssetPath).ToList(); //2.主体资源 res.Add(mainAssetPath); //开始加载队列 IEnumeratorTool.StartCoroutine(IEAsyncLoadAssetbundle(res, callback)); } else { BDebug.LogError("没有该资源:" + path); //没有该资源 callback(false); } }
/// <summary> /// 加载dll /// </summary> /// <param name="path"></param> /// <returns></returns> static IEnumerator IE_LoadDLL_AndroidOrPC(string path) { if (Application.isEditor) { path = "file://" + path; } var www = new WWW(path); yield return(www); if (www.isDone && www.error == null) { var assembly = Assembly.Load(www.bytes); var type = assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); method.Invoke(null, new object[] { false, true }); } else { BDebug.LogError("DLL加载失败:" + www.error); } }
static public void GenGameConfig(string str, string platform) { var gameConfig = new GameConfig(); var gcType = gameConfig.GetType(); //config var config = GameObject.Find("BDFrame").GetComponent <Config>(); var configType = config.GetType(); // foreach (var f in gcType.GetFields()) { var ctf = configType.GetField(f.Name); //反射赋值 if (f.FieldType == ctf.FieldType) { f.SetValue(gameConfig, ctf.GetValue(config)); } else if (f.FieldType == typeof(int) && ctf.FieldType.IsEnum) { f.SetValue(gameConfig, (int)ctf.GetValue(config)); } else { BDebug.LogError("类型不匹配:" + f.Name); } } var json = JsonMapper.ToJson(gameConfig); var fs = string.Format("{0}/{1}/{2}", str, platform, "GameConfig.json"); FileHelper.WriteAllText(fs, json); AssetDatabase.Refresh(); Debug.Log("导出成功:" + fs); }
/// <summary> /// 属性变动事件注册 /// </summary> /// <param name="name"></param> /// <param name="callback"></param> virtual public void RegAction(string name, CallBack callback, bool isTriggerCacheData = false) { if (dataMap.ContainsKey(name) == false) { BDebug.LogError("监听无效,无该数据:" + name); return; } // CallBack call = null; callbackMap.TryGetValue(name, out call); if (call == null) { callbackMap[name] = callback; } else { call += callback; callbackMap[name] = call; } if (isTriggerCacheData) { List <object> list = null; this.valueCacheMap.TryGetValue(name, out list); if (list != null) { foreach (var value in list) { callback(value); } //置空 this.valueCacheMap[name] = new List <object>(); } } }
//called by Physics World just before rigid body is added to world. //the current rigid body properties are used to rebuild the rigid body. internal override bool _BuildCollisionObject() { BPhysicsWorld world = BPhysicsWorld.Get(); if (m_rigidBody != null && isInWorld && world != null) { isInWorld = false; world.RemoveRigidBody(m_rigidBody); } if (transform.localScale != UnityEngine.Vector3.one) { BDebug.LogError(debugType, "The local scale on this rigid body is not one. Bullet physics does not support scaling on a rigid body world transform. Instead alter the dimensions of the CollisionShape."); } m_collisionShape = GetComponent <BCollisionShape>(); if (m_collisionShape == null) { BDebug.LogError(debugType, "There was no collision shape component attached to this BRigidBody. {0}", name); return(false); } CollisionShape cs = m_collisionShape.GetCollisionShape(); if (m_motionState == null) { m_motionState = new BGameObjectMotionState(transform); } BulletSharp.RigidBody rb = (BulletSharp.RigidBody)m_collisionObject; CreateOrConfigureRigidBody(ref rb, ref _localInertia, cs, m_motionState); m_collisionObject = rb; m_collisionObject.UserObject = this; return(true); }
public override void AutoSetMethod(IComponent com, MethodInfo methodInfo) { Action action = null; var btn = com.Transform.Find(this.path)?.GetComponent <Button>(); if (btn) { if (isTriggerThisOnly) { btn.onClick.RemoveAllListeners(); } btn.onClick.AddListener(() => { //触发按钮事件 methodInfo.Invoke(com, new object[] { }); }); } else { BDebug.LogError("未找到Btn:" + this.path); } }
/// <summary> /// 异步加载接口 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="assetName"></param> /// <param name="callback"></param> /// <returns>异步任务id</returns> public int AsyncLoad <T>(string assetName, Action <T> callback) where T : UnityEngine.Object { var taskGroup = CreateAsyncLoadTask <T>(assetName); if (taskGroup != null) { //添加完成回调 taskGroup.OnAllTaskCompleteCallback += (p) => { var obj = taskGroup.GetAssetBundleInstance <T>(); //回调 callback(obj); }; //添加到任务队列 AddAsyncTaskGroup(taskGroup); return(taskGroup.Id); } else { BDebug.LogError("不存在资源:" + assetName); } return(-1); }
/// <summary> /// 注册回调 /// </summary> private void RegisterActions() { //注册回调 var t = this.GetType(); var flag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; foreach (var methodInfo in t.GetMethods(flag)) { var attrs = methodInfo.GetCustomAttributes(typeof(UIMessageAttribute), false); if (attrs.Length > 0) { var _attr = attrs[0] as UIMessageAttribute; var action = Delegate.CreateDelegate(typeof(Action <UIMessageData>), this, methodInfo) as Action <UIMessageData>; if (action != null) { callbackMap[_attr.MessageName] = action; } else { BDebug.LogError("uimessage 函数签名错误:" + methodInfo.Name); } } } }
public void DoEvent(SkillEvent skillEvent, IBattle battle, IHeroFSM selfFSM, IHeroFSM targetFSM) { ISkillEvent _event = null; var cd = this.GetCalssData(skillEvent.EventName); if (cd != null) { _event = Activator.CreateInstance(cd.Type, skillEvent) as ISkillEvent; } // if (_event != null) { BDebug.Log("执行skillEvent:" + skillEvent.EventName); _event.Do(battle, selfFSM, targetFSM); } else { BDebug.LogError("未找到技能事件:" + skillEvent.EventName); } }
/// <summary> /// 注册回调 /// </summary> private void RegisterUIMessages() { //注册回调 var t = this.GetType(); var flag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; foreach (var mi in t.GetMethods(flag)) { var attr = mi.GetAttributeInILRuntime <UIMessageListenerAttribute>(); if (attr != null) { var @params = mi.GetParameters(); if (@params.Length == 1) { msgCallbackMap[@params[0].ParameterType] = mi; } else { BDebug.LogError("UIMsg 绑定失败,请检查函数签名:" + mi.Name); } } } }
/// <summary> /// 开始任务 /// </summary> /// <param name="serverConfigPath">服务器配置根目录</param> /// <param name="localConfigPath">本地根目录</param> /// <param name="onProcess"></param> /// <param name="onError"></param> /// 返回码: -1:error 0:success static async public Task <int> Start(string serverConfigPath, string localConfigPath, Action <int, int> onProcess, Action <string> onError) { IPath.Combine("", ""); var client = HttpMgr.Inst.GetFreeHttpClient(); var platform = Utils.GetPlatformPath(Application.platform); //开始下载服务器配置 var serverPath = serverConfigPath + "/" + platform + "/" + platform + "_VersionConfig.json"; Debug.Log("server:" + serverPath); string serverConfig = ""; try { serverConfig = await client.DownloadStringTaskAsync(serverPath); BDebug.Log("服务器资源配置:" + serverConfig); } catch (Exception e) { onError(e.Message); return(-1); } var serverconf = LitJson.JsonMapper.ToObject <AssetConfig>(serverConfig); AssetConfig localconf = null; var localPath = localConfigPath + "/" + platform + "/" + platform + "_VersionConfig.json"; if (File.Exists(localPath)) { localconf = LitJson.JsonMapper.ToObject <AssetConfig>(File.ReadAllText(localPath)); } //对比差异列表进行下载 var list = CompareConfig(localConfigPath, localconf, serverconf); if (list.Count > 0) { //预通知要进入热更模式 onProcess(0, list.Count); } int count = 0; foreach (var item in list) { count++; var sp = serverConfigPath + "/" + platform + "/" + item.HashName; var lp = localConfigPath + "/" + platform + "/" + item.LocalPath; //创建目录 var direct = Path.GetDirectoryName(lp); if (Directory.Exists(direct) == false) { Directory.CreateDirectory(direct); } //下载 try { await client.DownloadFileTaskAsync(sp, lp); } catch (Exception e) { BDebug.LogError(sp); onError(e.Message); return(-1); } BDebug.Log("下载成功:" + sp); onProcess(count, list.Count); } //写到本地 if (list.Count > 0) { File.WriteAllText(localPath, serverConfig); } else { BDebug.Log("可更新数量为0"); } return(0); }
/// <summary> /// 开始版本控制逻辑 /// </summary> /// <param name="serverUrl">服务器配置根目录</param> /// <param name="localSaveAssetsPath">本地根目录</param> /// <param name="onDownloadProccess">任务进度通知(下载完不等于任务完成!)</param> /// <param name="onTaskEndCallback">任务成功\失败通知!</param> /// 返回码: -1:error 0:success async private Task StartVersionControl(UpdateMode updateMode, string serverUrl, string localSaveAssetsPath, string subPackageName, Action <AssetItem, List <AssetItem> > onDownloadProccess, Action <RetStatus, string> onTaskEndCallback) { var platform = BApplication.RuntimePlatform; //目录准备 var platformStr = BApplication.GetRuntimePlatformPath(); var localSavePlatformPath = IPath.Combine(localSaveAssetsPath, platformStr); if (!Directory.Exists(localSavePlatformPath)) { Directory.CreateDirectory(localSavePlatformPath); } //子包模式判断 bool isDownloadSubPackageMode = !string.IsNullOrEmpty(subPackageName); //1.下载服务器version config var serverVersionInfo = new AssetsVersionInfo(); var localVersionInfo = new AssetsVersionInfo(); #region AssetVersion.info下载 BDebug.Log("【版本控制】1.获取版本信息~", "red"); { var ret = await DownloadAssetVersionInfo(serverUrl, localSaveAssetsPath); if (ret.Item1 != null) { await UniTask.SwitchToMainThread(); onTaskEndCallback?.Invoke(RetStatus.Error, ret.Item1); return; } serverVersionInfo = ret.Item2; localVersionInfo = ret.Item3; } #endregion //2.对比版本、获取对应数据 BDebug.Log("【版本控制】2.对比版本信息~", "red"); string err = null; string suc = null; var serverAssetsInfoList = new List <AssetItem>(); var localAssetsInfoList = new List <AssetItem>(); var serverAssetsContent = ""; // switch (updateMode) { case UpdateMode.Compare: case UpdateMode.CompareWithRepair: //CP模式对比版本与Compare一致 { if (isDownloadSubPackageMode) { //分包模式 (err, suc, serverAssetsInfoList, localAssetsInfoList, serverAssetsContent) = GetDownloadSubPackageData(serverUrl, subPackageName, platform, serverVersionInfo, localVersionInfo); } else { //全量下载 (err, suc, serverAssetsInfoList, localAssetsInfoList, serverAssetsContent) = GetDownloadAssetsData(serverUrl, platform, serverVersionInfo, localVersionInfo); } } break; case UpdateMode.Repair: { //服务器路径 var serverAssetInfosUrl = BResources.GetAssetsInfoPath(serverUrl, platform); //下载服务器Assets.info (err, serverAssetsInfoList, serverAssetsContent) = LoadServerAssetInfo(serverAssetInfosUrl); } break; } //返回返回结果,是否继续下载 if (err != null) { BDebug.LogError(err); await UniTask.SwitchToMainThread(); onTaskEndCallback?.Invoke(RetStatus.Error, err); return; } if (suc != null) { BDebug.Log(suc); await UniTask.SwitchToMainThread(); onTaskEndCallback?.Invoke(RetStatus.Success, suc); return; } //3.生成差异列表 BDebug.Log("【版本控制】3.获取差异列表~", "red"); Queue <AssetItem> diffDownloadQueue = null; #region 生成差异文件 switch (updateMode) { case UpdateMode.Compare: { diffDownloadQueue = Compare(localAssetsInfoList, serverAssetsInfoList, platform); } break; case UpdateMode.Repair: case UpdateMode.CompareWithRepair: //CP 获取差异模式与Repair一致 { diffDownloadQueue = Repair(serverAssetsInfoList, platform); } break; } BDebug.Log($"【版本控制】 配置数量:{serverAssetsInfoList.Count} ,本地存在{serverAssetsInfoList.Count - diffDownloadQueue.Count},下载文件数量{diffDownloadQueue.Count}", "yellow"); #endregion //4.开始下载 #region 根据差异文件下载 BDebug.Log("【版本控制】4.下载资源~", "red"); { var failDownloadList = await DownloadAssets(serverUrl, localSaveAssetsPath, diffDownloadQueue, onDownloadProccess); if (failDownloadList.Count > 0) { onTaskEndCallback(RetStatus.Error, "部分资源未下载完毕!"); return; } } #endregion //5.写入配置到本地 #region 存储配置到本地 BDebug.Log("【版本控制】5.写入配置~", "red"); string localAssetInfoPath = ""; if (isDownloadSubPackageMode) { localAssetInfoPath = BResources.GetAssetsSubPackageInfoPath(BApplication.persistentDataPath, platform, subPackageName); } else { localAssetInfoPath = BResources.GetAssetsInfoPath(BApplication.persistentDataPath, platform); } //写入Asset.Info File.WriteAllText(localAssetInfoPath, serverAssetsContent); BDebug.Log($"【版本控制】写入{Path.GetFileName(localAssetInfoPath)} \n {serverAssetsContent}"); //写入Version.Info if (isDownloadSubPackageMode) { localVersionInfo.Platfrom = serverVersionInfo.Platfrom; //子包版本信息 localVersionInfo.SubPckMap[subPackageName] = serverVersionInfo.SubPckMap[subPackageName]; } else { localVersionInfo.Platfrom = serverVersionInfo.Platfrom; //全量包信息 localVersionInfo.Version = serverVersionInfo.Version; } var localAssetsVersionInfoPath = BResources.GetServerAssetsVersionInfoPath(localSaveAssetsPath, platform); File.WriteAllText(localAssetsVersionInfoPath, JsonMapper.ToJson(localVersionInfo)); BDebug.Log($"【版本控制】写入{Path.GetFileName(localAssetsVersionInfoPath)}"); #endregion // 6.删除过期资源 BDebug.Log("【版本控制】6.冗余资源检查~", "red"); if (!isDownloadSubPackageMode) { var artAssetsPath = IPath.Combine(localSavePlatformPath, BResources.ART_ASSET_ROOT_PATH); var persistentArtAssets = Directory.GetFiles(artAssetsPath, "*", SearchOption.AllDirectories); var replacePath = localSavePlatformPath + "/"; foreach (var assetPath in persistentArtAssets) { var localPath = assetPath.Replace(replacePath, "").Replace("\\", "/"); var ret = serverAssetsInfoList.FirstOrDefault((info) => info.LocalPath.Equals(localPath)); if (ret == null) { BDebug.Log("【版本控制】删除过期资源:" + localPath); File.Delete(assetPath); } } } // 7.资源校验文件 BDebug.Log("【版本控制】7.整包资源校验~", "red"); err = null; foreach (var serverAssetItem in serverAssetsInfoList) { var ret = BResources.IsExsitAssetWithCheckHash(platform, serverAssetItem.LocalPath, serverAssetItem.HashName); if (!ret) { if (string.IsNullOrEmpty(err)) { err = "资源不存在:"; } err += $"\n {serverAssetItem.LocalPath}"; } } //the end. BDebug.Log("【版本控制】end.完成~", "red"); await UniTask.SwitchToMainThread(); if (err == null) { onTaskEndCallback?.Invoke(RetStatus.Success, null); } else { onTaskEndCallback?.Invoke(RetStatus.Error, err); } }
/// <summary> /// 加载 /// </summary> /// <param name="types"></param> /// <returns></returns> static public List <IMgr> LoadManagerInstance(Type[] types) { //管理器列表 var mgrList = new List <IMgr>(); for (int i = 0; i < types.Length; i++) { var type = types[i]; if (type != null && type.BaseType != null && type.BaseType.FullName != null) { if (type.BaseType.FullName.Contains(".ManagerBase`2")) //这里ILR里面只能这么做,丑但有效 { BDebug.Log("[hotfix]加载管理器-" + type.FullName, "green"); var mgr = type.BaseType.GetProperty("Inst").GetValue(null, null) as IMgr; if (mgr != null) { mgrList.Add(mgr); } else { BDebug.LogError("[hotfix]加载管理器失败-" + type.FullName); } } } } //按执行顺序排序 //按执行顺序排序 mgrList.Sort((a, b) => { var aAttr = a.GetType().GetCustomAttribute <ManagerOrder>(); var bAttr = a.GetType().GetCustomAttribute <ManagerOrder>(); var aOrder = aAttr == null ? 0 : aAttr.Order; var bOrder = bAttr == null ? 0 : bAttr.Order; //对比 return(aOrder.CompareTo(bOrder)); }); BDebug.Log("[hotfix]管理器加载完成", "green"); //遍历type执行逻辑 for (int i = 0; i < types.Length; i++) { var type = types[i]; var mgrAttribute = type.GetAttributeInILRuntime <ManagerAttribute>(); if (mgrAttribute == null) { continue; } //注册类型 foreach (var iMgr in mgrList) { iMgr.CheckType(type, mgrAttribute); } } //管理器初始化 foreach (var m in mgrList) { m.Init(); } return(mgrList); }
/// <summary> /// bind Tansform和State的值,防止每次都修改 /// </summary> /// <param name="t"></param> /// <param name="aState"></param> /// <returns></returns> private Dictionary <string, ComponentValueCahce> TransformStateBind(Transform t, AStateBase aState) { Dictionary <string, ComponentValueCahce> retMap = new Dictionary <string, ComponentValueCahce>(); //所有的成员信息 var memberInfos = StateFactory.GetCache(aState.GetType()); foreach (var mi in memberInfos.Values) { //先寻找节点 Transform transform = null; { var attrs = mi.GetCustomAttributes(typeof(TransformPath), false); if (attrs.Length > 0) { var attr = attrs[0] as TransformPath; transform = t.Find(attr.Path); if (!transform) { BDebug.LogError("节点不存在:" + attr.Path + " -" + aState.GetType().Name); continue; } } else { continue; } } //再进行值绑定 { ComponentValueCahce cvc = new ComponentValueCahce(); var attrType = typeof(ComponentValueBind); var attrs = mi.GetCustomAttributes(attrType, false); // if (attrs.Length > 0) //寻找ComponentValueBind { if (attrs[0] is ComponentValueBind) { var cvb = (ComponentValueBind)attrs[0]; if (cvb.Type.IsSubclassOf(typeof(UIBehaviour))) { cvc.UIBehaviour = transform.GetComponent(cvb.Type) as UIBehaviour; } else { cvc.Transform = transform; } cvc.ValueBind = cvb; } } else //如果只有Transform 没有ComponentValueBind标签,处理默认逻辑 { Type type = null; if (mi is FieldInfo) { type = ((FieldInfo)mi).FieldType; } else if (mi is PropertyInfo) { type = ((PropertyInfo)mi).PropertyType; } if (type.IsSubclassOf(typeof(PropsBase))) { //填充 子节点赋值逻辑 cvc.ValueBind = new ComponentValueBind(typeof(UFluxAutoLogic), nameof(UFluxAutoLogic.SetChildValue)); } else { cvc.ValueBind = new ComponentValueBind(typeof(UFluxAutoLogic), nameof(UFluxAutoLogic.ForeachSetChildValue)); #if UNITY_EDITOR //props 数组 if (type.IsArray && !type.GetElementType().IsSubclassOf(typeof(PropsBase))) //数组 { Debug.LogError("自动适配节点逻辑失败,类型元素不是Props!!!"); } //泛型 else if (type.IsGenericType && !type.GetGenericArguments()[0].IsSubclassOf(typeof(PropsBase))) //泛型 { Debug.LogError("自动适配节点逻辑失败,类型元素不是Props!!!"); } #endif //list t或者array if (type.IsArray || type.IsGenericType) //数组 { cvc.ValueBind = new ComponentValueBind(typeof(UFluxAutoLogic), nameof(UFluxAutoLogic.ForeachSetChildValue)); } } cvc.Transform = transform; } //缓存 retMap[mi.Name] = cvc; } } return(retMap); }
/// <summary> /// view层自动设置 /// </summary> /// <param name="view"></param> static private void ViewAutoSet(IView view) { var vt = view.GetType(); var fields = vt.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); var vTransform = view.Transform; foreach (var f in fields) { if (f.FieldType.IsSubclassOf(checkType) == false) { continue; } //1.自动获取节点 //TODO 热更层必须这样获取属性 var _attrs = f.GetCustomAttributes(typeof(TransformPath), false); //as Attribute[]; if (_attrs != null && _attrs.Length > 0) { var attr = _attrs.ToList().Find((a) => a is TransformPath) as TransformPath; if (attr == null) { continue; } //获取节点,并且获取组件 var trans = vTransform.Find(attr.Path); if (trans == null) { BDebug.LogError(string.Format("自动设置节点失败:{0} - {1}", vt.FullName, attr.Path)); } var comp = trans.GetComponent(f.FieldType); if (comp == null) { BDebug.LogError(string.Format("节点没有对应组件:type【{0}】 - {1}", f.FieldType, attr.Path)); } //设置属性 f.SetValue(view, comp); //Debug.LogFormat("字段{0}获取到setTransform ,path:{1}" , f.Name , attr.Path); } else { //Debug.LogFormat("字段{0}没找到setTransform" , f.Name); } //2.自动绑定数据驱动 _attrs = f.GetCustomAttributes(typeof(BindModel), false); //as Attribute[]; if (_attrs != null && _attrs.Length > 0) { var bAttr = _attrs.ToList().Find((a) => a is BindModel) as BindModel; if (bAttr == null) { continue; } var name = bAttr.Name; var _Model = view.Model; //注册属性名 _Model.AddData(bAttr.Name); //注册事件监听 _Model.AddListener(bAttr.Name, (v) => { if (f.FieldType == typeof(Text)) { var c = f.GetValue(view) as Text; c.text = v.ToString(); } else if (f.FieldType == typeof(Slider)) { var c = f.GetValue(view) as Slider; c.value = (float)v; } else if (f.FieldType == typeof(Scrollbar)) { var c = f.GetValue(view) as Scrollbar; c.value = (float)v; } else if (f.FieldType == typeof(Toggle)) { var c = f.GetValue(view) as Toggle; c.isOn = (bool)v; } else { BDebug.LogError("不支持类型,请扩展:" + f.Name + "-" + vt.FullName); } }); } } }
/// <summary> /// 设置数据 /// </summary> /// <param name="name">数据名</param> /// <param name="value">数据值</param> /// <param name="isTriggerCallback">是否触发回调</param> /// <param name="isOnlyTriggerEvent">是否只响应事件(不返回值)</param> virtual public void SetData(string name, object value, bool isTriggerCallback = true) { //移除任务 执行 while (removeTaskQueue.Count > 0) { var removeTask = removeTaskQueue.Dequeue(); List <ListenerCallbackData> listenerDatas = null; if (callbackMap.TryGetValue(removeTask.Name, out listenerDatas)) { foreach (var data in listenerDatas) { if (data.ActionAdaptor.Equals(removeTask.Action)) { listenerDatas.Remove(data); break; } } } } //数据验证 if (dataMap.ContainsKey(name)) { //editor抛出这个 if (Application.isEditor) { var lastV = dataMap[name]; if (lastV != null) { var lastT = lastV.GetType(); var currentT = value.GetType(); if (lastT != currentT) { Debug.LogErrorFormat("设置失败,类型不匹配:{0} curType:{1} setType:{2}", name, lastT.Name, currentT.Name); return; } } } dataMap[name] = value; } else { BDebug.LogError("设置无效,无该数据:" + name); return; } //触发回调 if (isTriggerCallback) { //all List <ListenerCallbackData> listenerCallbackDatas = null; // if (callbackMap.TryGetValue(name, out listenerCallbackDatas)) { //触发回调 for (int i = 0; i < listenerCallbackDatas.Count; i++) { var listenerCallback = listenerCallbackDatas[i]; //执行回调 listenerCallback.Invoke(value); } //清理列表 for (int i = listenerCallbackDatas.Count - 1; i >= 0; i--) { if (listenerCallbackDatas[i].TriggerNum == 0) { listenerCallbackDatas.RemoveAt(i); } } } else //cache list { List <object> list = null; valueCacheMap.TryGetValue(name, out list); if (list == null) { list = new List <object>(); valueCacheMap[name] = list; } if (list.Count >= maxCacheValueCount) { list.RemoveAt(0); } list.Add(value); } } }
/// <summary> /// 加载assetbundle 文件 /// </summary> private bool AsyncLoadAssetbundleFile() { //1.loadABFile,循环添加任务 while (!isCancel && AssetBundleMgrV2.IsCanAddGlobalTask && curLoadIdx < waitingLoadAssetBundleList.Count - 1) { curLoadIdx++; var abi = waitingLoadAssetBundleList[curLoadIdx]; //没有被加载过 var abw = loder.GetAssetBundleFromCache(abi.AssetBundlePath); if (abw == null) { //判断是否在加载中 var loadTask = AssetBundleMgrV2.GetExsitLoadTask(abi.AssetBundlePath); if (loadTask != null) { loadingTaskList.Add(new KeyValuePair <string, LoadTask>(abi.AssetBundlePath, loadTask)); } else { //创建任务 var abPath = loder.FindMultiAddressAsset(abi.AssetBundlePath); loadTask = new LoadTask(abPath, 0, (ulong)abi.Mix); //加入Global任务 AssetBundleMgrV2.AddGlobalLoadTask(loadTask); //添加到loading表 loadingTaskList.Add(new KeyValuePair <string, LoadTask>(abi.AssetBundlePath, loadTask)); //开始加载 loadTask.AysncLoad(); BDebug.Log($"【AsyncLoadTaskGroup】 加 载: {abi.AssetBundlePath}"); } } else { BDebug.Log($"【AsyncLoadTaskGroup】 无需加载: {abi.AssetBundlePath}"); } } //2.loadABFile,检测加载状态 if (loadingTaskList.Count > 0) { for (int i = loadingTaskList.Count - 1; i >= 0; i--) { var loadingTask = loadingTaskList[i]; var assetbundleFileName = loadingTask.Key; var loadTask = loadingTask.Value; //判断是否结束 if (loadTask.IsDone) { //添加到返回列表 if (loadTask.AssetBundle != null) { loder.AddAssetBundleToCache(assetbundleFileName, loadTask.AssetBundle); } else { BDebug.LogError("【AsyncLoadTaskGroup】ab资源为空:" + assetbundleFileName); } //移除成功任务 loadingTaskList.RemoveAt(i); //解锁 AssetBundleMgrV2.RemoveGlobalLoadTask(loadTask); BDebug.Log($"【AsyncLoadTaskGroup】--> 加载完成:{assetbundleFileName} 剩余:{loadingTaskList.Count + waitingLoadAssetBundleList.Count - (curLoadIdx + 1)}/{waitingLoadAssetBundleList.Count}"); } } } //3.任务执行完毕检测 if (!isCancel && loadingTaskList.Count == 0 && curLoadIdx == waitingLoadAssetBundleList.Count - 1) { //加载完成,主资源只要保证在 实例化之前加载完毕即可 //加载完则使用 BDebug.Log($"<color=green>【AsyncLoadTaskGroup】所有加载完成:{MainAssetBundleItem.AssetBundlePath}</color>"); return(true); } return(false); }
/// <summary> /// 异步加载 多个 /// </summary> /// <param name="assetsPath">资源</param> /// <param name="onLoadComplete">加载结束</param> /// <param name="onLoadProcess">进度</param> /// <returns>taskid</returns> public List <int> AsyncLoad(IList <string> assetsPath, Action <IDictionary <string, Object> > onLoadComplete, Action <int, int> onLoadProcess) { List <int> idList = new List <int>(); IDictionary <string, Object> retMap = new Dictionary <string, Object>(); assetsPath = assetsPath.Distinct().ToList(); //去重 int total = assetsPath.Count; //source int counter = 0; foreach (var assetPath in assetsPath) { var path = string.Format(RUNTIME, assetPath.ToLower()); // var mainItem = loder.Manifest.GetManifest(path); List <LoaderTaskData> taskQueue = new List <LoaderTaskData>(); //获取依赖 if (mainItem == null) { BDebug.LogError("不存在:" + path); total--; continue; } //依赖任务 foreach (var r in mainItem.Depend) { var task = new LoaderTaskData(r, typeof(Object)); taskQueue.Add(task); } //主任务 var mainTask = new LoaderTaskData(mainItem.Path, typeof(Object)); taskQueue.Add(mainTask); //添加任务组 //加载颗粒度10个 LoaderTaskGroup taskGroup = new LoaderTaskGroup(mainItem.Path, ASYNC_TASK_UNIT, taskQueue, AsyncLoadAssetBundle, //Load接口 (p, obj) => { counter++; //注意返回加载的id,不是具体地址的id retMap[assetPath] = obj; if (onLoadProcess != null) { onLoadProcess(counter, total); } //完成 if (retMap.Count == total) { onLoadComplete(retMap); } }); taskGroup.Id = this.taskIDCounter++; AddTaskGroup(taskGroup); idList.Add(taskGroup.Id); } //开始任务 DoNextTask(); // return(idList); }
/// <summary> /// 加载 /// 一般来说,主资源才需要load /// 依赖资源只要加载ab,会自动依赖 /// </summary> /// <param name="name"></param> /// <param name="isLoadObj">是否需要返回加载资源</param> /// <param name="callback"></param> /// <returns></returns> IEnumerator IE_AsyncLoadAssetbundle(string name, bool isLoadObj, Action <LoadAssetState, Object> callback) { // // var mainItem = loder.Manifest.GetManifest(name); // //单ab 多资源,加载真正ab名 // if (mainItem != null && !string.IsNullOrEmpty(mainItem.AB)) // { // name = mainItem.AB; // } //正在被加载中,放入后置队列 if (lockSet.Contains(name)) { callback(LoadAssetState.IsLoding, null); yield break; } //没被加载 if (!AssetbundleMap.ContainsKey(name)) { AssetBundleCreateRequest ret = null; string fullpath = ""; //加锁 lockSet.Add(name); { fullpath = FindAsset(name); ret = AssetBundle.LoadFromFileAsync(fullpath); yield return(ret); } //解锁 lockSet.Remove(name); //添加assetbundle if (ret.assetBundle != null) { AddAssetBundle(name, ret.assetBundle); if (isLoadObj) { callback(LoadAssetState.Success, LoadFormAssetBundle <Object>(name)); } else { callback(LoadAssetState.Success, null); } } else { callback(LoadAssetState.Fail, null); BDebug.LogError("ab资源为空:" + fullpath); } } else { if (isLoadObj) { callback(LoadAssetState.Success, LoadFormAssetBundle <Object>(name)); } else { callback(LoadAssetState.Success, null); } } }
//called by Physics World just before rigid body is added to world. //the current rigid body properties are used to rebuild the rigid body. internal override bool _BuildCollisionObject() { BPhysicsWorld world = BPhysicsWorld.Get(); if (m_rigidBody != null) { if (isInWorld && world != null) { isInWorld = false; world.RemoveRigidBody(m_rigidBody); } } if (transform.localScale != UnityEngine.Vector3.one) { BDebug.LogError(debugType, "The local scale on this rigid body is not one. Bullet physics does not support scaling on a rigid body world transform. Instead alter the dimensions of the CollisionShape."); } m_collisionShape = GetComponent <BCollisionShape>(); if (m_collisionShape == null) { BDebug.LogError(debugType, "There was no collision shape component attached to this BRigidBody. {0}", name); return(false); } CollisionShape cs = m_collisionShape.GetCollisionShape(); //rigidbody is dynamic if and only if mass is non zero, otherwise static _localInertia = BulletSharp.Math.Vector3.Zero; if (isDynamic()) { cs.CalculateLocalInertia(_mass, out _localInertia); } if (m_rigidBody == null) { m_motionState = new BGameObjectMotionState(transform); RigidBodyConstructionInfo rbInfo; if (isDynamic()) { rbInfo = new RigidBodyConstructionInfo(_mass, m_motionState, cs, _localInertia); } else { rbInfo = new RigidBodyConstructionInfo(0, m_motionState, cs, localInertia); } m_rigidBody = new RigidBody(rbInfo); m_rigidBody.UserObject = this; rbInfo.Dispose(); m_rigidBody.CollisionFlags = m_collisionFlags; } else { float usedMass = 0f; if (isDynamic()) { usedMass = _mass; } m_rigidBody.SetMassProps(usedMass, localInertia); m_rigidBody.CollisionShape = cs; m_rigidBody.CollisionFlags = m_collisionFlags; } //if kinematic then disable deactivation if ((m_collisionFlags & BulletSharp.CollisionFlags.KinematicObject) != 0) { m_rigidBody.ActivationState = ActivationState.DisableDeactivation; } return(true); }
/// <summary> /// 下载Assets /// 用于加载资源时,本地不存在则向服务器请求 /// </summary> /// <param name="serverUrl"></param> /// <param name="localSaveAssetsPath"></param> /// <param name="downloadQueue"></param> /// <param name="onDownloadProccess"></param> /// <param name="failDownloadList"></param> /// <returns></returns> public IEnumerator IE_DownloadAssets(string serverUrl, string localSaveAssetsPath, Queue <AssetItem> downloadQueue, Action <AssetItem, List <AssetItem> > onDownloadProccess) { var failDownloadList = new List <AssetItem>(); //url构建 var platform = BApplication.GetPlatformPath(BApplication.RuntimePlatform); serverUrl = IPath.Combine(serverUrl, platform); localSaveAssetsPath = IPath.Combine(localSaveAssetsPath, platform); //1.任务缓存 var downloadCacheList = downloadQueue.ToList(); //2.开始任务 while (downloadQueue.Count > 0) { var downloadItem = downloadQueue.Dequeue(); //本地存在hash文件 var localDownloadFile = IPath.Combine(localSaveAssetsPath, downloadItem.HashName); //下载 UnityWebRequest uwq = null; //先进行下载hash文件,所有的完成后再进行rename成资源 var serverAssetUrl = IPath.Combine(serverUrl, downloadItem.HashName); //下载具体资源 ,任务会重试5次 uwq = UnityWebRequest.Get(serverAssetUrl); for (int i = 0; i < RETRY_COUNT; i++) { yield return(uwq.SendWebRequest()); if (uwq.isHttpError || uwq.isNetworkError) { //对比hash var downloadFileHash = FileHelper.GetMurmurHash3(uwq.downloadHandler.data); if (downloadFileHash == downloadItem.HashName) { BDebug.Log("下载成功:" + serverAssetUrl); break; } else { BDebug.LogError("【版本控制】重下, hash校验失败! server-" + downloadItem.HashName + " local-" + downloadFileHash); } } } // if (!uwq.isHttpError && !uwq.isNetworkError) { onDownloadProccess(downloadItem, downloadCacheList); FileHelper.WriteAllBytes(localDownloadFile, uwq.downloadHandler.data); } else { //这边需要继续下载,最后统计失败文件 failDownloadList.Add(downloadItem); BDebug.LogError("下载失败:" + uwq.error); } uwq?.Dispose(); } //3.写入本地 foreach (var assetItem in downloadCacheList) { var localHashPath = IPath.Combine(localSaveAssetsPath, assetItem.HashName); var localRealPath = IPath.Combine(localSaveAssetsPath, assetItem.LocalPath); if (File.Exists(localHashPath)) { if (File.Exists(localRealPath)) { File.Delete(localRealPath); } //移动(重命名) FileHelper.Move(localHashPath, localRealPath); } } }
/// <summary> /// view层自动设置 /// </summary> /// <param name="view"></param> static private void ViewAutoSet(IView view) { var vt = view.GetType(); var fields = vt.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); var vTransform = vt.GetProperty("Transform").GetValue(view) as Transform; foreach (var f in fields) { if (!f.FieldType.IsSubclassOf(typeof(UnityEngine.Object))) { continue; } //1.自动获取节点 var attr = f.GetCustomAttribute <SetTransform>(); if (attr != null) { //获取节点,并且获取组件 var trans = vTransform.Find(attr.Path); if (trans == null) { BDebug.LogError(string.Format("自动设置节点失败:{0} - {1}", vt.FullName, attr.Path)); } var comp = trans.GetComponent(f.FieldType); if (comp == null) { BDebug.LogError(string.Format("节点没有对应组件:type【{0}】 - {1}", f.FieldType, attr.Path)); } //设置属性 f.SetValue(view, comp); } //2.自动绑定数据驱动 var bAttr = f.GetCustomAttribute <BindData>(); if (bAttr != null) { var name = bAttr.Name; var _Model = view.Model; //注册属性名 _Model.RegisterData(bAttr.Name); //注册事件监听 _Model.RegAction(bAttr.Name, (v) => { if (f.FieldType == typeof(Text)) { var c = f.GetValue(view) as Text; c.text = v.ToString(); } else if (f.FieldType == typeof(Slider)) { var c = f.GetValue(view) as Slider; c.value = (float)v; } else if (f.FieldType == typeof(Scrollbar)) { var c = f.GetValue(view) as Scrollbar; c.value = (float)v; } else if (f.FieldType == typeof(Toggle)) { var c = f.GetValue(view) as Toggle; c.isOn = (bool)v; } else { BDebug.LogError("不支持类型,请扩展:" + f.Name + "-" + vt.FullName); } }); } } }
/// <summary> /// 下载Assets /// </summary> /// <param name="serverUrl"></param> /// <param name="localSaveAssetsPath"></param> /// <param name="downloadQueue"></param> /// <param name="onDownloadProccess"></param> /// <returns></returns> async private Task <List <AssetItem> > DownloadAssets(string serverUrl, string localSaveAssetsPath, Queue <AssetItem> downloadQueue, Action <AssetItem, List <AssetItem> > onDownloadProccess) { var failDownloadList = new List <AssetItem>(); //url构建 var platform = BApplication.GetPlatformPath(BApplication.RuntimePlatform); serverUrl = IPath.Combine(serverUrl, platform); localSaveAssetsPath = IPath.Combine(localSaveAssetsPath, platform); //1.任务缓存 var downloadCacheList = downloadQueue.ToList(); //2.开始任务 while (downloadQueue.Count > 0) { var downloadItem = downloadQueue.Dequeue(); //本地存在hash文件 var localHashFile = IPath.Combine(localSaveAssetsPath, downloadItem.HashName); var serverAssetUrl = IPath.Combine(serverUrl, downloadItem.HashName); var err = ""; //开始下载 byte[] taskByte = null; for (int i = 0; i < RETRY_COUNT; i++) { try { var taskData = await webClient.DownloadDataTaskAsync(serverAssetUrl); var hash = FileHelper.GetMurmurHash3(taskData); if (hash == downloadItem.HashName) { taskByte = taskData; BDebug.Log($"下载成功:{serverAssetUrl} -{downloadItem.LocalPath}"); err = null; break; } else { err = "【版本控制】重下, hash校验失败! server-" + downloadItem.HashName + " local-" + hash; } } catch (Exception e) { err = e.Message; BDebug.LogError(err); } } if (string.IsNullOrEmpty(err)) { //切回主线程,防止回调触发主线程安全模型 await UniTask.SwitchToMainThread(); { onDownloadProccess(downloadItem, downloadCacheList); } await UniTask.SwitchToThreadPool(); //写入本地 FileHelper.WriteAllBytes(localHashFile, taskByte); } else { //这边需要继续下载,最后统计失败文件 failDownloadList.Add(downloadItem); BDebug.LogError($"下载失败:{err} - {serverUrl}"); } } //3.写入本地 foreach (var assetItem in downloadCacheList) { var localHashPath = IPath.Combine(localSaveAssetsPath, assetItem.HashName); var localRealPath = IPath.Combine(localSaveAssetsPath, assetItem.LocalPath); if (File.Exists(localHashPath)) { if (File.Exists(localRealPath)) { File.Delete(localRealPath); } //移动(重命名) FileHelper.Move(localHashPath, localRealPath); } } return(failDownloadList); }