Commit d05b3207 authored by Magix's avatar Magix Committed by GitHub
Browse files

Add more events

Merge pull request #1516 from Grasscutters/more-events
parents 9a104f6f a3e0f7f5
...@@ -3,7 +3,7 @@ package emu.grasscutter.command.commands; ...@@ -3,7 +3,7 @@ package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.Position; import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import java.util.List; import java.util.List;
...@@ -22,9 +22,8 @@ public final class TeleportAllCommand implements CommandHandler { ...@@ -22,9 +22,8 @@ public final class TeleportAllCommand implements CommandHandler {
for (Player player : targetPlayer.getWorld().getPlayers()) { for (Player player : targetPlayer.getWorld().getPlayers()) {
if (player.equals(targetPlayer)) if (player.equals(targetPlayer))
continue; continue;
Position pos = targetPlayer.getPosition();
player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), pos); player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), TeleportType.COMMAND, targetPlayer.getPosition());
} }
CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success"));
......
...@@ -3,6 +3,7 @@ package emu.grasscutter.command.commands; ...@@ -3,6 +3,7 @@ package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.List; import java.util.List;
...@@ -40,20 +41,21 @@ public final class TeleportCommand implements CommandHandler { ...@@ -40,20 +41,21 @@ public final class TeleportCommand implements CommandHandler {
} // Fallthrough } // Fallthrough
case 3: case 3:
try { try {
x = parseRelative(args.get(0), x); x = this.parseRelative(args.get(0), x);
y = parseRelative(args.get(1), y); y = this.parseRelative(args.get(1), y);
z = parseRelative(args.get(2), z); z = this.parseRelative(args.get(2), z);
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position"));
} }
break; break;
default: default:
sendUsageMessage(sender); this.sendUsageMessage(sender);
return; return;
} }
Position target_pos = new Position(x, y, z); Position target_pos = new Position(x, y, z);
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, target_pos); boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, TeleportType.COMMAND, target_pos);
if (!result) { if (!result) {
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error")); CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error"));
} else { } else {
......
...@@ -30,6 +30,7 @@ import emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo; ...@@ -30,6 +30,7 @@ import emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo;
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo; import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import emu.grasscutter.net.proto.VectorOuterClass.Vector; 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.PacketAvatarFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
...@@ -108,12 +109,16 @@ public class EntityAvatar extends GameEntity { ...@@ -108,12 +109,16 @@ public class EntityAvatar extends GameEntity {
@Override @Override
public void onDeath(int killerId) { public void onDeath(int killerId) {
super.onDeath(killerId); // Invoke super class's onDeath() method.
this.killedType = PlayerDieType.PLAYER_DIE_TYPE_KILL_BY_MONSTER; this.killedType = PlayerDieType.PLAYER_DIE_TYPE_KILL_BY_MONSTER;
this.killedBy = killerId; this.killedBy = killerId;
clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE); clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE);
} }
public void onDeath(PlayerDieType dieType, int killerId) { public void onDeath(PlayerDieType dieType, int killerId) {
super.onDeath(killerId); // Invoke super class's onDeath() method.
this.killedType = dieType; this.killedType = dieType;
this.killedBy = killerId; this.killedBy = killerId;
clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE); clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE);
...@@ -314,4 +319,21 @@ public class EntityAvatar extends GameEntity { ...@@ -314,4 +319,21 @@ public class EntityAvatar extends GameEntity {
// //
return abilityControlBlock.build(); 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);
}
} }
...@@ -13,6 +13,6 @@ public abstract class EntityBaseGadget extends GameEntity { ...@@ -13,6 +13,6 @@ public abstract class EntityBaseGadget extends GameEntity {
@Override @Override
public void onDeath(int killerId) { public void onDeath(int killerId) {
super.onDeath(killerId); // Invoke super class's onDeath() method.
} }
} }
...@@ -3,7 +3,6 @@ package emu.grasscutter.game.entity; ...@@ -3,7 +3,6 @@ package emu.grasscutter.game.entity;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.world.World;
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass; import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass;
...@@ -11,7 +10,6 @@ import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityIn ...@@ -11,7 +10,6 @@ import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityIn
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData; import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
import emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify; 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.MotionInfoOuterClass.MotionInfo;
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
...@@ -95,7 +93,7 @@ public class EntityClientGadget extends EntityBaseGadget { ...@@ -95,7 +93,7 @@ public class EntityClientGadget extends EntityBaseGadget {
@Override @Override
public void onDeath(int killerId) { public void onDeath(int killerId) {
super.onDeath(killerId); // Invoke super class's onDeath() method.
} }
@Override @Override
......
...@@ -175,6 +175,8 @@ public class EntityGadget extends EntityBaseGadget { ...@@ -175,6 +175,8 @@ public class EntityGadget extends EntityBaseGadget {
@Override @Override
public void onDeath(int killerId) { public void onDeath(int killerId) {
super.onDeath(killerId); // Invoke super class's onDeath() method.
if (this.getSpawnEntry() != null) { if (this.getSpawnEntry() != null) {
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry()); this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
} }
......
...@@ -158,6 +158,8 @@ public class EntityMonster extends GameEntity { ...@@ -158,6 +158,8 @@ public class EntityMonster extends GameEntity {
@Override @Override
public void onDeath(int killerId) { public void onDeath(int killerId) {
super.onDeath(killerId); // Invoke super class's onDeath() method.
if (this.getSpawnEntry() != null) { if (this.getSpawnEntry() != null) {
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry()); this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
} }
......
...@@ -15,6 +15,7 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; ...@@ -15,6 +15,7 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState; import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import emu.grasscutter.net.proto.VectorOuterClass.Vector; import emu.grasscutter.net.proto.VectorOuterClass.Vector;
import emu.grasscutter.server.event.entity.EntityDeathEvent;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.ints.Int2FloatMap; import it.unimi.dsi.fastutil.ints.Int2FloatMap;
...@@ -230,6 +231,17 @@ public abstract class GameEntity { ...@@ -230,6 +231,17 @@ public abstract class GameEntity {
} }
} }
/**
* 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 a player interacts with this entity * Called when a player interacts with this entity
* @param player Player that is interacting with this entity * @param player Player that is interacting with this entity
...@@ -251,7 +263,9 @@ public abstract class GameEntity { ...@@ -251,7 +263,9 @@ public abstract class GameEntity {
* @param killerId Entity id of the entity that killed this entity * @param killerId Entity id of the entity that killed this entity
*/ */
public void onDeath(int killerId) { public void onDeath(int killerId) {
// Invoke entity death event.
EntityDeathEvent event = new EntityDeathEvent(this, killerId);
event.call();
} }
public abstract SceneEntityInfo toProto(); public abstract SceneEntityInfo toProto();
......
...@@ -28,7 +28,6 @@ import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo; ...@@ -28,7 +28,6 @@ import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo;
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason; import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.utils.Position; 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.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
...@@ -42,15 +41,14 @@ import java.util.Optional; ...@@ -42,15 +41,14 @@ import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import static emu.grasscutter.config.Configuration.GAME_OPTIONS; import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
import static java.util.Map.entry;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
public class EnergyManager extends BasePlayerManager { public class EnergyManager extends BasePlayerManager {
private final Map<EntityAvatar, Integer> avatarNormalProbabilities; private final Map<EntityAvatar, Integer> avatarNormalProbabilities;
// energyUsage for each player
private Boolean energyUsage; private boolean energyUsage; // Should energy usage be enabled for this player?
private final static Int2ObjectMap<List<EnergyDropInfo>> energyDropData = new Int2ObjectOpenHashMap<>(); private final static Int2ObjectMap<List<EnergyDropInfo>> energyDropData = new Int2ObjectOpenHashMap<>();
private final static Int2ObjectMap<List<SkillParticleGenerationInfo>> skillParticleGenerationData = new Int2ObjectOpenHashMap<>(); private final static Int2ObjectMap<List<SkillParticleGenerationInfo>> skillParticleGenerationData = new Int2ObjectOpenHashMap<>();
...@@ -90,9 +88,9 @@ public class EnergyManager extends BasePlayerManager { ...@@ -90,9 +88,9 @@ public class EnergyManager extends BasePlayerManager {
} }
} }
/********** /**
Particle creation for elemental skills. * Particle creation for elemental skills.
**********/ */
private int getBallCountForAvatar(int avatarId) { private int getBallCountForAvatar(int avatarId) {
// We default to two particles. // We default to two particles.
int count = 2; int count = 2;
...@@ -120,12 +118,12 @@ public class EnergyManager extends BasePlayerManager { ...@@ -120,12 +118,12 @@ public class EnergyManager extends BasePlayerManager {
} }
private int getBallIdForElement(ElementType element) { 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) { if (element == null) {
return 2024; 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) { return switch (element) {
case Fire -> 2017; case Fire -> 2017;
case Water -> 2018; case Water -> 2018;
...@@ -156,7 +154,7 @@ public class EnergyManager extends BasePlayerManager { ...@@ -156,7 +154,7 @@ public class EnergyManager extends BasePlayerManager {
int amount = 2; int amount = 2;
// Try to get the casting avatar from the player's party. // Try to get the casting avatar from the player's party.
Optional<EntityAvatar> avatarEntity = getCastingAvatarEntityForEnergy(invoke.getEntityId()); Optional<EntityAvatar> avatarEntity = this.getCastingAvatarEntityForEnergy(invoke.getEntityId());
// Bug: invokes twice sometimes, Ayato, Keqing // Bug: invokes twice sometimes, Ayato, Keqing
// ToDo: deal with press, hold difference. deal with charge(Beidou, Yunjin) // ToDo: deal with press, hold difference. deal with charge(Beidou, Yunjin)
...@@ -174,20 +172,21 @@ public class EnergyManager extends BasePlayerManager { ...@@ -174,20 +172,21 @@ public class EnergyManager extends BasePlayerManager {
// particles we have to generate. // particles we have to generate.
if (skillDepotData != null) { if (skillDepotData != null) {
ElementType element = skillDepotData.getElementType(); ElementType element = skillDepotData.getElementType();
itemId = getBallIdForElement(element); itemId = this.getBallIdForElement(element);
} }
} }
} }
// Generate the particles. // Generate the particles.
for (int i = 0; i < amount; i++) { 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) { public void handlePickupElemBall(GameItem elemBall) {
// Check if the item is indeed an energy particle/orb. // Check if the item is indeed an energy particle/orb.
if (elemBall.getItemId() < 2001 ||elemBall.getItemId() > 2024) { if (elemBall.getItemId() < 2001 ||elemBall.getItemId() > 2024) {
...@@ -242,9 +241,10 @@ public class EnergyManager extends BasePlayerManager { ...@@ -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) { private void generateEnergyForNormalAndCharged(EntityAvatar avatar) {
// This logic is based on the descriptions given in // This logic is based on the descriptions given in
// https://genshin-impact.fandom.com/wiki/Energy#Energy_Generated_by_Normal_Attacks // https://genshin-impact.fandom.com/wiki/Energy#Energy_Generated_by_Normal_Attacks
...@@ -290,11 +290,10 @@ public class EnergyManager extends BasePlayerManager { ...@@ -290,11 +290,10 @@ public class EnergyManager extends BasePlayerManager {
// Make sure the target is an actual enemy. // Make sure the target is an actual enemy.
GameEntity targetEntity = this.player.getScene().getEntityById(attackRes.getDefenseId()); GameEntity targetEntity = this.player.getScene().getEntityById(attackRes.getDefenseId());
if (!(targetEntity instanceof EntityMonster)) { if (!(targetEntity instanceof EntityMonster targetMonster)) {
return; return;
} }
EntityMonster targetMonster = (EntityMonster)targetEntity;
MonsterType targetType = targetMonster.getMonsterData().getType(); MonsterType targetType = targetMonster.getMonsterData().getType();
if (targetType != MonsterType.MONSTER_ORDINARY && targetType != MonsterType.MONSTER_BOSS) { if (targetType != MonsterType.MONSTER_ORDINARY && targetType != MonsterType.MONSTER_BOSS) {
return; return;
...@@ -319,10 +318,10 @@ public class EnergyManager extends BasePlayerManager { ...@@ -319,10 +318,10 @@ public class EnergyManager extends BasePlayerManager {
this.generateEnergyForNormalAndCharged(attackerEntity.get()); this.generateEnergyForNormalAndCharged(attackerEntity.get());
} }
/*
* Energy logic related to using skills.
*/
/**********
Energy logic related to using skills.
**********/
private void handleBurstCast(Avatar avatar, int skillId) { private void handleBurstCast(Avatar avatar, int skillId) {
// Don't do anything if energy usage is disabled. // Don't do anything if energy usage is disabled.
if (!GAME_OPTIONS.energyUsage || !this.energyUsage) { if (!GAME_OPTIONS.energyUsage || !this.energyUsage) {
...@@ -351,9 +350,10 @@ public class EnergyManager extends BasePlayerManager { ...@@ -351,9 +350,10 @@ public class EnergyManager extends BasePlayerManager {
this.handleBurstCast(avatar, skillId); this.handleBurstCast(avatar, skillId);
} }
/********** /*
Monster energy drops. * Monster energy drops.
**********/ */
private void generateElemBallDrops(EntityMonster monster, int dropId) { private void generateElemBallDrops(EntityMonster monster, int dropId) {
// Generate all drops specified for the given drop id. // Generate all drops specified for the given drop id.
if (!energyDropData.containsKey(dropId)) { if (!energyDropData.containsKey(dropId)) {
...@@ -365,6 +365,7 @@ public class EnergyManager extends BasePlayerManager { ...@@ -365,6 +365,7 @@ public class EnergyManager extends BasePlayerManager {
this.generateElemBall(info.getBallId(), monster.getPosition(), info.getCount()); this.generateElemBall(info.getBallId(), monster.getPosition(), info.getCount());
} }
} }
public void handleMonsterEnergyDrop(EntityMonster monster, float hpBeforeDamage, float hpAfterDamage) { public void handleMonsterEnergyDrop(EntityMonster monster, float hpBeforeDamage, float hpAfterDamage) {
// Make sure this is actually a monster. // Make sure this is actually a monster.
// Note that some wildlife also has that type, like boars or birds. // Note that some wildlife also has that type, like boars or birds.
...@@ -373,7 +374,7 @@ public class EnergyManager extends BasePlayerManager { ...@@ -373,7 +374,7 @@ public class EnergyManager extends BasePlayerManager {
return; 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 maxHp = monster.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
float thresholdBefore = hpBeforeDamage / maxHp; float thresholdBefore = hpBeforeDamage / maxHp;
float thresholdAfter = hpAfterDamage / maxHp; float thresholdAfter = hpAfterDamage / maxHp;
...@@ -386,19 +387,20 @@ public class EnergyManager extends BasePlayerManager { ...@@ -386,19 +387,20 @@ public class EnergyManager extends BasePlayerManager {
float threshold = drop.getHpPercent() / 100.0f; float threshold = drop.getHpPercent() / 100.0f;
if (threshold < thresholdBefore && threshold >= thresholdAfter) { if (threshold < thresholdBefore && threshold >= thresholdAfter) {
generateElemBallDrops(monster, drop.getDropId()); this.generateElemBallDrops(monster, drop.getDropId());
} }
} }
// Handle kill drops. // Handle kill drops.
if (hpAfterDamage <= 0 && monster.getMonsterData().getKillDropId() != 0) { 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) { private void generateElemBall(int ballId, Position position, int count) {
// Generate a particle/orb with the specified parameters. // Generate a particle/orb with the specified parameters.
ItemData itemData = GameData.getItemDataMap().get(ballId); ItemData itemData = GameData.getItemDataMap().get(ballId);
...@@ -417,7 +419,7 @@ public class EnergyManager extends BasePlayerManager { ...@@ -417,7 +419,7 @@ public class EnergyManager extends BasePlayerManager {
// that cast the skill. // that cast the skill.
// Try to get the invoking entity from the scene. // 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, // 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 // or not an `EntityClientGadget`, we assume that we are directly looking at the casting avatar
...@@ -430,20 +432,20 @@ public class EnergyManager extends BasePlayerManager { ...@@ -430,20 +432,20 @@ public class EnergyManager extends BasePlayerManager {
: ((EntityClientGadget)entity).getOriginalOwnerEntityId(); : ((EntityClientGadget)entity).getOriginalOwnerEntityId();
// Finally, find the avatar entity in the player's team. // Finally, find the avatar entity in the player's team.
return player.getTeamManager().getActiveTeam() return this.player.getTeamManager().getActiveTeam()
.stream() .stream()
.filter(character -> character.getId() == avatarEntityId) .filter(character -> character.getId() == avatarEntityId)
.findFirst(); .findFirst();
} }
public Boolean getEnergyUsage() { public boolean getEnergyUsage() {
return energyUsage; return this.energyUsage;
} }
public void setEnergyUsage(Boolean energyUsage) { public void setEnergyUsage(boolean energyUsage) {
this.energyUsage = energyUsage; this.energyUsage = energyUsage;
if (!energyUsage) { // Refill team energy if usage is disabled 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); entityAvatar.addEnergy(1000, PropChangeReason.PROP_CHANGE_REASON_GM,true);
} }
} }
......
...@@ -5,11 +5,11 @@ import emu.grasscutter.game.player.Player; ...@@ -5,11 +5,11 @@ import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType; import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType;
import emu.grasscutter.net.proto.MarkMapReqOuterClass.MarkMapReq; import emu.grasscutter.net.proto.MarkMapReqOuterClass.MarkMapReq;
import emu.grasscutter.net.proto.MarkMapReqOuterClass.MarkMapReq.Operation; import emu.grasscutter.net.proto.MarkMapReqOuterClass.MarkMapReq.Operation;
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import emu.grasscutter.server.packet.send.PacketMarkMapRsp; import emu.grasscutter.server.packet.send.PacketMarkMapRsp;
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class MapMarksManager extends BasePlayerManager { public class MapMarksManager extends BasePlayerManager {
...@@ -20,7 +20,7 @@ public class MapMarksManager extends BasePlayerManager { ...@@ -20,7 +20,7 @@ public class MapMarksManager extends BasePlayerManager {
} }
public Map<String, MapMark> getMapMarks() { public Map<String, MapMark> getMapMarks() {
return getPlayer().getMapMarks(); return this.getPlayer().getMapMarks();
} }
public void handleMapMarkReq(MarkMapReq req) { public void handleMapMarkReq(MarkMapReq req) {
...@@ -30,26 +30,26 @@ public class MapMarksManager extends BasePlayerManager { ...@@ -30,26 +30,26 @@ public class MapMarksManager extends BasePlayerManager {
MapMark createMark = new MapMark(req.getMark()); MapMark createMark = new MapMark(req.getMark());
// keep teleporting functionality on fishhook mark. // keep teleporting functionality on fishhook mark.
if (createMark.getMapMarkPointType() == MapMarkPointType.MAP_MARK_POINT_TYPE_FISH_POOL) { if (createMark.getMapMarkPointType() == MapMarkPointType.MAP_MARK_POINT_TYPE_FISH_POOL) {
teleport(player, createMark); this.teleport(player, createMark);
return; return;
} }
addMapMark(createMark); this.addMapMark(createMark);
} }
case OPERATION_MOD -> { case OPERATION_MOD -> {
MapMark oldMark = new MapMark(req.getOld()); MapMark oldMark = new MapMark(req.getOld());
removeMapMark(oldMark.getPosition()); this.removeMapMark(oldMark.getPosition());
MapMark newMark = new MapMark(req.getMark()); MapMark newMark = new MapMark(req.getMark());
addMapMark(newMark); this.addMapMark(newMark);
} }
case OPERATION_DEL -> { case OPERATION_DEL -> {
MapMark deleteMark = new MapMark(req.getMark()); MapMark deleteMark = new MapMark(req.getMark());
removeMapMark(deleteMark.getPosition()); this.removeMapMark(deleteMark.getPosition());
} }
} }
if (op != Operation.OPERATION_GET) { 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) { public String getMapMarkKey(Position position) {
...@@ -57,27 +57,25 @@ public class MapMarksManager extends BasePlayerManager { ...@@ -57,27 +57,25 @@ public class MapMarksManager extends BasePlayerManager {
} }
public void removeMapMark(Position position) { public void removeMapMark(Position position) {
getMapMarks().remove(getMapMarkKey(position)); this.getMapMarks().remove(this.getMapMarkKey(position));
} }
public void addMapMark(MapMark mapMark) { public void addMapMark(MapMark mapMark) {
if (getMapMarks().size() < mapMarkMaxCount) { if (this.getMapMarks().size() < mapMarkMaxCount) {
getMapMarks().put(getMapMarkKey(mapMark.getPosition()), mapMark); this.getMapMarks().put(this.getMapMarkKey(mapMark.getPosition()), mapMark);
} }
} }
private void teleport(Player player, MapMark mapMark) { private void teleport(Player player, MapMark mapMark) {
float y; float y;
try { try {
y = (float)Integer.parseInt(mapMark.getName()); y = Float.parseFloat(mapMark.getName());
} catch (Exception e) { } catch (Exception e) {
y = 300; y = 300;
} }
Position pos = mapMark.getPosition(); Position pos = mapMark.getPosition();
player.getPosition().set(pos.getX(), y, pos.getZ()); player.getWorld().transferPlayerToScene(player, mapMark.getSceneId(), TeleportType.MAP, new Position(pos.getX(), y, pos.getZ()));
if (mapMark.getSceneId() != player.getSceneId()) {
player.getWorld().transferPlayerToScene(player, mapMark.getSceneId(), player.getPosition());
}
player.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(player)); player.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(player));
} }
} }
...@@ -20,6 +20,7 @@ import emu.grasscutter.net.packet.PacketOpcodes; ...@@ -20,6 +20,7 @@ import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType; import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState; import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType; 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.PacketAvatarDieAnimationEndRsp;
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify; import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify;
...@@ -76,7 +77,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -76,7 +77,7 @@ public class TeamManager extends BasePlayerDataManager {
} }
public World getWorld() { public World getWorld() {
return getPlayer().getWorld(); return this.getPlayer().getWorld();
} }
public Map<Integer, TeamInfo> getTeams() { public Map<Integer, TeamInfo> getTeams() {
...@@ -123,7 +124,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -123,7 +124,7 @@ public class TeamManager extends BasePlayerDataManager {
} }
public long getCurrentCharacterGuid() { public long getCurrentCharacterGuid() {
return getCurrentAvatarEntity().getAvatar().getGuid(); return this.getCurrentAvatarEntity().getAvatar().getGuid();
} }
public TeamInfo getCurrentTeamInfo() { public TeamInfo getCurrentTeamInfo() {
...@@ -166,20 +167,20 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -166,20 +167,20 @@ public class TeamManager extends BasePlayerDataManager {
} }
public EntityAvatar getCurrentAvatarEntity() { public EntityAvatar getCurrentAvatarEntity() {
return getActiveTeam().get(currentCharacterIndex); return this.getActiveTeam().get(currentCharacterIndex);
} }
public boolean isSpawned() { 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() { public int getMaxTeamSize() {
if (getPlayer().isInMultiplayer()) { if (this.getPlayer().isInMultiplayer()) {
int max = GAME_OPTIONS.avatarLimits.multiplayerTeam; int max = GAME_OPTIONS.avatarLimits.multiplayerTeam;
if (getPlayer().getWorld().getHost() == this.getPlayer()) { if (this.getPlayer().getWorld().getHost() == this.getPlayer()) {
return Math.max(1, (int) Math.ceil(max / (double) getWorld().getPlayerCount())); 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; return GAME_OPTIONS.avatarLimits.singlePlayerTeam;
...@@ -191,14 +192,14 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -191,14 +192,14 @@ public class TeamManager extends BasePlayerDataManager {
* Returns true if there is space to add the number of avatars to the team. * Returns true if there is space to add the number of avatars to the team.
*/ */
public boolean canAddAvatarsToTeam(TeamInfo team, int avatars) { 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. * Returns true if there is space to add to the team.
*/ */
public boolean canAddAvatarToTeam(TeamInfo team) { public boolean canAddAvatarToTeam(TeamInfo team) {
return canAddAvatarsToTeam(team, 1); return this.canAddAvatarsToTeam(team, 1);
} }
/** /**
...@@ -209,7 +210,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -209,7 +210,7 @@ public class TeamManager extends BasePlayerDataManager {
if (this.useTemporarilyTeamIndex != -1) { if (this.useTemporarilyTeamIndex != -1) {
return false; return false;
} }
return canAddAvatarsToTeam(this.getCurrentTeamInfo(), avatars); return this.canAddAvatarsToTeam(this.getCurrentTeamInfo(), avatars);
} }
/** /**
...@@ -217,7 +218,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -217,7 +218,7 @@ public class TeamManager extends BasePlayerDataManager {
* If the current team is temporary, returns false. * If the current team is temporary, returns false.
*/ */
public boolean canAddAvatarToCurrentTeam() { public boolean canAddAvatarToCurrentTeam() {
return canAddAvatarsToCurrentTeam(1); return this.canAddAvatarsToCurrentTeam(1);
} }
/** /**
...@@ -226,7 +227,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -226,7 +227,7 @@ public class TeamManager extends BasePlayerDataManager {
* If some can not be added, returns false and does not add any. * If some can not be added, returns false and does not add any.
*/ */
public boolean addAvatarsToTeam(TeamInfo team, Collection<Avatar> avatars) { public boolean addAvatarsToTeam(TeamInfo team, Collection<Avatar> avatars) {
if (!canAddAvatarsToTeam(team, avatars.size())) { if (!this.canAddAvatarsToTeam(team, avatars.size())) {
return false; return false;
} }
...@@ -237,20 +238,20 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -237,20 +238,20 @@ public class TeamManager extends BasePlayerDataManager {
if (this.getPlayer().isInMultiplayer()) { if (this.getPlayer().isInMultiplayer()) {
if (team.equals(this.getMpTeam())) { if (team.equals(this.getMpTeam())) {
// MP team Packet // MP team Packet
this.updateTeamEntities(new PacketChangeMpTeamAvatarRsp(getPlayer(), team)); this.updateTeamEntities(new PacketChangeMpTeamAvatarRsp(this.getPlayer(), team));
} }
} else { } else {
// SP team update packet // SP team update packet
getPlayer().sendPacket(new PacketAvatarTeamUpdateNotify(getPlayer())); this.getPlayer().sendPacket(new PacketAvatarTeamUpdateNotify(this.getPlayer()));
int teamId = this.getTeamId(team); int teamId = this.getTeamId(team);
if (teamId != -1) { if (teamId != -1) {
// This is one of the player's teams // This is one of the player's teams
// Update entites // Update entites
if (teamId == this.getCurrentTeamId()) { if (teamId == this.getCurrentTeamId()) {
this.updateTeamEntities(new PacketSetUpAvatarTeamRsp(getPlayer(), teamId, team)); this.updateTeamEntities(new PacketSetUpAvatarTeamRsp(this.getPlayer(), teamId, team));
} else { } 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 { ...@@ -263,7 +264,7 @@ public class TeamManager extends BasePlayerDataManager {
* Returns true if successful. * Returns true if successful.
*/ */
public boolean addAvatarToTeam(TeamInfo team, Avatar avatar) { 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 { ...@@ -276,7 +277,7 @@ public class TeamManager extends BasePlayerDataManager {
if (this.useTemporarilyTeamIndex != -1) { if (this.useTemporarilyTeamIndex != -1) {
return false; return false;
} }
return addAvatarsToTeam(this.getCurrentTeamInfo(), avatars); return this.addAvatarsToTeam(this.getCurrentTeamInfo(), avatars);
} }
/** /**
...@@ -285,7 +286,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -285,7 +286,7 @@ public class TeamManager extends BasePlayerDataManager {
* Returns true if successful. * Returns true if successful.
*/ */
public boolean addAvatarToCurrentTeam(Avatar avatar) { public boolean addAvatarToCurrentTeam(Avatar avatar) {
return addAvatarsToCurrentTeam(Collections.singleton(avatar)); return this.addAvatarsToCurrentTeam(Collections.singleton(avatar));
} }
private void updateTeamResonances() { private void updateTeamResonances() {
...@@ -294,7 +295,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -294,7 +295,7 @@ public class TeamManager extends BasePlayerDataManager {
this.getTeamResonances().clear(); this.getTeamResonances().clear();
this.getTeamResonancesConfig().clear(); this.getTeamResonancesConfig().clear();
for (EntityAvatar entity : getActiveTeam()) { for (EntityAvatar entity : this.getActiveTeam()) {
AvatarSkillDepotData skillData = entity.getAvatar().getAvatarData().getSkillDepot(); AvatarSkillDepotData skillData = entity.getAvatar().getAvatarData().getSkillDepot();
if (skillData != null) { if (skillData != null) {
map.addTo(skillData.getElementType().getValue(), 1); map.addTo(skillData.getElementType().getValue(), 1);
...@@ -329,7 +330,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -329,7 +330,7 @@ public class TeamManager extends BasePlayerDataManager {
Int2ObjectMap<EntityAvatar> existingAvatars = new Int2ObjectOpenHashMap<>(); Int2ObjectMap<EntityAvatar> existingAvatars = new Int2ObjectOpenHashMap<>();
int prevSelectedAvatarIndex = -1; int prevSelectedAvatarIndex = -1;
for (EntityAvatar entity : getActiveTeam()) { for (EntityAvatar entity : this.getActiveTeam()) {
existingAvatars.put(entity.getAvatar().getAvatarId(), entity); existingAvatars.put(entity.getAvatar().getAvatarId(), entity);
} }
...@@ -348,7 +349,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -348,7 +349,7 @@ public class TeamManager extends BasePlayerDataManager {
prevSelectedAvatarIndex = i; prevSelectedAvatarIndex = i;
} }
} else { } 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); this.getActiveTeam().add(entity);
...@@ -356,7 +357,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -356,7 +357,7 @@ public class TeamManager extends BasePlayerDataManager {
// Unload removed entities // Unload removed entities
for (EntityAvatar entity : existingAvatars.values()) { for (EntityAvatar entity : existingAvatars.values()) {
getPlayer().getScene().removeEntity(entity); this.getPlayer().getScene().removeEntity(entity);
entity.getAvatar().save(); entity.getAvatar().save();
} }
...@@ -368,33 +369,33 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -368,33 +369,33 @@ public class TeamManager extends BasePlayerDataManager {
this.currentCharacterIndex = prevSelectedAvatarIndex; this.currentCharacterIndex = prevSelectedAvatarIndex;
// Update team resonances // Update team resonances
updateTeamResonances(); this.updateTeamResonances();
// Packets // 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 // 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) { if (entity.getAvatar().getSkillExtraChargeMap().size() > 0) {
getPlayer().sendPacket(new PacketAvatarSkillInfoNotify(entity.getAvatar())); this.getPlayer().sendPacket(new PacketAvatarSkillInfoNotify(entity.getAvatar()));
} }
} }
// Run callback // Run callback
if (responsePacket != null) { if (responsePacket != null) {
getPlayer().sendPacket(responsePacket); this.getPlayer().sendPacket(responsePacket);
} }
// Check if character changed // Check if character changed
if (currentEntity != getCurrentAvatarEntity()) { if (currentEntity != this.getCurrentAvatarEntity()) {
// Remove and Add // Remove and Add
getPlayer().getScene().replaceEntity(currentEntity, getCurrentAvatarEntity()); this.getPlayer().getScene().replaceEntity(currentEntity, this.getCurrentAvatarEntity());
} }
} }
public synchronized void setupAvatarTeam(int teamId, List<Long> list) { public synchronized void setupAvatarTeam(int teamId, List<Long> list) {
// Sanity checks // Sanity checks
if (list.size() == 0 || list.size() > getMaxTeamSize() || getPlayer().isInMultiplayer()) { if (list.size() == 0 || list.size() > this.getMaxTeamSize() || this.getPlayer().isInMultiplayer()) {
return; return;
} }
...@@ -407,7 +408,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -407,7 +408,7 @@ public class TeamManager extends BasePlayerDataManager {
// Set team data // Set team data
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>(); LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
for (Long aLong : list) { for (Long aLong : list) {
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); Avatar avatar = this.getPlayer().getAvatars().getAvatarByGuid(aLong);
if (avatar == null || newTeam.contains(avatar)) { if (avatar == null || newTeam.contains(avatar)) {
// Should never happen // Should never happen
return; return;
...@@ -422,7 +423,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -422,7 +423,7 @@ public class TeamManager extends BasePlayerDataManager {
public void setupMpTeam(List<Long> list) { public void setupMpTeam(List<Long> list) {
// Sanity checks // Sanity checks
if (list.size() == 0 || list.size() > getMaxTeamSize() || !getPlayer().isInMultiplayer()) { if (list.size() == 0 || list.size() > this.getMaxTeamSize() || !this.getPlayer().isInMultiplayer()) {
return; return;
} }
...@@ -431,7 +432,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -431,7 +432,7 @@ public class TeamManager extends BasePlayerDataManager {
// Set team data // Set team data
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>(); LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
for (Long aLong : list) { for (Long aLong : list) {
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); Avatar avatar = this.getPlayer().getAvatars().getAvatarByGuid(aLong);
if (avatar == null || newTeam.contains(avatar)) { if (avatar == null || newTeam.contains(avatar)) {
// Should never happen // Should never happen
return; return;
...@@ -447,14 +448,14 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -447,14 +448,14 @@ public class TeamManager extends BasePlayerDataManager {
public void setupTemporaryTeam(List<List<Long>> guidList) { public void setupTemporaryTeam(List<List<Long>> guidList) {
this.temporaryTeam = guidList.stream().map(list -> { this.temporaryTeam = guidList.stream().map(list -> {
// Sanity checks // Sanity checks
if (list.size() == 0 || list.size() > getMaxTeamSize()) { if (list.size() == 0 || list.size() > this.getMaxTeamSize()) {
return null; return null;
} }
// Set team data // Set team data
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>(); LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
for (Long aLong : list) { for (Long aLong : list) {
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); Avatar avatar = this.getPlayer().getAvatars().getAvatarByGuid(aLong);
if (avatar == null || newTeam.contains(avatar)) { if (avatar == null || newTeam.contains(avatar)) {
// Should never happen // Should never happen
return null; return null;
...@@ -474,7 +475,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -474,7 +475,7 @@ public class TeamManager extends BasePlayerDataManager {
public void useTemporaryTeam(int index) { public void useTemporaryTeam(int index) {
this.useTemporarilyTeamIndex = index; this.useTemporarilyTeamIndex = index;
updateTeamEntities(null); this.updateTeamEntities(null);
} }
public void cleanTemporaryTeam() { public void cleanTemporaryTeam() {
...@@ -485,11 +486,11 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -485,11 +486,11 @@ public class TeamManager extends BasePlayerDataManager {
this.useTemporarilyTeamIndex = -1; this.useTemporarilyTeamIndex = -1;
this.temporaryTeam = null; this.temporaryTeam = null;
updateTeamEntities(null); this.updateTeamEntities(null);
} }
public synchronized void setCurrentTeam(int teamId) { public synchronized void setCurrentTeam(int teamId) {
// //
if (getPlayer().isInMultiplayer()) { if (this.getPlayer().isInMultiplayer()) {
return; return;
} }
...@@ -514,7 +515,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -514,7 +515,7 @@ public class TeamManager extends BasePlayerDataManager {
teamInfo.setName(teamName); teamInfo.setName(teamName);
// Packet // Packet
getPlayer().sendPacket(new PacketChangeTeamNameRsp(teamId, teamName)); this.getPlayer().sendPacket(new PacketChangeTeamNameRsp(teamId, teamName));
} }
public synchronized void changeAvatar(long guid) { public synchronized void changeAvatar(long guid) {
...@@ -526,10 +527,10 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -526,10 +527,10 @@ public class TeamManager extends BasePlayerDataManager {
EntityAvatar newEntity = null; EntityAvatar newEntity = null;
int index = -1; int index = -1;
for (int i = 0; i < getActiveTeam().size(); i++) { for (int i = 0; i < this.getActiveTeam().size(); i++) {
if (guid == getActiveTeam().get(i).getAvatar().getGuid()) { if (guid == this.getActiveTeam().get(i).getAvatar().getGuid()) {
index = i; index = i;
newEntity = getActiveTeam().get(i); newEntity = this.getActiveTeam().get(i);
} }
} }
...@@ -544,8 +545,8 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -544,8 +545,8 @@ public class TeamManager extends BasePlayerDataManager {
oldEntity.setMotionState(MotionState.MOTION_STATE_STANDBY); oldEntity.setMotionState(MotionState.MOTION_STATE_STANDBY);
// Remove and Add // Remove and Add
getPlayer().getScene().replaceEntity(oldEntity, newEntity); this.getPlayer().getScene().replaceEntity(oldEntity, newEntity);
getPlayer().sendPacket(new PacketChangeAvatarRsp(guid)); this.getPlayer().sendPacket(new PacketChangeAvatarRsp(guid));
} }
public void onAvatarDie(long dieGuid) { public void onAvatarDie(long dieGuid) {
...@@ -562,7 +563,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -562,7 +563,7 @@ public class TeamManager extends BasePlayerDataManager {
// Died in water. Do not replace // Died in water. Do not replace
// The official server has skipped this notify and will just respawn the team immediately after the animation. // 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? // TODO: Perhaps find a way to get vanilla experience?
getPlayer().sendPacket(new PacketWorldPlayerDieNotify(dieType, killedBy)); this.getPlayer().sendPacket(new PacketWorldPlayerDieNotify(dieType, killedBy));
} else { } else {
// Replacement avatar // Replacement avatar
EntityAvatar replacement = null; EntityAvatar replacement = null;
...@@ -579,20 +580,24 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -579,20 +580,24 @@ public class TeamManager extends BasePlayerDataManager {
if (replacement == null) { if (replacement == null) {
// No more living team members... // 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 { } else {
// Set index and spawn replacement member // Set index and spawn replacement member
this.setCurrentCharacterIndex(replaceIndex); this.setCurrentCharacterIndex(replaceIndex);
getPlayer().getScene().addEntity(replacement); this.getPlayer().getScene().addEntity(replacement);
} }
} }
// Response packet // Response packet
getPlayer().sendPacket(new PacketAvatarDieAnimationEndRsp(deadAvatar.getId(), 0)); this.getPlayer().sendPacket(new PacketAvatarDieAnimationEndRsp(deadAvatar.getId(), 0));
} }
public boolean reviveAvatar(Avatar avatar) { public boolean reviveAvatar(Avatar avatar) {
for (EntityAvatar entity : getActiveTeam()) { for (EntityAvatar entity : this.getActiveTeam()) {
if (entity.getAvatar() == avatar) { if (entity.getAvatar() == avatar) {
if (entity.isAlive()) { if (entity.isAlive()) {
return false; return false;
...@@ -602,8 +607,8 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -602,8 +607,8 @@ public class TeamManager extends BasePlayerDataManager {
FightProperty.FIGHT_PROP_CUR_HP, FightProperty.FIGHT_PROP_CUR_HP,
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .1f entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .1f
); );
getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); this.getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP));
getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); this.getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
return true; return true;
} }
} }
...@@ -612,7 +617,7 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -612,7 +617,7 @@ public class TeamManager extends BasePlayerDataManager {
} }
public boolean healAvatar(Avatar avatar, int healRate, int healAmount) { public boolean healAvatar(Avatar avatar, int healRate, int healAmount) {
for (EntityAvatar entity : getActiveTeam()) { for (EntityAvatar entity : this.getActiveTeam()) {
if (entity.getAvatar() == avatar) { if (entity.getAvatar() == avatar) {
if (!entity.isAlive()) { if (!entity.isAlive()) {
return false; return false;
...@@ -627,8 +632,8 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -627,8 +632,8 @@ public class TeamManager extends BasePlayerDataManager {
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP)
) )
); );
getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); this.getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP));
getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); this.getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
return true; return true;
} }
} }
...@@ -646,29 +651,29 @@ public class TeamManager extends BasePlayerDataManager { ...@@ -646,29 +651,29 @@ public class TeamManager extends BasePlayerDataManager {
player.getStaminaManager().stopSustainedStaminaHandler(); // prevent drowning immediately after respawn player.getStaminaManager().stopSustainedStaminaHandler(); // prevent drowning immediately after respawn
// Revive all team members // Revive all team members
for (EntityAvatar entity : getActiveTeam()) { for (EntityAvatar entity : this.getActiveTeam()) {
entity.setFightProperty( entity.setFightProperty(
FightProperty.FIGHT_PROP_CUR_HP, FightProperty.FIGHT_PROP_CUR_HP,
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .4f entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .4f
); );
getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); this.getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP));
getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); this.getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
} }
// Teleport player // 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 // Set player position
player.setSceneId(3); player.setSceneId(3);
player.getPosition().set(GameConstants.START_POSITION); player.getPosition().set(GameConstants.START_POSITION);
// Packets // Packets
getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp)); this.getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp));
} }
public void saveAvatars() { public void saveAvatars() {
// Save all avatars from active team // Save all avatars from active team
for (EntityAvatar entity : getActiveTeam()) { for (EntityAvatar entity : this.getActiveTeam()) {
entity.getAvatar().save(); entity.getAvatar().save();
} }
} }
......
...@@ -30,6 +30,7 @@ import emu.grasscutter.game.shop.ShopChestBatchUseTable; ...@@ -30,6 +30,7 @@ import emu.grasscutter.game.shop.ShopChestBatchUseTable;
import emu.grasscutter.game.shop.ShopChestTable; import emu.grasscutter.game.shop.ShopChestTable;
import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam; import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam;
import emu.grasscutter.net.proto.MaterialInfoOuterClass.MaterialInfo; 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.BaseGameSystem;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.*;
...@@ -812,37 +813,48 @@ public class InventorySystem extends BaseGameSystem { ...@@ -812,37 +813,48 @@ public class InventorySystem extends BaseGameSystem {
int used = 0; int used = 0;
boolean useSuccess = false; boolean useSuccess = false;
ItemData itemData = useItem.getItemData();
// Use // Use
switch (useItem.getItemData().getMaterialType()) { switch (itemData.getMaterialType()) {
case MATERIAL_FOOD: 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) { if (target == null) {
break; break;
} }
// 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; used = player.getTeamManager().reviveAvatar(target) ? 1 : 0;
}
} else { } else {
used = 1; used = 1;
} }
break; break;
case MATERIAL_NOTICE_ADD_HP: 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) { if (target == null) {
break; break;
} }
int[] SatiationParams = useItem.getItemData().getSatiationParams(); // 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; used = player.getTeamManager().healAvatar(target, SatiationParams[0], SatiationParams[1]) ? 1 : 0;
} }
}
break; break;
case MATERIAL_CONSUME: case MATERIAL_CONSUME:
// Make sure we have usage data for this material. // Make sure we have usage data for this material.
if (useItem.getItemData().getItemUse() == null) { if (itemData.getItemUse() == null) {
break; break;
} }
ItemUseOp useOp = useItem.getItemData().getItemUse().get(0).getUseOp(); ItemUseOp useOp = itemData.getItemUse().get(0).getUseOp();
// Unlock item based on use operation // Unlock item based on use operation
useSuccess = switch (useOp) { useSuccess = switch (useOp) {
...@@ -854,7 +866,7 @@ public class InventorySystem extends BaseGameSystem { ...@@ -854,7 +866,7 @@ public class InventorySystem extends BaseGameSystem {
break; break;
case MATERIAL_FURNITURE_FORMULA: case MATERIAL_FURNITURE_FORMULA:
case MATERIAL_FURNITURE_SUITE_FORMULA: case MATERIAL_FURNITURE_SUITE_FORMULA:
if (useItem.getItemData().getItemUse() == null) { if (itemData.getItemUse() == null) {
break; break;
} }
useSuccess = player.getFurnitureManager().unlockFurnitureOrSuite(useItem); useSuccess = player.getFurnitureManager().unlockFurnitureOrSuite(useItem);
...@@ -862,7 +874,7 @@ public class InventorySystem extends BaseGameSystem { ...@@ -862,7 +874,7 @@ public class InventorySystem extends BaseGameSystem {
break; break;
case MATERIAL_CONSUME_BATCH_USE: case MATERIAL_CONSUME_BATCH_USE:
// Make sure we have usage data for this material. // Make sure we have usage data for this material.
if (useItem.getItemData().getItemUse() == null) { if (itemData.getItemUse() == null) {
break; break;
} }
...@@ -889,11 +901,11 @@ public class InventorySystem extends BaseGameSystem { ...@@ -889,11 +901,11 @@ public class InventorySystem extends BaseGameSystem {
} }
for (ItemParamData itemParamData : shopChestTable.getContainsItem()) { for (ItemParamData itemParamData : shopChestTable.getContainsItem()) {
ItemData itemData = GameData.getItemDataMap().get(itemParamData.getId()); ItemData containedItem = GameData.getItemDataMap().get(itemParamData.getId());
if (itemData == null) { if (containedItem == null) {
continue; continue;
} }
rewardItemList.add(new GameItem(itemData, itemParamData.getCount())); rewardItemList.add(new GameItem(containedItem, itemParamData.getCount()));
} }
if (!rewardItemList.isEmpty()) { if (!rewardItemList.isEmpty()) {
...@@ -919,12 +931,12 @@ public class InventorySystem extends BaseGameSystem { ...@@ -919,12 +931,12 @@ public class InventorySystem extends BaseGameSystem {
} }
int optionItemId = shopChestBatchUseTable.getOptionItem().get(optionId - 1); int optionItemId = shopChestBatchUseTable.getOptionItem().get(optionId - 1);
ItemData itemData = GameData.getItemDataMap().get(optionItemId); ItemData optionItem = GameData.getItemDataMap().get(optionItemId);
if (itemData == null) { if (optionItem == null) {
break; break;
} }
player.getInventory().addItem(new GameItem(itemData, count), ActionReason.Shop); player.getInventory().addItem(new GameItem(optionItem, count), ActionReason.Shop);
used = count; used = count;
break; break;
...@@ -944,7 +956,7 @@ public class InventorySystem extends BaseGameSystem { ...@@ -944,7 +956,7 @@ public class InventorySystem extends BaseGameSystem {
// we return the item to make UseItemRsp a success. // we return the item to make UseItemRsp a success.
if (used > 0) { if (used > 0) {
// Handle use params, mainly server buffs // Handle use params, mainly server buffs
for (ItemUseData useData : useItem.getItemData().getItemUse()) { for (ItemUseData useData : itemData.getItemUse()) {
switch (useData.getUseOp()) { switch (useData.getUseOp()) {
case ITEM_USE_ADD_SERVER_BUFF -> { case ITEM_USE_ADD_SERVER_BUFF -> {
int buffId = Integer.parseInt(useData.getUseParam()[0]); int buffId = Integer.parseInt(useData.getUseParam()[0]);
......
...@@ -17,6 +17,8 @@ import emu.grasscutter.data.excels.SceneData; ...@@ -17,6 +17,8 @@ import emu.grasscutter.data.excels.SceneData;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType; import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
import emu.grasscutter.scripts.data.SceneConfig; 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.game.GameServer;
import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify; import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify;
import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify; import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
...@@ -53,7 +55,7 @@ public class World implements Iterable<Player> { ...@@ -53,7 +55,7 @@ public class World implements Iterable<Player> {
this.players = Collections.synchronizedList(new ArrayList<>()); this.players = Collections.synchronizedList(new ArrayList<>());
this.scenes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>()); this.scenes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
this.levelEntityId = getNextEntityId(EntityIdType.MPLEVEL); this.levelEntityId = this.getNextEntityId(EntityIdType.MPLEVEL);
this.worldLevel = player.getWorldLevel(); this.worldLevel = player.getWorldLevel();
this.isMultiplayer = isMultiplayer; this.isMultiplayer = isMultiplayer;
...@@ -101,7 +103,7 @@ public class World implements Iterable<Player> { ...@@ -101,7 +103,7 @@ public class World implements Iterable<Player> {
public Scene getSceneById(int sceneId) { public Scene getSceneById(int sceneId) {
// Get scene normally // Get scene normally
Scene scene = getScenes().get(sceneId); Scene scene = this.getScenes().get(sceneId);
if (scene != null) { if (scene != null) {
return scene; return scene;
} }
...@@ -118,7 +120,7 @@ public class World implements Iterable<Player> { ...@@ -118,7 +120,7 @@ public class World implements Iterable<Player> {
} }
public int getPlayerCount() { public int getPlayerCount() {
return getPlayers().size(); return this.getPlayers().size();
} }
public boolean isMultiplayer() { public boolean isMultiplayer() {
...@@ -131,7 +133,7 @@ public class World implements Iterable<Player> { ...@@ -131,7 +133,7 @@ public class World implements Iterable<Player> {
public synchronized void addPlayer(Player player) { public synchronized void addPlayer(Player player) {
// Check if player already in // Check if player already in
if (getPlayers().contains(player)) { if (this.getPlayers().contains(player)) {
return; return;
} }
...@@ -142,11 +144,11 @@ public class World implements Iterable<Player> { ...@@ -142,11 +144,11 @@ public class World implements Iterable<Player> {
// Register // Register
player.setWorld(this); player.setWorld(this);
getPlayers().add(player); this.getPlayers().add(player);
// Set player variables // Set player variables
player.setPeerId(this.getNextPeerId()); player.setPeerId(this.getNextPeerId());
player.getTeamManager().setEntityId(getNextEntityId(EntityIdType.TEAM)); player.getTeamManager().setEntityId(this.getNextEntityId(EntityIdType.TEAM));
// Copy main team to multiplayer team // Copy main team to multiplayer team
if (this.isMultiplayer()) { if (this.isMultiplayer()) {
...@@ -169,12 +171,12 @@ public class World implements Iterable<Player> { ...@@ -169,12 +171,12 @@ public class World implements Iterable<Player> {
player.sendPacket( player.sendPacket(
new PacketDelTeamEntityNotify( new PacketDelTeamEntityNotify(
player.getSceneId(), player.getSceneId(),
getPlayers().stream().map(p -> p.getTeamManager().getEntityId()).collect(Collectors.toList()) this.getPlayers().stream().map(p -> p.getTeamManager().getEntityId()).collect(Collectors.toList())
) )
); );
// Deregister // Deregister
getPlayers().remove(player); this.getPlayers().remove(player);
player.setWorld(null); player.setWorld(null);
// Remove from scene // Remove from scene
...@@ -187,7 +189,7 @@ public class World implements Iterable<Player> { ...@@ -187,7 +189,7 @@ public class World implements Iterable<Player> {
} }
// Disband world if host leaves // Disband world if host leaves
if (getHost() == player) { if (this.getHost() == player) {
List<Player> kicked = new ArrayList<>(this.getPlayers()); List<Player> kicked = new ArrayList<>(this.getPlayers());
for (Player victim : kicked) { for (Player victim : kicked) {
World world = new World(victim); World world = new World(victim);
...@@ -207,14 +209,28 @@ public class World implements Iterable<Player> { ...@@ -207,14 +209,28 @@ public class World implements Iterable<Player> {
} }
public boolean transferPlayerToScene(Player player, int sceneId, Position pos) { 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) { 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, 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.
} }
public boolean transferPlayerToScene(Player player, int sceneId, DungeonData dungeonData, Position pos) { // Set the destination.
teleportTo = event.getDestination();
if (GameData.getSceneDataMap().get(sceneId) == null) { if (GameData.getSceneDataMap().get(sceneId) == null) {
return false; return false;
} }
...@@ -224,7 +240,7 @@ public class World implements Iterable<Player> { ...@@ -224,7 +240,7 @@ public class World implements Iterable<Player> {
if (player.getScene() != null) { if (player.getScene() != null) {
oldScene = player.getScene(); 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) { if (oldScene.getId() == sceneId) {
oldScene.setDontDestroyWhenEmpty(true); oldScene.setDontDestroyWhenEmpty(true);
} }
...@@ -238,9 +254,9 @@ public class World implements Iterable<Player> { ...@@ -238,9 +254,9 @@ public class World implements Iterable<Player> {
// Dungeon // Dungeon
SceneConfig config = newScene.getScriptManager().getConfig(); SceneConfig config = newScene.getScriptManager().getConfig();
if (pos == null && config != null) { if (teleportTo == null && config != null) {
if (config.born_pos != null) { if (config.born_pos != null) {
pos = newScene.getScriptManager().getConfig().born_pos; teleportTo = newScene.getScriptManager().getConfig().born_pos;
} }
if (config.born_rot != null) { if (config.born_rot != null) {
player.getRotation().set(config.born_rot); player.getRotation().set(config.born_rot);
...@@ -248,11 +264,11 @@ public class World implements Iterable<Player> { ...@@ -248,11 +264,11 @@ public class World implements Iterable<Player> {
} }
// Set player position // Set player position
if (pos == null) { if (teleportTo == null) {
pos = player.getPosition(); teleportTo = player.getPosition();
} }
player.getPosition().set(pos); player.getPosition().set(teleportTo);
if (oldScene != null) { if (oldScene != null) {
newScene.setPrevScene(oldScene.getId()); newScene.setPrevScene(oldScene.getId());
...@@ -276,12 +292,12 @@ public class World implements Iterable<Player> { ...@@ -276,12 +292,12 @@ public class World implements Iterable<Player> {
} }
// Teleport packet // Teleport packet
player.sendPacket(new PacketPlayerEnterSceneNotify(player, enterType, enterReason, sceneId, pos)); player.sendPacket(new PacketPlayerEnterSceneNotify(player, enterType, enterReason, sceneId, teleportTo));
return true; return true;
} }
private void updatePlayerInfos(Player paramPlayer) { 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 // Dont send packets if player is logging in and filter out joining player
if (!player.hasSentLoginPackets() || player == paramPlayer) { if (!player.hasSentLoginPackets() || player == paramPlayer) {
continue; continue;
...@@ -326,6 +342,6 @@ public class World implements Iterable<Player> { ...@@ -326,6 +342,6 @@ public class World implements Iterable<Player> {
@Override @Override
public Iterator<Player> iterator() { public Iterator<Player> iterator() {
return getPlayers().iterator(); return this.getPlayers().iterator();
} }
} }
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
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;
}
}
package emu.grasscutter.server.event.player;
import emu.grasscutter.game.player.Player;
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 {
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
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
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 {
/**
* There is no specified reason to teleport.
*/
INTERNAL,
/**
* 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 into a dungeon.
*/
DUNGEON,
/**
* The player has asked to teleport using the command.
*/
COMMAND
}
}
\ No newline at end of file
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
...@@ -60,8 +60,7 @@ public class HandlerCombatInvocationsNotify extends PacketHandler { ...@@ -60,8 +60,7 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
new Position(motionInfo.getRot()), motionState); new Position(motionInfo.getRot()), motionState);
event.call(); event.call();
entity.getPosition().set(motionInfo.getPos()); entity.move(event.getPosition(), event.getRotation());
entity.getRotation().set(motionInfo.getRot());
entity.setLastMoveSceneTimeMs(moveInfo.getSceneTime()); entity.setLastMoveSceneTimeMs(moveInfo.getSceneTime());
entity.setLastMoveReliableSeq(moveInfo.getReliableSeq()); entity.setLastMoveReliableSeq(moveInfo.getReliableSeq());
entity.setMotionState(motionState); entity.setMotionState(motionState);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment