ProjectDDD/Assets/_Datas/SLShared/SLSystem/SLEntitySpace/Loader/YamlLoader.cs
2025-06-17 20:47:57 +09:00

207 lines
7.2 KiB (Stored with Git LFS)
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Superlazy.Loader
{
public static class YamlLoader
{
public static SLEntity LoadYaml(string yamlString)
{
var root = SLEntity.Empty;
LoadYaml(root, yamlString);
return root;
}
public static void LoadYaml(SLEntity root, string yamlString)
{
var currentEntity = root;
var stack = new Stack<Tuple<SLEntity, int>>();
using var reader = new StringReader(yamlString);
string line;
while ((line = reader.ReadLine()) != null)
{
var lineBegin = 0;
while (lineBegin < line.Length && line[lineBegin] == ' ') lineBegin++;
if (line.Length <= lineBegin) continue;
var separatorIndex = line.IndexOf(':');
string key;
var isArray = false;
if (separatorIndex == -1)
{
if (line[lineBegin] == '#')
{
continue;
}
else if (line[lineBegin] == '-')
{
isArray = true;// 배열 전용 처리
key = null;
separatorIndex = lineBegin;
}
else
{
continue;
}
}
else
{
var commentIndex = line.IndexOf('#');
if (commentIndex >= 0 && commentIndex <= separatorIndex) // 키에는 주석을 넣을수 없기 때문에 구분자 이전은 주석
{
continue; // 전체 주석
}
else
{
key = line.Substring(lineBegin, separatorIndex - lineBegin);
}
}
var valueBegin = separatorIndex + 2;
var valueEnd = line.Length;
if (valueBegin + 1 < valueEnd)
{
var commentIndex = line.IndexOf('#', valueBegin, valueEnd - valueBegin);
// TODO: 문자열 내의 #은 인식 못하도록 현재가 문자열 내부인지 체크가 필요
if (commentIndex >= 0 && (commentIndex == 0 || line[commentIndex - 1] == ' ')) // 빈칸이 하나 있어야 주석임
{
valueEnd = commentIndex - 1;
}
while (valueEnd > valueBegin && line[valueBegin] == ' ')
{
valueBegin++;
}
while (valueEnd >= valueBegin && line[valueEnd - 1] == ' ')
{
valueEnd--;
}
}
while (stack.Count > 0 && lineBegin <= stack.Peek().Item2)
{
currentEntity.EndModified();
currentEntity = stack.Pop().Item1;
}
if (isArray)
{
key = (currentEntity.Count() + 1).ToString();
}
if (valueBegin >= valueEnd)
{
stack.Push(new Tuple<SLEntity, int>(currentEntity, lineBegin));
currentEntity = currentEntity[key];
}
else
{
var forceString = false;
if (line[valueBegin] == '"' && line[valueEnd - 1] == '"' || line[valueBegin] == '\'' && line[valueEnd - 1] == '\'')
{
valueBegin += 1;
valueEnd -= 1;
forceString = true;
}
var value = line.Substring(valueBegin, valueEnd - valueBegin);
if (forceString)
{
currentEntity[key] = value;
}
else if (int.TryParse(value, out var intValue))
{
currentEntity[key] = intValue;
}
else if (double.TryParse(value, out var doubleValue))
{
currentEntity[key] = doubleValue;
}
else
{
currentEntity[key] = value;
}
}
}
while (stack.Count > 0)
{
currentEntity.EndModified();
currentEntity = stack.Pop().Item1;
}
}
public static string SaveToYaml(SLEntity entity, int indentation = 0, bool useArray = false)
{
var yamlString = new StringBuilder();
var index = 1;
IEnumerable<SLEntity> childs = entity;
if (useArray && entity.All(x => int.TryParse(x.ID, out _)))
{
childs = entity.OrderBy(x => int.Parse(x.ID));
}
else // 전부 int로 파싱 못하면, 배열로 처리하지 않음
{
useArray = false;
}
foreach (var child in childs)
{
var key = child.ID;
var value = child;
if (useArray && index > 0 && key == index.ToString())
{
key = "-";
++index;
yamlString.Append(' ', indentation).Append(key);
}
else
{
index = -1;
yamlString.Append(' ', indentation).Append(key).Append(':');
}
if (value.IsValue)
{
var valueString = value.ToString();
var needsQuotes =
value.IsNumeric == false && (int.TryParse(valueString, out _) || double.TryParse(valueString, out _)) // 숫자인데 강제로 문자화 한거거나
|| valueString.Contains('#') || valueString.StartsWith('[') || valueString.StartsWith('{') // 특수문자가 포함되어 있거나, 배열이나 객체로 시작하는 경우 {Value}
|| valueString.Contains(':') // "남은 시간: {Value}" 꼴
|| (value.IsNumeric == false && valueString.StartsWith('-')); // "- 어쩌고" 꼴, 배열인것으로 이해
yamlString.Append(' ');
if (needsQuotes)
{
yamlString.Append('"').Append(valueString.Replace("\"", "\\\"")).Append('"');
}
else
{
yamlString.Append(valueString);
}
yamlString.Append(Environment.NewLine);
}
else
{
yamlString.Append(Environment.NewLine).Append(SaveToYaml(value, indentation + 2, useArray));
}
}
return yamlString.ToString();
}
}
}