From 80e75fd023431ce0e24aacef95ce0fe6cf4a2cdc Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Fri, 15 Jul 2022 12:43:49 -0400 Subject: [PATCH 01/17] Implement `PlayerMoveEvent` --- .../grasscutter/game/entity/EntityAvatar.java | 82 ++++++++++------- .../grasscutter/game/entity/GameEntity.java | 89 +++++++++++-------- .../server/event/player/PlayerMoveEvent.java | 47 ++++++++++ 3 files changed, 147 insertions(+), 71 deletions(-) create mode 100644 src/main/java/emu/grasscutter/server/event/player/PlayerMoveEvent.java diff --git a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java index 311f25a89..c3134558a 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java @@ -30,6 +30,7 @@ import emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo; import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.VectorOuterClass.Vector; +import emu.grasscutter.server.event.player.PlayerMoveEvent; import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; @@ -41,22 +42,22 @@ import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; public class EntityAvatar extends GameEntity { private final Avatar avatar; - + private PlayerDieType killedType; private int killedBy; - + public EntityAvatar(Scene scene, Avatar avatar) { super(scene); this.avatar = avatar; this.avatar.setCurrentEnergy(); this.id = getScene().getWorld().getNextEntityId(EntityIdType.AVATAR); - + GameItem weapon = this.getAvatar().getWeapon(); if (weapon != null) { weapon.setWeaponEntityId(getScene().getWorld().getNextEntityId(EntityIdType.WEAPON)); } } - + public EntityAvatar(Avatar avatar) { super(null); this.avatar = avatar; @@ -71,7 +72,7 @@ public class EntityAvatar extends GameEntity { public Position getPosition() { return getPlayer().getPos(); } - + @Override public Position getRotation() { return getPlayer().getRotation(); @@ -80,11 +81,11 @@ public class EntityAvatar extends GameEntity { public Avatar getAvatar() { return avatar; } - + public int getKilledBy() { return killedBy; } - + public PlayerDieType getKilledType() { return killedType; } @@ -93,12 +94,12 @@ public class EntityAvatar extends GameEntity { public boolean isAlive() { return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f; } - + @Override public Int2FloatOpenHashMap getFightProperties() { return getAvatar().getFightProperties(); } - + public int getWeaponEntityId() { if (getAvatar().getWeapon() != null) { return getAvatar().getWeapon().getWeaponEntityId(); @@ -118,20 +119,20 @@ public class EntityAvatar extends GameEntity { this.killedBy = killerId; clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE); } - + @Override public float heal(float amount) { float healed = super.heal(amount); - + if (healed > 0f) { getScene().broadcastPacket( new PacketEntityFightPropChangeReasonNotify(this, FightProperty.FIGHT_PROP_CUR_HP, healed, PropChangeReason.PROP_CHANGE_REASON_ABILITY, ChangeHpReason.CHANGE_HP_REASON_CHANGE_HP_ADD_ABILITY) ); } - + return healed; } - + public void clearEnergy(ChangeEnergyReason reason) { // Fight props. FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp(); @@ -150,7 +151,7 @@ public class EntityAvatar extends GameEntity { this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, -maxEnergy, reason)); } } - + public void addEnergy(float amount, PropChangeReason reason) { this.addEnergy(amount, reason, false); } @@ -161,7 +162,7 @@ public class EntityAvatar extends GameEntity { float curEnergy = this.getFightProperty(curEnergyProp); float maxEnergy = this.getFightProperty(maxEnergyProp); - + // Get energy recharge. float energyRecharge = this.getFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY); @@ -172,16 +173,16 @@ public class EntityAvatar extends GameEntity { // Determine the new energy value. float newEnergy = Math.min(curEnergy + amount, maxEnergy); - + // Set energy and notify. if (newEnergy != curEnergy) { this.avatar.setCurrentEnergy(curEnergyProp, newEnergy); - + this.getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(this.getAvatar(), curEnergyProp)); this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, reason)); } - } - + } + public SceneAvatarInfo getSceneAvatarInfo() { SceneAvatarInfo.Builder avatarInfo = SceneAvatarInfo.newBuilder() .setUid(this.getPlayer().getUid()) @@ -198,7 +199,7 @@ public class EntityAvatar extends GameEntity { .setWearingFlycloakId(this.getAvatar().getFlyCloak()) .setCostumeId(this.getAvatar().getCostume()) .setBornTime(this.getAvatar().getBornTime()); - + for (GameItem item : avatar.getEquips().values()) { if (item.getItemData().getEquipType() == EquipType.EQUIP_WEAPON) { avatarInfo.setWeapon(item.createSceneWeaponInfo()); @@ -207,7 +208,7 @@ public class EntityAvatar extends GameEntity { } avatarInfo.addEquipIdList(item.getItemId()); } - + return avatarInfo.build(); } @@ -219,7 +220,7 @@ public class EntityAvatar extends GameEntity { .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) .setBornPos(Vector.newBuilder()) .build(); - + SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() .setEntityId(getId()) .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_AVATAR) @@ -229,11 +230,11 @@ public class EntityAvatar extends GameEntity { .setLastMoveSceneTimeMs(this.getLastMoveSceneTimeMs()) .setLastMoveReliableSeq(this.getLastMoveReliableSeq()) .setLifeState(this.getLifeState().getValue()); - + if (this.getScene() != null) { entityInfo.setMotionInfo(this.getMotionInfo()); } - + for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) { if (entry.getIntKey() == 0) { continue; @@ -241,23 +242,23 @@ public class EntityAvatar extends GameEntity { FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build(); entityInfo.addFightPropList(fightProp); } - + PropPair pair = PropPair.newBuilder() .setType(PlayerProperty.PROP_LEVEL.getId()) .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getAvatar().getLevel())) .build(); entityInfo.addPropList(pair); - + entityInfo.setAvatar(this.getSceneAvatarInfo()); - + return entityInfo.build(); } - + public AbilityControlBlock getAbilityControlBlock() { AvatarData data = this.getAvatar().getAvatarData(); AbilityControlBlock.Builder abilityControlBlock = AbilityControlBlock.newBuilder(); int embryoId = 0; - + // Add avatar abilities if (data.getAbilities() != null) { for (int id : data.getAbilities()) { @@ -269,7 +270,7 @@ public class EntityAvatar extends GameEntity { abilityControlBlock.addAbilityEmbryoList(emb); } } - // Add default abilities + // Add default abilities for (int id : GameConstants.DEFAULT_ABILITY_HASHES) { AbilityEmbryo emb = AbilityEmbryo.newBuilder() .setAbilityId(++embryoId) @@ -278,7 +279,7 @@ public class EntityAvatar extends GameEntity { .build(); abilityControlBlock.addAbilityEmbryoList(emb); } - // Add team resonances + // Add team resonances for (int id : this.getPlayer().getTeamManager().getTeamResonancesConfig()) { AbilityEmbryo emb = AbilityEmbryo.newBuilder() .setAbilityId(++embryoId) @@ -310,8 +311,25 @@ public class EntityAvatar extends GameEntity { abilityControlBlock.addAbilityEmbryoList(emb); } } - + // return abilityControlBlock.build(); } + + /** + * Move this entity to a new position. + * Additionally invoke player move event. + * @param newPosition The new position. + * @param rotation The new rotation. + */ + @Override public void move(Position newPosition, Position rotation) { + // Invoke player move event. + PlayerMoveEvent event = new PlayerMoveEvent( + this.getPlayer(), PlayerMoveEvent.MoveType.PLAYER, + this.getPosition(), newPosition + ); event.call(); + + // Set position and rotation. + super.move(event.getDestination(), rotation); + } } diff --git a/src/main/java/emu/grasscutter/game/entity/GameEntity.java b/src/main/java/emu/grasscutter/game/entity/GameEntity.java index 21d8f8173..691babe30 100644 --- a/src/main/java/emu/grasscutter/game/entity/GameEntity.java +++ b/src/main/java/emu/grasscutter/game/entity/GameEntity.java @@ -24,32 +24,32 @@ public abstract class GameEntity { protected int id; private final Scene scene; private SpawnDataEntry spawnEntry; - + private int blockId; private int configId; private int groupId; - + private MotionState moveState; private int lastMoveSceneTimeMs; private int lastMoveReliableSeq; - + // Abilities private Map metaOverrideMap; private Int2ObjectMap metaModifiers; - + public GameEntity(Scene scene) { this.scene = scene; this.moveState = MotionState.MOTION_STATE_NONE; } - + public int getId() { return this.id; } - + public int getEntityType() { return getId() >> 24; } - + public World getWorld() { return this.getScene().getWorld(); } @@ -57,7 +57,7 @@ public abstract class GameEntity { public Scene getScene() { return this.scene; } - + public boolean isAlive() { return true; } @@ -65,14 +65,14 @@ public abstract class GameEntity { public LifeState getLifeState() { return isAlive() ? LifeState.LIFE_ALIVE : LifeState.LIFE_DEAD; } - + public Map getMetaOverrideMap() { if (this.metaOverrideMap == null) { this.metaOverrideMap = new HashMap<>(); } return this.metaOverrideMap; } - + public Int2ObjectMap getMetaModifiers() { if (this.metaModifiers == null) { this.metaModifiers = new Int2ObjectOpenHashMap<>(); @@ -81,11 +81,11 @@ public abstract class GameEntity { } public abstract Int2FloatOpenHashMap getFightProperties(); - + public abstract Position getPosition(); - + public abstract Position getRotation(); - + public MotionState getMotionState() { return moveState; } @@ -109,23 +109,23 @@ public abstract class GameEntity { public void setLastMoveReliableSeq(int lastMoveReliableSeq) { this.lastMoveReliableSeq = lastMoveReliableSeq; } - + public void setFightProperty(FightProperty prop, float value) { this.getFightProperties().put(prop.getId(), value); } - + private void setFightProperty(int id, float value) { this.getFightProperties().put(id, value); } - + public void addFightProperty(FightProperty prop, float value) { this.getFightProperties().put(prop.getId(), getFightProperty(prop) + value); } - + public float getFightProperty(FightProperty prop) { return getFightProperties().getOrDefault(prop.getId(), 0f); } - + public void addAllFightPropsToEntityInfo(SceneEntityInfo.Builder entityInfo) { for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) { if (entry.getIntKey() == 0) { @@ -135,7 +135,7 @@ public abstract class GameEntity { entityInfo.addFightPropList(fightProp); } } - + public int getBlockId() { return blockId; } @@ -143,7 +143,7 @@ public abstract class GameEntity { public void setBlockId(int blockId) { this.blockId = blockId; } - + public int getConfigId() { return configId; } @@ -151,7 +151,7 @@ public abstract class GameEntity { public void setConfigId(int configId) { this.configId = configId; } - + public int getGroupId() { return groupId; } @@ -159,7 +159,7 @@ public abstract class GameEntity { public void setGroupId(int groupId) { this.groupId = groupId; } - + protected MotionInfo getMotionInfo() { MotionInfo proto = MotionInfo.newBuilder() .setPos(getPosition().toProto()) @@ -167,7 +167,7 @@ public abstract class GameEntity { .setSpeed(Vector.newBuilder()) .setState(this.getMotionState()) .build(); - + return proto; } @@ -178,7 +178,7 @@ public abstract class GameEntity { public void setSpawnEntry(SpawnDataEntry spawnEntry) { this.spawnEntry = spawnEntry; } - + public float heal(float amount) { if (this.getFightProperties() == null) { return 0f; @@ -186,62 +186,73 @@ public abstract class GameEntity { float curHp = getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); float maxHp = getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); - + if (curHp >= maxHp) { return 0f; } - + float healed = Math.min(maxHp - curHp, amount); this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, healed); - + getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP)); - + return healed; } - + public void damage(float amount) { damage(amount, 0); } - + public void damage(float amount, int killerId) { // Sanity check if (getFightProperties() == null) { return; } - + // Lose hp addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -amount); - + // Check if dead boolean isDead = false; if (getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) { setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f); isDead = true; } - + // Packets this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP)); - + // Check if dead if (isDead) { getScene().killEntity(this, killerId); } } - + + /** + * Move this entity to a new position. + * @param position The new position. + * @param rotation The new rotation. + */ + public void move(Position position, Position rotation) { + // Set the position and rotation. + this.getPosition().set(position); + this.getRotation().set(rotation); + } + /** * Called when this entity is added to the world */ public void onCreate() { - + } - + /** * Called when this entity dies * @param killerId Entity id of the entity that killed this entity */ public void onDeath(int killerId) { - + } - + public abstract SceneEntityInfo toProto(); } diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerMoveEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerMoveEvent.java new file mode 100644 index 000000000..143307a3b --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/player/PlayerMoveEvent.java @@ -0,0 +1,47 @@ +package emu.grasscutter.server.event.player; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.Cancellable; +import emu.grasscutter.server.event.types.PlayerEvent; +import emu.grasscutter.utils.Position; + +/** + * TODO: Allow plugins to change the position of the player. + */ +public final class PlayerMoveEvent extends PlayerEvent implements Cancellable { + private final MoveType type; + private final Position from; + private final Position to; + + public PlayerMoveEvent(Player player, MoveType type, Position from, Position to) { + super(player); + + this.type = type; + this.from = from; + this.to = to; + } + + public MoveType getMoveType() { + return this.type; + } + + public Position getSource() { + return this.from; + } + + public Position getDestination() { + return this.to; + } + + public enum MoveType { + /** + * The player has sent a combat invocation to move. + */ + PLAYER, + + /** + * The server has requested that the player moves. + */ + SERVER + } +} \ No newline at end of file From 1b8df002d127aa684d557ab5b708664c07decf40 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Fri, 15 Jul 2022 12:48:55 -0400 Subject: [PATCH 02/17] Remove `Cancellable` from `PlayerMoveEvent` --- .../emu/grasscutter/server/event/player/PlayerMoveEvent.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerMoveEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerMoveEvent.java index 143307a3b..ded4acfdc 100644 --- a/src/main/java/emu/grasscutter/server/event/player/PlayerMoveEvent.java +++ b/src/main/java/emu/grasscutter/server/event/player/PlayerMoveEvent.java @@ -1,14 +1,13 @@ package emu.grasscutter.server.event.player; import emu.grasscutter.game.player.Player; -import emu.grasscutter.server.event.Cancellable; import emu.grasscutter.server.event.types.PlayerEvent; import emu.grasscutter.utils.Position; /** * TODO: Allow plugins to change the position of the player. */ -public final class PlayerMoveEvent extends PlayerEvent implements Cancellable { +public final class PlayerMoveEvent extends PlayerEvent { private final MoveType type; private final Position from; private final Position to; From 02ca5cf23c3205ab1c91458d5f00ce15dc7eda3a Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Fri, 15 Jul 2022 16:12:22 -0400 Subject: [PATCH 03/17] Update to support `PlayerMoveEvent` --- .../server/packet/recv/HandlerCombatInvocationsNotify.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java index e77cbecb7..839ed5447 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java @@ -58,8 +58,7 @@ public class HandlerCombatInvocationsNotify extends PacketHandler { new Position(motionInfo.getRot()), motionState); event.call(); - entity.getPosition().set(motionInfo.getPos()); - entity.getRotation().set(motionInfo.getRot()); + entity.move(event.getPosition(), event.getRotation()); entity.setLastMoveSceneTimeMs(moveInfo.getSceneTime()); entity.setLastMoveReliableSeq(moveInfo.getReliableSeq()); entity.setMotionState(motionState); From f6b4016f1beb0b1ed0bae992b1271db2752ebb19 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Fri, 15 Jul 2022 16:18:46 -0400 Subject: [PATCH 04/17] Add `PlayerTeleportEvent` --- .../command/commands/TeleportAllCommand.java | 14 +++- .../command/commands/TeleportCommand.java | 11 ++- .../managers/mapmark/MapMarksManager.java | 15 ++-- .../event/player/PlayerTeleportEvent.java | 53 +++++++++++++ .../recv/HandlerSceneTransToPointReq.java | 79 ++++++++++--------- .../packet/recv/HandlerTryEnterHomeReq.java | 17 ++-- 6 files changed, 135 insertions(+), 54 deletions(-) create mode 100644 src/main/java/emu/grasscutter/server/event/player/PlayerTeleportEvent.java diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java index 5a28383a3..9549833db 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java @@ -4,6 +4,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.player.PlayerTeleportEvent; import emu.grasscutter.utils.Position; import java.util.List; @@ -19,15 +20,20 @@ public final class TeleportAllCommand implements CommandHandler { CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.error")); return; } - + for (Player player : targetPlayer.getWorld().getPlayers()) { if (player.equals(targetPlayer)) continue; - Position pos = targetPlayer.getPos(); - player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), pos); + Position pos = targetPlayer.getPos(); + PlayerTeleportEvent event = new PlayerTeleportEvent(targetPlayer, PlayerTeleportEvent.TeleportType.COMMAND, + targetPlayer.getPos(), pos); + event.call(); + + if(!event.isCanceled()) + player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), event.getDestination()); } - + CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success")); } } diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java index 0bc920ac7..f0e371b75 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java @@ -4,6 +4,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.player.PlayerTeleportEvent; import emu.grasscutter.utils.Position; import java.util.List; @@ -54,12 +55,16 @@ public final class TeleportCommand implements CommandHandler { } Position target_pos = new Position(x, y, z); - boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, target_pos); + PlayerTeleportEvent event = new PlayerTeleportEvent(targetPlayer, PlayerTeleportEvent.TeleportType.COMMAND, + targetPlayer.getPos(), target_pos); + event.call(); + + boolean result = !event.isCanceled() || targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, event.getDestination()); if (!result) { CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error")); } else { - CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success", - targetPlayer.getNickname(), Float.toString(x), Float.toString(y), + CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success", + targetPlayer.getNickname(), Float.toString(x), Float.toString(y), Float.toString(z), Integer.toString(sceneId)) ); } diff --git a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java index 1fa36ec58..e70ae6d81 100644 --- a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java +++ b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java @@ -4,6 +4,7 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType; import emu.grasscutter.net.proto.MarkMapReqOuterClass.MarkMapReq; import emu.grasscutter.net.proto.MarkMapReqOuterClass.MarkMapReq.Operation; +import emu.grasscutter.server.event.player.PlayerTeleportEvent; import emu.grasscutter.server.packet.send.PacketMarkMapRsp; import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; import emu.grasscutter.utils.Position; @@ -74,17 +75,21 @@ public class MapMarksManager { } private void teleport(Player player, MapMark mapMark) { - float y; - try { + float y; try { y = (float)Integer.parseInt(mapMark.getName()); } catch (Exception e) { y = 300; } + Position pos = mapMark.getPosition(); - player.getPos().set(pos.getX(), y, pos.getZ()); + PlayerTeleportEvent event = new PlayerTeleportEvent(player, PlayerTeleportEvent.TeleportType.MAP, + player.getPos(), new Position(pos.getX(), y, pos.getZ())); + + event.call(); if(event.isCanceled()) return; + player.getPos().set(event.getDestination()); + if (mapMark.getSceneId() != player.getSceneId()) { player.getWorld().transferPlayerToScene(player, mapMark.getSceneId(), player.getPos()); - } - player.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(player)); + } player.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(player)); } } diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerTeleportEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerTeleportEvent.java new file mode 100644 index 000000000..05928bb18 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/player/PlayerTeleportEvent.java @@ -0,0 +1,53 @@ +package emu.grasscutter.server.event.player; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.Cancellable; +import emu.grasscutter.server.event.types.PlayerEvent; +import emu.grasscutter.utils.Position; + +public final class PlayerTeleportEvent extends PlayerEvent implements Cancellable { + private final TeleportType type; + private final Position from; + private Position to; + + public PlayerTeleportEvent(Player player, TeleportType type, Position from, Position to) { + super(player); + + this.type = type; + this.from = from; + this.to = to; + } + + public TeleportType getTeleportType() { + return this.type; + } + + public Position getSource() { + return this.from; + } + + public Position getDestination() { + return this.to; + } + + public void setDestination(Position to) { + this.to = to; + } + + public enum TeleportType { + /** + * The player has asked to teleport to a waypoint. + */ + WAYPOINT, + + /** + * The player has asked to teleport using the map. + */ + MAP, + + /** + * The player has asked to teleport using the command. + */ + COMMAND + } +} \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java index 209dacdbb..28f4cffd0 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java @@ -1,36 +1,43 @@ -package emu.grasscutter.server.packet.recv; - -import emu.grasscutter.data.GameData; -import emu.grasscutter.data.binout.ScenePointEntry; -import emu.grasscutter.net.packet.Opcodes; -import emu.grasscutter.net.packet.PacketOpcodes; -import emu.grasscutter.net.proto.SceneTransToPointReqOuterClass.SceneTransToPointReq; -import emu.grasscutter.net.proto.SceneTransToPointRspOuterClass.SceneTransToPointRsp; -import emu.grasscutter.net.packet.PacketHandler; -import emu.grasscutter.server.game.GameSession; -import emu.grasscutter.server.packet.send.PacketSceneTransToPointRsp; -import emu.grasscutter.utils.Position; - -@Opcodes(PacketOpcodes.SceneTransToPointReq) -public class HandlerSceneTransToPointReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - SceneTransToPointReq req = SceneTransToPointReq.parseFrom(payload); - - String code = req.getSceneId() + "_" + req.getPointId(); - ScenePointEntry scenePointEntry = GameData.getScenePointEntries().get(code); - - if (scenePointEntry != null) { - float x = scenePointEntry.getPointData().getTranPos().getX(); - float y = scenePointEntry.getPointData().getTranPos().getY(); - float z = scenePointEntry.getPointData().getTranPos().getZ(); - - session.getPlayer().getWorld().transferPlayerToScene(session.getPlayer(), req.getSceneId(), new Position(x, y, z)); - session.send(new PacketSceneTransToPointRsp(session.getPlayer(), req.getPointId(), req.getSceneId())); - } else { - session.send(new PacketSceneTransToPointRsp()); - } - } - -} +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.binout.ScenePointEntry; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.SceneTransToPointReqOuterClass.SceneTransToPointReq; +import emu.grasscutter.net.proto.SceneTransToPointRspOuterClass.SceneTransToPointRsp; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.server.event.player.PlayerTeleportEvent; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketSceneTransToPointRsp; +import emu.grasscutter.utils.Position; + +@Opcodes(PacketOpcodes.SceneTransToPointReq) +public class HandlerSceneTransToPointReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + SceneTransToPointReq req = SceneTransToPointReq.parseFrom(payload); + + String code = req.getSceneId() + "_" + req.getPointId(); + ScenePointEntry scenePointEntry = GameData.getScenePointEntries().get(code); + + if (scenePointEntry != null) { + float x = scenePointEntry.getPointData().getTranPos().getX(); + float y = scenePointEntry.getPointData().getTranPos().getY(); + float z = scenePointEntry.getPointData().getTranPos().getZ(); + + PlayerTeleportEvent event = new PlayerTeleportEvent(session.getPlayer(), PlayerTeleportEvent.TeleportType.WAYPOINT, + session.getPlayer().getPos(), new Position(x, y, z)); + event.call(); + + if(!event.isCanceled()) { + session.getPlayer().getWorld().transferPlayerToScene(session.getPlayer(), req.getSceneId(), new Position(x, y, z)); + session.send(new PacketSceneTransToPointRsp(session.getPlayer(), req.getPointId(), req.getSceneId())); + } + } else { + session.send(new PacketSceneTransToPointRsp()); + } + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java index 69e66e7d9..e1927f30f 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java @@ -9,6 +9,7 @@ import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.TryEnterHomeReqOuterClass; import emu.grasscutter.scripts.data.SceneConfig; +import emu.grasscutter.server.event.player.PlayerTeleportEvent; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.PacketTryEnterHomeRsp; import emu.grasscutter.utils.Position; @@ -38,13 +39,17 @@ public class HandlerTryEnterHomeReq extends PacketHandler { Scene scene = session.getPlayer().getWorld().getSceneById(realmId); Position pos = scene.getScriptManager().getConfig().born_pos; - session.getPlayer().getWorld().transferPlayerToScene( + PlayerTeleportEvent event = new PlayerTeleportEvent(session.getPlayer(), PlayerTeleportEvent.TeleportType.WAYPOINT, + session.getPlayer().getPos(), pos); + event.call(); + + if(!event.isCanceled()) { + session.getPlayer().getWorld().transferPlayerToScene( session.getPlayer(), - realmId, - pos - ); + realmId, event.getDestination() + ); - - session.send(new PacketTryEnterHomeRsp(req.getTargetUid())); + session.send(new PacketTryEnterHomeRsp(req.getTargetUid())); + } } } From 7397c7f3008f5e4a1832fde3471035650f622fa3 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sun, 24 Jul 2022 12:08:59 -0400 Subject: [PATCH 05/17] Remove deprecated class --- .../event/game/CommandResponseEvent.java | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 src/main/java/emu/grasscutter/server/event/game/CommandResponseEvent.java diff --git a/src/main/java/emu/grasscutter/server/event/game/CommandResponseEvent.java b/src/main/java/emu/grasscutter/server/event/game/CommandResponseEvent.java deleted file mode 100644 index bacb3be5b..000000000 --- a/src/main/java/emu/grasscutter/server/event/game/CommandResponseEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package emu.grasscutter.server.event.game; - -import emu.grasscutter.game.player.Player; -import emu.grasscutter.server.event.types.ServerEvent; - -/** - * @deprecated Will be removed in 1.2.3-dev or 1.3.0. - */ -@Deprecated(since = "1.2.2-dev", forRemoval = true) -public final class CommandResponseEvent extends ServerEvent { - private String message; - private Player player; - - public CommandResponseEvent(Type type, Player player,String message) { - super(type); - this.message = message; - this.player = player; - } - - public String getMessage() { - return message; - } - - public Player getPlayer() { - return player; - } -} From a13725b1cb287bbc4d9e5e37bda0e8493fb7ccd9 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sun, 24 Jul 2022 12:17:38 -0400 Subject: [PATCH 06/17] Add a `Location` class (Scene + Position) --- .../java/emu/grasscutter/utils/Location.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/main/java/emu/grasscutter/utils/Location.java diff --git a/src/main/java/emu/grasscutter/utils/Location.java b/src/main/java/emu/grasscutter/utils/Location.java new file mode 100644 index 000000000..c0954b7ba --- /dev/null +++ b/src/main/java/emu/grasscutter/utils/Location.java @@ -0,0 +1,41 @@ +package emu.grasscutter.utils; + +import dev.morphia.annotations.Entity; +import dev.morphia.annotations.Transient; +import emu.grasscutter.game.world.Scene; +import lombok.Getter; +import lombok.Setter; + +@Entity +public class Location extends Position { + @Transient @Getter @Setter + private Scene scene; + + public Location(Scene scene, Position position) { + this.set(position); + + this.scene = scene; + } + + public Location(Scene scene, float x, float y) { + this.set(x, y); + + this.scene = scene; + } + + public Location(Scene scene, float x, float y, float z) { + this.set(x, y, z); + + this.scene = scene; + } + + @Override + public Location clone() { + return new Location(this.scene, super.clone()); + } + + @Override + public String toString() { + return String.format("%s:%s,%s,%s", this.scene.getId(), this.getX(), this.getY(), this.getZ()); + } +} \ No newline at end of file From 886c2e2f432a2b20cb9962865ce970229a84a183 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sun, 24 Jul 2022 13:20:42 -0400 Subject: [PATCH 07/17] Add `EntityDeathEvent` and implementations --- .../grasscutter/game/entity/EntityAvatar.java | 5 ++++ .../game/entity/EntityBaseGadget.java | 6 ++-- .../game/entity/EntityClientGadget.java | 30 +++++++++---------- .../grasscutter/game/entity/EntityGadget.java | 2 ++ .../game/entity/EntityMonster.java | 2 ++ .../grasscutter/game/entity/GameEntity.java | 5 +++- .../server/event/entity/EntityDeathEvent.java | 20 +++++++++++++ 7 files changed, 50 insertions(+), 20 deletions(-) create mode 100644 src/main/java/emu/grasscutter/server/event/entity/EntityDeathEvent.java diff --git a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java index 9353553b0..cb640c424 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java @@ -30,6 +30,7 @@ import emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo; import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.VectorOuterClass.Vector; +import emu.grasscutter.server.event.player.PlayerMoveEvent; import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; @@ -108,12 +109,16 @@ public class EntityAvatar extends GameEntity { @Override public void onDeath(int killerId) { + super.onDeath(killerId); // Invoke super class's onDeath() method. + this.killedType = PlayerDieType.PLAYER_DIE_TYPE_KILL_BY_MONSTER; this.killedBy = killerId; clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE); } public void onDeath(PlayerDieType dieType, int killerId) { + super.onDeath(killerId); // Invoke super class's onDeath() method. + this.killedType = dieType; this.killedBy = killerId; clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE); diff --git a/src/main/java/emu/grasscutter/game/entity/EntityBaseGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityBaseGadget.java index a5b2cb6c5..b063db33a 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityBaseGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityBaseGadget.java @@ -8,11 +8,11 @@ public abstract class EntityBaseGadget extends GameEntity { public EntityBaseGadget(Scene scene) { super(scene); } - + public abstract int getGadgetId(); - + @Override public void onDeath(int killerId) { - + super.onDeath(killerId); // Invoke super class's onDeath() method. } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java index 5e0c5eb00..769f571e7 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java @@ -3,7 +3,6 @@ package emu.grasscutter.game.entity; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.world.Scene; -import emu.grasscutter.game.world.World; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass; @@ -11,7 +10,6 @@ import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityIn import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify; -import emu.grasscutter.net.proto.GadgetClientParamOuterClass.GadgetClientParam; import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; @@ -25,10 +23,10 @@ import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; public class EntityClientGadget extends EntityBaseGadget { private final Player owner; - + private final Position pos; private final Position rot; - + private int configId; private int campId; private int campType; @@ -37,7 +35,7 @@ public class EntityClientGadget extends EntityBaseGadget { private boolean asyncLoad; private int originalOwnerEntityId; - + public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) { super(scene); this.owner = player; @@ -59,20 +57,20 @@ public class EntityClientGadget extends EntityBaseGadget { this.originalOwnerEntityId = this.ownerEntityId; } } - + @Override public int getGadgetId() { return configId; } - + public Player getOwner() { return owner; } - + public int getCampId() { return campId; } - + public int getCampType() { return campType; } @@ -80,7 +78,7 @@ public class EntityClientGadget extends EntityBaseGadget { public int getOwnerEntityId() { return ownerEntityId; } - + public int getTargetEntityId() { return targetEntityId; } @@ -95,7 +93,7 @@ public class EntityClientGadget extends EntityBaseGadget { @Override public void onDeath(int killerId) { - + super.onDeath(killerId); // Invoke super class's onDeath() method. } @Override @@ -124,7 +122,7 @@ public class EntityClientGadget extends EntityBaseGadget { .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) .setBornPos(Vector.newBuilder()) .build(); - + SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() .setEntityId(getId()) .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) @@ -133,13 +131,13 @@ public class EntityClientGadget extends EntityBaseGadget { .setEntityClientData(EntityClientData.newBuilder()) .setEntityAuthorityInfo(authority) .setLifeState(1); - + PropPair pair = PropPair.newBuilder() .setType(PlayerProperty.PROP_LEVEL.getId()) .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1)) .build(); entityInfo.addPropList(pair); - + ClientGadgetInfoOuterClass.ClientGadgetInfo clientGadget = ClientGadgetInfoOuterClass.ClientGadgetInfo.newBuilder() .setCampId(this.getCampId()) .setCampType(this.getCampType()) @@ -147,7 +145,7 @@ public class EntityClientGadget extends EntityBaseGadget { .setTargetEntityId(this.getTargetEntityId()) .setAsyncLoad(this.isAsyncLoad()) .build(); - + SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder() .setGadgetId(this.getGadgetId()) .setOwnerEntityId(this.getOwnerEntityId()) @@ -157,7 +155,7 @@ public class EntityClientGadget extends EntityBaseGadget { .setAuthorityPeerId(this.getOwner().getPeerId()); entityInfo.setGadget(gadgetInfo); - + return entityInfo.build(); } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java index 1f88f451a..a344b7fc1 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java @@ -175,6 +175,8 @@ public class EntityGadget extends EntityBaseGadget { @Override public void onDeath(int killerId) { + super.onDeath(killerId); // Invoke super class's onDeath() method. + if (this.getSpawnEntry() != null) { this.getScene().getDeadSpawnedEntities().add(getSpawnEntry()); } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java index 4c1426c02..d60c96df7 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java @@ -158,6 +158,8 @@ public class EntityMonster extends GameEntity { @Override public void onDeath(int killerId) { + super.onDeath(killerId); // Invoke super class's onDeath() method. + if (this.getSpawnEntry() != null) { this.getScene().getDeadSpawnedEntities().add(getSpawnEntry()); } diff --git a/src/main/java/emu/grasscutter/game/entity/GameEntity.java b/src/main/java/emu/grasscutter/game/entity/GameEntity.java index f2b2e4107..c0c15aaa2 100644 --- a/src/main/java/emu/grasscutter/game/entity/GameEntity.java +++ b/src/main/java/emu/grasscutter/game/entity/GameEntity.java @@ -15,6 +15,7 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.VectorOuterClass.Vector; +import emu.grasscutter.server.event.entity.EntityDeathEvent; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.utils.Position; import it.unimi.dsi.fastutil.ints.Int2FloatMap; @@ -262,7 +263,9 @@ public abstract class GameEntity { * @param killerId Entity id of the entity that killed this entity */ public void onDeath(int killerId) { - + // Invoke entity death event. + EntityDeathEvent event = new EntityDeathEvent(this, killerId); + event.call(); } public abstract SceneEntityInfo toProto(); diff --git a/src/main/java/emu/grasscutter/server/event/entity/EntityDeathEvent.java b/src/main/java/emu/grasscutter/server/event/entity/EntityDeathEvent.java new file mode 100644 index 000000000..fb9871318 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/entity/EntityDeathEvent.java @@ -0,0 +1,20 @@ +package emu.grasscutter.server.event.entity; + +import emu.grasscutter.game.entity.GameEntity; +import emu.grasscutter.server.event.types.EntityEvent; +import emu.grasscutter.utils.Location; +import lombok.Getter; + +import javax.annotation.Nullable; + +public final class EntityDeathEvent extends EntityEvent { + @Getter private final Location deathLocation; + @Getter @Nullable private final GameEntity killer; + + public EntityDeathEvent(GameEntity entity, int killerId) { + super(entity); + + this.deathLocation = new Location(entity.getScene(), entity.getPosition()); + this.killer = entity.getScene().getEntityById(killerId); + } +} \ No newline at end of file From 818bfb8c5bca96e6ab9685ea325df414ae444ea8 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sun, 24 Jul 2022 13:20:58 -0400 Subject: [PATCH 08/17] Add `PlayerTeamDeathEvent` and implementations --- .../grasscutter/game/player/TeamManager.java | 129 +++++++++--------- .../event/player/PlayerTeamDeathEvent.java | 20 +++ 2 files changed, 87 insertions(+), 62 deletions(-) create mode 100644 src/main/java/emu/grasscutter/server/event/player/PlayerTeamDeathEvent.java diff --git a/src/main/java/emu/grasscutter/game/player/TeamManager.java b/src/main/java/emu/grasscutter/game/player/TeamManager.java index ce4aafb66..8421b4ecf 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamManager.java +++ b/src/main/java/emu/grasscutter/game/player/TeamManager.java @@ -20,6 +20,7 @@ import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType; import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState; import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType; +import emu.grasscutter.server.event.player.PlayerTeamDeathEvent; import emu.grasscutter.server.packet.send.PacketAvatarDieAnimationEndRsp; import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify; @@ -76,7 +77,7 @@ public class TeamManager extends BasePlayerDataManager { } public World getWorld() { - return getPlayer().getWorld(); + return this.getPlayer().getWorld(); } public Map getTeams() { @@ -123,7 +124,7 @@ public class TeamManager extends BasePlayerDataManager { } public long getCurrentCharacterGuid() { - return getCurrentAvatarEntity().getAvatar().getGuid(); + return this.getCurrentAvatarEntity().getAvatar().getGuid(); } public TeamInfo getCurrentTeamInfo() { @@ -166,20 +167,20 @@ public class TeamManager extends BasePlayerDataManager { } public EntityAvatar getCurrentAvatarEntity() { - return getActiveTeam().get(currentCharacterIndex); + return this.getActiveTeam().get(currentCharacterIndex); } public boolean isSpawned() { - return getPlayer().getScene() != null && getPlayer().getScene().getEntities().containsKey(getCurrentAvatarEntity().getId()); + return this.getPlayer().getScene() != null && this.getPlayer().getScene().getEntities().containsKey(this.getCurrentAvatarEntity().getId()); } public int getMaxTeamSize() { - if (getPlayer().isInMultiplayer()) { + if (this.getPlayer().isInMultiplayer()) { int max = GAME_OPTIONS.avatarLimits.multiplayerTeam; - if (getPlayer().getWorld().getHost() == this.getPlayer()) { - return Math.max(1, (int) Math.ceil(max / (double) getWorld().getPlayerCount())); + if (this.getPlayer().getWorld().getHost() == this.getPlayer()) { + return Math.max(1, (int) Math.ceil(max / (double) this.getWorld().getPlayerCount())); } - return Math.max(1, (int) Math.floor(max / (double) getWorld().getPlayerCount())); + return Math.max(1, (int) Math.floor(max / (double) this.getWorld().getPlayerCount())); } return GAME_OPTIONS.avatarLimits.singlePlayerTeam; @@ -191,14 +192,14 @@ public class TeamManager extends BasePlayerDataManager { * Returns true if there is space to add the number of avatars to the team. */ public boolean canAddAvatarsToTeam(TeamInfo team, int avatars) { - return team.size() + avatars <= getMaxTeamSize(); + return team.size() + avatars <= this.getMaxTeamSize(); } /** * Returns true if there is space to add to the team. */ public boolean canAddAvatarToTeam(TeamInfo team) { - return canAddAvatarsToTeam(team, 1); + return this.canAddAvatarsToTeam(team, 1); } /** @@ -209,7 +210,7 @@ public class TeamManager extends BasePlayerDataManager { if (this.useTemporarilyTeamIndex != -1) { return false; } - return canAddAvatarsToTeam(this.getCurrentTeamInfo(), avatars); + return this.canAddAvatarsToTeam(this.getCurrentTeamInfo(), avatars); } /** @@ -217,7 +218,7 @@ public class TeamManager extends BasePlayerDataManager { * If the current team is temporary, returns false. */ public boolean canAddAvatarToCurrentTeam() { - return canAddAvatarsToCurrentTeam(1); + return this.canAddAvatarsToCurrentTeam(1); } /** @@ -226,7 +227,7 @@ public class TeamManager extends BasePlayerDataManager { * If some can not be added, returns false and does not add any. */ public boolean addAvatarsToTeam(TeamInfo team, Collection avatars) { - if (!canAddAvatarsToTeam(team, avatars.size())) { + if (!this.canAddAvatarsToTeam(team, avatars.size())) { return false; } @@ -237,20 +238,20 @@ public class TeamManager extends BasePlayerDataManager { if (this.getPlayer().isInMultiplayer()) { if (team.equals(this.getMpTeam())) { // MP team Packet - this.updateTeamEntities(new PacketChangeMpTeamAvatarRsp(getPlayer(), team)); + this.updateTeamEntities(new PacketChangeMpTeamAvatarRsp(this.getPlayer(), team)); } } else { // SP team update packet - getPlayer().sendPacket(new PacketAvatarTeamUpdateNotify(getPlayer())); + this.getPlayer().sendPacket(new PacketAvatarTeamUpdateNotify(this.getPlayer())); int teamId = this.getTeamId(team); if (teamId != -1) { // This is one of the player's teams // Update entites if (teamId == this.getCurrentTeamId()) { - this.updateTeamEntities(new PacketSetUpAvatarTeamRsp(getPlayer(), teamId, team)); + this.updateTeamEntities(new PacketSetUpAvatarTeamRsp(this.getPlayer(), teamId, team)); } else { - getPlayer().sendPacket(new PacketSetUpAvatarTeamRsp(getPlayer(), teamId, team)); + this.getPlayer().sendPacket(new PacketSetUpAvatarTeamRsp(this.getPlayer(), teamId, team)); } } } @@ -263,7 +264,7 @@ public class TeamManager extends BasePlayerDataManager { * Returns true if successful. */ public boolean addAvatarToTeam(TeamInfo team, Avatar avatar) { - return addAvatarsToTeam(team, Collections.singleton(avatar)); + return this.addAvatarsToTeam(team, Collections.singleton(avatar)); } /** @@ -276,7 +277,7 @@ public class TeamManager extends BasePlayerDataManager { if (this.useTemporarilyTeamIndex != -1) { return false; } - return addAvatarsToTeam(this.getCurrentTeamInfo(), avatars); + return this.addAvatarsToTeam(this.getCurrentTeamInfo(), avatars); } /** @@ -285,7 +286,7 @@ public class TeamManager extends BasePlayerDataManager { * Returns true if successful. */ public boolean addAvatarToCurrentTeam(Avatar avatar) { - return addAvatarsToCurrentTeam(Collections.singleton(avatar)); + return this.addAvatarsToCurrentTeam(Collections.singleton(avatar)); } private void updateTeamResonances() { @@ -294,7 +295,7 @@ public class TeamManager extends BasePlayerDataManager { this.getTeamResonances().clear(); this.getTeamResonancesConfig().clear(); - for (EntityAvatar entity : getActiveTeam()) { + for (EntityAvatar entity : this.getActiveTeam()) { AvatarSkillDepotData skillData = entity.getAvatar().getAvatarData().getSkillDepot(); if (skillData != null) { map.addTo(skillData.getElementType().getValue(), 1); @@ -329,7 +330,7 @@ public class TeamManager extends BasePlayerDataManager { Int2ObjectMap existingAvatars = new Int2ObjectOpenHashMap<>(); int prevSelectedAvatarIndex = -1; - for (EntityAvatar entity : getActiveTeam()) { + for (EntityAvatar entity : this.getActiveTeam()) { existingAvatars.put(entity.getAvatar().getAvatarId(), entity); } @@ -348,7 +349,7 @@ public class TeamManager extends BasePlayerDataManager { prevSelectedAvatarIndex = i; } } else { - entity = new EntityAvatar(getPlayer().getScene(), getPlayer().getAvatars().getAvatarById(avatarId)); + entity = new EntityAvatar(this.getPlayer().getScene(), this.getPlayer().getAvatars().getAvatarById(avatarId)); } this.getActiveTeam().add(entity); @@ -356,7 +357,7 @@ public class TeamManager extends BasePlayerDataManager { // Unload removed entities for (EntityAvatar entity : existingAvatars.values()) { - getPlayer().getScene().removeEntity(entity); + this.getPlayer().getScene().removeEntity(entity); entity.getAvatar().save(); } @@ -368,33 +369,33 @@ public class TeamManager extends BasePlayerDataManager { this.currentCharacterIndex = prevSelectedAvatarIndex; // Update team resonances - updateTeamResonances(); + this.updateTeamResonances(); // Packets - getPlayer().getWorld().broadcastPacket(new PacketSceneTeamUpdateNotify(getPlayer())); + this.getPlayer().getWorld().broadcastPacket(new PacketSceneTeamUpdateNotify(this.getPlayer())); // Skill charges packet - Yes, this is official server behavior as of 2.6.0 - for (EntityAvatar entity : getActiveTeam()) { + for (EntityAvatar entity : this.getActiveTeam()) { if (entity.getAvatar().getSkillExtraChargeMap().size() > 0) { - getPlayer().sendPacket(new PacketAvatarSkillInfoNotify(entity.getAvatar())); + this.getPlayer().sendPacket(new PacketAvatarSkillInfoNotify(entity.getAvatar())); } } // Run callback if (responsePacket != null) { - getPlayer().sendPacket(responsePacket); + this.getPlayer().sendPacket(responsePacket); } // Check if character changed - if (currentEntity != getCurrentAvatarEntity()) { + if (currentEntity != this.getCurrentAvatarEntity()) { // Remove and Add - getPlayer().getScene().replaceEntity(currentEntity, getCurrentAvatarEntity()); + this.getPlayer().getScene().replaceEntity(currentEntity, this.getCurrentAvatarEntity()); } } public synchronized void setupAvatarTeam(int teamId, List list) { // Sanity checks - if (list.size() == 0 || list.size() > getMaxTeamSize() || getPlayer().isInMultiplayer()) { + if (list.size() == 0 || list.size() > this.getMaxTeamSize() || this.getPlayer().isInMultiplayer()) { return; } @@ -407,7 +408,7 @@ public class TeamManager extends BasePlayerDataManager { // Set team data LinkedHashSet newTeam = new LinkedHashSet<>(); for (Long aLong : list) { - Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); + Avatar avatar = this.getPlayer().getAvatars().getAvatarByGuid(aLong); if (avatar == null || newTeam.contains(avatar)) { // Should never happen return; @@ -422,7 +423,7 @@ public class TeamManager extends BasePlayerDataManager { public void setupMpTeam(List list) { // Sanity checks - if (list.size() == 0 || list.size() > getMaxTeamSize() || !getPlayer().isInMultiplayer()) { + if (list.size() == 0 || list.size() > this.getMaxTeamSize() || !this.getPlayer().isInMultiplayer()) { return; } @@ -431,7 +432,7 @@ public class TeamManager extends BasePlayerDataManager { // Set team data LinkedHashSet newTeam = new LinkedHashSet<>(); for (Long aLong : list) { - Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); + Avatar avatar = this.getPlayer().getAvatars().getAvatarByGuid(aLong); if (avatar == null || newTeam.contains(avatar)) { // Should never happen return; @@ -447,14 +448,14 @@ public class TeamManager extends BasePlayerDataManager { public void setupTemporaryTeam(List> guidList) { this.temporaryTeam = guidList.stream().map(list -> { // Sanity checks - if (list.size() == 0 || list.size() > getMaxTeamSize()) { + if (list.size() == 0 || list.size() > this.getMaxTeamSize()) { return null; } // Set team data LinkedHashSet newTeam = new LinkedHashSet<>(); for (Long aLong : list) { - Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); + Avatar avatar = this.getPlayer().getAvatars().getAvatarByGuid(aLong); if (avatar == null || newTeam.contains(avatar)) { // Should never happen return null; @@ -474,7 +475,7 @@ public class TeamManager extends BasePlayerDataManager { public void useTemporaryTeam(int index) { this.useTemporarilyTeamIndex = index; - updateTeamEntities(null); + this.updateTeamEntities(null); } public void cleanTemporaryTeam() { @@ -485,11 +486,11 @@ public class TeamManager extends BasePlayerDataManager { this.useTemporarilyTeamIndex = -1; this.temporaryTeam = null; - updateTeamEntities(null); + this.updateTeamEntities(null); } public synchronized void setCurrentTeam(int teamId) { // - if (getPlayer().isInMultiplayer()) { + if (this.getPlayer().isInMultiplayer()) { return; } @@ -514,7 +515,7 @@ public class TeamManager extends BasePlayerDataManager { teamInfo.setName(teamName); // Packet - getPlayer().sendPacket(new PacketChangeTeamNameRsp(teamId, teamName)); + this.getPlayer().sendPacket(new PacketChangeTeamNameRsp(teamId, teamName)); } public synchronized void changeAvatar(long guid) { @@ -526,10 +527,10 @@ public class TeamManager extends BasePlayerDataManager { EntityAvatar newEntity = null; int index = -1; - for (int i = 0; i < getActiveTeam().size(); i++) { - if (guid == getActiveTeam().get(i).getAvatar().getGuid()) { + for (int i = 0; i < this.getActiveTeam().size(); i++) { + if (guid == this.getActiveTeam().get(i).getAvatar().getGuid()) { index = i; - newEntity = getActiveTeam().get(i); + newEntity = this.getActiveTeam().get(i); } } @@ -544,8 +545,8 @@ public class TeamManager extends BasePlayerDataManager { oldEntity.setMotionState(MotionState.MOTION_STATE_STANDBY); // Remove and Add - getPlayer().getScene().replaceEntity(oldEntity, newEntity); - getPlayer().sendPacket(new PacketChangeAvatarRsp(guid)); + this.getPlayer().getScene().replaceEntity(oldEntity, newEntity); + this.getPlayer().sendPacket(new PacketChangeAvatarRsp(guid)); } public void onAvatarDie(long dieGuid) { @@ -562,7 +563,7 @@ public class TeamManager extends BasePlayerDataManager { // Died in water. Do not replace // The official server has skipped this notify and will just respawn the team immediately after the animation. // TODO: Perhaps find a way to get vanilla experience? - getPlayer().sendPacket(new PacketWorldPlayerDieNotify(dieType, killedBy)); + this.getPlayer().sendPacket(new PacketWorldPlayerDieNotify(dieType, killedBy)); } else { // Replacement avatar EntityAvatar replacement = null; @@ -579,20 +580,24 @@ public class TeamManager extends BasePlayerDataManager { if (replacement == null) { // No more living team members... - getPlayer().sendPacket(new PacketWorldPlayerDieNotify(dieType, killedBy)); + this.getPlayer().sendPacket(new PacketWorldPlayerDieNotify(dieType, killedBy)); + // Invoke player team death event. + PlayerTeamDeathEvent event = new PlayerTeamDeathEvent(this.getPlayer(), + this.getActiveTeam().get(this.getCurrentCharacterIndex())); + event.call(); } else { // Set index and spawn replacement member this.setCurrentCharacterIndex(replaceIndex); - getPlayer().getScene().addEntity(replacement); + this.getPlayer().getScene().addEntity(replacement); } } // Response packet - getPlayer().sendPacket(new PacketAvatarDieAnimationEndRsp(deadAvatar.getId(), 0)); + this.getPlayer().sendPacket(new PacketAvatarDieAnimationEndRsp(deadAvatar.getId(), 0)); } public boolean reviveAvatar(Avatar avatar) { - for (EntityAvatar entity : getActiveTeam()) { + for (EntityAvatar entity : this.getActiveTeam()) { if (entity.getAvatar() == avatar) { if (entity.isAlive()) { return false; @@ -602,8 +607,8 @@ public class TeamManager extends BasePlayerDataManager { FightProperty.FIGHT_PROP_CUR_HP, entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .1f ); - getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); - getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); + this.getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); + this.getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); return true; } } @@ -612,7 +617,7 @@ public class TeamManager extends BasePlayerDataManager { } public boolean healAvatar(Avatar avatar, int healRate, int healAmount) { - for (EntityAvatar entity : getActiveTeam()) { + for (EntityAvatar entity : this.getActiveTeam()) { if (entity.getAvatar() == avatar) { if (!entity.isAlive()) { return false; @@ -627,8 +632,8 @@ public class TeamManager extends BasePlayerDataManager { entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) ) ); - getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); - getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); + this.getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); + this.getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); return true; } } @@ -646,29 +651,29 @@ public class TeamManager extends BasePlayerDataManager { player.getStaminaManager().stopSustainedStaminaHandler(); // prevent drowning immediately after respawn // Revive all team members - for (EntityAvatar entity : getActiveTeam()) { + for (EntityAvatar entity : this.getActiveTeam()) { entity.setFightProperty( FightProperty.FIGHT_PROP_CUR_HP, entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .4f ); - getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); - getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); + this.getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); + this.getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); } // Teleport player - getPlayer().sendPacket(new PacketPlayerEnterSceneNotify(getPlayer(), EnterType.ENTER_TYPE_SELF, EnterReason.Revival, 3, GameConstants.START_POSITION)); + this.getPlayer().sendPacket(new PacketPlayerEnterSceneNotify(this.getPlayer(), EnterType.ENTER_TYPE_SELF, EnterReason.Revival, 3, GameConstants.START_POSITION)); // Set player position player.setSceneId(3); player.getPosition().set(GameConstants.START_POSITION); // Packets - getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp)); + this.getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp)); } public void saveAvatars() { // Save all avatars from active team - for (EntityAvatar entity : getActiveTeam()) { + for (EntityAvatar entity : this.getActiveTeam()) { entity.getAvatar().save(); } } diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerTeamDeathEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerTeamDeathEvent.java new file mode 100644 index 000000000..0729dc53e --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/player/PlayerTeamDeathEvent.java @@ -0,0 +1,20 @@ +package emu.grasscutter.server.event.player; + +import emu.grasscutter.game.entity.EntityAvatar; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.types.PlayerEvent; +import lombok.Getter; + +/** + * This event is invoked when the ENTIRE TEAM dies. + * To listen for one player death, use {@link emu.grasscutter.server.event.entity.EntityDeathEvent}. + */ +public final class PlayerTeamDeathEvent extends PlayerEvent { + @Getter private final EntityAvatar selectedAvatar; + + public PlayerTeamDeathEvent(Player player, EntityAvatar selectedAvatar) { + super(player); + + this.selectedAvatar = selectedAvatar; + } +} \ No newline at end of file From 41ec2316e40880e2f42fbc65530900b2f35863e8 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sun, 24 Jul 2022 13:23:51 -0400 Subject: [PATCH 09/17] Attempt to fix the `teleport` command. --- .../grasscutter/command/commands/TeleportCommand.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java index a08565d79..b78778b77 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java @@ -55,10 +55,15 @@ public final class TeleportCommand implements CommandHandler { Position target_pos = new Position(x, y, z); PlayerTeleportEvent event = new PlayerTeleportEvent(targetPlayer, PlayerTeleportEvent.TeleportType.COMMAND, - targetPlayer.getPos(), target_pos); + targetPlayer.getPosition(), target_pos); event.call(); - boolean result = !event.isCanceled() || targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, event.getDestination()); + // Return if event was cancelled. + if(event.isCanceled()) { + return; + } + + boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, event.getDestination()); if (!result) { CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error")); } else { From c35705010aa976c1287574c2a53863059c3071dc Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Sun, 24 Jul 2022 13:27:43 -0400 Subject: [PATCH 10/17] Fix remaining traces of `Player#getPos` --- .../server/packet/recv/HandlerSceneTransToPointReq.java | 2 +- .../grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java index 28f4cffd0..895e43e6b 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java @@ -28,7 +28,7 @@ public class HandlerSceneTransToPointReq extends PacketHandler { float z = scenePointEntry.getPointData().getTranPos().getZ(); PlayerTeleportEvent event = new PlayerTeleportEvent(session.getPlayer(), PlayerTeleportEvent.TeleportType.WAYPOINT, - session.getPlayer().getPos(), new Position(x, y, z)); + session.getPlayer().getPosition(), new Position(x, y, z)); event.call(); if(!event.isCanceled()) { diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java index e1927f30f..fe6e1f182 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java @@ -40,7 +40,7 @@ public class HandlerTryEnterHomeReq extends PacketHandler { Position pos = scene.getScriptManager().getConfig().born_pos; PlayerTeleportEvent event = new PlayerTeleportEvent(session.getPlayer(), PlayerTeleportEvent.TeleportType.WAYPOINT, - session.getPlayer().getPos(), pos); + session.getPlayer().getPosition(), pos); event.call(); if(!event.isCanceled()) { From b9b4b6f42813187e409a71a79a2ec744c7b57321 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Mon, 1 Aug 2022 21:12:57 -0400 Subject: [PATCH 11/17] Clean-up the energy manager --- .../game/managers/energy/EnergyManager.java | 78 ++++++++++--------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java b/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java index e94a219fc..cf449977a 100644 --- a/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java +++ b/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java @@ -28,7 +28,6 @@ import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo; import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.utils.Position; -import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -42,15 +41,14 @@ import java.util.Optional; import java.util.concurrent.ThreadLocalRandom; import static emu.grasscutter.config.Configuration.GAME_OPTIONS; -import static java.util.Map.entry; import com.google.gson.reflect.TypeToken; import com.google.protobuf.InvalidProtocolBufferException; public class EnergyManager extends BasePlayerManager { private final Map avatarNormalProbabilities; -// energyUsage for each player - private Boolean energyUsage; + + private boolean energyUsage; // Should energy usage be enabled for this player? private final static Int2ObjectMap> energyDropData = new Int2ObjectOpenHashMap<>(); private final static Int2ObjectMap> skillParticleGenerationData = new Int2ObjectOpenHashMap<>(); @@ -90,9 +88,9 @@ public class EnergyManager extends BasePlayerManager { } } - /********** - Particle creation for elemental skills. - **********/ + /** + * Particle creation for elemental skills. + */ private int getBallCountForAvatar(int avatarId) { // We default to two particles. int count = 2; @@ -120,12 +118,12 @@ public class EnergyManager extends BasePlayerManager { } private int getBallIdForElement(ElementType element) { - // If we have no element, we default to an elementless particle. + // If we have no element, we default to an element-less particle. if (element == null) { return 2024; } - // Otherwise, we determin the particle's ID based on the element. + // Otherwise, we determine the particle's ID based on the element. return switch (element) { case Fire -> 2017; case Water -> 2018; @@ -156,7 +154,7 @@ public class EnergyManager extends BasePlayerManager { int amount = 2; // Try to get the casting avatar from the player's party. - Optional avatarEntity = getCastingAvatarEntityForEnergy(invoke.getEntityId()); + Optional avatarEntity = this.getCastingAvatarEntityForEnergy(invoke.getEntityId()); // Bug: invokes twice sometimes, Ayato, Keqing // ToDo: deal with press, hold difference. deal with charge(Beidou, Yunjin) @@ -174,20 +172,21 @@ public class EnergyManager extends BasePlayerManager { // particles we have to generate. if (skillDepotData != null) { ElementType element = skillDepotData.getElementType(); - itemId = getBallIdForElement(element); + itemId = this.getBallIdForElement(element); } } } // Generate the particles. for (int i = 0; i < amount; i++) { - generateElemBall(itemId, new Position(action.getPos()), 1); + this.generateElemBall(itemId, new Position(action.getPos()), 1); } } - /********** - Pickup of elemental particles and orbs. - **********/ + /** + * Pickup of elemental particles and orbs. + * @param elemBall The elemental particle or orb. + */ public void handlePickupElemBall(GameItem elemBall) { // Check if the item is indeed an energy particle/orb. if (elemBall.getItemId() < 2001 ||elemBall.getItemId() > 2024) { @@ -242,9 +241,10 @@ public class EnergyManager extends BasePlayerManager { } } - /********** - Energy generation for NAs/CAs. - **********/ + /** + * Energy generation for NAs/CAs. + * @param avatar The avatar. + */ private void generateEnergyForNormalAndCharged(EntityAvatar avatar) { // This logic is based on the descriptions given in // https://genshin-impact.fandom.com/wiki/Energy#Energy_Generated_by_Normal_Attacks @@ -290,11 +290,10 @@ public class EnergyManager extends BasePlayerManager { // Make sure the target is an actual enemy. GameEntity targetEntity = this.player.getScene().getEntityById(attackRes.getDefenseId()); - if (!(targetEntity instanceof EntityMonster)) { + if (!(targetEntity instanceof EntityMonster targetMonster)) { return; } - EntityMonster targetMonster = (EntityMonster)targetEntity; MonsterType targetType = targetMonster.getMonsterData().getType(); if (targetType != MonsterType.MONSTER_ORDINARY && targetType != MonsterType.MONSTER_BOSS) { return; @@ -319,10 +318,10 @@ public class EnergyManager extends BasePlayerManager { this.generateEnergyForNormalAndCharged(attackerEntity.get()); } + /* + * Energy logic related to using skills. + */ - /********** - Energy logic related to using skills. - **********/ private void handleBurstCast(Avatar avatar, int skillId) { // Don't do anything if energy usage is disabled. if (!GAME_OPTIONS.energyUsage || !this.energyUsage) { @@ -351,9 +350,10 @@ public class EnergyManager extends BasePlayerManager { this.handleBurstCast(avatar, skillId); } - /********** - Monster energy drops. - **********/ + /* + * Monster energy drops. + */ + private void generateElemBallDrops(EntityMonster monster, int dropId) { // Generate all drops specified for the given drop id. if (!energyDropData.containsKey(dropId)) { @@ -365,6 +365,7 @@ public class EnergyManager extends BasePlayerManager { this.generateElemBall(info.getBallId(), monster.getPosition(), info.getCount()); } } + public void handleMonsterEnergyDrop(EntityMonster monster, float hpBeforeDamage, float hpAfterDamage) { // Make sure this is actually a monster. // Note that some wildlife also has that type, like boars or birds. @@ -373,7 +374,7 @@ public class EnergyManager extends BasePlayerManager { return; } - // Calculate the HP tresholds for before and after the damage was taken. + // Calculate the HP thresholds for before and after the damage was taken. float maxHp = monster.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); float thresholdBefore = hpBeforeDamage / maxHp; float thresholdAfter = hpAfterDamage / maxHp; @@ -386,19 +387,20 @@ public class EnergyManager extends BasePlayerManager { float threshold = drop.getHpPercent() / 100.0f; if (threshold < thresholdBefore && threshold >= thresholdAfter) { - generateElemBallDrops(monster, drop.getDropId()); + this.generateElemBallDrops(monster, drop.getDropId()); } } // Handle kill drops. if (hpAfterDamage <= 0 && monster.getMonsterData().getKillDropId() != 0) { - generateElemBallDrops(monster, monster.getMonsterData().getKillDropId()); + this.generateElemBallDrops(monster, monster.getMonsterData().getKillDropId()); } } - /********** - Utility. - **********/ + /* + * Utilities. + */ + private void generateElemBall(int ballId, Position position, int count) { // Generate a particle/orb with the specified parameters. ItemData itemData = GameData.getItemDataMap().get(ballId); @@ -417,7 +419,7 @@ public class EnergyManager extends BasePlayerManager { // that cast the skill. // Try to get the invoking entity from the scene. - GameEntity entity = player.getScene().getEntityById(invokeEntityId); + GameEntity entity = this.player.getScene().getEntityById(invokeEntityId); // Determine the ID of the entity that originally cast this skill. If the scene entity is null, // or not an `EntityClientGadget`, we assume that we are directly looking at the casting avatar @@ -430,20 +432,20 @@ public class EnergyManager extends BasePlayerManager { : ((EntityClientGadget)entity).getOriginalOwnerEntityId(); // Finally, find the avatar entity in the player's team. - return player.getTeamManager().getActiveTeam() + return this.player.getTeamManager().getActiveTeam() .stream() .filter(character -> character.getId() == avatarEntityId) .findFirst(); } - public Boolean getEnergyUsage() { - return energyUsage; + public boolean getEnergyUsage() { + return this.energyUsage; } - public void setEnergyUsage(Boolean energyUsage) { + public void setEnergyUsage(boolean energyUsage) { this.energyUsage = energyUsage; if (!energyUsage) { // Refill team energy if usage is disabled - for (EntityAvatar entityAvatar : player.getTeamManager().getActiveTeam()) { + for (EntityAvatar entityAvatar : this.player.getTeamManager().getActiveTeam()) { entityAvatar.addEnergy(1000, PropChangeReason.PROP_CHANGE_REASON_GM,true); } } From 89575f587e6b1495fa96c95f99d1544454b0401e Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Mon, 1 Aug 2022 21:25:29 -0400 Subject: [PATCH 12/17] Move `PlayerTeleportEvent` occurrences into `World` --- .../command/commands/TeleportAllCommand.java | 11 +--- .../command/commands/TeleportCommand.java | 20 ++----- .../managers/mapmark/MapMarksManager.java | 36 +++++------ .../emu/grasscutter/game/world/World.java | 60 ++++++++++++------- .../event/player/PlayerTeleportEvent.java | 10 ++++ .../recv/HandlerSceneTransToPointReq.java | 13 +--- .../packet/recv/HandlerTryEnterHomeReq.java | 22 ++----- 7 files changed, 78 insertions(+), 94 deletions(-) diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java index e330cbfdc..ac817766b 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java @@ -3,8 +3,7 @@ package emu.grasscutter.command.commands; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; import emu.grasscutter.game.player.Player; -import emu.grasscutter.server.event.player.PlayerTeleportEvent; -import emu.grasscutter.utils.Position; +import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType; import java.util.List; @@ -24,13 +23,7 @@ public final class TeleportAllCommand implements CommandHandler { if (player.equals(targetPlayer)) continue; - Position pos = targetPlayer.getPosition(); - PlayerTeleportEvent event = new PlayerTeleportEvent(targetPlayer, PlayerTeleportEvent.TeleportType.COMMAND, - targetPlayer.getPosition(), pos); - event.call(); - - if(!event.isCanceled()) - player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), event.getDestination()); + player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), TeleportType.COMMAND, targetPlayer.getPosition()); } CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success")); diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java index b78778b77..6e5f99cc4 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java @@ -3,7 +3,7 @@ package emu.grasscutter.command.commands; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; import emu.grasscutter.game.player.Player; -import emu.grasscutter.server.event.player.PlayerTeleportEvent; +import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType; import emu.grasscutter.utils.Position; import java.util.List; @@ -41,29 +41,21 @@ public final class TeleportCommand implements CommandHandler { } // Fallthrough case 3: try { - x = parseRelative(args.get(0), x); - y = parseRelative(args.get(1), y); - z = parseRelative(args.get(2), z); + x = this.parseRelative(args.get(0), x); + y = this.parseRelative(args.get(1), y); + z = this.parseRelative(args.get(2), z); } catch (NumberFormatException ignored) { CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position")); } break; default: - sendUsageMessage(sender); + this.sendUsageMessage(sender); return; } Position target_pos = new Position(x, y, z); - PlayerTeleportEvent event = new PlayerTeleportEvent(targetPlayer, PlayerTeleportEvent.TeleportType.COMMAND, - targetPlayer.getPosition(), target_pos); - event.call(); + boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, TeleportType.COMMAND, target_pos); - // Return if event was cancelled. - if(event.isCanceled()) { - return; - } - - boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, event.getDestination()); if (!result) { CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error")); } else { diff --git a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java index 376f98738..23f9afd4d 100644 --- a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java +++ b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java @@ -5,12 +5,11 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType; import emu.grasscutter.net.proto.MarkMapReqOuterClass.MarkMapReq; import emu.grasscutter.net.proto.MarkMapReqOuterClass.MarkMapReq.Operation; -import emu.grasscutter.server.event.player.PlayerTeleportEvent; +import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType; import emu.grasscutter.server.packet.send.PacketMarkMapRsp; import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; import emu.grasscutter.utils.Position; -import java.util.HashMap; import java.util.Map; public class MapMarksManager extends BasePlayerManager { @@ -21,7 +20,7 @@ public class MapMarksManager extends BasePlayerManager { } public Map getMapMarks() { - return getPlayer().getMapMarks(); + return this.getPlayer().getMapMarks(); } public void handleMapMarkReq(MarkMapReq req) { @@ -31,26 +30,26 @@ public class MapMarksManager extends BasePlayerManager { MapMark createMark = new MapMark(req.getMark()); // keep teleporting functionality on fishhook mark. if (createMark.getMapMarkPointType() == MapMarkPointType.MAP_MARK_POINT_TYPE_FISH_POOL) { - teleport(player, createMark); + this.teleport(player, createMark); return; } - addMapMark(createMark); + this.addMapMark(createMark); } case OPERATION_MOD -> { MapMark oldMark = new MapMark(req.getOld()); - removeMapMark(oldMark.getPosition()); + this.removeMapMark(oldMark.getPosition()); MapMark newMark = new MapMark(req.getMark()); - addMapMark(newMark); + this.addMapMark(newMark); } case OPERATION_DEL -> { MapMark deleteMark = new MapMark(req.getMark()); - removeMapMark(deleteMark.getPosition()); + this.removeMapMark(deleteMark.getPosition()); } } if (op != Operation.OPERATION_GET) { - save(); + this.save(); } - player.getSession().send(new PacketMarkMapRsp(getMapMarks())); + player.getSession().send(new PacketMarkMapRsp(this.getMapMarks())); } public String getMapMarkKey(Position position) { @@ -58,12 +57,12 @@ public class MapMarksManager extends BasePlayerManager { } public void removeMapMark(Position position) { - getMapMarks().remove(getMapMarkKey(position)); + this.getMapMarks().remove(this.getMapMarkKey(position)); } public void addMapMark(MapMark mapMark) { - if (getMapMarks().size() < mapMarkMaxCount) { - getMapMarks().put(getMapMarkKey(mapMark.getPosition()), mapMark); + if (this.getMapMarks().size() < mapMarkMaxCount) { + this.getMapMarks().put(this.getMapMarkKey(mapMark.getPosition()), mapMark); } } @@ -75,14 +74,7 @@ public class MapMarksManager extends BasePlayerManager { } Position pos = mapMark.getPosition(); - PlayerTeleportEvent event = new PlayerTeleportEvent(player, PlayerTeleportEvent.TeleportType.MAP, - player.getPosition(), new Position(pos.getX(), y, pos.getZ())); - - event.call(); if(event.isCanceled()) return; - - player.getPosition().set(event.getDestination()); - if (mapMark.getSceneId() != player.getSceneId()) { - player.getWorld().transferPlayerToScene(player, mapMark.getSceneId(), player.getPosition()); - } player.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(player)); + player.getWorld().transferPlayerToScene(player, mapMark.getSceneId(), TeleportType.MAP, new Position(pos.getX(), y, pos.getZ())); + player.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(player)); } } diff --git a/src/main/java/emu/grasscutter/game/world/World.java b/src/main/java/emu/grasscutter/game/world/World.java index 9d6b972fb..66f669ca4 100644 --- a/src/main/java/emu/grasscutter/game/world/World.java +++ b/src/main/java/emu/grasscutter/game/world/World.java @@ -17,6 +17,8 @@ import emu.grasscutter.data.excels.SceneData; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType; import emu.grasscutter.scripts.data.SceneConfig; +import emu.grasscutter.server.event.player.PlayerTeleportEvent; +import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify; import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify; @@ -53,7 +55,7 @@ public class World implements Iterable { this.players = Collections.synchronizedList(new ArrayList<>()); this.scenes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>()); - this.levelEntityId = getNextEntityId(EntityIdType.MPLEVEL); + this.levelEntityId = this.getNextEntityId(EntityIdType.MPLEVEL); this.worldLevel = player.getWorldLevel(); this.isMultiplayer = isMultiplayer; @@ -101,7 +103,7 @@ public class World implements Iterable { public Scene getSceneById(int sceneId) { // Get scene normally - Scene scene = getScenes().get(sceneId); + Scene scene = this.getScenes().get(sceneId); if (scene != null) { return scene; } @@ -118,7 +120,7 @@ public class World implements Iterable { } public int getPlayerCount() { - return getPlayers().size(); + return this.getPlayers().size(); } public boolean isMultiplayer() { @@ -131,7 +133,7 @@ public class World implements Iterable { public synchronized void addPlayer(Player player) { // Check if player already in - if (getPlayers().contains(player)) { + if (this.getPlayers().contains(player)) { return; } @@ -142,11 +144,11 @@ public class World implements Iterable { // Register player.setWorld(this); - getPlayers().add(player); + this.getPlayers().add(player); // Set player variables player.setPeerId(this.getNextPeerId()); - player.getTeamManager().setEntityId(getNextEntityId(EntityIdType.TEAM)); + player.getTeamManager().setEntityId(this.getNextEntityId(EntityIdType.TEAM)); // Copy main team to multiplayer team if (this.isMultiplayer()) { @@ -169,12 +171,12 @@ public class World implements Iterable { player.sendPacket( new PacketDelTeamEntityNotify( player.getSceneId(), - getPlayers().stream().map(p -> p.getTeamManager().getEntityId()).collect(Collectors.toList()) + this.getPlayers().stream().map(p -> p.getTeamManager().getEntityId()).collect(Collectors.toList()) ) ); // Deregister - getPlayers().remove(player); + this.getPlayers().remove(player); player.setWorld(null); // Remove from scene @@ -187,7 +189,7 @@ public class World implements Iterable { } // Disband world if host leaves - if (getHost() == player) { + if (this.getHost() == player) { List kicked = new ArrayList<>(this.getPlayers()); for (Player victim : kicked) { World world = new World(victim); @@ -207,14 +209,28 @@ public class World implements Iterable { } public boolean transferPlayerToScene(Player player, int sceneId, Position pos) { - return transferPlayerToScene(player, sceneId, null, pos); + return this.transferPlayerToScene(player, sceneId, TeleportType.INTERNAL, null, pos); + } + + public boolean transferPlayerToScene(Player player, int sceneId, TeleportType teleportType, Position pos) { + return this.transferPlayerToScene(player, sceneId, teleportType, null, pos); } public boolean transferPlayerToScene(Player player, int sceneId, DungeonData data) { - return transferPlayerToScene(player, sceneId, data, null); + return this.transferPlayerToScene(player, sceneId, TeleportType.DUNGEON, data, null); } - public boolean transferPlayerToScene(Player player, int sceneId, DungeonData dungeonData, Position pos) { + public boolean transferPlayerToScene(Player player, int sceneId, TeleportType teleportType, DungeonData dungeonData, Position teleportTo) { + // Call player teleport event. + PlayerTeleportEvent event = new PlayerTeleportEvent(player, teleportType, player.getPosition(), teleportTo); + // Call event & check if it was canceled. + event.call(); if (event.isCanceled()) { + return false; // Teleport was canceled. + } + + // Set the destination. + teleportTo = event.getDestination(); + if (GameData.getSceneDataMap().get(sceneId) == null) { return false; } @@ -224,7 +240,7 @@ public class World implements Iterable { if (player.getScene() != null) { oldScene = player.getScene(); - // Dont deregister scenes if the player is going to tp back into them + // Don't deregister scenes if the player is going to tp back into them if (oldScene.getId() == sceneId) { oldScene.setDontDestroyWhenEmpty(true); } @@ -238,9 +254,9 @@ public class World implements Iterable { // Dungeon SceneConfig config = newScene.getScriptManager().getConfig(); - if (pos == null && config != null) { + if (teleportTo == null && config != null) { if (config.born_pos != null) { - pos = newScene.getScriptManager().getConfig().born_pos; + teleportTo = newScene.getScriptManager().getConfig().born_pos; } if (config.born_rot != null) { player.getRotation().set(config.born_rot); @@ -248,11 +264,11 @@ public class World implements Iterable { } // Set player position - if (pos == null) { - pos = player.getPosition(); + if (teleportTo == null) { + teleportTo = player.getPosition(); } - player.getPosition().set(pos); + player.getPosition().set(teleportTo); if (oldScene != null) { newScene.setPrevScene(oldScene.getId()); @@ -276,12 +292,12 @@ public class World implements Iterable { } // Teleport packet - player.sendPacket(new PacketPlayerEnterSceneNotify(player, enterType, enterReason, sceneId, pos)); + player.sendPacket(new PacketPlayerEnterSceneNotify(player, enterType, enterReason, sceneId, teleportTo)); return true; } private void updatePlayerInfos(Player paramPlayer) { - for (Player player : getPlayers()) { + for (Player player : this.getPlayers()) { // Dont send packets if player is logging in and filter out joining player if (!player.hasSentLoginPackets() || player == paramPlayer) { continue; @@ -292,7 +308,7 @@ public class World implements Iterable { player.getTeamManager().getMpTeam().copyFrom(player.getTeamManager().getMpTeam(), player.getTeamManager().getMaxTeamSize()); player.getTeamManager().updateTeamEntities(null); } - + // Dont send packets if player is loading into the scene if (player.getSceneLoadState().getValue() < SceneLoadState.INIT.getValue() ) { // World player info packets @@ -326,6 +342,6 @@ public class World implements Iterable { @Override public Iterator iterator() { - return getPlayers().iterator(); + return this.getPlayers().iterator(); } } diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerTeleportEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerTeleportEvent.java index 05928bb18..f7b9d2aae 100644 --- a/src/main/java/emu/grasscutter/server/event/player/PlayerTeleportEvent.java +++ b/src/main/java/emu/grasscutter/server/event/player/PlayerTeleportEvent.java @@ -35,6 +35,11 @@ public final class PlayerTeleportEvent extends PlayerEvent implements Cancellabl } public enum TeleportType { + /** + * There is no specified reason to teleport. + */ + INTERNAL, + /** * The player has asked to teleport to a waypoint. */ @@ -45,6 +50,11 @@ public final class PlayerTeleportEvent extends PlayerEvent implements Cancellabl */ MAP, + /** + * The player has asked to teleport into a dungeon. + */ + DUNGEON, + /** * The player has asked to teleport using the command. */ diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java index 895e43e6b..96ec7aa9e 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java @@ -5,9 +5,8 @@ import emu.grasscutter.data.binout.ScenePointEntry; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.SceneTransToPointReqOuterClass.SceneTransToPointReq; -import emu.grasscutter.net.proto.SceneTransToPointRspOuterClass.SceneTransToPointRsp; import emu.grasscutter.net.packet.PacketHandler; -import emu.grasscutter.server.event.player.PlayerTeleportEvent; +import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.PacketSceneTransToPointRsp; import emu.grasscutter.utils.Position; @@ -27,14 +26,8 @@ public class HandlerSceneTransToPointReq extends PacketHandler { float y = scenePointEntry.getPointData().getTranPos().getY(); float z = scenePointEntry.getPointData().getTranPos().getZ(); - PlayerTeleportEvent event = new PlayerTeleportEvent(session.getPlayer(), PlayerTeleportEvent.TeleportType.WAYPOINT, - session.getPlayer().getPosition(), new Position(x, y, z)); - event.call(); - - if(!event.isCanceled()) { - session.getPlayer().getWorld().transferPlayerToScene(session.getPlayer(), req.getSceneId(), new Position(x, y, z)); - session.send(new PacketSceneTransToPointRsp(session.getPlayer(), req.getPointId(), req.getSceneId())); - } + boolean result = session.getPlayer().getWorld().transferPlayerToScene(session.getPlayer(), req.getSceneId(), TeleportType.WAYPOINT, new Position(x, y, z)); + if(result) session.send(new PacketSceneTransToPointRsp(session.getPlayer(), req.getPointId(), req.getSceneId())); } else { session.send(new PacketSceneTransToPointRsp()); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java index fe6e1f182..fbd15dbcd 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java @@ -1,15 +1,11 @@ package emu.grasscutter.server.packet.recv; -import emu.grasscutter.data.GameData; -import emu.grasscutter.database.DatabaseHelper; -import emu.grasscutter.game.home.GameHome; import emu.grasscutter.game.world.Scene; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.TryEnterHomeReqOuterClass; -import emu.grasscutter.scripts.data.SceneConfig; -import emu.grasscutter.server.event.player.PlayerTeleportEvent; +import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.PacketTryEnterHomeRsp; import emu.grasscutter.utils.Position; @@ -39,17 +35,9 @@ public class HandlerTryEnterHomeReq extends PacketHandler { Scene scene = session.getPlayer().getWorld().getSceneById(realmId); Position pos = scene.getScriptManager().getConfig().born_pos; - PlayerTeleportEvent event = new PlayerTeleportEvent(session.getPlayer(), PlayerTeleportEvent.TeleportType.WAYPOINT, - session.getPlayer().getPosition(), pos); - event.call(); - - if(!event.isCanceled()) { - session.getPlayer().getWorld().transferPlayerToScene( - session.getPlayer(), - realmId, event.getDestination() - ); - - session.send(new PacketTryEnterHomeRsp(req.getTargetUid())); - } + boolean result = session.getPlayer().getWorld().transferPlayerToScene( + session.getPlayer(), realmId, + TeleportType.WAYPOINT, pos + ); if (result) session.send(new PacketTryEnterHomeRsp(req.getTargetUid())); } } From faeb96927a62fb84e5d24969459f25553875628f Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Mon, 1 Aug 2022 21:32:30 -0400 Subject: [PATCH 13/17] Add `PlayerUseFoodEvent` and implementations --- .../game/systems/InventorySystem.java | 56 +++++++++++-------- .../event/player/PlayerUseFoodEvent.java | 24 ++++++++ 2 files changed, 58 insertions(+), 22 deletions(-) create mode 100644 src/main/java/emu/grasscutter/server/event/player/PlayerUseFoodEvent.java diff --git a/src/main/java/emu/grasscutter/game/systems/InventorySystem.java b/src/main/java/emu/grasscutter/game/systems/InventorySystem.java index 537f1c0b7..fbea95715 100644 --- a/src/main/java/emu/grasscutter/game/systems/InventorySystem.java +++ b/src/main/java/emu/grasscutter/game/systems/InventorySystem.java @@ -30,6 +30,7 @@ import emu.grasscutter.game.shop.ShopChestBatchUseTable; import emu.grasscutter.game.shop.ShopChestTable; import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam; import emu.grasscutter.net.proto.MaterialInfoOuterClass.MaterialInfo; +import emu.grasscutter.server.event.player.PlayerUseFoodEvent; import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.*; @@ -812,38 +813,49 @@ public class InventorySystem extends BaseGameSystem { int used = 0; boolean useSuccess = false; + ItemData itemData = useItem.getItemData(); // Use - switch (useItem.getItemData().getMaterialType()) { + switch (itemData.getMaterialType()) { case MATERIAL_FOOD: - if (useItem.getItemData().getUseTarget() == ItemUseTarget.ITEM_USE_TARGET_SPECIFY_DEAD_AVATAR) { + if (itemData.getUseTarget() == ItemUseTarget.ITEM_USE_TARGET_SPECIFY_DEAD_AVATAR) { if (target == null) { break; } - used = player.getTeamManager().reviveAvatar(target) ? 1 : 0; + // Invoke player use food event. + PlayerUseFoodEvent event = new PlayerUseFoodEvent(player, itemData, target.getAsEntity()); + // Call the event. + event.call(); if(!event.isCanceled()) { + used = player.getTeamManager().reviveAvatar(target) ? 1 : 0; + } } else { used = 1; } break; case MATERIAL_NOTICE_ADD_HP: - if (useItem.getItemData().getUseTarget() == ItemUseTarget.ITEM_USE_TARGET_SPECIFY_ALIVE_AVATAR) { + if (itemData.getUseTarget() == ItemUseTarget.ITEM_USE_TARGET_SPECIFY_ALIVE_AVATAR) { if (target == null) { break; } - int[] SatiationParams = useItem.getItemData().getSatiationParams(); - used = player.getTeamManager().healAvatar(target, SatiationParams[0], SatiationParams[1]) ? 1 : 0; + // Invoke player use food event. + PlayerUseFoodEvent event = new PlayerUseFoodEvent(player, itemData, target.getAsEntity()); + // Call the event. + event.call(); if(!event.isCanceled()) { + int[] SatiationParams = itemData.getSatiationParams(); + used = player.getTeamManager().healAvatar(target, SatiationParams[0], SatiationParams[1]) ? 1 : 0; + } } break; case MATERIAL_CONSUME: // Make sure we have usage data for this material. - if (useItem.getItemData().getItemUse() == null) { + if (itemData.getItemUse() == null) { break; } - - ItemUseOp useOp = useItem.getItemData().getItemUse().get(0).getUseOp(); - + + ItemUseOp useOp = itemData.getItemUse().get(0).getUseOp(); + // Unlock item based on use operation useSuccess = switch (useOp) { case ITEM_USE_UNLOCK_FORGE -> player.getForgingManager().unlockForgingBlueprint(useItem); @@ -854,7 +866,7 @@ public class InventorySystem extends BaseGameSystem { break; case MATERIAL_FURNITURE_FORMULA: case MATERIAL_FURNITURE_SUITE_FORMULA: - if (useItem.getItemData().getItemUse() == null) { + if (itemData.getItemUse() == null) { break; } useSuccess = player.getFurnitureManager().unlockFurnitureOrSuite(useItem); @@ -862,7 +874,7 @@ public class InventorySystem extends BaseGameSystem { break; case MATERIAL_CONSUME_BATCH_USE: // Make sure we have usage data for this material. - if (useItem.getItemData().getItemUse() == null) { + if (itemData.getItemUse() == null) { break; } @@ -889,11 +901,11 @@ public class InventorySystem extends BaseGameSystem { } for (ItemParamData itemParamData : shopChestTable.getContainsItem()) { - ItemData itemData = GameData.getItemDataMap().get(itemParamData.getId()); - if (itemData == null) { + ItemData containedItem = GameData.getItemDataMap().get(itemParamData.getId()); + if (containedItem == null) { continue; } - rewardItemList.add(new GameItem(itemData, itemParamData.getCount())); + rewardItemList.add(new GameItem(containedItem, itemParamData.getCount())); } if (!rewardItemList.isEmpty()) { @@ -919,12 +931,12 @@ public class InventorySystem extends BaseGameSystem { } int optionItemId = shopChestBatchUseTable.getOptionItem().get(optionId - 1); - ItemData itemData = GameData.getItemDataMap().get(optionItemId); - if (itemData == null) { + ItemData optionItem = GameData.getItemDataMap().get(optionItemId); + if (optionItem == null) { break; } - player.getInventory().addItem(new GameItem(itemData, count), ActionReason.Shop); + player.getInventory().addItem(new GameItem(optionItem, count), ActionReason.Shop); used = count; break; @@ -944,23 +956,23 @@ public class InventorySystem extends BaseGameSystem { // we return the item to make UseItemRsp a success. if (used > 0) { // Handle use params, mainly server buffs - for (ItemUseData useData : useItem.getItemData().getItemUse()) { + for (ItemUseData useData : itemData.getItemUse()) { switch (useData.getUseOp()) { case ITEM_USE_ADD_SERVER_BUFF -> { int buffId = Integer.parseInt(useData.getUseParam()[0]); float time = Float.parseFloat(useData.getUseParam()[1]); - + player.getBuffManager().addBuff(buffId, time); } default -> {} } } - + // Remove item from inventory since we used it player.getInventory().removeItem(useItem, used); return useItem; } - + if (useSuccess) { return useItem; } diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerUseFoodEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerUseFoodEvent.java new file mode 100644 index 000000000..63f665e6e --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/player/PlayerUseFoodEvent.java @@ -0,0 +1,24 @@ +package emu.grasscutter.server.event.player; + +import emu.grasscutter.data.excels.ItemData; +import emu.grasscutter.game.entity.EntityAvatar; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.Cancellable; +import emu.grasscutter.server.event.types.PlayerEvent; +import lombok.Getter; +import lombok.Setter; + +/** + * This event is invoked when the player uses food on an avatar. + */ +public final class PlayerUseFoodEvent extends PlayerEvent implements Cancellable { + @Getter @Setter private ItemData foodUsed; + @Getter private final EntityAvatar selectedAvatar; + + public PlayerUseFoodEvent(Player player, ItemData foodUsed, EntityAvatar selectedAvatar) { + super(player); + + this.foodUsed = foodUsed; + this.selectedAvatar = selectedAvatar; + } +} \ No newline at end of file From 9cb9fe099c884a3122605c46a1e179771c3af8b1 Mon Sep 17 00:00:00 2001 From: Magix <27646710+KingRainbow44@users.noreply.github.com> Date: Thu, 4 Aug 2022 13:44:50 -0400 Subject: [PATCH 14/17] Update src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java Co-authored-by: Luke H-W --- .../grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java index fbd15dbcd..a4fd488f2 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java @@ -38,6 +38,7 @@ public class HandlerTryEnterHomeReq extends PacketHandler { boolean result = session.getPlayer().getWorld().transferPlayerToScene( session.getPlayer(), realmId, TeleportType.WAYPOINT, pos - ); if (result) session.send(new PacketTryEnterHomeRsp(req.getTargetUid())); + ); + if (result) session.send(new PacketTryEnterHomeRsp(req.getTargetUid())); } } From 164baa7251dcdc709226003fd377b1875de245f4 Mon Sep 17 00:00:00 2001 From: Magix <27646710+KingRainbow44@users.noreply.github.com> Date: Thu, 4 Aug 2022 13:44:56 -0400 Subject: [PATCH 15/17] Update src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java Co-authored-by: Luke H-W --- .../grasscutter/game/managers/mapmark/MapMarksManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java index 23f9afd4d..a40fbaaa6 100644 --- a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java +++ b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java @@ -67,8 +67,9 @@ public class MapMarksManager extends BasePlayerManager { } private void teleport(Player player, MapMark mapMark) { - float y; try { - y = (float)Integer.parseInt(mapMark.getName()); + float y; + try { + y = Float.parseFloat(mapMark.getName()); } catch (Exception e) { y = 300; } From d24c10eec53656310f74d9ad78b29b7438afb835 Mon Sep 17 00:00:00 2001 From: Magix <27646710+KingRainbow44@users.noreply.github.com> Date: Thu, 4 Aug 2022 13:45:02 -0400 Subject: [PATCH 16/17] Update src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java Co-authored-by: Luke H-W --- .../server/packet/recv/HandlerSceneTransToPointReq.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java index 96ec7aa9e..16d6a0e69 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java @@ -26,8 +26,8 @@ public class HandlerSceneTransToPointReq extends PacketHandler { float y = scenePointEntry.getPointData().getTranPos().getY(); float z = scenePointEntry.getPointData().getTranPos().getZ(); - boolean result = session.getPlayer().getWorld().transferPlayerToScene(session.getPlayer(), req.getSceneId(), TeleportType.WAYPOINT, new Position(x, y, z)); - if(result) session.send(new PacketSceneTransToPointRsp(session.getPlayer(), req.getPointId(), req.getSceneId())); + if (session.getPlayer().getWorld().transferPlayerToScene(session.getPlayer(), req.getSceneId(), TeleportType.WAYPOINT, new Position(x, y, z))) { + session.send(new PacketSceneTransToPointRsp(session.getPlayer(), req.getPointId(), req.getSceneId())); } else { session.send(new PacketSceneTransToPointRsp()); } From a3e0f7f5f0b88e1e2ed442cc2f81f172e49e382d Mon Sep 17 00:00:00 2001 From: Magix <27646710+KingRainbow44@users.noreply.github.com> Date: Thu, 4 Aug 2022 13:49:38 -0400 Subject: [PATCH 17/17] Update HandlerSceneTransToPointReq.java --- .../server/packet/recv/HandlerSceneTransToPointReq.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java index 16d6a0e69..70b2f78d3 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java @@ -28,6 +28,7 @@ public class HandlerSceneTransToPointReq extends PacketHandler { if (session.getPlayer().getWorld().transferPlayerToScene(session.getPlayer(), req.getSceneId(), TeleportType.WAYPOINT, new Position(x, y, z))) { session.send(new PacketSceneTransToPointRsp(session.getPlayer(), req.getPointId(), req.getSceneId())); + } } else { session.send(new PacketSceneTransToPointRsp()); }