구형 CSVImporter 제거
This commit is contained in:
@@ -51,12 +51,9 @@
|
|||||||
<Compile Include="Assets\Scripts\Editor\MonsterPrefabSetup.cs" />
|
<Compile Include="Assets\Scripts\Editor\MonsterPrefabSetup.cs" />
|
||||||
<Compile Include="Assets\FlatKit\[Render Pipeline] URP\Water\Editor\Tooltips.cs" />
|
<Compile Include="Assets\FlatKit\[Render Pipeline] URP\Water\Editor\Tooltips.cs" />
|
||||||
<Compile Include="Assets\Scripts\Editor\EnemyPortalEditor.cs" />
|
<Compile Include="Assets\Scripts\Editor\EnemyPortalEditor.cs" />
|
||||||
<Compile Include="Assets\Editor\DataImporter\ImporterWindow.cs" />
|
|
||||||
<Compile Include="Assets\Scripts\Editor\ObstacleSpawnerEditor.cs" />
|
<Compile Include="Assets\Scripts\Editor\ObstacleSpawnerEditor.cs" />
|
||||||
<Compile Include="Assets\Editor\DataImporter\CSVDebugger.cs" />
|
|
||||||
<Compile Include="Assets\Scripts\Editor\IPrefabSetup.cs" />
|
<Compile Include="Assets\Scripts\Editor\IPrefabSetup.cs" />
|
||||||
<Compile Include="Assets\FlatKit\[Render Pipeline] URP\Water\Editor\WaterEditor.cs" />
|
<Compile Include="Assets\FlatKit\[Render Pipeline] URP\Water\Editor\WaterEditor.cs" />
|
||||||
<Compile Include="Assets\Editor\DataImporter\CSVToSOImporter.cs" />
|
|
||||||
<Compile Include="Assets\FlatKit\Shaders\Editor\ObjectOutlineEditorUtils.cs" />
|
<Compile Include="Assets\FlatKit\Shaders\Editor\ObjectOutlineEditorUtils.cs" />
|
||||||
<Compile Include="Assets\FlatKit\Demos\Common\Scripts\Motion\Editor\LinearMotionEditor.cs" />
|
<Compile Include="Assets\FlatKit\Demos\Common\Scripts\Motion\Editor\LinearMotionEditor.cs" />
|
||||||
<Compile Include="Assets\FlatKit\Shaders\GradientSkybox\Editor\GradientSkyboxEditor.cs" />
|
<Compile Include="Assets\FlatKit\Shaders\GradientSkybox\Editor\GradientSkyboxEditor.cs" />
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 208723e08bdfdc347bc1af53f4be5c3c
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 8f4724b7534e0a443a8eabbe6f5483ad
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -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("=== 디버그 완료 ===");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 95247e4274c204446ac0f9c45c334c56
|
|
||||||
@@ -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<string, IPrefabSetup> prefabSetups =
|
|
||||||
new System.Collections.Generic.Dictionary<string, IPrefabSetup>();
|
|
||||||
|
|
||||||
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<ScriptableObject>();
|
|
||||||
|
|
||||||
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<T>)
|
|
||||||
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<GameObject>(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<GameObject>(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<string>();
|
|
||||||
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}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 79f372743463a5e4cb3a9b915de9bebe
|
|
||||||
@@ -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<ImporterWindow>("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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 017c665c9c855fa43b55f1d61c238903
|
|
||||||
Reference in New Issue
Block a user