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>
253 lines
9.0 KiB
Java
253 lines
9.0 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.BuildingManager;
|
|
import engine.gameManager.ChatManager;
|
|
import engine.gameManager.DbManager;
|
|
import engine.math.FastMath;
|
|
import engine.math.Quaternion;
|
|
import engine.math.Vector3fImmutable;
|
|
import engine.objects.*;
|
|
|
|
public class RotateCmd extends AbstractDevCmd {
|
|
|
|
public RotateCmd() {
|
|
super("rotate");
|
|
this.addCmdString("rot");
|
|
}
|
|
|
|
@Override
|
|
protected void _doCmd(PlayerCharacter pc, String[] words,
|
|
AbstractGameObject target) {
|
|
if (target == null && (words.length != 2)) {
|
|
this.sendUsage(pc);
|
|
return;
|
|
}
|
|
|
|
|
|
if (words.length == 3) {
|
|
try {
|
|
|
|
} catch (Exception e) {
|
|
|
|
}
|
|
}
|
|
|
|
|
|
float rot;
|
|
if (target != null && words.length == 1) {
|
|
|
|
try {
|
|
if (words[0].equalsIgnoreCase("face")) {
|
|
this.rotateFace(pc, target);
|
|
return;
|
|
}
|
|
|
|
rot = Float.parseFloat(words[0]);
|
|
} catch (NumberFormatException e) {
|
|
throwbackError(pc, "Supplied rotation " + words[0]
|
|
+ " failed to parse to a Float");
|
|
return;
|
|
} catch (Exception e) {
|
|
throwbackError(pc,
|
|
"Invalid Rotate Command. Need Rotation specified.");
|
|
return;
|
|
}
|
|
|
|
if (target instanceof Building)
|
|
rotateBuilding(pc, (Building) target, (float) Math.toRadians(rot));
|
|
else if (target instanceof NPC)
|
|
rotateNPC(pc, (NPC) target, (float) Math.toRadians(rot));
|
|
else if (target instanceof Mob)
|
|
rotateMob(pc, (Mob) target, (float) Math.toRadians(rot));
|
|
else
|
|
throwbackError(pc, "Target " + target.getObjectType()
|
|
+ " is not a valid object type");
|
|
} else {
|
|
|
|
int id = 0;
|
|
if (words.length == 2) {
|
|
try {
|
|
id = Integer.parseInt(words[0]);
|
|
|
|
if (words[1].equalsIgnoreCase("face")) {
|
|
|
|
Building b;
|
|
if (id != 0)
|
|
b = BuildingManager.getBuilding(id);
|
|
else
|
|
b = getTargetAsBuilding(pc);
|
|
if (b != null) {
|
|
rotateFace(pc, b);
|
|
return;
|
|
}
|
|
|
|
// building failed, try npc
|
|
NPC npc;
|
|
if (id != 0)
|
|
npc = NPC.getNPC(id);
|
|
else
|
|
npc = getTargetAsNPC(pc);
|
|
if (npc != null) {
|
|
rotateFace(pc, npc);
|
|
return;
|
|
}
|
|
|
|
// NPC failed, try mob
|
|
Mob mob;
|
|
if (id != 0)
|
|
mob = Mob.getMob(id);
|
|
else
|
|
mob = getTargetAsMob(pc);
|
|
if (mob != null) {
|
|
rotateFace(pc, mob);
|
|
return;
|
|
}
|
|
throwbackError(pc, "Nothing found to rotate.");
|
|
return;
|
|
}
|
|
rot = Float.parseFloat(words[1]);
|
|
} catch (NumberFormatException e) {
|
|
throwbackError(pc, "Supplied arguments " + words[0] + ' '
|
|
+ words[1] + " failed to parse");
|
|
return;
|
|
} catch (Exception e) {
|
|
throwbackError(pc,
|
|
"Invalid Rotate Command. Need Rotation specified.");
|
|
return; // NaN
|
|
}
|
|
} else {
|
|
try {
|
|
rot = Float.parseFloat(words[0]);
|
|
} catch (NumberFormatException e) {
|
|
throwbackError(pc, "Supplied rotation " + words[0]
|
|
+ " failed to parse to a Float");
|
|
return;
|
|
} catch (Exception e) {
|
|
throwbackError(pc,
|
|
"Invalid Rotate Command. Need Rotation specified.");
|
|
return; // NaN
|
|
}
|
|
}
|
|
|
|
Building b;
|
|
if (id != 0)
|
|
b = BuildingManager.getBuilding(id);
|
|
else
|
|
b = getTargetAsBuilding(pc);
|
|
if (b != null) {
|
|
rotateBuilding(pc, b, (float) Math.toRadians(rot));
|
|
return;
|
|
}
|
|
|
|
// building failed, try npc
|
|
NPC npc;
|
|
if (id != 0)
|
|
npc = NPC.getNPC(id);
|
|
else
|
|
npc = getTargetAsNPC(pc);
|
|
if (npc != null) {
|
|
rotateNPC(pc, npc, (float) Math.toRadians(rot));
|
|
return;
|
|
}
|
|
|
|
// NPC failed, try mob
|
|
Mob mob;
|
|
if (id != 0)
|
|
mob = Mob.getMob(id);
|
|
else
|
|
mob = getTargetAsMob(pc);
|
|
if (mob != null) {
|
|
rotateMob(pc, mob, (float) Math.toRadians(rot));
|
|
return;
|
|
}
|
|
throwbackError(pc, "Nothing found to rotate.");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected String _getHelpString() {
|
|
return "Rotates targeted or specified object";
|
|
}
|
|
|
|
@Override
|
|
protected String _getUsageString() {
|
|
return "' /rotate [objectID] degrees' || ' /rot [objectID] degrees' || ' /rotate face'";
|
|
}
|
|
|
|
private void rotateBuilding(PlayerCharacter pc, Building building, float yaw) {
|
|
|
|
if (this.refuseStaticTarget(pc, building))
|
|
return;
|
|
|
|
building.setRotation(Quaternion.fromYaw(yaw));
|
|
building.getBounds().setBounds(building);
|
|
WorldGrid.updateObject(building, pc);
|
|
DbManager.BuildingQueries.SET_PROPERTY(building, "rotY", building.getRotation().y);
|
|
DbManager.BuildingQueries.SET_PROPERTY(building, "w", building.getRotation().w);
|
|
ChatManager.chatSayInfo(pc,
|
|
"Building with ID " + building.getObjectUUID() + " rotated");
|
|
}
|
|
|
|
private void rotateNPC(PlayerCharacter pc, NPC npc, float yaw) {
|
|
|
|
if (this.refuseStaticTarget(pc, npc))
|
|
return;
|
|
|
|
npc.setRotation(characterRotation(yaw));
|
|
DbManager.NPCQueries.SET_PROPERTY(npc, "npc_rotation", npc.getRotation().w);
|
|
WorldGrid.updateObject(npc, pc);
|
|
ChatManager.chatSayInfo(pc,
|
|
"NPC with ID " + npc.getObjectUUID() + " rotated");
|
|
}
|
|
|
|
private void rotateMob(PlayerCharacter pc, Mob mob, float yaw) {
|
|
|
|
if (this.refuseStaticTarget(pc, mob))
|
|
return;
|
|
|
|
mob.setRotation(characterRotation(yaw));
|
|
DbManager.MobQueries.SET_PROPERTY(mob, "mob_rotation", mob.getRotation().w);
|
|
WorldGrid.updateObject(mob, pc);
|
|
ChatManager.chatSayInfo(pc,
|
|
"Mob with ID " + mob.getObjectUUID() + " rotated");
|
|
}
|
|
|
|
// npc_rotation and mob_rotation store w = cos θ/2, which reloads to the same yaw only for θ in [0, 2π).
|
|
private static Quaternion characterRotation(float yaw) {
|
|
return Quaternion.fromYaw((float) (yaw - FastMath.TWO_PI * Math.floor(yaw / FastMath.TWO_PI)));
|
|
}
|
|
|
|
private void rotateFace(PlayerCharacter pc, AbstractGameObject target) {
|
|
AbstractWorldObject awo = (AbstractWorldObject) target;
|
|
if (awo == null)
|
|
return;
|
|
Vector3fImmutable buildingLoc = awo.getLoc();
|
|
Vector3fImmutable playerLoc = pc.getLoc();
|
|
|
|
Vector3fImmutable faceDirection = playerLoc.subtract2D(buildingLoc);
|
|
|
|
float rotangle = faceDirection.getRotation();
|
|
|
|
if (target instanceof Building)
|
|
rotateBuilding(pc, (Building) target, rotangle);
|
|
else if (target instanceof NPC)
|
|
rotateNPC(pc, (NPC) target, rotangle);
|
|
else if (target instanceof Mob)
|
|
rotateMob(pc, (Mob) target, rotangle);
|
|
else
|
|
throwbackError(pc, "Target " + target.getObjectType()
|
|
+ " is not a valid object type");
|
|
|
|
}
|
|
} |