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 {
......
...@@ -8,11 +8,11 @@ public abstract class EntityBaseGadget extends GameEntity { ...@@ -8,11 +8,11 @@ public abstract class EntityBaseGadget extends GameEntity {
public EntityBaseGadget(Scene scene) { public EntityBaseGadget(Scene scene) {
super(scene); super(scene);
} }
public abstract int getGadgetId(); public abstract int getGadgetId();
@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;
...@@ -25,10 +23,10 @@ import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; ...@@ -25,10 +23,10 @@ import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
public class EntityClientGadget extends EntityBaseGadget { public class EntityClientGadget extends EntityBaseGadget {
private final Player owner; private final Player owner;
private final Position pos; private final Position pos;
private final Position rot; private final Position rot;
private int configId; private int configId;
private int campId; private int campId;
private int campType; private int campType;
...@@ -37,7 +35,7 @@ public class EntityClientGadget extends EntityBaseGadget { ...@@ -37,7 +35,7 @@ public class EntityClientGadget extends EntityBaseGadget {
private boolean asyncLoad; private boolean asyncLoad;
private int originalOwnerEntityId; private int originalOwnerEntityId;
public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) { public EntityClientGadget(Scene scene, Player player, EvtCreateGadgetNotify notify) {
super(scene); super(scene);
this.owner = player; this.owner = player;
...@@ -59,20 +57,20 @@ public class EntityClientGadget extends EntityBaseGadget { ...@@ -59,20 +57,20 @@ public class EntityClientGadget extends EntityBaseGadget {
this.originalOwnerEntityId = this.ownerEntityId; this.originalOwnerEntityId = this.ownerEntityId;
} }
} }
@Override @Override
public int getGadgetId() { public int getGadgetId() {
return configId; return configId;
} }
public Player getOwner() { public Player getOwner() {
return owner; return owner;
} }
public int getCampId() { public int getCampId() {
return campId; return campId;
} }
public int getCampType() { public int getCampType() {
return campType; return campType;
} }
...@@ -80,7 +78,7 @@ public class EntityClientGadget extends EntityBaseGadget { ...@@ -80,7 +78,7 @@ public class EntityClientGadget extends EntityBaseGadget {
public int getOwnerEntityId() { public int getOwnerEntityId() {
return ownerEntityId; return ownerEntityId;
} }
public int getTargetEntityId() { public int getTargetEntityId() {
return targetEntityId; return targetEntityId;
} }
...@@ -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
...@@ -124,7 +122,7 @@ public class EntityClientGadget extends EntityBaseGadget { ...@@ -124,7 +122,7 @@ public class EntityClientGadget extends EntityBaseGadget {
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
.setBornPos(Vector.newBuilder()) .setBornPos(Vector.newBuilder())
.build(); .build();
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
.setEntityId(getId()) .setEntityId(getId())
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
...@@ -133,13 +131,13 @@ public class EntityClientGadget extends EntityBaseGadget { ...@@ -133,13 +131,13 @@ public class EntityClientGadget extends EntityBaseGadget {
.setEntityClientData(EntityClientData.newBuilder()) .setEntityClientData(EntityClientData.newBuilder())
.setEntityAuthorityInfo(authority) .setEntityAuthorityInfo(authority)
.setLifeState(1); .setLifeState(1);
PropPair pair = PropPair.newBuilder() PropPair pair = PropPair.newBuilder()
.setType(PlayerProperty.PROP_LEVEL.getId()) .setType(PlayerProperty.PROP_LEVEL.getId())
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1)) .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
.build(); .build();
entityInfo.addPropList(pair); entityInfo.addPropList(pair);
ClientGadgetInfoOuterClass.ClientGadgetInfo clientGadget = ClientGadgetInfoOuterClass.ClientGadgetInfo.newBuilder() ClientGadgetInfoOuterClass.ClientGadgetInfo clientGadget = ClientGadgetInfoOuterClass.ClientGadgetInfo.newBuilder()
.setCampId(this.getCampId()) .setCampId(this.getCampId())
.setCampType(this.getCampType()) .setCampType(this.getCampType())
...@@ -147,7 +145,7 @@ public class EntityClientGadget extends EntityBaseGadget { ...@@ -147,7 +145,7 @@ public class EntityClientGadget extends EntityBaseGadget {
.setTargetEntityId(this.getTargetEntityId()) .setTargetEntityId(this.getTargetEntityId())
.setAsyncLoad(this.isAsyncLoad()) .setAsyncLoad(this.isAsyncLoad())
.build(); .build();
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder() SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
.setGadgetId(this.getGadgetId()) .setGadgetId(this.getGadgetId())
.setOwnerEntityId(this.getOwnerEntityId()) .setOwnerEntityId(this.getOwnerEntityId())
...@@ -157,7 +155,7 @@ public class EntityClientGadget extends EntityBaseGadget { ...@@ -157,7 +155,7 @@ public class EntityClientGadget extends EntityBaseGadget {
.setAuthorityPeerId(this.getOwner().getPeerId()); .setAuthorityPeerId(this.getOwner().getPeerId());
entityInfo.setGadget(gadgetInfo); entityInfo.setGadget(gadgetInfo);
return entityInfo.build(); return entityInfo.build();
} }
} }
...@@ -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;
...@@ -23,64 +24,64 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; ...@@ -23,64 +24,64 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public abstract class GameEntity { public abstract class GameEntity {
protected int id; protected int id;
private final Scene scene; private final Scene scene;
private SpawnDataEntry spawnEntry; private SpawnDataEntry spawnEntry;
private int blockId; private int blockId;
private int configId; private int configId;
private int groupId; private int groupId;
private MotionState moveState; private MotionState moveState;
private int lastMoveSceneTimeMs; private int lastMoveSceneTimeMs;
private int lastMoveReliableSeq; private int lastMoveReliableSeq;
// Abilities // Abilities
private Map<String, Float> metaOverrideMap; private Map<String, Float> metaOverrideMap;
private Int2ObjectMap<String> metaModifiers; private Int2ObjectMap<String> metaModifiers;
public GameEntity(Scene scene) { public GameEntity(Scene scene) {
this.scene = scene; this.scene = scene;
this.moveState = MotionState.MOTION_STATE_NONE; this.moveState = MotionState.MOTION_STATE_NONE;
} }
public int getId() { public int getId() {
return this.id; return this.id;
} }
public int getEntityType() { public int getEntityType() {
return getId() >> 24; return getId() >> 24;
} }
public World getWorld() { public World getWorld() {
return this.getScene().getWorld(); return this.getScene().getWorld();
} }
public Scene getScene() { public Scene getScene() {
return this.scene; return this.scene;
} }
public boolean isAlive() { public boolean isAlive() {
return true; return true;
} }
public LifeState getLifeState() { public LifeState getLifeState() {
return isAlive() ? LifeState.LIFE_ALIVE : LifeState.LIFE_DEAD; return isAlive() ? LifeState.LIFE_ALIVE : LifeState.LIFE_DEAD;
} }
public Map<String, Float> getMetaOverrideMap() { public Map<String, Float> getMetaOverrideMap() {
if (this.metaOverrideMap == null) { if (this.metaOverrideMap == null) {
this.metaOverrideMap = new HashMap<>(); this.metaOverrideMap = new HashMap<>();
} }
return this.metaOverrideMap; return this.metaOverrideMap;
} }
public Int2ObjectMap<String> getMetaModifiers() { public Int2ObjectMap<String> getMetaModifiers() {
if (this.metaModifiers == null) { if (this.metaModifiers == null) {
this.metaModifiers = new Int2ObjectOpenHashMap<>(); this.metaModifiers = new Int2ObjectOpenHashMap<>();
} }
return this.metaModifiers; return this.metaModifiers;
} }
public abstract Int2FloatOpenHashMap getFightProperties(); public abstract Int2FloatOpenHashMap getFightProperties();
...@@ -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));
} }
} }
...@@ -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,38 +813,49 @@ public class InventorySystem extends BaseGameSystem { ...@@ -812,38 +813,49 @@ 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;
} }
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 { } 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.
used = player.getTeamManager().healAvatar(target, SatiationParams[0], SatiationParams[1]) ? 1 : 0; 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; 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) {
case ITEM_USE_UNLOCK_FORGE -> player.getForgingManager().unlockForgingBlueprint(useItem); case ITEM_USE_UNLOCK_FORGE -> player.getForgingManager().unlockForgingBlueprint(useItem);
...@@ -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,23 +956,23 @@ public class InventorySystem extends BaseGameSystem { ...@@ -944,23 +956,23 @@ 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]);
float time = Float.parseFloat(useData.getUseParam()[1]); float time = Float.parseFloat(useData.getUseParam()[1]);
player.getBuffManager().addBuff(buffId, time); player.getBuffManager().addBuff(buffId, time);
} }
default -> {} default -> {}
} }
} }
// Remove item from inventory since we used it // Remove item from inventory since we used it
player.getInventory().removeItem(useItem, used); player.getInventory().removeItem(useItem, used);
return useItem; return useItem;
} }
if (useSuccess) { if (useSuccess) {
return useItem; return useItem;
} }
......
...@@ -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, 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) { 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;
...@@ -292,7 +308,7 @@ public class World implements Iterable<Player> { ...@@ -292,7 +308,7 @@ public class World implements Iterable<Player> {
player.getTeamManager().getMpTeam().copyFrom(player.getTeamManager().getMpTeam(), player.getTeamManager().getMaxTeamSize()); player.getTeamManager().getMpTeam().copyFrom(player.getTeamManager().getMpTeam(), player.getTeamManager().getMaxTeamSize());
player.getTeamManager().updateTeamEntities(null); player.getTeamManager().updateTeamEntities(null);
} }
// Dont send packets if player is loading into the scene // Dont send packets if player is loading into the scene
if (player.getSceneLoadState().getValue() < SceneLoadState.INIT.getValue() ) { if (player.getSceneLoadState().getValue() < SceneLoadState.INIT.getValue() ) {
// World player info packets // World player info packets
...@@ -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