StringTab

This commit is contained in:
Le Duc Anh
2025-10-11 15:57:15 +07:00
parent 51eeb4e642
commit 142611dddd
21 changed files with 2353 additions and 0 deletions
@@ -0,0 +1,255 @@
using System;
using System.IO;
using ModelRenderer.Scripts.Common;
namespace BrewMonster.Common
{
public struct SCRIPTINFO
{
public byte[] pFileBuf; // Pointer to file data buffer
public byte[] pStart; // Start address of buffer
public byte[] pEnd; // End address of buffer
public byte[] pCur; // Current pointer. Pointer size is 2 bytes
public uint pCurIndex; // Current pointer index
public int iLine; // Line counter
}
public class AWScriptFile
{
private const int MAX_LINELEN = 2048;
public ushort[] m_szToken = new ushort[MAX_LINELEN];
protected SCRIPTINFO m_Script = new SCRIPTINFO();
public bool Open(FileStream stream)
{
uint dwFilelen = (uint)stream.Length;
if (dwFilelen <= 0)
{
BMLogger.LogError($"EC_StringTab::Open: {stream.Name} File length is 0");
return false;
}
byte[] pBuf = new byte[dwFilelen];
stream.Read(pBuf, 0, (int)dwFilelen);
// Check unicode file header
ushort wChar = BitConverter.ToUInt16(new byte[] {pBuf[0], pBuf[1]});
if (wChar != 0xfeff)
{
BMLogger.LogError($"EC_StringTab::Open: {stream.Name} File is not unicode");
return false;
}
m_Script.pFileBuf = pBuf;
m_Script.pStart = new []{m_Script.pFileBuf[2], m_Script.pFileBuf[3]}; // Skip unicode magic number
m_Script.pCur = m_Script.pStart;
m_Script.pEnd = new [] {m_Script.pFileBuf[pBuf.Length - 2], m_Script.pFileBuf[pBuf.Length - 1]};
m_Script.pCurIndex = 2;
m_Script.iLine = 0;
return true;
}
public bool Open(string szFile)
{
if (!File.Exists(szFile))
{
BMLogger.LogError($"EC_StringTab::Open: {szFile} File not found");
return false;
}
using (FileStream stream = new FileStream(szFile, FileMode.Open, FileAccess.Read))
{
var bRet = Open(stream);
if (!bRet)
{
BMLogger.LogError($"EC_StringTab::Open: {szFile} File open failed");
return false;
}
stream.Close();
return true;
}
}
public void Close()
{
//TODO: May be not needed
m_Script.pFileBuf = null;
m_Script.pStart = null;
m_Script.pCur = null;
m_Script.pEnd = null;
}
/// <summary>
/// Get next token and move file pointer forward.
/// </summary>
/// <param name="bCrossLine">true, search next token until it is found or all buffer has been checked;<br/> false, only search next token in current line</param>
/// <returns>true for success, otherwise return false</returns>
public bool GetNextToken(bool bCrossLine)
{
NewLine:
while (m_Script.pCurIndex < m_Script.pFileBuf.Length)
{
// get the first byte because the pointer is 2 bytes. The second byte should be 0 in these cases (value < 255)
if (m_Script.pFileBuf[m_Script.pCurIndex] > 32 && m_Script.pFileBuf[m_Script.pCurIndex] != ';' &&
m_Script.pFileBuf[m_Script.pCurIndex] != ',')
break;
m_Script.pCurIndex += 2; // move pointer forward 2 bytes because it's w_char (2 bytes)
if (m_Script.pCurIndex >= m_Script.pFileBuf.Length)
return false;
m_Script.pCur[0] = m_Script.pFileBuf[m_Script.pCurIndex];
m_Script.pCur[1] = m_Script.pFileBuf[m_Script.pCurIndex + 1];
if (m_Script.pCur[0] == '\n')
{
if (!bCrossLine)
{
m_Script.pCurIndex -= 2; // Let search pointer still stop in this line
return false;
}
m_Script.iLine++;
}
}
if (m_Script.pCurIndex >= m_Script.pFileBuf.Length)
return false;
// Skip comment lines those begin with '//'
if (m_Script.pFileBuf[m_Script.pCurIndex] == '/' && m_Script.pFileBuf[m_Script.pCurIndex + 2] == '/')
{
// This is a note line, search it's ending.
while (!m_Script.pCur.Equals(m_Script.pEnd) && m_Script.pFileBuf[m_Script.pCurIndex] != '\n')
{
m_Script.pCurIndex += 2;
}
if (m_Script.pCurIndex >= m_Script.pFileBuf.Length) // Found nothing
return false;
if (!bCrossLine) // Don't search cross line
return false;
m_Script.pCurIndex += 2; // Skip '\n'
m_Script.iLine++;
goto NewLine;
}
// Text between /* */ are also comment
if (m_Script.pFileBuf[m_Script.pCurIndex] == '/' && m_Script.pFileBuf[m_Script.pCurIndex + 2] == '*')
{
bool bError = false;
m_Script.pCurIndex += 4; // Skip /*
while (m_Script.pFileBuf[m_Script.pCurIndex] != '*' || m_Script.pFileBuf[m_Script.pCurIndex + 2] != '/')
{
if (m_Script.pCurIndex >= m_Script.pEnd.Length) // Found nothing
return false;
else if (m_Script.pFileBuf[m_Script.pCurIndex] == '\n')
{
if (!bCrossLine)
{
// This is a fatal error, we should return false.
// But we must search the '*/' so that next time our begin point
// isn't in comment paragraph
bError = true;
}
m_Script.iLine++;
}
m_Script.pCurIndex += 2;
}
m_Script.pCurIndex += 4; // Skip */
if (bError)
return false;
goto NewLine;
}
int i = 0;
// Copy string in "" or () pair
if (m_Script.pFileBuf[m_Script.pCurIndex] == '"' || m_Script.pFileBuf[m_Script.pCurIndex] == '(')
{
char cEnd = m_Script.pFileBuf[m_Script.pCurIndex] == '"' ? '"' : ')';
// Quoted token
m_Script.pCurIndex += 2; // Skip " or (
m_Script.pCur[0] = m_Script.pFileBuf[m_Script.pCurIndex];
m_Script.pCur[1] = m_Script.pFileBuf[m_Script.pCurIndex + 1];
while (!m_Script.pCur.Equals(m_Script.pEnd) && m_Script.pFileBuf[m_Script.pCurIndex] != cEnd)
{
if (i >= MAX_LINELEN-1)
return false;
// save the text into the token array
m_szToken[i++] = BitConverter.ToUInt16(m_Script.pCur);
m_Script.pCurIndex += 2;
m_Script.pCur[0] = m_Script.pFileBuf[m_Script.pCurIndex];
m_Script.pCur[1] = m_Script.pFileBuf[m_Script.pCurIndex + 1];
}
m_Script.pCurIndex += 2; // Skip " or )
m_Script.pCur[0] = m_Script.pFileBuf[m_Script.pCurIndex];
m_Script.pCur[1] = m_Script.pFileBuf[m_Script.pCurIndex + 1];
}
else // Is a normal token
{
while (!m_Script.pCur.Equals(m_Script.pEnd) && BitConverter.ToInt16(m_Script.pCur) > 32 &&
m_Script.pFileBuf[m_Script.pCurIndex] != ';' && m_Script.pFileBuf[m_Script.pCurIndex] != ',')
{
if (i >= MAX_LINELEN-1)
return false;
m_szToken[i++] = BitConverter.ToUInt16(m_Script.pCur);
m_Script.pCurIndex += 2;
m_Script.pCur[0] = m_Script.pFileBuf[m_Script.pCurIndex];
m_Script.pCur[1] = m_Script.pFileBuf[m_Script.pCurIndex + 1];
}
}
m_szToken[i] = '\0';
return true;
}
/// <summary>
/// Peek next token and don't move file pointer
/// Return true for success, otherwise return false
/// </summary>
/// <param name="bCrossLine">true, search next token until it is found or all buffer has been checked; false, only search next token in current line</param>
public bool PeekNextToken(bool bCrossLine)
{
// Record current pointer and line
var pCur = new [] {m_Script.pCur[0], m_Script.pCur[1]};
var iLine = m_Script.iLine;
var pCurIndex = m_Script.pCurIndex;
bool bRet = GetNextToken(bCrossLine);
// Restore pointer and line
m_Script.pCur = pCur;
m_Script.iLine = iLine;
m_Script.pCurIndex = pCurIndex;
return bRet;
}
public int GetNextTokenAsInt(bool bCrossLine)
{
GetNextToken(bCrossLine);
return int.Parse(ByteToStringUtils.UshortArrayToUnicodeString(m_szToken));
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2c2c2e6c750c64c4fb852e667a353b22
@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.IO;
using ModelRenderer.Scripts.Common;
namespace BrewMonster.Common
{
public class CECStringTab
{
private Dictionary<int, string> m_AStrTab = new Dictionary<int, string>();
private Dictionary<int, string> m_WStrTab = new Dictionary<int, string>();
protected bool m_bInit = false;
protected bool m_bUnicode = false;
public bool IsInitialized() => m_bInit;
public void Clear()
{
m_AStrTab.Clear();
m_WStrTab.Clear();
m_bInit = false;
m_bUnicode = false;
}
public bool Init(string szFile, bool bUnicode)
{
bool bRet = false;
if (bUnicode)
{
bRet = LoadWideStrings(szFile);
}
if (!bRet)
{
BMLogger.LogError($"EC_StringTab::Init: {szFile} File load failed");
return false;
}
m_bInit = true;
return true;
}
private bool LoadWideStrings(string szFile)
{
AWScriptFile ScriptFile = new AWScriptFile();
if (!ScriptFile.Open(szFile)) return false;
bool bIndex = false;
bool bFileEnd = true;
// Read configs
while (ScriptFile.GetNextToken(true))
{
string tokenStr = ByteToStringUtils.UshortArrayToUnicodeString(ScriptFile.m_szToken);
if (ByteToStringUtils.UshortArrayToUnicodeString(ScriptFile.m_szToken).StartsWith("#_index"))
bIndex = true;
else if (ByteToStringUtils.UshortArrayToUnicodeString(ScriptFile.m_szToken).StartsWith("#_begin"))
{
bFileEnd = false;
break;
}
}
if (bFileEnd)
{
ScriptFile.Close();
return true;
}
if (bIndex)
{
// Every string has a preset index
while (ScriptFile.PeekNextToken(true))
{
int n = ScriptFile.GetNextTokenAsInt(true);
ScriptFile.GetNextToken(false);
string pstr = ByteToStringUtils.UshortArrayToUnicodeString(ScriptFile.m_szToken);
if (string.IsNullOrEmpty(pstr))
{
ScriptFile.Close();
BMLogger.LogError($"EC_StringTab::LoadWideStrings: {szFile} Not enough memory");
return false;
}
if (!m_WStrTab.TryAdd(n, pstr))
{
BMLogger.LogError($"EC_StringTab::LoadWideStrings: {szFile} Failed to add string to dictionary");
return false;
}
}
}
else
{
int iCnt = 0;
// Read strings sequently
while (ScriptFile.GetNextToken(true))
{
string pstr = ByteToStringUtils.UshortArrayToUnicodeString(ScriptFile.m_szToken);
if (string.IsNullOrEmpty(pstr))
{
ScriptFile.Close();
BMLogger.LogError($"EC_StringTab::LoadWideStrings: {szFile} Not enough memory");
return false;
}
if (!m_WStrTab.TryAdd(iCnt++, pstr))
{
BMLogger.LogError($"EC_StringTab::LoadWideStrings: {szFile} Failed to add string to dictionary");
return false;
}
}
}
ScriptFile.Close();
return true;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b95d268e43a5da14f9cf8e1ed98bfd73
@@ -0,0 +1,48 @@
using System.IO;
using UnityEngine;
namespace BrewMonster.Common
{
public class StringTabTest : MonoBehaviour
{
private CECStringTab m_pStringTab;
[ContextMenu("Test SkillStr")]
void TestSkillStr()
{
if (m_pStringTab == null)
{
m_pStringTab = new CECStringTab();
}
m_pStringTab.Clear();
string path = Path.Combine(Application.streamingAssetsPath, "configs/skillstr.txt");
m_pStringTab.Init(path, true);
}
[ContextMenu("Test Item Desc")]
public void TestItemDesc()
{
if (m_pStringTab == null)
{
m_pStringTab = new CECStringTab();
}
m_pStringTab.Clear();
string path = Path.Combine(Application.streamingAssetsPath, "configs/item_desc.txt");
m_pStringTab.Init(path, true);
}
[ContextMenu("Test Fixed Message")]
public void TestFixedMessage()
{
if (m_pStringTab == null)
{
m_pStringTab = new CECStringTab();
}
m_pStringTab.Clear();
string path = Path.Combine(Application.streamingAssetsPath, "configs/fixed_msg.txt");
m_pStringTab.Init(path, true);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3dee7c1499b302c43ac95e29bd235e3f
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e6d11b7855791e740ba22f037c41f0d9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,54 @@
1 -3023.42 218.73 3804.07 -2315.22 251.55 4416.35
2 -1922.07 217.27 4276.7 -1194.75 220.13 4256.25
3 -856.27 219.49 3957.78 -355.67 237.19 3916.26
4 897.03 219.1 4351.59 35.11 219.65 3989.86
5 1549.96 243.59 3865.42 1243.7 219.07 4543.64
6 2453.35 228.05 4307.06 2715.47 247.63 4105.12
7 -2510.53 218.28 2802.99 -2402.91 218.09 3356.69
8 -1557.7 218.62 2583.67 -1349.28 264.35 2927.5
9 -212.46 220.38 2724.44 -654.49 222.47 3541.15
10 197.31 248.51 3087.58 483.42 222.32 2844.72
11 2038.49 218.29 3936.27 1578.52 229 3672.47
12 1745.09 273.48 2860.03 1602.8 218.98 3481.97
13 2343.84 219.9 2511.81 2266.59 221.58 1991.78
14 -2591.45 218.19 2454.08 -2261.2 218.91 1746.06
15 -1860.3 218.36 2139.75 -1150.03 245.14 1773.89
16 -791.97 214.17 2471.02 -129.35 224.08 2081.36
17 368.38 219.54 2182.4 279.82 221.15 1761.76
18 2011.77 222.19 2400.27 1294.64 336.56 2261.45
19 -2292.16 469.47 1185.61 -2842.81 528.89 760.08
20 -1674.26 220.34 435.34 -1905.86 229.63 -61.49
21 -557.8 413.98 831.01 -21.79 219.42 972.1
22 147.18 216.57 1146.07 462.83 231.23 764.32
23 1470.78 220.53 645.87 1079.88 221.18 1256.26
24 2846.67 217.35 953.47 2413.6 218.71 537.18
25 -2957.37 520.29 -272.5 -2225.5 523.78 377.31
26 -2025.75 219.2 -375.8 -1894.25 226.35 -192.02
27 -993.31 522.37 20.72 -521.16 522.2 489.45
28 -285.09 234.15 465.15 -607.3 219.14 -489.76
29 646.27 218.46 -271.57 471.1 216.63 380.43
30 358.89 218.47 -463.42 492.2 222.58 -109.62
31 1271.29 244.23 224.86 1048.12 238.15 -293.67
32 2447.06 219.6 -145.47 2778.47 220.67 213.79
33 -2149.01 525.18 -1064.02 -2852.9 524.33 -1270.3
34 -1702.3 522.73 -1141.74 -1140.11 522.96 -868.99
35 -127.76 218.48 -1512.58 -539.96 219.56 -870.73
36 25.99 218.68 -833.9 543.07 218.09 -808.75
37 1463.93 219.4 -1472.2 1737.68 218.85 -947.34
38 2451.27 219.75 -1456.2 2584.51 221.31 -677.67
39 -2344.41 523.96 -1576.39 -2819 524.02 -2181.16
40 -1160.61 219.03 -2087.02 -1833.15 504.52 -2360.84
41 -479.77 218.9 -2059.16 -828.94 216.61 -2484.79
42 958.61 219.02 -2082.36 130.06 219.85 -2275.24
43 1065.01 218.99 -2207.16 1594.66 220.67 -2471.93
44 2310.6 219.28 -1578.46 2532.92 220.95 -1665.75
45 2827.66 225.81 -3084.25 2360.43 217.55 -3279.74
46 1579.91 245.92 -4094.02 1594.13 248.55 -3849.75
47 2453.18 245.07 -3711.65 2865.72 217.89 -4411.53
48 -2153.87 204.16 -3154.12 -2573.45 217.27 -3501.96
49 -1297.92 216.52 -2908.71 -1716.92 232.57 -2805.03
50 -642.59 216.87 -3442.9 -550.52 218.04 -2764.84
51 226.82 241.05 -3121.08 880.44 239.78 -3066.87
52 3337.821 230.013 3998.825 3717.706 253.014 3667.437
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bccfbf7d03830734fb6cd82a31536791
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 06d9a02a2d455104d9b49c78ed8fc6d3
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 22d591e6986fa6c4ab705ee890953236
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0b095c8d0e089f747a289d8e6c7b693e
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5429be2b686cda24e8f5ab2049a68b27
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,139 @@
//物品id 喊话id 显示参数 喊话次数(默认为1) 喊话间隔
//如果出现同一物品id对应不同的喊话id,程序中将只取靠后的那个喊话id
//参数含义(3: 先显示物品名再显示玩家名,2:先显示玩家名再显示物品名,1:显示玩家名,0:都不显示);
//0 都不显示
//1 显示玩家名
//2 先显示玩家名再显示物品名
//3 先显示物品名再显示玩家名
//4 显示顺序:服务器-玩家-道具
//5 显示顺序:道具-服务器-玩家
//6 显示顺序:服务器-玩家
//7 显示顺序:服务器
//本服喊话ID对照
11599 4521 2
11600 4522 2
12227 4523 1
12265 4524 2
12264 4525 2
12266 4526 2
12769 4527 2
12719 4528 2
12646 4529 2
12647 4529 2
12648 4529 2
12649 4529 2
12650 4529 2
12651 4529 2
13548 4648 0
13565 4665 0
13566 4666 0
13567 4667 0
13568 4668 0
13569 4669 0
13570 4670 0
13571 4671 0
13572 4672 0
13573 4673 0
13574 4674 0
13575 4675 0
13576 4676 0
13577 4677 0
13578 4678 0
13579 4679 0
13580 4680 0
13581 4681 0
13582 4682 0
13583 4683 0
13584 4684 0
13585 4685 0
13586 4686 0
13587 4687 0
13588 4688 0
13589 4689 0
13590 4690 0
13591 4691 0
13592 4692 0
13593 4693 0
13594 4694 0
13595 4695 0
13596 4696 0
13597 4697 0
13598 4698 0
13599 4699 0
13600 4700 0
14290 4532 1
20853 4533 3
20255 4534 3
20289 4535 3
21065 4536 3
20311 4537 3
20852 4538 3
20218 4539 3
20402 4540 3
20851 4541 3
20394 4542 3
20363 4543 3
26061 4544 3
26053 4545 3
28607 4546 2
29453 4547 3
30207 4548 3
44960 4549 3
45043 4550 3
48694 4551 3
48695 4551 3
48696 4552 3
48697 4552 3
50139 4554 2
50145 4554 2
50151 4554 2
50157 4554 2
50163 4554 2
50169 4554 2
50175 4554 2
50181 4554 2
50187 4554 2
50193 4554 2
50199 4554 2
50205 4554 2
50211 4554 2
50217 4554 2
50223 4554 2
50229 4554 2
50140 4555 2
50146 4555 2
50152 4555 2
50158 4555 2
50164 4555 2
50170 4555 2
50176 4555 2
50182 4555 2
50188 4555 2
50194 4555 2
50200 4555 2
50206 4555 2
50212 4555 2
50218 4555 2
50224 4555 2
50230 4555 2
//跨服喊话ID对照
49647 4801 4
50702 4802 6
50704 4803 6
50706 4804 6
50708 4805 6
50710 4806 6
50712 4807 6
50714 4808 6
50716 4809 6
50718 4810 6
50720 4811 6
50722 4812 6
50724 4813 6
50726 4814 6
50728 4815 6
50730 4816 6
50732 4817 6
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 76f11583e7abe3e4bbf976a45f946fe7
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6ee4a110a33412e4aa3f879764bec33b
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: