Skip to content

Commit 4cc3aef

Browse files
committed
feat: add json export
1 parent da1c38d commit 4cc3aef

File tree

4 files changed

+264
-0
lines changed

4 files changed

+264
-0
lines changed

src/main/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function(BUILD_GAME GAME GAME_PATH SDK)
1313
HL2SDK-${SDK}
1414
fmt::fmt
1515
spdlog
16+
nlohmann_json::nlohmann_json
1617
${CMAKE_DL_LIBS}
1718
)
1819

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/**
2+
* =============================================================================
3+
* DumpSource2
4+
* Copyright (C) 2026 ValveResourceFormat Contributors
5+
* =============================================================================
6+
*
7+
* This program is free software; you can redistribute it and/or modify it under
8+
* the terms of the GNU General Public License, version 3.0, as published by the
9+
* Free Software Foundation.
10+
*
11+
* This program is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14+
* details.
15+
*
16+
* You should have received a copy of the GNU General Public License along with
17+
* this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "json_exporter.h"
21+
#include "globalvariables.h"
22+
#include "interfaces.h"
23+
#include <filesystem>
24+
#include <fstream>
25+
#include <map>
26+
#include <unordered_set>
27+
#include <algorithm>
28+
#include <optional>
29+
#include <spdlog/spdlog.h>
30+
#include <nlohmann/json.hpp>
31+
32+
using json = nlohmann::json;
33+
34+
namespace Dumpers::Schemas::JsonExporter
35+
{
36+
37+
json SerializeMetadataArray(const std::vector<IntermediateMetadata>& metadataVector)
38+
{
39+
json arr = json::array();
40+
for (const auto& metadata : metadataVector)
41+
{
42+
json j;
43+
j["name"] = metadata.name;
44+
if (metadata.hasValue && metadata.stringValue.has_value())
45+
{
46+
j["value"] = *metadata.stringValue;
47+
}
48+
49+
arr.push_back(j);
50+
}
51+
return arr;
52+
}
53+
54+
json SerializeType(CSchemaType* type)
55+
{
56+
if (!type)
57+
return nullptr;
58+
59+
json j;
60+
61+
switch (type->m_eTypeCategory)
62+
{
63+
case SCHEMA_TYPE_BUILTIN:
64+
j["category"] = "builtin";
65+
j["name"] = type->m_sTypeName.String();
66+
break;
67+
case SCHEMA_TYPE_POINTER:
68+
j["category"] = "ptr";
69+
j["inner"] = SerializeType(static_cast<CSchemaType_Ptr*>(type)->m_pObjectType);
70+
break;
71+
case SCHEMA_TYPE_FIXED_ARRAY:
72+
{
73+
auto* arr = static_cast<CSchemaType_FixedArray*>(type);
74+
j["category"] = "fixed_array";
75+
j["count"] = arr->m_nElementCount;
76+
j["inner"] = SerializeType(arr->m_pElementType);
77+
break;
78+
}
79+
case SCHEMA_TYPE_ATOMIC:
80+
{
81+
j["category"] = "atomic";
82+
83+
// Extract outer name from m_sTypeName before '<'
84+
std::string typeName = type->m_sTypeName.String();
85+
auto pos = typeName.find('<');
86+
if (pos != std::string::npos)
87+
{
88+
auto name = typeName.substr(0, pos);
89+
// Trim trailing whitespace
90+
while (!name.empty() && name.back() == ' ')
91+
name.pop_back();
92+
j["name"] = name;
93+
}
94+
else
95+
{
96+
j["name"] = typeName;
97+
}
98+
99+
if (type->m_eAtomicCategory == SCHEMA_ATOMIC_T ||
100+
type->m_eAtomicCategory == SCHEMA_ATOMIC_COLLECTION_OF_T)
101+
{
102+
j["inner"] = SerializeType(static_cast<CSchemaType_Atomic_T*>(type)->m_pTemplateType);
103+
}
104+
else if (type->m_eAtomicCategory == SCHEMA_ATOMIC_TT)
105+
{
106+
auto* tt = static_cast<CSchemaType_Atomic_TT*>(type);
107+
j["inner"] = SerializeType(tt->m_pTemplateType);
108+
j["inner2"] = SerializeType(tt->m_pTemplateType2);
109+
}
110+
break;
111+
}
112+
case SCHEMA_TYPE_DECLARED_CLASS:
113+
{
114+
j["category"] = "declared_class";
115+
auto* classType = static_cast<CSchemaType_DeclaredClass*>(type);
116+
if (classType->m_pClassInfo && classType->m_pClassInfo->m_pszName)
117+
{
118+
j["name"] = classType->m_pClassInfo->m_pszName;
119+
j["module"] = classType->m_pClassInfo->m_pszProjectName;
120+
}
121+
else
122+
j["name"] = type->m_sTypeName.String();
123+
break;
124+
}
125+
case SCHEMA_TYPE_DECLARED_ENUM:
126+
{
127+
j["category"] = "declared_enum";
128+
auto* enumType = static_cast<CSchemaType_DeclaredEnum*>(type);
129+
if (enumType->m_pEnumInfo && enumType->m_pEnumInfo->m_pszName)
130+
{
131+
j["name"] = enumType->m_pEnumInfo->m_pszName;
132+
j["module"] = enumType->m_pEnumInfo->m_pszProjectName;
133+
}
134+
else
135+
j["name"] = type->m_sTypeName.String();
136+
break;
137+
}
138+
case SCHEMA_TYPE_BITFIELD:
139+
j["category"] = "bitfield";
140+
j["count"] = static_cast<CSchemaType_Bitfield*>(type)->m_nBitfieldCount;
141+
break;
142+
default:
143+
j["category"] = "builtin";
144+
j["name"] = type->m_sTypeName.String();
145+
break;
146+
}
147+
148+
return j;
149+
}
150+
151+
void DumpClasses(const std::vector<IntermediateSchemaClass>& classes, json& classesArray)
152+
{
153+
for (const auto& intermediateClass : classes)
154+
{
155+
spdlog::trace("Dumping class for json: '{}'", intermediateClass.name);
156+
157+
json classObj;
158+
classObj["name"] = intermediateClass.name;
159+
classObj["module"] = intermediateClass.module;
160+
classObj["metadata"] = SerializeMetadataArray(intermediateClass.metadata);
161+
162+
json parents = json::array();
163+
for (const auto& parent : intermediateClass.parents)
164+
{
165+
json parentObj;
166+
parentObj["name"] = parent.name;
167+
parentObj["module"] = parent.module;
168+
parents.push_back(std::move(parentObj));
169+
}
170+
171+
classObj["parents"] = parents;
172+
173+
json fields = json::array();
174+
for (const auto& field : intermediateClass.fields)
175+
{
176+
spdlog::trace("Dumping field: '{}' for class: '{}'", field.name, intermediateClass.name);
177+
json fieldObj;
178+
fieldObj["name"] = field.name;
179+
fieldObj["offset"] = field.offset;
180+
fieldObj["type"] = SerializeType(field.type);
181+
fieldObj["metadata"] = SerializeMetadataArray(field.metadata);
182+
fields.push_back(fieldObj);
183+
}
184+
classObj["fields"] = fields;
185+
186+
classesArray.push_back(std::move(classObj));
187+
}
188+
}
189+
190+
void DumpEnums(const std::vector<IntermediateSchemaEnum>& enums, json& enumsArray)
191+
{
192+
for (const auto& intermediateEnum : enums)
193+
{
194+
json enumObj;
195+
enumObj["name"] = intermediateEnum.name;
196+
enumObj["module"] = intermediateEnum.module;
197+
enumObj["alignment"] = intermediateEnum.stringAlignment;
198+
199+
enumObj["metadata"] = SerializeMetadataArray(intermediateEnum.metadata);
200+
201+
json members = json::array();
202+
for (const auto& member : intermediateEnum.members)
203+
{
204+
json memberObj;
205+
memberObj["name"] = member.name;
206+
memberObj["value"] = member.value;
207+
208+
memberObj["metadata"] = SerializeMetadataArray(member.metadata);
209+
members.push_back(std::move(memberObj));
210+
}
211+
enumObj["members"] = std::move(members);
212+
enumsArray.push_back(std::move(enumObj));
213+
}
214+
}
215+
216+
void Dump(const std::vector<IntermediateSchemaEnum>& enums, const std::vector<IntermediateSchemaClass>& classes)
217+
{
218+
spdlog::info("Dumping schemas to json");
219+
220+
json root;
221+
json classesArray = json::array();
222+
json enumsArray = json::array();
223+
224+
DumpClasses(classes, classesArray);
225+
DumpEnums(enums, enumsArray);
226+
227+
root["classes"] = classesArray;
228+
root["enums"] = enumsArray;
229+
230+
std::ofstream output(Globals::outputPath / "schemas.json");
231+
output << root.dump(1);
232+
233+
spdlog::info("Wrote schemas.json ({} classes, {} enums)", classesArray.size(), enumsArray.size());
234+
}
235+
236+
} // namespace Dumpers::Schemas::JsonExporter
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* =============================================================================
3+
* DumpSource2
4+
* Copyright (C) 2026 ValveResourceFormat Contributors
5+
* =============================================================================
6+
*
7+
* This program is free software; you can redistribute it and/or modify it under
8+
* the terms of the GNU General Public License, version 3.0, as published by the
9+
* Free Software Foundation.
10+
*
11+
* This program is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14+
* details.
15+
*
16+
* You should have received a copy of the GNU General Public License along with
17+
* this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
#pragma once
20+
#include "schemas.h"
21+
22+
namespace Dumpers::Schemas::JsonExporter
23+
{
24+
void Dump(const std::vector<IntermediateSchemaEnum>& enums, const std::vector<IntermediateSchemaClass>& classes);
25+
} // namespace Dumpers::Schemas::JsonExporter

src/main/dumpers/schemas/schemas.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "schemasystem/schemasystem.h"
2727
#undef private
2828
#include "filesystem_exporter.h"
29+
#include "json_exporter.h"
2930

3031
namespace Dumpers::Schemas
3132
{
@@ -167,6 +168,7 @@ void Dump()
167168
DumpTypeScope(schemaSystem->GlobalTypeScope(), enums, classes);
168169

169170
FilesystemExporter::Dump(enums, classes);
171+
JsonExporter::Dump(enums, classes);
170172
}
171173

172174
} // namespace Dumpers::Schemas

0 commit comments

Comments
 (0)