using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
public class CSV_Data_Paser : EditorWindow
{
private string csvFilePath = "";
private string outputFolder = "Assets/ScriptableObjects";
[MenuItem("Tools/CSV to ScriptableObject Converter %J")]
public static void ShowWindow()
{
GetWindow<CSV_Data_Paser>("CSV Converter");
}
private void OnGUI()
{
GUILayout.Label("CSV to ScriptableObject Converter", EditorStyles.boldLabel);
csvFilePath = EditorGUILayout.TextField("CSV File Path", csvFilePath);
if (GUILayout.Button("Select CSV File"))
{
csvFilePath = EditorUtility.OpenFilePanel("Select CSV File", "", "csv");
}
outputFolder = EditorGUILayout.TextField("Output Folder", outputFolder);
if (GUILayout.Button("Select Output Folder"))
{
outputFolder = EditorUtility.SaveFolderPanel("Select Output Folder", "Assets", "");
outputFolder = outputFolder.Replace(Application.dataPath, "Assets");
}
if (GUILayout.Button("Convert CSV to ScriptableObject"))
{
ConvertCSVToScriptableObject();
}
}
private void ConvertCSVToScriptableObject()
{
if (string.IsNullOrEmpty(csvFilePath) || !File.Exists(csvFilePath))
{
Debug.LogError("Invalid CSV file path.");
return;
}
string[] lines = File.ReadAllLines(csvFilePath);
if (lines.Length < 2)
{
Debug.LogError("CSV file is empty or has no data rows.");
return;
}
string[] headers = lines[0].Split(',');
for (int i = 1; i < lines.Length; i++)
{
string[] values = lines[i].Split(',');
if (values.Length != headers.Length)
{
Debug.LogWarning($"Skipping row {i} due to mismatched column count.");
continue;
}
CSVData data = ScriptableObject.CreateInstance<CSVData>();
data.PopulateData(headers, values);
string assetPath = $"{outputFolder}/CSVData_{i}.asset";
AssetDatabase.CreateAsset(data, assetPath);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log("CSV conversion completed.");
}
}
public class CSVData : ScriptableObject
{
public string[] headers;
public string[] values;
public void PopulateData(string[] headers, string[] values)
{
this.headers = headers;
this.values = values;
}
}
% : ctrl
# : shift
복수의 데이터를 저장하는 방식으로 위의 방식은 너무 많은 스크립터블오브젝트를 생성한다. 따라서 아래와 같이 변경
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
public class CSV_Data_Paser : EditorWindow
{
private string csvFilePath = "";
private string outputFolder = "Assets/ScriptableObjects";
private string fileName = "CSVDataContainer";
[MenuItem("Tools/CSV to ScriptableObject Converter %#C")] // Ctrl+Shift+C (Windows) or Cmd+Shift+C (Mac)
public static void ShowWindow()
{
GetWindow<CSV_Data_Paser>("CSV Converter");
}
private void OnGUI()
{
GUILayout.Label("CSV to ScriptableObject Converter", EditorStyles.boldLabel);
csvFilePath = EditorGUILayout.TextField("CSV File Path", csvFilePath);
if (GUILayout.Button("Select CSV File"))
{
csvFilePath = EditorUtility.OpenFilePanel("Select CSV File", "", "csv");
}
outputFolder = EditorGUILayout.TextField("Output Folder", outputFolder);
if (GUILayout.Button("Select Output Folder"))
{
outputFolder = EditorUtility.SaveFolderPanel("Select Output Folder", "Assets", "");
outputFolder = outputFolder.Replace(Application.dataPath, "Assets");
}
fileName = EditorGUILayout.TextField("File Name", fileName);
if (GUILayout.Button("Convert CSV to ScriptableObject"))
{
ConvertCSVToScriptableObject();
}
}
private void ConvertCSVToScriptableObject()
{
if (string.IsNullOrEmpty(csvFilePath) || !File.Exists(csvFilePath))
{
Debug.LogError("Invalid CSV file path.");
return;
}
string[] lines = File.ReadAllLines(csvFilePath);
if (lines.Length < 2)
{
Debug.LogError("CSV file is empty or has no data rows.");
return;
}
CSVDataContainer container = ScriptableObject.CreateInstance<CSVDataContainer>();
container.headers = lines[0].Split(',');
container.dataRows = new List<CSVDataRow>();
for (int i = 1; i < lines.Length; i++)
{
string[] values = lines[i].Split(',');
if (values.Length != container.headers.Length)
{
Debug.LogWarning($"Skipping row {i} due to mismatched column count.");
continue;
}
CSVDataRow row = new CSVDataRow();
row.values = values;
container.dataRows.Add(row);
}
string assetPath = $"{outputFolder}/{fileName}.asset";
AssetDatabase.CreateAsset(container, assetPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log($"CSV conversion completed. ScriptableObject saved at {assetPath}");
}
}
[System.Serializable]
public class CSVDataRow
{
public string[] values;
}
public class CSVDataContainer : ScriptableObject
{
public string[] headers;
public List<CSVDataRow> dataRows;
public string GetValue(int rowIndex, string headerName)
{
if (rowIndex < 0 || rowIndex >= dataRows.Count)
{
Debug.LogError($"Row index {rowIndex} is out of range.");
return null;
}
int columnIndex = System.Array.IndexOf(headers, headerName);
if (columnIndex == -1)
{
Debug.LogError($"Header '{headerName}' not found.");
return null;
}
return dataRows[rowIndex].values[columnIndex];
}
}
에셋이 변경되면 자동으로 스크립터블 오브젝트를 생성해주는 기능
유니티의 에셋포스트프로세서 기능을 이용.
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections.Generic;
public class CSVToScriptableObjectConverter : AssetPostprocessor
{
private static readonly string csvFolderPath = "Assets/CSV";
private static readonly string outputFolderPath = "Assets/ScriptableObjects";
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
Debug.Log("CSV files converted");
foreach (string assetPath in importedAssets)
{
if (Path.GetExtension(assetPath).ToLower() == ".csv" && assetPath.StartsWith(csvFolderPath))
{
ConvertCSVToScriptableObject(assetPath);
}
}
}
private static void ConvertCSVToScriptableObject(string csvPath)
{
string fileName = Path.GetFileNameWithoutExtension(csvPath);
string outputPath = $"{outputFolderPath}/{fileName}.asset";
if (!Directory.Exists(outputFolderPath))
{
Directory.CreateDirectory(outputFolderPath);
}
CSVDataContainer2 container = AssetDatabase.LoadAssetAtPath<CSVDataContainer2>(outputPath);
if (container == null)
{
container = ScriptableObject.CreateInstance<CSVDataContainer2>();
AssetDatabase.CreateAsset(container, outputPath);
}
string[] lines = File.ReadAllLines(csvPath);
if (lines.Length < 2)
{
Debug.LogError($"CSV file {csvPath} is empty or has no data rows.");
return;
}
container.headers = lines[0].Split(',');
container.dataRows = new List<CSVDataRow2>();
for (int i = 1; i < lines.Length; i++)
{
string[] values = lines[i].Split(',');
if (values.Length != container.headers.Length)
{
Debug.LogWarning($"Skipping row {i} in {csvPath} due to mismatched column count.");
continue;
}
CSVDataRow2 row = new CSVDataRow2();
row.values = values;
container.dataRows.Add(row);
}
EditorUtility.SetDirty(container);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log($"CSV conversion completed for {csvPath}. ScriptableObject saved at {outputPath}");
}
}
[System.Serializable]
public class CSVDataRow2
{
public string[] values;
}
public class CSVDataContainer2 : ScriptableObject
{
public string[] headers;
public List<CSVDataRow2> dataRows;
public string GetValue(int rowIndex, string headerName)
{
if (rowIndex < 0 || rowIndex >= dataRows.Count)
{
Debug.LogError($"Row index {rowIndex} is out of range.");
return null;
}
int columnIndex = System.Array.IndexOf(headers, headerName);
if (columnIndex == -1)
{
Debug.LogError($"Header '{headerName}' not found.");
return null;
}
return dataRows[rowIndex].values[columnIndex];
}
}
명시적인 구조체로 만들어주기
using System;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections.Generic;
public class CSVToScriptableObjectConverter : AssetPostprocessor
{
private static readonly string csvFolderPath = "Assets/CSV";
private static readonly string outputFolderPath = "Assets/ScriptableObjects";
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
Debug.Log("CSV files converted");
foreach (string assetPath in importedAssets)
{
if (Path.GetExtension(assetPath).ToLower() == ".csv" && assetPath.StartsWith(csvFolderPath))
{
ConvertCSVToScriptableObject(assetPath);
}
}
}
private static void ConvertCSVToScriptableObject(string csvPath)
{
string fileName = Path.GetFileNameWithoutExtension(csvPath);
string outputPath = $"{outputFolderPath}/{fileName}.asset";
if (!Directory.Exists(outputFolderPath))
{
Directory.CreateDirectory(outputFolderPath);
}
CSVDataContainer2 container = AssetDatabase.LoadAssetAtPath<CSVDataContainer2>(outputPath);
if (container == null)
{
container = ScriptableObject.CreateInstance<CSVDataContainer2>();
AssetDatabase.CreateAsset(container, outputPath);
}
string[] lines = File.ReadAllLines(csvPath);
if (lines.Length < 2)
{
Debug.LogError($"CSV file {csvPath} is empty or has no data rows.");
return;
}
container.headers = lines[0].Split(',');
container.dataRows = new List<CSVDataRow2>();
for (int i = 1; i < lines.Length; i++)
{
string[] values = lines[i].Split(',');
if (values.Length != container.headers.Length)
{
Debug.LogWarning($"Skipping row {i} in {csvPath} due to mismatched column count.");
continue;
}
CSVDataRow2 row = new CSVDataRow2();
row.index = Int32.Parse(values[0]);
row.hp = Int32.Parse(values[1]);
row.mp = Int32.Parse(values[2]);
row.attackPower = Int32.Parse(values[3]);
container.dataRows.Add(row);
}
EditorUtility.SetDirty(container);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log($"CSV conversion completed for {csvPath}. ScriptableObject saved at {outputPath}");
}
}
[System.Serializable]
public class CSVDataRow2
{
public int index;
public int hp;
public int mp;
public int attackPower;
}
public class CSVDataContainer2 : ScriptableObject
{
public string[] headers;
public List<CSVDataRow2> dataRows;
}