Created
November 2, 2018 15:42
-
-
Save shane-harper/d060b1c6e2581fcd58a5932bcb537a88 to your computer and use it in GitHub Desktop.
A handy tool for copying Unity meta data from one asset to another (Place in Editor folder)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using UnityEditor; | |
using UnityEngine; | |
/// <summary> | |
/// Tool for copying Unity meta data directly from one file to another | |
/// </summary> | |
public class MetaCopier : EditorWindow | |
{ | |
private static Vector2 _scroll = Vector2.zero; | |
private static bool _showProperties = true; | |
private static GUIStyle _dragAreaStyle; | |
/// <summary> | |
/// List of properties to copy, editable in the UI, will reset to these values on recompile though | |
/// </summary> | |
private static readonly List<string> Properties = new List<string> | |
{ | |
"alignment:", | |
"spritePivot:", | |
"spritePixelsToUnits:", | |
"spriteBorder:" | |
}; | |
private static readonly List<Object> SourceFiles = new List<Object>(1); | |
private static readonly List<Object> TargetFiles = new List<Object>(1); | |
[MenuItem("Window/Meta Copier")] | |
public static void CreateWindow() | |
{ | |
var window = GetWindow<MetaCopier>("Meta Copier", true); | |
window.Show(); | |
} | |
private void OnGUI() | |
{ | |
// Make sure the drag area style skin isn't null | |
if (_dragAreaStyle == null) | |
{ | |
var target = EditorStyles.helpBox; | |
_dragAreaStyle = new GUIStyle(GUI.skin.button) | |
{ | |
normal = {background = target.normal.background}, | |
border = target.border, | |
richText = true | |
}; | |
} | |
// Scroll view | |
_scroll = EditorGUILayout.BeginScrollView(_scroll, false, true, | |
GUIStyle.none, GUI.skin.verticalScrollbar, GUIStyle.none); | |
var columnWidth = GUILayout.Width((Screen.width-13)/2f); | |
EditorGUILayout.BeginHorizontal(); | |
// List source files | |
EditorGUILayout.BeginVertical(columnWidth); | |
DropAreaGUI("Source Files", "Drag <b>Source</b> Files Here", SourceFiles, 50); | |
DrawList(SourceFiles); | |
EditorGUILayout.EndVertical(); | |
// List target files | |
EditorGUILayout.BeginVertical(columnWidth); | |
DropAreaGUI("Target Files", "Drag <b>Target</b> Files Here", TargetFiles, 50); | |
DrawList(TargetFiles); | |
EditorGUILayout.EndVertical(); | |
EditorGUILayout.EndHorizontal(); | |
// Fill out space and end scroll | |
GUILayout.FlexibleSpace(); | |
EditorGUILayout.EndScrollView(); | |
// List properties | |
var propertiesLabel = string.Format("Properties ({0})", Properties.Count); | |
_showProperties = EditorGUILayout.Foldout(_showProperties, propertiesLabel, true); | |
if (_showProperties) | |
{ | |
DrawList(Properties); | |
EditorGUILayout.Space(); | |
} | |
// Disable go button if criteria are not met | |
var enabled = GUI.enabled; | |
GUI.enabled = SourceFiles.Count > 0 && SourceFiles.Count == TargetFiles.Count && Properties.Count > 0; | |
if (GUILayout.Button("Go", GUILayout.Height(40))) | |
CopyProperties(SourceFiles, TargetFiles, Properties); | |
GUI.enabled = enabled; | |
EditorGUILayout.Space(); | |
} | |
/// <summary> | |
/// Copy properties from source meta files to target meta files | |
/// </summary> | |
/// <param name="source">List containing source assets</param> | |
/// <param name="target">List containing target assets</param> | |
/// <param name="properties">List of properties to copy</param> | |
public static void CopyProperties(IList<Object> source, IList<Object> target, IList<string> properties) | |
{ | |
// Get project path | |
var dataPath = Application.dataPath; | |
var projectPath = dataPath.Substring(0, dataPath.LastIndexOf('/') + 1); | |
// Copy files | |
var builder = new StringBuilder(); | |
var count = Mathf.Min(source.Count, target.Count); | |
for (var i = 0; i < count; ++i) | |
{ | |
// Check each file exists | |
var sourceFile = source[i]; | |
if (sourceFile == null) continue; | |
var targetFile = target[i]; | |
if (targetFile == null) continue; | |
// Get file paths | |
builder.AppendFormat("{0}{1}.meta", projectPath, AssetDatabase.GetAssetPath(sourceFile)); | |
var sourcePath = builder.ToString(); | |
builder.Length = 0; | |
builder.AppendFormat("{0}{1}.meta", projectPath, AssetDatabase.GetAssetPath(targetFile)); | |
var targetPath = builder.ToString(); | |
builder.Length = 0; | |
// Copy! | |
CopyProperties(sourcePath, targetPath, properties); | |
} | |
} | |
/// <summary> | |
/// Copy properties from source meta file to target meta file | |
/// </summary> | |
/// <param name="source">Path to source asset meta file</param> | |
/// <param name="target">Path to target asset meta file</param> | |
/// <param name="properties">List of properties to copy</param> | |
public static void CopyProperties(string source, string target, IList<string> properties) | |
{ | |
// If either file doesn't exist, skip it | |
if (!File.Exists(source) || !File.Exists(target)) return; | |
// Create array to contain values | |
int lineCount; | |
var values = GetValues(source, properties, out lineCount); | |
// Read existing target file and load into array | |
var targetLines = new List<string>(lineCount); | |
using (var reader = new StreamReader(target)) | |
{ | |
var line = reader.ReadLine(); | |
do | |
{ | |
var found = false; | |
for (var i = 0; i < properties.Count; ++i) | |
{ | |
if (!line.StartsWith(properties[i])) continue; | |
if (string.IsNullOrEmpty(values[i])) | |
{ | |
Debug.LogErrorFormat("No value for {0} to copy", properties[i]); | |
continue; | |
} | |
targetLines.Add(values[i]); | |
found = true; | |
} | |
if (!found) targetLines.Add(line); | |
line = reader.ReadLine(); | |
} while (line != null); | |
reader.Close(); | |
} | |
// Write new file from array | |
using (var writer = new StreamWriter(target, false)) | |
{ | |
foreach (var line in targetLines) | |
writer.WriteLine(line); | |
writer.Close(); | |
} | |
} | |
/// <summary> | |
/// Read values from source file | |
/// </summary> | |
private static string[] GetValues(string source, IList<string> properties, out int lineCount) | |
{ | |
var values = new string[properties.Count]; | |
lineCount = 0; | |
using (var reader = new StreamReader(source)) | |
{ | |
var line = reader.ReadLine(); | |
do | |
{ | |
++lineCount; | |
for (var i = 0; i < properties.Count; ++i) | |
{ | |
if (!line.StartsWith(properties[i])) continue; | |
values[i] = line; | |
break; | |
} | |
line = reader.ReadLine(); | |
} while (line != null); | |
reader.Close(); | |
} | |
return values; | |
} | |
/// <summary> | |
/// Display a list of strings | |
/// </summary> | |
private static void DrawList(IList<string> list) | |
{ | |
for (var i = 0; i < list.Count; ++i) | |
{ | |
EditorGUILayout.BeginHorizontal(); | |
list[i] = EditorGUILayout.TextField(list[i]); | |
if (GUILayout.Button("Remove", EditorStyles.miniButton, GUILayout.ExpandWidth(false))) | |
list.RemoveAt(i); | |
EditorGUILayout.EndHorizontal(); | |
} | |
EditorGUILayout.BeginHorizontal(); | |
if (GUILayout.Button("Clear", EditorStyles.miniButtonLeft, GUILayout.ExpandWidth(false))) | |
list.Clear(); | |
if (GUILayout.Button("+", EditorStyles.miniButtonRight)) | |
list.Add(""); | |
EditorGUILayout.EndHorizontal(); | |
} | |
/// <summary> | |
/// Display an object list | |
/// </summary> | |
private static void DrawList<T>(IList<T> list) where T : Object | |
{ | |
for (var i = 0; i < list.Count; ++i) | |
{ | |
list[i] = (T) EditorGUILayout.ObjectField(list[i], typeof(T), true); | |
if (list[i] != null) continue; | |
list.RemoveAt(i); | |
--i; | |
} | |
} | |
/// <summary> | |
/// Draw a drag and drop area for an Object list | |
/// </summary> | |
private static void DropAreaGUI(string title, string message, ICollection<Object> target, float height) | |
{ | |
if (!string.IsNullOrEmpty(title)) | |
{ | |
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); | |
EditorGUILayout.LabelField(title, EditorStyles.boldLabel); | |
if (GUILayout.Button("Clear", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) | |
target.Clear(); | |
EditorGUILayout.EndHorizontal(); | |
} | |
var currentEvent = Event.current; | |
var dropArea = GUILayoutUtility.GetRect(0.0f, height, GUILayout.ExpandWidth(true)); | |
GUI.Box(dropArea, message, _dragAreaStyle); | |
switch (currentEvent.type) | |
{ | |
case EventType.DragUpdated: | |
case EventType.DragPerform: | |
if (!dropArea.Contains(currentEvent.mousePosition)) return; | |
DragAndDrop.visualMode = DragAndDropVisualMode.Link; | |
if (currentEvent.type == EventType.DragPerform) | |
{ | |
DragAndDrop.AcceptDrag(); | |
foreach (var item in DragAndDrop.objectReferences) | |
target.Add(item); | |
} | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment