/* * CraftBook Copyright (C) 2010-2017 sk89q <http://www.sk89q.com> * CraftBook Copyright (C) 2011-2017 me4502 <http://www.me4502.com> * CraftBook Copyright (C) Contributors * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program. If not, * see <http://www.gnu.org/licenses/>. */ package com.sk89q.craftbook.sponge.mechanics; import com.google.common.reflect.TypeToken; import com.google.inject.Inject; import com.me4502.modularframework.module.Module; import com.me4502.modularframework.module.guice.ModuleConfiguration; import com.sk89q.craftbook.core.util.ConfigValue; import com.sk89q.craftbook.core.util.CraftBookException; import com.sk89q.craftbook.core.util.PermissionNode; import com.sk89q.craftbook.core.util.TernaryState; import com.sk89q.craftbook.core.util.documentation.DocumentationProvider; import com.sk89q.craftbook.sponge.mechanics.types.SpongeBlockMechanic; import com.sk89q.craftbook.sponge.util.SpongePermissionNode; import ninja.leaping.configurate.ConfigurationNode; import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockTypes; import org.spongepowered.api.data.key.Keys; import org.spongepowered.api.data.type.HandType; import org.spongepowered.api.entity.EntityTypes; import org.spongepowered.api.entity.Item; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.block.InteractBlockEvent; import org.spongepowered.api.event.cause.Cause; import org.spongepowered.api.event.cause.NamedCause; import org.spongepowered.api.event.cause.entity.spawn.SpawnCause; import org.spongepowered.api.event.cause.entity.spawn.SpawnTypes; import org.spongepowered.api.event.filter.cause.Named; import org.spongepowered.api.item.ItemTypes; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.service.permission.PermissionDescription; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; import java.util.concurrent.atomic.AtomicInteger; @Module(id = "xpstorer", name = "XPStorer", onEnable="onInitialize", onDisable="onDisable") public class XPStorer extends SpongeBlockMechanic implements DocumentationProvider { @Inject @ModuleConfiguration public ConfigurationNode config; private SpongePermissionNode usePermissions = new SpongePermissionNode("craftbook.xp-storer.use", "Allows the user to use the " + getName() + " mechanic.", PermissionDescription.ROLE_USER); private ConfigValue<Boolean> requireBottle = new ConfigValue<>("require-bottle", "Requires the player to be holding a glass bottle to use.", false); private ConfigValue<BlockState> block = new ConfigValue<>("block", "The block that is an XP Storer.", BlockTypes.MOB_SPAWNER.getDefaultState(), TypeToken.of(BlockState.class)); private ConfigValue<TernaryState> sneakState = new ConfigValue<>("sneak-state", "Sets how the player must be sneaking in order to use the XP Storer.", TernaryState.FALSE, TypeToken.of(TernaryState.class)); private ConfigValue<Integer> xpPerBottle = new ConfigValue<>("xp-per-bottle", "Sets the amount of XP points required per each bottle.", 16); @Override public void onInitialize() throws CraftBookException { super.onInitialize(); block.load(config); requireBottle.load(config); sneakState.load(config); xpPerBottle.load(config); usePermissions.register(); } @Listener public void onPlayerInteract(InteractBlockEvent.Secondary.MainHand event, @Named(NamedCause.SOURCE) Player player) { event.getTargetBlock().getLocation().filter((this::isValid)).ifPresent(location -> { if (!sneakState.getValue().doesPass(player.get(Keys.IS_SNEAKING).orElse(false)) || player.get(Keys.EXPERIENCE_LEVEL).orElse(0) < 1 || !usePermissions.hasPermission(player)) { return; } AtomicInteger max = new AtomicInteger(Integer.MAX_VALUE); if(requireBottle.getValue()) { max.set(0); for (HandType handType : Sponge.getRegistry().getAllOf(HandType.class)) { player.getItemInHand(handType).filter(itemStack -> itemStack.getItem() == ItemTypes.GLASS_BOTTLE) .ifPresent((itemStack -> max.addAndGet(itemStack.getQuantity()))); } if (max.get() == 0) { player.sendMessage(Text.of(TextColors.RED, "You need a bottle to use this mechanic!")); return; } } int xp = player.get(Keys.TOTAL_EXPERIENCE).orElse(0); // Reset their xp player.offer(Keys.EXPERIENCE_LEVEL, 0); player.offer(Keys.TOTAL_EXPERIENCE, 0); if (xp < xpPerBottle.getValue()) { player.sendMessage(Text.of(TextColors.RED, "Not enough XP!")); return; } int bottleCount = (int) Math.min(max.get(), Math.floor(((float) xp) / xpPerBottle.getValue())); if(requireBottle.getValue()) { bottleCount = player.getInventory().query(ItemTypes.GLASS_BOTTLE).poll(bottleCount).orElse(ItemStack.of(ItemTypes.GLASS_BOTTLE, 0)).getQuantity(); } int tempBottles = bottleCount; while(tempBottles > 0) { ItemStack bottles = ItemStack.of(ItemTypes.EXPERIENCE_BOTTLE, Math.min(tempBottles, 64)); Item item = (Item) location.getExtent().createEntity(EntityTypes.ITEM, location.getPosition()); item.offer(Keys.REPRESENTED_ITEM, bottles.createSnapshot()); SpawnCause cause = Sponge.getRegistry().createBuilder(SpawnCause.Builder.class).type(SpawnTypes.DROPPED_ITEM).build(); location.getExtent().spawnEntity(item, Cause.source(cause).build()); tempBottles -= 64; } int remainingXP = xp - bottleCount * xpPerBottle.getValue(); player.offer(Keys.TOTAL_EXPERIENCE, remainingXP); }); } @Override public String getPath() { return "mechanics/xp_storer"; } @Override public PermissionNode[] getPermissionNodes() { return new PermissionNode[] { usePermissions }; } @Override public ConfigValue<?>[] getConfigurationNodes() { return new ConfigValue<?>[] { requireBottle, block, sneakState, xpPerBottle }; } @Override public boolean isValid(Location<World> location) { return location.getBlock().equals(block.getValue()); } }