com.skelril.skree.content.world.wilderness.WildernessWorldWrapper.java Source code

Java tutorial

Introduction

Here is the source code for com.skelril.skree.content.world.wilderness.WildernessWorldWrapper.java

Source

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package com.skelril.skree.content.world.wilderness;

import com.flowpowered.math.vector.Vector3d;
import com.google.common.collect.Lists;
import com.skelril.nitro.combat.PlayerCombatParser;
import com.skelril.nitro.data.util.EnchantmentUtil;
import com.skelril.nitro.droptable.DropTable;
import com.skelril.nitro.droptable.DropTableEntryImpl;
import com.skelril.nitro.droptable.DropTableImpl;
import com.skelril.nitro.droptable.MasterDropTable;
import com.skelril.nitro.droptable.resolver.SimpleDropResolver;
import com.skelril.nitro.droptable.roller.SlipperySingleHitDiceRoller;
import com.skelril.nitro.entity.EntityHealthPrinter;
import com.skelril.nitro.item.ItemDropper;
import com.skelril.nitro.item.ItemFountain;
import com.skelril.nitro.numeric.MathExt;
import com.skelril.nitro.probability.Probability;
import com.skelril.nitro.registry.block.DropRegistry;
import com.skelril.nitro.registry.block.MultiTypeRegistry;
import com.skelril.nitro.text.CombinedText;
import com.skelril.nitro.text.PlaceHolderText;
import com.skelril.nitro.time.IntegratedRunnable;
import com.skelril.nitro.time.TimedRunnable;
import com.skelril.skree.SkreePlugin;
import com.skelril.skree.content.droptable.CofferResolver;
import com.skelril.skree.content.modifier.Modifiers;
import com.skelril.skree.content.world.main.MainWorldWrapper;
import com.skelril.skree.service.ModifierService;
import com.skelril.skree.service.PvPService;
import com.skelril.skree.service.WorldService;
import com.skelril.skree.service.internal.world.WorldEffectWrapperImpl;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
import org.apache.commons.lang3.Validate;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockSnapshot;
import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.block.BlockType;
import org.spongepowered.api.block.BlockTypes;
import org.spongepowered.api.data.Transaction;
import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.data.manipulator.mutable.entity.HealthData;
import org.spongepowered.api.data.meta.ItemEnchantment;
import org.spongepowered.api.data.type.HandTypes;
import org.spongepowered.api.data.value.mutable.Value;
import org.spongepowered.api.effect.particle.ParticleEffect;
import org.spongepowered.api.effect.particle.ParticleTypes;
import org.spongepowered.api.effect.sound.SoundTypes;
import org.spongepowered.api.entity.*;
import org.spongepowered.api.entity.explosive.PrimedTNT;
import org.spongepowered.api.entity.living.Living;
import org.spongepowered.api.entity.living.monster.Boss;
import org.spongepowered.api.entity.living.monster.Creeper;
import org.spongepowered.api.entity.living.monster.Monster;
import org.spongepowered.api.entity.living.monster.Wither;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.entity.living.player.gamemode.GameModes;
import org.spongepowered.api.entity.projectile.Egg;
import org.spongepowered.api.entity.projectile.Projectile;
import org.spongepowered.api.entity.projectile.explosive.fireball.Fireball;
import org.spongepowered.api.event.Cancellable;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.block.ChangeBlockEvent;
import org.spongepowered.api.event.cause.Cause;
import org.spongepowered.api.event.cause.NamedCause;
import org.spongepowered.api.event.cause.entity.damage.DamageModifier;
import org.spongepowered.api.event.cause.entity.damage.source.EntityDamageSource;
import org.spongepowered.api.event.cause.entity.damage.source.IndirectEntityDamageSource;
import org.spongepowered.api.event.cause.entity.spawn.BlockSpawnCause;
import org.spongepowered.api.event.cause.entity.spawn.SpawnCause;
import org.spongepowered.api.event.cause.entity.spawn.SpawnTypes;
import org.spongepowered.api.event.entity.CollideEntityEvent;
import org.spongepowered.api.event.entity.DamageEntityEvent;
import org.spongepowered.api.event.entity.DestructEntityEvent;
import org.spongepowered.api.event.entity.SpawnEntityEvent;
import org.spongepowered.api.event.entity.living.humanoid.player.RespawnPlayerEvent;
import org.spongepowered.api.item.Enchantments;
import org.spongepowered.api.item.ItemType;
import org.spongepowered.api.item.inventory.ItemStack;
import org.spongepowered.api.scheduler.Task;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.channel.MessageChannel;
import org.spongepowered.api.text.format.TextColor;
import org.spongepowered.api.text.format.TextColors;
import org.spongepowered.api.text.format.TextStyles;
import org.spongepowered.api.text.title.Title;
import org.spongepowered.api.util.Tuple;
import org.spongepowered.api.world.BlockChangeFlag;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
import org.spongepowered.api.world.biome.BiomeTypes;
import org.spongepowered.api.world.explosion.Explosion;
import org.spongepowered.api.world.extent.Extent;

import javax.annotation.Nullable;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import static com.skelril.nitro.item.ItemStackFactory.newItemStack;
import static com.skelril.nitro.transformer.ForgeTransformer.tf;
import static com.skelril.skree.content.registry.TypeCollections.ore;
import static com.skelril.skree.content.registry.block.CustomBlockTypes.GRAVE_STONE;
import static com.skelril.skree.content.registry.item.CustomItemTypes.*;
import static java.util.concurrent.TimeUnit.SECONDS;

public class WildernessWorldWrapper extends WorldEffectWrapperImpl implements Runnable {

    private DropTable commonDropTable;
    private DropTable netherMobDropTable;

    private Map<UUID, WildernessPlayerMeta> playerMetaMap = new HashMap<>();

    public WildernessWorldWrapper() {
        this(new ArrayList<>());
    }

    public WildernessWorldWrapper(Collection<World> worlds) {
        super("Wilderness", worlds);

        SlipperySingleHitDiceRoller slipRoller = new SlipperySingleHitDiceRoller((a, b) -> (int) (a + b));
        commonDropTable = new MasterDropTable(
                slipRoller, Lists
                        .newArrayList(
                                new DropTableImpl(slipRoller, Lists.newArrayList(
                                        new DropTableEntryImpl(new CofferResolver(50), 12))),
                                new DropTableImpl(
                                        slipRoller, Lists
                                                .newArrayList(
                                                        new DropTableEntryImpl(
                                                                new SimpleDropResolver(
                                                                        Lists.newArrayList(newItemStack(
                                                                                (ItemType) SCROLL_OF_SUMMATION))),
                                                                2000),
                                                        new DropTableEntryImpl(
                                                                new SimpleDropResolver(Lists.newArrayList(
                                                                        newItemStack((ItemType) TWO_TAILED_SWORD))),
                                                                10000))),
                                new DropTableImpl(slipRoller,
                                        Lists.newArrayList(new DropTableEntryImpl(
                                                new SimpleDropResolver(
                                                        Lists.newArrayList(newItemStack((ItemType) RED_FEATHER))),
                                                100000)))));
        netherMobDropTable = new MasterDropTable(
                slipRoller, Lists
                        .newArrayList(commonDropTable,
                                new DropTableImpl(
                                        slipRoller, Lists
                                                .newArrayList(
                                                        new DropTableEntryImpl(
                                                                new SimpleDropResolver(Lists.newArrayList(
                                                                        newItemStack((ItemType) NETHER_BOW))),
                                                                10000),
                                                        new DropTableEntryImpl(
                                                                new SimpleDropResolver(Lists.newArrayList(
                                                                        newItemStack((ItemType) NETHER_BOWL))),
                                                                20000)))));

        Task.builder().execute(this).interval(1, SECONDS).submit(SkreePlugin.inst());
    }

    @Override
    public void addWorld(World world) {
        super.addWorld(world);
        tf(world).setAllowedSpawnTypes(true, true);
    }

    @Listener
    public void onEntitySpawn(SpawnEntityEvent event) {
        List<Entity> entities = event.getEntities();

        Optional<BlockSpawnCause> optBlockCause = event.getCause().first(BlockSpawnCause.class);
        for (Entity entity : entities) {
            Location<World> loc = entity.getLocation();
            Optional<Integer> optLevel = getLevel(loc);

            if (!optLevel.isPresent())
                continue;
            int level = optLevel.get();

            if (entity instanceof Egg && optBlockCause.isPresent()) {
                PrimedTNT explosive = (PrimedTNT) entity.getLocation().getExtent()
                        .createEntity(EntityTypes.PRIMED_TNT, entity.getLocation().getPosition());

                explosive.setVelocity(entity.getVelocity());
                // TODO Use Sponge API after 1.9 release w/ Fuse Data merge
                // explosive.offer(Keys.FUSE_DURATION, 20 * 4);
                tf(explosive).setFuse(20 * 4);

                // TODO used to have a 1/4 chance of creating fire
                entity.getLocation().getExtent().spawnEntity(explosive,
                        Cause.source(SpawnCause.builder().type(SpawnTypes.DISPENSE).build()).build());

                event.setCancelled(true);
                return;
            }

            if (level > 1) {
                // TODO move damage modification
                if (entity instanceof Monster) {
                    HealthData healthData = ((Monster) entity).getHealthData();
                    double curMax = healthData.maxHealth().get();

                    if (curMax <= 80) { // TODO do this a better way, but for now it prevents super mobs

                        double newMax = curMax * getHealthMod(level);

                        healthData.set(Keys.MAX_HEALTH, newMax);
                        healthData.set(Keys.HEALTH, newMax);

                        entity.offer(healthData);
                    }
                }
            }

            Optional<Value<Integer>> optExplosiveRadius = Optional.empty();
            // Optional<Value<Integer>> optExplosiveRadius = event.getEntity().getValue(Keys.EXPLOSIVE_RADIUS);

            if (optExplosiveRadius.isPresent()) {
                Value<Integer> explosiveRadius = optExplosiveRadius.get();
                int min = explosiveRadius.get();

                entity.offer(Keys.EXPLOSION_RADIUS,
                        Optional.of(MathExt.bound((min + level) / 2, min, entity instanceof Fireball ? 4 : 9)));
            }
        }
    }

    @Listener
    public void onRespawn(RespawnPlayerEvent event) {
        if (isApplicable(event.getToTransform().getExtent())) {
            Optional<WorldService> optWorldService = Sponge.getServiceManager().provide(WorldService.class);
            if (optWorldService.isPresent()) {
                Collection<World> worlds = optWorldService.get().getEffectWrapper(MainWorldWrapper.class).get()
                        .getWorlds();
                event.setToTransform(new Transform<>(worlds.iterator().next().getSpawnLocation()));
            }
        }
    }

    private final EntityHealthPrinter healthPrinter = new EntityHealthPrinter(
            CombinedText.of(TextColors.DARK_AQUA, "Entity Health: ", new PlaceHolderText("health int"), " / ",
                    new PlaceHolderText("max health int")),
            CombinedText.of(TextColors.GOLD, TextStyles.BOLD, "KO!"));

    private PlayerCombatParser createFor(Cancellable event, int level) {
        return new PlayerCombatParser() {
            @Override
            public void processPvP(Player attacker, Player defender) {
                if (allowsPvP(level)) {
                    return;
                }

                Optional<PvPService> optService = Sponge.getServiceManager().provide(PvPService.class);
                if (optService.isPresent()) {
                    PvPService service = optService.get();
                    if (service.getPvPState(attacker).allowByDefault()
                            && service.getPvPState(defender).allowByDefault()) {
                        return;
                    }
                }

                attacker.sendMessage(Text.of(TextColors.RED, "PvP is opt-in only in this part of the Wilderness!"));
                attacker.sendMessage(
                        Text.of(TextColors.RED, "Mandatory PvP is from level ", getFirstPvPLevel(), " and on."));

                event.setCancelled(true);
            }

            @Override
            public void processMonsterAttack(Living attacker, Player defender) {
                if (!(event instanceof DamageEntityEvent)) {
                    return;
                }

                DamageEntityEvent dEvent = (DamageEntityEvent) event;
                // If they're endermites they hit through armor, otherwise they get a damage boost
                if (attacker.getType() == EntityTypes.ENDERMITE) {
                    for (Tuple<DamageModifier, Function<? super Double, Double>> modifier : dEvent.getModifiers()) {
                        dEvent.setDamage(modifier.getFirst(), (a) -> 0D);
                    }

                    dEvent.setBaseDamage(1);
                } else {
                    dEvent.setBaseDamage(dEvent.getBaseDamage() + getDamageMod(level));
                }

                // Only apply scoring while in survival mode
                if (defender.get(Keys.GAME_MODE).orElse(GameModes.SURVIVAL) != GameModes.SURVIVAL) {
                    return;
                }

                WildernessPlayerMeta meta = playerMetaMap.get(defender.getUniqueId());
                if (meta != null) {
                    meta.hit();
                }
            }

            @Override
            public void processPlayerAttack(Player attacker, Living defender) {
                Task.builder().delayTicks(1)
                        .execute(() -> healthPrinter.print(MessageChannel.fixed(attacker), defender))
                        .submit(SkreePlugin.inst());

                if (!(defender instanceof Monster) || defender instanceof Creeper) {
                    return;
                }

                // Only apply scoring while in survival mode
                if (attacker.get(Keys.GAME_MODE).orElse(GameModes.SURVIVAL) != GameModes.SURVIVAL) {
                    return;
                }

                WildernessPlayerMeta meta = playerMetaMap.get(attacker.getUniqueId());
                if (meta != null) {
                    meta.attack();

                    if (meta.getRatio() > 30 && meta.getFactors() > 35) {
                        Deque<Entity> spawned = new ArrayDeque<>();
                        for (int i = Probability.getRandom(5); i > 0; --i) {
                            Entity entity = attacker.getWorld().createEntity(EntityTypes.ENDERMITE,
                                    defender.getLocation().getPosition());

                            entity.getWorld().spawnEntity(entity,
                                    Cause.source(SpawnCause.builder().type(SpawnTypes.PLUGIN).build()).build());
                            spawned.add(entity);
                        }

                        IntegratedRunnable runnable = new IntegratedRunnable() {
                            @Override
                            public boolean run(int times) {
                                Entity mob = spawned.poll();
                                if (mob.isLoaded() && mob.getWorld().equals(attacker.getWorld())) {
                                    mob.setLocation(attacker.getLocation());
                                }
                                return true;
                            }

                            @Override
                            public void end() {

                            }
                        };

                        TimedRunnable timedRunnable = new TimedRunnable<>(runnable, spawned.size());

                        timedRunnable.setTask(Task.builder().execute(timedRunnable).delayTicks(40).intervalTicks(20)
                                .submit(SkreePlugin.inst()));
                    }

                    if (System.currentTimeMillis() - meta.getLastReset() >= TimeUnit.MINUTES.toMillis(5)) {
                        meta.reset();
                    }
                }
            }
        };
    }

    @Listener
    public void onPlayerCombat(DamageEntityEvent event) {
        Optional<Integer> optLevel = getLevel(event.getTargetEntity().getLocation());
        if (!optLevel.isPresent()) {
            return;
        }

        createFor(event, optLevel.get()).parse(event);
    }

    @Listener
    public void onPlayerCombat(CollideEntityEvent.Impact event) {
        Optional<Projectile> optProjectile = event.getCause().first(Projectile.class);
        if (!optProjectile.isPresent()) {
            return;
        }

        Optional<Integer> optLevel = getLevel(optProjectile.get().getLocation());
        if (!optLevel.isPresent()) {
            return;
        }

        createFor(event, optLevel.get()).parse(event);
    }

    @Listener
    public void onEntityDeath(DestructEntityEvent.Death event) {
        Entity entity = event.getTargetEntity();

        Location<World> loc = entity.getLocation();
        Optional<Integer> optLevel = getLevel(loc);

        if (!optLevel.isPresent()) {
            return;
        }
        int level = optLevel.get();

        if (entity instanceof Monster) {
            DropTable dropTable;

            if (entity.getLocation().getExtent().getBiome(loc.getBlockX(), loc.getBlockZ()) == BiomeTypes.HELL
                    || entity instanceof Wither) {
                dropTable = netherMobDropTable;
            } else {
                dropTable = commonDropTable;
            }

            Optional<EntityDamageSource> optDamageSource = event.getCause().first(EntityDamageSource.class);
            if (optDamageSource.isPresent()) {
                Entity srcEntity;
                if (optDamageSource.isPresent() && optDamageSource.get() instanceof IndirectEntityDamageSource) {
                    srcEntity = ((IndirectEntityDamageSource) optDamageSource.get()).getIndirectSource();
                } else {
                    srcEntity = optDamageSource.get().getSource();
                }

                int dropTier = level;

                if (srcEntity instanceof Player) {
                    Optional<ItemStack> optHeldItem = ((Player) srcEntity).getItemInHand(HandTypes.MAIN_HAND);
                    if (optHeldItem.isPresent()) {
                        Optional<ItemEnchantment> optLooting = EnchantmentUtil
                                .getHighestEnchantment(optHeldItem.get(), Enchantments.LOOTING);

                        if (optLooting.isPresent()) {
                            dropTier += optLooting.get().getLevel();
                        }
                    }

                    dropTier = getDropTier(dropTier);

                    Collection<ItemStack> drops = dropTable.getDrops((entity instanceof Boss ? 5 : 1) * dropTier,
                            getDropMod(dropTier, ((Monster) entity).getHealthData().maxHealth().get(),
                                    entity.getType()));

                    int times = 1;

                    Optional<ModifierService> optService = Sponge.getServiceManager()
                            .provide(ModifierService.class);
                    if (optService.isPresent()) {
                        ModifierService service = optService.get();
                        if (service.isActive(Modifiers.DOUBLE_WILD_DROPS)) {
                            times *= 2;
                        }
                    }

                    ItemDropper dropper = new ItemDropper(loc);
                    for (int i = 0; i < times; ++i) {
                        dropper.dropStacks(drops, SpawnTypes.DROPPED_ITEM);
                    }
                }
            }

            if (entity.getType() == EntityTypes.ENDERMITE && Probability.getChance(20)) {
                entity.getWorld().triggerExplosion(Explosion.builder().location(entity.getLocation())
                        .shouldBreakBlocks(true).radius(4F).build(), Cause.source(SkreePlugin.inst()).build());
            }
        }
        GRAVE_STONE.createGraveFromDeath(event);
    }

    @Listener
    public void onBlockBreak(ChangeBlockEvent.Break event) {
        Optional<Entity> optSrcEnt = event.getCause().get(NamedCause.SOURCE, Entity.class);
        if (!optSrcEnt.isPresent()) {
            return;
        }

        Entity srcEnt = optSrcEnt.get();

        List<Transaction<BlockSnapshot>> transactions = event.getTransactions();
        for (Transaction<BlockSnapshot> block : transactions) {
            BlockSnapshot original = block.getOriginal();
            Optional<Location<World>> optLoc = original.getLocation();

            if (!optLoc.isPresent()) {
                continue;
            }

            Optional<Integer> optLevel = getLevel(optLoc.get());

            if (!optLevel.isPresent()) {
                continue;
            }

            int level = optLevel.get();
            Location<World> loc = optLoc.get();

            BlockState state = original.getState();
            BlockType type = state.getType();
            if (ore().contains(type)) {
                int fortuneMod = 0;
                boolean silkTouch = false;

                if (srcEnt instanceof ArmorEquipable) {
                    Optional<ItemStack> held = ((ArmorEquipable) srcEnt).getItemInHand(HandTypes.MAIN_HAND);
                    if (held.isPresent()) {
                        ItemStack stack = held.get();

                        // TODO Currently abusing NMS to determine "breakability"
                        ItemType itemType = stack.getItem();
                        if (itemType instanceof Item && state instanceof IBlockState) {
                            if (!((Item) stack.getItem()).canHarvestBlock((IBlockState) state)) {
                                continue;
                            }
                        }

                        // Handle fortune
                        Optional<ItemEnchantment> optFortune = EnchantmentUtil.getHighestEnchantment(stack,
                                Enchantments.FORTUNE);
                        if (optFortune.isPresent()) {
                            fortuneMod = optFortune.get().getLevel();
                        }

                        // Handle silk touch
                        Optional<ItemEnchantment> optSilkTouch = EnchantmentUtil.getHighestEnchantment(stack,
                                Enchantments.SILK_TOUCH);
                        if (optSilkTouch.isPresent()) {
                            silkTouch = true;
                        }
                    } else if (srcEnt instanceof Player) {
                        continue;
                    }
                }

                addPool(loc, type, fortuneMod, silkTouch);
            } else if (srcEnt instanceof Player && type.equals(BlockTypes.STONE)
                    && Probability.getChance(Math.max(12, 100 - level))) {
                Vector3d max = loc.getPosition().add(1, 1, 1);
                Vector3d min = loc.getPosition().sub(1, 1, 1);

                Extent world = loc.getExtent();

                if (Probability.getChance(3)) {
                    Entity entity = world.createEntity(EntityTypes.SILVERFISH, loc.getPosition().add(.5, 0, .5));
                    world.spawnEntity(entity,
                            Cause.source(SpawnCause.builder().type(SpawnTypes.BLOCK_SPAWNING).build()).build());
                }

                // Do this one tick later to guarantee no collision with transaction data
                Task.builder().delayTicks(1).execute(() -> {
                    for (int x = min.getFloorX(); x <= max.getFloorX(); ++x) {
                        for (int z = min.getFloorZ(); z <= max.getFloorZ(); ++z) {
                            for (int y = min.getFloorY(); y <= max.getFloorY(); ++y) {
                                if (!world.containsBlock(x, y, z)) {
                                    continue;
                                }

                                if (world.getBlockType(x, y, z) == BlockTypes.STONE) {
                                    world.setBlockType(x, y, z, BlockTypes.MONSTER_EGG, BlockChangeFlag.NONE,
                                            Cause.source(SkreePlugin.container()).build());
                                }
                            }
                        }
                    }
                }).submit(SkreePlugin.inst());
            }
        }
    }

    @Listener
    public void onBlockPlace(ChangeBlockEvent.Place event) {
        Optional<Player> optPlayer = event.getCause().get(NamedCause.SOURCE, Player.class);
        if (optPlayer.isPresent()) {
            Player player = optPlayer.get();

            for (Transaction<BlockSnapshot> block : event.getTransactions()) {
                Optional<Location<World>> optLoc = block.getFinal().getLocation();

                if (!optLoc.isPresent() || !isApplicable(optLoc.get())) {
                    continue;
                }

                Location<World> loc = optLoc.get();
                BlockType finalType = block.getFinal().getState().getType();
                if (ore().contains(finalType)) {
                    // Allow creative mode players to still place blocks
                    if (player.getGameModeData().type().get().equals(GameModes.CREATIVE)) {
                        continue;
                    }

                    BlockType originalType = block.getOriginal().getState().getType();
                    if (ore().contains(originalType)) {
                        continue;
                    }

                    try {
                        Vector3d origin = loc.getPosition();
                        World world = loc.getExtent();
                        for (int i = 0; i < 40; ++i) {
                            ParticleEffect effect = ParticleEffect.builder().type(ParticleTypes.CRIT_MAGIC)
                                    .motion(new Vector3d(Probability.getRangedRandom(-1, 1),
                                            Probability.getRangedRandom(-.7, .7),
                                            Probability.getRangedRandom(-1, 1)))
                                    .count(1).build();

                            world.spawnParticles(effect, origin.add(.5, .5, .5));
                        }
                    } catch (Exception ex) {
                        player.sendMessage(
                                /* ChatTypes.SYSTEM, */
                                Text.of(TextColors.RED, "You find yourself unable to place that block."));
                    }

                    block.setValid(false);
                }
            }
        }
    }

    public Set<Map.Entry<Player, WildernessPlayerMeta>> getMetaInformation() {
        Set<Map.Entry<Player, WildernessPlayerMeta>> resultSets = new HashSet<>();
        for (Map.Entry<UUID, WildernessPlayerMeta> entry : playerMetaMap.entrySet()) {
            Optional<Player> optPlayer = Sponge.getServer().getPlayer(entry.getKey());
            if (!optPlayer.isPresent()) {
                continue;
            }

            Player player = optPlayer.get();
            if (!player.isOnline()) {
                continue;
            }

            resultSets.add(new AbstractMap.SimpleEntry<>(player, entry.getValue()));
        }
        return resultSets;
    }

    public Optional<Integer> getLevel(Location<World> location) {

        // Not in Wilderness
        if (!isApplicable(location)) {
            return Optional.empty();
        }

        // In Wilderness
        return Optional.of(Math.max(0, Math.max(Math.abs(location.getBlockX()), Math.abs(location.getBlockZ()))
                / getLevelUnit(location.getExtent())) + 1);
    }

    public int getLevelUnit(World world) {
        return 500;
    }

    public int getFirstPvPLevel() {
        return 6;
    }

    public boolean allowsPvP(int level) {
        return level >= getFirstPvPLevel();
    }

    public int getDropTier(int level) {
        return Math.min(level, 30);
    }

    public double getDropMod(int dropTier) {
        return getDropMod(dropTier, null, null);
    }

