diff --git a/src/main/java/emu/grasscutter/command/CommandHelpers.java b/src/main/java/emu/grasscutter/command/CommandHelpers.java index e43c2212c..c723a770e 100644 --- a/src/main/java/emu/grasscutter/command/CommandHelpers.java +++ b/src/main/java/emu/grasscutter/command/CommandHelpers.java @@ -54,4 +54,15 @@ public class CommandHelpers { }); return args; } + + public static float parseRelative(String input, Float current) { + if (input.contains("~")) { // Relative + if (!input.equals("~")) { // Relative with offset + current += Float.parseFloat(input.replace("~", "")); + } // Else no offset, no modification + } else { // Absolute + current = Float.parseFloat(input); + } + return current; + } } diff --git a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java index f815cc4c0..1b570539a 100644 --- a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java @@ -21,9 +21,9 @@ import lombok.Setter; label = "spawn", aliases = {"drop", "s"}, usage = { - " [x] [blk] [grp] [cfg] ", - " [x] [state] [maxhp] [hp(0 for infinite)] [atk] [def] [blk] [grp] [cfg] ", - " [x] [lv] [ai] [maxhp] [hp(0 for infinite)] [atk] [def] [blk] [grp] [cfg] " + " [x] [blk] [grp] [cfg] [ ] [ ]", + " [x] [state] [maxhp] [hp(0 for infinite)] [atk] [def] [blk] [grp] [cfg] [ ] [ ]", + " [x] [lv] [ai] [maxhp] [hp(0 for infinite)] [atk] [def] [blk] [grp] [cfg] [ ] [ ]" }, permission = "server.spawn", permissionTargeted = "server.spawn.others") @@ -53,14 +53,25 @@ public final class SpawnCommand implements CommandHandler { sendUsageMessage(sender); // Reachable if someone does `/give lv90` or similar throw new IllegalArgumentException(); } + + Position pos = targetPlayer.getPosition(); + Position rot = targetPlayer.getRotation(); + switch (args.size()) { + case 7: + try { + rot.setX(CommandHelpers.parseRelative(args.get(4), rot.getX())); + rot.setY(CommandHelpers.parseRelative(args.get(5), rot.getY())); + rot.setZ(CommandHelpers.parseRelative(args.get(6), rot.getZ())); + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage( + sender, translate(sender, "commands.execution.argument_error")); + } // Fallthrough case 4: try { - float x, y, z; - x = Float.parseFloat(args.get(1)); - y = Float.parseFloat(args.get(2)); - z = Float.parseFloat(args.get(3)); - param.pos = new Position(x, y, z); + pos.setX(CommandHelpers.parseRelative(args.get(1), pos.getX())); + pos.setY(CommandHelpers.parseRelative(args.get(2), pos.getY())); + pos.setZ(CommandHelpers.parseRelative(args.get(3), pos.getZ())); } catch (NumberFormatException ignored) { CommandHandler.sendMessage( sender, translate(sender, "commands.execution.argument_error")); @@ -77,6 +88,8 @@ public final class SpawnCommand implements CommandHandler { sendUsageMessage(sender); return; } + param.pos = pos; + param.rot = rot; MonsterData monsterData = GameData.getMonsterDataMap().get(param.id); GadgetData gadgetData = GameData.getGadgetDataMap().get(param.id); @@ -102,12 +115,8 @@ public final class SpawnCommand implements CommandHandler { } double maxRadius = Math.sqrt(param.amount * 0.2 / Math.PI); - if (param.pos == null) { - param.pos = targetPlayer.getPosition(); - } - for (int i = 0; i < param.amount; i++) { - Position pos = GetRandomPositionInCircle(param.pos, maxRadius).addY(3); + pos = GetRandomPositionInCircle(param.pos, maxRadius).addY(3); GameEntity entity = null; if (itemData != null) { entity = createItem(itemData, param, pos); @@ -128,12 +137,12 @@ public final class SpawnCommand implements CommandHandler { } private EntityItem createItem(ItemData itemData, SpawnParameters param, Position pos) { - return new EntityItem(param.scene, null, itemData, pos, 1, true); + return new EntityItem(param.scene, null, itemData, pos, param.rot, 1, true); } private EntityMonster createMonster( MonsterData monsterData, SpawnParameters param, Position pos) { - var entity = new EntityMonster(param.scene, monsterData, pos, param.lvl); + var entity = new EntityMonster(param.scene, monsterData, pos, param.rot, param.lvl); if (param.ai != -1) { entity.setAiId(param.ai); } @@ -144,16 +153,13 @@ public final class SpawnCommand implements CommandHandler { GadgetData gadgetData, SpawnParameters param, Position pos, Player targetPlayer) { EntityBaseGadget entity; if (gadgetData.getType() == EntityType.Vehicle) { - entity = - new EntityVehicle( - param.scene, targetPlayer, param.id, 0, pos, targetPlayer.getRotation()); + entity = new EntityVehicle(param.scene, targetPlayer, param.id, 0, pos, param.rot); } else { - entity = new EntityGadget(param.scene, param.id, pos, targetPlayer.getRotation()); + entity = new EntityGadget(param.scene, param.id, pos, param.rot); if (param.state != -1) { ((EntityGadget) entity).setState(param.state); } } - return entity; } @@ -207,6 +213,7 @@ public final class SpawnCommand implements CommandHandler { @Setter public int def = -1; @Setter public int ai = -1; @Setter public Position pos = null; + @Setter public Position rot = null; public Scene scene = null; } } diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java index f75acb42a..110b4f199 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java @@ -16,18 +16,6 @@ import java.util.List; permissionTargeted = "player.teleport.others") public final class TeleportCommand implements CommandHandler { - private float parseRelative( - String input, Float current) { // TODO: Maybe this will be useful elsewhere later - if (input.contains("~")) { // Relative - if (!input.equals("~")) { // Relative with offset - current += Float.parseFloat(input.replace("~", "")); - } // Else no offset, no modification - } else { // Absolute - current = Float.parseFloat(input); - } - return current; - } - @Override public void execute(Player sender, Player targetPlayer, List args) { Position pos = targetPlayer.getPosition(); @@ -46,9 +34,9 @@ public final class TeleportCommand implements CommandHandler { } // Fallthrough case 3: try { - x = this.parseRelative(args.get(0), x); - y = this.parseRelative(args.get(1), y); - z = this.parseRelative(args.get(2), z); + x = CommandHelpers.parseRelative(args.get(0), x); + y = CommandHelpers.parseRelative(args.get(1), y); + z = CommandHelpers.parseRelative(args.get(2), z); } catch (NumberFormatException ignored) { CommandHandler.sendMessage( sender, translate(sender, "commands.teleport.invalid_position")); diff --git a/src/main/java/emu/grasscutter/game/HandbookActions.java b/src/main/java/emu/grasscutter/game/HandbookActions.java index 5c946ad9a..967b5037c 100644 --- a/src/main/java/emu/grasscutter/game/HandbookActions.java +++ b/src/main/java/emu/grasscutter/game/HandbookActions.java @@ -241,7 +241,7 @@ public interface HandbookActions { // Create the entity. for (var i = 1; i <= request.getAmount(); i++) { - var entity = new EntityMonster(scene, entityData, player.getPosition(), level); + var entity = new EntityMonster(scene, entityData, player.getPosition(), player.getRotation(), level); scene.addEntity(entity); } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityHomeAnimal.java b/src/main/java/emu/grasscutter/game/entity/EntityHomeAnimal.java index 40e61c339..5be82c916 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityHomeAnimal.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityHomeAnimal.java @@ -18,8 +18,8 @@ public class EntityHomeAnimal extends EntityMonster implements Rebornable { @Getter private final int rebirthCD; private final AtomicBoolean disappeared = new AtomicBoolean(); - public EntityHomeAnimal(Scene scene, HomeWorldAnimalData data, Position pos) { - super(scene, GameData.getMonsterDataMap().get(data.getMonsterID()), pos, 1); + public EntityHomeAnimal(Scene scene, HomeWorldAnimalData data, Position pos, Position rot) { + super(scene, GameData.getMonsterDataMap().get(data.getMonsterID()), pos, rot, 1); this.rebornPos = pos.clone(); this.rebirth = data.getIsRebirth(); diff --git a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java index 4c4777548..b469925fc 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java @@ -54,14 +54,14 @@ public class EntityMonster extends GameEntity { @Getter private List playerOnBattle; @Nullable @Getter @Setter private SceneMonster metaMonster; - public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) { + public EntityMonster(Scene scene, MonsterData monsterData, Position pos, Position rot, int level) { super(scene); this.id = this.getWorld().getNextEntityId(EntityIdType.MONSTER); this.monsterData = monsterData; this.fightProperties = new Int2FloatOpenHashMap(); this.position = new Position(pos); - this.rotation = new Position(); + this.rotation = new Position(rot); this.bornPos = this.getPosition().clone(); this.level = level; this.playerOnBattle = new ArrayList<>(); diff --git a/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java b/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java index 93031537c..111dba9cf 100644 --- a/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java +++ b/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java @@ -107,7 +107,8 @@ public class HomeSceneItem { return new EntityHomeAnimal( scene, GameData.getHomeWorldAnimalDataMap().get(homeAnimalItem.getFurnitureId()), - homeAnimalItem.getSpawnPos()); + homeAnimalItem.getSpawnPos(), + homeAnimalItem.getSpawnRot()); }) .toList(); } diff --git a/src/main/java/emu/grasscutter/game/managers/blossom/BlossomActivity.java b/src/main/java/emu/grasscutter/game/managers/blossom/BlossomActivity.java index 5b902d347..323576588 100644 --- a/src/main/java/emu/grasscutter/game/managers/blossom/BlossomActivity.java +++ b/src/main/java/emu/grasscutter/game/managers/blossom/BlossomActivity.java @@ -104,7 +104,7 @@ public final class BlossomActivity { var monsterData = GameData.getMonsterDataMap().get((int) entry); var level = scene.getEntityLevel(1, worldLevelOverride); - var entity = new EntityMonster(scene, monsterData, pos.nearby2d(4f), level); + var entity = new EntityMonster(scene, monsterData, pos.nearby2d(4f), Position.ZERO, level); scene.addEntity(entity); newMonsters.add(entity); } diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index 481bcbe8f..0caadfe2d 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -816,8 +816,7 @@ public class Scene { int level = this.getEntityLevel(entry.getLevel(), worldLevelOverride); - EntityMonster monster = new EntityMonster(this, data, entry.getPos(), level); - monster.getRotation().set(entry.getRot()); + EntityMonster monster = new EntityMonster(this, data, entry.getPos(), entry.getRot(), level); monster.setGroupId(entry.getGroup().getGroupId()); monster.setPoseId(entry.getPoseId()); monster.setConfigId(entry.getConfigId()); diff --git a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java index 33cadecf8..5ca90345d 100644 --- a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java +++ b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java @@ -1037,8 +1037,7 @@ public class SceneScriptManager { } // Spawn mob - EntityMonster entity = new EntityMonster(getScene(), data, monster.pos, level); - entity.getRotation().set(monster.rot); + EntityMonster entity = new EntityMonster(getScene(), data, monster.pos, monster.rot, level); entity.setGroupId(groupId); entity.setBlockId(blockId); entity.setConfigId(monster.config_id); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerQuestCreateEntityReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerQuestCreateEntityReq.java index 2c2b5015c..62582d13e 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerQuestCreateEntityReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerQuestCreateEntityReq.java @@ -61,7 +61,7 @@ public class HandlerQuestCreateEntityReq extends PacketHandler { val monsterId = entity.getMonsterId(); val level = entity.getLevel(); MonsterData monsterData = GameData.getMonsterDataMap().get(monsterId); - gameEntity = new EntityMonster(scene, monsterData, pos, level); + gameEntity = new EntityMonster(scene, monsterData, pos, rot, level); } case NPC_ID -> {} }