/*
* 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.treelopper;
import com.google.common.collect.Lists;
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.documentation.DocumentationProvider;
import com.sk89q.craftbook.sponge.CraftBookPlugin;
import com.sk89q.craftbook.sponge.mechanics.treelopper.command.ToggleCommand;
import com.sk89q.craftbook.sponge.mechanics.types.SpongeMechanic;
import com.sk89q.craftbook.sponge.util.BlockFilter;
import com.sk89q.craftbook.sponge.util.BlockUtil;
import com.sk89q.craftbook.sponge.util.ItemUtil;
import com.sk89q.craftbook.sponge.util.SpongePermissionNode;
import com.sk89q.craftbook.sponge.util.type.TypeTokens;
import ninja.leaping.configurate.ConfigurationNode;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandMapping;
import org.spongepowered.api.command.args.GenericArguments;
import org.spongepowered.api.command.spec.CommandSpec;
import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.data.type.HandTypes;
import org.spongepowered.api.data.type.TreeType;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.block.ChangeBlockEvent;
import org.spongepowered.api.event.cause.NamedCause;
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.util.Direction;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Module(id = "treelopper", name = "TreeLopper", onEnable="onInitialize", onDisable="onDisable")
public class TreeLopper extends SpongeMechanic implements DocumentationProvider {
@Inject
@ModuleConfiguration
public ConfigurationNode config;
private ConfigValue<List<BlockFilter>> allowedBlocks = new ConfigValue<>("allowed-blocks", "A list of blocks that are logs.", getDefaultBlocks(), new TypeTokens.BlockFilterListTypeToken());
private ConfigValue<List<ItemStack>> allowedItems = new ConfigValue<>("allowed-items", "The list of items that can be used with this mechanic.", getDefaultItems(), new TypeTokens.ItemStackListTypeToken());
public ConfigValue<List<UUID>> disabledPlayers = new ConfigValue<>("disabled-users", "A list of users that have disabled the mechanic.", new ArrayList<>(), new TypeTokens.UUIDListTypeToken());
private SpongePermissionNode usePermission = new SpongePermissionNode("craftbook.treelopper.use", "Allows the user to use TreeLopper.", PermissionDescription.ROLE_USER);
private SpongePermissionNode togglePermission = new SpongePermissionNode("craftbook.treelopper.toggle", "Allows the user to toggle TreeLopper on and off.", PermissionDescription.ROLE_USER);
private CommandMapping treelopperCommandMapping;
@Override
public void onInitialize() throws CraftBookException {
super.onInitialize();
allowedBlocks.load(config);
allowedItems.load(config);
disabledPlayers.load(config);
togglePermission.register();
CommandSpec toggleCommand = CommandSpec.builder()
.description(Text.of("Toggles TreeLopper being enabled."))
.permission(togglePermission.getNode())
.arguments(GenericArguments.optional(GenericArguments.bool(Text.of("state"))))
.executor(new ToggleCommand(this))
.build();
CommandSpec treeLopperCommand = CommandSpec.builder()
.description(Text.of("Base TreeLopper command"))
.child(toggleCommand, "toggle")
.build();
treelopperCommandMapping = Sponge.getCommandManager().register(CraftBookPlugin.inst(), treeLopperCommand, "treelopper", "timber").orElse(null);
}
@Override
public void onDisable() {
super.onDisable();
disabledPlayers.save(config);
if (treelopperCommandMapping != null) {
Sponge.getCommandManager().removeMapping(treelopperCommandMapping);
}
}
@Listener
public void onBlockBreak(ChangeBlockEvent.Break event, @Named(NamedCause.SOURCE) Player player) {
if(ItemUtil.doesStackPassFilters(allowedItems.getValue(), player.getItemInHand(HandTypes.MAIN_HAND).orElse(null)) && !disabledPlayers.getValue().contains(player.getUniqueId())) {
event.getTransactions().stream().filter((t) -> BlockUtil.doesStatePassFilters(allowedBlocks.getValue(), t.getOriginal().getState())).forEach(transaction -> {
Optional<TreeType> treeType = transaction.getOriginal().get(Keys.TREE_TYPE);
treeType.ifPresent(treeType1 -> transaction.getOriginal().getLocation().ifPresent(location -> {
List<Location> traversed = Lists.newArrayList(location);
for(Direction dir : BlockUtil.getDirectFaces()) {
checkBlocks(location.getRelative(dir), player, treeType1, traversed);
}
}));
});
}
}
private static void checkBlocks(Location<World> block, Player player, TreeType type, List<Location> traversed) {
if(traversed.contains(block)) return;
traversed.add(block);
Optional<TreeType> data = block.getBlock().get(Keys.TREE_TYPE);
if(data.isPresent() && data.get().equals(type)) { //Same tree type.
// TODO Switch to FakePlayer when implemented.
//block.getExtent().digBlockWith(block.getBlockPosition(), player.getItemInHand(HandTypes.MAIN_HAND).orElse(null), Cause.of(NamedCause.simulated(player)));
block.removeBlock(CraftBookPlugin.spongeInst().getCause().build());
for(Direction dir : BlockUtil.getDirectFaces()) {
checkBlocks(block.getRelative(dir), player, type, traversed);
}
}
}
private static List<BlockFilter> getDefaultBlocks() {
List<BlockFilter> states = Lists.newArrayList();
states.add(new BlockFilter("LOG"));
states.add(new BlockFilter("LOG2"));
return states;
}
private static List<ItemStack> getDefaultItems() {
List<ItemStack> stacks = Lists.newArrayList();
stacks.add(ItemStack.of(ItemTypes.DIAMOND_AXE, 1));
stacks.add(ItemStack.of(ItemTypes.GOLDEN_AXE, 1));
stacks.add(ItemStack.of(ItemTypes.IRON_AXE, 1));
stacks.add(ItemStack.of(ItemTypes.STONE_AXE, 1));
stacks.add(ItemStack.of(ItemTypes.WOODEN_AXE, 1));
return stacks;
}
@Override
public ConfigValue<?>[] getConfigurationNodes() {
return new ConfigValue<?>[] {
allowedBlocks,
allowedItems,
disabledPlayers
};
}
@Override
public PermissionNode[] getPermissionNodes() {
return new PermissionNode[] {
usePermission,
togglePermission
};
}
@Override
public String getPath() {
return "mechanics/tree_lopper";
}
}