Skip to content

Commit 0d1d441

Browse files
Merge pull request #14 from ReactiioN1337/develop
Updated legacy branch
2 parents 4e87582 + e70229b commit 0d1d441

10 files changed

+697
-117
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "thirdparty/liblzma"]
2+
path = thirdparty/liblzma
3+
url = https://github.com/ReactiioN1337/liblzma.git

CMakeLists.txt

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# CMakeList.txt: projekt CMake dla elementu vpk_kv_generator, dołącz źródło i zdefiniuj
2+
# tutaj logikę specyficzną dla projektu.
3+
#
4+
cmake_minimum_required (VERSION 3.10)
5+
6+
include_guard(GLOBAL)
7+
8+
set (CMAKE_CXX_STANDARD 17) #this does not change __cplusplus var in MSVC for some reason
9+
10+
project ("valve-bsp-parser")
11+
12+
13+
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Werror -funroll-loops -fvisibility=hidden -O3")
14+
15+
#Template compilation fails at x64 MSVC in parse_map template function
16+
# beacuse of _NODISCARD macro
17+
#Since in c++17 keyword [[nodiscard]] is already defined we use it instead of a macro
18+
#TODO: Can we use x64 version of the lib?
19+
20+
#TODO: LZMA compression of lumps
21+
#TODO: entity lump
22+
#TODO: Overwrite in-mem bsp file with standalone lump files present in same directory as map
23+
#Research from leak: This functionality is "temporarily" disabled from the multiplayer games, due to possibility of exploits. sv_pure cannot detect such patches. The comment cites a wallhack as an example.
24+
# Dodaj źródło do pliku wykonywalnego tego projektu.
25+
set (PRIVATE_INCLUDES
26+
"include/valve-bsp-parser/bsp_parser.hpp"
27+
"include/valve-bsp-parser/core/matrix.hpp"
28+
"include/valve-bsp-parser/core/requirements.hpp"
29+
"include/valve-bsp-parser/core/valve_structs.hpp")
30+
31+
set (SOURCES
32+
"src/bsp_parser.cpp")
33+
34+
add_library(valve-bsp-parser STATIC ${PRIVATE_INCLUDES} ${SOURCES})
35+
36+
37+
38+
39+
add_subdirectory(thirdparty/liblzma)
40+
41+
add_dependencies(valve-bsp-parser lzma)
42+
target_include_directories(valve-bsp-parser PUBLIC
43+
${Boost_INCLUDE_DIR}
44+
"${PROJECT_SOURCE_DIR}/include/"
45+
"${PROJECT_SOURCE_DIR}/thirdparty/liblzma/include"
46+
)
47+
48+
49+
target_link_libraries(valve-bsp-parser PRIVATE lzma)
50+
51+
52+
53+
# TODO: Dodaj testy i zainstaluj elementy docelowe w razie potrzeby.

include/valve-bsp-parser/bsp_parser.hpp

+133-29
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
///--------------------------------------------------------------------------------
1+
///--------------------------------------------------------------------------------
22
///-- Author ReactiioN
33
///-- Copyright 2016-2020, ReactiioN
44
///-- License MIT
@@ -7,6 +7,11 @@
77

88
#include <valve-bsp-parser/core/valve_structs.hpp>
99
#include <shared_mutex>
10+
#include <LzmaLib.h>
11+
#include <cstring>
12+
#include <cassert>
13+
#include <mutex>
14+
#include <optional>
1015

1116
namespace rn {
1217
class bsp_parser final
@@ -39,21 +44,34 @@ class bsp_parser final
3944
std::string& file_path
4045
);
4146

47+
4248
bool parse_planes(
43-
std::ifstream& file
49+
std::ifstream& file,
50+
std::optional<valve::lumpfileheader_t> lumpFileHeader
51+
);
52+
bool parse_entities(
53+
std::ifstream& file,
54+
std::optional<valve::lumpfileheader_t> lumpFileHeader
4455
);
4556

4657
bool parse_nodes(
47-
std::ifstream& file
58+
std::ifstream& file,
59+
std::optional<valve::lumpfileheader_t> lumpFileHeader
4860
);
4961

5062
bool parse_leaffaces(
51-
std::ifstream& file
63+
std::ifstream& file,
64+
std::optional<valve::lumpfileheader_t> lumpFileHeader
5265
);
5366

5467
bool parse_leafbrushes(
55-
std::ifstream& file
56-
);
68+
std::ifstream& file,
69+
std::optional<valve::lumpfileheader_t> lumpFileHeader
70+
);
71+
72+
//bool parse_entities(
73+
// std::ifstream& file
74+
//);
5775

5876
bool parse_polygons();
5977

@@ -81,26 +99,104 @@ class bsp_parser final
8199
)const;
82100

