From b6636de0d92a5fc6a2a97766d75c71aaa7a52f82 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Tue, 10 Nov 2026 20:09:06 -0600 Subject: [PATCH] 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 --- dCommon/dEnums/eTriggerCommandType.h | 3 ++- tests/dCommonTests/ClientZoneFilesTests.cpp | 7 ++++++- tests/dCommonTests/ZonePublishTests.cpp | 11 +++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/dCommon/dEnums/eTriggerCommandType.h b/dCommon/dEnums/eTriggerCommandType.h index fadfafb86..10936527e 100644 --- a/dCommon/dEnums/eTriggerCommandType.h +++ b/dCommon/dEnums/eTriggerCommandType.h @@ -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}, diff --git a/tests/dCommonTests/ClientZoneFilesTests.cpp b/tests/dCommonTests/ClientZoneFilesTests.cpp index 561d0f978..c165a1c48 100644 --- a/tests/dCommonTests/ClientZoneFilesTests.cpp +++ b/tests/dCommonTests/ClientZoneFilesTests.cpp @@ -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(ZoneFile::FileFormatVersion::Launch)) continue; ADD_FAILURE() << path << ": " << problem.code << ": " << problem.message << (problem.offset ? " at " + std::to_string(*problem.offset) : ""); } diff --git a/tests/dCommonTests/ZonePublishTests.cpp b/tests/dCommonTests/ZonePublishTests.cpp index fbe801860..86d960456 100644 --- a/tests/dCommonTests/ZonePublishTests.cpp +++ b/tests/dCommonTests/ZonePublishTests.cpp @@ -10,6 +10,9 @@ #include "ZoneEditLock.h" #include "ZoneOverrideStore.h" #include "ZonePublish.h" +#include +#include +#include "eTriggerCommandType.h" namespace fs = std::filesystem; @@ -316,6 +319,14 @@ TEST_F(ZonePublishTests, TriggerChecks) { EXPECT_EQ(ZonePublish::CheckTriggers("").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("" + "").empty()); + EXPECT_EQ(TriggerCommandType::StringToTriggerCommandType("DectivateSpawnerNetwork"), eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK); + EXPECT_EQ(TriggerCommandType::StringToTriggerCommandType("DeactivateSpawnerNetwork"), eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK); + EXPECT_EQ(ZonePublish::CheckTriggers("" + "").at(0).code, "unknown_trigger_command"); } TEST_F(ZonePublishTests, BadObjectConfigAndObjectCap) {