From eab66b0a04f3523b9f84c0c1dfc0b37bfb4c4853 Mon Sep 17 00:00:00 2001 From: sin365 <353374337@qq.com> Date: Fri, 14 Jun 2024 14:16:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BD=92=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HunterIDHelper.cs | 113 +++++++++++++++++++++++++++++++++ MHFCharacterIDConverter.csproj | 12 ++++ Program.cs | 17 +++++ README.md | 47 ++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 HunterIDHelper.cs create mode 100644 MHFCharacterIDConverter.csproj create mode 100644 Program.cs create mode 100644 README.md diff --git a/HunterIDHelper.cs b/HunterIDHelper.cs new file mode 100644 index 0000000..e946f18 --- /dev/null +++ b/HunterIDHelper.cs @@ -0,0 +1,113 @@ +using System.Text; + +namespace MHFCharacterIDConverter +{ + public static class HunterIDHelper + { + public static string UIntIDToInGameID(uint Id) + { + string base32String = MHFBase32Converter.ToBase32((int)Id); + string inGameID = Base32StringToInGameID(base32String); + return inGameID; + } + + public static uint InGameIDToUIntID(string inGameID) + { + string base32String = InGameIDToBase32String(inGameID); + uint Id = (uint)MHFBase32Converter.FromBase32(base32String); + return Id; + } + + + static string Base32StringToInGameID(string str) + { + string result = ""; + for (int i = str.Length - 1; i >= 0; i--) + { + result += str[i]; + } + + while (result.Length < 6) + { + result += "1"; + } + return result; + } + + + static string InGameIDToBase32String(string str) + { + string result = ""; + for (int i = 0; i < str.Length; i++) + result = str[i] + result; + + List temp = result.ToList(); + + result = ""; + + bool bhadfristVal = false; + for (int i = 0; i < temp.Count; i++) + { + if (!bhadfristVal && temp[i] == '1') + continue; + bhadfristVal = true; + result += temp[i]; + } + + return result; + } + } + + public static class MHFBase32Converter + { + private const string Base35Chars = "123456789ABCDEFGHJKLMNPQRTUVWXYZ"; // 35个字符,从'1'到'Z' + + // 整数转换为35进制字符串(自定义的,其中'1'代表0) + public static string ToBase32(int number) + { + + StringBuilder result = new StringBuilder(); + while (number > 0) + { + int remainder = number % 32; + result.Insert(0, Base35Chars[remainder]); // 注意这里不需要减1,因为直接从'1'开始 + number /= 32; + } + + // 如果number是0,则添加'1'表示 + if (result.Length == 0) + { + result.Append(Base35Chars[0]); + } + + return result.ToString(); + } + + // 35进制字符串转换为整数(自定义的,其中'1'代表0) + public static int FromBase32(string base32String) + { + if (string.IsNullOrWhiteSpace(base32String)) throw new ArgumentNullException(nameof(base32String)); + + int result = 0; + int power = 1; + + for (int i = base32String.Length - 1; i >= 0; i--) + { + char currentChar = base32String[i]; + int index = Base35Chars.IndexOf(currentChar); + + if (index == -1) + { + throw new ArgumentException("Invalid character in base32 string."); + } + + // 如果第一个字符是'1',则不需要加1,因为'1'代表0 + result += (i == 0 && currentChar == '1' ? 0 : index) * power; + power *= 32; + } + + return result; + } + + } +} diff --git a/MHFCharacterIDConverter.csproj b/MHFCharacterIDConverter.csproj new file mode 100644 index 0000000..fbb4a9b --- /dev/null +++ b/MHFCharacterIDConverter.csproj @@ -0,0 +1,12 @@ + + + + Exe + net8.0 + enable + enable + true + true + + + diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..044797e --- /dev/null +++ b/Program.cs @@ -0,0 +1,17 @@ +namespace MHFCharacterIDConverter +{ + internal class Program + { + static void Main(string[] args) + { + //Test + for (uint i = 1; i < 1300u; i++) + { + string InGameID = HunterIDHelper.UIntIDToInGameID(i); + uint reConvID = HunterIDHelper.InGameIDToUIntID(InGameID); + Console.WriteLine($"srcCharID: {i} | InGameID: {InGameID} | reConvID: {reConvID}"); + } + Console.ReadLine(); + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..27d7e6a --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +##[Cn] + +在Monster Hunter Frontier (任意版本) 中,浏览角色信息,有一个ID,形如"W6BX11",这种六位数。 + +通过查看服务端代码和截取包,发现服务器仅发送了uint32的数据库的CharacterID,并没有发送"W6BX11"这种字符串。 + +这完全是客户端逻辑,为了不显示真实ID,做了一个换算。 + +我搞清楚了其换算机制,机制如下: + +1. MHF客户端是基于0~Z的36进制,但是把‘0’、‘I’、‘O’、‘S’ 这四个字符扔了,变成32进制。 + +2. 从0到32的数值,对应的表示符号是“123456789ABCDEFGHJKLMNPQRTUVWXYZ” + +3. 按照如上对应表,把uint32的CharacterID进行转换之后。 + +4. 将结果倒序,(并不是HEX的高位在前,是直接整个字符串倒序) + +5. 然后不足6位填充“1”,因为“1”就是0 + +相反的行为,换算回去 + +已用于皓月云MHF-FW5在线网页游戏实况的需要内存采集的一部分功能。 + +##[En] + +In Monster Hunter Frontier (any version), when browsing character information, there is an ID in the form of "W6BX11", a six-digit number. + +By checking the server code and intercepting the package, it was found that the server only sent the CharacterID of the uint32 database, and did not send the string "W6BX11". + +This is completely client logic. In order not to display the real ID, a conversion was made. + +I figured out its conversion mechanism, which is as follows: + +1. The MHF client is based on 36-decimal system 0~Z, but the four characters '0', 'I', 'O', and 'S' are thrown away and converted to 32-decimal system. + +2. The corresponding symbols for the values ​​from 0 to 32 are "123456789ABCDEFGHJKLMNPQRTUVWXYZ" + +3. According to the corresponding table above, convert the CharacterID of uint32. + +4. Reverse the result (not the high bit of HEX first, but the whole string in reverse order) + +5. Then fill "1" if there are less than 6 bits, because "1" is 0 + +The opposite behavior, convert back + +It has been used for some functions of axibug.com MHF-FW5 online web game live that require memory acquisition. \ No newline at end of file