Reworked FastCollatedDropQueue into cleaner system

This commit is contained in:
Auxilor 2020-12-18 14:35:03 +00:00
parent baebd9e904
commit eff46ed738
8 changed files with 308 additions and 106 deletions

View File

@ -5,8 +5,8 @@ import com.willfp.ecoenchants.command.AbstractCommand;
import com.willfp.ecoenchants.display.EnchantmentCache;
import com.willfp.ecoenchants.enchantments.EcoEnchant;
import com.willfp.ecoenchants.enchantments.EcoEnchants;
import com.willfp.ecoenchants.util.internal.FastCollatedDropQueue;
import com.willfp.ecoenchants.util.internal.Logger;
import com.willfp.ecoenchants.util.internal.drops.FastCollatedDropQueue;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment;
@ -14,7 +14,11 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Field;
import java.util.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@SuppressWarnings("unchecked")

View File

@ -4,7 +4,6 @@ import com.willfp.ecoenchants.enchantments.EcoEnchant;
import com.willfp.ecoenchants.enchantments.util.EnchantChecks;
import com.willfp.ecoenchants.integrations.antigrief.AntigriefManager;
import com.willfp.ecoenchants.util.internal.DropQueue;
import com.willfp.ecoenchants.util.internal.FastCollatedDropQueue;
import com.willfp.ecoenchants.util.tuplets.Pair;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
@ -98,11 +97,6 @@ public class InfernalTouch extends EcoEnchant {
event.getItems().clear();
if(FastCollatedDropQueue.use()) {
FastCollatedDropQueue.collateDrop(player, drops, experience.get(), block.getLocation());
return;
}
new DropQueue(player)
.setLocation(block.getLocation())
.addItems(drops)

View File

@ -8,7 +8,6 @@ import com.willfp.ecoenchants.events.entitydeathbyentity.EntityDeathByEntityEven
import com.willfp.ecoenchants.integrations.antigrief.AntigriefManager;
import com.willfp.ecoenchants.nms.TridentStack;
import com.willfp.ecoenchants.util.internal.DropQueue;
import com.willfp.ecoenchants.util.internal.FastCollatedDropQueue;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block;
@ -56,11 +55,6 @@ public class Telekinesis extends EcoEnchant {
event.getItems().clear();
if(FastCollatedDropQueue.use()) {
FastCollatedDropQueue.collateDrop(player, drops, 0, block.getLocation());
return;
}
new DropQueue(player)
.setLocation(block.getLocation())
.addItems(drops)

View File

@ -1,34 +1,21 @@
package com.willfp.ecoenchants.util.internal;
import com.willfp.ecoenchants.enchantments.EcoEnchants;
import com.willfp.ecoenchants.enchantments.util.EnchantChecks;
import com.willfp.ecoenchants.util.NumberUtils;
import org.bukkit.*;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ExperienceOrb;
import com.willfp.ecoenchants.util.internal.drops.AbstractDropQueue;
import com.willfp.ecoenchants.util.internal.drops.FastCollatedDropQueue;
import com.willfp.ecoenchants.util.internal.drops.InternalDropQueue;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerExpChangeEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
/**
* All drops generated from enchantments should be sent through a {@link DropQueue}
* Interacts with {@link EcoEnchants#TELEKINESIS}
*/
public class DropQueue {
private final List<ItemStack> items;
private int xp;
private final Player player;
private Location loc;
private boolean hasTelekinesis = false;
private ItemStack item;
private static boolean useOrb;
private final AbstractDropQueue handle;
/**
* Create {@link DropQueue} linked to player
@ -36,11 +23,7 @@ public class DropQueue {
* @param player The player
*/
public DropQueue(Player player) {
this.items = new ArrayList<>();
this.xp = 0;
this.player = player;
this.loc = player.getLocation();
this.item = player.getInventory().getItemInMainHand();
handle = FastCollatedDropQueue.use() ? new FastCollatedDropQueue(player) : new InternalDropQueue(player);
}
/**
@ -51,7 +34,7 @@ public class DropQueue {
* @return The DropQueue
*/
public DropQueue addItem(ItemStack item) {
this.items.add(item);
handle.addItem(item);
return this;
}
@ -63,7 +46,7 @@ public class DropQueue {
* @return The DropQueue
*/
public DropQueue addItems(Collection<ItemStack> itemStacks) {
this.items.addAll(itemStacks);
handle.addItems(itemStacks);
return this;
}
@ -75,7 +58,7 @@ public class DropQueue {
* @return The DropQueue
*/
public DropQueue addXP(int amount) {
this.xp += amount;
handle.addXP(amount);
return this;
}
@ -87,7 +70,7 @@ public class DropQueue {
* @return The DropQueue
*/
public DropQueue setLocation(Location l) {
this.loc = l;
handle.setLocation(l);
return this;
}
@ -97,7 +80,7 @@ public class DropQueue {
* @return The DropQueue
*/
public DropQueue forceTelekinesis() {
this.hasTelekinesis = true;
handle.forceTelekinesis();
return this;
}
@ -110,7 +93,7 @@ public class DropQueue {
* @return The DropQueue
*/
public DropQueue setItem(ItemStack item) {
this.item = item;
handle.setItem(item);
return this;
}
@ -118,45 +101,6 @@ public class DropQueue {
* Push the queue
*/
public void push() {
if(!hasTelekinesis) hasTelekinesis = EnchantChecks.item(item, EcoEnchants.TELEKINESIS);
if(hasTelekinesis && !EcoEnchants.TELEKINESIS.isEnabled()) hasTelekinesis = false;
World world = loc.getWorld();
assert world != null;
if(hasTelekinesis) {
HashMap<Integer, ItemStack> leftover = player.getInventory().addItem(items.toArray(new ItemStack[]{}));
for(ItemStack drop : leftover.values()) {
world.dropItemNaturally(loc.add(0.5, 0, 0.5), drop).setVelocity(new Vector());
}
if (xp > 0) {
PlayerExpChangeEvent event = new PlayerExpChangeEvent(player, xp);
Bukkit.getPluginManager().callEvent(event);
if (useOrb) {
ExperienceOrb orb = (ExperienceOrb) world.spawnEntity(player.getLocation().add(0, 0.2, 0), EntityType.EXPERIENCE_ORB);
orb.setVelocity(new Vector(0, 0, 0));
orb.setExperience(event.getAmount());
} else {
player.giveExp(event.getAmount());
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.AMBIENT, 1f, (float) NumberUtils.randFloat(0.7, 1.2));
}
}
} else {
for (ItemStack drop : items) {
world.dropItemNaturally(loc.add(0.5, 0, 0.5), drop).setVelocity(new Vector());
}
if (xp > 0) {
ExperienceOrb orb = (ExperienceOrb) world.spawnEntity(loc, EntityType.EXPERIENCE_ORB);
orb.setExperience(xp);
}
}
}
public static void update() {
useOrb = EcoEnchants.TELEKINESIS.getConfig().getBool(EcoEnchants.CONFIG_LOCATION + "use-orb");
}
static {
update();
handle.push();
}
}

View File

@ -8,7 +8,11 @@ import com.willfp.ecoenchants.command.tabcompleters.TabCompleterEnchantinfo;
import com.willfp.ecoenchants.config.ConfigManager;
import com.willfp.ecoenchants.display.EnchantDisplay;
import com.willfp.ecoenchants.display.EnchantmentCache;
import com.willfp.ecoenchants.display.packets.*;
import com.willfp.ecoenchants.display.packets.PacketChat;
import com.willfp.ecoenchants.display.packets.PacketOpenWindowMerchant;
import com.willfp.ecoenchants.display.packets.PacketSetCreativeSlot;
import com.willfp.ecoenchants.display.packets.PacketSetSlot;
import com.willfp.ecoenchants.display.packets.PacketWindowItems;
import com.willfp.ecoenchants.enchantments.EcoEnchant;
import com.willfp.ecoenchants.enchantments.EcoEnchants;
import com.willfp.ecoenchants.enchantments.meta.EnchantmentRarity;
@ -29,7 +33,12 @@ import com.willfp.ecoenchants.integrations.anticheat.plugins.AnticheatMatrix;
import com.willfp.ecoenchants.integrations.anticheat.plugins.AnticheatNCP;
import com.willfp.ecoenchants.integrations.anticheat.plugins.AnticheatSpartan;
import com.willfp.ecoenchants.integrations.antigrief.AntigriefManager;
import com.willfp.ecoenchants.integrations.antigrief.plugins.*;
import com.willfp.ecoenchants.integrations.antigrief.plugins.AntigriefFactionsUUID;
import com.willfp.ecoenchants.integrations.antigrief.plugins.AntigriefGriefPrevention;
import com.willfp.ecoenchants.integrations.antigrief.plugins.AntigriefKingdoms;
import com.willfp.ecoenchants.integrations.antigrief.plugins.AntigriefLands;
import com.willfp.ecoenchants.integrations.antigrief.plugins.AntigriefTowny;
import com.willfp.ecoenchants.integrations.antigrief.plugins.AntigriefWorldGuard;
import com.willfp.ecoenchants.integrations.essentials.EssentialsManager;
import com.willfp.ecoenchants.integrations.essentials.plugins.IntegrationEssentials;
import com.willfp.ecoenchants.integrations.mcmmo.McmmoManager;
@ -40,6 +49,8 @@ import com.willfp.ecoenchants.integrations.worldguard.WorldguardManager;
import com.willfp.ecoenchants.integrations.worldguard.plugins.WorldguardIntegrationImpl;
import com.willfp.ecoenchants.util.interfaces.Callable;
import com.willfp.ecoenchants.util.interfaces.EcoRunnable;
import com.willfp.ecoenchants.util.internal.drops.FastCollatedDropQueue;
import com.willfp.ecoenchants.util.internal.drops.InternalDropQueue;
import com.willfp.ecoenchants.util.internal.updater.PlayerJoinListener;
import com.willfp.ecoenchants.util.internal.updater.UpdateChecker;
import com.willfp.ecoenchants.util.optional.Prerequisite;
@ -50,7 +61,11 @@ import org.bukkit.event.HandlerList;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.plugin.Plugin;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -367,7 +382,7 @@ public class Loader {
EnchantmentRarity.update();
EnchantmentTarget.update();
EcoEnchants.update();
DropQueue.update();
InternalDropQueue.update();
EnchantDisplay.update();
TabCompleterEnchantinfo.reload();
FastCollatedDropQueue.update();

View File

@ -0,0 +1,66 @@
package com.willfp.ecoenchants.util.internal.drops;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
import java.util.Collection;
public interface AbstractDropQueue {
/**
* Add item to queue
*
* @param item The item to add
*
* @return The DropQueue
*/
AbstractDropQueue addItem(ItemStack item);
/**
* Add multiple items to queue
*
* @param itemStacks The items to add
*
* @return The DropQueue
*/
AbstractDropQueue addItems(Collection<ItemStack> itemStacks);
/**
* Add xp to queue
*
* @param amount The amount to add
*
* @return The DropQueue
*/
AbstractDropQueue addXP(int amount);
/**
* Set location of the origin of the drops
*
* @param l The location
*
* @return The DropQueue
*/
AbstractDropQueue setLocation(Location l);
/**
* Force the queue to act as if player has {@link com.willfp.ecoenchants.enchantments.EcoEnchants#TELEKINESIS}
*
* @return The DropQueue
*/
AbstractDropQueue forceTelekinesis();
/**
* Set the queue to test specific item for {@link com.willfp.ecoenchants.enchantments.EcoEnchants#TELEKINESIS}
* Default item is the player's held item, however for this is required for Tridents.
*
* @param item The item to test
*
* @return The DropQueue
*/
AbstractDropQueue setItem(ItemStack item);
/**
* Push the queue
*/
void push();
}

View File

@ -1,45 +1,46 @@
package com.willfp.ecoenchants.util.internal;
package com.willfp.ecoenchants.util.internal.drops;
import com.willfp.ecoenchants.EcoEnchantsPlugin;
import com.willfp.ecoenchants.config.ConfigManager;
import com.willfp.ecoenchants.util.internal.DropQueue;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FastCollatedDropQueue {
/**
* Backend implementation of {@link AbstractDropQueue}
* {@link this#push()} adds to a map that creates a new {@link InternalDropQueue} at the end of every tick
*
* The drops are not instantly pushed when called, instead the map is iterated over at the end of every tick. This massively improves performance.
*/
public class FastCollatedDropQueue extends InternalDropQueue {
private static boolean collate = false;
private static final HashMap<Player, CollatedDrops> COLLATED_MAP = new HashMap<>();
static {
Bukkit.getScheduler().runTaskTimer(EcoEnchantsPlugin.getInstance(), () -> {
if (!collate) return;
for (Map.Entry<Player, CollatedDrops> entry : COLLATED_MAP.entrySet()) {
new DropQueue(entry.getKey())
.setLocation(entry.getValue().getLocation())
.addItems(entry.getValue().getDrops())
.addXP(entry.getValue().getXp())
.push();
}
COLLATED_MAP.clear();
}, 0, 1);
update();
/**
* Create {@link DropQueue} linked to player
*
* @param player The player
*/
public FastCollatedDropQueue(Player player) {
super(player);
}
public static void collateDrop(Player player, Collection<ItemStack> items, int xp, Location location) {
@Override
public void push() {
CollatedDrops collatedDrops;
if(COLLATED_MAP.containsKey(player)) {
List<ItemStack> dropSet = COLLATED_MAP.get(player).getDrops();
dropSet.addAll(items);
collatedDrops = new CollatedDrops(dropSet, location, xp);
collatedDrops = new FastCollatedDropQueue.CollatedDrops(dropSet, loc, xp);
} else {
collatedDrops = new CollatedDrops(new ArrayList<>(items), location, xp);
collatedDrops = new FastCollatedDropQueue.CollatedDrops(new ArrayList<>(items), loc, xp);
}
COLLATED_MAP.put(player, collatedDrops);
@ -53,6 +54,22 @@ public class FastCollatedDropQueue {
collate = ConfigManager.getConfig().getBool( "drops.collate");
}
static {
Bukkit.getScheduler().runTaskTimer(EcoEnchantsPlugin.getInstance(), () -> {
if (!collate) return;
for (Map.Entry<Player, CollatedDrops> entry : COLLATED_MAP.entrySet()) {
new InternalDropQueue(entry.getKey())
.setLocation(entry.getValue().getLocation())
.addItems(entry.getValue().getDrops())
.addXP(entry.getValue().getXp())
.push();
}
COLLATED_MAP.clear();
}, 0, 1);
update();
}
private static class CollatedDrops {
private final List<ItemStack> drops;
private final Location location;

View File

@ -0,0 +1,168 @@
package com.willfp.ecoenchants.util.internal.drops;
import com.willfp.ecoenchants.enchantments.EcoEnchants;
import com.willfp.ecoenchants.enchantments.util.EnchantChecks;
import com.willfp.ecoenchants.util.NumberUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerExpChangeEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
public class InternalDropQueue implements AbstractDropQueue {
protected final List<ItemStack> items;
protected int xp;
protected final Player player;
protected Location loc;
protected boolean hasTelekinesis = false;
protected ItemStack item;
private static boolean useOrb;
/**
* Create {@link com.willfp.ecoenchants.util.internal.DropQueue} linked to player
*
* @param player The player
*/
public InternalDropQueue(Player player) {
this.items = new ArrayList<>();
this.xp = 0;
this.player = player;
this.loc = player.getLocation();
this.item = player.getInventory().getItemInMainHand();
}
/**
* Add item to queue
*
* @param item The item to add
*
* @return The DropQueue
*/
@Override
public AbstractDropQueue addItem(ItemStack item) {
this.items.add(item);
return this;
}
/**
* Add multiple items to queue
*
* @param itemStacks The items to add
*
* @return The DropQueue
*/
@Override
public AbstractDropQueue addItems(Collection<ItemStack> itemStacks) {
this.items.addAll(itemStacks);
return this;
}
/**
* Add xp to queue
*
* @param amount The amount to add
*
* @return The DropQueue
*/
@Override
public AbstractDropQueue addXP(int amount) {
this.xp += amount;
return this;
}
/**
* Set location of the origin of the drops
*
* @param l The location
*
* @return The DropQueue
*/
@Override
public AbstractDropQueue setLocation(Location l) {
this.loc = l;
return this;
}
/**
* Force the queue to act as if player has {@link EcoEnchants#TELEKINESIS}
*
* @return The DropQueue
*/
@Override
public AbstractDropQueue forceTelekinesis() {
this.hasTelekinesis = true;
return this;
}
/**
* Set the queue to test specific item for {@link EcoEnchants#TELEKINESIS}
* Default item is the player's held item, however for this is required for Tridents.
*
* @param item The item to test
*
* @return The DropQueue
*/
@Override
public AbstractDropQueue setItem(ItemStack item) {
this.item = item;
return this;
}
/**
* Push the queue
*/
public void push() {
if(!hasTelekinesis) hasTelekinesis = EnchantChecks.item(item, EcoEnchants.TELEKINESIS);
if(hasTelekinesis && !EcoEnchants.TELEKINESIS.isEnabled()) hasTelekinesis = false;
World world = loc.getWorld();
assert world != null;
if(hasTelekinesis) {
HashMap<Integer, ItemStack> leftover = player.getInventory().addItem(items.toArray(new ItemStack[]{}));
for(ItemStack drop : leftover.values()) {
world.dropItemNaturally(loc.add(0.5, 0, 0.5), drop).setVelocity(new Vector());
}
if (xp > 0) {
PlayerExpChangeEvent event = new PlayerExpChangeEvent(player, xp);
Bukkit.getPluginManager().callEvent(event);
if (useOrb) {
ExperienceOrb orb = (ExperienceOrb) world.spawnEntity(player.getLocation().add(0, 0.2, 0), EntityType.EXPERIENCE_ORB);
orb.setVelocity(new Vector(0, 0, 0));
orb.setExperience(event.getAmount());
} else {
player.giveExp(event.getAmount());
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.AMBIENT, 1f, (float) NumberUtils.randFloat(0.7, 1.2));
}
}
} else {
for (ItemStack drop : items) {
world.dropItemNaturally(loc.add(0.5, 0, 0.5), drop).setVelocity(new Vector());
}
if (xp > 0) {
ExperienceOrb orb = (ExperienceOrb) world.spawnEntity(loc, EntityType.EXPERIENCE_ORB);
orb.setExperience(xp);
}
}
}
public static void update() {
useOrb = EcoEnchants.TELEKINESIS.getConfig().getBool(EcoEnchants.CONFIG_LOCATION + "use-orb");
}
static {
update();
}
}