diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index e4ffec5..33273b5 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -51,12 +51,9 @@ - - - diff --git a/Assets/Editor.meta b/Assets/Editor.meta deleted file mode 100644 index 7afea97..0000000 --- a/Assets/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 208723e08bdfdc347bc1af53f4be5c3c -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Editor/DataImporter.meta b/Assets/Editor/DataImporter.meta deleted file mode 100644 index 3a49ee8..0000000 --- a/Assets/Editor/DataImporter.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 8f4724b7534e0a443a8eabbe6f5483ad -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Editor/DataImporter/CSVDebugger.cs b/Assets/Editor/DataImporter/CSVDebugger.cs deleted file mode 100644 index 4730533..0000000 --- a/Assets/Editor/DataImporter/CSVDebugger.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Assets/Editor/DataImporter/CSVDebugger.cs - -using UnityEngine; -using UnityEditor; -using System.IO; -using System.Text; - -namespace Northbound.Editor -{ - public static class CSVDebugger - { - [MenuItem("Northbound/Debug CSV Files")] - public static void DebugCSVFiles() - { - string gameDataPath = Path.Combine(Application.dataPath, "..", "GameData"); - var csvFiles = Directory.GetFiles(gameDataPath, "*.csv"); - - Debug.Log("=== CSV 파일 디버그 ===\n"); - - foreach (var csvPath in csvFiles) - { - string fileName = Path.GetFileName(csvPath); - - if (fileName.StartsWith(".")) - continue; - - Debug.Log($"📄 파일: {fileName}"); - - // 파일 크기 - FileInfo fileInfo = new FileInfo(csvPath); - Debug.Log($" 📊 크기: {fileInfo.Length} bytes"); - - // 인코딩 테스트 - try - { - // UTF-8로 읽기 - var lines = File.ReadAllLines(csvPath, Encoding.UTF8); - Debug.Log($" ✅ UTF-8 읽기 성공: {lines.Length}줄"); - - // ⭐ 모든 줄 출력 - for (int i = 0; i < lines.Length; i++) - { - string line = lines[i]; - Debug.Log($" 📋 [{i}] 길이:{line.Length} | 내용: '{line}'"); - - // 특수문자 확인 - if (string.IsNullOrWhiteSpace(line)) - { - Debug.Log($" ⚠️ 빈 줄 또는 공백만 있음"); - } - - // 바이트 출력 (첫 20바이트만) - byte[] bytes = Encoding.UTF8.GetBytes(line); - string byteStr = ""; - for (int j = 0; j < Mathf.Min(bytes.Length, 20); j++) - { - byteStr += $"{bytes[j]:X2} "; - } - if (bytes.Length > 20) byteStr += "..."; - Debug.Log($" 바이트: {byteStr}"); - } - - // BOM 체크 - byte[] fileBytes = File.ReadAllBytes(csvPath); - if (fileBytes.Length >= 3 && fileBytes[0] == 0xEF && fileBytes[1] == 0xBB && fileBytes[2] == 0xBF) - { - Debug.Log($" ℹ️ UTF-8 BOM 있음"); - } - else - { - Debug.Log($" ℹ️ BOM 없음"); - } - - // 전체 파일 바이트 (처음 100바이트만) - string fileBytesStr = ""; - for (int i = 0; i < Mathf.Min(fileBytes.Length, 100); i++) - { - fileBytesStr += $"{fileBytes[i]:X2} "; - if ((i + 1) % 20 == 0) fileBytesStr += "\n "; - } - Debug.Log($" 📦 파일 바이트 (처음 100):\n {fileBytesStr}"); - } - catch (System.Exception e) - { - Debug.LogError($" ❌ 읽기 실패: {e.Message}"); - } - - Debug.Log(""); - } - - Debug.Log("=== 디버그 완료 ==="); - } - } -} \ No newline at end of file diff --git a/Assets/Editor/DataImporter/CSVDebugger.cs.meta b/Assets/Editor/DataImporter/CSVDebugger.cs.meta deleted file mode 100644 index ec4952f..0000000 --- a/Assets/Editor/DataImporter/CSVDebugger.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 95247e4274c204446ac0f9c45c334c56 \ No newline at end of file diff --git a/Assets/Editor/DataImporter/CSVToSOImporter.cs b/Assets/Editor/DataImporter/CSVToSOImporter.cs deleted file mode 100644 index 8e354e8..0000000 --- a/Assets/Editor/DataImporter/CSVToSOImporter.cs +++ /dev/null @@ -1,320 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System; -using System.IO; -using System.Reflection; -using System.Collections; // 추가: 리스트 처리를 위해 필요 -using System.Collections.Generic; - -namespace Northbound.Editor -{ - public static class CSVToSOImporter - { - private static readonly string GAMEDATA_PATH = Path.Combine(Application.dataPath, "..", "GameData"); - private static readonly string SO_BASE_PATH = "Assets/Data/ScriptableObjects"; - private static readonly string PREFAB_BASE_PATH = "Assets/Prefabs"; - private static readonly string TEMPLATE_BASE_PATH = "Assets/Data/Templates"; - - private static System.Collections.Generic.Dictionary prefabSetups = - new System.Collections.Generic.Dictionary(); - - static CSVToSOImporter() - { - RegisterPrefabSetups(); - } - - private static void RegisterPrefabSetups() - { - prefabSetups.Clear(); - prefabSetups["Monster"] = new MonsterPrefabSetup(); - - // To add new data types, create a class implementing IPrefabSetup - // Example: - // prefabSetups["Tower"] = new TowerPrefabSetup(); - // prefabSetups["Player"] = new PlayerPrefabSetup(); - } - - [MenuItem("Tools/Data/Import All CSV")] // 메뉴 추가 (편의성) - public static void ImportAll() - { - Debug.Log("=== 전체 데이터 Import 시작 ==="); - if (!Directory.Exists(GAMEDATA_PATH)) { Debug.LogError("GameData 폴더가 없습니다."); return; } - - var csvFiles = Directory.GetFiles(GAMEDATA_PATH, "*.csv"); - int totalSuccess = 0; - int totalFail = 0; - - foreach (var csvPath in csvFiles) - { - if (csvPath.Contains("Backups")) continue; - string schemaName = Path.GetFileNameWithoutExtension(csvPath); - if (schemaName.StartsWith(".")) continue; - - if (ImportSchema(schemaName)) totalSuccess++; - else totalFail++; - } - - Debug.Log($"\n🎉 Import 완료: 성공 {totalSuccess}, 실패 {totalFail}"); - } - - public static bool ImportSchema(string schemaName) - { - string csvPath = Path.Combine(GAMEDATA_PATH, $"{schemaName}.csv"); - string outputPath = Path.Combine(SO_BASE_PATH, schemaName); - - if (!File.Exists(csvPath)) return false; - if (!Directory.Exists(outputPath)) Directory.CreateDirectory(outputPath); - - string className = schemaName + "Data"; - Type dataType = FindScriptableObjectType(className); - if (dataType == null) return false; - - try - { - var lines = File.ReadAllLines(csvPath, System.Text.Encoding.UTF8); - if (lines.Length < 2) return false; - - var headers = ParseCSVLine(lines[0]); - var createdSOs = new List(); - - for (int lineIndex = 1; lineIndex < lines.Length; lineIndex++) - { - string line = lines[lineIndex].Trim(); - if (string.IsNullOrEmpty(line)) continue; - - var values = ParseCSVLine(line); - var so = ScriptableObject.CreateInstance(dataType); - - for (int col = 0; col < headers.Length; col++) - { - if (col >= values.Length) break; - string fieldName = ToCamelCase(headers[col]); - FieldInfo field = dataType.GetField(fieldName, BindingFlags.Public | BindingFlags.Instance); - if (field != null) SetFieldValue(so, field, values[col]); - } - - string assetName = GetAssetName(so, lineIndex); - string soPath = Path.Combine(outputPath, $"{assetName}.asset"); - - AssetDatabase.CreateAsset(so, soPath); - createdSOs.Add(so); - - GenerateOrUpdatePrefab(schemaName, assetName, so, lineIndex); - } - - AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); - return true; - } - catch (Exception e) - { - Debug.LogError($"{schemaName} 오류: {e.Message}"); - return false; - } - } - - private static void SetFieldValue(object obj, FieldInfo field, string value) - { - Type fieldType = field.FieldType; - - // 1. 리스트 타입 처리 (List) - if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(List<>)) - { - Type elementType = fieldType.GetGenericArguments()[0]; - IList list = (IList)field.GetValue(obj); - if (list == null) - { - list = (IList)Activator.CreateInstance(fieldType); - field.SetValue(obj, list); - } - list.Clear(); - - if (!string.IsNullOrWhiteSpace(value)) - { - // 쉼표(,) 혹은 세미콜론(;)으로 분할 가능하게 설정 - string[] items = value.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); - foreach (var item in items) - { - object convertedItem = ConvertValue(item.Trim(), elementType); - if (convertedItem != null) list.Add(convertedItem); - } - } - return; - } - - if (string.IsNullOrWhiteSpace(value)) - { - field.SetValue(obj, null); - return; - } - - // 2. Nullable 처리 - if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - Type underlyingType = Nullable.GetUnderlyingType(fieldType); - field.SetValue(obj, ConvertValue(value, underlyingType)); - } - else - { - // 3. 일반 타입 처리 - field.SetValue(obj, ConvertValue(value, fieldType)); - } - } - - private static object ConvertValue(string value, Type targetType) - { - if (string.IsNullOrWhiteSpace(value)) return null; - - try - { - if (targetType == typeof(int)) return int.Parse(value); - if (targetType == typeof(float)) return float.Parse(value); - if (targetType == typeof(bool)) - { - string l = value.ToLower(); - return l == "true" || l == "1" || l == "yes"; - } - if (targetType == typeof(string)) return value.Replace("\\n", "\n"); - return Convert.ChangeType(value, targetType); - } - catch { return null; } - } - - private static int GetColumnIndex(string[] headers, string columnName) - { - for (int i = 0; i < headers.Length; i++) - { - if (headers[i].Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) - { - return i; - } - } - return -1; - } - - private static void GenerateOrUpdatePrefab(string schemaName, string prefabName, ScriptableObject so, int lineNumber) - { - string prefabOutputPath = Path.Combine(PREFAB_BASE_PATH, schemaName); - if (!Directory.Exists(prefabOutputPath)) - { - Directory.CreateDirectory(prefabOutputPath); - } - - string prefabPath = Path.Combine(prefabOutputPath, $"{prefabName}.prefab"); - IPrefabSetup prefabSetup = GetPrefabSetup(schemaName); - - if (prefabSetup == null) - { - Debug.LogWarning($"[CSVImporter] No prefab setup found for {schemaName}, skipping prefab generation"); - return; - } - - GameObject template = LoadTemplate(schemaName); - if (template == null) - { - Debug.LogWarning($"[CSVImporter] No template found for {schemaName}, skipping prefab generation"); - return; - } - - if (AssetDatabase.LoadAssetAtPath(prefabPath) != null) - { - UpdateExistingPrefab(prefabPath, so, prefabSetup); - } - else - { - GameObject prefabInstance = GameObject.Instantiate(template); - prefabInstance.name = prefabName; - PrefabUtility.SaveAsPrefabAsset(prefabInstance, prefabPath); - GameObject.DestroyImmediate(prefabInstance); - - UpdateExistingPrefab(prefabPath, so, prefabSetup); - - Debug.Log($"[CSVImporter] Created prefab: {prefabPath}"); - } - - AssetDatabase.SaveAssets(); - } - - private static GameObject LoadTemplate(string schemaName) - { - string templatePath = Path.Combine(TEMPLATE_BASE_PATH, $"{schemaName}Template.prefab"); - return AssetDatabase.LoadAssetAtPath(templatePath); - } - - private static IPrefabSetup GetPrefabSetup(string schemaName) - { - prefabSetups.TryGetValue(schemaName, out IPrefabSetup setup); - return setup; - } - - private static void UpdateExistingPrefab(string prefabPath, ScriptableObject so, IPrefabSetup prefabSetup) - { - GameObject prefabContents = PrefabUtility.LoadPrefabContents(prefabPath); - - prefabSetup.SetupPrefab(prefabContents, so); - - PrefabUtility.SaveAsPrefabAsset(prefabContents, prefabPath); - GameObject.DestroyImmediate(prefabContents); - } - - private static void RemoveOldModel(GameObject prefab) - { - Transform oldModel = prefab.transform.Find("Model"); - if (oldModel != null) - { - GameObject.DestroyImmediate(oldModel.gameObject); - } - } - - // --- 유틸리티 메서드 (기존과 동일) --- - private static string[] ParseCSVLine(string line) - { - var result = new List(); - bool inQuotes = false; - string current = ""; - for (int i = 0; i < line.Length; i++) - { - char c = line[i]; - if (c == '"') inQuotes = !inQuotes; - else if (c == ',' && !inQuotes) { result.Add(current.Trim()); current = ""; } - else current += c; - } - result.Add(current.Trim()); - return result.ToArray(); - } - - private static Type FindScriptableObjectType(string className) - { - string fullName = $"Northbound.Data.{className}"; - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - Type type = assembly.GetType(fullName); - if (type != null && type.IsSubclassOf(typeof(ScriptableObject))) return type; - } - return null; - } - - private static string ToCamelCase(string snakeCase) - { - if (string.IsNullOrEmpty(snakeCase)) return snakeCase; - var parts = snakeCase.Split('_'); - if (parts.Length == 1) return snakeCase; - string result = parts[0]; - for (int i = 1; i < parts.Length; i++) - if (parts[i].Length > 0) result += char.ToUpper(parts[i][0]) + parts[i].Substring(1); - return result; - } - - private static string GetAssetName(object so, int lineNumber) - { - Type type = so.GetType(); - FieldInfo idField = type.GetField("id", BindingFlags.Public | BindingFlags.Instance); - if (idField != null) - { - var val = idField.GetValue(so); - if (val != null) return $"{type.Name.Replace("Data", "")}{val:D3}"; - } - return $"Data_Row{lineNumber}"; - } - } -} \ No newline at end of file diff --git a/Assets/Editor/DataImporter/CSVToSOImporter.cs.meta b/Assets/Editor/DataImporter/CSVToSOImporter.cs.meta deleted file mode 100644 index 8d6a1a9..0000000 --- a/Assets/Editor/DataImporter/CSVToSOImporter.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 79f372743463a5e4cb3a9b915de9bebe \ No newline at end of file diff --git a/Assets/Editor/DataImporter/ImporterWindow.cs b/Assets/Editor/DataImporter/ImporterWindow.cs deleted file mode 100644 index e77a651..0000000 --- a/Assets/Editor/DataImporter/ImporterWindow.cs +++ /dev/null @@ -1,122 +0,0 @@ -// Assets/Editor/DataImporter/ImporterWindow.cs - -using UnityEngine; -using UnityEditor; -using System.IO; -using System.Linq; - -namespace Northbound.Editor -{ - public class ImporterWindow : EditorWindow - { - private Vector2 scrollPosition; - - [MenuItem("Northbound/Data Importer")] - public static void ShowWindow() - { - var window = GetWindow("Data Importer"); - window.minSize = new Vector2(400, 300); - } - - private void OnGUI() - { - GUILayout.Label("CSV → ScriptableObject Importer", EditorStyles.boldLabel); - GUILayout.Space(10); - - EditorGUILayout.HelpBox( - "GameData 폴더의 CSV 파일을 ScriptableObject로 변환합니다.\n" + - "자동 생성된 C# 클래스를 사용합니다.", - MessageType.Info - ); - - GUILayout.Space(10); - - scrollPosition = GUILayout.BeginScrollView(scrollPosition); - - string gameDataPath = Path.Combine(Application.dataPath, "..", "GameData"); - - if (!Directory.Exists(gameDataPath)) - { - EditorGUILayout.HelpBox( - "GameData 폴더를 찾을 수 없습니다.", - MessageType.Warning - ); - } - else - { - var csvFiles = Directory.GetFiles(gameDataPath, "*.csv") - .Where(f => !f.Contains("Backups") && !Path.GetFileName(f).StartsWith(".")) - .ToArray(); - - if (csvFiles.Length == 0) - { - EditorGUILayout.HelpBox( - "CSV 파일이 없습니다.\n" + - "sync-from-notion.ps1을 먼저 실행하세요.", - MessageType.Warning - ); - } - else - { - GUILayout.Label("발견된 CSV 파일:", EditorStyles.boldLabel); - GUILayout.Space(5); - - foreach (var filePath in csvFiles) - { - string fileName = Path.GetFileNameWithoutExtension(filePath); - - GUILayout.BeginHorizontal(); - - GUILayout.Label($"📊 {fileName}", GUILayout.Width(200)); - - if (GUILayout.Button("Import", GUILayout.Width(100))) - { - ImportSingle(fileName); - } - - GUILayout.EndHorizontal(); - } - } - } - - GUILayout.EndScrollView(); - - GUILayout.Space(20); - - GUI.backgroundColor = Color.green; - if (GUILayout.Button("Import All Data", GUILayout.Height(50))) - { - if (EditorUtility.DisplayDialog( - "전체 데이터 Import", - "모든 CSV 파일을 읽어서 ScriptableObject를 생성합니다.\n" + - "기존 파일은 덮어씌워집니다.", - "Import All", - "Cancel")) - { - CSVToSOImporter.ImportAll(); - } - } - GUI.backgroundColor = Color.white; - - GUILayout.Space(10); - - EditorGUILayout.HelpBox( - "Import 후 Assets/Data/ScriptableObjects 폴더를 확인하세요.", - MessageType.None - ); - } - - private void ImportSingle(string schemaName) - { - if (EditorUtility.DisplayDialog( - $"{schemaName} Import", - $"{schemaName}.csv를 읽어서 ScriptableObject를 생성합니다.\n" + - "기존 파일은 덮어씌워집니다.", - "Import", - "Cancel")) - { - CSVToSOImporter.ImportSchema(schemaName); - } - } - } -} \ No newline at end of file diff --git a/Assets/Editor/DataImporter/ImporterWindow.cs.meta b/Assets/Editor/DataImporter/ImporterWindow.cs.meta deleted file mode 100644 index 5fc7a11..0000000 --- a/Assets/Editor/DataImporter/ImporterWindow.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 017c665c9c855fa43b55f1d61c238903 \ No newline at end of file