4#include "phys-model.hpp"
5#include "displacements/triangulated-displacement.hpp"
6#include "enums/lump.hpp"
7#include "helpers/offset-data-view.hpp"
8#include "helpers/zip.hpp"
9#include "structs/common.hpp"
10#include "structs/detail-props.hpp"
11#include "structs/displacements.hpp"
12#include "structs/geometry.hpp"
13#include "structs/headers.hpp"
14#include "structs/models.hpp"
15#include "structs/static-props.hpp"
16#include "structs/textures.hpp"
30 explicit Bsp(std::span<const std::byte> data);
32 std::span<const std::byte> data;
36 std::span<const Structs::GameLump> gameLumps;
38 std::span<const Structs::Vector> vertices;
39 std::span<const Structs::Plane> planes;
40 std::span<const Structs::Edge> edges;
41 std::span<const int32_t> surfaceEdges;
42 std::span<const Structs::Face> faces;
44 std::span<const Structs::TexInfo> textureInfos;
45 std::span<const Structs::TexData> textureDatas;
46 std::span<const int32_t> textureStringTable;
47 std::span<const char> textureStringData;
49 std::span<const Structs::Model> models;
51 std::span<const Structs::DispInfo> displacementInfos;
52 std::span<const Structs::DispVert> displacementVertices;
60 std::vector<PhysModel> physicsModels;
62 std::vector<Zip::ZipFileEntry> compressedPakfile;
67 std::optional<std::span<const Structs::StaticPropDict>> staticPropDictionary = std::nullopt;
68 std::optional<std::span<const Structs::StaticPropLeaf>> staticPropLeaves = std::nullopt;
70 std::optional<std::variant<
71 std::span<const Structs::StaticPropV4>,
72 std::span<const Structs::StaticPropV5>,
73 std::span<const Structs::StaticPropV6>,
74 std::span<const Structs::StaticPropV7Multiplayer2013>>>
75 staticProps = std::nullopt;
84 template <
typename LumpType>
85 std::span<const LumpType> parseLump(Enums::Lump lump,
size_t maxItems = std::numeric_limits<size_t>::max()) {
86 const auto& lumpHeader = header->
lumps.at(
static_cast<size_t>(lump));
88 assertLumpHeaderValid(lump, lumpHeader);
90 if (lumpHeader.length %
sizeof(LumpType) != 0) {
91 throw Errors::InvalidBody(
94 "Lump header has length ({}) which is not a multiple of the size of its item type ({})",
101 const auto numItems = lumpHeader.length /
sizeof(LumpType);
102 if (numItems > maxItems) {
103 throw Errors::InvalidBody(
104 lump, std::format(
"Number of lump items ({}) exceeds source engine maximum ({})", numItems, maxItems)
108 return std::span<const LumpType>(
reinterpret_cast<const LumpType*
>(&data[lumpHeader.offset]), numItems);
111 [[nodiscard]] std::span<const Structs::GameLump> parseGameLumpHeaders()
const;
113 [[nodiscard]] std::vector<PhysModel> parsePhysCollideLump()
const;
115 template <
class StaticProp>
116 [[nodiscard]] std::span<const StaticProp> parseStaticPropLump(
const Structs::GameLump& lumpHeader) {
117 if (lumpHeader.offset < 0) {
118 throw Errors::InvalidBody(
119 Enums::Lump::GameLump,
120 std::format(
"Static prop game lump header has a negative offset ({})", lumpHeader.offset)
124 if (lumpHeader.length < 0) {
125 throw Errors::InvalidBody(
126 Enums::Lump::GameLump,
127 std::format(
"Static prop game lump header has a negative length ({})", lumpHeader.length)
131 if (lumpHeader.offset + lumpHeader.length > data.size_bytes()) {
132 throw Errors::OutOfBoundsAccess(
133 Enums::Lump::GameLump,
135 "Static prop game lump header has offset + length ({}) overrunning the file ({})",
136 lumpHeader.offset + lumpHeader.length,
142 const auto dictionaryData = Internal::OffsetDataView(std::span(&data[lumpHeader.offset], lumpHeader.length));
143 const auto numDictionaryEntries = dictionaryData.parseStruct<int32_t>(
144 0,
"Static prop game lump length is shorter than a single int32 for the dictionary count"
146 staticPropDictionary = dictionaryData.parseStructArray<Structs::StaticPropDict>(
147 sizeof(int32_t), numDictionaryEntries,
"Static prop game lump dictionary entries overflowed the lump"
150 const auto leafData =
151 dictionaryData.withRelativeOffset(
sizeof(int32_t) + numDictionaryEntries *
sizeof(Structs::StaticPropDict));
152 const auto numLeaves = leafData.parseStruct<int32_t>(
153 0,
"Static prop game lump length is shorter than its dictionary entries plus a single int32 for the leaf count"
155 staticPropLeaves = leafData.parseStructArray<Structs::StaticPropLeaf>(
156 sizeof(int32_t), numLeaves,
"Static prop game lump leaves overflowed the lump"
159 const auto propData = leafData.withRelativeOffset(
sizeof(int32_t) + numLeaves *
sizeof(Structs::StaticPropLeaf));
160 const auto numProps = propData.parseStruct<int32_t>(
161 0,
"Static prop game lump length is shorter than its dictionary, leaves, and a single int32 for the prop count"
163 const auto props = propData.parseStructArray<StaticProp>(
164 sizeof(int32_t), numProps,
"Static prop game lump props overflowed the lump"
170 [[nodiscard]] std::vector<Zip::ZipFileEntry> parsePakfileLump()
const;
172 void assertLumpHeaderValid(Enums::Lump lump,
const Structs::Lump& lumpHeader)
const;
174 [[nodiscard]] TriangulatedDisplacement createTriangulatedDisplacement(
175 const Structs::DispInfo& displacementInfo
Definition: BSPParser.hpp:8
void smoothNeighbouringDisplacements()
Definition: bsp.cpp:93
std::vector< TriangulatedDisplacement > displacements
Definition: bsp.hpp:58