구글 시트 매니저 로직 수정
This commit is contained in:
parent
c04291fdd4
commit
df3341158a
@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
#if UNITY_EDITOR
|
||||||
using UnityEditor.AddressableAssets;
|
using UnityEditor.AddressableAssets;
|
||||||
|
#endif
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.AddressableAssets;
|
using UnityEngine.AddressableAssets;
|
||||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||||
|
@ -89,8 +89,6 @@ public static async Task<T> LoadSo<T>() where T : ScriptableObject
|
|||||||
[Button("데이터 최신화"), EnableIf(nameof(CanFetchData))]
|
[Button("데이터 최신화"), EnableIf(nameof(CanFetchData))]
|
||||||
private async Task FetchGoogleSheet()
|
private async Task FetchGoogleSheet()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
_availSheetArray = _availSheets.Split('/');
|
_availSheetArray = _availSheets.Split('/');
|
||||||
|
|
||||||
var prevLog = AssetDatabase.LoadAssetAtPath<GoogleSheetChangeLog>(ChangeLogAssetPath);
|
var prevLog = AssetDatabase.LoadAssetAtPath<GoogleSheetChangeLog>(ChangeLogAssetPath);
|
||||||
@ -366,14 +364,17 @@ private void GenerateClassFilesPerSheet(string jsonInput)
|
|||||||
foreach (var property in ((JObject)items[i]).Properties())
|
foreach (var property in ((JObject)items[i]).Properties())
|
||||||
{
|
{
|
||||||
string rawName = property.Name;
|
string rawName = property.Name;
|
||||||
|
|
||||||
// ✅ Enum 타입 여부 판단
|
|
||||||
string enumType = null;
|
string enumType = null;
|
||||||
if (rawName.EndsWith("_Enum"))
|
|
||||||
|
// ✅ 단일 필드 Enum: Cookware:Enum
|
||||||
|
if (rawName.Contains(":Enum"))
|
||||||
{
|
{
|
||||||
enumType = rawName.Contains(":")
|
enumType = rawName.Split(':')[0]; // 필드 이름이 곧 Enum 이름
|
||||||
? rawName.Split(':')[1].Replace("_Enum", "")
|
}
|
||||||
: rawName.Replace("_Enum", "");
|
// ✅ 공통 Enum: Taste1:Taste_Enum
|
||||||
|
else if (rawName.Contains(":") && rawName.EndsWith("_Enum"))
|
||||||
|
{
|
||||||
|
enumType = rawName.Split(':')[1].Replace("_Enum", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(enumType))
|
if (!string.IsNullOrEmpty(enumType))
|
||||||
@ -389,17 +390,17 @@ private void GenerateClassFilesPerSheet(string jsonInput)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnumTypes.cs 생성
|
// ✅ EnumTypes.cs 생성
|
||||||
StringBuilder enumCode = new();
|
StringBuilder enumCode = new();
|
||||||
enumCode.AppendLine("// <auto-generated>");
|
enumCode.AppendLine("// <auto-generated>");
|
||||||
enumCode.AppendLine("using System;\n");
|
enumCode.AppendLine("using System;");
|
||||||
enumCode.AppendLine();
|
enumCode.AppendLine();
|
||||||
enumCode.AppendLine($"namespace {_namespace}");
|
enumCode.AppendLine($"namespace {_namespace}");
|
||||||
enumCode.AppendLine("{");
|
enumCode.AppendLine("{");
|
||||||
|
|
||||||
foreach (var kvp in enumCandidates)
|
foreach (var kvp in enumCandidates)
|
||||||
{
|
{
|
||||||
enumCode.AppendLine($" public enum {kvp.Key} \n{{");
|
enumCode.AppendLine($" public enum {kvp.Key} \n {{");
|
||||||
enumCode.AppendLine(" None = 0,");
|
enumCode.AppendLine(" None = 0,");
|
||||||
int index = 1;
|
int index = 1;
|
||||||
foreach (string value in kvp.Value)
|
foreach (string value in kvp.Value)
|
||||||
@ -410,6 +411,7 @@ private void GenerateClassFilesPerSheet(string jsonInput)
|
|||||||
|
|
||||||
enumCode.AppendLine(" }\n");
|
enumCode.AppendLine(" }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
enumCode.AppendLine("}");
|
enumCode.AppendLine("}");
|
||||||
|
|
||||||
File.WriteAllText($"{BaseAssetPath}/EnumTypes.cs", enumCode.ToString());
|
File.WriteAllText($"{BaseAssetPath}/EnumTypes.cs", enumCode.ToString());
|
||||||
@ -421,7 +423,7 @@ private void GenerateClassFilesPerSheet(string jsonInput)
|
|||||||
AssetDatabase.ImportAsset(ClassedFullPath);
|
AssetDatabase.ImportAsset(ClassedFullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 시트별 클래스 생성
|
// ✅ 시트별 클래스/So 생성
|
||||||
foreach (var jObject in jsonObject)
|
foreach (var jObject in jsonObject)
|
||||||
{
|
{
|
||||||
string className = jObject.Key;
|
string className = jObject.Key;
|
||||||
@ -451,10 +453,10 @@ private string GenerateSoClassCode(string className)
|
|||||||
"using System.Collections.Generic;\n" +
|
"using System.Collections.Generic;\n" +
|
||||||
"using UnityEngine;\n\n" +
|
"using UnityEngine;\n\n" +
|
||||||
$"namespace {_namespace}\n" +
|
$"namespace {_namespace}\n" +
|
||||||
"{\n" +
|
$"{{\n" +
|
||||||
$" [CreateAssetMenu(fileName = \"{className}So\", menuName = \"GoogleSheet/{className}So\")]\n" +
|
$" [CreateAssetMenu(fileName = \"{className}So\", menuName = \"GoogleSheet/{className}So\")]\n" +
|
||||||
$" public class {className}So : ScriptableObject \n" +
|
$" public class {className}So : DataSo<{className}> {{ }}\n" +
|
||||||
$" {{\n public List<{className}> {className}List;\n }}\n}}\n";
|
$"}}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GenerateDataClassCode(string className, JArray items)
|
private string GenerateDataClassCode(string className, JArray items)
|
||||||
@ -470,7 +472,7 @@ private string GenerateDataClassCode(string className, JArray items)
|
|||||||
sb.AppendLine($"namespace {_namespace}");
|
sb.AppendLine($"namespace {_namespace}");
|
||||||
sb.AppendLine("{");
|
sb.AppendLine("{");
|
||||||
sb.AppendLine(" [Serializable]");
|
sb.AppendLine(" [Serializable]");
|
||||||
sb.AppendLine($" public class {className}");
|
sb.AppendLine($" public class {className} : IId");
|
||||||
sb.AppendLine(" {");
|
sb.AppendLine(" {");
|
||||||
|
|
||||||
int count = sampleRow.Properties().Count();
|
int count = sampleRow.Properties().Count();
|
||||||
@ -487,22 +489,27 @@ private string GenerateDataClassCode(string className, JArray items)
|
|||||||
string fieldName = rawName;
|
string fieldName = rawName;
|
||||||
string explicitType = null;
|
string explicitType = null;
|
||||||
|
|
||||||
if (rawName.Contains(":"))
|
if (rawName.Contains(":Enum"))
|
||||||
|
{
|
||||||
|
fieldName = rawName.Split(':')[0];
|
||||||
|
explicitType = fieldName;
|
||||||
|
}
|
||||||
|
else if (rawName.Contains(":") && rawName.EndsWith("_Enum"))
|
||||||
{
|
{
|
||||||
var parts = rawName.Split(':');
|
var parts = rawName.Split(':');
|
||||||
fieldName = parts[0];
|
fieldName = parts[0];
|
||||||
explicitType = parts[1].Replace("_Enum", "");
|
explicitType = parts[1].Replace("_Enum", "");
|
||||||
}
|
}
|
||||||
else if (rawName.EndsWith("_Enum"))
|
else if (rawName.Contains(":"))
|
||||||
{
|
{
|
||||||
fieldName = rawName.Replace("_Enum", "");
|
var parts = rawName.Split(':');
|
||||||
explicitType = fieldName;
|
fieldName = parts[0];
|
||||||
|
explicitType = parts[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
types[i] = explicitType ?? GetCSharpType(prop.Value.Type);
|
types[i] = explicitType ?? GetCSharpType(prop.Value.Type);
|
||||||
names[i] = fieldName;
|
names[i] = fieldName;
|
||||||
tooltips[i] ??= commentRow.TryGetValue(rawName, out var tip) ? tip.ToString() : "";
|
tooltips[i] ??= commentRow.TryGetValue(rawName, out var tip) ? tip.ToString() : "";
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -515,11 +522,20 @@ private string GenerateDataClassCode(string className, JArray items)
|
|||||||
sb.AppendLine($" [Tooltip(\"{tooltips[i]}\")]");
|
sb.AppendLine($" [Tooltip(\"{tooltips[i]}\")]");
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.AppendLine($" public {types[i]} {names[i]};\n");
|
if (names[i] == "Id" && types[i] == "string")
|
||||||
|
{
|
||||||
|
sb.AppendLine(" [field: SerializeField]");
|
||||||
|
sb.AppendLine(" public string Id { get; set; }\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.AppendLine($" public {types[i]} {names[i]};\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.AppendLine(" }");
|
sb.AppendLine(" }");
|
||||||
sb.AppendLine("}");
|
sb.AppendLine("}");
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,7 +632,6 @@ private async Task<bool> InternalCreateGoogleSheetSoAsync()
|
|||||||
string soPath = $"{soDirectory}/{sheetName}So.asset";
|
string soPath = $"{soDirectory}/{sheetName}So.asset";
|
||||||
ScriptableObject soInstance = AssetDatabase.LoadAssetAtPath<ScriptableObject>(soPath);
|
ScriptableObject soInstance = AssetDatabase.LoadAssetAtPath<ScriptableObject>(soPath);
|
||||||
|
|
||||||
// 💡 잘못된 asset이면 삭제 후 새로 생성
|
|
||||||
if (soInstance == null)
|
if (soInstance == null)
|
||||||
{
|
{
|
||||||
if (File.Exists(soPath))
|
if (File.Exists(soPath))
|
||||||
@ -629,11 +644,10 @@ private async Task<bool> InternalCreateGoogleSheetSoAsync()
|
|||||||
AssetDatabase.CreateAsset(soInstance, soPath);
|
AssetDatabase.CreateAsset(soInstance, soPath);
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
AssetDatabase.ImportAsset(soPath, ImportAssetOptions.ForceSynchronousImport);
|
AssetDatabase.ImportAsset(soPath, ImportAssetOptions.ForceSynchronousImport);
|
||||||
await Task.Delay(100); // meta 확정 시간 확보
|
await Task.Delay(100);
|
||||||
AssetDatabase.Refresh();
|
AssetDatabase.Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🧠 Sprite나 Enum 값을 반영한 List<T> 생성
|
|
||||||
IList list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(dataType));
|
IList list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(dataType));
|
||||||
var dataArray = (JArray)sheetPair.Value;
|
var dataArray = (JArray)sheetPair.Value;
|
||||||
|
|
||||||
@ -648,24 +662,33 @@ private async Task<bool> InternalCreateGoogleSheetSoAsync()
|
|||||||
string fieldName = rawName;
|
string fieldName = rawName;
|
||||||
string explicitType = null;
|
string explicitType = null;
|
||||||
|
|
||||||
if (rawName.Contains(":"))
|
if (rawName.Contains(":Enum"))
|
||||||
{
|
{
|
||||||
var split = rawName.Split(':');
|
fieldName = rawName.Split(':')[0];
|
||||||
fieldName = split[0];
|
|
||||||
explicitType = split[1].Replace("_Enum", "");
|
|
||||||
}
|
|
||||||
else if (rawName.EndsWith("_Enum"))
|
|
||||||
{
|
|
||||||
fieldName = rawName.Replace("_Enum", "");
|
|
||||||
explicitType = fieldName;
|
explicitType = fieldName;
|
||||||
}
|
}
|
||||||
|
else if (rawName.Contains(":") && rawName.EndsWith("_Enum"))
|
||||||
|
{
|
||||||
|
var parts = rawName.Split(':');
|
||||||
|
fieldName = parts[0];
|
||||||
|
explicitType = parts[1].Replace("_Enum", "");
|
||||||
|
}
|
||||||
|
else if (rawName.Contains(":"))
|
||||||
|
{
|
||||||
|
var parts = rawName.Split(':');
|
||||||
|
fieldName = parts[0];
|
||||||
|
explicitType = parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
FieldInfo field = dataType.GetField(fieldName,
|
FieldInfo field = dataType.GetField(fieldName,
|
||||||
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
|
||||||
if (field == null)
|
PropertyInfo property = dataType.GetProperty(fieldName,
|
||||||
|
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
if (field == null && property == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[GoogleSheetManager] 필드 누락: {dataType.Name}.{fieldName}");
|
Debug.LogWarning($"[GoogleSheetManager] 필드/프로퍼티 누락: {dataType.Name}.{fieldName}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,12 +696,12 @@ private async Task<bool> InternalCreateGoogleSheetSoAsync()
|
|||||||
{
|
{
|
||||||
object value;
|
object value;
|
||||||
|
|
||||||
// ✅ Sprite 처리 (주소로부터 비동기 로드)
|
// Sprite, Color 등 기존 로직 유지
|
||||||
if (explicitType == "Sprite" && field.FieldType == typeof(Sprite))
|
if (explicitType == "Sprite" && (field?.FieldType == typeof(Sprite) ||
|
||||||
|
property?.PropertyType == typeof(Sprite)))
|
||||||
{
|
{
|
||||||
string spriteKey = prop.Value.ToString().Trim();
|
string spriteKey = prop.Value.ToString().Trim();
|
||||||
if (string.IsNullOrEmpty(spriteKey))
|
if (string.IsNullOrEmpty(spriteKey)) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!AssetManager.HasLabel(spriteKey, "Sprite"))
|
if (!AssetManager.HasLabel(spriteKey, "Sprite"))
|
||||||
{
|
{
|
||||||
@ -696,68 +719,62 @@ private async Task<bool> InternalCreateGoogleSheetSoAsync()
|
|||||||
}
|
}
|
||||||
|
|
||||||
value = handle.Result;
|
value = handle.Result;
|
||||||
field.SetValue(dataInstance, value);
|
|
||||||
continue; // 이후 변환 스킵
|
|
||||||
}
|
}
|
||||||
|
else if ((field?.FieldType.IsEnum ?? false) || (property?.PropertyType.IsEnum ?? false))
|
||||||
// ✅ Enum 처리
|
|
||||||
if (field.FieldType.IsEnum)
|
|
||||||
{
|
{
|
||||||
|
Type enumType = field?.FieldType ?? property?.PropertyType;
|
||||||
string formatted = NormalizeEnumKey(prop.Value.ToString());
|
string formatted = NormalizeEnumKey(prop.Value.ToString());
|
||||||
value = Enum.TryParse(field.FieldType, formatted, out var parsed)
|
value = Enum.TryParse(enumType, formatted, out var parsed)
|
||||||
? parsed
|
? parsed
|
||||||
: Activator.CreateInstance(field.FieldType);
|
: Activator.CreateInstance(enumType);
|
||||||
}
|
}
|
||||||
// ✅ Color 처리
|
else if ((field?.FieldType == typeof(Color)) || (property?.PropertyType == typeof(Color)))
|
||||||
else if (field.FieldType == typeof(Color))
|
|
||||||
{
|
{
|
||||||
value = ColorUtility.TryParseHtmlString(prop.Value.ToString(), out var color)
|
value = ColorUtility.TryParseHtmlString(prop.Value.ToString(), out var color)
|
||||||
? color
|
? color
|
||||||
: Color.white;
|
: Color.white;
|
||||||
}
|
}
|
||||||
// ✅ 기본 타입 처리
|
else if ((field?.FieldType == typeof(string)) || (property?.PropertyType == typeof(string)))
|
||||||
|
{
|
||||||
|
value = prop.Value.ToString();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
value = Convert.ChangeType(prop.Value.ToString(), field.FieldType);
|
Type targetType = field?.FieldType ?? property?.PropertyType;
|
||||||
|
value = Convert.ChangeType(prop.Value.ToString(), targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
field.SetValue(dataInstance, value);
|
if (field != null)
|
||||||
|
field.SetValue(dataInstance, value);
|
||||||
|
else if (property != null && property.CanWrite)
|
||||||
|
property.SetValue(dataInstance, value);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.LogWarning(
|
Debug.LogWarning($"[GoogleSheetManager] 값 할당 실패: {fieldName} = {prop.Value} → {e.Message}");
|
||||||
$"[GoogleSheetManager] 값 할당 실패: {fieldName} = {prop.Value} ({field.FieldType}) → {e.Message}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list.Add(dataInstance);
|
list.Add(dataInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ 리스트 필드에 값 설정
|
// ✅ SetDataList() 호출
|
||||||
FieldInfo listField = soType.GetField($"{sheetName}List",
|
MethodInfo setMethod = soType.GetMethod("SetDataList",
|
||||||
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
if (setMethod != null)
|
||||||
if (listField != null)
|
|
||||||
{
|
{
|
||||||
object existingListObj = listField.GetValue(soInstance);
|
setMethod.Invoke(soInstance, new object[] { list });
|
||||||
if (existingListObj is IList existingList)
|
|
||||||
{
|
|
||||||
existingList.Clear(); // ✅ 기존 리스트를 완전히 비움
|
|
||||||
}
|
|
||||||
|
|
||||||
listField.SetValue(soInstance, list);
|
|
||||||
EditorUtility.SetDirty(soInstance);
|
EditorUtility.SetDirty(soInstance);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogError($"[GoogleSheetManager] {soType.Name}에 {sheetName}List 필드가 없습니다.");
|
Debug.LogError($"[GoogleSheetManager] {soType.Name}에 SetDataList 메서드가 없습니다.");
|
||||||
allSuccess = false;
|
allSuccess = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
AssetDatabase.Refresh();
|
AssetDatabase.Refresh();
|
||||||
|
|
||||||
// ✅ Addressables 등록은 마지막에, 유효한 경우만
|
|
||||||
if (AssetDatabase.LoadAssetAtPath<ScriptableObject>(soPath) != null)
|
if (AssetDatabase.LoadAssetAtPath<ScriptableObject>(soPath) != null)
|
||||||
{
|
{
|
||||||
GoogleSheetAddressableAutoSetup.AutoRegisterSo(soPath);
|
GoogleSheetAddressableAutoSetup.AutoRegisterSo(soPath);
|
||||||
@ -781,9 +798,17 @@ private Type FindTypeByName(string sheetName)
|
|||||||
|
|
||||||
private string NormalizeEnumKey(string input)
|
private string NormalizeEnumKey(string input)
|
||||||
{
|
{
|
||||||
string validName = System.Text.RegularExpressions.Regex.Replace(input, @"[^a-zA-Z0-9_]", "_");
|
if (string.IsNullOrEmpty(input))
|
||||||
|
return "None";
|
||||||
|
|
||||||
|
// 특수문자 및 공백을 밑줄(_)로 치환
|
||||||
|
string validName = System.Text.RegularExpressions.Regex.Replace(input, @"[^a-zA-Z0-9_]+", "_");
|
||||||
|
|
||||||
|
// 숫자로 시작하는 경우 밑줄 추가
|
||||||
if (char.IsDigit(validName[0]))
|
if (char.IsDigit(validName[0]))
|
||||||
validName = "_" + validName;
|
validName = "_" + validName;
|
||||||
|
|
||||||
|
// 첫 글자 대문자화
|
||||||
return char.ToUpper(validName[0]) + validName.Substring(1);
|
return char.ToUpper(validName[0]) + validName.Substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user