fix(triggers): the spawner network deactivate command as the game names it

The shipped trigger files name the command DectivateSpawnerNetwork. The server
now reads that name as the deactivate spawner network command, so those triggers
run, and the edited file checks take it. The correctly spelt name stays as an alias.
The shipped files test no longer lets unknown trigger ids through for the
retail clients.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-11-10 20:09:06 -06:00
parent 99b9e580e7
commit b6636de0d9
3 changed files with 19 additions and 2 deletions

View File

@@ -104,7 +104,8 @@ public:
{ "setModelToBuild", eTriggerCommandType::SET_MODEL_TO_BUILD},
{ "spawnModelBricks", eTriggerCommandType::SPAWN_MODEL_BRICKS},
{ "ActivateSpawnerNetwork", eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK},
{ "DeactivateSpawnerNetwork", eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK},
{ "DectivateSpawnerNetwork", eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK}, // the name the game's trigger files use (fv_pp_01_instance.lutriggers)
{ "DeactivateSpawnerNetwork", eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK}, // alias, kept for anything written with the correct spelling
{ "ResetSpawnerNetwork", eTriggerCommandType::RESET_SPAWNER_NETWORK},
{ "DestroySpawnerNetworkObjects", eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS},
{ "Go_To_Waypoint", eTriggerCommandType::GO_TO_WAYPOINT},

View File

@@ -177,7 +177,12 @@ TEST_F(ClientZoneFilesTests, PublishChecksTakeEveryClientFile) {
// What must never happen is a file the game ships reading as damaged. Triggers and object settings
// the server doesn't know are in shipped files (a misspelt command in one live zone, more in test
// maps), and so are test maps' zone files from before launch with bytes after their last part.
if (problem.code != "parse_failed") continue;
// Retail files must pass the trigger checks as they are. The pre-launch builds (the 0.179 client and the
// alpha leaks) have test maps with commands and events from before launch that the server doesn't know.
const auto text = path.generic_string();
const bool preLaunch = text.find("/0.179.12/") != std::string::npos || text.find("/leaks/") != std::string::npos;
if (problem.code.starts_with("unknown_trigger") && preLaunch) continue;
if (problem.code != "parse_failed" && !problem.code.starts_with("unknown_trigger")) continue;
if (name.ends_with(".luz") && version < static_cast<uint32_t>(ZoneFile::FileFormatVersion::Launch)) continue;
ADD_FAILURE() << path << ": " << problem.code << ": " << problem.message << (problem.offset ? " at " + std::to_string(*problem.offset) : "");
}

View File

@@ -10,6 +10,9 @@
#include "ZoneEditLock.h"
#include "ZoneOverrideStore.h"
#include "ZonePublish.h"
#include <map>
#include <string>
#include "eTriggerCommandType.h"
namespace fs = std::filesystem;
@@ -316,6 +319,14 @@ TEST_F(ZonePublishTests, TriggerChecks) {
EXPECT_EQ(ZonePublish::CheckTriggers("<other/>").at(0).code, "parse_failed");
EXPECT_TRUE(ZonePublish::CheckTriggers("").empty());
EXPECT_TRUE(ZonePublish::CheckTriggers(GOOD_TRIGGERS).empty());
// The name the game's fv_pp_01_instance.lutriggers uses is the deactivate command, a different misspelling is not
EXPECT_TRUE(ZonePublish::CheckTriggers("<triggers><trigger id=\"1\"><event id=\"OnCreate\">"
"<command id=\"DectivateSpawnerNetwork\" target=\"objGroup\"/></event></trigger></triggers>").empty());
EXPECT_EQ(TriggerCommandType::StringToTriggerCommandType("DectivateSpawnerNetwork"), eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK);
EXPECT_EQ(TriggerCommandType::StringToTriggerCommandType("DeactivateSpawnerNetwork"), eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK);
EXPECT_EQ(ZonePublish::CheckTriggers("<triggers><trigger id=\"1\"><event id=\"OnCreate\">"
"<command id=\"DectivateSpawnerNetworks\" target=\"objGroup\"/></event></trigger></triggers>").at(0).code, "unknown_trigger_command");
}
TEST_F(ZonePublishTests, BadObjectConfigAndObjectCap) {