Files
test/Assets/PerfectWorld/Scripts/Config/SkillStateActionConfig.cs
vuong dinh hoang f8512de72e deal damage overtime
2026-05-12 16:56:22 +07:00

116 lines
4.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace BrewMonster.Config
{
/// <summary>One row of skill_state_action.txt: skill id, visible state id, be-hit action, optional stay-down action.</summary>
[Serializable]
public struct SkillStateActionRow
{
public int skill;
public int state;
public string beHitAction;
public string stayDownAction;
}
/// <summary>Parses the classic comma-separated skill_state_action table (same rules as legacy client / CECAttacksMan TextAsset loader).</summary>
public static class SkillStateActionTextParser
{
/// <summary>
/// Strip CSV-style wrapping quotes (Excel export often writes "2244","117",...).
/// Handles doubled-quote escapes inside a quoted field.
/// </summary>
private static string UnquoteCsvField(string raw)
{
if (string.IsNullOrEmpty(raw))
return string.Empty;
string s = raw.Trim().TrimStart('\uFEFF');
while (s.Length >= 2 && s[0] == '"' && s[s.Length - 1] == '"')
{
s = s.Substring(1, s.Length - 2).Replace("\"\"", "\"").Trim();
}
// Odd exports / naive splits can leave stray " on one side.
s = s.Trim('"').Trim();
return s;
}
public static List<SkillStateActionRow> Parse(string text, ICollection<string> warnings = null)
{
var rows = new List<SkillStateActionRow>();
if (string.IsNullOrEmpty(text))
return rows;
// Saved-as-UTF-8-with-BOM breaks int.TryParse on the first column of line 1 (\ufeff123,...).
text = text.TrimStart('\uFEFF');
using (var reader = new StringReader(text))
{
string line;
int lineNum = 0;
while ((line = reader.ReadLine()) != null)
{
lineNum++;
string trimmed = line.TrimStart('\uFEFF').Trim();
if (trimmed.Length == 0 || trimmed.StartsWith("//") || trimmed.StartsWith("#"))
continue;
string[] v = trimmed.Split(',');
// Some configs use tabs instead of commas.
if (v.Length < 3)
v = trimmed.Split('\t');
if (v.Length < 3)
{
warnings?.Add($"Line {lineNum}: need at least 3 comma-separated fields");
continue;
}
string s0 = UnquoteCsvField(v[0]);
string s1 = UnquoteCsvField(v[1]);
if (!int.TryParse(s0, System.Globalization.NumberStyles.Integer,
System.Globalization.CultureInfo.InvariantCulture, out int skillId) ||
!int.TryParse(s1, System.Globalization.NumberStyles.Integer,
System.Globalization.CultureInfo.InvariantCulture, out int stateId))
{
warnings?.Add($"Line {lineNum}: invalid skill or state id (got \"{s0}\", \"{s1}\")");
continue;
}
string beHit = UnquoteCsvField(v[2]);
string stayDown = v.Length > 3 ? UnquoteCsvField(v[3]) : string.Empty;
rows.Add(new SkillStateActionRow
{
skill = skillId,
state = stateId,
beHitAction = beHit,
stayDownAction = stayDown
});
}
}
return rows;
}
}
[CreateAssetMenu(fileName = "skill_state_action", menuName = "PerfectWorld/Skill State Action Config")]
public class SkillStateActionConfig : ScriptableObject
{
[SerializeField] private List<SkillStateActionRow> entries = new List<SkillStateActionRow>();
public IReadOnlyList<SkillStateActionRow> Entries => entries;
#if UNITY_EDITOR
/// <summary>Editor / tools: replace serialized rows after import.</summary>
public void SetEntries(List<SkillStateActionRow> newEntries)
{
entries = newEntries ?? new List<SkillStateActionRow>();
}
#endif
}
}