remove dm/start/coop checking

remove entity target(name) checking; as mods and maps get more complex, this is best left up to the editors to use the FGD to report these things.
This commit is contained in:
Jonathan 2022-06-13 07:10:53 -04:00
parent 81686200c3
commit b2a0f8039e
5 changed files with 3 additions and 161 deletions

View File

@ -140,9 +140,3 @@ void WriteEntitiesToString(const settings::worldspawn_keys &cfg, mbsp_t *bsp);
aabb3d EstimateVisibleBoundsAtPoint(const qvec3d &point);
bool EntDict_CheckNoEmptyValues(const mbsp_t *bsp, const entdict_t &entdict);
bool EntDict_CheckTargetKeysMatched(
const mbsp_t *bsp, const entdict_t &entity, const std::vector<entdict_t> &all_edicts);
bool EntDict_CheckTargetnameKeyMatched(
const mbsp_t *bsp, const entdict_t &entity, const std::vector<entdict_t> &all_edicts);

View File

@ -133,21 +133,6 @@ struct texdata_t
#include <common/imglib.hh>
#include <qbsp/wad.hh>
struct start_spots_t
{
private:
std::bitset<3> bits {};
public:
constexpr bool has_info_player_start() const { return bits[0]; }
constexpr bool has_info_player_coop() const { return bits[1]; }
constexpr bool has_info_player_deathmatch() const { return bits[2]; }
void set_info_player_start(bool value) { bits.set(0, value); }
void set_info_player_coop(bool value) { bits.set(1, value); }
void set_info_player_deathmatch(bool value) { bits.set(2, value); }
};
struct mapdata_t
{
/* Arrays of actual items */
@ -186,9 +171,6 @@ struct mapdata_t
// misc
bool wadlist_tried_loading = false;
std::list<wad_t> wadlist;
// todo type-cleanup: move to gamedef
start_spots_t start_spots;
// helpers
const std::string &miptexTextureName(int mt) const { return miptex.at(mt).name; }

View File

@ -176,95 +176,6 @@ bool EntDict_CheckNoEmptyValues(const mbsp_t *bsp, const entdict_t &entdict)
return ok;
}
/**
* Checks `edicts` for unmatched targets/targetnames and prints warnings
*/
bool EntDict_CheckTargetKeysMatched(
const mbsp_t *bsp, const entdict_t &entity, const std::vector<entdict_t> &all_edicts)
{
bool ok = true;
// TODO: what if we just do this for any key that contains `target` not immediately followed by `name`?
const std::vector<std::string> targetKeys{
"target", "killtarget", "target2", "angrytarget", "deathtarget" // from AD
};
const std::string &targetname = EntDict_StringForKey(entity, "targetname");
// search for "target" values such that no entity has a matching "targetname"
for (const auto &targetKey : targetKeys) {
const auto &targetVal = EntDict_StringForKey(entity, targetKey);
if (!targetVal.length())
continue;
if (targetVal == targetname) {
logging::print("WARNING: {} has \"{}\" set to itself\n", EntDict_PrettyDescription(bsp, entity), targetKey);
ok = false;
continue;
}
bool found = false;
for (const entdict_t &target : all_edicts) {
if (&target == &entity) {
continue;
}
if (string_iequals(targetVal, EntDict_StringForKey(target, "targetname"))) {
found = true;
break;
}
}
if (!found) {
logging::print("WARNING: {} has unmatched \"{}\" ({})\n", EntDict_PrettyDescription(bsp, entity), targetKey,
targetVal);
ok = false;
}
}
return ok;
}
bool EntDict_CheckTargetnameKeyMatched(
const mbsp_t *bsp, const entdict_t &entity, const std::vector<entdict_t> &all_edicts)
{
// search for "targetname" values such that no entity has a matching "target"
// accept any key name as a target, so we don't print false positive
// if the map has "some_mod_specific_target" "foo"
bool ok = true;
const auto &targetnameVal = EntDict_StringForKey(entity, "targetname");
if (targetnameVal.length()) {
bool found = false;
for (const entdict_t &targetter : all_edicts) {
if (&targetter == &entity) {
continue;
}
for (const auto &targetter_keyval : targetter) {
if (targetnameVal == targetter_keyval.second) {
found = true;
break;
}
}
if (found) {
break;
}
}
if (!found) {
logging::print("WARNING: {} has targetname \"{}\", which is not targeted by anything.\n",
EntDict_PrettyDescription(bsp, entity), targetnameVal);
ok = false;
}
}
return ok;
}
static void SetupSpotlights(const settings::worldspawn_keys &cfg)
{
for (auto &entity : all_lights) {
@ -861,8 +772,6 @@ void LoadEntities(const settings::worldspawn_keys &cfg, const mbsp_t *bsp)
// Make warnings
for (auto &entdict : entdicts) {
EntDict_CheckNoEmptyValues(bsp, entdict);
EntDict_CheckTargetKeysMatched(bsp, entdict, entdicts);
EntDict_CheckTargetnameKeyMatched(bsp, entdict, entdicts);
}
/* handle worldspawn */

View File

@ -17,27 +17,3 @@ TEST_CASE("CheckEmptyValues", "[entities]")
CHECK_FALSE(EntDict_CheckNoEmptyValues(nullptr, bad2));
CHECK_FALSE(EntDict_CheckNoEmptyValues(nullptr, bad3));
}
TEST_CASE("CheckTargetKeysMatched", "[entities]")
{
std::vector<entdict_t> edicts{// good
{{"target", "matched"}}, {{"target2", "matched"}}, {{"targetname", "matched"}},
// bad
{{"target", "unmatched"}}, {{"target", "targets_self"}, {"targetname", "targets_self"}}};
CHECK(EntDict_CheckTargetKeysMatched(nullptr, edicts.at(0), edicts));
CHECK(EntDict_CheckTargetKeysMatched(nullptr, edicts.at(1), edicts));
CHECK(EntDict_CheckTargetKeysMatched(nullptr, edicts.at(2), edicts));
CHECK_FALSE(EntDict_CheckTargetKeysMatched(nullptr, edicts.at(3), edicts));
CHECK_FALSE(EntDict_CheckTargetKeysMatched(nullptr, edicts.at(4), edicts));
}
TEST_CASE("CheckTargetnameKeyMatched", "[entities]")
{
std::vector<entdict_t> edicts{// good
{{"some_mod_specific_target_key", "matched"}}, {{"targetname", "matched"}},
// bad
{{"targetname", "unmatched"}}};
CHECK(EntDict_CheckTargetnameKeyMatched(nullptr, edicts.at(0), edicts));
CHECK(EntDict_CheckTargetnameKeyMatched(nullptr, edicts.at(1), edicts));
CHECK_FALSE(EntDict_CheckTargetnameKeyMatched(nullptr, edicts.at(2), edicts));
}

View File

@ -167,6 +167,7 @@ int FindMiptex(const char *name, std::optional<extended_texinfo_t> &extended_inf
const char *pathsep;
int i;
// FIXME: figure out a way that we can move this to gamedef
if (options.target_game->id != GAME_QUAKE_II) {
/* Ignore leading path in texture names (Q2 map compatibility) */
pathsep = strrchr(name, '/');
@ -346,6 +347,8 @@ static surfflags_t SurfFlagsForEntity(const mtexinfo_t &texinfo, const mapentity
// into a special function, like.. I dunno,
// game->surface_flags_from_name(surfflags_t &inout, const char *name)
// which we can just call instead of this block.
// the only annoyance is we can't access the various options (noskip,
// splitturb, etc) from there.
if (options.target_game->id != GAME_QUAKE_II) {
if (IsSkipName(texname))
flags.is_skip = true;
@ -455,20 +458,6 @@ static void ParseEpair(parser_t &parser, mapentity_t *entity)
if (string_iequals(key, "origin")) {
GetVectorForKey(entity, key.c_str(), entity->origin);
} else if (string_iequals(key, "classname")) {
if (string_iequals(parser.token, "info_player_start")) {
// Quake II uses multiple starts for level transitions/backtracking.
// TODO: instead, this should check targetnames. There should only be
// one info_player_start per targetname in Q2.
if (options.target_game->id != GAME_QUAKE_II && (map.start_spots.has_info_player_start())) {
logging::print("WARNING: Multiple info_player_start entities\n");
}
map.start_spots.set_info_player_start(true);
} else if (string_iequals(parser.token, "info_player_deathmatch")) {
map.start_spots.set_info_player_deathmatch(true);
} else if (string_iequals(parser.token, "info_player_coop")) {
map.start_spots.set_info_player_coop(true);
}
}
}
@ -1947,14 +1936,6 @@ void LoadMapFile(void)
map.entities.pop_back();
}
// Print out warnings for entities
if (!map.start_spots.has_info_player_start())
logging::print("WARNING: No info_player_start entity in level\n");
if (!map.start_spots.has_info_player_deathmatch())
logging::print("WARNING: No info_player_deathmatch entities in level\n");
// if (!(map.start_spots & info_player_coop))
// logging::print("WARNING: No info_player_coop entities in level\n");
logging::print(logging::flag::STAT, " {:8} faces\n", map.faces.size());
logging::print(logging::flag::STAT, " {:8} brushes\n", map.brushes.size());
logging::print(logging::flag::STAT, " {:8} entities\n", map.entities.size());