Removed all reflection.

This commit is contained in:
Brianna 2021-06-01 11:10:04 -05:00
parent a6bad531f2
commit 8e4a6c8b1b
5 changed files with 133 additions and 835 deletions

View File

@ -5,6 +5,7 @@ import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.configuration.Config;
import com.songoda.core.nms.NmsManager;
import com.songoda.core.nms.nbt.NBTItem;
import com.songoda.core.utils.EntityUtils;
import com.songoda.epicspawners.EpicSpawners;
import com.songoda.epicspawners.particles.ParticleDensity;
import com.songoda.epicspawners.particles.ParticleEffect;
@ -179,39 +180,9 @@ public class SpawnerManager {
.build();
List<EntityType> entities = new ArrayList<>(Collections.singletonList(type));
List<CompatibleMaterial> spawnBlocks = new ArrayList<>(Collections.singletonList(CompatibleMaterial.AIR));
List<CompatibleMaterial> spawnBlocks;
switch (typeString.toUpperCase()) {
case "PIG":
case "SHEEP":
case "CHICKEN":
case "COW":
case "RABBIT":
case "LLAMA":
case "HORSE":
case "CAT":
spawnBlocks = new ArrayList<>(Collections.singletonList(CompatibleMaterial.GRASS_BLOCK));
break;
case "MUSHROOM_COW":
spawnBlocks = new ArrayList<>(Collections.singletonList(CompatibleMaterial.MYCELIUM));
break;
case "SQUID":
case "ELDER_GUARDIAN":
case "COD":
case "SALMON":
case "PUFFERFISH":
case "TROPICAL_FISH":
spawnBlocks = new ArrayList<>(Collections.singletonList(CompatibleMaterial.WATER));
break;
case "OCELOT":
spawnBlocks = new ArrayList<>(Arrays.asList(CompatibleMaterial.GRASS_BLOCK,
CompatibleMaterial.JUNGLE_LEAVES, CompatibleMaterial.ACACIA_LEAVES,
CompatibleMaterial.BIRCH_LEAVES, CompatibleMaterial.DARK_OAK_LEAVES,
CompatibleMaterial.OAK_LEAVES, CompatibleMaterial.SPRUCE_LEAVES));
break;
default:
break;
}
spawnBlocks = EntityUtils.getSpawnBlocks(type);
SpawnerTierBuilder tierBuilder = new SpawnerTierBuilder(spawnerData)
.setEntities(entities)
@ -329,7 +300,7 @@ public class SpawnerManager {
if (currentSection2.contains("Conditions")) {
String biomeString = currentSection2.getString("Conditions.Biomes");
Set<Biome> biomes;
if (biomeString.toLowerCase().equals("all"))
if (biomeString.toUpperCase().equals("ALL"))
biomes = EnumSet.allOf(Biome.class);
else {
biomes = new HashSet<>();

View File

@ -2,7 +2,6 @@ package com.songoda.epicspawners.spawners.spawner;
import com.google.common.base.Preconditions;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.gui.GuiUtils;
import com.songoda.core.nms.NmsManager;
import com.songoda.core.nms.nbt.NBTItem;
@ -16,8 +15,7 @@ import com.songoda.epicspawners.spawners.condition.SpawnCondition;
import com.songoda.epicspawners.spawners.spawner.option.SpawnOption;
import com.songoda.epicspawners.spawners.spawner.option.SpawnOptionBlock;
import com.songoda.epicspawners.spawners.spawner.option.SpawnOptionCommand;
import com.songoda.epicspawners.spawners.spawner.option.SpawnOptionEntity_1_12;
import com.songoda.epicspawners.spawners.spawner.option.SpawnOptionEntity_1_13;
import com.songoda.epicspawners.spawners.spawner.option.SpawnOptionEntity;
import com.songoda.epicspawners.spawners.spawner.option.SpawnOptionItem;
import com.songoda.epicspawners.utils.CostType;
import org.apache.commons.lang.math.NumberUtils;
@ -81,11 +79,7 @@ public class SpawnerTier {
public void reloadSpawnMethods() {
spawnOptions.clear();
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) {
if (!entities.isEmpty()) spawnOptions.add(new SpawnOptionEntity_1_13(entities));
} else {
if (!entities.isEmpty()) spawnOptions.add(new SpawnOptionEntity_1_12(entities));
}
if (!entities.isEmpty()) spawnOptions.add(new SpawnOptionEntity(entities));
if (!blocks.isEmpty()) spawnOptions.add(new SpawnOptionBlock(blocks));
if (!items.isEmpty()) spawnOptions.add(new SpawnOptionItem(items));
if (!commands.isEmpty()) spawnOptions.add(new SpawnOptionCommand(commands));

View File

@ -0,0 +1,127 @@
package com.songoda.epicspawners.spawners.spawner.option;
import com.songoda.core.math.MathUtils;
import com.songoda.core.utils.EntityUtils;
import com.songoda.epicspawners.EpicSpawners;
import com.songoda.epicspawners.api.events.SpawnerSpawnEvent;
import com.songoda.epicspawners.boost.types.Boosted;
import com.songoda.epicspawners.particles.ParticleType;
import com.songoda.epicspawners.settings.Settings;
import com.songoda.epicspawners.spawners.condition.SpawnCondition;
import com.songoda.epicspawners.spawners.condition.SpawnConditionNearbyEntities;
import com.songoda.epicspawners.spawners.spawner.PlacedSpawner;
import com.songoda.epicspawners.spawners.spawner.SpawnerStack;
import com.songoda.epicspawners.spawners.spawner.SpawnerTier;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.metadata.FixedMetadataValue;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.ThreadLocalRandom;
public class SpawnOptionEntity implements SpawnOption {
private final EntityType[] types;
private final EpicSpawners plugin = EpicSpawners.getInstance();
private static final boolean mcmmo = Bukkit.getPluginManager().isPluginEnabled("mcMMO");
public SpawnOptionEntity(EntityType... types) {
this.types = types;
}
public SpawnOptionEntity(Collection<EntityType> entities) {
this(entities.toArray(new EntityType[0]));
}
@Override
public void spawn(SpawnerTier data, SpawnerStack stack, PlacedSpawner spawner) {
Location location = spawner.getLocation();
location.add(.5, .5, .5);
if (location.getWorld() == null) return;
String[] randomLowHigh = Settings.RANDOM_LOW_HIGH.getString().split(":");
// Get the amount of entities to spawn per spawner in the stack.
int spawnCount = 0;
for (int i = 0; i < stack.getStackSize(); i++) {
int randomAmt = ThreadLocalRandom.current().nextInt(Integer.parseInt(randomLowHigh[0]), Integer.parseInt(randomLowHigh[1]));
String equation = Settings.SPAWNER_SPAWN_EQUATION.getString();
equation = equation.replace("{RAND}", Integer.toString(randomAmt));
equation = equation.replace("{STACK_SIZE}", Integer.toString(stack.getStackSize()));
spawnCount += MathUtils.eval(equation,
"EpicSpawners (Mobs Spawned Per Single Spawn) Equation");
}
// Get the max entities allowed around a spawner.
int maxEntitiesAllowed = 0;
for (SpawnCondition spawnCondition : data.getConditions()) {
if (spawnCondition instanceof SpawnConditionNearbyEntities)
maxEntitiesAllowed = ((SpawnConditionNearbyEntities) spawnCondition).getMax();
}
// Should we skip the max entity amount on first spawn?
if (spawner.getSpawnCount() == 0 && Settings.IGNORE_MAX_ON_FIRST_SPAWN.getBoolean())
maxEntitiesAllowed = Integer.MAX_VALUE;
// Get the amount of entities around the spawner.
int size = SpawnConditionNearbyEntities.getEntitiesAroundSpawner(location, true);
// Calculate the amount of entities to spawn.
spawnCount = Math.min(maxEntitiesAllowed - size, spawnCount) + spawner.getBoosts().stream().mapToInt(Boosted::getAmountBoosted).sum();
ParticleType particleType = data.getEntitySpawnParticle();
int amountSpawned = spawner.spawn(spawnCount,
particleType != ParticleType.NONE ? null : particleType.getEffect(),
new HashSet<>(Arrays.asList(data.getSpawnBlocks())), entity -> {
SpawnerSpawnEvent event = new SpawnerSpawnEvent(entity, spawner);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
entity.remove();
return false;
}
if (data.isSpawnOnFire()) entity.setFireTicks(160);
entity.setMetadata("ESData", new FixedMetadataValue(plugin, data.getSpawnerData().getIdentifyingName()));
entity.setMetadata("ESTier", new FixedMetadataValue(plugin, data.getIdentifyingName()));
if (mcmmo)
entity.setMetadata("mcMMO: Spawned Entity", new FixedMetadataValue(plugin, true));
if (Settings.NO_AI.getBoolean())
EntityUtils.setUnaware(entity);
plugin.getSpawnManager().addUnnaturalSpawn(entity.getUniqueId());
return true;
}, types);
spawner.setSpawnCount(spawner.getSpawnCount() + amountSpawned);
EpicSpawners.getInstance().getDataManager().updateSpawner(spawner);
}
@Override
public SpawnOptionType getType() {
return SpawnOptionType.ENTITY;
}
@Override
public int hashCode() {
return 31 * (types != null ? Arrays.hashCode(types) : 0);
}
@Override
public boolean equals(Object object) {
if (object == this) return true;
if (!(object instanceof SpawnOptionEntity)) return false;
SpawnOptionEntity other = (SpawnOptionEntity) object;
return Arrays.equals(types, other.types);
}
}

View File

@ -1,387 +0,0 @@
package com.songoda.epicspawners.spawners.spawner.option;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.CompatibleParticleHandler;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.utils.EntityUtils;
import com.songoda.epicspawners.EpicSpawners;
import com.songoda.epicspawners.api.events.SpawnerSpawnEvent;
import com.songoda.epicspawners.boost.types.Boosted;
import com.songoda.epicspawners.particles.ParticleType;
import com.songoda.epicspawners.settings.Settings;
import com.songoda.epicspawners.spawners.condition.SpawnCondition;
import com.songoda.epicspawners.spawners.condition.SpawnConditionNearbyEntities;
import com.songoda.epicspawners.spawners.spawner.PlacedSpawner;
import com.songoda.epicspawners.spawners.spawner.SpawnerStack;
import com.songoda.epicspawners.spawners.spawner.SpawnerTier;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.Plugin;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
public class SpawnOptionEntity_1_12 implements SpawnOption {
private final EntityType[] types;
private final ScriptEngine engine;
private final EpicSpawners plugin = EpicSpawners.getInstance();
private boolean useUltimateStacker;
private boolean mcmmo;
private final Map<String, Integer> cache = new HashMap<>();
private Class<?> clazzMobSpawnerData,
clazzCraftWorld,
clazzWorld,
clazzEntity,
clazzEntityInsentient,
clazzBlockPosition;
private Method methodAddEntity,
methodCreateEntityByName,
methodSetPositionRotation,
methodB,
methodSetString,
methodGetHandle,
methodEntityInsentientPrepare,
methodChunkRegionLoaderA,
methodEntityGetBukkitEntity,
methodCraftEntityTeleport,
methodEntityInsentientCanSpawn,
methodChunkRegionLoaderA2,
methodGetDamageScaler;
private Field fieldWorldRandom;
public SpawnOptionEntity_1_12(EntityType... types) {
this.types = types;
this.engine = new ScriptEngineManager(null).getEngineByName("JavaScript");
if (Bukkit.getPluginManager().isPluginEnabled("UltimateStacker")) {
this.useUltimateStacker = ((Plugin) com.songoda.ultimatestacker.UltimateStacker.getInstance()).getConfig().getBoolean("Entities.Enabled");
}
init();
}
public SpawnOptionEntity_1_12(Collection<EntityType> entities) {
this(entities.toArray(new EntityType[0]));
}
private void init() {
try {
String ver = Bukkit.getServer().getClass().getPackage().getName().substring(23);
Class<?> clazzChunkRegionLoader = Class.forName("net.minecraft.server." + ver + ".ChunkRegionLoader");
Class<?> clazzCraftEntity = Class.forName("org.bukkit.craftbukkit." + ver + ".entity.CraftEntity");
Class<?> clazzSpawnReason = Class.forName("org.bukkit.event.entity.CreatureSpawnEvent$SpawnReason");
Class<?> clazzGroupDataEntity = Class.forName("net.minecraft.server." + ver + ".GroupDataEntity");
Class<?> clazzDifficultyDamageScaler = Class.forName("net.minecraft.server." + ver + ".DifficultyDamageScaler");
clazzWorld = Class.forName("net.minecraft.server." + ver + ".World");
clazzEntity = Class.forName("net.minecraft.server." + ver + ".Entity");
clazzCraftWorld = Class.forName("org.bukkit.craftbukkit." + ver + ".CraftWorld");
clazzEntityInsentient = Class.forName("net.minecraft.server." + ver + ".EntityInsentient");
clazzBlockPosition = Class.forName("net.minecraft.server." + ver + ".BlockPosition");
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) {
clazzMobSpawnerData = Class.forName("net.minecraft.server." + ver + ".MobSpawnerData");
Class<?> clazzNBTTagCompound = Class.forName("net.minecraft.server." + ver + ".NBTTagCompound");
methodB = clazzMobSpawnerData.getDeclaredMethod("b");
methodSetString = clazzNBTTagCompound.getDeclaredMethod("setString", String.class, String.class);
methodGetDamageScaler = clazzWorld.getDeclaredMethod("D", clazzBlockPosition);
methodChunkRegionLoaderA = clazzChunkRegionLoader.getDeclaredMethod("a", clazzNBTTagCompound, clazzWorld, double.class, double.class, double.class, boolean.class);
methodChunkRegionLoaderA2 = clazzChunkRegionLoader.getDeclaredMethod("a", clazzEntity, clazzWorld, clazzSpawnReason);
} else {
Class<?> clazzEntityTypes = Class.forName("net.minecraft.server." + ver + ".EntityTypes");
methodCreateEntityByName = clazzEntityTypes.getDeclaredMethod("createEntityByName", String.class, clazzWorld);
methodSetPositionRotation = clazzEntity.getDeclaredMethod("setPositionRotation", double.class, double.class, double.class, float.class, float.class);
methodAddEntity = clazzWorld.getDeclaredMethod("addEntity", clazzEntity, clazzSpawnReason);
methodGetDamageScaler = clazzWorld.getDeclaredMethod("E", clazzBlockPosition);
}
methodGetHandle = clazzCraftWorld.getDeclaredMethod("getHandle");
methodEntityGetBukkitEntity = clazzEntity.getDeclaredMethod("getBukkitEntity");
methodCraftEntityTeleport = clazzCraftEntity.getDeclaredMethod("teleport", Location.class);
methodEntityInsentientCanSpawn = clazzEntityInsentient.getDeclaredMethod("canSpawn");
methodEntityInsentientPrepare = clazzEntityInsentient.getDeclaredMethod("prepare", clazzDifficultyDamageScaler, clazzGroupDataEntity);
fieldWorldRandom = clazzWorld.getDeclaredField("random");
fieldWorldRandom.setAccessible(true);
} catch (NoSuchFieldException | NoSuchMethodException | ClassNotFoundException e) {
e.printStackTrace();
}
this.mcmmo = Bukkit.getPluginManager().isPluginEnabled("mcMMO");
}
@Override
public void spawn(SpawnerTier data, SpawnerStack stack, PlacedSpawner spawner) {
Location location = spawner.getLocation();
location.add(.5, .5, .5);
if (location.getWorld() == null) return;
String[] randomLowHigh = Settings.RANDOM_LOW_HIGH.getString().split(":");
// Get the amount of entities to spawn per spawner in the stack.
int spawnCount = 0;
for (int i = 0; i < stack.getStackSize(); i++) {
int randomAmt = ThreadLocalRandom.current().nextInt(Integer.parseInt(randomLowHigh[0]), Integer.parseInt(randomLowHigh[1]));
String equation = Settings.SPAWNER_SPAWN_EQUATION.getString();
equation = equation.replace("{RAND}", Integer.toString(randomAmt));
equation = equation.replace("{STACK_SIZE}", Integer.toString(stack.getStackSize()));
try {
if (!cache.containsKey(equation)) {
spawnCount += (int) Math.round(Double.parseDouble(engine.eval(equation).toString()));
cache.put(equation, spawnCount);
} else {
spawnCount += cache.get(equation);
}
} catch (ScriptException e) {
System.out.println("Your spawner equation is broken, fix it.");
}
}
// Get the max entities allowed around a spawner.
int maxEntitiesAllowed = 0;
for (SpawnCondition spawnCondition : data.getConditions()) {
if (spawnCondition instanceof SpawnConditionNearbyEntities)
maxEntitiesAllowed = ((SpawnConditionNearbyEntities) spawnCondition).getMax();
}
// Should we skip the max entity amount on first spawn?
if (spawner.getSpawnCount() == 0 && Settings.IGNORE_MAX_ON_FIRST_SPAWN.getBoolean())
maxEntitiesAllowed = Integer.MAX_VALUE;
// Get the amount of entities around the spawner.
int size = SpawnConditionNearbyEntities.getEntitiesAroundSpawner(location, true);
// Calculate the amount of entities to spawn.
spawnCount = Math.min(maxEntitiesAllowed - size, spawnCount) + spawner.getBoosts().stream().mapToInt(Boosted::getAmountBoosted).sum();
// Check to make sure we're not spawning a stack smaller than the minimum stack size.
boolean useUltimateStacker = this.useUltimateStacker && com.songoda.ultimatestacker.settings
.Settings.DISABLED_WORLDS.getStringList().stream()
.noneMatch(worldStr -> location.getWorld().getName().equalsIgnoreCase(worldStr))
&& spawnCount >= com.songoda.ultimatestacker.settings.Settings.MIN_STACK_ENTITIES.getInt();
int spawnCountUsed = useUltimateStacker ? 1 : spawnCount;
while (spawnCountUsed-- > 0) {
EntityType type = types[ThreadLocalRandom.current().nextInt(types.length)];
Entity entity = spawnEntity(type, spawner, data);
if (entity != null) {
// If we're using UltimateStacker and this entity is indeed stackable then spawn a single stack with the desired stack size.
if (useUltimateStacker && com.songoda.ultimatestacker.UltimateStacker.getInstance().getMobFile().getBoolean("Mobs." + entity.getType().name() + ".Enabled"))
com.songoda.ultimatestacker.UltimateStacker.getInstance().getEntityStackManager().addStack((LivingEntity) entity, spawnCount);
spawner.setSpawnCount(spawner.getSpawnCount() + (useUltimateStacker ? spawnCount : 1));
EpicSpawners.getInstance().getDataManager().updateSpawner(spawner);
}
}
}
private Entity spawnEntity(EntityType type, PlacedSpawner spawner, SpawnerTier tier) {
try {
Object objMobSpawnerData = null;
Object objNBTTagCompound;
String typeTranslationUpper = TypeTranslations.getUpperFromType(type);
String typeTranslationLower = TypeTranslations.getLowerFromType(type);
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) {
objMobSpawnerData = clazzMobSpawnerData.newInstance();
objNBTTagCompound = methodB.invoke(objMobSpawnerData);
methodSetString.invoke(objNBTTagCompound, "id", ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11) ? "minecraft:" + typeTranslationLower : typeTranslationUpper);
}
int spawnRange = 4;
for (int i = 0; i < 25; i++) {
Object objCraftWorld = clazzCraftWorld.cast(spawner.getWorld());
objCraftWorld = methodGetHandle.invoke(objCraftWorld);
Object objWorld = clazzWorld.cast(objCraftWorld);
Random random = (Random) fieldWorldRandom.get(objWorld);
double x = (double) spawner.getX() + (random.nextDouble() - random.nextDouble()) * (double) spawnRange + 0.5D;
double y = spawner.getY() + random.nextInt(3) - 1;
double z = (double) spawner.getZ() + (random.nextDouble() - random.nextDouble()) * (double) spawnRange + 0.5D;
Object objEntity;
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) {
objNBTTagCompound = methodB.invoke(objMobSpawnerData);
objEntity = methodChunkRegionLoaderA.invoke(null, objNBTTagCompound, objWorld, x, y, z, false);
} else {
objEntity = methodCreateEntityByName.invoke(null, typeTranslationUpper, objWorld);
methodSetPositionRotation.invoke(objEntity, x, y, z, 360.0F, 0.0F);
}
Object objEntityInsentient = null;
if (clazzEntityInsentient.isInstance(objEntity))
objEntityInsentient = clazzEntityInsentient.cast(objEntity);
Location spot = new Location(spawner.getWorld(), x, y, z);
if (!canSpawn(objEntityInsentient, tier, spot))
continue;
Object objBlockPosition = clazzBlockPosition.getConstructor(clazzEntity).newInstance(objEntity);
Object objDamageScaler = methodGetDamageScaler.invoke(objWorld, objBlockPosition);
methodEntityInsentientPrepare.invoke(objEntity, objDamageScaler, null);
ParticleType particleType = tier.getEntitySpawnParticle();
if (particleType != ParticleType.NONE) {
float xx = (float) (0 + (Math.random() * 1));
float yy = (float) (0 + (Math.random() * 2));
float zz = (float) (0 + (Math.random() * 1));
CompatibleParticleHandler.spawnParticles(CompatibleParticleHandler.ParticleType.getParticle(particleType.getEffect()),
spot, 5, xx, yy, zz, 0);
}
Entity craftEntity = (Entity) methodEntityGetBukkitEntity.invoke(objEntity);
SpawnerSpawnEvent event = new SpawnerSpawnEvent(craftEntity, spawner);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
craftEntity.remove();
return null;
}
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) {
methodChunkRegionLoaderA2.invoke(null, objEntity, objWorld, CreatureSpawnEvent.SpawnReason.SPAWNER);
} else {
methodAddEntity.invoke(objWorld, objEntity, CreatureSpawnEvent.SpawnReason.SPAWNER);
}
if (tier.isSpawnOnFire()) craftEntity.setFireTicks(160);
craftEntity.setMetadata("ESData", new FixedMetadataValue(plugin, tier.getSpawnerData().getIdentifyingName()));
craftEntity.setMetadata("ESTier", new FixedMetadataValue(plugin, tier.getIdentifyingName()));
if (mcmmo)
craftEntity.setMetadata("mcMMO: Spawned Entity", new FixedMetadataValue(plugin, true));
if (Settings.NO_AI.getBoolean())
EntityUtils.setUnaware(objEntity);
Object objBukkitEntity = methodEntityGetBukkitEntity.invoke(objEntity);
spot.setYaw(random.nextFloat() * 360.0F);
methodCraftEntityTeleport.invoke(objBukkitEntity, spot);
plugin.getSpawnManager().addUnnaturalSpawn(craftEntity.getUniqueId());
return craftEntity;
}
} catch (IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
private boolean canSpawn(Object objEntityInsentient, SpawnerTier data, Location location) {
try {
if (!(boolean) methodEntityInsentientCanSpawn.invoke(objEntityInsentient))
return false;
CompatibleMaterial[] spawnBlocks = data.getSpawnBlocks();
CompatibleMaterial spawnedIn = CompatibleMaterial.getMaterial(location.getBlock());
CompatibleMaterial spawnedOn = CompatibleMaterial.getMaterial(location.getBlock().getRelative(BlockFace.DOWN));
if (!spawnedIn.isAir()
&& !spawnedIn.isWater()
&& !spawnedIn.name().contains("PRESSURE")
&& !spawnedIn.name().contains("SLAB")) {
return false;
}
for (CompatibleMaterial material : spawnBlocks) {
if (material == null) continue;
if (spawnedOn.equals(material) || material.isAir())
return true;
}
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
return false;
}
public enum TypeTranslations {
VINDICATOR("vindication_illager", "VindicationIllager"),
SNOWMAN("snowman", "SnowMan"),
PIG_ZOMBIE("zombie_pigman", "PigZombie"),
EVOKER("evocation_illager", "EvocationIllager"),
ILLUSIONER("illusion_illager", "IllusionIllager"),
IRON_GOLEM("villager_golem", "VillagerGolem"),
MUSHROOM_COW("mooshroom", "MushroomCow"),
MAGMA_CUBE("magma_cube", "LavaSlime");
private final String lower;
private final String upper;
TypeTranslations(String lower, String upper) {
this.lower = lower;
this.upper = upper;
}
public static String getLowerFromType(EntityType type) {
try {
TypeTranslations typeTranslation = valueOf(type.name());
return typeTranslation.lower;
} catch (Exception e) {
return type.name().toLowerCase();
}
}
public static String getUpperFromType(EntityType type) {
try {
TypeTranslations typeTranslation = valueOf(type.name());
return typeTranslation.upper;
} catch (Exception e) {
return WordUtils.capitalize(type.name().toLowerCase()).replace(" ", "");
}
}
}
@Override
public SpawnOptionType getType() {
return SpawnOptionType.ENTITY;
}
@Override
public int hashCode() {
return 31 * (types != null ? Arrays.hashCode(types) : 0);
}
@Override
public boolean equals(Object object) {
if (object == this) return true;
if (!(object instanceof SpawnOptionEntity_1_12)) return false;
SpawnOptionEntity_1_12 other = (SpawnOptionEntity_1_12) object;
return Arrays.equals(types, other.types);
}
}

View File

@ -1,407 +0,0 @@
package com.songoda.epicspawners.spawners.spawner.option;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.utils.EntityUtils;
import com.songoda.epicspawners.EpicSpawners;
import com.songoda.epicspawners.api.events.SpawnerSpawnEvent;
import com.songoda.epicspawners.boost.types.Boosted;
import com.songoda.epicspawners.particles.ParticleType;
import com.songoda.epicspawners.settings.Settings;
import com.songoda.epicspawners.spawners.condition.SpawnCondition;
import com.songoda.epicspawners.spawners.condition.SpawnConditionNearbyEntities;
import com.songoda.epicspawners.spawners.spawner.PlacedSpawner;
import com.songoda.epicspawners.spawners.spawner.SpawnerStack;
import com.songoda.epicspawners.spawners.spawner.SpawnerTier;
import com.songoda.epicspawners.utils.PaperUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.Plugin;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
public class SpawnOptionEntity_1_13 implements SpawnOption {
private final EntityType[] types;
private final ScriptEngine engine;
private final EpicSpawners plugin = EpicSpawners.getInstance();
private boolean useUltimateStacker;
private Enum<?> SpawnerEnum;
private boolean mcmmo;
private final Map<String, Integer> cache = new HashMap<>();
private Class<?> clazzMobSpawnerData,
clazzWorldServer,
clazzWorldAccess,
clazzGeneratorAccess,
clazzCraftWorld,
clazzWorld,
clazzEntity,
clazzEntityInsentient,
clazzBlockPosition,
clazzIWorldReader,
clazzICollisionAccess;
private Method methodGetEntity,
methodGetChunkCoordinates,
methodSetString,
methodSetPosition,
methodA,
methodAddEntity,
methodGetHandle,
methodChunkRegionLoaderA,
methodEntityGetBukkitEntity,
methodCraftEntityTeleport,
methodEntityInsentientPrepare,
methodChunkRegionLoaderA2,
methodGetDamageScaler,
methodGetCubes,
methodGetBoundingBox;
private Field fieldWorldRandom,
fieldSpawnReason;
public SpawnOptionEntity_1_13(EntityType... types) {
this.types = types;
this.engine = new ScriptEngineManager(null).getEngineByName("JavaScript");
if (Bukkit.getPluginManager().isPluginEnabled("UltimateStacker")) {
this.useUltimateStacker = ((Plugin) com.songoda.ultimatestacker.UltimateStacker.getInstance()).getConfig().getBoolean("Entities.Enabled");
}
init();
}
public SpawnOptionEntity_1_13(Collection<EntityType> entities) {
this(entities.toArray(new EntityType[0]));
}
private void init() {
try {
String ver = Bukkit.getServer().getClass().getPackage().getName().substring(23);
Class<?> clazzNBTTagCompound = Class.forName("net.minecraft.server." + ver + ".NBTTagCompound"),
clazzChunkRegionLoader = Class.forName("net.minecraft.server." + ver + ".ChunkRegionLoader"),
clazzCraftEntity = Class.forName("org.bukkit.craftbukkit." + ver + ".entity.CraftEntity"),
clazzGroupDataEntity = Class.forName("net.minecraft.server." + ver + ".GroupDataEntity"),
clazzDifficultyDamageScaler = Class.forName("net.minecraft.server." + ver + ".DifficultyDamageScaler"),
clazzAxisAlignedBB = Class.forName("net.minecraft.server." + ver + ".AxisAlignedBB"),
clazzEntityTypes = Class.forName("net.minecraft.server." + ver + ".EntityTypes");
clazzMobSpawnerData = Class.forName("net.minecraft.server." + ver + ".MobSpawnerData");
clazzCraftWorld = Class.forName("org.bukkit.craftbukkit." + ver + ".CraftWorld");
clazzWorld = Class.forName("net.minecraft.server." + ver + ".World");
clazzEntity = Class.forName("net.minecraft.server." + ver + ".Entity");
clazzEntityInsentient = Class.forName("net.minecraft.server." + ver + ".EntityInsentient");
clazzBlockPosition = Class.forName("net.minecraft.server." + ver + ".BlockPosition");
clazzIWorldReader = Class.forName("net.minecraft.server." + ver + ".IWorldReader");
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16))
methodGetChunkCoordinates = clazzEntity.getMethod("getChunkCoordinates");
try {
clazzICollisionAccess = Class.forName("net.minecraft.server." + ver + ".ICollisionAccess");
methodGetCubes = clazzICollisionAccess.getDeclaredMethod("getCubes", clazzEntity, clazzAxisAlignedBB);
} catch (ClassNotFoundException e) {
clazzIWorldReader = Class.forName("net.minecraft.server." + ver + ".IWorldReader");
methodGetCubes = clazzIWorldReader.getDeclaredMethod("getCubes", clazzEntity, clazzAxisAlignedBB);
}
if (ServerVersion.isServerVersionBelow(ServerVersion.V1_16)
|| ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16) && ver.equals("v1_16_R1"))
clazzGeneratorAccess = Class.forName("net.minecraft.server." + ver + ".GeneratorAccess");
else
clazzWorldAccess = Class.forName("net.minecraft.server." + ver + ".WorldAccess");
try {
methodGetEntity = clazzMobSpawnerData.getDeclaredMethod("getEntity");
} catch (NoSuchMethodException e) {
methodGetEntity = clazzMobSpawnerData.getDeclaredMethod("b");
}
methodSetString = clazzNBTTagCompound.getDeclaredMethod("setString", String.class, String.class);
methodGetBoundingBox = clazzEntity.getDeclaredMethod("getBoundingBox");
methodSetPosition = clazzEntity.getDeclaredMethod("setPosition", double.class, double.class, double.class);
methodGetHandle = clazzCraftWorld.getDeclaredMethod("getHandle");
try {
methodChunkRegionLoaderA = clazzChunkRegionLoader.getDeclaredMethod("a", clazzNBTTagCompound, clazzWorld, double.class, double.class, double.class, boolean.class);
methodEntityInsentientPrepare = clazzEntityInsentient.getDeclaredMethod("prepare", clazzDifficultyDamageScaler, clazzGroupDataEntity, clazzNBTTagCompound);
methodChunkRegionLoaderA2 = clazzChunkRegionLoader.getDeclaredMethod("a", clazzEntity, clazzGeneratorAccess, Class.forName("org.bukkit.event.entity.CreatureSpawnEvent$SpawnReason"));
} catch (NoSuchMethodException e) {
methodA = clazzEntityTypes.getDeclaredMethod("a", clazzNBTTagCompound, clazzWorld);
Class<?> clazzEnumMobSpawn = Class.forName("net.minecraft.server." + ver + ".EnumMobSpawn");
for (Object enumValue : clazzEnumMobSpawn.getEnumConstants()) {
Enum<?> mobSpawnEnum = (Enum<?>) enumValue;
if (mobSpawnEnum.name().equals("SPAWNER")) {
this.SpawnerEnum = mobSpawnEnum;
break;
}
}
clazzWorldServer = Class.forName("net.minecraft.server." + ver + ".WorldServer");
methodEntityInsentientPrepare = clazzEntityInsentient.getDeclaredMethod("prepare", clazzGeneratorAccess == null ? clazzWorldAccess : clazzGeneratorAccess, clazzDifficultyDamageScaler, clazzEnumMobSpawn, clazzGroupDataEntity, clazzNBTTagCompound);
methodAddEntity = clazzWorldServer.getDeclaredMethod("addEntity", clazzEntity, Class.forName("org.bukkit.event.entity.CreatureSpawnEvent$SpawnReason"));
}
methodEntityGetBukkitEntity = clazzEntity.getDeclaredMethod("getBukkitEntity");
methodCraftEntityTeleport = clazzCraftEntity.getDeclaredMethod("teleport", Location.class);
methodGetDamageScaler = clazzWorld.getDeclaredMethod("getDamageScaler", clazzBlockPosition);
fieldWorldRandom = clazzWorld.getDeclaredField("random");
fieldWorldRandom.setAccessible(true);
if (PaperUtils.isPaper()) {
fieldSpawnReason = clazzEntity.getDeclaredField("spawnReason");
}
} catch (NoSuchFieldException | NoSuchMethodException | ClassNotFoundException e) {
e.printStackTrace();
}
this.mcmmo = Bukkit.getPluginManager().isPluginEnabled("mcMMO");
}
@Override
public void spawn(SpawnerTier data, SpawnerStack stack, PlacedSpawner spawner) {
Location location = spawner.getLocation();
location.add(.5, .5, .5);
if (location.getWorld() == null) return;
String[] randomLowHigh = Settings.RANDOM_LOW_HIGH.getString().split(":");
// Get the amount of entities to spawn per spawner in the stack.
int spawnCount = 0;
for (int i = 0; i < stack.getStackSize(); i++) {
int randomAmt = ThreadLocalRandom.current().nextInt(Integer.parseInt(randomLowHigh[0]), Integer.parseInt(randomLowHigh[1]));
String equation = Settings.SPAWNER_SPAWN_EQUATION.getString();
equation = equation.replace("{RAND}", Integer.toString(randomAmt));
equation = equation.replace("{STACK_SIZE}", Integer.toString(stack.getStackSize()));
try {
if (!cache.containsKey(equation)) {
spawnCount += (int) Math.round(Double.parseDouble(engine.eval(equation).toString()));
cache.put(equation, spawnCount);
} else {
spawnCount += cache.get(equation);
}
} catch (ScriptException e) {
System.out.println("Your spawner equation is broken, fix it.");
}
}
// Get the max entities allowed around a spawner.
int maxEntitiesAllowed = 0;
for (SpawnCondition spawnCondition : data.getConditions()) {
if (spawnCondition instanceof SpawnConditionNearbyEntities)
maxEntitiesAllowed = ((SpawnConditionNearbyEntities) spawnCondition).getMax();
}
// Should we skip the max entity amount on first spawn?
if (spawner.getSpawnCount() == 0 && Settings.IGNORE_MAX_ON_FIRST_SPAWN.getBoolean())
maxEntitiesAllowed = Integer.MAX_VALUE;
// Get the amount of entities around the spawner.
int size = SpawnConditionNearbyEntities.getEntitiesAroundSpawner(location, true);
// Calculate the amount of entities to spawn.
spawnCount = Math.min(maxEntitiesAllowed - size, spawnCount) + spawner.getBoosts().stream().mapToInt(Boosted::getAmountBoosted).sum();
// Check to make sure we're not spawning a stack smaller than the minimum stack size.
boolean useUltimateStacker = this.useUltimateStacker && com.songoda.ultimatestacker.settings
.Settings.DISABLED_WORLDS.getStringList().stream()
.noneMatch(worldStr -> location.getWorld().getName().equalsIgnoreCase(worldStr))
&& spawnCount >= com.songoda.ultimatestacker.settings.Settings.MIN_STACK_ENTITIES.getInt();
int spawnCountUsed = useUltimateStacker ? 1 : spawnCount;
while (spawnCountUsed-- > 0) {
EntityType type = types[ThreadLocalRandom.current().nextInt(types.length)];
Entity entity = spawnEntity(type, spawner, data);
if (entity != null) {
// If we're using UltimateStacker and this entity is indeed stackable then spawn a single stack with the desired stack size.
if (useUltimateStacker && com.songoda.ultimatestacker.UltimateStacker.getInstance().getMobFile().getBoolean("Mobs." + entity.getType().name() + ".Enabled"))
com.songoda.ultimatestacker.UltimateStacker.getInstance().getEntityStackManager().addStack((LivingEntity) entity, spawnCount);
spawner.setSpawnCount(spawner.getSpawnCount() + (useUltimateStacker ? spawnCount : 1));
EpicSpawners.getInstance().getDataManager().updateSpawner(spawner);
}
}
}
private Entity spawnEntity(EntityType type, PlacedSpawner spawner, SpawnerTier tier) {
try {
Object objMobSpawnerData = clazzMobSpawnerData.newInstance();
Object objNTBTagCompound = methodGetEntity.invoke(objMobSpawnerData);
String name = type.name().toLowerCase().replace("pig_zombie", "zombie_pigman").replace("snowman", "snow_golem").replace("mushroom_cow", "mooshroom");
methodSetString.invoke(objNTBTagCompound, "id", "minecraft:" + name);
short spawnRange = 4;
for (int i = 0; i < 50; i++) {
Object objNBTTagCompound = methodGetEntity.invoke(objMobSpawnerData);
Object objCraftWorld = clazzCraftWorld.cast(spawner.getWorld());
objCraftWorld = methodGetHandle.invoke(objCraftWorld);
Object objWorld = clazzWorld.cast(objCraftWorld);
Random random = (Random) fieldWorldRandom.get(objWorld);
double x = (double) spawner.getX() + (random.nextDouble() - random.nextDouble()) * (double) spawnRange + 0.5D;
double y = spawner.getY() + random.nextInt(3) - 1;
double z = (double) spawner.getZ() + (random.nextDouble() - random.nextDouble()) * (double) spawnRange + 0.5D;
Object objEntity;
if (methodChunkRegionLoaderA != null) {
objEntity = methodChunkRegionLoaderA.invoke(null, objNBTTagCompound, objWorld, x, y, z, false);
} else {
Optional optional = (Optional) methodA.invoke(null, objNBTTagCompound, objWorld);
if (!optional.isPresent()) continue;
objEntity = optional.get();
methodSetPosition.invoke(objEntity, x, y, z);
}
Object objBlockPosition;
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16))
objBlockPosition = methodGetChunkCoordinates.invoke(objEntity);
else
objBlockPosition = clazzBlockPosition.getConstructor(clazzEntity).newInstance(objEntity);
Object objDamageScaler = methodGetDamageScaler.invoke(objWorld, objBlockPosition);
Object objEntityInsentient = clazzEntityInsentient.isInstance(objEntity) ? clazzEntityInsentient.cast(objEntity) : null;
Location spot = new Location(spawner.getWorld(), x, y, z);
if (!canSpawn(objWorld, objEntityInsentient, tier, spot))
continue;
if (methodChunkRegionLoaderA != null) {
methodEntityInsentientPrepare.invoke(objEntity, objDamageScaler, null, null);
} else {
methodEntityInsentientPrepare.invoke(objEntity, objWorld, objDamageScaler, SpawnerEnum, null, null);
}
Entity craftEntity = (Entity) methodEntityGetBukkitEntity.invoke(objEntity);
SpawnerSpawnEvent event = new SpawnerSpawnEvent(craftEntity, spawner);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
craftEntity.remove();
return null;
}
ParticleType particleType = tier.getEntitySpawnParticle();
if (particleType != ParticleType.NONE) {
float xx = (float) (0 + (Math.random() * 1));
float yy = (float) (0 + (Math.random() * 2));
float zz = (float) (0 + (Math.random() * 1));
spot.getWorld().spawnParticle(Particle.valueOf(particleType.getEffect()), spot, 5, xx, yy, zz, 0);
}
if (methodChunkRegionLoaderA != null) {
methodChunkRegionLoaderA2.invoke(null, objEntity, objWorld, CreatureSpawnEvent.SpawnReason.SPAWNER);
} else {
methodAddEntity.invoke(clazzWorldServer.cast(objWorld), objEntity, CreatureSpawnEvent.SpawnReason.SPAWNER);
}
if (fieldSpawnReason != null) {
fieldSpawnReason.set(objEntity, CreatureSpawnEvent.SpawnReason.SPAWNER);
}
if (tier.isSpawnOnFire()) craftEntity.setFireTicks(160);
craftEntity.setMetadata("ESData", new FixedMetadataValue(plugin, tier.getSpawnerData().getIdentifyingName()));
craftEntity.setMetadata("ESTier", new FixedMetadataValue(plugin, tier.getIdentifyingName()));
if (mcmmo)
craftEntity.setMetadata("mcMMO: Spawned Entity", new FixedMetadataValue(plugin, true));
if (Settings.NO_AI.getBoolean())
EntityUtils.setUnaware(objEntity);
Object objBukkitEntity = methodEntityGetBukkitEntity.invoke(objEntity);
spot.setYaw(random.nextFloat() * 360.0F);
methodCraftEntityTeleport.invoke(objBukkitEntity, spot);
plugin.getSpawnManager().addUnnaturalSpawn(craftEntity.getUniqueId());
return craftEntity;
}
} catch (IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
private boolean canSpawn(Object objWorld, Object objEntityInsentient, SpawnerTier data, Location location) {
try {
Object objIWR = clazzIWorldReader == null ? clazzICollisionAccess.cast(objWorld) : clazzIWorldReader.cast(objWorld);
if (!(boolean) methodGetCubes.invoke(objIWR, objEntityInsentient, methodGetBoundingBox.invoke(objEntityInsentient)))
return false;
CompatibleMaterial[] spawnBlocks = data.getSpawnBlocks();
CompatibleMaterial spawnedIn = CompatibleMaterial.getMaterial(location.getBlock());
CompatibleMaterial spawnedOn = CompatibleMaterial.getMaterial(location.getBlock().getRelative(BlockFace.DOWN));
if (!spawnedIn.isAir()
&& !spawnedIn.isWater()
&& !spawnedIn.name().contains("PRESSURE")
&& !spawnedIn.name().contains("SLAB")) {
return false;
}
for (CompatibleMaterial material : spawnBlocks) {
if (material == null) continue;
if (spawnedOn.equals(material) || material.isAir())
return true;
}
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
return false;
}
@Override
public SpawnOptionType getType() {
return SpawnOptionType.ENTITY;
}
@Override
public int hashCode() {
return 31 * (types != null ? Arrays.hashCode(types) : 0);
}
@Override
public boolean equals(Object object) {
if (object == this) return true;
if (!(object instanceof SpawnOptionEntity_1_13)) return false;
SpawnOptionEntity_1_13 other = (SpawnOptionEntity_1_13) object;
return Arrays.equals(types, other.types);
}
}