83101
template<typename type>
84-
_NODISCARD
102+
NODISCARD
85103
bool parse_lump(
86104
std::ifstream& file,
87105
const valve::lump_index lump_index,
88-
std::vector<type>& out
106+
std::vector<type>& out,
107+
std::optional<valve::lumpfileheader_t> fileLump = std::nullopt
89108
) const
90109
{
110+
using rn::valve::lzma_header_t;
111+
using rn::valve::has_valid_lzma_ident;
91112
const auto index = static_cast<std::underlying_type_t<valve::lump_index>>( lump_index );
92-
if( index >= _bsp_header.lumps.size() ) {
113+
114+
115+
116+
if( index >= bsp_header.lumps.size() ) {
93117
return false;
94118
}
119+
//TODO: decompress lump here if compressed
120+
//Default behavior is casting data to underlying types.
121+
//It doesn't handle compression
122+
123+
124+
//There are two exceptions though: Game lumps (35) (yes, multiple; compressed individually), and PAK Lump (40) (basically a zip file)
125+
126+
127+
const auto& lump = bsp_header.lumps.at( index );
128+
129+
std::size_t lumpOffset,lumpSize;
130+
131+
valve::lumpfileheader_t lumpPatch;
132+
if (fileLump.has_value()) {
133+
lumpPatch = fileLump.value();
134+
lumpOffset = lumpPatch.file_offset;
135+
lumpSize = lumpPatch.file_size;
136+
} else {
137+
138+
lumpOffset = lump.file_offset;
139+
lumpSize = lump.file_size;
140+
}
141+
142+
auto size = static_cast<std::size_t>( lumpSize ) / sizeof( type );
143+
//out.resize( size );
144+
145+
146+
char* tmpData = new char[lumpSize + sizeof(lzma_header_t) + 1]; //lump.file_size doesn't count size of the header
147+
file.seekg( lumpOffset );
148+
//Temporarily make this array. This data may be compressed.
149+
150+
memset(tmpData, 0, lumpSize + sizeof(lzma_header_t) + 1);
151+
152+
file.read(tmpData, lumpSize);
95153

96-
const auto& lump = _bsp_header.lumps.at( index );
97-
const auto size = static_cast<std::size_t>( lump.file_size ) / sizeof( type );
154+
lzma_header_t lzma_header;
155+
memcpy(&lzma_header, tmpData, sizeof(lzma_header));
98156

99-
out.resize( size );
100157

101-
file.seekg( lump.file_offset );
102-
file.read( reinterpret_cast<char*>( out.data() ), size * static_cast<std::size_t>( sizeof( type ) ) );
158+
if (has_valid_lzma_ident(lzma_header.id))
159+
{
160+
assert(lump_index != valve::lump_index::game_lump || lump_index != valve::lump_index::pak_file); //Those have special rules regarding compression.
103161

162+
163+
164+
//This section below was BEFORE if check. This resulted on malloc pulling array size from garbage data
165+
//without checking if data were actually compressed.
166+
167+
168+
char* tmpUncompressedData;
169+
//bool isCompressed = false;
170+
171+
172+
tmpUncompressedData = new char[lzma_header.actualSize + 1];
173+
174+
175+
size_t lzmaSize = lzma_header.lzmaSize,realSize = lzma_header.actualSize;
176+
177+
178+
LzmaUncompress(reinterpret_cast<unsigned char*>(tmpUncompressedData),
179+
&realSize,
180+
reinterpret_cast<unsigned char*>(tmpData+sizeof(lzma_header_t)), //point to actual data, not the header
181+
&lzmaSize,
182+
reinterpret_cast<unsigned char*>(lzma_header.properties.data()),
183+
LZMA_PROPS_SIZE);
184+
out.resize(static_cast<std::size_t>(lzma_header.actualSize) / sizeof(type));
185+
out.assign(reinterpret_cast<type*>(tmpUncompressedData),reinterpret_cast<type*>(tmpUncompressedData+realSize));
186+
delete[] tmpUncompressedData;
187+
188+
}
189+
else
190+
{
191+
out.resize(size/sizeof(type));
192+
out.assign(reinterpret_cast<type*>(tmpData),reinterpret_cast<type*>(tmpData+lumpSize));
193+
}
194+
195+
196+
197+
198+
//file.read( reinterpret_cast<char*>( out.data() ), size * static_cast<std::size_t>( sizeof( type ) ) );
199+
delete[] tmpData;
104200
return true;
105201
}
106202

@@ -120,23 +216,31 @@ class bsp_parser final
120216
const vector3& final,
121217
valve::trace_t* out
122218
);
219+
void unload_map();
123220

