using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace Thry { public class MaterialLinker { private static Dictionary> linked_materials; private static void Load() { if (linked_materials == null) { linked_materials = new Dictionary>(); string raw = FileHelper.ReadFileIntoString(PATH.LINKED_MATERIALS_FILE); string[][] parsed = Parser.ParseToObject(raw); if(parsed!=null) foreach (string[] material_cloud in parsed) { List materials = new List(); for (int i = 1; i < material_cloud.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(material_cloud[i]); Material m = AssetDatabase.LoadAssetAtPath(path); if (m != null) materials.Add(m); } foreach (Material m in materials) linked_materials.Add(GetKey(m, material_cloud[0]), materials); } } } private static void Save() { Dictionary> save_linked_materials = new Dictionary>(linked_materials); List save_structre = new List(); HashSet has_already_been_saved = new HashSet(); foreach (KeyValuePair> link in save_linked_materials) { if (has_already_been_saved.Contains(link.Key)) continue; string[] value = new string[link.Value.Count + 1]; value[0] = System.Text.RegularExpressions.Regex.Split(link.Key,@"###")[1]; int i = 1; foreach (Material m in link.Value) { string guid = UnityHelper.GetGUID(m); has_already_been_saved.Add(guid+"###"+value[0]); value[i++] = guid; } save_structre.Add(value); } FileHelper.WriteStringToFile(Parser.ObjectToString(save_structre),PATH.LINKED_MATERIALS_FILE); } public static List GetLinked(MaterialProperty p) { return GetLinked((Material)p.targets[0], p); } public static List GetLinked(Material m, MaterialProperty p) { Load(); string key = GetKey(m,p); if (linked_materials.ContainsKey(key)) return linked_materials[key]; return null; } public static void Link(Material master, Material add_to, MaterialProperty p) { Load(); Debug.Log("link " + master.name + "," + add_to.name); string key1 = GetKey(master,p); string key2 = GetKey(add_to,p); bool containes_key1 = linked_materials.ContainsKey(key1); bool containes_key2 = linked_materials.ContainsKey(key2); if(containes_key1 && containes_key2) { Unlink(add_to, p); Link(master, add_to, p); return; } else if (containes_key1) AddToListIfMaterialAlreadyLinked(key1, key2, add_to); else if (containes_key2) AddToListIfMaterialAlreadyLinked(key2, key1, master); else { List value = new List(); value.Add(master); value.Add(add_to); linked_materials[key1] = value; linked_materials[key2] = value; } } private static void AddToListIfMaterialAlreadyLinked(string existing_key, string add_key, Material add_material) { List value = linked_materials[existing_key]; value.Add(add_material); linked_materials[add_key] = value; } public static void Unlink(Material m, MaterialProperty p) { Load(); string key = GetKey(m,p); List value = linked_materials[key]; value.Remove(m); linked_materials.Remove(key); } private static void UpdateLinkList(List new_linked_materials, MaterialProperty p) { string key = GetKey(p); if (linked_materials.ContainsKey(key)) { List old_materials = linked_materials[key]; foreach (Material m in old_materials) linked_materials.Remove(GetKey(m, p)); } foreach (Material m in new_linked_materials) linked_materials[GetKey(m, p)] = new_linked_materials; } public static void UnlinkAll(Material m) { string guid = UnityHelper.GetGUID(m); List remove_keys = new List(); foreach (KeyValuePair> link_cloud in linked_materials) { if (link_cloud.Key.StartsWith(guid + "###")) { link_cloud.Value.Remove(m); remove_keys.Add(link_cloud.Key); } } foreach (string k in remove_keys) linked_materials.Remove(k); RemoveEmptyLinks(); Save(); } private static void RemoveEmptyLinks() { List remove_keys = new List(); foreach (KeyValuePair> link_cloud in linked_materials) { if (link_cloud.Value.Count < 2) { link_cloud.Value.Clear(); remove_keys.Add(link_cloud.Key); } } foreach (string k in remove_keys) linked_materials.Remove(k); } private static string GetKey(Material m, MaterialProperty p) { return GetKey(m, p.name); } private static string GetKey(MaterialProperty p) { return GetKey((Material)(p.targets[0]), p.name); } private static string GetKey(Material m, string p) { return UnityHelper.GetGUID(m) + "###" + p; } private static MaterialLinkerPopupWindow window; public static void Popup(Rect activeation_rect, List linked_materials, MaterialProperty p) { Vector2 pos = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); pos.x = Mathf.Min(EditorWindow.focusedWindow.position.x + EditorWindow.focusedWindow.position.width - 250, pos.x); pos.y = Mathf.Min(EditorWindow.focusedWindow.position.y + EditorWindow.focusedWindow.position.height - 200, pos.y); Load(); if (window != null) window.Close(); window = ScriptableObject.CreateInstance(); window.position = new Rect(pos.x, pos.y, 250, 200); window.Init(linked_materials, p); window.ShowPopup(); } private class MaterialLinkerPopupWindow : EditorWindow { private Vector2 scrollPos; private List linked_materials; private MaterialProperty materialProperty; public void Init(List linked_materials, MaterialProperty p) { if (linked_materials == null) linked_materials = new List(); this.linked_materials = new List(linked_materials); string self_guid = UnityHelper.GetGUID((Material)p.targets[0]); for (int i = this.linked_materials.Count - 1; i >= 0; i--) { if (UnityHelper.GetGUID(this.linked_materials[i]) == self_guid) this.linked_materials.RemoveAt(i); } this.materialProperty = p; } public new Vector2 minSize = new Vector2(250, 200); void OnGUI() { GUILayout.Label("Linked Materials", EditorStyles.boldLabel); float listMaxHeight = this.position.height - 110; GuiHelper.DrawListField(linked_materials, listMaxHeight, ref scrollPos); GUILayout.Box("Drag and Drop new Material", EditorStyles.helpBox, GUILayout.MinHeight(30)); //Rect drag_rect = GUILayoutUtility.GetLastRect(); Rect lastRect = GUILayoutUtility.GetLastRect(); Rect drag_rect = new Rect(0, lastRect.y, Screen.width, Screen.height - lastRect.y - 30); Event e = Event.current; if ((e.type == EventType.DragPerform || e.type == EventType.DragUpdated) && drag_rect.Contains(e.mousePosition)) { DragAndDrop.visualMode = DragAndDropVisualMode.Copy; if (e.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); HanldeDropEvent(); } } if (GUI.Button(new Rect(0,this.position.height-30,this.position.width,30),"Done")) this.Close(); } public void HanldeDropEvent() { string[] paths = DragAndDrop.paths; if (AssetDatabase.GetMainAssetTypeAtPath(paths[0]) == typeof(Material)) { linked_materials.Add(AssetDatabase.LoadAssetAtPath(paths[0])); } } void Awake() { } void OnDestroy() { //add itself bool contains_itself = false; string self_guid = UnityHelper.GetGUID((Material)materialProperty.targets[0]); for (int i = linked_materials.Count - 1; i >= 0; i--) { if (UnityHelper.GetGUID(linked_materials[i]) == self_guid) contains_itself = true; if (linked_materials[i] == null) linked_materials.RemoveAt(i); } if (linked_materials.Count>0 && !contains_itself) linked_materials.Add((Material)materialProperty.targets[0]); UpdateLinkList(linked_materials, materialProperty); Save(); } } } }