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:
parent
81686200c3
commit
b2a0f8039e
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
25
qbsp/map.cc
25
qbsp/map.cc
|
|
@ -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());
|
||||
|
|
|
|||
Loading…
Reference in New Issue