Rewrite Potions

This commit is contained in:
ThatCreeper 2020-12-30 18:29:07 -06:00
parent 50b44e46e0
commit d7883d29ff
8 changed files with 79 additions and 274 deletions

View File

@ -33,7 +33,6 @@ import net.minestom.server.network.packet.server.play.UpdateViewDistancePacket;
import net.minestom.server.particle.Particle;
import net.minestom.server.ping.ResponseDataConsumer;
import net.minestom.server.potion.PotionEffect;
import net.minestom.server.potion.PotionEffectManager;
import net.minestom.server.potion.PotionType;
import net.minestom.server.recipe.RecipeManager;
import net.minestom.server.registry.ResourceGatherer;
@ -117,7 +116,6 @@ public final class MinecraftServer {
private static DimensionTypeManager dimensionTypeManager;
private static BiomeManager biomeManager;
private static AdvancementManager advancementManager;
private static PotionEffectManager potionEffectManager;
private static ExtensionManager extensionManager;
@ -179,7 +177,6 @@ public final class MinecraftServer {
dimensionTypeManager = new DimensionTypeManager();
biomeManager = new BiomeManager();
advancementManager = new AdvancementManager();
potionEffectManager = new PotionEffectManager();
updateManager = new UpdateManager();
@ -624,16 +621,6 @@ public final class MinecraftServer {
return advancementManager;
}
/**
* Gets the manager handling potions.
*
* @return the potion effect manager
*/
public static PotionEffectManager getPotionEffectManager() {
checkInitStatus(potionEffectManager);
return potionEffectManager;
}
/**
* Get the manager handling {@link Extension}.
*

View File

@ -22,6 +22,8 @@ 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.thread.ThreadProvider;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Position;
@ -130,6 +132,9 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
protected boolean noGravity;
protected Pose pose = Pose.STANDING;
private ArrayList<Potion> effects = new ArrayList<>();
private ArrayList<Long> effectTimes = new ArrayList<>();
// list of scheduled tasks to be executed during the next entity tick
protected final Queue<Consumer<Entity>> nextTick = Queues.newConcurrentLinkedQueue();
@ -396,6 +401,29 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
return;
}
// remove expired effects
{
if (effects.size() > 0) {
boolean foundToRemove = true;
while (foundToRemove) {
foundToRemove = false;
int i = 0;
while (i < effects.size()) {
if (effects.get(i).duration * 50 +
effectTimes.get(i) <= System.nanoTime() / 1000000) {
foundToRemove = true;
break;
}
i++;
}
if (foundToRemove) {
effects.remove(i);
effectTimes.remove(i);
}
}
}
}
// scheduled tasks
if (!nextTick.isEmpty()) {
Consumer<Entity> callback;
@ -1442,6 +1470,45 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
DYING
}
public List<Potion> getActiveEffects() {
return effects;
}
/**
* Removes effect from entity, if it has it.
*
* @param effect The effect to remove
*/
public void removeEffect(@NotNull PotionEffect effect) {
if (effects.size() == 0) return;
int i = 0;
boolean found = false;
while (i < effects.size()) {
if (effects.get(i).effect == effect) {
found = true;
break;
}
i++;
}
if (found) {
effects.get(i).sendRemovePacket(this);
effects.remove(i);
effectTimes.remove(i);
}
}
/**
* Adds an effect to an entity
*
* @param potion The potion to add
*/
public void addEffect(@NotNull Potion potion) {
removeEffect(potion.effect);
effects.add(potion);
effectTimes.add(System.nanoTime() / 1000000);
potion.sendAddPacket(this);
}
protected boolean shouldRemove() {
return shouldRemove;
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.potion;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.EntityEffectPacket;
import net.minestom.server.network.packet.server.play.RemoveEntityEffectPacket;
@ -42,17 +43,17 @@ public class Potion {
return computed;
}
public void sendAddPacket(@NotNull Player player) {
public void sendAddPacket(@NotNull Entity entity) {
EntityEffectPacket eep = new EntityEffectPacket();
eep.entityId = player.getEntityId();
eep.entityId = entity.getEntityId();
eep.potion = this;
player.sendPacketToViewersAndSelf(eep);
entity.sendPacketToViewersAndSelf(eep);
}
public void sendRemovePacket(@NotNull Player player) {
public void sendRemovePacket(@NotNull Entity entity) {
RemoveEntityEffectPacket reep = new RemoveEntityEffectPacket();
reep.entityId = player.getEntityId();
reep.entityId = entity.getEntityId();
reep.effect = effect;
player.sendPacketToViewersAndSelf(reep);
entity.sendPacketToViewersAndSelf(reep);
}
}

View File

@ -1,185 +0,0 @@
package net.minestom.server.potion;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.event.player.PlayerDisconnectEvent;
import net.minestom.server.event.player.PlayerSpawnEvent;
import net.minestom.server.timer.SchedulerManager;
import net.minestom.server.utils.time.TimeUnit;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
/**
* Manages active potion effects on players
*/
public class PotionEffectManager {
private HashMap<UUID, ArrayList<PotionTask>> playerEffects;
private boolean persistEffects = false;
/**
* Creates a new PotionEffectManager
*/
public PotionEffectManager() {
playerEffects = new HashMap<>();
addEventHandlers();
}
/**
* Returns the active effects of a player.
*
* @param player The player to get the effects of.
* @return Null if no active effects, otherwise the active effects.
*/
public @Nullable List<PotionTask> getActiveEffects(@Nullable Player player) {
if (player == null) return null;
return playerEffects.get(player.getUuid());
}
/**
* Returns a {@link PotionTask} on a player of a type {@link PotionEffect}
*
* @param player The player with the effect.
* @param potionEffect The type of potion to look for.
* @return Null if the player does not have the effect, otherwise the effect.
*/
public @Nullable PotionTask getPotionTask(@Nullable Player player, @Nullable PotionEffect potionEffect) {
if (player == null) return null;
if (potionEffect == null) return null;
ArrayList<PotionTask> potionTasks = playerEffects.get(player.getUuid());
if (potionTasks == null) return null;
for (PotionTask potionTask : potionTasks) {
if (potionTask.getPotion().effect == potionEffect) {
return potionTask;
}
}
return null;
}
/**
* Returns if the player has an effect of specified type.
*
* @param player The player to check.
* @param potionEffect The type of potion to check for.
* @return If the player has a potion effect with the specified type.
*/
public boolean hasPotionEffect(@Nullable Player player, @Nullable PotionEffect potionEffect) {
return getPotionTask(player, potionEffect) != null;
}
/**
* Removes the {@link PotionTask}.
*
* @param task The {@link PotionTask} to remove.
*/
public void removeEffect(@NotNull PotionTask task) {
task.getValue().task.cancel();
for (UUID uuid : playerEffects.keySet()) {
if (playerEffects.get(uuid).contains(task)) {
playerEffects.get(uuid).remove(task);
Player player = MinecraftServer.getConnectionManager().getPlayer(uuid);
if (player != null && player.isOnline()) {
task.getPotion().sendRemovePacket(player);
}
return;
}
}
}
/**
* If the player has a potion of type effect, remove it.
*
* @param player The player to remove from.
* @param effect The {@link PotionEffect} to remove.
*/
public void removeEffect(@NotNull Player player, @NotNull PotionEffect effect) {
PotionTask task = null;
ArrayList<PotionTask> potionTasks = playerEffects.get(player.getUuid());
if (potionTasks == null) return;
for (PotionTask potionTask : potionTasks) {
if (potionTask.getPotion().effect == effect) {
task = potionTask;
break;
}
}
if (task == null) return;
removeEffect(task);
}
/**
* Clears a player's effects.
*
* @param player The player to clear.
*/
public void clearEffects(@Nullable Player player) {
if (player == null) return;
ArrayList<PotionTask> potionTasks = playerEffects.get(player.getUuid());
if (potionTasks == null) return;
for (PotionTask potionTask : potionTasks) {
potionTask.getValue().task.cancel();
if (player.isOnline()) {
potionTask.getPotion().sendRemovePacket(player);
}
}
potionTasks.clear();
playerEffects.remove(player.getUuid());
}
/**
* Gives a player a potion effect.
*
* @param player The player to give to.
* @param potion The {@link Potion} to give.
*/
public void addPotion(@Nullable Player player, @Nullable Potion potion) {
if (player == null) return;
if (potion == null) return;
removeEffect(player, potion.effect);
ArrayList<PotionTask> potionTasks = playerEffects.computeIfAbsent(player.getUuid(), k -> new ArrayList<>());
SchedulerManager schedulerManager = MinecraftServer.getSchedulerManager();
PotionTimeTask ptt = new PotionTimeTask(MinecraftServer.getSchedulerManager(),
TimeUnit.TICK.toMilliseconds(potion.duration));
potionTasks.add(new PotionTask(potion, ptt));
potion.sendAddPacket(player);
}
// NOT IMPLEMENTED
// public void setPersistEffects(Boolean persistEffects) {
// this.persistEffects = persistEffects;
// }
//
// public boolean getPersistEffects() {
// return persistEffects;
// }
/**
* Adds a {@link PlayerSpawnEvent} and {@link PlayerDisconnectEvent} handler to pause and resume potion effects.
*/
private void addEventHandlers() {
GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
globalEventHandler.addEventCallback(PlayerSpawnEvent.class, playerSpawnEvent -> {
if (persistEffects) {
// TODO: Implement persist
}
});
globalEventHandler.addEventCallback(PlayerDisconnectEvent.class, playerDisconnectEvent -> {
if (persistEffects) {
// TODO: Implement persist
} else {
clearEffects(playerDisconnectEvent.getPlayer());
}
});
}
}

View File

@ -1,25 +0,0 @@
package net.minestom.server.potion;
import javafx.util.Pair;
import net.minestom.server.MinecraftServer;
public class PotionTask extends Pair<Potion, PotionTimeTask> {
/**
* Creates a new PotionTask
*
* @param potion The {@link Potion}
* @param task The {@link PotionTimeTask}
*/
public PotionTask(Potion potion, PotionTimeTask task) {
super(potion, task);
task.potionTask = this;
}
public Potion getPotion() {
return this.getKey();
}
public void removeEffect() {
MinecraftServer.getPotionEffectManager().removeEffect(this);
}
}

View File

@ -1,27 +0,0 @@
package net.minestom.server.potion;
import net.minestom.server.timer.SchedulerManager;
import net.minestom.server.timer.Task;
import net.minestom.server.utils.time.TimeUnit;
import org.jetbrains.annotations.NotNull;
public class PotionTimeTask {
public Long remainingTime;
public Task task;
public PotionTask potionTask;
/**
* Creates a task.
*
* @param schedulerManager The manager for the task
* @param delay The time to delay
*/
public PotionTimeTask(@NotNull SchedulerManager schedulerManager, long delay) {
Runnable runTask = () -> {
potionTask.removeEffect();
};
task = schedulerManager.buildTask(runTask).delay(delay, TimeUnit.MILLISECOND).schedule();
this.remainingTime = delay;
}
}

View File

@ -1,12 +0,0 @@
package net.minestom.server.potion;
public class PotionTimeTaskHolder {
/**
* Only updates when task is paused
*/
public Long timeRemaining;
public PotionTimeTaskHolder() {
// TODO: Implement persist
}
}

View File

@ -9,9 +9,6 @@ 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;
import net.minestom.server.potion.PotionTask;
import java.util.List;
public class PotionCommand extends Command {
@ -43,10 +40,12 @@ public class PotionCommand extends Command {
final PotionEffect potion = args.getPotionEffect("potion");
final int duration = args.getInteger("duration");
MinecraftServer.getPotionEffectManager().addPotion(player, new Potion(
player.sendMessage(player.getActiveEffects().toString());
player.addEffect(new Potion(
potion,
(byte) 1,
duration * 20
(byte) 0,
duration
));
}