/// <summary> /// 回复纹理大小 /// </summary> /// <param name="texObj"></param> public static void RecoverTextureFromMeta(Texture2D texObj) { string assetpath = AssetDatabase.GetAssetPath(texObj); TextureImporter ti = AssetImporter.GetAtPath(assetpath) as TextureImporter; if (ti == null) { return; } int maxTextSize = 0; if (!TextureAlreadyShrinked(assetpath)) { return; } TextureImporterFormat tf = new TextureImporterFormat(); bool ret = ti.GetPlatformTextureSettings("WP8", out maxTextSize, out tf); if (ret == false) { maxTextSize = ti.maxTextureSize; ti.SetPlatformTextureSettings("WP8", maxTextSize, ti.textureFormat); //若没有设置WP8平台,则用default的设置来设置 ApplyAssetChange(texObj, null, ti); return; } TextureProperty afterTexPro = db.GetTextureProperty(AssetDatabase.GetAssetPath(texObj), true); SaveTextureData(texObj, afterTexPro, afterTexPro); ti.SetPlatformTextureSettings("WP8", afterTexPro.MaxSize, tf); ti.mipmapEnabled = afterTexPro.MipmapEnabled; ApplyAssetChange(texObj, null, ti); }
/// <summary> /// 缩纹理大小 /// </summary> /// <param name="texObj"></param> /// <returns></returns> public static ShrinkResult ShrinkTexture(Texture2D texObj, bool divideByFour = false) { string assetpath = AssetDatabase.GetAssetPath(texObj); if (texObj == null) { return(ShrinkResult.Failure); } int max = texObj.width > texObj.height ? texObj.width : texObj.height; if (divideByFour && !assetpath.Contains("UIRes")) { max /= 2; } TextureImporter ti = TextureImporter.GetAtPath(assetpath) as TextureImporter; if (ti == null) { Debug.Log(AssetDatabase.GetAssetPath(texObj) + " has no texture importer"); return(ShrinkResult.Failure); } if (TextureAlreadyShrinked(assetpath)) {//已经压缩过了 return(ShrinkResult.Success); } int maxTextSize = 0; TextureImporterFormat tf = new TextureImporterFormat(); bool ret = ti.GetPlatformTextureSettings("WP8", out maxTextSize, out tf);//获取WP8的平台设置 if (ret == false) { maxTextSize = ti.maxTextureSize; ti.SetPlatformTextureSettings("WP8", maxTextSize, ti.textureFormat); //若没有设置WP8平台,则用default的设置来设置 } //备份原始属性 TextureProperty originalTextureProp = new TextureProperty(maxTextSize, ti.mipmapEnabled); originalTextureProp.isOriginal = true; if (TextureNoNeedShrink(max, maxTextSize)) {//不需要再压缩 SaveTextureData(texObj, originalTextureProp, originalTextureProp); return(ShrinkResult.Ignore); } int a = maxTextSize; while (a >= max) { a = a >> 1; } ti.SetPlatformTextureSettings("WP8", a, tf); TextureProperty currentTextureProp = new TextureProperty(a, ti.mipmapEnabled); SaveTextureData(texObj, originalTextureProp, currentTextureProp); ApplyAssetChange(texObj, null, ti); return(ShrinkResult.Success); }
/// <summary> /// 显示第index个Texture的属性 /// </summary> /// <param name="index"></param> private void ShowTextureProperty(int index) { TextureProperty originTex = BobShrinker.db.mTextureOriginalInfoList[index]; TextureProperty currentTex = BobShrinker.db.mTextureCurrentInfoList[index]; GUILayout.Label(BobShrinker.db.mTexturePaths[index]); GUILayout.Label("origin: " + originTex.MaxSize + " " + originTex.MipmapEnabled); GUILayout.Label("current: " + currentTex.MaxSize + " " + currentTex.MipmapEnabled); }
/// <summary> /// 根据贴图的属性判断是否已经被缩减过 /// 若在db中不存在,则认为没有缩减过 /// 否则根据属性的isOriginal值进行判断 /// </summary> /// <param name="path">贴图的文件路径</param> /// <returns>true表示已经缩减过了;false表示未缩减过</returns> public static bool TextureAlreadyShrinked(string path) { TextureProperty tp = db.GetTextureProperty(path); if (tp == null) { return(false); } return(!tp.isOriginal); }
/// <summary> /// 搜集项目中的atlas以及贴图资源显示在文件列表中 /// </summary> public static void CollectAtlas() { string baseDir = Application.dataPath.Substring(0, Application.dataPath.IndexOf("Assets")) + "Assets/MLDJ"; GameObject[] prefabs = BobShrinker.GetPrefabListUsingFileSys(baseDir); List <GameObject> prefabsList = new List <GameObject>(prefabs); GameObject[] atlaslist = BobShrinker.GetUIAtlasListFromPrefabList(prefabs); for (int i = 0; i < atlaslist.Length; i++) { BobUtils.DisplayProgressBar(i, atlaslist.Length, "搜集UIAtlas", atlaslist[i].name); string atlaspath = AssetDatabase.GetAssetPath(atlaslist[i]); if (!BobShrinker.db.ContainsPath(atlaspath)) { AtlasProperty originalAtlasProp = BobShrinker.GetAtlasProperty(atlaslist[i].GetComponent <UIAtlas>(), true); BobShrinker.db.SaveAtlasData(atlaspath, originalAtlasProp, originalAtlasProp); } prefabsList.Remove(atlaslist[i].gameObject); } BobUtils.ClearProgressBar(); Object[] dependencies = EditorUtility.CollectDependencies(prefabsList.ToArray()); for (int i = 0; i < dependencies.Length; i++) { if (dependencies[i] is Texture2D) { BobUtils.DisplayProgressBar(i, dependencies.Length, "搜集Textures", dependencies[i].name); string texturePath = AssetDatabase.GetAssetPath(dependencies[i]); if (!BobShrinker.db.ContainsPath(texturePath)) { TextureImporter ti = TextureImporter.GetAtPath(texturePath) as TextureImporter; if (ti == null) { Debug.LogError(texturePath); continue; } int maxTextSize = 0; TextureImporterFormat tf = new TextureImporterFormat(); bool ret = ti.GetPlatformTextureSettings("WP8", out maxTextSize, out tf);//获取WP8的平台设置 if (ret == false) { maxTextSize = ti.maxTextureSize; ti.SetPlatformTextureSettings("WP8", maxTextSize, ti.textureFormat); //若没有设置WP8平台,则用default的设置来设置 } //备份原始属性 TextureProperty originalTextureProp = new TextureProperty(maxTextSize, ti.mipmapEnabled); originalTextureProp.isOriginal = true; BobShrinker.db.SaveTextureData(texturePath, originalTextureProp, originalTextureProp); } } } BobUtils.ClearProgressBar(); }
/// <summary> /// Read a TextureProperties class /// </summary> /// <param name="fileStream"></param> /// <param name="result"></param> /// <returns>Returns false if a exit flag or end of file was hit</returns> private static void ReadSingleTextureProperties(FileStream fileStream, out TextureProperty result) { var startingPos = fileStream.Position; // Read unknown properties const int byte32Count = 20; var unknownProp = new int[byte32Count]; for (var j = 0; j < byte32Count; j++) { if (fileStream.Position >= fileStream.Length) { Console.WriteLine(@"/!\ HIT END OF FILE EARLY /!\"); // Hit end of file, terminate read fileStream.Seek(startingPos, SeekOrigin.Begin); result = null; return; } unknownProp[j] = fileStream.ReadInt32(); } result = new TextureProperty { TextureIndexes = unknownProp, Index = fileStream.ReadInt32(), Unknown1 = fileStream.ReadInt32() }; // Read unknown 16 bits const int byte16Count = 16; result.TilePropertyFlags = new TexturePropertyFlag[byte16Count]; for (var j = 0; j < byte16Count; j++) { var(sinkDepth, height) = fileStream.Read4BitByte(); var(groundClass, brakingFactor) = fileStream.Read4BitByte(); result.TilePropertyFlags[j] = new TexturePropertyFlag { SinkDepth = (byte)sinkDepth, Height = (byte)height, GroundClass = (byte)groundClass, BrakingFactor = (byte)brakingFactor }; } // Create data set object result.UnknownIndex = fileStream.ReadInt32(); result.Unknown2 = fileStream.ReadInt32(); }
public void SetProperty(TextureProperty property) { foreach (var mat in materials) { mat.SetTexture(property.name, property.val); } foreach (var r in renderers) { r.SetTexture(property.name, property.val); } if (toGlobal) { Shader.SetGlobalTexture(property.name, property.val); } }
/// <summary> /// 保存Texture数据 /// </summary> /// <param name="path"></param> /// <param name="origin"></param> /// <param name="cur"></param> public void SaveTextureData(string path, TextureProperty origin, TextureProperty cur) { int _index = mTexturePaths.IndexOf(path); if (_index == -1) { mTexturePaths.Add(path); mTextureOriginalInfoList.Add(origin); mTextureCurrentInfoList.Add(cur); } else { mTextureOriginalInfoList[_index] = (origin); mTextureCurrentInfoList[_index] = (cur); } }
private static void EmitTextureQuery(EmitterContext context, bool bindless) { OpCodeTex op = (OpCodeTex)context.CurrOp; if (op.Rd.IsRZ) { return; } TextureProperty property = (TextureProperty)op.RawOpCode.Extract(22, 6); // TODO: Validate and use property. Instruction inst = Instruction.TextureSize; SamplerType type = SamplerType.Texture2D; TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None; int raIndex = op.Ra.Index; Operand Ra() { if (raIndex > RegisterConsts.RegisterZeroIndex) { return(Const(0)); } return(context.Copy(Register(raIndex++, RegisterType.Gpr))); } List <Operand> sourcesList = new List <Operand>(); if (bindless) { sourcesList.Add(Ra()); } sourcesList.Add(Ra()); Operand[] sources = sourcesList.ToArray(); int rdIndex = op.Rd.Index; Operand GetDest() { if (rdIndex > RegisterConsts.RegisterZeroIndex) { return(Const(0)); } return(Register(rdIndex++, RegisterType.Gpr)); } int handle = !bindless ? op.Immediate : 0; for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) { if ((compMask & 1) != 0) { Operand dest = GetDest(); TextureOperation operation = new TextureOperation( inst, type, flags, handle, compIndex, dest, sources); context.Add(operation); } } }
set => SetValue(TextureProperty, value);
/// <summary> /// 保存texture改变前后的信息 /// </summary> /// <param name="texObj"></param> /// <param name="originalTexProp"></param> /// <param name="currentTexProp"></param> private static void SaveTextureData(Texture2D texObj, TextureProperty originalTexProp, TextureProperty currentTexProp) { db.SaveTextureData(AssetDatabase.GetAssetPath(texObj), originalTexProp, currentTexProp); EditorUtility.SetDirty(db); }
//finds all properties and headers and stores them in correct order private void CollectAllProperties() { //load display names from file if it exists MaterialProperty[] props = current.properties; Dictionary <string, string> labels = LoadDisplayNamesFromFile(); LoadLocales(); current.propertyDictionary = new Dictionary <string, ShaderProperty>(); shaderparts = new ShaderHeader(); //init top object that all Shader Objects are childs of Stack <ShaderGroup> headerStack = new Stack <ShaderGroup>(); //header stack. used to keep track if current header to parent new objects to headerStack.Push(shaderparts); //add top object as top object to stack headerStack.Push(shaderparts); //add top object a second time, because it get's popped with first actual header item footer = new List <ButtonData>(); //init footer list int headerCount = 0; Type materialPropertyDrawerType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.MaterialPropertyHandler"); MethodInfo getPropertyHandlerMethod = materialPropertyDrawerType.GetMethod("GetShaderPropertyHandler", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); PropertyInfo drawerProperty = materialPropertyDrawerType.GetProperty("propertyDrawer"); Type materialToggleDrawerType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.MaterialToggleDrawer"); FieldInfo keyWordField = materialToggleDrawerType.GetField("keyword", BindingFlags.Instance | BindingFlags.NonPublic); for (int i = 0; i < props.Length; i++) { string displayName = props[i].displayName; if (locale != null) { foreach (string key in locale.GetAllKeys()) { if (displayName.Contains("locale::" + key)) { displayName = displayName.Replace("locale::" + key, locale.Get(key)); } } } displayName = Regex.Replace(displayName, @"''", "\""); if (labels.ContainsKey(props[i].name)) { displayName = labels[props[i].name]; } PropertyOptions options = ExtractExtraOptionsFromDisplayName(ref displayName); int offset = options.offset + headerCount; //Handle keywords object propertyHandler = getPropertyHandlerMethod.Invoke(null, new object[] { current.shader, props[i].name }); //if has custom drawer if (propertyHandler != null) { object propertyDrawer = drawerProperty.GetValue(propertyHandler, null); //if custom drawer exists if (propertyDrawer != null) { if (propertyDrawer.GetType().ToString() == "UnityEditor.MaterialToggleDrawer") { object keyword = keyWordField.GetValue(propertyDrawer); if (keyword != null) { foreach (Material m in current.materials) { if (m.GetFloat(props[i].name) == 1) { m.EnableKeyword((string)keyword); } else { m.DisableKeyword((string)keyword); } } } } } } ThryPropertyType type = GetPropertyType(props[i], options); switch (type) { case ThryPropertyType.header: headerStack.Pop(); break; case ThryPropertyType.header_start: offset = options.offset + ++headerCount; break; case ThryPropertyType.header_end: headerStack.Pop(); headerCount--; break; case ThryPropertyType.on_swap_to: on_swap_to_actions = options.actions; break; } ShaderProperty newPorperty = null; switch (type) { case ThryPropertyType.master_label: masterLabelText = displayName; break; case ThryPropertyType.footer: footer.Add(Parser.ParseToObject <ButtonData>(displayName)); break; case ThryPropertyType.header: case ThryPropertyType.header_start: ShaderHeader newHeader = new ShaderHeader(props[i], current.editor, displayName, offset, options); headerStack.Peek().addPart(newHeader); headerStack.Push(newHeader); break; case ThryPropertyType.group_start: ShaderGroup new_group = new ShaderGroup(options); headerStack.Peek().addPart(new_group); headerStack.Push(new_group); break; case ThryPropertyType.group_end: headerStack.Pop(); break; case ThryPropertyType.none: case ThryPropertyType.property: DrawingData.lastPropertyUsedCustomDrawer = false; current.editor.GetPropertyHeight(props[i]); bool forceOneLine = props[i].type == MaterialProperty.PropType.Vector && !DrawingData.lastPropertyUsedCustomDrawer; if (props[i].type == MaterialProperty.PropType.Texture) { newPorperty = new TextureProperty(props[i], displayName, offset, options, props[i].flags != MaterialProperty.PropFlags.NoScaleOffset, !DrawingData.lastPropertyUsedCustomDrawer); } else { newPorperty = new ShaderProperty(props[i], displayName, offset, options, forceOneLine); } break; case ThryPropertyType.lightmap_flags: newPorperty = new GIProperty(props[i], displayName, offset, options, false); break; case ThryPropertyType.dsgi: newPorperty = new DSGIProperty(props[i], displayName, offset, options, false); break; case ThryPropertyType.instancing: newPorperty = new InstancingProperty(props[i], displayName, offset, options, false); break; case ThryPropertyType.locale: newPorperty = new LocaleProperty(props[i], displayName, offset, options, false); break; } if (newPorperty != null) { if (current.propertyDictionary.ContainsKey(props[i].name)) { continue; } current.propertyDictionary.Add(props[i].name, newPorperty); if (type != ThryPropertyType.none) { headerStack.Peek().addPart(newPorperty); } } } }
//finds all properties and headers and stores them in correct order private void CollectAllProperties() { //load display names from file if it exists MaterialProperty[] props = current.properties; Dictionary <string, string> labels = LoadDisplayNamesFromFile(); current.propertyDictionary = new Dictionary <string, ShaderProperty>(); shaderparts = new ShaderHeader(); //init top object that all Shader Objects are childs of Stack <ShaderHeader> headerStack = new Stack <ShaderHeader>(); //header stack. used to keep track if current header to parent new objects to headerStack.Push(shaderparts); //add top object as top object to stack headerStack.Push(shaderparts); //add top object a second time, because it get's popped with first actual header item footer = new List <ButtonData>(); //init footer list int headerCount = 0; for (int i = 0; i < props.Length; i++) { string displayName = props[i].displayName; displayName = Regex.Replace(displayName, @"''", "\""); if (labels.ContainsKey(props[i].name)) { displayName = labels[props[i].name]; } PropertyOptions options = ExtractExtraOptionsFromDisplayName(ref displayName); int offset = options.offset + headerCount; ThryPropertyType type = GetPropertyType(props[i]); switch (type) { case ThryPropertyType.header: headerStack.Pop(); break; case ThryPropertyType.header_start: offset = options.offset + ++headerCount; break; case ThryPropertyType.header_end: headerStack.Pop(); headerCount--; break; } switch (type) { case ThryPropertyType.footer: footer.Add(Parser.ParseToObject <ButtonData>(displayName)); break; case ThryPropertyType.header: case ThryPropertyType.header_start: ShaderHeader newHeader = new ShaderHeader(props[i], current.editor, displayName, offset, options); headerStack.Peek().addPart(newHeader); headerStack.Push(newHeader); break; case ThryPropertyType.property: ShaderProperty newPorperty = null; DrawingData.lastPropertyUsedCustomDrawer = false; current.editor.GetPropertyHeight(props[i]); bool forceOneLine = props[i].type == MaterialProperty.PropType.Vector && !DrawingData.lastPropertyUsedCustomDrawer; if (props[i].type == MaterialProperty.PropType.Texture) { newPorperty = new TextureProperty(props[i], displayName, offset, options, props[i].flags != MaterialProperty.PropFlags.NoScaleOffset, !DrawingData.lastPropertyUsedCustomDrawer); } else { newPorperty = new ShaderProperty(props[i], displayName, offset, options, forceOneLine); } headerStack.Peek().addPart(newPorperty); current.propertyDictionary.Add(props[i].name, newPorperty); break; case ThryPropertyType.lightmap_flags: current.draw_material_option_lightmap = true; break; case ThryPropertyType.dsgi: current.draw_material_option_dsgi = true; break; case ThryPropertyType.instancing: current.draw_material_option_instancing = true; break; } } }
//-------------Init functions-------------------- //finds all properties and headers and stores them in correct order private void CollectAllProperties() { //load display names from file if it exists MaterialProperty label_file_property = null; MaterialProperty[] props = current.properties; foreach (MaterialProperty m in props) { if (m.name == "shader_properties_label_file") { label_file_property = m; } } Dictionary <string, string> labels = new Dictionary <string, string>(); if (label_file_property != null) { string[] guids = AssetDatabase.FindAssets(label_file_property.displayName); if (guids.Length == 0) { Debug.LogError("Label File could not be found"); } string path = AssetDatabase.GUIDToAssetPath(guids[0]); string[] data = Regex.Split(Helper.ReadFileIntoString(path), @"\r?\n"); foreach (string d in data) { string[] set = Regex.Split(d, ":="); if (set.Length > 1) { labels[set[0]] = set[1]; } } } shaderparts = new ShaderHeader(); //init top object that all Shader Objects are childs of Stack <ShaderHeader> headerStack = new Stack <ShaderHeader>(); //header stack. used to keep track if current header to parent new objects to headerStack.Push(shaderparts); //add top object as top object to stack headerStack.Push(shaderparts); //add top object a second time, because it get's popped with first actual header item footer = new List <string>(); //init footer list int headerCount = 0; for (int i = 0; i < props.Length; i++) { //if property is a footer add to footer list if (props[i].name.StartsWith("footer_") && props[i].flags == MaterialProperty.PropFlags.HideInInspector) { footer.Add(props[i].displayName); //if property is end if a header block pop the top header } else if (props[i].name.StartsWith("m_end") && props[i].flags == MaterialProperty.PropFlags.HideInInspector) { headerStack.Pop(); headerCount--; } else //else add new object under current header { //get the display name out of property or file string displayName = props[i].displayName; if (labels.ContainsKey(props[i].name)) { displayName = labels[props[i].name]; } string ogDisplayName = displayName; //extract offset int extraOffset = Helper.propertyOptionToInt(EXTRA_OFFSET_OPTION, ogDisplayName); int offset = extraOffset + headerCount; displayName = displayName.Replace(EXTRA_OPTION_PREFIX + EXTRA_OFFSET_OPTION + EXTRA_OPTION_INFIX + extraOffset, ""); //extract on hover string onHover = Helper.getPropertyOptionValue(HOVER_OPTION, ogDisplayName); displayName = displayName.Replace(EXTRA_OPTION_PREFIX + HOVER_OPTION + EXTRA_OPTION_INFIX + onHover, ""); //extract alt click string altClick = Helper.getPropertyOptionValue(ON_ALT_CLICK_OPTION, ogDisplayName); displayName = displayName.Replace(EXTRA_OPTION_PREFIX + ON_ALT_CLICK_OPTION + EXTRA_OPTION_INFIX + altClick, ""); //if property is submenu add 1 extra offset if (props[i].name.StartsWith("m_start") && props[i].flags == MaterialProperty.PropFlags.HideInInspector) { offset = extraOffset + ++headerCount; } //if property is normal menu pop out if old header else if (props[i].name.StartsWith("m_") && props[i].flags == MaterialProperty.PropFlags.HideInInspector) { headerStack.Pop(); } //if proeprty is submenu or normal menu push in header stack if (props[i].name.StartsWith("m_") && props[i].flags == MaterialProperty.PropFlags.HideInInspector) { ShaderHeader newHeader = new ShaderHeader(props[i], current.editor, displayName, offset, onHover, altClick); headerStack.Peek().addPart(newHeader); headerStack.Push(newHeader); } //if property is actual property and not hidden add under current header else if (props[i].flags != MaterialProperty.PropFlags.HideInInspector) { ShaderProperty newPorperty = null; DrawingData.lastPropertyUsedCustomDrawer = false; current.editor.GetPropertyHeight(props[i]); if (props[i].type == MaterialProperty.PropType.Texture) { newPorperty = new TextureProperty(props[i], displayName, offset, onHover, altClick, !DrawingData.lastPropertyUsedCustomDrawer); } else { newPorperty = new ShaderProperty(props[i], displayName, offset, onHover, altClick); } headerStack.Peek().addPart(newPorperty); } } } }
/// <summary> /// 添加单个文件路径 /// </summary> /// <param name="filepath"></param> private void AddFileItems(string filepath) { filepath = filepath.Replace('\\', '/'); Object obj = AssetDatabase.LoadAssetAtPath(filepath, typeof(UnityEngine.Object)); if (obj == null) { return; } if (!System.IO.File.Exists(filepath) && System.IO.Directory.Exists(filepath)) {///如果是目录,则遍历其中的所有文件 string[] files = System.IO.Directory.GetFiles(filepath, "*.*", System.IO.SearchOption.AllDirectories); for (int i = 0; i < files.Length; ++i) { AddFileItems(files[i]); } return; } if (obj is Texture) { if (BobShrinker.db.mTexturePaths.Contains(filepath)) { return; } else { TextureImporter ti = TextureImporter.GetAtPath(filepath) as TextureImporter; if (ti == null) { return; } BobUtils.DisplayProgressBar(1, 1, "添加文件", filepath); int maxTextSize = 0; TextureImporterFormat tf = new TextureImporterFormat(); bool ret = ti.GetPlatformTextureSettings("WP8", out maxTextSize, out tf);//获取WP8的平台设置 if (ret == false) { maxTextSize = ti.maxTextureSize; ti.SetPlatformTextureSettings("WP8", maxTextSize, ti.textureFormat); //若没有设置WP8平台,则用default的设置来设置 } //备份原始属性 TextureProperty originalTextureProp = new TextureProperty(maxTextSize, ti.mipmapEnabled); originalTextureProp.isOriginal = true; BobShrinker.db.SaveTextureData(filepath, originalTextureProp, originalTextureProp); } } if (obj is GameObject) { GameObject go = obj as GameObject; UIAtlas uiatlas = go.GetComponent <UIAtlas>(); if (uiatlas != null) { if (BobShrinker.db.mAtlasPaths.Contains(filepath)) { return; } else if (uiatlas.spriteMaterial == null) { Debug.LogError(filepath + " has no materials"); return; } else { BobUtils.DisplayProgressBar(1, 1, "添加文件", filepath); AtlasProperty originalAtlasProp = BobShrinker.GetAtlasProperty(uiatlas, true); BobShrinker.db.SaveAtlasData(filepath, originalAtlasProp, originalAtlasProp); } } List <string> dependencies = BobUtils.CollectDependencies(filepath);//获取依赖资源 接着AddItems for (int i = 0; i < dependencies.Count; ++i) { AddFileItems(dependencies[i]); } } }