mirror of
https://github.com/songoda/UltimateStacker.git
synced 2025-02-04 13:41:22 +01:00
Merge branch 'development'
This commit is contained in:
commit
92027b0bb6
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -35,7 +35,7 @@ jobs:
|
||||
with:
|
||||
append_snapshot: ${{ github.ref_type == 'tag' && 'false' || 'true' }}
|
||||
version: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
|
||||
increment_version: ${{ github.ref_type == 'tag' && '' || 'patch' }}
|
||||
increment_version: ${{ github.ref_type != 'tag' && 'patch' || '' }}
|
||||
increment_version_only_if_not_snapshot_version: ${{ github.ref == 'refs/heads/development' && 'true' || 'false' }}
|
||||
|
||||
- name: Build with Maven
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.craftaro</groupId>
|
||||
<artifactId>UltimateStacker-Parent</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>3.1.2</version>
|
||||
</parent>
|
||||
<artifactId>UltimateStacker-API</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.craftaro</groupId>
|
||||
<artifactId>UltimateStacker-Parent</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>3.1.2</version>
|
||||
</parent>
|
||||
<artifactId>UltimateStacker-Plugin</artifactId>
|
||||
|
||||
@ -118,6 +118,13 @@
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.6</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.craftaro</groupId>
|
||||
<artifactId>CraftaroCore</artifactId>
|
||||
@ -128,7 +135,7 @@
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.18-R0.1-SNAPSHOT</version>
|
||||
<version>1.20-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
@ -10,12 +10,10 @@ import com.craftaro.core.dependency.Dependency;
|
||||
import com.craftaro.core.gui.GuiManager;
|
||||
import com.craftaro.core.hooks.EntityStackerManager;
|
||||
import com.craftaro.core.hooks.HologramManager;
|
||||
import com.craftaro.core.hooks.HookManager;
|
||||
import com.craftaro.core.hooks.ProtectionManager;
|
||||
import com.craftaro.core.hooks.WorldGuardHook;
|
||||
import com.craftaro.core.hooks.holograms.DecentHologramsHolograms;
|
||||
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
|
||||
import com.craftaro.core.utils.TextUtils;
|
||||
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
|
||||
import com.craftaro.ultimatestacker.api.UltimateStackerApi;
|
||||
import com.craftaro.ultimatestacker.api.stack.block.BlockStack;
|
||||
import com.craftaro.ultimatestacker.api.stack.block.BlockStackManager;
|
||||
@ -25,13 +23,7 @@ import com.craftaro.ultimatestacker.api.stack.item.StackedItemManager;
|
||||
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStack;
|
||||
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStackManager;
|
||||
import com.craftaro.ultimatestacker.api.utils.Hologramable;
|
||||
import com.craftaro.ultimatestacker.commands.CommandConvert;
|
||||
import com.craftaro.ultimatestacker.commands.CommandGiveSpawner;
|
||||
import com.craftaro.ultimatestacker.commands.CommandLootables;
|
||||
import com.craftaro.ultimatestacker.commands.CommandReload;
|
||||
import com.craftaro.ultimatestacker.commands.CommandRemoveAll;
|
||||
import com.craftaro.ultimatestacker.commands.CommandSettings;
|
||||
import com.craftaro.ultimatestacker.commands.CommandSpawn;
|
||||
import com.craftaro.ultimatestacker.commands.*;
|
||||
import com.craftaro.ultimatestacker.database.migrations._1_InitialMigration;
|
||||
import com.craftaro.ultimatestacker.database.migrations._2_EntityStacks;
|
||||
import com.craftaro.ultimatestacker.database.migrations._3_BlockStacks;
|
||||
@ -39,15 +31,7 @@ import com.craftaro.ultimatestacker.database.migrations._6_RemoveStackedEntityTa
|
||||
import com.craftaro.ultimatestacker.hook.StackerHook;
|
||||
import com.craftaro.ultimatestacker.hook.hooks.JobsHook;
|
||||
import com.craftaro.ultimatestacker.hook.hooks.SuperiorSkyblock2Hook;
|
||||
import com.craftaro.ultimatestacker.listeners.BlockListeners;
|
||||
import com.craftaro.ultimatestacker.listeners.BreedListeners;
|
||||
import com.craftaro.ultimatestacker.listeners.ClearLagListeners;
|
||||
import com.craftaro.ultimatestacker.listeners.DeathListeners;
|
||||
import com.craftaro.ultimatestacker.listeners.InteractListeners;
|
||||
import com.craftaro.ultimatestacker.listeners.ShearListeners;
|
||||
import com.craftaro.ultimatestacker.listeners.SheepDyeListeners;
|
||||
import com.craftaro.ultimatestacker.listeners.SpawnerListeners;
|
||||
import com.craftaro.ultimatestacker.listeners.TameListeners;
|
||||
import com.craftaro.ultimatestacker.listeners.*;
|
||||
import com.craftaro.ultimatestacker.listeners.entity.EntityCurrentListener;
|
||||
import com.craftaro.ultimatestacker.listeners.entity.EntityListeners;
|
||||
import com.craftaro.ultimatestacker.listeners.item.ItemCurrentListener;
|
||||
@ -62,6 +46,7 @@ import com.craftaro.ultimatestacker.stackable.entity.custom.CustomEntityManager;
|
||||
import com.craftaro.ultimatestacker.stackable.item.StackedItemManagerImpl;
|
||||
import com.craftaro.ultimatestacker.stackable.spawner.SpawnerStackImpl;
|
||||
import com.craftaro.ultimatestacker.stackable.spawner.SpawnerStackManagerImpl;
|
||||
import com.craftaro.ultimatestacker.tasks.BreedingTask;
|
||||
import com.craftaro.ultimatestacker.tasks.StackingTask;
|
||||
import com.craftaro.ultimatestacker.utils.Async;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
@ -72,12 +57,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class UltimateStacker extends SongodaPlugin {
|
||||
|
||||
@ -99,8 +79,10 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
private CommandManager commandManager;
|
||||
private CustomEntityManager customEntityManager;
|
||||
private StackingTask stackingTask;
|
||||
private BreedingTask breedingTask;
|
||||
private UltimateStackerApi API;
|
||||
private SuperiorSkyblock2Hook superiorSkyblock2Hook;
|
||||
private boolean instantStacking;
|
||||
|
||||
public static UltimateStacker getInstance() {
|
||||
return INSTANCE;
|
||||
@ -121,9 +103,8 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
|
||||
@Override
|
||||
public void onPluginDisable() {
|
||||
if (this.stackingTask != null) {
|
||||
this.stackingTask.stop();
|
||||
}
|
||||
if (this.stackingTask != null)
|
||||
this.stackingTask.cancel();
|
||||
this.dataManager.saveBatchSync(this.spawnerStackManager.getStacksData());
|
||||
this.dataManager.saveBatchSync(this.blockStackManager.getStacksData());
|
||||
this.dataManager.shutdownNow();
|
||||
@ -153,7 +134,7 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
new CommandGiveSpawner(this),
|
||||
new CommandSpawn(this),
|
||||
new CommandLootables(this),
|
||||
new CommandConvert( guiManager)
|
||||
new CommandConvert(guiManager)
|
||||
);
|
||||
|
||||
PluginManager pluginManager = Bukkit.getPluginManager();
|
||||
@ -212,6 +193,7 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13))
|
||||
pluginManager.registerEvents(new EntityCurrentListener(this), this);
|
||||
|
||||
this.instantStacking = Settings.STACK_ENTITIES.getBoolean() && Settings.INSTANT_STACKING.getBoolean();
|
||||
pluginManager.registerEvents(new EntityListeners(this), this);
|
||||
pluginManager.registerEvents(new ItemListeners(this), this);
|
||||
|
||||
@ -246,7 +228,7 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
public void onDataLoad() {
|
||||
if (HologramManager.isEnabled())
|
||||
// Set the offset so that the holograms don't end up inside the blocks.
|
||||
HologramManager.getHolograms().setPositionOffset(.5,.65,.5);
|
||||
HologramManager.getHolograms().setPositionOffset(.5, .65, .5);
|
||||
|
||||
// Load current data.
|
||||
final boolean useSpawnerHolo = Settings.SPAWNER_HOLOGRAMS.getBoolean();
|
||||
@ -262,16 +244,21 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
}
|
||||
});
|
||||
|
||||
this.stackingTask = new StackingTask(this);
|
||||
//Start stacking task
|
||||
if (Settings.STACK_ENTITIES.getBoolean()) {
|
||||
this.breedingTask = new BreedingTask(this);
|
||||
this.stackingTask = new StackingTask(this);
|
||||
}
|
||||
|
||||
this.instantStacking = Settings.STACK_ENTITIES.getBoolean() && Settings.INSTANT_STACKING.getBoolean();
|
||||
final boolean useBlockHolo = Settings.BLOCK_HOLOGRAMS.getBoolean();
|
||||
this.dataManager.loadBatch(BlockStackImpl.class, "blocks").forEach((data) -> {
|
||||
BlockStack blockStack = (BlockStack) data;
|
||||
this.blockStackManager.addBlock(blockStack);
|
||||
if (useBlockHolo) {
|
||||
if (blockStack == null) return;
|
||||
if (blockStack.getLocation().getWorld() != null) {
|
||||
if (blockStack.getLocation().getWorld() != null)
|
||||
updateHologram(blockStack);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -301,8 +288,12 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
this.setLocale(getConfig().getString("System.Language Mode"), true);
|
||||
this.locale.reloadMessages();
|
||||
|
||||
this.stackingTask.stop();
|
||||
this.stackingTask = new StackingTask(this);
|
||||
if (stackingTask != null)
|
||||
this.stackingTask.cancel();
|
||||
|
||||
if (Settings.STACK_ENTITIES.getBoolean()) {
|
||||
this.stackingTask = new StackingTask(this);
|
||||
}
|
||||
|
||||
this.mobFile.load();
|
||||
this.itemFile.load();
|
||||
@ -409,6 +400,10 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
return superiorSkyblock2Hook;
|
||||
}
|
||||
|
||||
public boolean isInstantStacking() {
|
||||
return instantStacking;
|
||||
}
|
||||
|
||||
//////// Convenient API //////////
|
||||
|
||||
/**
|
||||
@ -460,4 +455,8 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
return !whitelist.isEmpty() && !whitelist.contains(combined)
|
||||
|| !blacklist.isEmpty() && blacklist.contains(combined);
|
||||
}
|
||||
|
||||
public BreedingTask getBreedingTask() {
|
||||
return breedingTask;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
package com.craftaro.ultimatestacker.commands;
|
||||
|
||||
import com.craftaro.core.commands.AbstractCommand;
|
||||
import com.craftaro.core.world.SSpawner;
|
||||
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStack;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CommandForceSpawn extends AbstractCommand {
|
||||
private final UltimateStacker plugin;
|
||||
|
||||
public CommandForceSpawn(UltimateStacker plugin) {
|
||||
super(CommandType.PLAYER_ONLY, "forcespawn");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReturnType runCommand(CommandSender sender, String... args) {
|
||||
Player player = (Player) sender;
|
||||
|
||||
Block block = player.getTargetBlock(null, 200);
|
||||
|
||||
if (XMaterial.matchXMaterial(block.getType().name()).get() != XMaterial.SPAWNER) {
|
||||
this.plugin.getLocale().newMessage("&cThat is not a spawner...").sendPrefixedMessage(player);
|
||||
return ReturnType.FAILURE;
|
||||
}
|
||||
|
||||
//PlacedSpawner spawner = this.plugin.getSpawnerManager().getSpawnerFromWorld(block.getLocation());
|
||||
SpawnerStack spawner = this.plugin.getSpawnerStackManager().getSpawner(block.getLocation());
|
||||
if (spawner == null) {
|
||||
//it is a vanilla spawner
|
||||
CreatureSpawner vanillaSpawner = (CreatureSpawner) block.getState();
|
||||
SSpawner creatureSpawner = new SSpawner(block.getLocation());
|
||||
creatureSpawner.spawn(vanillaSpawner.getSpawnCount(), vanillaSpawner.getSpawnedType());
|
||||
} else {
|
||||
//it is an epic spawner
|
||||
spawner.spawn();
|
||||
}
|
||||
this.plugin.getLocale().newMessage("&aSpawning successful.").sendPrefixedMessage(player);
|
||||
return ReturnType.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> onTab(CommandSender sender, String... args) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPermissionNode() {
|
||||
return "ultimatestacker.admin.forcespawn";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSyntax() {
|
||||
return "forcespawn";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Force the spawner you are looking at to spawn so long as the spawn conditions are met.";
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import com.craftaro.core.commands.AbstractCommand;
|
||||
import com.craftaro.core.utils.TextUtils;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
|
||||
import com.craftaro.ultimatestacker.tasks.StackingTask;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@ -51,9 +52,12 @@ public class CommandSpawn extends AbstractCommand {
|
||||
}
|
||||
sender.sendMessage(TextUtils.formatText("&6" + list));
|
||||
} else {
|
||||
LivingEntity entity = (LivingEntity)player.getWorld().spawnEntity(player.getLocation(), type);
|
||||
EntityStack stack = plugin.getEntityStackManager().createStackedEntity(entity, Integer.parseInt(args[1]));
|
||||
plugin.getStackingTask().attemptSplit(stack, entity);
|
||||
StackingTask stackingTask = plugin.getStackingTask();
|
||||
if (stackingTask != null) {
|
||||
LivingEntity entity = (LivingEntity)player.getWorld().spawnEntity(player.getLocation(), type);
|
||||
EntityStack stack = plugin.getEntityStackManager().createStackedEntity(entity, Integer.parseInt(args[1]));
|
||||
stackingTask.attemptSplit(stack, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return ReturnType.SUCCESS;
|
||||
|
@ -1,29 +1,39 @@
|
||||
package com.craftaro.ultimatestacker.listeners;
|
||||
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import org.bukkit.Bukkit;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStackManager;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityBreedEvent;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
|
||||
public class BreedListeners implements Listener {
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
private final EntityStackManager entityStackManager;
|
||||
|
||||
public BreedListeners(UltimateStacker plugin) {
|
||||
this.plugin = plugin;
|
||||
this.entityStackManager = plugin.getEntityStackManager();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBread(EntityBreedEvent event) {
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
||||
event.getFather().removeMetadata("breedCooldown", plugin);
|
||||
event.getMother().removeMetadata("breedCooldown", plugin);
|
||||
}, 5 * 20 * 60);
|
||||
event.getFather().setMetadata("breedCooldown", new FixedMetadataValue(plugin, true));
|
||||
event.getFather().removeMetadata("inLove", plugin);
|
||||
event.getMother().setMetadata("breedCooldown", new FixedMetadataValue(plugin, true));
|
||||
event.getMother().removeMetadata("inLove", plugin);
|
||||
EntityStack stackedMother = entityStackManager.getStackedEntity(event.getMother());
|
||||
EntityStack stackedFather = entityStackManager.getStackedEntity(event.getFather());
|
||||
|
||||
plugin.getBreedingTask().addBreedingTicket(event.getMother(), event.getFather());
|
||||
|
||||
if (stackedMother != null) {
|
||||
EntityStack stack = entityStackManager.getStackedEntity(event.getMother());
|
||||
if (stack.getAmount() <= 1) return;
|
||||
stack.releaseHost();
|
||||
}
|
||||
|
||||
if (stackedFather != null) {
|
||||
EntityStack stack = entityStackManager.getStackedEntity(event.getFather());
|
||||
if (stack.getAmount() <= 1) return;
|
||||
stack.releaseHost();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,12 +77,10 @@ public class DeathListeners implements Listener {
|
||||
List<Drop> drops = custom ? plugin.getLootablesManager().getDrops(event.getEntity())
|
||||
: event.getDrops().stream().map(Drop::new).collect(Collectors.toList());
|
||||
|
||||
if (custom) {
|
||||
for (ItemStack item : new ArrayList<>(event.getDrops())) {
|
||||
if (custom)
|
||||
for (ItemStack item : new ArrayList<>(event.getDrops()))
|
||||
if (shouldDrop(event.getEntity(), item.getType()))
|
||||
drops.add(new Drop(item));
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin.getCustomEntityManager().getCustomEntity(entity) == null) {
|
||||
//Run commands here, or it will be buggy
|
||||
|
@ -1,20 +1,12 @@
|
||||
package com.craftaro.ultimatestacker.listeners;
|
||||
|
||||
import com.craftaro.core.compatibility.ServerVersion;
|
||||
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
|
||||
import com.craftaro.ultimatestacker.settings.Settings;
|
||||
import com.craftaro.ultimatestacker.stackable.entity.Split;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.Cat;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Horse;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Wolf;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
||||
@ -64,66 +56,75 @@ public class InteractListeners implements Listener {
|
||||
&& !((Ageable) entity).isAdult()) {
|
||||
return;
|
||||
}
|
||||
entity.setMetadata("inLove", new FixedMetadataValue(plugin, true));
|
||||
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> {
|
||||
if (entity.isDead()) return;
|
||||
entity.removeMetadata("inLove", plugin);
|
||||
}, 20 * 20);
|
||||
plugin.getBreedingTask().addInLoveTicket(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean correctFood(ItemStack is, Entity entity) {
|
||||
Material type = is.getType();
|
||||
|
||||
switch (entity.getType().name()) {
|
||||
case "COW":
|
||||
case "MUSHROOM_COW":
|
||||
case "SHEEP":
|
||||
return type == Material.WHEAT;
|
||||
case "PIG":
|
||||
return type == Material.CARROT || (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9) && type == Material.BEETROOT) || type == Material.POTATO;
|
||||
return type == Material.CARROT || type == Material.BEETROOT || type == Material.POTATO;
|
||||
case "CHICKEN":
|
||||
return type == XMaterial.WHEAT_SEEDS.parseMaterial()
|
||||
return type == Material.WHEAT_SEEDS
|
||||
|| type == Material.MELON_SEEDS
|
||||
|| type == Material.PUMPKIN_SEEDS
|
||||
|| type == XMaterial.BEETROOT_SEEDS.parseMaterial();
|
||||
|| type == Material.BEETROOT_SEEDS;
|
||||
case "HORSE":
|
||||
return (type == Material.GOLDEN_APPLE || type == Material.GOLDEN_CARROT) && ((Horse)entity).isTamed();
|
||||
case "DONKEY":
|
||||
case "MULE":
|
||||
return (type == Material.GOLDEN_APPLE || type == Material.GOLDEN_CARROT) && ((AbstractHorse) entity).isTamed();
|
||||
case "WOLF":
|
||||
return type == XMaterial.BEEF.parseMaterial()
|
||||
|| type == XMaterial.CHICKEN.parseMaterial()
|
||||
|| type == XMaterial.COD.parseMaterial()
|
||||
|| type == XMaterial.MUTTON.parseMaterial()
|
||||
|| type == XMaterial.PORKCHOP.parseMaterial()
|
||||
|| type == XMaterial.RABBIT.parseMaterial()
|
||||
|| XMaterial.SALMON.equals(XMaterial.matchXMaterial(is))
|
||||
|| type == XMaterial.COOKED_BEEF.parseMaterial()
|
||||
|| type == XMaterial.COOKED_CHICKEN.parseMaterial()
|
||||
|| type == XMaterial.COOKED_COD.parseMaterial()
|
||||
|| type == XMaterial.COOKED_MUTTON.parseMaterial()
|
||||
|| type == XMaterial.COOKED_PORKCHOP.parseMaterial()
|
||||
|| type == XMaterial.COOKED_RABBIT.parseMaterial()
|
||||
|| XMaterial.COOKED_SALMON.equals(XMaterial.matchXMaterial(is))
|
||||
return type == Material.BEEF
|
||||
|| type == Material.CHICKEN
|
||||
|| type == Material.COD
|
||||
|| type == Material.MUTTON
|
||||
|| type == Material.PORKCHOP
|
||||
|| type == Material.RABBIT
|
||||
|| type == Material.SALMON
|
||||
|| type == Material.COOKED_BEEF
|
||||
|| type == Material.COOKED_CHICKEN
|
||||
|| type == Material.COOKED_COD
|
||||
|| type == Material.COOKED_MUTTON
|
||||
|| type == Material.COOKED_PORKCHOP
|
||||
|| type == Material.COOKED_RABBIT
|
||||
|| type == Material.COOKED_SALMON
|
||||
|| type == Material.ROTTEN_FLESH
|
||||
&& ((Wolf) entity).isTamed();
|
||||
case "OCELOT":
|
||||
return (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|
||||
? type == Material.SALMON
|
||||
|| type == Material.COD
|
||||
|| type == Material.PUFFERFISH
|
||||
|| type == Material.TROPICAL_FISH
|
||||
: type == XMaterial.COD.parseMaterial()); // Now broken in 1.13 ((Ocelot) entity).isTamed()
|
||||
case "PANDA":
|
||||
return (type == Material.BAMBOO);
|
||||
case "FOX":
|
||||
return type == Material.SWEET_BERRIES;
|
||||
case "CAT":
|
||||
return (type == Material.COD || type == Material.SALMON) && ((Cat) entity).isTamed();
|
||||
return (type == Material.COD || type == Material.SALMON) && ((Tameable) entity).isTamed();
|
||||
case "PANDA":
|
||||
return type == Material.BAMBOO;
|
||||
case "FOX":
|
||||
return type == Material.SWEET_BERRIES || type == Material.GLOW_BERRIES;
|
||||
case "RABBIT":
|
||||
return type == Material.CARROT || type == Material.GOLDEN_CARROT || type == Material.DANDELION;
|
||||
case "LLAMA":
|
||||
case "TRADER_LLAMA":
|
||||
return type == Material.HAY_BLOCK;
|
||||
case "TURTLE":
|
||||
return type == Material.SEAGRASS;
|
||||
case "HOGLIN":
|
||||
return type == Material.CRIMSON_FUNGUS;
|
||||
case "STRIDER":
|
||||
return type == Material.WARPED_FUNGUS;
|
||||
case "BEE":
|
||||
return type == Material.HONEYCOMB || type == Material.HONEY_BOTTLE;
|
||||
case "AXOLOTL":
|
||||
return type == Material.TROPICAL_FISH_BUCKET;
|
||||
case "GOAT":
|
||||
return type == Material.WHEAT;
|
||||
case "GLOW_SQUID":
|
||||
return type == Material.GLOW_INK_SAC;
|
||||
case "CAMEL":
|
||||
return type == Material.CACTUS;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.craftaro.ultimatestacker.listeners.entity;
|
||||
|
||||
import com.craftaro.core.configuration.Config;
|
||||
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.UltimateStackerApi;
|
||||
@ -8,6 +9,7 @@ import com.craftaro.ultimatestacker.api.stack.entity.EntityStackManager;
|
||||
import com.craftaro.ultimatestacker.api.stack.item.StackedItem;
|
||||
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStack;
|
||||
import com.craftaro.ultimatestacker.settings.Settings;
|
||||
import com.craftaro.ultimatestacker.tasks.StackingTask;
|
||||
import com.craftaro.ultimatestacker.utils.Methods;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@ -38,9 +40,12 @@ import java.util.List;
|
||||
public class EntityListeners implements Listener {
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
private int searchRadius = Settings.SEARCH_RADIUS.getInt() * 16; //SEARCH_RADIUS is in chunks, so multiply by 16 to get blocks
|
||||
private Config mobsConfig;
|
||||
|
||||
public EntityListeners(UltimateStacker plugin) {
|
||||
this.plugin = plugin;
|
||||
mobsConfig = plugin.getMobFile();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@ -73,9 +78,7 @@ public class EntityListeners implements Listener {
|
||||
item.setAmount(Math.min(amount, item.getMaxStackSize()));
|
||||
if (amount > item.getMaxStackSize()) {
|
||||
StackedItem stackedItem = UltimateStackerApi.getStackedItemManager().getStackedItem(event.getEntity());
|
||||
if (stackedItem != null) {
|
||||
stackedItem.setAmount(amount - item.getMaxStackSize());
|
||||
}
|
||||
stackedItem.setAmount(amount - item.getMaxStackSize());
|
||||
}
|
||||
event.getEntity().setItemStack(item);
|
||||
}
|
||||
@ -102,7 +105,31 @@ public class EntityListeners implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onSpawn(CreatureSpawnEvent event) {
|
||||
event.getEntity().setMetadata("US_REASON", new FixedMetadataValue(plugin, event.getSpawnReason().name()));
|
||||
String spawnReason = event.getSpawnReason().name();
|
||||
if (plugin.isInstantStacking()) {
|
||||
LivingEntity spawningEntity = event.getEntity();
|
||||
EntityStackManager stackManager = plugin.getEntityStackManager();
|
||||
if (stackManager.isStackedEntity(spawningEntity)) return; //We don't want to stack split entities or respawned stacks
|
||||
|
||||
List<LivingEntity> stackableFriends = plugin.getStackingTask().getSimilarEntitiesAroundEntity(spawningEntity, spawningEntity.getLocation());
|
||||
if (stackableFriends.isEmpty()) {
|
||||
event.getEntity().setMetadata("US_REASON", new FixedMetadataValue(plugin, spawnReason));
|
||||
return;
|
||||
}
|
||||
|
||||
LivingEntity friendStack = stackableFriends.get(0);
|
||||
if (stackManager.isStackedEntity(friendStack)) {
|
||||
EntityStack stack = stackManager.getStackedEntity(friendStack);
|
||||
//getSimilarEntitiesAroundEntity check for max stack size, we don't need to check again
|
||||
stack.add(1);
|
||||
event.setCancelled(true);
|
||||
} else {
|
||||
stackManager.createStackedEntity(friendStack, 2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
event.getEntity().setMetadata("US_REASON", new FixedMetadataValue(plugin, spawnReason));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
@ -67,6 +67,7 @@ public class LootablesManager {
|
||||
//Apply SuperiorSkyblock2 mob-drops multiplier if present
|
||||
if (superiorSkyblock2Hook.isEnabled()) {
|
||||
for (Drop drop : toDrop) {
|
||||
if (drop.getItemStack() == null) continue; //Maybe it is just exp
|
||||
drop.getItemStack().setAmount(superiorSkyblock2Hook.getDropMultiplier(entity.getLocation()) * drop.getItemStack().getAmount());
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ public class Settings implements com.craftaro.ultimatestacker.api.Settings {
|
||||
"The speed in which a new stacks will be created.",
|
||||
"It is advised to keep this number low.");
|
||||
|
||||
public static final ConfigSetting INSTANT_STACKING = new ConfigSetting(config, "Main.Instant Stacking", false,
|
||||
"Should entities stacked into existing stacks before they spawned?");
|
||||
|
||||
public static final ConfigSetting DISABLED_WORLDS = new ConfigSetting(config, "Main.Disabled Worlds", Arrays.asList("World1", "World2", "World3"),
|
||||
"Worlds that stacking doesn't happen in.");
|
||||
|
||||
@ -45,8 +48,10 @@ public class Settings implements com.craftaro.ultimatestacker.api.Settings {
|
||||
"The maximum amount of each entity type stack allowed in a chunk.");
|
||||
|
||||
public static final ConfigSetting STACK_WHOLE_CHUNK = new ConfigSetting(config, "Entities.Stack Whole Chunk", false,
|
||||
"Should all qualifying entities in each chunk be stacked?",
|
||||
"This will override the stacking radius.");
|
||||
"Should all qualifying entities in each chunk be stacked?");
|
||||
|
||||
public static final ConfigSetting STACK_WHOLE_CHUNK_RADIUS = new ConfigSetting(config, "Entities.Stack Whole Chunk Radius", 1,
|
||||
"Radius in chunks every direction around the entity that will be stacked.", "0 means only the chunk the entity is in.");
|
||||
|
||||
public static final ConfigSetting ENTITY_NAMETAGS = new ConfigSetting(config, "Entities.Holograms Enabled", true,
|
||||
"Should holograms be displayed above stacked entities?");
|
||||
@ -103,7 +108,11 @@ public class Settings implements com.craftaro.ultimatestacker.api.Settings {
|
||||
"\"HORSE_STYLE\", \"HORSE_CARRYING_CHEST\", \"HORSE_HAS_ARMOR\", \"HORSE_HAS_SADDLE\",",
|
||||
"\"HORSE_JUMP\", \"RABBIT_TYPE\", \"VILLAGER_PROFESSION\", \"LLAMA_COLOR\",",
|
||||
"\"LLAMA_STRENGTH\", \"PARROT_TYPE\", \"PUFFERFISH_STATE\", \"TROPICALFISH_PATTERN\",",
|
||||
"\"TROPICALFISH_BODY_COLOR\", \"TROPICALFISH_PATTERN_COLOR\", \"PHANTOM_SIZE\", \"CAT_TYPE\".");
|
||||
"\"TROPICALFISH_BODY_COLOR\", \"TROPICALFISH_PATTERN_COLOR\", \"PHANTOM_SIZE\", \"CAT_TYPE\"",
|
||||
"\"AXOLOTL_VARIANT\", \"AXOLOTL_PLAYING_DEAD\", \"GLOW_SQUID_DARK_TICKS\", \"GOAT_HAS_HORNS\",",
|
||||
"\"FROG_VARIANT\", \"TADPOLE_AGE\", \"WARDEN_ANGER_LEVEL\", \"SNIFFER_HAS_SEEDS\",",
|
||||
"\"FOX_TYPE\", \"HOGLIN_IMMUNE\".");
|
||||
|
||||
|
||||
public static final ConfigSetting SPLIT_CHECKS = new ConfigSetting(config, "Entities.Split Checks", Arrays.asList(Split.values()).stream()
|
||||
.map(Split::name).collect(Collectors.toList()),
|
||||
|
@ -19,7 +19,7 @@ public enum Check {
|
||||
SLIME_SIZE(true),
|
||||
PIG_SADDLE(true),
|
||||
SHEEP_SHEARED(true),
|
||||
SHEEP_COLOR(false),
|
||||
SHEEP_COLOR(true),
|
||||
SNOWMAN_DERPED(true),
|
||||
WOLF_COLLAR_COLOR(true),
|
||||
OCELOT_TYPE(false),
|
||||
@ -39,8 +39,17 @@ public enum Check {
|
||||
TROPICALFISH_BODY_COLOR(true),
|
||||
TROPICALFISH_PATTERN_COLOR(true),
|
||||
PHANTOM_SIZE(true),
|
||||
CAT_TYPE(false);
|
||||
|
||||
CAT_TYPE(false),
|
||||
AXOLOTL_VARIANT(false),
|
||||
AXOLOTL_PLAYING_DEAD(true),
|
||||
GLOW_SQUID_DARK_TICKS(true),
|
||||
GOAT_HAS_HORNS(false),
|
||||
FROG_VARIANT(true),
|
||||
TADPOLE_AGE(false),
|
||||
WARDEN_ANGER_LEVEL(false),
|
||||
SNIFFER_HAS_SEEDS(true),
|
||||
FOX_TYPE(false),
|
||||
HOGLIN_IMMUNE(true);
|
||||
private final boolean isEnabledByDefault;
|
||||
private final static Map<String, Check> checks = new HashMap();
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
package com.craftaro.ultimatestacker.stackable.entity;
|
||||
|
||||
import com.craftaro.core.SongodaCore;
|
||||
import com.craftaro.core.compatibility.ServerVersion;
|
||||
import com.craftaro.core.lootables.loot.Drop;
|
||||
import com.craftaro.core.lootables.loot.DropUtils;
|
||||
import com.craftaro.core.utils.EntityUtils;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.UltimateStackerApi;
|
||||
import com.craftaro.ultimatestacker.api.events.entity.EntityStackKillEvent;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
|
||||
import com.craftaro.ultimatestacker.settings.Settings;
|
||||
@ -14,7 +12,7 @@ import com.craftaro.ultimatestacker.utils.Async;
|
||||
import com.craftaro.ultimatestacker.utils.Methods;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.ExperienceOrb;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@ -22,10 +20,10 @@ import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
@ -33,35 +31,73 @@ import java.util.UUID;
|
||||
public class EntityStackImpl implements EntityStack {
|
||||
|
||||
private final UltimateStacker plugin = UltimateStacker.getInstance();
|
||||
private final NamespacedKey STACKED_ENTITY_KEY = new NamespacedKey(plugin, "US_AMOUNT");
|
||||
private int amount;
|
||||
private LivingEntity hostEntity;
|
||||
|
||||
/**
|
||||
* Gets an existing stack from an entity or creates a new one if it doesn't exist.
|
||||
*
|
||||
* @param entity The entity to get the stack from.
|
||||
*/
|
||||
public EntityStackImpl(LivingEntity entity) {
|
||||
if (entity == null) return;
|
||||
if (!UltimateStacker.getInstance().getEntityStackManager().isStackedEntity(entity)) {
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), 1));
|
||||
this.amount = 1;
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
PersistentDataContainer container = entity.getPersistentDataContainer();
|
||||
if (container.has(STACKED_ENTITY_KEY, PersistentDataType.INTEGER)) {
|
||||
this.amount = container.get(STACKED_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
} else {
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), 1));
|
||||
this.amount = 1;
|
||||
}
|
||||
} else {
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), 1));
|
||||
this.amount = 1;
|
||||
}
|
||||
} else {
|
||||
//get the amount from the entity
|
||||
this.amount = entity.getMetadata("US_AMOUNT").get(0).asInt();
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
PersistentDataContainer container = entity.getPersistentDataContainer();
|
||||
if (container.has(STACKED_ENTITY_KEY, PersistentDataType.INTEGER)) {
|
||||
this.amount = container.get(STACKED_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||
} else {
|
||||
this.amount = getMetaCount(entity);
|
||||
}
|
||||
} else {
|
||||
this.amount = getMetaCount(entity);
|
||||
}
|
||||
}
|
||||
this.hostEntity = entity;
|
||||
}
|
||||
|
||||
private int getMetaCount(LivingEntity entity) {
|
||||
if (entity.hasMetadata("US_AMOUNT")) {
|
||||
return entity.getMetadata("US_AMOUNT").get(0).asInt();
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new stack or overrides an existing stack.
|
||||
*
|
||||
* @param entity The entity to create the stack for.
|
||||
* @param amount The amount of entities in the stack.
|
||||
*/
|
||||
public EntityStackImpl(LivingEntity entity, int amount) {
|
||||
if (entity == null) return;
|
||||
this.hostEntity = entity;
|
||||
if (amount <= 0) {
|
||||
throw new IllegalArgumentException("Amount must be greater than 0");
|
||||
}
|
||||
this.amount = amount;
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
PersistentDataContainer container = entity.getPersistentDataContainer();
|
||||
container.set(STACKED_ENTITY_KEY, PersistentDataType.INTEGER, amount);
|
||||
} else {
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
}
|
||||
updateNameTag();
|
||||
}
|
||||
|
||||
@ -78,7 +114,12 @@ public class EntityStackImpl implements EntityStack {
|
||||
@Override
|
||||
public void setAmount(int amount) {
|
||||
this.amount = amount;
|
||||
this.hostEntity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
PersistentDataContainer container = hostEntity.getPersistentDataContainer();
|
||||
container.set(STACKED_ENTITY_KEY, PersistentDataType.INTEGER, amount);
|
||||
} else {
|
||||
hostEntity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
}
|
||||
updateNameTag();
|
||||
}
|
||||
|
||||
@ -196,10 +237,10 @@ public class EntityStackImpl implements EntityStack {
|
||||
@Override
|
||||
public synchronized LivingEntity takeOneAndSpawnEntity(Location location) {
|
||||
if (amount <= 0) return null;
|
||||
|
||||
LivingEntity entity = (LivingEntity) Objects.requireNonNull(location.getWorld()).spawnEntity(location, hostEntity.getType());
|
||||
if (Settings.NO_AI.getBoolean()) {
|
||||
if (Settings.NO_AI.getBoolean())
|
||||
EntityUtils.setUnaware(entity);
|
||||
}
|
||||
this.hostEntity = entity;
|
||||
setAmount(amount--);
|
||||
updateNameTag();
|
||||
@ -208,13 +249,27 @@ public class EntityStackImpl implements EntityStack {
|
||||
|
||||
@Override
|
||||
public synchronized void releaseHost() {
|
||||
LivingEntity oldHost = hostEntity;
|
||||
LivingEntity entity = takeOneAndSpawnEntity(hostEntity.getLocation());
|
||||
if (getAmount() >= 0) {
|
||||
plugin.getEntityStackManager().updateStack(oldHost, entity);
|
||||
updateNameTag();
|
||||
wipeData();
|
||||
|
||||
//Summon a new entity, update the stack and remove the metadata from the old entity
|
||||
this.hostEntity = takeOneAndSpawnEntity(hostEntity.getLocation());
|
||||
if (amount == 2) {
|
||||
wipeData();
|
||||
} else {
|
||||
destroy();
|
||||
setAmount(amount - 1);
|
||||
updateNameTag();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void wipeData() {
|
||||
hostEntity.setCustomName(null);
|
||||
hostEntity.setCustomNameVisible(false);
|
||||
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
PersistentDataContainer container = hostEntity.getPersistentDataContainer();
|
||||
container.remove(STACKED_ENTITY_KEY);
|
||||
} else {
|
||||
hostEntity.removeMetadata("US_AMOUNT", plugin);
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,9 +281,9 @@ public class EntityStackImpl implements EntityStack {
|
||||
}
|
||||
|
||||
public void updateNameTag() {
|
||||
if (hostEntity == null) {
|
||||
if (hostEntity == null)
|
||||
return;
|
||||
}
|
||||
|
||||
hostEntity.setCustomNameVisible(!Settings.HOLOGRAMS_ON_LOOK_ENTITY.getBoolean());
|
||||
hostEntity.setCustomName(Methods.compileEntityName(hostEntity, getAmount()));
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
package com.craftaro.ultimatestacker.stackable.entity;
|
||||
|
||||
import com.craftaro.core.compatibility.ServerVersion;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStackManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import uk.antiperson.stackmob.api.StackedEntity;
|
||||
|
||||
import java.util.UUID;
|
||||
@ -15,9 +19,11 @@ import java.util.UUID;
|
||||
public class EntityStackManagerImpl implements EntityStackManager {
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
private final NamespacedKey STACKED_ENTITY_KEY;
|
||||
|
||||
public EntityStackManagerImpl(UltimateStacker plugin) {
|
||||
this.plugin = plugin;
|
||||
this.STACKED_ENTITY_KEY = new NamespacedKey(plugin, "US_AMOUNT");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -29,7 +35,13 @@ public class EntityStackManagerImpl implements EntityStackManager {
|
||||
|
||||
@Override
|
||||
public boolean isStackedEntity(Entity entity) {
|
||||
return entity.hasMetadata("US_AMOUNT");
|
||||
if (entity.hasMetadata("US_AMOUNT")) {
|
||||
return true;
|
||||
}
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
return entity.getPersistentDataContainer().has(STACKED_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,8 +22,6 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class StackedItemManagerImpl implements StackedItemManager {
|
||||
|
||||
private final static int MAX_INT = 1500000000;
|
||||
|
||||
@Override
|
||||
public @NotNull StackedItem getStackedItem(Item item) {
|
||||
return new StackedItemImpl(item);
|
||||
@ -106,8 +104,8 @@ public class StackedItemManagerImpl implements StackedItemManager {
|
||||
}
|
||||
}
|
||||
|
||||
int maxItemStackSize = Settings.MAX_STACK_ITEMS.getInt();
|
||||
if (maxItemStackSize > MAX_INT) maxItemStackSize = MAX_INT;
|
||||
long maxItemStackSize = Settings.MAX_STACK_ITEMS.getLong();
|
||||
if (maxItemStackSize > Integer.MAX_VALUE) maxItemStackSize = Integer.MAX_VALUE;
|
||||
|
||||
ItemStack fromItemStack = from.getItemStack();
|
||||
ItemStack toItemStack = to.getItemStack();
|
||||
|
@ -84,7 +84,7 @@ public class SpawnerStackImpl implements SpawnerStack {
|
||||
|
||||
@Override
|
||||
public int spawn() {
|
||||
return spawn(-1, false);
|
||||
return spawn(-1, Settings.NO_AI.getBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,48 @@
|
||||
package com.craftaro.ultimatestacker.tasks;
|
||||
|
||||
import com.craftaro.core.task.TaskScheduler;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BreedingTask extends TaskScheduler {
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
|
||||
private final Set<UUID> breedingEntities = new HashSet<>();
|
||||
private final Set<UUID> inLoveEntities = new HashSet<>();
|
||||
|
||||
public BreedingTask(UltimateStacker plugin) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
|
||||
}
|
||||
|
||||
public void addBreedingTicket(LivingEntity mother, LivingEntity father) {
|
||||
UUID motherUUID = mother.getUniqueId();
|
||||
UUID fatherUUID = father.getUniqueId();
|
||||
|
||||
addTask(() -> {
|
||||
breedingEntities.remove(motherUUID);
|
||||
breedingEntities.remove(fatherUUID);
|
||||
}, 20L * 1000L);
|
||||
|
||||
breedingEntities.add(motherUUID);
|
||||
inLoveEntities.remove(motherUUID);
|
||||
breedingEntities.add(fatherUUID);
|
||||
inLoveEntities.remove(fatherUUID);
|
||||
}
|
||||
|
||||
public void addInLoveTicket(LivingEntity entity) {
|
||||
UUID entityUUID = entity.getUniqueId();
|
||||
addTask(() -> inLoveEntities.remove(entityUUID), 5L * 60L * 1000L);
|
||||
inLoveEntities.add(entityUUID);
|
||||
}
|
||||
|
||||
public boolean isInQueue(UUID uniqueId) {
|
||||
return breedingEntities.contains(uniqueId) || inLoveEntities.contains(uniqueId);
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@ package com.craftaro.ultimatestacker.tasks;
|
||||
|
||||
import com.craftaro.core.compatibility.ServerVersion;
|
||||
import com.craftaro.core.hooks.WorldGuardHook;
|
||||
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
|
||||
import com.craftaro.core.world.SWorld;
|
||||
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStackManager;
|
||||
@ -11,64 +11,24 @@ import com.craftaro.ultimatestacker.settings.Settings;
|
||||
import com.craftaro.ultimatestacker.stackable.entity.Check;
|
||||
import com.craftaro.ultimatestacker.stackable.entity.custom.CustomEntity;
|
||||
import com.craftaro.ultimatestacker.utils.CachedChunk;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.AbstractHorse;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Cat;
|
||||
import org.bukkit.entity.ChestedHorse;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Horse;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Llama;
|
||||
import org.bukkit.entity.Ocelot;
|
||||
import org.bukkit.entity.Parrot;
|
||||
import org.bukkit.entity.Phantom;
|
||||
import org.bukkit.entity.Pig;
|
||||
import org.bukkit.entity.PufferFish;
|
||||
import org.bukkit.entity.Rabbit;
|
||||
import org.bukkit.entity.Sheep;
|
||||
import org.bukkit.entity.Skeleton;
|
||||
import org.bukkit.entity.Slime;
|
||||
import org.bukkit.entity.Snowman;
|
||||
import org.bukkit.entity.Tameable;
|
||||
import org.bukkit.entity.TropicalFish;
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.bukkit.entity.Wolf;
|
||||
import org.bukkit.entity.Zombie;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.craftaro.ultimatestacker.stackable.entity.Check.getChecks;
|
||||
|
||||
public class StackingTask extends TimerTask {
|
||||
public class StackingTask extends BukkitRunnable {
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
private final EntityStackManager stackManager;
|
||||
private final BreedingTask breedingTask;
|
||||
|
||||
private final ConfigurationSection configurationSection = UltimateStacker.getInstance().getMobFile();
|
||||
private final List<UUID> processed = new ArrayList<>();
|
||||
@ -77,6 +37,7 @@ public class StackingTask extends TimerTask {
|
||||
private final int maxEntityStackSize = Settings.MAX_STACK_ENTITIES.getInt(),
|
||||
minEntityStackSize = Settings.MIN_STACK_ENTITIES.getInt(),
|
||||
searchRadius = Settings.SEARCH_RADIUS.getInt(),
|
||||
chunkRadius = Settings.STACK_WHOLE_CHUNK_RADIUS.getInt(),
|
||||
maxPerTypeStacksPerChunk = Settings.MAX_PER_TYPE_STACKS_PER_CHUNK.getInt();
|
||||
private final List<String> disabledWorlds = Settings.DISABLED_WORLDS.getStringList(),
|
||||
stackReasons = Settings.STACK_REASONS.getStringList();
|
||||
@ -87,278 +48,259 @@ public class StackingTask extends TimerTask {
|
||||
onlyStackFromSpawners = Settings.ONLY_STACK_FROM_SPAWNERS.getBoolean(),
|
||||
onlyStackOnSurface = Settings.ONLY_STACK_ON_SURFACE.getBoolean();
|
||||
|
||||
Set<SWorld> loadedWorlds = new HashSet<>();
|
||||
private final Set<SWorld> loadedWorlds;
|
||||
|
||||
public StackingTask(UltimateStacker plugin) {
|
||||
this.plugin = plugin;
|
||||
this.stackManager = plugin.getEntityStackManager();
|
||||
stackManager = plugin.getEntityStackManager();
|
||||
breedingTask = plugin.getBreedingTask();
|
||||
|
||||
// Add loaded worlds.
|
||||
for (World world : Bukkit.getWorlds())
|
||||
loadedWorlds = new HashSet<>();
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
//Filter disabled worlds to avoid continuous checks in the stacking loop
|
||||
if (isWorldDisabled(world)) continue;
|
||||
loadedWorlds.add(new SWorld(world));
|
||||
}
|
||||
|
||||
// Start the stacking task.
|
||||
//runTaskTimerAsynchronously(plugin, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt());
|
||||
executorService.scheduleAtFixedRate(this, 0, (Settings.STACK_SEARCH_TICK_SPEED.getInt()*50L), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
executorService.shutdown();
|
||||
int tickRate = Settings.STACK_SEARCH_TICK_SPEED.getInt();
|
||||
runTaskTimer(plugin, tickRate, tickRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//make sure if the task running if any error occurs
|
||||
//Make sure to continue the task if any exception occurs
|
||||
try {
|
||||
// Should entities be stacked?
|
||||
if (!Settings.STACK_ENTITIES.getBoolean()) return;
|
||||
|
||||
// Loop through each world.
|
||||
for (SWorld sWorld : loadedWorlds) {
|
||||
// If world is disabled then continue to the next world.
|
||||
if (isWorldDisabled(sWorld.getWorld())) continue;
|
||||
|
||||
// Get the loaded entities from the current world and reverse them.
|
||||
List<LivingEntity> entities;
|
||||
try {
|
||||
entities = getLivingEntitiesSync(sWorld).get();
|
||||
} catch (ExecutionException | InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
continue;
|
||||
// Get the loaded entities from the current world and reverse them.
|
||||
entities = sWorld.getLivingEntities();
|
||||
|
||||
//Filter non-stackable entities to improve performance on main thread
|
||||
entities.removeIf(this::isEntityNotStackable);
|
||||
|
||||
for (LivingEntity entity : entities) {
|
||||
// Check our WorldGuard flag.
|
||||
Boolean flag = WorldGuardHook.isEnabled() ? WorldGuardHook.getBooleanFlag(entity.getLocation(), "mob-stacking") : null; //Does this work async?
|
||||
if (flag != null && !flag)
|
||||
entities.removeIf(entity1 -> entity1.getUniqueId().equals(entity.getUniqueId()));
|
||||
}
|
||||
Collections.reverse(entities);
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
// Loop through the entities.
|
||||
for (LivingEntity entity : entities) {
|
||||
// Make sure our entity has not already been processed.
|
||||
// Skip it if it has been.
|
||||
if (this.processed.contains(entity.getUniqueId())) continue;
|
||||
// Loop through the entities.
|
||||
for (LivingEntity entity : entities) {
|
||||
// Make sure our entity has not already been processed.
|
||||
// Skip it if it has been.
|
||||
if (processed.contains(entity.getUniqueId())) continue;
|
||||
|
||||
// Check to see if entity is not stackable.
|
||||
if (!isEntityStackable(entity)) {
|
||||
continue;
|
||||
}
|
||||
// Get entity location to pass around as its faster this way.
|
||||
Location location = entity.getLocation();
|
||||
|
||||
// Get entity location to pass around as its faster this way.
|
||||
Location location = entity.getLocation();
|
||||
|
||||
// Process the entity.
|
||||
this.processEntity(entity, sWorld, location);
|
||||
}
|
||||
});
|
||||
// Process the entity.
|
||||
processEntity(entity, location, entities);
|
||||
}
|
||||
}
|
||||
// Clear caches in preparation for the next run.
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
// Make sure we clear the processed list.
|
||||
this.processed.clear();
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
private Future<List<LivingEntity>> getLivingEntitiesSync(SWorld sWorld) {
|
||||
CompletableFuture<List<LivingEntity>> future = new CompletableFuture<>();
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(this.plugin, () -> future.complete(sWorld.getLivingEntities()));
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
private Future<Entity[]> getEntitiesInChunkSync(CachedChunk cachedChunk) {
|
||||
CompletableFuture<Entity[]> future = new CompletableFuture<>();
|
||||
Bukkit.getScheduler().runTask(this.plugin, () -> future.complete(cachedChunk.getEntities()));
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWorldDisabled(World world) {
|
||||
return disabledWorlds.stream().anyMatch(worldStr -> world.getName().equalsIgnoreCase(worldStr));
|
||||
}
|
||||
|
||||
private boolean isEntityStackable(Entity entity) {
|
||||
//Returns true if the entity is not stackable, and it will be removed from the list
|
||||
private boolean isEntityNotStackable(LivingEntity entity) {
|
||||
if (isMaxStack(entity)) return true;
|
||||
|
||||
// Make sure we have the correct entity type and that it is valid.
|
||||
if (!entity.isValid()
|
||||
|| entity instanceof HumanEntity
|
||||
|| entity instanceof ArmorStand
|
||||
|
||||
// Make sure the entity is not in love.
|
||||
|| entity.hasMetadata("inLove")
|
||||
// Or in breeding cooldown.
|
||||
|| entity.hasMetadata("breedCooldown"))
|
||||
return false;
|
||||
// Make sure the entity is not in love or in the breeding queue.
|
||||
|| breedingTask.isInQueue(entity.getUniqueId()))
|
||||
return true;
|
||||
|
||||
if (!configurationSection.getBoolean("Mobs." + entity.getType().name() + ".Enabled")) {
|
||||
return false;
|
||||
}
|
||||
if (!configurationSection.getBoolean("Mobs." + entity.getType().name() + ".Enabled"))
|
||||
return true;
|
||||
|
||||
// Allow spawn if stackreasons are set and match, or if from a spawner
|
||||
// Allow spawn if stack reasons are set and match, or if from a spawner
|
||||
final String spawnReason = entity.hasMetadata("US_REASON") && !entity.getMetadata("US_REASON").isEmpty()
|
||||
? entity.getMetadata("US_REASON").get(0).asString() : null;
|
||||
List<String> stackReasons;
|
||||
if (onlyStackFromSpawners) {
|
||||
// If only stack from spawners is enabled, make sure the entity spawned from a spawner.
|
||||
if (!"SPAWNER".equals(spawnReason))
|
||||
return false;
|
||||
return true;
|
||||
} else if (!(stackReasons = this.stackReasons).isEmpty() && !stackReasons.contains(spawnReason)) {
|
||||
// Only stack if on the list of events to stack
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cast our entity to living entity.
|
||||
LivingEntity livingEntity = (LivingEntity) entity;
|
||||
|
||||
// If only stack on surface is enabled make sure the entity is on a surface then entity is stackable.
|
||||
return !onlyStackOnSurface
|
||||
|| canFly(livingEntity)
|
||||
|| entity.getType().name().equals("SHULKER")
|
||||
|
||||
|| (livingEntity.isOnGround()
|
||||
|| (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|
||||
&& livingEntity.isSwimming()));
|
||||
|
||||
//return !onlyStackOnSurface || canFly(entity) || entity.getType().name().equals("SHULKER") || ((entity).isOnGround() || (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) && (entity).isSwimming()));
|
||||
return onlyStackOnSurface && canFly(entity) && !entity.getType().name().equals("SHULKER") && !entity.isOnGround() && !(ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) && (entity).isSwimming());
|
||||
}
|
||||
|
||||
private void processEntity(LivingEntity baseEntity, SWorld sWorld, Location location) {
|
||||
|
||||
// Check our WorldGuard flag.
|
||||
Boolean flag = WorldGuardHook.isEnabled() ? WorldGuardHook.getBooleanFlag(baseEntity.getLocation(), "mob-stacking") : null;
|
||||
if (flag != null && !flag) {
|
||||
return;
|
||||
}
|
||||
|
||||
private void processEntity(LivingEntity baseEntity, Location location, List<LivingEntity> entities) {
|
||||
// Get the stack from the entity. It should be noted that this value will
|
||||
// be null if our entity is not a stack.
|
||||
EntityStack baseStack = plugin.getEntityStackManager().getStackedEntity(baseEntity);
|
||||
|
||||
// Get the maximum stack size for this entity.
|
||||
int maxEntityStackSize = getEntityStackSize(baseEntity);
|
||||
int maxEntityStackSize = getEntityMaxStackSize(baseEntity);
|
||||
|
||||
// Is this entity stacked?
|
||||
boolean isStack = baseStack != null;
|
||||
|
||||
if (isStack && baseStack.getAmount() == maxEntityStackSize) {
|
||||
// If the stack is already at the max size then we can skip it.
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
// The amount that is stackable.
|
||||
int baseSize = isStack ? baseStack.getAmount() : 1;
|
||||
|
||||
// Attempt to split overstacked entities.
|
||||
// If this is successful, we can return because the entity was processed
|
||||
if (isStack && attemptSplit(baseStack, maxEntityStackSize)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The amount that is stackable.
|
||||
int amountToStack = isStack ? baseStack.getAmount() : 1;
|
||||
|
||||
// Attempt to split our stack. If the split is successful then skip this entity.
|
||||
if (isStack && attemptSplit(baseStack, baseEntity)) return;
|
||||
|
||||
// If this entity is named, a custom entity or disabled then skip it.
|
||||
if (!isStack && (baseEntity.getCustomName() != null
|
||||
&& plugin.getCustomEntityManager().getCustomEntity(baseEntity) == null)
|
||||
|| !configurationSection.getBoolean("Mobs." + baseEntity.getType().name() + ".Enabled")) {
|
||||
// If this entity is named or a custom entity skip it.
|
||||
if (!isStack && (baseEntity.getCustomName() != null && plugin.getCustomEntityManager().getCustomEntity(baseEntity) != null)) {
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
// Get similar entities around our entity and make sure those entities are both compatible and stackable.
|
||||
List<LivingEntity> stackableFriends = new LinkedList<>();
|
||||
List<LivingEntity> list = getSimilarEntitiesAroundEntity(baseEntity, sWorld, location);
|
||||
for (LivingEntity entity : list) {
|
||||
// Check to see if entity is not stackable.
|
||||
if (!isEntityStackable(entity))
|
||||
continue;
|
||||
// Add this entity to our stackable friends.
|
||||
stackableFriends.add(entity);
|
||||
}
|
||||
List<LivingEntity> stackableFriends = getSimilarEntitiesAroundEntity(baseEntity, location);
|
||||
|
||||
//Total entities that can be stacked into the base entity
|
||||
int maxStackable = maxEntityStackSize - baseSize;
|
||||
int toStack = 0;
|
||||
List<LivingEntity> remove = new ArrayList<>();
|
||||
|
||||
// Loop through our similar stackable entities.
|
||||
for (LivingEntity friendlyEntity : stackableFriends) {
|
||||
// Make sure the friendlyEntity has not already been processed.
|
||||
if (this.processed.contains(friendlyEntity.getUniqueId())) continue;
|
||||
|
||||
// Get this entities friendStack.
|
||||
if (!entities.contains(friendlyEntity))
|
||||
continue;
|
||||
|
||||
// Process similar entities.
|
||||
EntityStack friendStack = stackManager.getStackedEntity(friendlyEntity);
|
||||
int amount = friendStack != null ? friendStack.getAmount() : 1;
|
||||
|
||||
// Check to see if this friendlyEntity is stacked and friendStack plus
|
||||
// our amount to stack is not above our max friendStack size
|
||||
// for this friendlyEntity.
|
||||
|
||||
boolean overstack = (amount + amountToStack) > maxEntityStackSize;
|
||||
|
||||
if (!overstack) {
|
||||
stackManager.createStackedEntity(friendlyEntity, amount + amountToStack);
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
if (baseEntity.isLeashed()) {
|
||||
baseEntity.getWorld().dropItemNaturally(baseEntity.getLocation(), XMaterial.LEAD.parseItem());
|
||||
}
|
||||
baseEntity.remove();
|
||||
});
|
||||
return;
|
||||
if (toStack + amount <= maxStackable) {
|
||||
toStack += amount;
|
||||
remove.add(friendlyEntity);
|
||||
continue;
|
||||
}
|
||||
break; //We max, exit loop
|
||||
}
|
||||
|
||||
//Nothing to stack
|
||||
if (toStack == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Add to base stack and remove stacked friends
|
||||
stackManager.createStackedEntity(baseEntity, baseSize + toStack);
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
|
||||
//Remove merged entities
|
||||
//We in sync, so we can remove entities
|
||||
for (LivingEntity entity : remove) {
|
||||
processed.add(entity.getUniqueId());
|
||||
entity.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean attemptSplit(EntityStack baseStack, LivingEntity livingEntity) {
|
||||
/**
|
||||
* This method splitting overstacked entities into new stacks.
|
||||
* Must be called synchronously.
|
||||
*
|
||||
* @param baseStack The base stack to check for splitting.
|
||||
* @param maxEntityStackSize The maximum stack size for the entity. -1 if we need to calculate it.
|
||||
* @return True if the split was successful, false otherwise.
|
||||
*/
|
||||
public boolean attemptSplit(EntityStack baseStack, int maxEntityStackSize) {
|
||||
LivingEntity hostEntity = baseStack.getHostEntity();
|
||||
int stackSize = baseStack.getAmount();
|
||||
int maxEntityStackAmount = getEntityStackSize(livingEntity);
|
||||
int maxEntityStackAmount = maxEntityStackSize == -1 ? getEntityMaxStackSize(hostEntity) : maxEntityStackSize;
|
||||
|
||||
if (stackSize <= maxEntityStackAmount) return false;
|
||||
|
||||
baseStack.setAmount(maxEntityStackAmount);
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
int finalStackSize = stackSize - maxEntityStackAmount;
|
||||
do {
|
||||
// Create a new stack, summon entity and add to stack.
|
||||
LivingEntity newEntity = (LivingEntity) livingEntity.getWorld().spawnEntity(livingEntity.getLocation(), livingEntity.getType());
|
||||
int toAdd = Math.min(finalStackSize, maxEntityStackAmount);
|
||||
EntityStack newStack = stackManager.createStackedEntity(newEntity, toAdd);
|
||||
processed.add(newEntity.getUniqueId());
|
||||
finalStackSize -= maxEntityStackAmount;
|
||||
} while (finalStackSize >= 0);
|
||||
});
|
||||
int finalStackSize = stackSize - maxEntityStackAmount;
|
||||
do {
|
||||
// Create a new stack, summon entity and add to stack.
|
||||
LivingEntity newEntity = (LivingEntity) hostEntity.getWorld().spawnEntity(hostEntity.getLocation(), hostEntity.getType());
|
||||
int toAdd = Math.min(finalStackSize, maxEntityStackAmount);
|
||||
EntityStack newStack = stackManager.createStackedEntity(newEntity, toAdd);
|
||||
processed.add(newEntity.getUniqueId());
|
||||
finalStackSize -= maxEntityStackAmount;
|
||||
} while (finalStackSize >= 0);
|
||||
|
||||
//Mark it as processed.
|
||||
processed.add(livingEntity.getUniqueId());
|
||||
processed.add(hostEntity.getUniqueId());
|
||||
return true;
|
||||
}
|
||||
|
||||
private Set<CachedChunk> getNearbyChunks(SWorld sWorld, Location location, double radius, boolean singleChunk) {
|
||||
//get current chunk
|
||||
if (radius == -1) {
|
||||
return new HashSet<>(Collections.singletonList(new CachedChunk(sWorld, location.getChunk().getX(), location.getChunk().getZ())));
|
||||
private Set<CachedChunk> getNearbyChunks(SWorld sWorld, Location location) {
|
||||
//Only stack entities in the same chunk
|
||||
if (stackWholeChunk && chunkRadius == 0) {
|
||||
return Collections.singleton(new CachedChunk(sWorld, location.getChunk().getX(), location.getChunk().getZ()));
|
||||
}
|
||||
World world = location.getWorld();
|
||||
Set<CachedChunk> chunks = new HashSet<>();
|
||||
if (world == null) return chunks;
|
||||
if (world == null) return new HashSet<>();
|
||||
|
||||
CachedChunk firstChunk = new CachedChunk(sWorld, location);
|
||||
Set<CachedChunk> chunks = new TreeSet<>(Comparator.comparingInt(CachedChunk::getX).thenComparingInt(CachedChunk::getZ));
|
||||
chunks.add(firstChunk);
|
||||
|
||||
if (singleChunk) return chunks;
|
||||
|
||||
int minX = (int) Math.floor(((location.getX() - radius) - 2.0D) / 16.0D);
|
||||
int maxX = (int) Math.floor(((location.getX() + radius) + 2.0D) / 16.0D);
|
||||
int minZ = (int) Math.floor(((location.getZ() - radius) - 2.0D) / 16.0D);
|
||||
int maxZ = (int) Math.floor(((location.getZ() + radius) + 2.0D) / 16.0D);
|
||||
//Calculate chunk coordinates we need to check
|
||||
int minX = (int) Math.floor((location.getX() - chunkRadius) / 16.0D);
|
||||
int maxX = (int) Math.floor((location.getX() + chunkRadius) / 16.0D);
|
||||
int minZ = (int) Math.floor((location.getZ() - chunkRadius) / 16.0D);
|
||||
int maxZ = (int) Math.floor((location.getZ() + chunkRadius) / 16.0D);
|
||||
|
||||
for (int x = minX; x <= maxX; ++x) {
|
||||
for (int z = minZ; z <= maxZ; ++z) {
|
||||
if (firstChunk.getX() == x && firstChunk.getZ() == z) continue;
|
||||
chunks.add(new CachedChunk(sWorld, x, z));
|
||||
if (x == minX || x == maxX || z == minZ || z == maxZ) {
|
||||
chunks.add(new CachedChunk(sWorld, x, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Set a bedrock in the top left corner of the chunks
|
||||
for (CachedChunk chunk : chunks) {
|
||||
int x = chunk.getX() * 16;
|
||||
int z = chunk.getZ() * 16;
|
||||
world.getBlockAt(x, 319, z).setType(XMaterial.BEDROCK.parseMaterial());
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all entities around an entity within a radius which are similar to the entity.
|
||||
*
|
||||
* @param entity The entity to get similar entities around.
|
||||
* @param radius The radius to get entities around.
|
||||
* @param singleChunk Whether to only get entities in the same chunk as the entity.
|
||||
* @return A list of similar entities around the entity.
|
||||
*/
|
||||
private List<LivingEntity> getFriendlyStacksNearby(LivingEntity entity, double radius, boolean singleChunk) {
|
||||
public List<LivingEntity> getFriendlyStacksNearby(LivingEntity entity) {
|
||||
if (!stackWholeChunk) {
|
||||
return entity.getNearbyEntities(searchRadius / 2.0, searchRadius / 2.0, searchRadius / 2.0)
|
||||
.stream().filter(e -> e.getType() == entity.getType() && !isMaxStack((LivingEntity) e))
|
||||
.map(e -> (LivingEntity) e).collect(Collectors.toList());
|
||||
}
|
||||
List<LivingEntity> entities = new ArrayList<>();
|
||||
try {
|
||||
Set<CachedChunk> chunks = getNearbyChunks(new SWorld(entity.getWorld()), entity.getLocation(), radius, singleChunk);
|
||||
Set<CachedChunk> chunks = getNearbyChunks(new SWorld(entity.getWorld()), entity.getLocation());
|
||||
for (CachedChunk chunk : chunks) {
|
||||
Entity[] entityList = chunk.getEntities();
|
||||
for (Entity e : entityList) {
|
||||
if (!processed.contains(e.getUniqueId()) && e.getType() == entity.getType() && e instanceof LivingEntity && e.isValid() && e.getLocation().distance(entity.getLocation()) <= radius) {
|
||||
if (e.getType() == entity.getType() && !isMaxStack((LivingEntity) e)) {
|
||||
entities.add((LivingEntity) e);
|
||||
}
|
||||
}
|
||||
@ -370,10 +312,10 @@ public class StackingTask extends TimerTask {
|
||||
return entities;
|
||||
}
|
||||
|
||||
public List<LivingEntity> getSimilarEntitiesAroundEntity(LivingEntity initialEntity, SWorld sWorld, Location location) {
|
||||
public List<LivingEntity> getSimilarEntitiesAroundEntity(LivingEntity initialEntity, Location location) {
|
||||
try {
|
||||
// Create a list of all entities around the initial entity of the same type.
|
||||
List<LivingEntity> entityList = new LinkedList<>(getFriendlyStacksNearby(initialEntity, searchRadius, stackWholeChunk));
|
||||
List<LivingEntity> entityList = new ArrayList<>(getFriendlyStacksNearby(initialEntity));
|
||||
|
||||
CustomEntity customEntity = plugin.getCustomEntityManager().getCustomEntity(initialEntity);
|
||||
if (customEntity != null)
|
||||
@ -616,6 +558,64 @@ public class StackingTask extends TimerTask {
|
||||
entityList.removeIf(entity -> ((Phantom) entity).getSize() != phantom.getSize());
|
||||
break;
|
||||
}
|
||||
case AXOLOTL_VARIANT: {
|
||||
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_17)
|
||||
|| !(initialEntity instanceof Axolotl)) break;
|
||||
Axolotl axolotl = (Axolotl) initialEntity;
|
||||
entityList.removeIf(entity -> ((Axolotl) entity).getVariant() != axolotl.getVariant());
|
||||
break;
|
||||
}
|
||||
case GOAT_HAS_HORNS: {
|
||||
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_17)
|
||||
|| !(initialEntity instanceof Goat)) break;
|
||||
Goat goat = (Goat) initialEntity;
|
||||
boolean hasLeftHorn = goat.hasLeftHorn();
|
||||
boolean hasRightHorn = goat.hasRightHorn();
|
||||
entityList.removeIf(entity -> {
|
||||
Goat otherGoat = (Goat) entity;
|
||||
return otherGoat.hasLeftHorn() != hasLeftHorn || otherGoat.hasRightHorn() != hasRightHorn;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case FROG_VARIANT: {
|
||||
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_19)
|
||||
|| !(initialEntity instanceof Frog)) break;
|
||||
Frog frog = (Frog) initialEntity;
|
||||
entityList.removeIf(entity -> ((Frog) entity).getVariant() != frog.getVariant());
|
||||
break;
|
||||
}
|
||||
case TADPOLE_AGE: {
|
||||
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_19)
|
||||
|| !(initialEntity instanceof Tadpole)) break;
|
||||
Tadpole tadpole = (Tadpole) initialEntity;
|
||||
entityList.removeIf(entity -> ((Tadpole) entity).getAge() != tadpole.getAge());
|
||||
break;
|
||||
}
|
||||
case WARDEN_ANGER_LEVEL: {
|
||||
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_19)
|
||||
|| !(initialEntity instanceof Warden)) break;
|
||||
Warden warden = (Warden) initialEntity;
|
||||
entityList.removeIf(entity -> ((Warden) entity).getAnger() != warden.getAnger());
|
||||
break;
|
||||
}
|
||||
case FOX_TYPE: {
|
||||
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)
|
||||
|| !(initialEntity instanceof Fox)) break;
|
||||
Fox fox = (Fox) initialEntity;
|
||||
entityList.removeIf(entity -> ((Fox) entity).getFoxType() != fox.getFoxType());
|
||||
break;
|
||||
}
|
||||
case HOGLIN_IMMUNE: {
|
||||
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)
|
||||
|| !(initialEntity instanceof Hoglin)) break;
|
||||
Hoglin hoglin = (Hoglin) initialEntity;
|
||||
if (hoglin.isImmuneToZombification()) {
|
||||
entityList.removeIf(entity -> !((Hoglin) entity).isImmuneToZombification());
|
||||
} else {
|
||||
entityList.removeIf(entity -> ((Hoglin) entity).isImmuneToZombification());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -641,16 +641,20 @@ public class StackingTask extends TimerTask {
|
||||
|| (equipment.getBoots() != null && equipment.getBoots().getType() != Material.AIR));
|
||||
}
|
||||
|
||||
private int getEntityStackSize(LivingEntity initialEntity) {
|
||||
Integer max = entityStackSizes.get(initialEntity.getType());
|
||||
if (max == null) {
|
||||
max = configurationSection.getInt("Mobs." + initialEntity.getType().name() + ".Max Stack Size");
|
||||
if (max == -1) {
|
||||
max = maxEntityStackSize;
|
||||
private int getEntityMaxStackSize(LivingEntity initialEntity) {
|
||||
return entityStackSizes.computeIfAbsent(initialEntity.getType(), type -> {
|
||||
int maxStackSize = configurationSection.getInt("Mobs." + initialEntity.getType().name() + ".Max Stack Size");
|
||||
if (maxStackSize == -1) {
|
||||
maxStackSize = maxEntityStackSize;
|
||||
}
|
||||
entityStackSizes.put(initialEntity.getType(), max);
|
||||
}
|
||||
return max;
|
||||
return maxStackSize;
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isMaxStack(LivingEntity livingEntity) {
|
||||
EntityStack stack = stackManager.getStackedEntity(livingEntity);
|
||||
if (stack == null) return false;
|
||||
return stack.getAmount() >= getEntityMaxStackSize(livingEntity);
|
||||
}
|
||||
|
||||
public boolean canFly(LivingEntity entity) {
|
||||
|
4
pom.xml
4
pom.xml
@ -7,7 +7,7 @@
|
||||
<groupId>com.craftaro</groupId>
|
||||
<artifactId>UltimateStacker-Parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>3.0.1</version>
|
||||
<version>3.1.2</version>
|
||||
|
||||
<modules>
|
||||
<module>UltimateStacker-API</module>
|
||||
@ -19,7 +19,7 @@
|
||||
<url>https://craftaro.com/marketplace/product/16</url>
|
||||
|
||||
<properties>
|
||||
<craftaro.coreVersion>3.0.0-SNAPSHOT</craftaro.coreVersion>
|
||||
<craftaro.coreVersion>3.0.1-SNAPSHOT</craftaro.coreVersion>
|
||||
|
||||
<maven.compiler.release>8</maven.compiler.release>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
|
Loading…
Reference in New Issue
Block a user