From 302d600f4c559a16932eaca45dab6adf72c260d7 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 30 Jan 2023 00:28:31 -0700 Subject: [PATCH] qbsp: strip _tb_ keys, convert __TB_empty to skip --- common/entdata.cc | 5 +++++ include/common/entdata.h | 3 +++ qbsp/map.cc | 7 +++++++ testmaps/q2_tb_cleanup.map | 21 +++++++++++++++++++++ tests/test_qbsp_q2.cc | 18 ++++++++++++++++++ 5 files changed, 54 insertions(+) create mode 100644 testmaps/q2_tb_cleanup.map diff --git a/common/entdata.cc b/common/entdata.cc index 36218d9d..a0adbce0 100644 --- a/common/entdata.cc +++ b/common/entdata.cc @@ -182,6 +182,11 @@ void entdict_t::parse(parser_base_t &parser) } } +bool entdict_t::operator==(const entdict_t& other) const +{ + return this->keyvalues == other.keyvalues; +} + void EntData_ParseInto(parser_t &parser, std::vector &vector) { /* go through all the entities */ diff --git a/include/common/entdata.h b/include/common/entdata.h index 989f5243..07a4f207 100644 --- a/include/common/entdata.h +++ b/include/common/entdata.h @@ -68,6 +68,9 @@ public: // the parser must be at a position where { is // the next token parsed. void parse(parser_base_t &parser); + + // order-sensitive + bool operator==(const entdict_t& other) const; }; void EntData_ParseInto(parser_t &parser, std::vector &vector); diff --git a/qbsp/map.cc b/qbsp/map.cc index a2257eec..c35f13ac 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -459,6 +459,8 @@ static bool IsSkipName(const char *name) return true; if (!Q_strcasecmp(name, "null")) // zhlt compat return true; + if (!Q_strcasecmp(name, "__TB_empty")) + return true; return false; } @@ -3287,6 +3289,11 @@ void WriteEntitiesToString() map.bsp.dentdata += "{\n"; for (auto &ep : entity.epairs) { + if (ep.first.starts_with("_tb_")) { + // Remove TrenchBroom keys. _tb_textures tends to be long and can crash vanilla clients. + // generally, these are mapper metadata and unwanted in the .bsp. + continue; + } if (ep.first.size() >= qbsp_options.target_game->max_entity_key - 1) { logging::print("WARNING: {} at {} has long key {} (length {} >= {})\n", entity.epairs.get("classname"), diff --git a/testmaps/q2_tb_cleanup.map b/testmaps/q2_tb_cleanup.map new file mode 100644 index 00000000..a295547b --- /dev/null +++ b/testmaps/q2_tb_cleanup.map @@ -0,0 +1,21 @@ +// Game: Quake 2 +// Format: Quake2 +// entity 0 +{ +"classname" "worldspawn" +"_tb_textures" "textures/e1u1;textures/e1u2;textures/e1u3;textures/e1u4;textures/e2u1;textures/e2u2;textures/e2u3;textures/e3u1;textures/e3u2;textures/e3u3" +// brush 0 +{ +( -64 -64 -32 ) ( -64 -63 -32 ) ( -64 -64 -31 ) __TB_empty 0 0 0 1 1 +( -64 -64 -32 ) ( -64 -64 -31 ) ( -63 -64 -32 ) __TB_empty 0 0 0 1 1 +( -64 -64 -32 ) ( -63 -64 -32 ) ( -64 -63 -32 ) __TB_empty 0 0 0 1 1 +( 64 64 0 ) ( 64 65 0 ) ( 65 64 0 ) __TB_empty 0 0 0 1 1 +( 64 64 0 ) ( 65 64 0 ) ( 64 64 1 ) __TB_empty 0 0 0 1 1 +( 64 64 0 ) ( 64 64 1 ) ( 64 65 0 ) __TB_empty 0 0 0 1 1 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "-48 -16 24" +} diff --git a/tests/test_qbsp_q2.cc b/tests/test_qbsp_q2.cc index ec9b8a17..d2d9e908 100644 --- a/tests/test_qbsp_q2.cc +++ b/tests/test_qbsp_q2.cc @@ -635,3 +635,21 @@ TEST_CASE("q2_hint_missing_faces" * doctest::test_suite("testmaps_q2") * doctest CHECK(BSP_FindFaceAtPoint(&bsp, &bsp.dmodels[0], {36, 144, 30})); } + +TEST_CASE("q2_tb_cleanup" * doctest::test_suite("testmaps_q2")) +{ + const auto [bsp, bspx, prt] = LoadTestmapQ2("q2_tb_cleanup.map"); + + { + INFO("check that __TB_empty was converted to skip"); + CHECK(nullptr == BSP_FindFaceAtPoint(&bsp, &bsp.dmodels[0], {0, 0, 0})); + } + + { + auto ents = EntData_Parse(bsp); + + REQUIRE(ents.size() == 2); + INFO("check that _tb_textures was stripped out"); + CHECK(entdict_t{{"classname", "worldspawn"}} == ents[0]); + } +}