Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save impmja/23867e954c3cb33144dab672ba263618 to your computer and use it in GitHub Desktop.
Save impmja/23867e954c3cb33144dab672ba263618 to your computer and use it in GitHub Desktop.
This Unity Editor extension generates a constant or enum C# file from a defined set of tk2dSpriteCollection prefabs. It's thereby only useful if you use the Unity 2D Toolkit: http://www.assetstore.unity3d.com/en/#!/content/908 - Enjoy
/*
The MIT License(MIT)
Copyright(c) 2016 Jan Schulte @ http://github.com/impmja
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
NOTE: This Unity Editor extension generates a constant or enum C# file from a defined set of tk2dSpriteCollection prefabs.
It's thereby only useful if you use the Unity 2D Toolkit: http://www.assetstore.unity3d.com/en/#!/content/908
NOTE: It's heavily inspired by: http://github.com/nickgravelyn/UnityToolbag/blob/master/UnityConstants/Editor/UnityConstantsGenerator.cs
NOTE: I'm NOT affiliated in any way with 2D Toolkit - It's just a helper I use within my project which I wanted to share - Enjoy.
*/
using System;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace tk2d {
namespace editor {
namespace generator {
public static class Constants {
public static string PREFAB_EXTENSION = ".prefab";
public static string ASSETS_DIRECTORY = "Assets";
public static string LINE_INDENT = " ";
}
public static class Configuration {
public enum GenerationType {
Constants = 0,
Enums = 1
};
public static string DEFAULT_OUTPUT_FILENAME = "tk2dSpriteCollectionConstants";
public static string DEFAULT_OUTPUT_FILENAME_EXTENSION = "cs";
public static string DEFAULT_OUTPUT_FILENAME_WITH_EXTENSION = DEFAULT_OUTPUT_FILENAME + "." +
DEFAULT_OUTPUT_FILENAME_EXTENSION;
public static string DEFAULT_NAMESPACE = "tk2dSpriteCollectionConstants";
private static string EDITOR_PREFS_FIRST_START = "tk2dSpriteCollectionConstantsGenerator_FirstStart";
private static string EDITOR_PREFS_SPRITE_COLLECTIONS_DIRECTORY =
"tk2dSpriteCollectionConstantsGenerator_SpriteCollectionsDirectory";
private static string EDITOR_PREFS_OUTPUT_FILENAME =
"tk2dSpriteCollectionConstantsGenerator_OutputFilename";
private static string EDITOR_PREFS_NAMESPACES = "tk2dSpriteCollectionConstantsGenerator_Namespaces";
private static string EDITOR_PREFS_GENERATION_TYPE =
"tk2dSpriteCollectionConstantsGenerator_GenerationType";
private static readonly char[] NAMESPACE_DELIMITERS = {' ', ',', ';', '_', '\n', '\r', '\t'};
public static bool IsFirstStart() {
if (EditorPrefs.HasKey(EDITOR_PREFS_FIRST_START)) {
return EditorPrefs.GetBool(EDITOR_PREFS_FIRST_START);
}
return false;
}
public static void SetFirstStart(bool value) {
EditorPrefs.SetBool(EDITOR_PREFS_FIRST_START, value);
}
public static void SetSpriteCollectionsDirectory(string directory) {
if (!string.IsNullOrEmpty(directory)) {
EditorPrefs.SetString(EDITOR_PREFS_SPRITE_COLLECTIONS_DIRECTORY,
Utilities.FixAbsoluteAssetDirectory(directory));
}
}
public static string GetSpriteCollectionsDirectory() {
var result = Constants.ASSETS_DIRECTORY;
if (EditorPrefs.HasKey(EDITOR_PREFS_SPRITE_COLLECTIONS_DIRECTORY)) {
var directory = EditorPrefs.GetString(EDITOR_PREFS_SPRITE_COLLECTIONS_DIRECTORY);
if (!string.IsNullOrEmpty(directory)) {
result = Utilities.FixAbsoluteAssetDirectory(directory);
}
}
return result;
}
public static void SetOutputFilename(string filename) {
if (!string.IsNullOrEmpty(filename)) {
EditorPrefs.SetString(EDITOR_PREFS_OUTPUT_FILENAME, filename);
}
}
public static string GetOutputFilename() {
var result = DEFAULT_OUTPUT_FILENAME_WITH_EXTENSION;
if (EditorPrefs.HasKey(EDITOR_PREFS_OUTPUT_FILENAME)) {
var filename = EditorPrefs.GetString(EDITOR_PREFS_OUTPUT_FILENAME);
if (!string.IsNullOrEmpty(filename)) {
result = filename;
}
}
return result;
}
public static void SetNamespaces(string namespaces) {
if (!string.IsNullOrEmpty(namespaces)) {
EditorPrefs.SetString(EDITOR_PREFS_NAMESPACES, namespaces);
}
}
public static string GetNamespaces() {
var result = DEFAULT_NAMESPACE;
if (EditorPrefs.HasKey(EDITOR_PREFS_NAMESPACES)) {
var namespaces = EditorPrefs.GetString(EDITOR_PREFS_NAMESPACES);
if (!string.IsNullOrEmpty(namespaces)) {
result = namespaces;
}
}
return result;
}
public static string[] GetCompiledNamespaces() {
var namespaces = GetNamespaces();
var result = namespaces.Split(NAMESPACE_DELIMITERS, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < result.Length; ++i) {
result[i] = Utilities.MakeCodeSafe(result[i]);
}
return result;
}
public static void SetGenerationType(GenerationType type) {
EditorPrefs.SetInt(EDITOR_PREFS_GENERATION_TYPE, (int) type);
}
public static GenerationType GetGenerationType() {
var result = GenerationType.Constants;
if (EditorPrefs.HasKey(EDITOR_PREFS_GENERATION_TYPE)) {
return (GenerationType) EditorPrefs.GetInt(EDITOR_PREFS_GENERATION_TYPE);
}
return result;
}
private static void Reset() {
if (EditorPrefs.HasKey(EDITOR_PREFS_FIRST_START)) {
EditorPrefs.DeleteKey(EDITOR_PREFS_FIRST_START);
}
if (EditorPrefs.HasKey(EDITOR_PREFS_SPRITE_COLLECTIONS_DIRECTORY)) {
EditorPrefs.DeleteKey(EDITOR_PREFS_SPRITE_COLLECTIONS_DIRECTORY);
}
if (EditorPrefs.HasKey(EDITOR_PREFS_OUTPUT_FILENAME)) {
EditorPrefs.DeleteKey(EDITOR_PREFS_OUTPUT_FILENAME);
}
if (EditorPrefs.HasKey(EDITOR_PREFS_NAMESPACES)) {
EditorPrefs.DeleteKey(EDITOR_PREFS_NAMESPACES);
}
if (EditorPrefs.HasKey(EDITOR_PREFS_GENERATION_TYPE)) {
EditorPrefs.DeleteKey(EDITOR_PREFS_GENERATION_TYPE);
}
}
}
public class ConfigurationWindow : EditorWindow {
private static string WINDOW_TITLE = "tk2dSpriteCollection Constant Generator: Configuration";
private static string DIALOG_CHOOSE_SPRITE_COLLECTIONS_DIRECTORY_TITLE = "Select Sprite Collections directory";
private static string DIALOG_OUTPUT_FILENAME_TITLE = "Select Output Filename";
private static string DIALOG_OUTPUT_FILENAME_DESCRIPTION = "Select Filename to which the tk2dSpriteCollection constants/enums should be saved.";
private static string LABEL_SET_SPRITE_COLLECTIONS_DIRECTORY = "Sprite Collections Directory: ";
private static string BUTTON_SET_SPRITE_COLLECTIONS_DIRECTORY = "Select";
private static string LABEL_SET_OUTPUT_FILENAME = "Output Filename: ";
private static string BUTTON_SET_OUTPUT_FILENAME = "Select";
private static string LABEL_SET_NAMESPACES = "Namespace(s):";
private static string LABEL_GENERATION_TYPE = "Generate as:";
private static readonly string[] SELECTION_GRID_GENERATION_TYPE = {"Constants", "Enums"};
private static string BUTTON_RESET = "Reset";
private static string BUTTON_CANCEL = "Cancel";
private static string BUTTON_SAVE = "Save";
private static string BUTTON_SAVE_AND_GENERATE = "Save & Generate";
private string _outputFilename = Configuration.GetOutputFilename();
private string _namespaces = Configuration.GetNamespaces();
private string _spriteCollectionsDirectory = Configuration.GetSpriteCollectionsDirectory();
private Configuration.GenerationType _generationType = Configuration.GetGenerationType();
[MenuItem("2D Toolkit/Sprite Collection/Configurate")]
public static void Initialize() {
var window = GetWindow(typeof(ConfigurationWindow));
window.Show();
}
public void OnEnable() {
titleContent.text = WINDOW_TITLE;
minSize = new Vector2(570.0f, 230.0f);
}
public void OnGUI() {
GUILayout.Label(WINDOW_TITLE, EditorStyles.boldLabel);
GUILayout.Space(10.0f);
GUILayout.BeginHorizontal("box");
GUILayout.Label(LABEL_SET_SPRITE_COLLECTIONS_DIRECTORY + _spriteCollectionsDirectory);
if (GUILayout.Button(BUTTON_SET_SPRITE_COLLECTIONS_DIRECTORY, GUILayout.Width(120.0f))) {
var spriteCollectionsDirectory =
EditorUtility.OpenFolderPanel(DIALOG_CHOOSE_SPRITE_COLLECTIONS_DIRECTORY_TITLE,
_spriteCollectionsDirectory /*Application.dataPath*/, "");
if (!string.IsNullOrEmpty(spriteCollectionsDirectory)) {
_spriteCollectionsDirectory = Utilities.FixAbsoluteAssetDirectory(spriteCollectionsDirectory);
}
GUIUtility.ExitGUI();
}
GUILayout.EndHorizontal();
GUILayout.Space(10.0f);
GUILayout.BeginHorizontal("box");
GUILayout.Label(LABEL_SET_OUTPUT_FILENAME + _outputFilename);
if (GUILayout.Button(BUTTON_SET_OUTPUT_FILENAME, GUILayout.Width(120.0f))) {
var outputFilename = EditorUtility.SaveFilePanelInProject(DIALOG_OUTPUT_FILENAME_TITLE,
_outputFilename,
Configuration
.DEFAULT_OUTPUT_FILENAME_EXTENSION,
DIALOG_OUTPUT_FILENAME_DESCRIPTION);
if (!string.IsNullOrEmpty(outputFilename)) {
_outputFilename = outputFilename;
}
GUIUtility.ExitGUI();
}
GUILayout.EndHorizontal();
GUILayout.Space(10.0f);
GUILayout.BeginHorizontal("box");
GUILayout.Label(LABEL_SET_NAMESPACES);
_namespaces = GUILayout.TextArea(_namespaces, GUILayout.MinWidth(200.0f));
GUILayout.EndHorizontal();
GUILayout.Space(10.0f);
GUILayout.BeginHorizontal("box");
GUILayout.Label(LABEL_GENERATION_TYPE);
_generationType =
(Configuration.GenerationType)
GUILayout.SelectionGrid((int) _generationType, SELECTION_GRID_GENERATION_TYPE,
SELECTION_GRID_GENERATION_TYPE.Length, GUILayout.Width(240.0f));
GUILayout.EndHorizontal();
GUILayout.Space(20.0f);
GUILayout.BeginHorizontal("box");
if (GUILayout.Button(BUTTON_RESET, GUILayout.Width(120.0f))) {
_spriteCollectionsDirectory = Constants.ASSETS_DIRECTORY;
_outputFilename = Configuration.DEFAULT_OUTPUT_FILENAME_WITH_EXTENSION;
_namespaces = Configuration.DEFAULT_NAMESPACE;
_generationType = Configuration.GenerationType.Constants;
Configuration.SetFirstStart(true);
Repaint();
}
GUILayout.Space(40.0f);
if (GUILayout.Button(BUTTON_CANCEL, GUILayout.Width(120.0f))) {
Close();
}
GUILayout.Space(10.0f);
GUI.enabled = IsValid();
if (GUILayout.Button(BUTTON_SAVE, GUILayout.Width(120.0f))) {
Configuration.SetFirstStart(false);
Configuration.SetSpriteCollectionsDirectory(_spriteCollectionsDirectory);
Configuration.SetOutputFilename(_outputFilename);
Configuration.SetNamespaces(_namespaces);
Configuration.SetGenerationType(_generationType);
Close();
}
GUI.enabled = true;
GUILayout.Space(10.0f);
GUI.enabled = IsValid();
if (GUILayout.Button(BUTTON_SAVE_AND_GENERATE, GUILayout.Width(120.0f))) {
Configuration.SetFirstStart(false);
Configuration.SetSpriteCollectionsDirectory(_spriteCollectionsDirectory);
Configuration.SetOutputFilename(_outputFilename);
Configuration.SetNamespaces(_namespaces);
Configuration.SetGenerationType(_generationType);
Close();
SpriteCollectionConstantsGenerator.Generate();
}
GUI.enabled = true;
GUILayout.EndHorizontal();
}
private bool IsValid() {
if (string.IsNullOrEmpty(_spriteCollectionsDirectory) ||
string.IsNullOrEmpty(_outputFilename) ||
string.IsNullOrEmpty(_namespaces)) {
return false;
}
return true;
}
}
public static class Utilities {
public static string FixAbsoluteAssetDirectory(string directory) {
if (directory.StartsWith(Application.dataPath)) {
return Constants.ASSETS_DIRECTORY + directory.Substring(Application.dataPath.Length);
}
return directory;
}
/// <summary>
/// Taken from: http://github.com/nickgravelyn/UnityToolbag/blob/master/UnityConstants/Editor/UnityConstantsGenerator.cs
/// </summary>
public static string MakeCodeSafe(string name) {
name = Regex.Replace(name, "[^a-zA-Z0-9_]", "_", RegexOptions.Compiled);
if (char.IsDigit(name[0])) {
name = "_" + name;
}
return name;
}
/// <summary>
/// Recursively gather all files under the given directory including all its subfolders.
/// Taken from: http://answers.unity3d.com/questions/234935/how-do-i-enumerate-the-contents-of-an-asset-folder.html
/// </summary>
public static IEnumerable<string> GetFiles(string directory) {
var queue = new Queue<string>();
queue.Enqueue(directory);
while (queue.Count > 0) {
directory = queue.Dequeue();
try {
foreach (var subDir in Directory.GetDirectories(directory)) {
queue.Enqueue(subDir);
}
}
catch (System.Exception ex) {
Debug.LogError(ex.Message);
}
string[] files = null;
try {
files = Directory.GetFiles(directory);
}
catch (System.Exception ex) {
Debug.LogError(ex.Message);
}
if (files != null) {
for (int i = 0; i < files.Length; ++i) {
yield return files[i];
}
}
}
}
}
public static class SpriteCollectionConstantsGenerator {
[MenuItem("2D Toolkit/Sprite Collection/Generate")]
public static void Generate() {
if (Configuration.IsFirstStart()) {
ConfigurationWindow.Initialize();
return;
}
var prefabPaths = Utilities.GetFiles(Configuration.GetSpriteCollectionsDirectory()).Where(path => path.EndsWith(Constants.PREFAB_EXTENSION));
var spriteCollections = prefabPaths.Select(prefabPath => AssetDatabase.LoadAssetAtPath(prefabPath, typeof(tk2dSpriteCollectionData))).Cast<tk2dSpriteCollectionData>().Where(component => component != null);
switch (Configuration.GetGenerationType()) {
case Configuration.GenerationType.Constants: {
GenerateConstants(spriteCollections);
break;
}
case Configuration.GenerationType.Enums: {
GenerateEnums(spriteCollections);
break;
}
}
AssetDatabase.Refresh();
}
private static void GenerateConstants(IEnumerable<tk2dSpriteCollectionData> spriteCollections) {
using (var writer = new StreamWriter(Configuration.GetOutputFilename())) {
var namespaces = Configuration.GetCompiledNamespaces();
WriteHeader(writer);
WriteNamespacesBegin(writer, namespaces);
WriteConstants(writer, spriteCollections, namespaces.Length);
WriteNamespacesEnd(writer, namespaces);
WriteFooter(writer);
}
}
private static void GenerateEnums(IEnumerable<tk2dSpriteCollectionData> spriteCollections) {
using (var writer = new StreamWriter(Configuration.GetOutputFilename())) {
var namespaces = Configuration.GetCompiledNamespaces();
WriteHeader(writer);
WriteNamespacesBegin(writer, namespaces);
WriteEnums(writer, spriteCollections, namespaces.Length);
WriteNamespacesEnd(writer, namespaces);
WriteFooter(writer);
}
}
private static void WriteHeader(TextWriter writer) {
writer.WriteLine("/// This file is auto-generated. Modifications are not saved.");
writer.WriteLine();
}
private static void WriteFooter(TextWriter writer) {
writer.WriteLine();
}
private static void WriteNamespacesBegin(TextWriter writer, string[] namespaces) {
if (namespaces == null || namespaces.Length == 0) {
return;
}
for (var i = 0; i < namespaces.Length; ++i) {
WriteIdents(writer, i);
writer.WriteLine("namespace " + namespaces[i] + " {");
}
writer.WriteLine();
}
private static void WriteNamespacesEnd(TextWriter writer, string[] namespaces) {
if (namespaces == null || namespaces.Length == 0) {
return;
}
for (int i = 0, j = namespaces.Length - 1; i < namespaces.Length; ++i, --j) {
WriteIdents(writer, j);
writer.WriteLine("}");
}
}
private static void WriteIdents(TextWriter writer, int numIdents) {
for (var i = 0; i < numIdents; ++i) {
writer.Write(Constants.LINE_INDENT);
}
}
private static void WriteEnums(TextWriter writer,
IEnumerable<tk2dSpriteCollectionData> spriteCollections, int numIdents) {
foreach (var spriteCollection in spriteCollections) {
WriteEnumsBegin(writer, spriteCollection, numIdents);
for (var i = 0; i < spriteCollection.spriteDefinitions.Length; ++i) {
WriteEnum(writer, spriteCollection, spriteCollection.spriteDefinitions[i], numIdents + 1);
}
WriteAllEnum(writer, spriteCollection.spriteDefinitions.Length, numIdents + 1);
WriteEnumsEnd(writer, numIdents);
}
}
private static void WriteEnumsBegin(TextWriter writer, tk2dSpriteCollectionData spriteCollection,
int numIdents) {
WriteIdents(writer, numIdents);
writer.WriteLine("public enum " + Utilities.MakeCodeSafe(spriteCollection.spriteCollectionName) +
" {");
}
private static void WriteEnumsEnd(TextWriter writer, int numIdents) {
WriteIdents(writer, numIdents);
writer.WriteLine("}");
writer.WriteLine();
}
private static void WriteEnum(TextWriter writer, tk2dSpriteCollectionData spriteCollection,
tk2dSpriteDefinition spriteDefinition, int numIdents) {
var spriteName = spriteDefinition.name;
var spriteId = spriteCollection.GetSpriteIdByName(spriteName, -1);
WriteIdents(writer, numIdents);
writer.WriteLine("/// <summary>");
WriteIdents(writer, numIdents);
writer.WriteLine("/// Name '{0}'", spriteName);
WriteIdents(writer, numIdents);
writer.WriteLine("/// <para> Id '{0}' </para>", spriteId);
WriteIdents(writer, numIdents);
writer.WriteLine("/// </summary>");
WriteIdents(writer, numIdents);
writer.WriteLine("{0} = {1},", Utilities.MakeCodeSafe(spriteName), spriteId);
writer.WriteLine();
}
private static void WriteAllEnum(TextWriter writer, int numSprites, int numIdents) {
WriteIdents(writer, numIdents);
writer.WriteLine("/// <summary>");
WriteIdents(writer, numIdents);
writer.WriteLine("/// Sum of all sprites within this collection");
WriteIdents(writer, numIdents);
writer.WriteLine("/// </summary>");
WriteIdents(writer, numIdents);
writer.WriteLine("All = {0},", numSprites);
}
private static void WriteConstants(TextWriter writer,
IEnumerable<tk2dSpriteCollectionData> spriteCollections, int numIdents) {
foreach (var spriteCollection in spriteCollections) {
WriteConstantsBegin(writer, spriteCollection, numIdents);
for (var i = 0; i < spriteCollection.spriteDefinitions.Length; ++i) {
WriteConstant(writer, spriteCollection, spriteCollection.spriteDefinitions[i], numIdents + 1);
}
WriteAllConstant(writer, spriteCollection.spriteDefinitions.Length, numIdents + 1);
WriteConstantsEnd(writer, numIdents);
}
}
private static void WriteConstantsBegin(TextWriter writer, tk2dSpriteCollectionData spriteCollection,
int numIdents) {
WriteIdents(writer, numIdents);
writer.WriteLine("public static class " +
Utilities.MakeCodeSafe(spriteCollection.spriteCollectionName) + " {");
}
private static void WriteConstantsEnd(TextWriter writer, int numIdents) {
WriteIdents(writer, numIdents);
writer.WriteLine("}");
writer.WriteLine();
}
private static void WriteConstant(TextWriter writer, tk2dSpriteCollectionData spriteCollection,
tk2dSpriteDefinition spriteDefinition, int numIdents) {
var spriteName = spriteDefinition.name;
var spriteId = spriteCollection.GetSpriteIdByName(spriteName, -1);
WriteIdents(writer, numIdents);
writer.WriteLine("/// <summary>");
WriteIdents(writer, numIdents);
writer.WriteLine("/// Name '{0}'", spriteName);
WriteIdents(writer, numIdents);
writer.WriteLine("/// <para> Id '{0}' </para>", spriteId);
WriteIdents(writer, numIdents);
writer.WriteLine("/// </summary>");
WriteIdents(writer, numIdents);
writer.WriteLine("public static int {0} = {1};", Utilities.MakeCodeSafe(spriteName), spriteId);
writer.WriteLine();
}
private static void WriteAllConstant(TextWriter writer, int numSprites, int numIdents) {
WriteIdents(writer, numIdents);
writer.WriteLine("/// <summary>");
WriteIdents(writer, numIdents);
writer.WriteLine("/// Sum of all sprites within this collection");
WriteIdents(writer, numIdents);
writer.WriteLine("/// </summary>");
WriteIdents(writer, numIdents);
writer.WriteLine("public static int All = {0};", numSprites);
}
}
} // namespace generator
} // namespace editor
} // namespace tk2d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment