├── .gitignore
├── Dumpcs2Protobuf.sln
├── Dumpcs2Protobuf
├── App.config
├── Dumpcs2Protobuf.csproj
├── MainApp.cs
├── Proto.cs
└── packages.config
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
298 | *.vbp
299 |
300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
301 | *.dsw
302 | *.dsp
303 |
304 | # Visual Studio 6 technical files
305 | *.ncb
306 | *.aps
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # Visual Studio History (VSHistory) files
365 | .vshistory/
366 |
367 | # BeatPulse healthcheck temp database
368 | healthchecksdb
369 |
370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
371 | MigrationBackup/
372 |
373 | # Ionide (cross platform F# VS Code tools) working folder
374 | .ionide/
375 |
376 | # Fody - auto-generated XML schema
377 | FodyWeavers.xsd
378 |
379 | # VS Code files for those working on multiple tools
380 | .vscode/*
381 | !.vscode/settings.json
382 | !.vscode/tasks.json
383 | !.vscode/launch.json
384 | !.vscode/extensions.json
385 | *.code-workspace
386 |
387 | # Local History for Visual Studio Code
388 | .history/
389 |
390 | # Windows Installer files from build outputs
391 | *.cab
392 | *.msi
393 | *.msix
394 | *.msm
395 | *.msp
396 |
397 | # JetBrains Rider
398 | *.sln.iml
399 |
--------------------------------------------------------------------------------
/Dumpcs2Protobuf.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.4.33205.214
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dumpcs2Protobuf", "Dumpcs2Protobuf\Dumpcs2Protobuf.csproj", "{8FFC710D-27B5-493F-9512-45DC39479258}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {8FFC710D-27B5-493F-9512-45DC39479258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {8FFC710D-27B5-493F-9512-45DC39479258}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {8FFC710D-27B5-493F-9512-45DC39479258}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {8FFC710D-27B5-493F-9512-45DC39479258}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {BFEE0E59-A539-419D-8D68-7DCC514AFF09}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/Dumpcs2Protobuf/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Dumpcs2Protobuf/Dumpcs2Protobuf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Dumpcs2Protobuf/MainApp.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | namespace DumpFileParser;
3 |
4 | public class Dumper
5 | {
6 | static string parseType(string type)
7 | {
8 | type = type.Trim(' ');
9 | switch (type)
10 | {
11 | case "int":
12 | return "int32";
13 | case "uint":
14 | return "uint32";
15 | case "long":
16 | return "int64";
17 | case "ulong":
18 | return "uint64";
19 | case "string":
20 | return "string";
21 | case "ByteString": // Google.Protobuf.ByteString beebyte
22 | return "bytes";
23 | default:
24 | // Console.WriteLine($"returning unknown field type {type}");
25 | if (type.Contains(".")) {
26 | type = type.Split(".").Last();
27 | }
28 | return type;
29 | }
30 | }
31 |
32 | static void Main(string[] args)
33 | {
34 | string fileName = "dump.cs";
35 | string searchString = "IMessage";
36 | string asmName = "RPG.Network.Proto.dll";
37 | string outputFolder = "output";
38 | List blackListEnumNames = new();
39 |
40 | if (!File.Exists(fileName))
41 | {
42 | Console.WriteLine($"File '{fileName}' not found.");
43 | return;
44 | }
45 |
46 | if (!Directory.Exists(outputFolder))
47 | {
48 | Directory.CreateDirectory(outputFolder);
49 | }
50 |
51 |
52 | string fileText = File.ReadAllText(fileName);
53 | StreamWriter outputFile = new(Path.Combine(outputFolder, "output.proto"));
54 | outputFile.WriteLine($"// Extracted from {fileName} using Dumpcs2Protobuf");
55 | outputFile.WriteLine("syntax = \"proto3\";\n");
56 | string[] segments = fileText.Split(new string[] { "// AssemblyIndex:" }, StringSplitOptions.None);
57 | Console.WriteLine($"Parsing {segments.Length} segments...");
58 |
59 | foreach (string segment in segments)
60 | {
61 | if (!segment.Split("\n")[2].Trim().EndsWith(asmName)) {
62 | continue;
63 | }
64 | string classNameStuff = segment.Split("\n")[5].Trim();
65 | // public sealed class ChessRogueSkipTeachingLevelScRsp : IMessage, IMessage, IEquatable, IDeepCloneable
66 | if (classNameStuff.StartsWith("public sealed class") && classNameStuff.Contains($": {searchString}"))
67 | {
68 | string className = classNameStuff.Split("public sealed class ")[1].Split(" :")[0].Trim();
69 |
70 | // if (className != "SceneEntityInfo") continue;
71 |
72 | string[] lines = segment.Split("\n");
73 | List fieldNums = GetFieldNums(lines);
74 | List fieldStrings = GetFieldStrings(lines);
75 | ProtoEnum? oneofEnum = null;
76 | ProtoMessage protoMessage = new();
77 | string? oneOfEnumName = null;
78 | string? oneOfName = null;
79 | if (fieldNums.Count != fieldStrings.Count) {
80 | string trimmed = fieldStrings.Last().Replace(" { get; }", "").Replace("public ", "");
81 | oneOfName = trimmed.Split(" ")[1];
82 | oneOfEnumName = trimmed.Split(" ")[0];
83 | blackListEnumNames.Add(oneOfEnumName.Split(".").Last());
84 | oneofEnum = FindAndParseEnum(oneOfEnumName, segments);
85 | }
86 |
87 | for (int i = 0; i < fieldNums.Count; i++) {
88 | ProtoFIeld field = new();
89 | string fieldstr = fieldStrings[i]
90 | .Replace("public ", "")
91 | .Replace(" { get; set; }", "")
92 | .Replace(" { get; }", "")
93 | .TrimEnd();
94 | if (fieldstr.StartsWith("RepeatedField<")) {
95 | fieldstr = fieldstr.Substring("RepeatedField<".Length).Replace(">", "");
96 | string fieldType = parseType(fieldstr.Split(" ")[0]);
97 | string fieldName = fieldstr.Split(" ")[1];
98 | field.isRepeated = true;
99 | field.fieldName = fieldName;
100 | field.fieldType = fieldType;
101 | } else if (fieldstr.StartsWith("MapField<")) {
102 | fieldstr = fieldstr.Substring("MapField<".Length).Replace(">", "");
103 | string[] types = fieldstr.Replace(",", "").Split(" ");
104 | string key = parseType(types[0]);
105 | string val = parseType(types[1]);
106 | field.mapKey = key;
107 | field.mapValue = val;
108 | field.fieldName = types[2];
109 | } else {
110 | string fieldType = parseType(fieldstr.Split(" ")[0]);
111 | string fieldName = fieldstr.Split(" ")[1];
112 | field.fieldType = fieldType;
113 | field.fieldName = fieldName;
114 | }
115 | field.val = fieldNums[i];
116 |
117 | if (oneofEnum != null && oneofEnum.valDict.ContainsValue((int)field.val)) {
118 | if (protoMessage.oneOfList.Any(oneOfField => oneOfField.oneOfName == oneOfName)) {
119 | OneOf oneOf = protoMessage.oneOfList.Find(oneOfField => oneOfField.oneOfName == oneOfName)!;
120 | oneOf.fieldList.Add(field);
121 | } else {
122 | OneOf oneOf = new();
123 | oneOf.oneOfName = oneOfName!;
124 | oneOf.fieldList.Add(field);
125 | protoMessage.oneOfList.Add(oneOf);
126 | }
127 | } else {
128 | protoMessage.fieldList.Add(field);
129 | }
130 | }
131 | protoMessage.protoName = className;
132 | WriteMessageToFile(protoMessage, outputFile);
133 | } else if (classNameStuff.StartsWith("public enum ")) {
134 | string className = classNameStuff.Split("public enum ").Last().Trim();
135 | string[] lines = segment.Split("\n");
136 | ProtoEnum protoEnum = parseEnum(className, lines);
137 | WriteEnumToFile(protoEnum, outputFile, blackListEnumNames);
138 | }
139 |
140 | }
141 | Console.WriteLine("File parsing completed.");
142 | outputFile.Close();
143 | }
144 |
145 | static string CamelToSnake(string camelStr) {
146 | bool isAllUppercase = camelStr.All(char.IsUpper); // Beebyte
147 | if (string.IsNullOrEmpty(camelStr) || isAllUppercase)
148 | return camelStr;
149 | return Regex.Replace(camelStr, @"(([a-z])(?=[A-Z][a-zA-Z])|([A-Z])(?=[A-Z][a-z]))", "$1_").ToLower();
150 | }
151 |
152 | static void WriteMessageToFile(ProtoMessage msg, StreamWriter writer) {
153 | writer.WriteLine($"message {msg.protoName} {{");
154 | foreach (ProtoFIeld field in msg.fieldList) {
155 | if (field.isRepeated) {
156 | writer.WriteLine($"\trepeated {field.fieldType} {CamelToSnake(field.fieldName)} = {field.val};");
157 | } else if (field.mapKey != null) {
158 | writer.WriteLine($"\tmap<{field.mapKey},{field.mapValue}> {CamelToSnake(field.fieldName)} = {field.val};");
159 | } else {
160 | writer.WriteLine($"\t{field.fieldType} {CamelToSnake(field.fieldName)} = {field.val};");
161 | }
162 | }
163 | foreach (OneOf oneOf in msg.oneOfList) {
164 | writer.WriteLine($"\toneof {oneOf.oneOfName} {{");
165 | foreach (ProtoFIeld field in oneOf.fieldList) {
166 | if (field.isRepeated) {
167 | writer.WriteLine($"\t\trepeated {field.fieldType} {CamelToSnake(field.fieldName)} = {field.val};");
168 | } else if (field.mapKey != null) {
169 | writer.WriteLine($"\t\tmap<{field.mapKey},{field.mapValue}> {CamelToSnake(field.fieldName)} = {field.val};");
170 | } else {
171 | writer.WriteLine($"\t\t{field.fieldType} {CamelToSnake(field.fieldName)} = {field.val};");
172 | }
173 | }
174 | writer.WriteLine($"\t}}");
175 | }
176 | writer.WriteLine("}\n");
177 | }
178 |
179 | static void WriteEnumToFile(ProtoEnum msg, StreamWriter writer, List blackListEnumNames) {
180 | if (blackListEnumNames.Contains(msg.enumName)) {
181 | return;
182 | }
183 | writer.WriteLine($"enum {msg.enumName} {{");
184 | foreach (KeyValuePair entry in msg.valDict) {
185 | writer.WriteLine($"\t{entry.Key} = {entry.Value};");
186 | }
187 | writer.WriteLine("}\n");
188 | }
189 |
190 | static ProtoEnum FindAndParseEnum(string enumName, string[] segments) {
191 | var segment = segments.FirstOrDefault(s => {
192 | var lines = s.Split('\n');
193 | return lines.Length > 5 && lines[5].Trim().Contains($"enum {enumName}");
194 | });
195 |
196 | if (segment != null) {
197 | var lines = segment.Split('\n');
198 | return parseEnum(enumName, lines);
199 | }
200 |
201 | throw new ArgumentException($"Enum {enumName} not found in the provided segments.");
202 | }
203 |
204 | static ProtoEnum parseEnum(string enumName, string[] lines) {
205 | ProtoEnum result = new();
206 | for (int i=0; i GetFieldNums(string[] lines) {
227 | List result = new();
228 |
229 | int fieldsStartIndex = -1;
230 | int propertiesStartIndex = -1;
231 |
232 | // Find the indices of the "// Fields" and "// Properties" lines
233 | for (int i = 0; i < lines.Length; i++) {
234 | if (lines[i].Trim().StartsWith("// Fields")) {
235 | fieldsStartIndex = i + 1; // Start reading from the next line
236 | } else if (lines[i].Trim().StartsWith("// Properties")) {
237 | propertiesStartIndex = i; // Stop reading just before this line
238 | break; // No need to search further
239 | }
240 | }
241 |
242 | // If both indices were found, parse the field definitions
243 | if (fieldsStartIndex >= 0 && propertiesStartIndex > fieldsStartIndex) {
244 | for (int i = fieldsStartIndex; i < propertiesStartIndex; i++) {
245 | string line = lines[i].Trim();
246 | // Skip empty lines or comments
247 | if (string.IsNullOrEmpty(line) || line.StartsWith("//")) {
248 | continue;
249 | }
250 |
251 | // Extract field definition: get the part that represents the field number
252 | // This assumes that the field number is defined as `public const int SomeFieldName = 15;`
253 | var match = Regex.Match(line, @"public\s+const\s+int\s+(\w+)\s*=\s*(\d+);");
254 |
255 | if (match.Success) {
256 | // The field number is the value assigned to the constant
257 | if (uint.TryParse(match.Groups[2].Value, out uint fieldNum)) {
258 | result.Add(fieldNum);
259 | }
260 | }
261 | }
262 | }
263 |
264 | return result;
265 | }
266 |
267 | static List GetFieldStrings(string[] lines) {
268 | List properties = new();
269 |
270 | foreach (var line in lines) {
271 | string trimmedLine = line.Trim();
272 |
273 | // Check for public properties that are not static
274 | if (trimmedLine.StartsWith("public ") && !trimmedLine.Contains("static")) {
275 | // Match for property pattern: public { get; set; }
276 | var match = Regex.Match(trimmedLine,
277 | @"public\s+([\w\.]+(\s*<.*?>)?)\s+(\w+)\s*\{( get;(\s+set;)?| set;(\s+get;)?| get;| set;) \}");
278 |
279 |
280 | if (match.Success) {
281 | properties.Add(trimmedLine);
282 | }
283 | }
284 | }
285 |
286 | return properties;
287 | }
288 |
289 | }
--------------------------------------------------------------------------------
/Dumpcs2Protobuf/Proto.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 | using System.Text.RegularExpressions;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 |
8 | namespace DumpFileParser;
9 |
10 | public class ProtoMessage
11 | {
12 | public string protoName = "";
13 | public List importNameList = new();
14 | public List fieldList = new();
15 | public List oneOfList = new();
16 | }
17 |
18 | public class ProtoFIeld
19 | {
20 | public string fieldName = "";
21 | public string fieldType = "";
22 | public string? mapKey;
23 | public string? mapValue;
24 | public bool isRepeated;
25 | public uint val;
26 | }
27 |
28 | public class OneOf
29 | {
30 | public string oneOfName = "";
31 | public List fieldList = new();
32 | }
33 |
34 | public class ProtoEnum
35 | {
36 | public string enumName = "";
37 | public Dictionary valDict = new();
38 | }
--------------------------------------------------------------------------------
/Dumpcs2Protobuf/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dumpcs2Protobuf
2 | some shit i tried to make to extract the obfuscated protobuf messages from dump.cs file (needs to set manually the proto base class name)
3 |
4 | # Target Games: HSR, GI (pre-3.5, not tested)
5 | # YOU WILL NEED A FULL DUMP.CS FILE CONTAINING 100% FULL DUMP (INCLUDING ALL FULL FIELDS AND VALUES) ELSE IT WONT WORK
6 |
7 |
8 | # USAGE
9 |
10 | 1- edit the "string searchString" in the code to match the proto base class name
11 |
12 | 2- build it via Visual Studio 2022
13 |
14 | 3- put the dump.cs in same folder as the executable
15 |
16 | 4- run the program
17 |
18 | 5- you will be left with an `output` folder, containing the protobuf definition.
19 |
20 | 6- profit
21 |
22 | # I WILL NOT GUIDE YOU ON HOW TO DEOBFUSCATE PROTOS, YOU CAN DO IT USING TOOLS OR MANUALLY IF YOU'RE CRAZY ENOUGH
23 |
24 | ### Example proto class:
25 | ```cs
26 | // AssemblyIndex: 73 TypeIndexInAssembly: 4771
27 | // TypeDefIndex: 21606
28 | // Module: RPG.Network.Proto.dll
29 | // Namespace:
30 | // FullName: IEFELCIJJDA
31 | public sealed class IEFELCIJJDA : IMessage, IMessage, IEquatable, IDeepCloneable
32 | {
33 | // Fields
34 | private static readonly MessageParser CHAOHFOCDEB;
35 | private UnknownFieldSet JALDALIDBOO;
36 | public const int CPBHCOPAGBD = 13;
37 | private uint AOJNJCGDHBB;
38 | public const int NEFBNAELMLD = 14;
39 | private static readonly FieldCodec GKHOGKOMPFM;
40 | private readonly RepeatedField OMOIAPKFPBC;
41 |
42 | // Properties
43 | [DebuggerNonUserCodeAttribute]
44 | public static MessageParser MGGKOEHEENL { get; }
45 | [DebuggerNonUserCodeAttribute]
46 | private MessageDescriptor OMGLPJBHFAO { get; }
47 | [DebuggerNonUserCodeAttribute]
48 | public uint EGPKLBOKFNF { get; set; }
49 | [DebuggerNonUserCodeAttribute]
50 | public RepeatedField MDDLGJHLLAI { get; }
51 |
52 | // Constructors
53 | [DebuggerNonUserCodeAttribute]
54 | public void .ctor() // RVA: 0x03B6EED0
55 | [DebuggerNonUserCodeAttribute]
56 | public void .ctor(IEFELCIJJDA IDBLEINEBMO) // RVA: 0x03B6EE10
57 | private static void .cctor() // RVA: 0x03B6ECF0
58 |
59 | // Methods
60 | public static MessageParser LBDIKGFHEFF() // RVA: 0x03B6EA40
61 | private MessageDescriptor pb::Google.Protobuf.IMessage.get_Descriptor() // RVA: 0x00B90D10
62 | [DebuggerNonUserCodeAttribute]
63 | public IEFELCIJJDA Clone() // RVA: 0x03B6E750
64 | public uint IBNPDOJNDPO() // RVA: 0x00B00EA0
65 | public void HAMKADHBBJA(uint HONMPMJILHE) // RVA: 0x00B00EB0
66 | public RepeatedField AMDIKNJGNNN() // RVA: 0x00AF4D50
67 | [DebuggerNonUserCodeAttribute]
68 | public override bool Equals(object IDBLEINEBMO) // RVA: 0x03B6E8D0
69 | [DebuggerNonUserCodeAttribute]
70 | public bool Equals(IEFELCIJJDA IDBLEINEBMO) // RVA: 0x03B6E840
71 | [DebuggerNonUserCodeAttribute]
72 | public override int GetHashCode() // RVA: 0x03B6E9B0
73 | [DebuggerNonUserCodeAttribute]
74 | public override string ToString() // RVA: 0x03B6EBE0
75 | [DebuggerNonUserCodeAttribute]
76 | public void WriteTo(CodedOutputStream PKLLLHGLILG) // RVA: 0x03B6EC30
77 | [DebuggerNonUserCodeAttribute]
78 | public int CalculateSize() // RVA: 0x03B6E690
79 | [DebuggerNonUserCodeAttribute]
80 | public void MergeFrom(IEFELCIJJDA IDBLEINEBMO) // RVA: 0x03B6EA90
81 | [DebuggerNonUserCodeAttribute]
82 | public void MergeFrom(CodedInputStream PFFEJAFDIGF) // RVA: 0x03B6EB10
83 | }
84 | ```
85 |
86 | ### Example of enum class:
87 | ```cs
88 | // AssemblyIndex: 73 TypeIndexInAssembly: 4781
89 | // TypeDefIndex: 21616
90 | // Module: RPG.Network.Proto.dll
91 | // Namespace:
92 | // FullName: FGEMFOPIADP
93 | public enum FGEMFOPIADP
94 | {
95 | // Fields
96 | public int value__;
97 | [OriginalNameAttribute(Name = "CmdShopTypeNone", PreferredAlias = True)]
98 | public const FGEMFOPIADP IHJPPFIKELH = 0;
99 | [OriginalNameAttribute(Name = "CmdCityShopInfoScNotify", PreferredAlias = True)]
100 | public const FGEMFOPIADP PNKKDKOGMOM = 1533;
101 | [OriginalNameAttribute(Name = "CmdGetShopListScRsp", PreferredAlias = True)]
102 | public const FGEMFOPIADP MBBBOBNIMHF = 1571;
103 | [OriginalNameAttribute(Name = "CmdTakeCityShopRewardCsReq", PreferredAlias = True)]
104 | public const FGEMFOPIADP BNMFLHDJNIK = 1579;
105 | [OriginalNameAttribute(Name = "CmdGetShopListCsReq", PreferredAlias = True)]
106 | public const FGEMFOPIADP HJNDCEDJHHE = 1598;
107 | [OriginalNameAttribute(Name = "CmdTakeCityShopRewardScRsp", PreferredAlias = True)]
108 | public const FGEMFOPIADP DEHKAMAMCBO = 1577;
109 | [OriginalNameAttribute(Name = "CmdBuyGoodsCsReq", PreferredAlias = True)]
110 | public const FGEMFOPIADP OPINDNKEFNF = 1583;
111 | [OriginalNameAttribute(Name = "CmdBuyGoodsScRsp", PreferredAlias = True)]
112 | public const FGEMFOPIADP GOLLAMKKECD = 1542;
113 | }
114 | ```
--------------------------------------------------------------------------------