diff --git a/Assets/1_Script/System/CSVLoader.cs b/Assets/1_Script/System/CSVLoader.cs new file mode 100644 index 0000000..5ee3138 --- /dev/null +++ b/Assets/1_Script/System/CSVLoader.cs @@ -0,0 +1,118 @@ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; +using UnityEngine.Networking; +/// +/// CSV 데이터를 다양한 소스에서 Pull 방식으로 로드할 수 있는 클래스입니다. +/// 호출 측에서 MoveNext()를 통해 처리 타이밍을 제어하세요. +/// +public static class CSVLoader +{ + /// CSV 파싱 로직 정의 + public interface IParser + { + T Parse(string[] columns); + } + + /// 로딩 진행 상태 메타데이터 + public struct Progress + { + public int TotalRows; + public int RowsLoaded; + } + + /// URL(HTTP)로부터 다운로드하여 파싱 + public static IEnumerator Download(string url, + IParser parser, + List outList) + { + using var uwr = UnityWebRequest.Get(url); + var operation = uwr.SendWebRequest(); + // 요청이 완료될 때까지 대기 (Progress 타입 반환은 요청 상태 표시용) + while (!operation.isDone) + { + yield return new Progress { TotalRows = 0, RowsLoaded = 0 }; + } + + if (uwr.result != UnityWebRequest.Result.Success) + { + Logger.LogError($"CSVLoader: Download failed '{url}': {uwr.error}"); + yield break; + } + + string text = uwr.downloadHandler.text; + foreach (var prog in ProcessText(text, parser, outList)) + yield return prog; + } + + /// 절대 경로의 파일을 읽어 파싱 + public static IEnumerator LoadFromFile(string filePath, + IParser parser, + List outList) + { + if (!File.Exists(filePath)) + { + Logger.LogError($"CSVLoader: File not found '{filePath}'"); + yield break; + } + string text = File.ReadAllText(filePath); + foreach (var prog in ProcessText(text, parser, outList)) + yield return prog; + } + + /// StreamingAssets 내 상대 경로 또는 URL로부터 로드 + public static IEnumerator LoadFromStreamingAssets(string relativePath, + IParser parser, + List outList) + { + string fullPath = Path.Combine(Application.streamingAssetsPath, relativePath); + if (fullPath.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + var downloadEnum = Download(fullPath, parser, outList); + while (downloadEnum.MoveNext()) + yield return downloadEnum.Current; + } + else + { + var fileEnum = LoadFromFile(fullPath, parser, outList); + while (fileEnum.MoveNext()) + yield return fileEnum.Current; + } + } + + /// Resources 폴더 내 TextAsset로부터 로드 + public static IEnumerator LoadFromResources(string resourcePath, + IParser parser, + List outList) + { + var ta = Resources.Load(resourcePath); + if (ta == null) + { + Logger.LogError($"CSVLoader: Resource not found '{resourcePath}'"); + yield break; + } + string text = ta.text; + foreach (var prog in ProcessText(text, parser, outList)) + yield return prog; + } + + /// 텍스트를 실제 파싱하여 Progress를 반환하는 내부 모듈 + static IEnumerable ProcessText(string text, + IParser parser, + List outList) + { + var lines = text.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + int total = lines.Length; + // 첫 번째 줄은 헤더이므로 무시 + // 두 번째 줄은 설명이므로 무시 + for (int i = 2; i < total; i++) + { + var cols = lines[i].TrimEnd('\r').Split(','); + outList.Add(parser.Parse(cols)); + yield return new Progress { TotalRows = total, RowsLoaded = i + 1 }; + } + } +} \ No newline at end of file diff --git a/Assets/1_Script/System/CSVLoader.cs.meta b/Assets/1_Script/System/CSVLoader.cs.meta new file mode 100644 index 0000000..36638a1 --- /dev/null +++ b/Assets/1_Script/System/CSVLoader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b37f2c717edfd748bf3173c734fee71 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: