278 lines
11 KiB
C#
278 lines
11 KiB
C#
#if UNITY_EDITOR
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using UnityEditor;
|
|
using UnityEditor.AddressableAssets;
|
|
using UnityEditor.AddressableAssets.Settings;
|
|
using UnityEngine;
|
|
|
|
namespace DDD
|
|
{
|
|
public static class AssetPostprocessorEnvironment
|
|
{
|
|
private static readonly HashSet<string> TileTargetPaths = new();
|
|
private static readonly HashSet<string> PropTargetPaths = new();
|
|
private static readonly HashSet<string> FoodTargetPaths = new();
|
|
|
|
private const string BasePrefabPath_Prop = "Assets/_DDD/_Raw/Environments/Env_Mesh_Prop.prefab";
|
|
private const string BasePrefabPath_Tile = "Assets/_DDD/_Raw/Environments/Env_Sprite_Background.prefab";
|
|
private const string BasePrefabPath_Food = "Assets/_DDD/_Raw/Environments/Env_Unlit_Food.prefab";
|
|
private const string ShaderName = "Universal Render Pipeline/LitEnvironment";
|
|
private const string Prop = "Prop_";
|
|
private const string BaseUpper = "_BASE";
|
|
private const string NormalUpper = "_NORMAL";
|
|
|
|
public enum EnvPrefabType
|
|
{
|
|
Tile,
|
|
Prop,
|
|
Food
|
|
}
|
|
|
|
public static void OnPreprocessTexture(TextureImporter importer)
|
|
{
|
|
var path = importer.assetPath;
|
|
string fileNameUpper = Utils.FileName(path).ToUpper();
|
|
|
|
if (fileNameUpper.Contains(NormalUpper))
|
|
{
|
|
importer.textureType = TextureImporterType.NormalMap;
|
|
}
|
|
else if (fileNameUpper.Contains(BaseUpper))
|
|
{
|
|
importer.textureType = TextureImporterType.Sprite;
|
|
importer.spriteImportMode = SpriteImportMode.Single;
|
|
}
|
|
else
|
|
{
|
|
importer.textureType = TextureImporterType.Default;
|
|
importer.sRGBTexture = true;
|
|
}
|
|
|
|
importer.mipmapEnabled = true;
|
|
}
|
|
|
|
public static void OnAdd(string path)
|
|
{
|
|
AddTargetPath(path);
|
|
}
|
|
|
|
public static void OnRemove(string path, string movePath = "")
|
|
{
|
|
AddTargetPath(path);
|
|
|
|
}
|
|
|
|
private static void AddTargetPath(string path)
|
|
{
|
|
string upperPath = path.ToUpper();
|
|
|
|
if (upperPath.Contains(PathConstants.RawEnvPathUpper_Tile) &&
|
|
upperPath.Contains(ExtenstionConstants.PngExtensionUpper))
|
|
{
|
|
TileTargetPaths.Add(path);
|
|
}
|
|
else if (upperPath.Contains(PathConstants.RawEnvPathUpper_Prop) &&
|
|
upperPath.Contains(ExtenstionConstants.PngExtensionUpper))
|
|
{
|
|
PropTargetPaths.Add(path);
|
|
}
|
|
else if (upperPath.Contains(PathConstants.RawEnvPathUpper_Food) &&
|
|
upperPath.Contains(ExtenstionConstants.PngExtensionUpper))
|
|
{
|
|
FoodTargetPaths.Add(path);
|
|
}
|
|
}
|
|
|
|
public static void BuildMaterialAndPrefab(string path, EnvPrefabType prefabType)
|
|
{
|
|
var di = new DirectoryInfo(path);
|
|
if (!di.Exists) return;
|
|
|
|
string folderName = di.Name;
|
|
string rawRoot = PathConstants.RawFolderPath; // "/_Raw"
|
|
string addrRoot = PathConstants.AddressablesFolderPath; // "/_Addressables"
|
|
|
|
string destDir = path.Replace(rawRoot, addrRoot);
|
|
string materialPath = $"{destDir}/{folderName}{ExtenstionConstants.MaterialExtenstionLower}";
|
|
string prefabPath = $"{destDir}/{prefabType.ToString()}{folderName}{ExtenstionConstants.PrefabExtenstionLower}";
|
|
|
|
Utils.MakeFolderFromFilePath(materialPath);
|
|
|
|
bool bShouldCreateMaterial = false;
|
|
bShouldCreateMaterial = prefabType != EnvPrefabType.Food; // Add conditions if needed.
|
|
if (bShouldCreateMaterial)
|
|
{
|
|
// 머티리얼 생성 또는 로드
|
|
var mat = CreateOrLoadMaterial(path, materialPath, out var files, out var shader);
|
|
MatchTexturesToShaderProperties(shader, files, mat);
|
|
AssetDatabase.ImportAsset(materialPath, ImportAssetOptions.ForceUpdate);
|
|
AssetDatabase.SaveAssets();
|
|
CreateMaterialPrefabVariantIfNotExist(folderName, mat, prefabPath, prefabType);
|
|
}
|
|
else // Set sprite to renderer
|
|
{
|
|
var files = Directory.GetFiles(path, $"*{ExtenstionConstants.PngExtensionLower}",
|
|
SearchOption.TopDirectoryOnly);
|
|
foreach (var file in files)
|
|
{
|
|
string texName = Path.GetFileNameWithoutExtension(file).ToUpper();
|
|
Sprite tex = AssetDatabase.LoadAssetAtPath<Sprite>(file);
|
|
if (tex == null) continue;
|
|
// 셰이더 프로퍼티명과 텍스처 파일명의 접미사 매칭
|
|
if (IsTextureMatchingPropertyBySuffix(texName, BaseUpper))
|
|
CreateSpritePrefabVariantIfNotExist(folderName, tex, prefabPath, prefabType);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static Material CreateOrLoadMaterial(string path, string materialPath, out string[] files, out Shader shader)
|
|
{
|
|
Material mat = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
|
|
if (mat == null)
|
|
{
|
|
mat = new Material(Shader.Find(ShaderName));
|
|
AssetDatabase.CreateAsset(mat, materialPath);
|
|
}
|
|
|
|
// PNG 텍스처 매핑 - 셰이더 프로퍼티와 텍스처 접미사 매칭
|
|
files = Directory.GetFiles(path, $"*{ExtenstionConstants.PngExtensionLower}", SearchOption.TopDirectoryOnly);
|
|
shader = mat.shader;
|
|
return mat;
|
|
}
|
|
|
|
private static void MatchTexturesToShaderProperties(Shader shader, string[] files, Material mat)
|
|
{
|
|
for (int i = 0; i < ShaderUtil.GetPropertyCount(shader); i++)
|
|
{
|
|
if (ShaderUtil.GetPropertyType(shader, i) != ShaderUtil.ShaderPropertyType.TexEnv)
|
|
continue;
|
|
|
|
string propertyName = ShaderUtil.GetPropertyName(shader, i);
|
|
|
|
foreach (var file in files)
|
|
{
|
|
string texName = Path.GetFileNameWithoutExtension(file).ToUpper();
|
|
var tex = AssetDatabase.LoadAssetAtPath<Texture>(file);
|
|
if (tex == null) continue;
|
|
|
|
// 셰이더 프로퍼티명과 텍스처 파일명의 접미사 매칭
|
|
if (IsTextureMatchingPropertyBySuffix(texName, propertyName))
|
|
{
|
|
mat.SetTexture(propertyName, tex);
|
|
break; // 매칭되면 다음 프로퍼티로
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool IsTextureMatchingPropertyBySuffix(string textureName, string propertyName)
|
|
{
|
|
// 셰이더 프로퍼티명에서 접미사 추출 (예: _BaseMap -> BASEMAP)
|
|
string propertySuffix = propertyName.TrimStart('_').ToUpper();
|
|
|
|
// 텍스처 파일명이 해당 접미사로 끝나는지 확인
|
|
return textureName.Contains($"_{propertySuffix}");
|
|
}
|
|
|
|
private static void CreateMaterialPrefabVariantIfNotExist(string folderName, Material mat, string prefabPath, EnvPrefabType prefabType)
|
|
{
|
|
if (AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath) != null) return;
|
|
|
|
if (InstantiatePrefabByType(folderName, prefabPath, prefabType, out var instancePrefab)) return;
|
|
|
|
if (mat != null)
|
|
{
|
|
var renderer = instancePrefab.GetComponentInChildren<Renderer>();
|
|
if (renderer != null) renderer.sharedMaterial = mat;
|
|
}
|
|
|
|
SavePrefabInstance(prefabPath, instancePrefab);
|
|
}
|
|
|
|
private static void CreateSpritePrefabVariantIfNotExist(string folderName, Sprite sprite, string prefabPath,
|
|
EnvPrefabType prefabType)
|
|
{
|
|
if (AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath) != null) return;
|
|
|
|
if (InstantiatePrefabByType(folderName, prefabPath, prefabType, out var instancePrefab)) return;
|
|
|
|
if (sprite != null)
|
|
{
|
|
var renderer = instancePrefab.GetComponentInChildren<SpriteRenderer>();
|
|
if (renderer != null) renderer.sprite = sprite;
|
|
}
|
|
|
|
SavePrefabInstance(prefabPath, instancePrefab);
|
|
}
|
|
|
|
private static void SavePrefabInstance(string prefabPath, GameObject instancePrefab)
|
|
{
|
|
Utils.MakeFolderFromFilePath(prefabPath);
|
|
PrefabUtility.SaveAsPrefabAssetAndConnect(instancePrefab, prefabPath, InteractionMode.AutomatedAction);
|
|
Object.DestroyImmediate(instancePrefab);
|
|
|
|
AssetDatabase.ImportAsset(prefabPath, ImportAssetOptions.ForceUpdate);
|
|
AssetDatabase.SaveAssets();
|
|
AssetDatabase.Refresh();
|
|
}
|
|
|
|
private static bool InstantiatePrefabByType(string folderName, string prefabPath, EnvPrefabType prefabType,
|
|
out GameObject instancePrefab)
|
|
{
|
|
// EnvPrefabType에 따라 베이스 프리팹 결정
|
|
string basePrefabPath = GetBasePrefabPath(prefabType);
|
|
|
|
var basePrefab = AssetDatabase.LoadAssetAtPath<GameObject>(basePrefabPath);
|
|
if (basePrefab == null)
|
|
{
|
|
Debug.LogWarning($"Base prefab not found: {basePrefabPath}");
|
|
instancePrefab = null;
|
|
return true;
|
|
}
|
|
|
|
instancePrefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
|
if (instancePrefab == null)
|
|
{
|
|
instancePrefab = (GameObject)PrefabUtility.InstantiatePrefab(basePrefab);
|
|
instancePrefab.name = $"{Prop}{folderName}";
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static string GetBasePrefabPath(EnvPrefabType prefabType)
|
|
{
|
|
return prefabType switch
|
|
{
|
|
EnvPrefabType.Prop => BasePrefabPath_Prop,
|
|
EnvPrefabType.Tile => BasePrefabPath_Tile,
|
|
EnvPrefabType.Food => BasePrefabPath_Food,
|
|
_ => BasePrefabPath_Prop
|
|
};
|
|
}
|
|
|
|
public static void BuildTarget()
|
|
{
|
|
foreach (var path in TileTargetPaths)
|
|
{
|
|
BuildMaterialAndPrefab(Utils.FolderPath(path), EnvPrefabType.Tile);
|
|
}
|
|
|
|
foreach (var path in PropTargetPaths)
|
|
{
|
|
BuildMaterialAndPrefab(Utils.FolderPath(path), EnvPrefabType.Prop);
|
|
}
|
|
|
|
foreach (var path in FoodTargetPaths)
|
|
{
|
|
BuildMaterialAndPrefab(Utils.FolderPath(path), EnvPrefabType.Food);
|
|
}
|
|
|
|
TileTargetPaths.Clear();
|
|
PropTargetPaths.Clear();
|
|
FoodTargetPaths.Clear();
|
|
}
|
|
}
|
|
}
|
|
#endif |