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