mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-06 03:47:13 +00:00
chore: remove the scene point spawn commands and send /getadjacentscenes as one message
The spawn commands were only for testing. /getscene and /getadjacentscenes stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -835,23 +835,6 @@ void SlashCommandHandler::Startup() {
|
||||
};
|
||||
RegisterCommand(GetAdjacentScenesCommand);
|
||||
|
||||
Command SpawnScenePointsCommand{
|
||||
.help = "Spawn bricks at points across your current scene",
|
||||
.info = "Spawns bricks across the player's current scene using terrain scene map data, one every <step> heightmap points (default 8). Usage: /spawnscenepoints (step)",
|
||||
.aliases = { "spawnscenepoints" },
|
||||
.handle = DEVGMCommands::SpawnScenePoints,
|
||||
.requiredLevel = eGameMasterLevel::DEVELOPER
|
||||
};
|
||||
RegisterCommand(SpawnScenePointsCommand);
|
||||
|
||||
Command SpawnAllScenePointsCommand{
|
||||
.help = "Spawn bricks across all scenes in the zone",
|
||||
.info = "Spawns bricks across every scene in the zone, one every <step> heightmap points (default 8; 1 = every point, a massive number of entities). Usage: /spawnallscenepoints (step)",
|
||||
.aliases = { "spawnallscenepoints", "spawnallscenes" },
|
||||
.handle = DEVGMCommands::SpawnAllScenePoints,
|
||||
.requiredLevel = eGameMasterLevel::DEVELOPER
|
||||
};
|
||||
RegisterCommand(SpawnAllScenePointsCommand);
|
||||
|
||||
// Register Greater Than Zero Commands
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "DEVGMCommands.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
|
||||
// Classes
|
||||
@@ -25,8 +24,6 @@
|
||||
|
||||
// Database
|
||||
#include "Database.h"
|
||||
#include "CDClientManager.h"
|
||||
#include "CDBrickIDTableTable.h"
|
||||
#include "CDObjectsTable.h"
|
||||
#include "CDRewardCodesTable.h"
|
||||
#include "CDLootMatrixTable.h"
|
||||
@@ -1894,19 +1891,6 @@ namespace DEVGMCommands {
|
||||
}
|
||||
}
|
||||
|
||||
// A different LEGO brick per scene so the scenes can be told apart, from the BrickIDTable (every brick's LOT)
|
||||
static LOT GetScenePointLot(uint8_t sceneID) {
|
||||
static const std::vector<LOT> brickLots = [] {
|
||||
std::vector<LOT> lots;
|
||||
for (const auto& brick : CDClientManager::GetTable<CDBrickIDTableTable>()->Query([](const CDBrickIDTable&) { return true; })) {
|
||||
lots.push_back(brick.NDObjectID);
|
||||
}
|
||||
std::ranges::sort(lots);
|
||||
return lots;
|
||||
}();
|
||||
return brickLots.empty() ? LOT_NULL : brickLots[sceneID % brickLots.size()];
|
||||
}
|
||||
|
||||
void GetScene(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||
const auto position = entity->GetPosition();
|
||||
|
||||
@@ -1964,171 +1948,23 @@ namespace DEVGMCommands {
|
||||
// Get adjacent scenes
|
||||
const auto adjacentSceneIDs = Game::zoneManager->GetAdjacentScenes(sceneID);
|
||||
|
||||
if (adjacentSceneIDs.empty()) {
|
||||
std::ostringstream feedback;
|
||||
feedback << "Current Scene: " << sceneID.GetSceneID() << " (" << currentSceneName << ")";
|
||||
feedback << " - No adjacent scenes found.";
|
||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(feedback.str()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Build the feedback message with current scene
|
||||
std::ostringstream feedback;
|
||||
feedback << "Current Scene: " << sceneID.GetSceneID() << " (" << currentSceneName << ")";
|
||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(feedback.str()));
|
||||
|
||||
// List all adjacent scenes
|
||||
feedback.str("");
|
||||
feedback << "Adjacent Scenes (" << adjacentSceneIDs.size() << "):";
|
||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(feedback.str()));
|
||||
|
||||
for (const auto& adjSceneID : adjacentSceneIDs) {
|
||||
feedback.str("");
|
||||
feedback << " - Scene ID: " << adjSceneID.GetSceneID();
|
||||
feedback << " (Layer: " << adjSceneID.GetLayerID() << ")";
|
||||
|
||||
// Get the scene name if available
|
||||
const auto* sceneRef = zone->GetScene(adjSceneID);
|
||||
if (sceneRef && !sceneRef->name.empty()) {
|
||||
feedback << " - " << sceneRef->name;
|
||||
}
|
||||
|
||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(feedback.str()));
|
||||
}
|
||||
}
|
||||
if (adjacentSceneIDs.empty()) {
|
||||
feedback << " - No adjacent scenes found.";
|
||||
} else {
|
||||
feedback << "\nAdjacent Scenes (" << adjacentSceneIDs.size() << "):";
|
||||
for (const auto& adjSceneID : adjacentSceneIDs) {
|
||||
feedback << "\n - Scene ID: " << adjSceneID.GetSceneID() << " (Layer: " << adjSceneID.GetLayerID() << ")";
|
||||
|
||||
void SpawnScenePoints(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||
// Spawn one brick every <step> heightmap points (default 8)
|
||||
const auto parsedStep = GeneralUtils::TryParse<uint32_t>(args);
|
||||
const uint32_t step = parsedStep && *parsedStep > 0 ? *parsedStep : 8;
|
||||
|
||||
// Get player's current position and scene
|
||||
const auto position = entity->GetPosition();
|
||||
const auto currentSceneID = Game::zoneManager->GetSceneIDFromPosition(position);
|
||||
if (currentSceneID == LWOSCENEID_INVALID) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"No scene found at current position.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the zone
|
||||
const auto* zone = Game::zoneManager->GetZone();
|
||||
if (!zone) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"No zone loaded.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the Raw terrain data
|
||||
const auto& raw = zone->GetZoneRaw();
|
||||
if (raw.chunks.empty()) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Zone does not have valid terrain data.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t spawnedCount = 0;
|
||||
|
||||
for (const auto& chunk : raw.chunks) {
|
||||
if (!chunk.IsValidForSceneLookup()) continue;
|
||||
|
||||
for (uint32_t i = 0; i < chunk.width; i += step) {
|
||||
for (uint32_t j = 0; j < chunk.height; j += step) {
|
||||
const uint8_t sceneID = chunk.GetSceneIDAtGrid(i, j);
|
||||
if (sceneID != currentSceneID.GetSceneID()) continue;
|
||||
|
||||
EntityInfo info;
|
||||
info.lot = GetScenePointLot(sceneID);
|
||||
info.pos = chunk.GridToWorldPos(i, j);
|
||||
info.rot = QuatUtils::IDENTITY;
|
||||
info.spawner = nullptr;
|
||||
info.spawnerID = entity->GetObjectID();
|
||||
info.spawnerNodeID = 0;
|
||||
info.settings.Insert(u"SpawnedFromSlashCommand", true);
|
||||
|
||||
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
|
||||
if (newEntity != nullptr) {
|
||||
Game::entityManager->ConstructEntity(newEntity);
|
||||
spawnedCount++;
|
||||
}
|
||||
// Get the scene name if available
|
||||
const auto* sceneRef = zone->GetScene(adjSceneID);
|
||||
if (sceneRef && !sceneRef->name.empty()) {
|
||||
feedback << " - " << sceneRef->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spawnedCount == 0) {
|
||||
std::ostringstream feedback;
|
||||
feedback << "No spawn points found in current scene (ID: " << currentSceneID.GetSceneID() << ").";
|
||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(feedback.str()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Send feedback
|
||||
const auto* sceneRef = zone->GetScene(currentSceneID);
|
||||
const std::string sceneName = sceneRef ? sceneRef->name : "Unknown";
|
||||
std::ostringstream feedback;
|
||||
feedback << "Spawned " << spawnedCount << " points (LOT " << GetScenePointLot(currentSceneID.GetSceneID()) << ") in scene "
|
||||
<< currentSceneID.GetSceneID() << " (" << sceneName << ").";
|
||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(feedback.str()));
|
||||
}
|
||||
|
||||
void SpawnAllScenePoints(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||
// Spawn one brick every <step> heightmap points (default 8)
|
||||
const auto parsedStep = GeneralUtils::TryParse<uint32_t>(args);
|
||||
const uint32_t step = parsedStep && *parsedStep > 0 ? *parsedStep : 8;
|
||||
|
||||
// Get the zone
|
||||
const auto* zone = Game::zoneManager->GetZone();
|
||||
if (!zone) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"No zone loaded.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the Raw terrain data
|
||||
const auto& raw = zone->GetZoneRaw();
|
||||
if (raw.chunks.empty()) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Zone does not have valid terrain data.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t spawnedCount = 0;
|
||||
std::map<uint8_t, uint32_t> sceneSpawnCounts;
|
||||
|
||||
for (const auto& chunk : raw.chunks) {
|
||||
if (!chunk.IsValidForSceneLookup()) continue;
|
||||
|
||||
for (uint32_t i = 0; i < chunk.width; i += step) {
|
||||
for (uint32_t j = 0; j < chunk.height; j += step) {
|
||||
const uint8_t sceneID = chunk.GetSceneIDAtGrid(i, j);
|
||||
if (sceneID == 0) continue;
|
||||
|
||||
EntityInfo info;
|
||||
info.lot = GetScenePointLot(sceneID);
|
||||
info.pos = chunk.GridToWorldPos(i, j);
|
||||
info.rot = QuatUtils::IDENTITY;
|
||||
info.spawner = nullptr;
|
||||
info.spawnerID = entity->GetObjectID();
|
||||
info.spawnerNodeID = 0;
|
||||
info.settings.Insert(u"SpawnedFromSlashCommand", true);
|
||||
|
||||
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
|
||||
if (newEntity != nullptr) {
|
||||
Game::entityManager->ConstructEntity(newEntity);
|
||||
spawnedCount++;
|
||||
sceneSpawnCounts[sceneID]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send detailed feedback
|
||||
std::ostringstream feedback;
|
||||
feedback << "Spawned " << spawnedCount << " total points across "
|
||||
<< sceneSpawnCounts.size() << " scenes:\n";
|
||||
|
||||
for (const auto& [sceneID, count] : sceneSpawnCounts) {
|
||||
const auto* sceneRef = zone->GetScene(LWOSCENEID(sceneID));
|
||||
const std::string sceneName = sceneRef ? sceneRef->name : "Unknown";
|
||||
feedback << " Scene " << static_cast<int>(sceneID) << ", LOT: " << GetScenePointLot(sceneID) << " (" << sceneName << "): " << count << " points\n";
|
||||
}
|
||||
|
||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(feedback.str()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -79,8 +79,6 @@ namespace DEVGMCommands {
|
||||
void Execute(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||
void GetScene(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||
void GetAdjacentScenes(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||
void SpawnScenePoints(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||
void SpawnAllScenePoints(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||
}
|
||||
|
||||
#endif //!DEVGMCOMMANDS_H
|
||||
|
||||
@@ -145,8 +145,6 @@ These commands are primarily for development and testing. The usage of many of t
|
||||
|getnavmeshheight|`/getnavmeshheight`|Display the navmesh height at your current position|8|
|
||||
|getscene|`/getscene`|Display the scene ID and name at your current position (alias `/scene`)|8|
|
||||
|getadjacentscenes|`/getadjacentscenes`|List the scenes connected to your current scene by scene transitions (alias `/adjacentscenes`)|8|
|
||||
|spawnscenepoints|`/spawnscenepoints (step)`|Spawns a brick every `step` terrain points (default 8) across your current scene|8|
|
||||
|spawnallscenepoints|`/spawnallscenepoints (step)`|Spawns a brick every `step` terrain points (default 8) across every scene, one brick type per scene (alias `/spawnallscenes`)|8|
|
||||
|giveuscore|`/giveuscore <uscore>`|Gives uscore|8|
|
||||
|gmadditem|`/gmadditem <id> (count)`|Adds the given item to your inventory by id. Aliases: `/give`.|8|
|
||||
|inspect|`/inspect <component or ldf variable or player name> (-m <waypoint> | -a <animation> | -s | -p | -f (faction) | -t)`|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.|8|
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include <fstream>
|
||||
|
||||
#include "AssetManager.h"
|
||||
#include "CDBrickIDTableTable.h"
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
#include "CDZoneTableTable.h"
|
||||
#include "DEVGMCommands.h"
|
||||
#include "Entity.h"
|
||||
@@ -230,41 +228,16 @@ TEST_F(ZoneSceneTest, UnreadableRawStillLoadsTheZone) {
|
||||
EXPECT_EQ(Game::zoneManager->GetSceneIDFromPosition(NiPoint3(0.5f, 0.0f, 0.5f)), LWOSCENEID_INVALID);
|
||||
}
|
||||
|
||||
TEST_F(ZoneSceneTest, ScenePointCommandsSpawnBricks) {
|
||||
TEST_F(ZoneSceneTest, SceneCommandsReport) {
|
||||
WriteZone();
|
||||
WriteFile("test.raw", MakeRaw());
|
||||
LoadZone();
|
||||
|
||||
auto& bricks = CDClientManager::GetEntriesMutable<CDBrickIDTableTable>();
|
||||
bricks = { { 40, 3005 }, { 33, 3001 }, { 35, 3003 } };
|
||||
// the bricks have no components, so creating them needs no client database
|
||||
for (const LOT lot : { 33, 35, 40 }) CDClientManager::GetEntriesMutable<CDComponentsRegistryTable>()[lot] = 0;
|
||||
|
||||
EntityInfo playerInfo = info;
|
||||
playerInfo.pos = NiPoint3(0.5f, 0.0f, 0.5f); // scene 1
|
||||
auto player = std::make_unique<Entity>(1, playerInfo);
|
||||
|
||||
// Grid point (i, j) is at (2i, 2j); its scene cell is (min(i, 1), min(j, 1)), so of the 9 points scene 1 has 5,
|
||||
// scene 2 has 2 ((0, 1), (0, 2)) and scene 3 has 2 ((1, 0), (2, 0))
|
||||
DEVGMCommands::SpawnScenePoints(player.get(), UNASSIGNED_SYSTEM_ADDRESS, "1");
|
||||
// bricks sorted by LOT: 33, 35, 40; scene 1 -> 35, scene 2 -> 40, scene 3 -> 33
|
||||
const auto sceneOne = Game::entityManager->GetEntitiesByLOT(35);
|
||||
EXPECT_EQ(sceneOne.size(), 5);
|
||||
for (const auto* brick : sceneOne) EXPECT_EQ(Game::zoneManager->GetSceneIDFromPosition(brick->GetPosition()), LWOSCENEID(1, 0));
|
||||
EXPECT_TRUE(Game::entityManager->GetEntitiesByLOT(40).empty());
|
||||
|
||||
// the default step of 8 only samples point (0, 0)
|
||||
DEVGMCommands::SpawnAllScenePoints(player.get(), UNASSIGNED_SYSTEM_ADDRESS, "");
|
||||
EXPECT_EQ(Game::entityManager->GetEntitiesByLOT(35).size(), 5 + 1);
|
||||
EXPECT_TRUE(Game::entityManager->GetEntitiesByLOT(40).empty());
|
||||
|
||||
DEVGMCommands::SpawnAllScenePoints(player.get(), UNASSIGNED_SYSTEM_ADDRESS, "1");
|
||||
EXPECT_EQ(Game::entityManager->GetEntitiesByLOT(35).size(), 6 + 5);
|
||||
EXPECT_EQ(Game::entityManager->GetEntitiesByLOT(40).size(), 2);
|
||||
EXPECT_EQ(Game::entityManager->GetEntitiesByLOT(33).size(), 2);
|
||||
|
||||
// the scene commands only report; they must not fail with or without scene data
|
||||
// the scene commands only report; they must not fail
|
||||
DEVGMCommands::GetScene(player.get(), UNASSIGNED_SYSTEM_ADDRESS, "");
|
||||
DEVGMCommands::GetAdjacentScenes(player.get(), UNASSIGNED_SYSTEM_ADDRESS, "");
|
||||
bricks.clear();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user