148 lines
4.7 KiB
C#
148 lines
4.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
|
|
namespace BrewMonster.Scripts.Chat.EmotionData
|
|
{
|
|
/// <summary>
|
|
/// Parser token giống thứ tự đọc trong AUIManager.cpp (Emotions{N}.txt).
|
|
/// Token order matches AUIManager.cpp when loading Emotions{N}.txt.
|
|
/// </summary>
|
|
public static class EmotionTxtParser
|
|
{
|
|
public const int MaxFrames = 20; // AUITEXTAREA_EMOTHION_MAXFRAME
|
|
|
|
public readonly struct ParseResult
|
|
{
|
|
public readonly List<EmotionEntryData> Entries;
|
|
public readonly string ErrorMessage;
|
|
|
|
public bool Success => string.IsNullOrEmpty(ErrorMessage);
|
|
|
|
public ParseResult(List<EmotionEntryData> entries, string error)
|
|
{
|
|
Entries = entries;
|
|
ErrorMessage = error ?? "";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Đọc toàn bộ nội dung file txt; token tách bằng whitespace (giống GetNextToken cơ bản).
|
|
/// Reads full txt; tokens split by whitespace (basic GetNextToken behavior).
|
|
/// </summary>
|
|
public static ParseResult Parse(string text)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(text))
|
|
return new ParseResult(new List<EmotionEntryData>(), "Empty text.");
|
|
|
|
var tokens = Tokenize(text);
|
|
var entries = new List<EmotionEntryData>();
|
|
int t = 0;
|
|
|
|
while (t < tokens.Count)
|
|
{
|
|
if (!TryParseInt(tokens[t], out int startPos))
|
|
return new ParseResult(null, $"Invalid nStartPos at token index {t}: '{tokens[t]}'");
|
|
|
|
t++;
|
|
if (t >= tokens.Count)
|
|
return new ParseResult(null, "Unexpected EOF after nStartPos.");
|
|
|
|
if (!TryParseInt(tokens[t], out int numFramesRaw))
|
|
return new ParseResult(null, $"Invalid nNumFrames at token index {t}.");
|
|
|
|
int numFrames = Math.Min(Math.Max(0, numFramesRaw), MaxFrames);
|
|
t++;
|
|
|
|
if (t >= tokens.Count)
|
|
return new ParseResult(null, "Unexpected EOF after nNumFrames (missing hint).");
|
|
|
|
string hint = tokens[t];
|
|
t++;
|
|
|
|
var frameTicks = new int[numFrames];
|
|
for (int i = 0; i < numFrames; i++)
|
|
{
|
|
if (t >= tokens.Count)
|
|
return new ParseResult(null,
|
|
$"Unexpected EOF: need {numFrames} frame tick values for entry starting at StartPos={startPos}.");
|
|
|
|
if (!TryParseInt(tokens[t], out frameTicks[i]))
|
|
return new ParseResult(null, $"Invalid nFrameTick[{i}] at token index {t}.");
|
|
|
|
t++;
|
|
}
|
|
|
|
entries.Add(new EmotionEntryData
|
|
{
|
|
StartPos = startPos,
|
|
NumFrames = numFrames,
|
|
Hint = hint,
|
|
FrameTicks = frameTicks
|
|
});
|
|
}
|
|
|
|
return new ParseResult(entries, null);
|
|
}
|
|
|
|
private static bool TryParseInt(string s, out int v)
|
|
{
|
|
return int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tách token: khoảng trắng; hỗ trợ chuỗi trong dấu ngoặc kép cho hint nếu sau này cần.
|
|
/// </summary>
|
|
private static List<string> Tokenize(string text)
|
|
{
|
|
var list = new List<string>();
|
|
var sb = new StringBuilder();
|
|
bool inQuotes = false;
|
|
|
|
for (int i = 0; i < text.Length; i++)
|
|
{
|
|
char c = text[i];
|
|
|
|
if (inQuotes)
|
|
{
|
|
if (c == '"')
|
|
inQuotes = false;
|
|
else
|
|
sb.Append(c);
|
|
continue;
|
|
}
|
|
|
|
if (c == '"')
|
|
{
|
|
if (sb.Length > 0)
|
|
{
|
|
list.Add(sb.ToString());
|
|
sb.Clear();
|
|
}
|
|
|
|
inQuotes = true;
|
|
continue;
|
|
}
|
|
|
|
if (char.IsWhiteSpace(c))
|
|
{
|
|
if (sb.Length > 0)
|
|
{
|
|
list.Add(sb.ToString());
|
|
sb.Clear();
|
|
}
|
|
continue;
|
|
}
|
|
|
|
sb.Append(c);
|
|
}
|
|
|
|
if (sb.Length > 0)
|
|
list.Add(sb.ToString());
|
|
|
|
return list;
|
|
}
|
|
}
|
|
}
|