UNITY编辑器模式下static变量的坑
在unity中写编辑器扩展工具,如在编辑器中加个菜单,点击这个菜单项时执行打包功能。
类如下,其中的静态变量,如果每次进来不清空,则LIST会越来越大,打包函数执行完后系统不会帮我们清空
#if UNITY_EDITOR using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor; using UnityEngine;
using LitJson;
using System.Security.Cryptography; //资源清单,列出了游戏中用到的所有资源
[Serializable]
public class AssetsList
{
/*** 资源清单
* <相对路径, MD5串>
*/
public Dictionary<string, string> Assets2Md5 = new Dictionary<string, string>();//容量未设置,后面可以写成常量,根据上次数据得出
} public class AssetBundleBuilder
{
public static string BundlePath = "";
public static AssetsList AssetsList = new AssetsList();
public static List<string> DependAssets_PathList = new List<string>(); //InGameRes所依赖的ArtSource等文件夹下的资源
public static List<string> Assets_PathList = new List<string>(); //InGameRes文件夹下的资源
public static List<AssetBundleBuild> BuildList = new List<AssetBundleBuild>(); //估计值,后面可以写成常量,根据上次数据得出 public static string ResRootPath = "Assets/Resources"; //资源目录,根据此目录查找所有依赖的资源
public static string ResDependPath = "Assets/ArtSource"; //资源目录,根据此目录查找所有依赖的资源
public static string ResFolder = "Resources"; //资源打包的依据文件夹,此文件夹下的所有文件及所有依赖文件都被打进AB包,不要在此文件夹下放备份或无用的资源 public static string Depends_List_File = "Assets/depends_list.json";
public static string Assets_List_File = "Assets/assets_list.json"; public static int FileNumLimit = ; //测试使用,只收集限定数量的文件
public static void BuildAB(BuildTarget buildTarget)
{
if (!Directory.Exists(ResRootPath))
{
Debug.LogError("资源目录不存在:" + ResRootPath);
return;
} var files = Directory.GetFiles(ResRootPath, "*", SearchOption.AllDirectories); var stopwt = System.Diagnostics.Stopwatch.StartNew();
var t1 = stopwt.ElapsedMilliseconds; /***
* 坑,这里必须要清空,否则每次进来就会往Assets_PathList里添加一次内容
*/
BuildList.Clear();
Assets_PathList.Clear();
DependAssets_PathList.Clear();
AssetsList.Assets2Md5.Clear(); var infoTitle = "收集文件,目录 : " + ResRootPath;
//第一步,将ResRootPath目录下的文件收集起来,此目录的东西都是游戏中要用到的,此目录之外的东西不一定会用到
var idx = ;
for (int i=, cnt=files.Length; i<cnt; ++i)
{
var item = files[i];
var ext = Path.GetExtension(item);
if (string.Compare(ext, ".meta", true)== || string.Compare(ext, ".cs", true)==)
continue; if ((string.Compare(ext, ".prefab", true) == || string.Compare(ext, ".mat", true) ==
|| string.Compare(ext, ".unity", true) == || string.Compare(ext, ".controller", true) == ))
{
idx++;
if (idx > FileNumLimit)
break;
//添加到构建列表
var abName = AddToBuildList(item);
Assets_PathList.Add(abName);
} EditorUtility.DisplayProgressBar(infoTitle, item, i * 1.0f / cnt);
} WriteToJson(Assets_List_File, Assets_PathList); //第二步,将ResRootPath依赖的文件收集进来
CheckAllDepends(files); var infoTitle2 = "收集依赖,目录 : " + ResDependPath; for (int i = , cnt = DependAssets_PathList.Count; i < cnt; ++i)
{
var item = DependAssets_PathList[i]; //添加到构建列表
AddToBuildList(item); EditorUtility.DisplayProgressBar(infoTitle2, item, i * 1.0f / cnt);
} //第三步,增量打包
var targetName = buildTarget == BuildTarget.iOS ? "IOS" : "Android";
BundlePath = Application.dataPath.Substring(, Application.dataPath.Length-) + "Bundles" + targetName; //放到Assets同目录 if (!Directory.Exists(BundlePath))
{
Directory.CreateDirectory(BundlePath);
} var dt1 = stopwt.ElapsedMilliseconds - t1; ClearUnusedBundles(files);
/***
* 一次传入所有需要打包的数据,UNITY会保证它们之间的依赖被正确处理:先打被依赖的包,再打自己
* 我们必须保证传入数据的完全,如果被依赖的包不在我们传入的列表中,则相应资源会被打到所有用到该包的包中,造成资源的重复包含
*/
AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(BundlePath, BuildList.ToArray(), BuildAssetBundleOptions.ChunkBasedCompression, buildTarget);
EditorUtility.ClearProgressBar(); var dt2 = stopwt.ElapsedMilliseconds - t1 - dt1; EditorUtility.DisplayDialog("打包完成", "耗时:" + dt1 / 1000.0f + " + " + dt2/1000.0f + "\n路径:" + BundlePath, "ok"); GenResList(manifest); EditorUtility.UnloadUnusedAssetsImmediate(); } public static string AddToBuildList(string resPath)
{
var relativeDir = resPath; //不能这样处理,因为可能有同名却不同后缀的文件存在
//relativeDir = relativeDir.Substring(0, relativeDir.LastIndexOf(".")); //去除后缀
relativeDir = relativeDir.Replace("\\", "/");
var abBuild = new AssetBundleBuild();
abBuild.assetBundleName = relativeDir;
abBuild.assetNames = new string[] { resPath };
abBuild.assetBundleVariant = "ab";
BuildList.Add(abBuild); return relativeDir;
} //将AB包移动到StreamingAssets目录下,为打APK或IPA作准备
public static void CopyToStreamingAssets(BuildTarget buildTarget)
{
CopyFolder(BundlePath, Application.streamingAssetsPath + "/Bundles/");
} /***
* 增量打包的关键,遍历上次打出的包,与本次【构建列表BuildList】里的内容对比,不在列表中的删除掉。
* 在列表中的保留不变。这样当我们再次执行打包操作时,如果文件对应的AB包已存在且文件没有更改,则不用重新打包
*/
public static void ClearUnusedBundles(string[] files)
{
if (!Directory.Exists(BundlePath))
{
Debug.LogError("包目录不存在:" + BundlePath);
return;
} var abFiles = Directory.GetFiles(BundlePath + "/assets", "*", SearchOption.AllDirectories);
var delList = new List<string>(); for (int i=, n=abFiles.Length; i<n; ++i)
{
var ext = Path.GetExtension(abFiles[i]);
var file = Path.ChangeExtension(abFiles[i], null);
if(string.Compare(ext, ".manifest", true) == )
{
file = Path.ChangeExtension(file, null);
} file = file.Substring(file.IndexOf("assets", StringComparison.CurrentCultureIgnoreCase));
if (!File.Exists(file))
{
delList.Add(abFiles[i]);
} EditorUtility.DisplayProgressBar("正在检查AssetBundle", file, i * 1.0f / n); } for (int i=, n= delList.Count; i<n; ++i)
{
EditorUtility.DisplayProgressBar("正在清理无用的AssetBundle", delList[i], i * 1.0f / n);
if (!File.Exists(delList[i]))
{
EditorUtility.DisplayDialog("", "不存在此文件", "ok");
continue;
} File.Delete(delList[i]); } EditorUtility.ClearProgressBar(); WriteToJson("Assets/delete_list.json", delList);
} //剪切到某个目录,并重命名
public static void MoveFolder(string src, string dest)
{
if (Directory.Exists(dest))
{
Directory.Delete(dest, true);
}
Directory.CreateDirectory(dest); File.Move(src, dest + "/Bundles");
} //复制到某个目录,并重命名
public static void CopyFolder(string src, string dest)
{
if (Directory.Exists(dest))
{
Directory.Delete(dest, true);
}
Directory.CreateDirectory(dest); foreach (var sub in Directory.GetDirectories(src))
{
CopyFolder(sub + "/", dest + Path.GetFileName(sub) + "/");
} foreach (var file in Directory.GetFiles(src))
{
File.Copy(file, dest + Path.GetFileName(file));
}
} /*** 生成资源清单
* 格式:MD5 : 相对于/Bundles/的路径
* 作用:热更的对比依据,通过MD5对比,确定文件的增-删-修改
*/
public static void GenResList(AssetBundleManifest manifest)
{
AssetsList.Assets2Md5.Clear(); var abs = manifest.GetAllAssetBundles();
foreach (var ab in abs)
{
var hashes = manifest.GetAssetBundleHash(ab);
AssetsList.Assets2Md5.Add(ab, hashes.ToString());
} var writer = new JsonWriter();
writer.PrettyPrint = true;
JsonMapper.ToJson(AssetsList, writer);
File.WriteAllText(BundlePath + "/asset_list.json", writer.ToString(), System.Text.Encoding.ASCII); } public static void DeleteBundles(BuildTarget target)
{
var path = Application.dataPath + "/../" + (target == BuildTarget.Android ? "BundlesAndroid" : "BundlesIOS");
var msg = "文件夹不存在" + " " + path;
if (Directory.Exists(path))
{
Directory.Delete(path, true);
msg = "清理完成";
} EditorUtility.DisplayDialog("清理", msg, "ok");
} //得到指定文件夹下资源的所有依赖
public static void CheckAllDepends(string targetPath)
{
if (!Directory.Exists(targetPath))
{
Debug.LogError("资源目录不存在:" + targetPath);
return;
} var files = Directory.GetFiles(targetPath, "*", SearchOption.AllDirectories); CheckAllDepends(files);
} //得到指定文件的所有依赖
public static void CheckAllDepends(string[] files)
{
var stopWatch = System.Diagnostics.Stopwatch.StartNew();
var startTime = stopWatch.ElapsedMilliseconds; DependAssets_PathList.Clear(); var idx = ;
for(int i=, fileNum = files.Length; i< fileNum; ++i)
{
var item = files[i];
var ext = Path.GetExtension(item); if (string.Compare(ext, ".meta", true) == || string.Compare(ext, ".cs",true) == )
continue;
if ((string.Compare(ext, ".prefab", true) == || string.Compare(ext, ".mat", true) ==
|| string.Compare(ext, ".unity", true) == || string.Compare(ext, ".controller", true) == ))
{
idx++;
if (idx > FileNumLimit)
break; var dpends = AssetDatabase.GetDependencies(item, true);
foreach (var s in dpends)
{
if (s.Contains(ResFolder) || s.Contains(".cs"))
continue;
//var substr = s.Substring(s.IndexOf("Assets/"));
if (!DependAssets_PathList.Contains(s))
{
DependAssets_PathList.Add(s);
}
}
} var progress = i *1.0f/ fileNum;
EditorUtility.DisplayProgressBar("正在查找引用" + fileNum, item, progress);
} EditorUtility.ClearProgressBar(); //var savePath = "Assets/refs_list.json";
WriteToJson(Depends_List_File, DependAssets_PathList); var deltaTime = stopWatch.ElapsedMilliseconds - startTime; EditorUtility.DisplayDialog("检查完成", "耗时" + deltaTime/1000.0f + "\n保存路径: " + Depends_List_File, "ok");
} public static void WriteToJson(string path, object obj)
{
var writer = new JsonWriter();
writer.PrettyPrint = true;
JsonMapper.ToJson(obj, writer);
File.WriteAllText(path, writer.ToString());
} [MenuItem("AssetBundle/安卓/构建AB包")]
public static void BuildAndroidAB()
{
BuildAB(BuildTarget.Android);
} [MenuItem("AssetBundle/IOS/构建AB包")]
public static void BuildIOSAB()
{
BuildAB(BuildTarget.iOS);
} [MenuItem("AssetBundle/安卓一键打包")]
public static void AndroidOneKeyBuild()
{
BuildAB(BuildTarget.Android);
CopyToStreamingAssets(BuildTarget.Android);
} [MenuItem("AssetBundle/IOS一键打包")]
public static void IOSOneKeyBuild()
{
BuildAB(BuildTarget.iOS);
CopyToStreamingAssets(BuildTarget.iOS);
} [MenuItem("AssetBundle/安卓/拷到StreamingAssets目录")]
public static void CopyAndroidABToStreamingAssets()
{
CopyToStreamingAssets(BuildTarget.Android);
} [MenuItem("AssetBundle/IOS/拷到StreamingAssets目录")]
public static void CopyIOSABToStreamingAssets()
{
CopyToStreamingAssets(BuildTarget.iOS);
} [MenuItem("AssetBundle/清理/清理安卓包")]
public static void DeleteAndroidABs()
{
DeleteBundles(BuildTarget.Android);
} [MenuItem("AssetBundle/清理/清理苹果包")]
public static void DeleteIOSABs()
{
DeleteBundles(BuildTarget.iOS);
} [MenuItem("AssetBundle/资源检查/检查依赖")]
public static void CheckAssetsDepends()
{
CheckAllDepends(ResRootPath);
}
} #endif
UNITY编辑器模式下static变量的坑的更多相关文章
- 实现Unity编辑器模式下的旋转
最近在做一个模型展示的项目,我的想法是根据滑动屏幕的x方向差值和Y方向的差值,来根据世界坐标下的X轴和Y轴进行旋转,但是实习时候总是有一些卡顿.在观察unity编辑器下的旋转之后,发现编辑器下的旋转非 ...
- 二、Unity Editor模式下,操作选中对象
使用Unity提供的工具类 UnityEditor.Selection public static GameObject activeGameObject public static UnityEng ...
- 编辑器模式下如何实例化Prefab
当我们在EditMode下需要用脚本批量添加prefab时,可以用 PrefabUtility.InstantiatePrefab(prefab) as GameObject; 注意:如果用GameO ...
- unity editor模式下读取文件夹资源
string path = EditorUtility.OpenFolderPanel("Load png Textures", "", "" ...
- Unity编辑器 - 编辑器控制特效播放
编辑器控制特效播放 Unity的动画编辑器不能预览粒子系统的播放,为了方便预览特效,设想制作一个预览特效的工具,通常一个特效有三种组件: - Animation - Animator - Partic ...
- Lua------------------改善Unity编辑器对Lua文件的支持
原创 2017年03月10日 18:44:22 标签: Unity / lua / 编辑器 952 当前版本的Unity(截至Unity5.5.x)中TextAsset类不支持后缀为lua的文件,将l ...
- VUE Node模式下,如何改变菜单的颜色,如何将超长文字缩略显示,在鼠标进入后展开全部显示,鼠标移出则恢复缩略显示
VUE Node模式下,如何改变菜单的颜色,如何将超长文字缩略显示,在鼠标进入后展开全部显示,鼠标移出则恢复缩略显示: “事件”引起变量值的变化,系统引擎自动根据变量值的变化刷新页面 在VUE Nod ...
- 交互模式下测试python代码及变量的四则运算
在交互模式下,python代码可以立即执行,所以这很方便我们进行代码测试 1.命令窗口,输入python (如果没配置环境变量则需带python安装目录的绝对路径) >>> 这个就是 ...
- DEBUG模式下, 内存中的变量地址分析
测试函数的模板实现 /// @file my_template.h /// @brief 测试数据类型用的模板实现 #ifndef MY_TEMPLATE_H_2016_0123_1226 #defi ...
随机推荐
- java中java.util.Date和java.sql.Date之间的关系和使用选择
关系: java.util.Date是java.sql.Date的父类 区别:(java.sql.Date包含年月日信息,java.util.Date包含年月日时分秒) 1:“规范化”的java.sq ...
- 12 (H5*) JS第二天 流程控制:顺序结构、分支结构、循环结构
目录 1:一元运算符 2:流程控制 3:分支之if语句 4:分支之if-else语句 5:分支语句之三元运算符 6:if和else if语句 7:switch-case语句 8:while循环 9:d ...
- HIbernate入门3
HIbernate的一对多操作: 1. 创建实体类:一个Customer类(客户类)和一个LinkMan类(联系人),两者的关系为:一个客户中可能有多个联系人(关于一对多的实体类之间的关联,不做详细介 ...
- Java WebService 参考文档
webservice 基础使用 java 与tomcat使用http://cxshun.iteye.com/blog/1275408 spring mvc中使用https://www.cnblogs. ...
- [19/05/18-星期六] HTML_form标签
一.form标签(一) <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> & ...
- dfs(找环)
https://codeforces.com/problemset/problem/1249/B2 B2. Books Exchange (hard version) time limit per t ...
- Python时间模块datetime用法
时间模块datetime是python内置模块,datetime是Python处理日期和时间的标准库. 1,导入时间模块 from datetime import datetime 2,实例 from ...
- 使用hash表进行数组去重
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列 ...
- C#控制文本框(TextBox)只能输入正数,负数,小数
由于项目需要,需要写一个TextBox文本框,此文本框需要满足:只能输入正数,负数和小数.比如:3,0.3,-4,-0.4等等. 在网上找了许多正则表达式都不好用,由于本人又对正则表达式 ...
- SSM商城系统开发笔记-问题02- Error creating bean with name 'userController'
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean wit ...