Files
Server/src/engine/devcmd/cmds/AddBuildingCmd.java
T
MagicBotandClaude Opus 5.5 bd3787f9d5 Refuse dev commands that would change static world objects
World Boot Task 0.6. Static objects are built from client data each boot,
so dev commands answer "Must use external tooling to modify gameworld" and
log the command, target and caller instead of changing them.

- /addbuilding, /mob and /npc always refuse (addsWorldContent hook in doCmd).
- rotate, pull, setbuildingaltitude, remove, rename, npcname, setowner,
  setguild, setrank and forcerename refuse a static target.
- purge skips static objects and reports how many it skipped.

Value changes: none for non-static objects; the purge message now also
reports the skipped count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 18:57:40 -04:00

127 lines
4.1 KiB
Java

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.devcmd.cmds;
import engine.InterestManagement.WorldGrid;
import engine.devcmd.AbstractDevCmd;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager;
import engine.gameManager.ZoneManager;
import engine.math.Quaternion;
import engine.math.Vector3fImmutable;
import engine.mbEnums.ProtectionState;
import engine.objects.*;
import engine.server.MBServerStatics;
public class AddBuildingCmd extends AbstractDevCmd {
public AddBuildingCmd() {
super("addbuilding");
// super("addbuilding", MBServerStatics.ACCESS_GROUP_DESIGNER_UP, 0, false, true);
this.addCmdString("building");
}
@Override
protected void _doCmd(PlayerCharacter pc, String[] words,
AbstractGameObject target) {
// Arg Count Check
if (words.length != 2) {
this.sendUsage(pc);
return;
}
int ID;
int rank;
Blueprint blueprint;
try {
ID = Integer.parseInt(words[0]);
rank = Integer.parseInt(words[1]);
} catch (Exception e) {
throwbackError(pc, "Invalid addBuilding Command. Need Building ID and rank.");
return; // NaN
}
if (ID < 1) {
throwbackError(pc,
"Invalid addBuilding Command. Invalid Building ID.");
return;
}
Quaternion rotation = new Quaternion();
Zone zone = ZoneManager.findSmallestZone(pc.getLoc());
if (zone == null) {
throwbackError(pc, "Failed to find zone to place building in.");
return;
}
blueprint = Blueprint.getBlueprint(ID);
if ((blueprint != null) && (rank > blueprint.getMaxRank())) {
throwbackError(pc, rank + " is not a valid rank for this building");
return;
}
Building likeBuilding = DbManager.BuildingQueries.GET_BUILDING_BY_MESH(ID);
if (likeBuilding != null) {
rotation = likeBuilding.getRotation();
}
String buildingName = "";
int blueprintUUID = 0;
Vector3fImmutable localLoc = ZoneManager.worldToLocal(pc.getLoc(), zone);
if (localLoc == null)
return;
if (blueprint != null) {
buildingName = blueprint.getName();
blueprintUUID = blueprint.getBlueprintUUID();
}
Building building = Building.persistBuilding(Building.createBuilding(
zone, 0, buildingName, ID,
localLoc, 1.0f, 0, ProtectionState.PROTECTED, 0, rank,
null, blueprintUUID, rotation.w, rotation.y));
if (building == null) {
throwbackError(pc, "Failed to add building.");
return;
}
building.setObjectTypeMask(MBServerStatics.MASK_BUILDING);
WorldGrid.addObject(building, pc);
ChatManager.chatSayInfo(pc,
"Building with ID " + building.getObjectUUID() + " added");
this.setResult(String.valueOf(building.getObjectUUID()));
}
@Override
protected boolean addsWorldContent() {
return true;
}
@Override
protected String _getHelpString() {
return "Creates a building of type 'buildingID' at the location your character is standing.";
}
@Override
protected String _getUsageString() {
return "' /addbuilding buildingID rank' || ' /building buildingID rank'";
}
}