221+
222+
223+
224+
//TODO: Cannot remove leading underscores as some code relies on it.
225+
public:
226+
std::string map_name;
227+
valve::dheader_t bsp_header;
228+
//entities go here
229+
std::vector<valve::mvertex_t> vertices;
230+
std::vector<valve::cplane_t> planes;
231+
std::vector<valve::dedge_t> edges;
232+
std::vector<std::int32_t> surf_edges;
233+
std::vector<valve::dleaf_t> leaves;
234+
std::vector<valve::snode_t> nodes;
235+
std::vector<valve::dface_t> surfaces;
236+
std::vector<valve::texinfo_t> tex_infos;
237+
std::vector<valve::dbrush_t> brushes;
238+
std::vector<valve::dbrushside_t> brush_sides;
239+
std::vector<std::uint16_t> leaf_faces;
240+
std::vector<std::uint16_t> leaf_brushes;
241+
std::vector<valve::polygon> polygons;
242+
std::vector<valve::entity_t> entities;
124243
private:
125-
std::string _map_name;
126-
valve::dheader_t _bsp_header;
127-
std::vector<valve::mvertex_t> _vertices;
128-
std::vector<valve::cplane_t> _planes;
129-
std::vector<valve::dedge_t> _edges;
130-
std::vector<std::int32_t> _surf_edges;
131-
std::vector<valve::dleaf_t> _leaves;
132-
std::vector<valve::snode_t> _nodes;
133-
std::vector<valve::dface_t> _surfaces;
134-
std::vector<valve::texinfo_t> _tex_infos;
135-
std::vector<valve::dbrush_t> _brushes;
136-
std::vector<valve::dbrushside_t> _brush_sides;
137-
std::vector<std::uint16_t> _leaf_faces;
138-
std::vector<std::uint16_t> _leaf_brushes;
139-
std::vector<valve::polygon> _polygons;
140244
mutable std::shared_timed_mutex _mutex;
141245
};
142246
}

include/valve-bsp-parser/core/matrix.hpp

+11-11
Original file line numberDiff line numberDiff line change
@@ -295,15 +295,15 @@ class matrix_t
295295
return at( row_index * num_cols + col_index );
296296
}
297297

298-
_NODISCARD
298+
NODISCARD
299299
const float& at(
300300
const std::size_t index
301301
) const
302302
{
303303
return _data.at( clamp_index( index ) );
304304
}
305305

306-
_NODISCARD
306+
NODISCARD
307307
const float& at(
308308
const std::size_t row_index,
309309
const std::size_t col_index
@@ -312,13 +312,13 @@ class matrix_t
312312
return at( row_index * num_cols + col_index );
313313
}
314314

315-
_NODISCARD
315+
NODISCARD
316316
bool is_zero() const
317317
{
318318
return all_of( 0.f );
319319
}
320320

321-
_NODISCARD
321+
NODISCARD
322322
bool all_of(
323323
const float value
324324
) const
@@ -329,7 +329,7 @@ class matrix_t
329329
} );
330330
}
331331

332-
_NODISCARD
332+
NODISCARD
333333
float normsqr() const
334334
{
335335
static_assert( is_vector(), "norm() can only be used on vectors" );
@@ -343,10 +343,10 @@ class matrix_t
343343
return value;
344344
}
345345

346-
_NODISCARD
346+
NODISCARD
347347
float norm() const
348348
{
349-
return std::sqrtf( normsqr() );
349+
return std::sqrt( normsqr() );
350350
}
351351

352352
matrix_t<1, num_cols> row(
@@ -421,7 +421,7 @@ class matrix_t
421421
( *this ) /= norm();
422422
}
423423

424-
_NODISCARD
424+
NODISCARD
425425
matrix_t normalized() const
426426
{
427427
auto lhs = *this;
@@ -430,7 +430,7 @@ class matrix_t
430430
}
431431

432432
template<std::size_t rhs_num_rows, std::size_t rhs_num_cols>
433-
_NODISCARD
433+
NODISCARD
434434
float dot(
435435
const matrix_t<rhs_num_rows, rhs_num_cols>& rhs
436436
) const
@@ -447,7 +447,7 @@ class matrix_t
447447
return value;
448448
}
449449

450-
_NODISCARD
450+
NODISCARD
451451
matrix_t cross(
452452
const matrix_t& rhs
453453
) const
@@ -461,7 +461,7 @@ class matrix_t
461461
};
462462
}
463463

464-
_NODISCARD
464+
NODISCARD
465465
matrix_t ncross(
466466
const matrix_t& rhs
467467
) const

include/valve-bsp-parser/core/requirements.hpp

+13
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,16 @@
1717
#include <fstream>
1818
#include <string>
1919
#include <vector>
20+
#include <unordered_map>
21+
#include <sstream>
22+
23+
24+
// check for nodiscard
25+
26+
#if __cplusplus >= 201703L // in MSVC this variable is bogus and refers to C++98 version.
27+
#define NODISCARD [[nodiscard]]
28+
#elif defined(_MSC_VER)
29+
#define NODISCARD _NODISCARD
30+
#else
31+
#define NODISCARD [[nodiscard]]
32+
#endif

0 commit comments

Comments
 (0)