mirror of
https://github.com/Minestom/Minestom.git
synced 2025-03-02 11:21:15 +01:00
Merge pull request #92 from ThatCreeper/potion-api
Add a basic potion api
This commit is contained in:
commit
4d8bd8430b
@ -22,6 +22,9 @@ import net.minestom.server.instance.block.CustomBlock;
|
||||
import net.minestom.server.network.packet.server.play.*;
|
||||
import net.minestom.server.permission.Permission;
|
||||
import net.minestom.server.permission.PermissionHandler;
|
||||
import net.minestom.server.potion.Potion;
|
||||
import net.minestom.server.potion.PotionEffect;
|
||||
import net.minestom.server.potion.TimedPotion;
|
||||
import net.minestom.server.thread.ThreadProvider;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.Position;
|
||||
@ -41,6 +44,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
@ -130,6 +134,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
|
||||
protected boolean noGravity;
|
||||
protected Pose pose = Pose.STANDING;
|
||||
|
||||
private CopyOnWriteArrayList<TimedPotion> effects = new CopyOnWriteArrayList<>();
|
||||
|
||||
// list of scheduled tasks to be executed during the next entity tick
|
||||
protected final Queue<Consumer<Entity>> nextTick = Queues.newConcurrentLinkedQueue();
|
||||
|
||||
@ -396,6 +402,13 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
|
||||
return;
|
||||
}
|
||||
|
||||
// remove expired effects
|
||||
{
|
||||
effects.removeIf(timedPotion -> time
|
||||
>=
|
||||
(timedPotion.getStartingTime() + timedPotion.getPotion().getDuration() * MinecraftServer.TICK_MS));
|
||||
}
|
||||
|
||||
// scheduled tasks
|
||||
if (!nextTick.isEmpty()) {
|
||||
Consumer<Entity> callback;
|
||||
@ -1442,6 +1455,36 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
|
||||
DYING
|
||||
}
|
||||
|
||||
public List<TimedPotion> getActiveEffects() {
|
||||
return effects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes effect from entity, if it has it.
|
||||
*
|
||||
* @param effect The effect to remove
|
||||
*/
|
||||
public void removeEffect(@NotNull PotionEffect effect) {
|
||||
effects.removeIf(timedPotion -> {
|
||||
if (timedPotion.getPotion().getEffect() == effect) {
|
||||
timedPotion.getPotion().sendRemovePacket(this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an effect to an entity.
|
||||
*
|
||||
* @param potion The potion to add
|
||||
*/
|
||||
public void addEffect(@NotNull Potion potion) {
|
||||
removeEffect(potion.getEffect());
|
||||
effects.add(new TimedPotion(potion, System.currentTimeMillis()));
|
||||
potion.sendAddPacket(this);
|
||||
}
|
||||
|
||||
protected boolean shouldRemove() {
|
||||
return shouldRemove;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import net.minestom.server.network.packet.client.play.ClientPlayerDiggingPacket;
|
||||
import net.minestom.server.network.packet.server.play.AcknowledgePlayerDiggingPacket;
|
||||
import net.minestom.server.network.packet.server.play.EntityEffectPacket;
|
||||
import net.minestom.server.network.packet.server.play.RemoveEntityEffectPacket;
|
||||
import net.minestom.server.potion.Potion;
|
||||
import net.minestom.server.potion.PotionEffect;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
|
||||
@ -189,10 +190,14 @@ public class PlayerDiggingListener {
|
||||
|
||||
EntityEffectPacket entityEffectPacket = new EntityEffectPacket();
|
||||
entityEffectPacket.entityId = player.getEntityId();
|
||||
entityEffectPacket.effect = PotionEffect.MINING_FATIGUE;
|
||||
entityEffectPacket.amplifier = -1;
|
||||
entityEffectPacket.duration = 0;
|
||||
entityEffectPacket.flags = 0;
|
||||
entityEffectPacket.potion = new Potion(
|
||||
PotionEffect.MINING_FATIGUE,
|
||||
(byte) -1,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
);
|
||||
player.getPlayerConnection().sendPacket(entityEffectPacket);
|
||||
}
|
||||
|
||||
|
@ -2,25 +2,22 @@ package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.potion.PotionEffect;
|
||||
import net.minestom.server.potion.Potion;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class EntityEffectPacket implements ServerPacket {
|
||||
|
||||
public int entityId;
|
||||
public PotionEffect effect;
|
||||
public byte amplifier;
|
||||
public int duration;
|
||||
public byte flags;
|
||||
public Potion potion;
|
||||
|
||||
@Override
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
writer.writeVarInt(entityId);
|
||||
writer.writeByte((byte) effect.getId());
|
||||
writer.writeByte(amplifier);
|
||||
writer.writeVarInt(duration);
|
||||
writer.writeByte(flags);
|
||||
writer.writeByte((byte) potion.getEffect().getId());
|
||||
writer.writeByte(potion.getAmplifier());
|
||||
writer.writeVarInt(potion.getDuration());
|
||||
writer.writeByte(potion.getFlags());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
118
src/main/java/net/minestom/server/potion/Potion.java
Normal file
118
src/main/java/net/minestom/server/potion/Potion.java
Normal file
@ -0,0 +1,118 @@
|
||||
package net.minestom.server.potion;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.network.packet.server.play.EntityEffectPacket;
|
||||
import net.minestom.server.network.packet.server.play.RemoveEntityEffectPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class Potion {
|
||||
private final PotionEffect effect;
|
||||
private final byte amplifier;
|
||||
private final int duration;
|
||||
private final byte flags;
|
||||
|
||||
/**
|
||||
* Creates a new potion.
|
||||
*
|
||||
* @param effect The type of potion.
|
||||
* @param amplifier The strength of the potion.
|
||||
* @param duration The length of the potion in ticks.
|
||||
*/
|
||||
public Potion(PotionEffect effect, byte amplifier, int duration) {
|
||||
this(effect, amplifier, duration, true, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new potion.
|
||||
*
|
||||
* @param effect The type of potion.
|
||||
* @param amplifier The strength of the potion.
|
||||
* @param duration The length of the potion in ticks.
|
||||
* @param particles If the potion has particles.
|
||||
*/
|
||||
public Potion(PotionEffect effect, byte amplifier, int duration, boolean particles) {
|
||||
this(effect, amplifier, duration, particles, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new potion.
|
||||
*
|
||||
* @param effect The type of potion.
|
||||
* @param amplifier The strength of the potion.
|
||||
* @param duration The length of the potion in ticks.
|
||||
* @param particles If the potion has particles.
|
||||
* @param icon If the potion has an icon.
|
||||
*/
|
||||
public Potion(PotionEffect effect, byte amplifier, int duration, boolean particles, boolean icon) {
|
||||
this(effect, amplifier, duration, particles, icon, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new potion.
|
||||
*
|
||||
* @param effect The type of potion.
|
||||
* @param amplifier The strength of the potion.
|
||||
* @param duration The length of the potion in ticks.
|
||||
* @param particles If the potion has particles.
|
||||
* @param icon If the potion has an icon.
|
||||
* @param ambient If the potion came from a beacon.
|
||||
*/
|
||||
public Potion(PotionEffect effect, byte amplifier, int duration, boolean particles, boolean icon, boolean ambient) {
|
||||
this.effect = effect;
|
||||
this.amplifier = amplifier;
|
||||
this.duration = duration;
|
||||
byte flags = 0;
|
||||
if (ambient) {
|
||||
flags = (byte) (flags | 0x01);
|
||||
}
|
||||
if (particles) {
|
||||
flags = (byte) (flags | 0x02);
|
||||
}
|
||||
if (icon) {
|
||||
flags = (byte) (flags | 0x04);
|
||||
}
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
public PotionEffect getEffect() {
|
||||
return effect;
|
||||
}
|
||||
|
||||
public byte getAmplifier() {
|
||||
return amplifier;
|
||||
}
|
||||
|
||||
public int getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public byte getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet that a potion effect has been applied to the entity.
|
||||
* <p>
|
||||
* Used internally by {@link net.minestom.server.entity.Player#addEffect(Potion)}
|
||||
* @param entity
|
||||
*/
|
||||
public void sendAddPacket(@NotNull Entity entity) {
|
||||
EntityEffectPacket eep = new EntityEffectPacket();
|
||||
eep.entityId = entity.getEntityId();
|
||||
eep.potion = this;
|
||||
entity.sendPacketToViewersAndSelf(eep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet that a potion effect has been removed from the entity.
|
||||
* <p>
|
||||
* Used internally by {@link net.minestom.server.entity.Player#removeEffect(PotionEffect)}
|
||||
* @param entity
|
||||
*/
|
||||
public void sendRemovePacket(@NotNull Entity entity) {
|
||||
RemoveEntityEffectPacket reep = new RemoveEntityEffectPacket();
|
||||
reep.entityId = entity.getEntityId();
|
||||
reep.effect = effect;
|
||||
entity.sendPacketToViewersAndSelf(reep);
|
||||
}
|
||||
}
|
19
src/main/java/net/minestom/server/potion/TimedPotion.java
Normal file
19
src/main/java/net/minestom/server/potion/TimedPotion.java
Normal file
@ -0,0 +1,19 @@
|
||||
package net.minestom.server.potion;
|
||||
|
||||
public class TimedPotion {
|
||||
private final Potion potion;
|
||||
private final long startingTime;
|
||||
|
||||
public TimedPotion(Potion potion, long startingTime) {
|
||||
this.potion = potion;
|
||||
this.startingTime = startingTime;
|
||||
}
|
||||
|
||||
public Potion getPotion() {
|
||||
return potion;
|
||||
}
|
||||
|
||||
public long getStartingTime() {
|
||||
return startingTime;
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ public class Main {
|
||||
commandManager.register(new ShutdownCommand());
|
||||
commandManager.register(new TeleportCommand());
|
||||
commandManager.register(new PlayersCommand());
|
||||
commandManager.register(new PotionCommand());
|
||||
|
||||
commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage("unknown command"));
|
||||
|
||||
|
@ -29,6 +29,7 @@ import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.ConnectionManager;
|
||||
import net.minestom.server.network.packet.server.play.PlayerListHeaderAndFooterPacket;
|
||||
import net.minestom.server.ping.ResponseDataConsumer;
|
||||
import net.minestom.server.timer.TaskBuilder;
|
||||
import net.minestom.server.utils.PacketUtils;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.Vector;
|
||||
|
51
src/test/java/demo/commands/PotionCommand.java
Normal file
51
src/test/java/demo/commands/PotionCommand.java
Normal file
@ -0,0 +1,51 @@
|
||||
package demo.commands;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.command.builder.Arguments;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.arguments.ArgumentType;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.potion.Potion;
|
||||
import net.minestom.server.potion.PotionEffect;
|
||||
|
||||
public class PotionCommand extends Command {
|
||||
|
||||
public PotionCommand() {
|
||||
super("potion");
|
||||
|
||||
setCondition(this::condition);
|
||||
|
||||
setDefaultExecutor(((sender, args) -> {
|
||||
sender.sendMessage("Usage: /potion [type] [duration (seconds)]");
|
||||
}));
|
||||
|
||||
Argument potionArg = ArgumentType.Potion("potion");
|
||||
Argument durationArg = ArgumentType.Integer("duration");
|
||||
|
||||
addSyntax(this::onPotionCommand, potionArg, durationArg);
|
||||
}
|
||||
|
||||
private boolean condition(CommandSender sender, String commandString) {
|
||||
if (!sender.isPlayer()) {
|
||||
sender.sendMessage("The command is only available for players");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void onPotionCommand(CommandSender sender, Arguments args) {
|
||||
final Player player = (Player) sender;
|
||||
final PotionEffect potion = args.getPotionEffect("potion");
|
||||
final int duration = args.getInteger("duration");
|
||||
|
||||
player.sendMessage(player.getActiveEffects().toString());
|
||||
player.addEffect(new Potion(
|
||||
potion,
|
||||
(byte) 0,
|
||||
duration * MinecraftServer.TICK_PER_SECOND
|
||||
));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user