118 lines
4.0 KiB
C#
118 lines
4.0 KiB
C#
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
using UnityEngine.Networking;
|
|
/// <summary>
|
|
/// CSV 데이터를 다양한 소스에서 Pull 방식으로 로드할 수 있는 클래스입니다.
|
|
/// 호출 측에서 MoveNext()를 통해 처리 타이밍을 제어하세요.
|
|
/// </summary>
|
|
public static class CSVLoader
|
|
{
|
|
/// <summary>CSV 파싱 로직 정의</summary>
|
|
public interface IParser<T>
|
|
{
|
|
T Parse(string[] columns);
|
|
}
|
|
|
|
/// <summary>로딩 진행 상태 메타데이터</summary>
|
|
public struct Progress
|
|
{
|
|
public int TotalRows;
|
|
public int RowsLoaded;
|
|
}
|
|
|
|
/// <summary>URL(HTTP)로부터 다운로드하여 파싱</summary>
|
|
public static IEnumerator<Progress> Download<T>(string url,
|
|
IParser<T> parser,
|
|
List<T> 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;
|
|
}
|
|
|
|
/// <summary>절대 경로의 파일을 읽어 파싱</summary>
|
|
public static IEnumerator<Progress> LoadFromFile<T>(string filePath,
|
|
IParser<T> parser,
|
|
List<T> 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;
|
|
}
|
|
|
|
/// <summary>StreamingAssets 내 상대 경로 또는 URL로부터 로드</summary>
|
|
public static IEnumerator<Progress> LoadFromStreamingAssets<T>(string relativePath,
|
|
IParser<T> parser,
|
|
List<T> 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;
|
|
}
|
|
}
|
|
|
|
/// <summary>Resources 폴더 내 TextAsset로부터 로드</summary>
|
|
public static IEnumerator<Progress> LoadFromResources<T>(string resourcePath,
|
|
IParser<T> parser,
|
|
List<T> outList)
|
|
{
|
|
var ta = Resources.Load<TextAsset>(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;
|
|
}
|
|
|
|
/// <summary>텍스트를 실제 파싱하여 Progress를 반환하는 내부 모듈</summary>
|
|
static IEnumerable<Progress> ProcessText<T>(string text,
|
|
IParser<T> parser,
|
|
List<T> 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 };
|
|
}
|
|
}
|
|
} |