Files
test/Assets/Scripts/CECStringTab.cs
T
2025-12-08 16:15:01 +07:00

241 lines
8.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using ModelRenderer.Scripts.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine; // thêm để dùng Resources & TextAsset
namespace BrewMonster
{
public class CECStringTab
{
private readonly Dictionary<int, string> m_AStrTab = new Dictionary<int, string>();
private readonly Dictionary<int, string> m_WStrTab = new Dictionary<int, string>();
private bool m_bInit = false;
private bool m_bUnicode = false;
public CECStringTab() { }
~CECStringTab() { Release(); }
public bool Init(string szFile, bool bUnicode)
{
Release();
m_bUnicode = bUnicode;
try
{
bool ok = bUnicode ? LoadWideStrings(szFile) : LoadANSIStrings(szFile);
m_bInit = ok;
return ok;
}
catch (Exception e)
{
Debug.LogError($"[CECStringTab] Init failed: {e}");
Release();
return false;
}
}
public void Release()
{
m_AStrTab.Clear();
m_WStrTab.Clear();
m_bInit = false;
m_bUnicode = false;
}
public string GetANSIString(int n) => m_AStrTab.TryGetValue(n, out var s) ? s : null;
public string GetWideString(int n) => m_WStrTab.TryGetValue(n, out var s) ? s : null;
public string GetWideStringObject(int n) => GetWideString(n);
public bool IsInitialized() => m_bInit;
// ==== Đọc từ Resources thay vì đường dẫn ====
protected bool LoadANSIStrings(string resourceName)
{
try
{
// If a real file path is provided (e.g. StreamingAssets), read directly from disk.
// 如果提供的是实际文件路径(例如 StreamingAssets),则直接从磁盘读取。
if (File.Exists(resourceName))
{
// ANSI tables are in CP936 in original PW; keep using CP936 decoder.
// 原版完美世界的ANSI表是CP936编码,这里保持一致。
byte[] bytes = File.ReadAllBytes(resourceName);
string content = ByteToStringUtils.ByteArrayToCP936String(bytes);
using var srFile = new StringReader(content);
return ParseIntoDict(srFile, isWide: false);
}
// Fallback to Resources (old behaviour).
// 回退到 Resources 加载(旧行为)。
TextAsset textAsset = Resources.Load<TextAsset>(resourceName);
if (textAsset == null)
{
Debug.LogError($"[CECStringTab] Resource not found: {resourceName}");
return false;
}
string resContent = ByteToStringUtils.ByteArrayToCP936String(textAsset.bytes);
using var srRes = new StringReader(resContent);
return ParseIntoDict(srRes, isWide: false);
}
catch (Exception e)
{
Debug.LogError($"[CECStringTab] LoadANSIStrings failed for '{resourceName}': {e}");
return false;
}
}
protected bool LoadWideStrings(string resourceName)
{
try
{
// Support absolute / relative filesystem paths (e.g. StreamingAssets/configs/*.txt)
// 支持文件系统路径(例如 StreamingAssets/configs/*.txt
if (File.Exists(resourceName))
{
// String tables we ship in StreamingAssets are saved as UTF-8.
// 我们放在 StreamingAssets 里的字符串表保存为 UTF-8。
string content = File.ReadAllText(resourceName, Encoding.UTF8);
using var srFile = new StringReader(content);
return ParseIntoDict(srFile, isWide: true);
}
// Fallback to Resources-based loading (old behaviour)
// 回退到基于 Resources 的加载(旧行为)
TextAsset textAsset = Resources.Load<TextAsset>(resourceName);
if (textAsset == null)
{
Debug.LogError($"[CECStringTab] Resource not found: {resourceName}");
return false;
}
// Unity TextAsset.text is already UTF-8 decoded.
string resContent = textAsset.text;
using var srRes = new StringReader(resContent);
return ParseIntoDict(srRes, isWide: true);
}
catch (Exception e)
{
Debug.LogError($"[CECStringTab] LoadWideStrings failed for '{resourceName}': {e}");
return false;
}
}
private static Encoding DetectEncoding(byte[] bom)
{
if (bom.Length >= 3 && bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) return Encoding.UTF8;
if (bom.Length >= 2 && bom[0] == 0xFF && bom[1] == 0xFE) return Encoding.Unicode;
if (bom.Length >= 2 && bom[0] == 0xFE && bom[1] == 0xFF) return Encoding.BigEndianUnicode;
return null;
}
private bool ParseIntoDict(StringReader sr, bool isWide)
{
bool bIndexMode = false;
bool bBegan = false;
int autoIndex = 0;
var allLines = new List<string>();
string line;
while ((line = sr.ReadLine()) != null)
{
allLines.Add(line);
}
for (int i = 0; i < allLines.Count; i++)
{
var ln = allLines[i].Trim();
if (ln.Length == 0) continue;
if (ln.Equals("#_index", StringComparison.OrdinalIgnoreCase))
{
bIndexMode = true;
}
else if (ln.Equals("#_begin", StringComparison.OrdinalIgnoreCase))
{
bBegan = true;
for (int j = i + 1; j < allLines.Count; j++)
{
var payload = allLines[j].Trim();
if (payload.Length == 0) continue;
if (payload.StartsWith("#")) continue;
if (payload.StartsWith("//")) continue;
if (bIndexMode)
{
if (!TrySplitIndexAndText(payload, out int idx, out string text))
continue;
PutString(idx, text, isWide);
}
else
{
PutString(autoIndex++, payload, isWide);
}
}
break;
}
}
return bBegan;
}
private static bool TrySplitIndexAndText(string line, out int index, out string text)
{
index = 0; text = null;
int eq = line.IndexOf('=');
if (eq >= 0)
{
var left = line.Substring(0, eq).Trim();
var right = line.Substring(eq + 1);
if (int.TryParse(left, out index))
{
text = right;
return true;
}
return false;
}
int sp = FirstWhiteSpaceIndex(line);
if (sp <= 0) return false;
var left2 = line.Substring(0, sp).Trim();
var right2 = line.Substring(sp).TrimStart();
if (int.TryParse(left2, out index))
{
text = right2;
return true;
}
return false;
}
private static int FirstWhiteSpaceIndex(string s)
{
for (int i = 0; i < s.Length; i++)
if (char.IsWhiteSpace(s[i])) return i;
return -1;
}
private void PutString(int id, string value, bool isWide)
{
if (string.IsNullOrEmpty(value))
return;
// Many PW string tables wrap the payload in double quotes, e.g.:
// 12345 "^ffcb4aSome text\rMore text"
// Strip a single leading/trailing quote pair to avoid showing raw quotes in UI.
// 许多字符串表会用双引号包裹内容,这里去掉首尾各一个引号以避免在UI中显示多余的引号。
if (value.Length >= 2 && value[0] == '"' && value[value.Length - 1] == '"')
{
value = value.Substring(1, value.Length - 2);
}
if (isWide) m_WStrTab[id] = value;
else m_AStrTab[id] = value;
}
}
}