Skip to content

Instantly share code, notes, and snippets.

@Hafune
Last active July 6, 2024 14:26
Show Gist options
  • Save Hafune/60acdbff098ccc756a183b863a774073 to your computer and use it in GitHub Desktop.
Save Hafune/60acdbff098ccc756a183b863a774073 to your computer and use it in GitHub Desktop.
Unity - базовый пример кодогенерации
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEditor;
//-----------
using Core.TestNamespace;
namespace Core.TestNamespace
{
public interface IData
{
}
public class Data1 : IData
{
}
public class Data2 : IData
{
}
public class Data3 : IData
{
}
public class Data4 : IData
{
}
}
//-------------
namespace Core.Editor
{
[InitializeOnLoad]
public static class GenLauncher
{
private const string DIR = "Core/_GeneratedFiles";
public static string MakePath(string name) => $"{DIR}/{name}.cs";
static GenLauncher()
{
if (EditorApplication.isPlayingOrWillChangePlaymode)
return;
if (!GenActionEnum.Gen())
return;
AssetDatabase.Refresh();
Debug.Log("Generated");
}
}
public static class GenActionEnum
{
public const string EnumName = "ActionEnum";
private static string Template = $@"//Файл генерируется в {nameof(GenActionEnum)}
namespace Core.Generated
{{
public enum {EnumName}
{{
#FIELDS#
}}
}}";
public static bool Gen()
{
Dictionary<string, int> keyValues = new();
var implementingTypes = AppDomain.CurrentDomain.GetAssignableTypes<IData>();
foreach (var implementingType in implementingTypes)
keyValues[implementingType.Name] = Animator.StringToHash(implementingType.Name);
var fields = keyValues.Select(pair => $"{pair.Key} = {pair.Value},").OrderBy(i => i);
string content = Template;
content = TemplateUtility.ReplaceTagWithIndentedMultiline(content, "#FIELDS#", fields);
return TemplateUtility.WriteScriptIfDifferent(content, GenLauncher.MakePath(EnumName));
}
public static Type[] GetAssignableTypes<T>(this AppDomain appDomain, bool findGenerics = false)
{
var _assemblies = appDomain.GetAssemblies();
var typeT = typeof(T);
return _assemblies
.SelectMany(assembly => assembly.GetTypes()
.Where(type =>
typeT.IsAssignableFrom(type) && !type.IsAbstract && type.IsGenericType == findGenerics))
.ToArray();
}
}
internal static class TemplateUtility
{
public static string ReplaceTagWithIndentedMultiline(string templateContent, string tag,
IEnumerable<string> newLines)
{
var tagWithIndentRegex = $"\\ *{tag}";
var match = Regex.Match(templateContent, tagWithIndentRegex);
var indent = match.Value.Substring(0, match.Value.Length - tag.Length);
var replacement = string.Join(Environment.NewLine + indent, newLines);
return Regex.Replace(templateContent, tag, replacement);
}
public static bool WriteScriptIfDifferent(string content, string assetFilePath)
{
var fullPath = GetFullPath(assetFilePath);
var directoryPath = Path.GetDirectoryName(fullPath)!;
if (!Directory.Exists(directoryPath))
Directory.CreateDirectory(directoryPath);
if (File.Exists(fullPath) && File.ReadAllText(fullPath) == content)
return false;
File.WriteAllText(fullPath, content);
return true;
}
private static string GetFullPath(string fileName) => Path.Combine(Application.dataPath, fileName);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment