-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathPresetCodeUtils.cs
More file actions
151 lines (149 loc) · 5.91 KB
/
Copy pathPresetCodeUtils.cs
File metadata and controls
151 lines (149 loc) · 5.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
using EFT.Communications;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace WeaponBuildMaster
{
//核心工具, 包含编码解码和提示器封装
public class PresetCodeUtils
{
//物品Id编码方法
//忽视MongoId的编码规则, 只看结果, 它是一串24位的16进制字符串
//因此我们将其切割为12个16进制数字, 视作字节处理
//12个字节用base64得到16个字符
public static byte[] HexStringToBytes(string hex)
{
byte[] bytes = new byte[12];
for (int i = 0; i < 12; i++)
{
bytes[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return bytes;
}
//生成数据段
public static string EncodeSparkCode(List<RawWeaponNode> rawTree)
{
//高速读写
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(ms))
{
//遍历树节点
for (int i = 0; i < rawTree.Count; i++)
{
var node = rawTree[i];
//写入物品段
writer.Write(HexStringToBytes(node.tpl));
//1字节存储节点索引
writer.Write((byte)i);
//1字节存储父节点索引
//根节点的父节点为空, 返回0xFF
if (string.IsNullOrEmpty(node.parent))
{
writer.Write((byte)255);
}
else
{
//父节点索引
int parentIndex = rawTree.FindIndex(n => n.id == node.parent);
writer.Write((byte)parentIndex);
}
//1字节存储slot索引
//依然根节点0xFF
if (string.IsNullOrEmpty(node.slotId)) // 或者判断 slotIndex == 0
{
writer.Write((byte)255);
}
else
{
//存储
writer.Write((byte)node.slotIndex);
}
}
//内存流转换到base64
return Convert.ToBase64String(ms.ToArray());
}
}
//物品Id解码
public static string BytesToHexString(byte[] bytes)
{
//BitConverter会把数组变成AA-BB-CC的形式, 去掉横杠转小写
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
//改枪码解码
public static List<RawWeaponNode> DecodeSparkCode(string clipboardText)
{
//预生成树结构
List<RawWeaponNode> rawTree = new List<RawWeaponNode>();
try
{
//定义
string text = clipboardText.Trim();
string base64Data = text;
//去除末尾换行符, 保留SPT-PS-WBM-数据段
string[] lines = text.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
if (lines.Length > 0)
{
string firstLine = lines[0];
string prefix = "SPT-ProjectSpark-WBM-";
//去除头
if (firstLine.StartsWith(prefix))
{
base64Data = firstLine.Substring(prefix.Length);
}
else
{
//仅保留改枪码也可以正常解析
base64Data = firstLine;
}
}
//还原字节流
byte[] data = Convert.FromBase64String(base64Data);
//数据段是完美的15个字节1个节点, 校验长度
if (data.Length % 15 != 0)
{
Console.WriteLine($"[枪匠大师]: 数据长度异常 ({data.Length} bytes),非完整 15 字节区块!");
return null;
}
using (MemoryStream ms = new MemoryStream(data))
using (BinaryReader reader = new BinaryReader(ms))
{
int nodeCount = data.Length / 15;
//切割字段
for (int i = 0; i < nodeCount; i++)
{
//还原物品ID
byte[] tplBytes = reader.ReadBytes(12);
string tpl = BytesToHexString(tplBytes);
//还原节点信息
byte selfIndex = reader.ReadByte();
byte parentIndex = reader.ReadByte();
byte slotIndex = reader.ReadByte();
//重建树结构
RawWeaponNode node = new RawWeaponNode();
node.tpl = tpl;
node.id = selfIndex.ToString();
node.parent = parentIndex == 255 ? "" : parentIndex.ToString();
node.slotIndex = slotIndex == 255 ? 0 : slotIndex;
rawTree.Add(node);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"[枪匠大师]: Base64 解析失败,可能复制了非法的字符串。错误: {ex.Message}");
return null;
}
return rawTree;
}
//提示器封装
public static void ShowMessage(string message)
{
NotificationManager.DisplayMessageNotification(message);
}
public static void ShowErrorMessage(string message)
{
NotificationManager.DisplayWarningNotification(message);
}
}
}