feat: testmap improvements (#2009)

* feat: testmap improvements

fixes #1191

removed the force flag because it would only work to let you softlock your character.

tested that taking the lego club door now spawns you at the lego club/ns lego club doors always vs letting you spawn where ever.

tested that a testmap no longer spawns you where you last were in a zone and instead spawns you at the spawn point

inspect allows you to inspect zoneControl and localCharacter now
updated docs with the new info

* Update Entity.cpp
This commit is contained in:
David Markowitz
2026-06-20 15:10:13 -07:00
committed by GitHub
parent 135aec8112
commit ccad52a5ce
5 changed files with 41 additions and 22 deletions

View File

@@ -261,7 +261,7 @@ void SlashCommandHandler::Startup() {
Command TestMapCommand{
.help = "Transfers you to the given zone",
.info = "Transfers you to the given zone by id and clone id. Add \"force\" to skip checking if the zone is accessible (this can softlock your character, though, if you e.g. try to teleport to Frostburgh).",
.info = "Transfers you to the given zone by id and clone id and then spawns you at the specified spawn point if one was specified. Ignores instance-id for now.",
.aliases = { "testmap", "tm" },
.handle = DEVGMCommands::TestMap,
.requiredLevel = eGameMasterLevel::FORUM_MODERATOR
@@ -468,7 +468,7 @@ void SlashCommandHandler::Startup() {
Command InspectCommand{
.help = "Inspect an object",
.info = "Finds the closest entity with the given component or LNV variable (ignoring players and racing cars), printing its ID, distance from the player, and whether it is sleeping, as well as the the IDs of all components the entity has. See detailed usage in the DLU docs",
.info = "Finds the closest entity with the given component or LNV variable (ignoring players and racing cars), printing its ID, distance from the player, and whether it is sleeping, as well as the IDs of all components the entity has. Use `localCharacter` or `zoneControl` to inspect your current character or the zone control object.",
.aliases = { "inspect" },
.handle = DEVGMCommands::Inspect,
.requiredLevel = eGameMasterLevel::DEVELOPER

View File

@@ -1051,7 +1051,8 @@ namespace DEVGMCommands {
ChatPackets::SendSystemMessage(sysAddr, u"Requesting map change...");
LWOCLONEID cloneId = 0;
bool force = false;
LWOINSTANCEID instanceID{};
std::string targetScene;
const auto reqZoneOptional = GeneralUtils::TryParse<LWOMAPID>(splitArgs[0]);
if (!reqZoneOptional) {
@@ -1061,29 +1062,34 @@ namespace DEVGMCommands {
const LWOMAPID reqZone = reqZoneOptional.value();
if (splitArgs.size() > 1) {
auto index = 1;
if (splitArgs[index] == "force") {
index++;
force = true;
const auto cloneIdOptional = GeneralUtils::TryParse<LWOCLONEID>(splitArgs[1]);
if (!cloneIdOptional) {
ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone id.");
return;
}
if (splitArgs.size() > index) {
const auto cloneIdOptional = GeneralUtils::TryParse<LWOCLONEID>(splitArgs[index]);
if (!cloneIdOptional) {
ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone id.");
cloneId = cloneIdOptional.value();
if (splitArgs.size() > 2) {
const auto instanceIDVal = GeneralUtils::TryParse<LWOINSTANCEID>(splitArgs[2]);
if (!instanceIDVal) {
ChatPackets::SendSystemMessage(sysAddr, u"Invalid instance id.");
return;
}
cloneId = cloneIdOptional.value();
instanceID = instanceIDVal.value();
}
if (splitArgs.size() > 3) {
targetScene = splitArgs[3];
}
}
const auto objid = entity->GetObjectID();
if (force || Game::zoneManager->CheckIfAccessibleZone(reqZone)) { // to prevent tomfoolery
if (Game::zoneManager->CheckIfAccessibleZone(reqZone)) { // to prevent tomfoolery
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, reqZone, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) {
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, reqZone, cloneId, false, [objid, targetScene](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) {
auto* entity = Game::entityManager->GetEntity(objid);
if (!entity) return;
@@ -1101,6 +1107,7 @@ namespace DEVGMCommands {
entity->GetCharacter()->SetZoneID(zoneID);
entity->GetCharacter()->SetZoneInstance(zoneInstance);
entity->GetCharacter()->SetZoneClone(zoneClone);
entity->GetCharacter()->SetTargetScene(targetScene);
entity->GetComponent<CharacterComponent>()->SetLastRocketConfig(u"");
}
@@ -1513,7 +1520,15 @@ namespace DEVGMCommands {
void Inspect(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
const auto splitArgs = GeneralUtils::SplitString(args, ' ');
if (splitArgs.empty()) return;
const auto idParsed = GeneralUtils::TryParse<LWOOBJID>(splitArgs[0]);
std::optional<LWOOBJID> idIntermed;
if (splitArgs[0] == "zoneControl") {
idIntermed = 0x3FFF'FFFFFFFE;
} else if (splitArgs[0] == "localCharacter") {
idIntermed = entity->GetObjectID();
} else {
idIntermed = GeneralUtils::TryParse<LWOOBJID>(splitArgs[0]);
}
const auto idParsed = idIntermed;
// First try to get the object by its ID if provided.
// Second try to get the object by player name.