    public double getDropMod(int dropTier, @Nullable Double mobHealth, @Nullable EntityType entityType) {
        double modifier = (dropTier * .2) + (mobHealth != null ? mobHealth * .04 : 0);
        if (entityType != null) {
            if (entityType == EntityTypes.WITHER || entityType == EntityTypes.CREEPER) {
                modifier *= 5;
            } else if (entityType == EntityTypes.SILVERFISH) {
                modifier *= 2;
            } else if (entityType == EntityTypes.ENDERMITE) {
                modifier *= .1;
            }
        }
        return modifier;
    }

    public int getHealthMod(int level) {
        return level > 1 ? level : 1;
    }

    public int getDamageMod(int level) {
        return level > 1 ? (level - 1) * 2 : 0;
    }

    public int getOreMod(int dropTier) {
        int modifier = (int) Math.round(Math.max(1, dropTier * 1.5));

        Optional<ModifierService> optService = Sponge.getServiceManager().provide(ModifierService.class);
        if (optService.isPresent()) {
            ModifierService service = optService.get();
            if (service.isActive(Modifiers.DOUBLE_WILD_ORES)) {
                modifier *= 2;
            }
        }

        return modifier;
    }

    public Collection<ItemStack> createDropsFor(BlockType blockType, boolean hasSilkTouch) {
        if (!hasSilkTouch && MultiTypeRegistry.isRedstoneOre(blockType)) {
            return Lists.newArrayList(newItemStack((ItemType) RED_SHARD));
        }
        return DropRegistry.createDropsFor(blockType, hasSilkTouch);
    }

    private void addPool(Location<World> block, BlockType blockType, int fortune, boolean hasSilkTouch) {

        Optional<Integer> optLevel = getLevel(block);
        Validate.isTrue(optLevel.isPresent());
        int level = optLevel.get();

        Collection<ItemStack> generalDrop = createDropsFor(blockType, hasSilkTouch);
        if (DropRegistry.dropsSelf(blockType)) {
            fortune = 0;
        }

        final int times = Probability.getRandom(getOreMod(getDropTier(level)));
        final int finalFortune = fortune;
        ItemFountain fountain = new ItemFountain(
                new Location<>(block.getExtent(), block.getPosition().add(.5, 0, .5)), (a) -> finalFortune,
                generalDrop, SpawnTypes.DROPPED_ITEM) {
            @Override
            public boolean run(int timesL) {
                getExtent().playSound(SoundTypes.ENTITY_BLAZE_BURN, getPos(),
                        Math.min(1, (((float) timesL / times) * .6F) + ((float) 1 / times)), 1);
                return super.run(timesL);
            }

            @Override
            public void end() {
                getExtent().playSound(SoundTypes.ENTITY_BLAZE_DEATH, getPos(), .2F, 0);
            }
        };

        TimedRunnable<IntegratedRunnable> runnable = new TimedRunnable<>(fountain, times);
        Task task = Task.builder().execute(runnable).delay(1, SECONDS).interval(1, SECONDS)
                .submit(SkreePlugin.inst());
        runnable.setTask(task);
    }

    @Override
    public void run() {
        for (Player player : Sponge.getServer().getOnlinePlayers()) {
            int currentLevel = getLevel(player.getLocation()).orElse(-1);
            WildernessPlayerMeta meta = playerMetaMap.getOrDefault(player.getUniqueId(),
                    new WildernessPlayerMeta());
            int lastLevel = meta.getLevel();

            // Always set the level so as to mark the player meta as relevant
            // if it is -1 no time stamp update shall be performed
            meta.setLevel(currentLevel);

            // Display a title change, unless the current level is -1 (outside of the Wilderness)
            if (currentLevel != -1 && currentLevel != lastLevel) {
                TextColor color = (allowsPvP(currentLevel) ? TextColors.RED : TextColors.WHITE);
                player.sendTitle(Title.builder().title(Text.of(color, "Wilderness Level"))
                        .subtitle(Text.of(color, currentLevel)).fadeIn(20).fadeOut(20).build());
                playerMetaMap.putIfAbsent(player.getUniqueId(), meta);
            }
        }

        playerMetaMap.entrySet().removeIf(entry -> System.currentTimeMillis()
                - entry.getValue().getLastChange() >= TimeUnit.MINUTES.toMillis(5));
    }
}