/* * 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.ics.chips.world.block; import com.sk89q.craftbook.core.util.RegexUtil; import com.sk89q.craftbook.sponge.CraftBookPlugin; import com.sk89q.craftbook.sponge.mechanics.ics.IC; import com.sk89q.craftbook.sponge.mechanics.ics.InvalidICException; import com.sk89q.craftbook.sponge.mechanics.ics.SerializedICData; import com.sk89q.craftbook.sponge.mechanics.ics.factory.ICFactory; import com.sk89q.craftbook.sponge.mechanics.ics.factory.SerializedICFactory; import com.sk89q.craftbook.sponge.util.BlockUtil; import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockTypes; import org.spongepowered.api.data.DataContainer; import org.spongepowered.api.data.DataQuery; import org.spongepowered.api.data.DataView; import org.spongepowered.api.data.key.Keys; import org.spongepowered.api.data.persistence.InvalidDataException; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.item.inventory.InteractInventoryEvent; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.InventoryArchetypes; import org.spongepowered.api.item.inventory.property.InventoryDimension; import org.spongepowered.api.item.inventory.property.InventoryTitle; import org.spongepowered.api.text.Text; import org.spongepowered.api.util.Direction; import org.spongepowered.api.world.BlockChangeFlag; import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; public class BlockReplacer extends IC { private Factory.BlockTypeData blockTypeData; private int delay; private int mode; private boolean physics; public BlockReplacer(ICFactory<BlockReplacer> icFactory, Location<World> block) { super(icFactory, block); } @Override public void create(Player player, List<Text> lines) throws InvalidICException { super.create(player, lines); blockTypeData = new BlockReplacer.Factory.BlockTypeData(); Inventory offBlockInventory = Inventory.builder() .of(InventoryArchetypes.CHEST) .property(InventoryTitle.PROPERTY_NAME, InventoryTitle.of(Text.of("Enter Off Block"))) .property(InventoryDimension.PROPERTY_NAME, InventoryDimension.of(9, 1)) .listener(InteractInventoryEvent.Close.class, close -> { Inventory inventory = close.getTargetInventory(); inventory.peek().ifPresent(itemStack -> blockTypeData.offBlock = itemStack.get(Keys.ITEM_BLOCKSTATE).orElse(itemStack.getItem().getBlock().orElse(BlockTypes.AIR).getDefaultState())); }) .build(CraftBookPlugin.spongeInst().container); Inventory onBlockInventory = Inventory.builder() .of(InventoryArchetypes.CHEST) .property(InventoryTitle.PROPERTY_NAME, InventoryTitle.of(Text.of("Enter On Block"))) .property(InventoryDimension.PROPERTY_NAME, InventoryDimension.of(9, 1)) .listener(InteractInventoryEvent.Close.class, close -> { Inventory inventory = close.getTargetInventory(); inventory.peek().ifPresent(itemStack -> { blockTypeData.onBlock = itemStack.get(Keys.ITEM_BLOCKSTATE).orElse(itemStack.getItem().getBlock().orElse(BlockTypes.AIR).getDefaultState()); player.openInventory(offBlockInventory, CraftBookPlugin.spongeInst().getCause().build()); }); }) .build(CraftBookPlugin.spongeInst().container); player.openInventory(onBlockInventory, CraftBookPlugin.spongeInst().getCause().build()); } @Override public void load() { super.load(); String[] data = RegexUtil.COLON_PATTERN.split(getLine(3)); delay = Integer.parseInt(data[0]); if(data.length > 1) mode = Integer.parseInt(data[1]); else mode = 0; physics = data.length <= 2 || data[2].equalsIgnoreCase("1") || data[2].equalsIgnoreCase("true"); } @Override public void trigger() { if (blockTypeData.onBlock != null && blockTypeData.offBlock != null) { Location<World> block = getBackBlock(); if(block.getBlock().equals(blockTypeData.onBlock)) { if(!getPinSet().getInput(0, this)) { block.setBlock(blockTypeData.offBlock, physics ? BlockChangeFlag.ALL : BlockChangeFlag.NONE, CraftBookPlugin.spongeInst().getCause().build()); } } else if (block.getBlock().equals(blockTypeData.offBlock)) { if (getPinSet().getInput(0, this)) { block.setBlock(blockTypeData.onBlock, physics ? BlockChangeFlag.ALL : BlockChangeFlag.NONE, CraftBookPlugin.spongeInst().getCause().build()); } } Set<Location> traversedBlocks = new HashSet<>(); traversedBlocks.add(block); getPinSet().setOutput(0, replaceBlocks(getPinSet().getInput(0, this), block, traversedBlocks), this); } } private boolean replaceBlocks(final boolean on, final Location<World> block, final Set<Location> traversedBlocks) { if (traversedBlocks.size() > 15000) { return true; } if (mode == 0) { for (Direction direction : BlockUtil.getDirectFaces()) { final Location<World> b = block.getRelative(direction); if (traversedBlocks.contains(b)) { continue; } traversedBlocks.add(b); if (b.getBlock().equals(blockTypeData.onBlock)) { if (!on) { b.setBlock(blockTypeData.offBlock, physics ? BlockChangeFlag.ALL : BlockChangeFlag.NONE, CraftBookPlugin.spongeInst().getCause().build()); } Sponge.getScheduler().createTaskBuilder().delayTicks(delay).execute(() -> replaceBlocks(on, b, traversedBlocks)).submit(CraftBookPlugin.spongeInst().container); } else if (b.getBlock().equals(blockTypeData.offBlock)) { if (on) { b.setBlock(blockTypeData.onBlock, physics ? BlockChangeFlag.ALL : BlockChangeFlag.NONE, CraftBookPlugin.spongeInst().getCause().build()); } Sponge.getScheduler().createTaskBuilder().delayTicks(delay).execute(() -> replaceBlocks(on, b, traversedBlocks)).submit(CraftBookPlugin.spongeInst().container); } } } return traversedBlocks.size() > 0; } public static class Factory extends SerializedICFactory<BlockReplacer, Factory.BlockTypeData> { public Factory() { super(BlockTypeData.class, 1); } @Override public BlockReplacer createInstance(Location<World> location) { return new BlockReplacer(this, location); } @Override public String[] getLineHelp() { return new String[] { "", "delay:mode:physics" }; } @Override public String[][] getPinHelp() { return new String[][] { new String[] { "Clock" }, new String[] { "None" } }; } @Override public void setData(BlockReplacer ic, BlockTypeData data) { ic.blockTypeData = data; } @Override public BlockTypeData getData(BlockReplacer ic) { return ic.blockTypeData; } @Override protected Optional<BlockTypeData> buildContent(DataView container) throws InvalidDataException { BlockTypeData blockTypeData = new BlockTypeData(); blockTypeData.onBlock = container.getSerializable(DataQuery.of("OnBlock"), BlockState.class).orElse(null); blockTypeData.offBlock = container.getSerializable(DataQuery.of("OffBlock"), BlockState.class).orElse(null); if (blockTypeData.onBlock == null || blockTypeData.offBlock == null) { return Optional.empty(); } return Optional.of(blockTypeData); } public static class BlockTypeData extends SerializedICData { public BlockState onBlock = BlockTypes.STONEBRICK.getDefaultState(); public BlockState offBlock = BlockTypes.COBBLESTONE.getDefaultState(); @Override public int getContentVersion() { return 1; } @Override public DataContainer toContainer() { return super.toContainer() .set(DataQuery.of("OnBlock"), this.onBlock) .set(DataQuery.of("OffBlock"), this.offBlock); } } } }