/* * Copyright (C) 2014 eccentric_nz * * 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 me.eccentric_nz.TARDIS.rooms; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import me.eccentric_nz.TARDIS.JSON.JSONArray; import me.eccentric_nz.TARDIS.JSON.JSONObject; import me.eccentric_nz.TARDIS.TARDIS; import me.eccentric_nz.TARDIS.TARDISConstants; import me.eccentric_nz.TARDIS.database.QueryFactory; import me.eccentric_nz.TARDIS.enumeration.COMPASS; import me.eccentric_nz.TARDIS.enumeration.ROOM; import static me.eccentric_nz.TARDIS.schematic.TARDISBannerSetter.setBanners; import me.eccentric_nz.TARDIS.utility.TARDISBlockSetters; import me.eccentric_nz.TARDIS.utility.TARDISLocationGetters; import me.eccentric_nz.TARDIS.utility.TARDISMessage; import me.eccentric_nz.TARDIS.utility.TARDISNumberParsers; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; /** * The TARDIS had a swimming pool. After the TARDIS' crash following the * Doctor's tenth regeneration, the pool's water - or perhaps the pool itself - * fell into the library. After the TARDIS had fixed itself, the swimming pool * was restored but the Doctor did not know where it was. * * @author eccentric_nz */ public class TARDISRoomRunnable implements Runnable { private final TARDIS plugin; private final Location l; JSONObject s; private int task, level, row, col, h, w, c, startx, starty, startz, resetx, resety, resetz; private final int tardis_id; private final Material wall_type, floor_type; Material type; byte data, wall_data, floor_data; Block b; COMPASS d; String room; String grammar; private boolean running; Player p; World world; List<Chunk> chunkList = new ArrayList<Chunk>(); List<Block> iceblocks = new ArrayList<Block>(); List<Block> lampblocks = new ArrayList<Block>(); List<Block> caneblocks = new ArrayList<Block>(); List<Block> melonblocks = new ArrayList<Block>(); List<Block> potatoblocks = new ArrayList<Block>(); List<Block> carrotblocks = new ArrayList<Block>(); List<Block> pumpkinblocks = new ArrayList<Block>(); List<Block> wheatblocks = new ArrayList<Block>(); List<Material> notThese = new ArrayList<Material>(); HashMap<Block, Byte> cocoablocks = new HashMap<Block, Byte>(); HashMap<Block, Byte> doorblocks = new HashMap<Block, Byte>(); HashMap<Block, Byte> leverblocks = new HashMap<Block, Byte>(); HashMap<Block, Byte> torchblocks = new HashMap<Block, Byte>(); HashMap<Block, Byte> redstoneTorchblocks = new HashMap<Block, Byte>(); HashMap<Block, Byte> mushroomblocks = new HashMap<Block, Byte>(); HashMap<Block, JSONObject> standingBanners = new HashMap<Block, JSONObject>(); HashMap<Block, JSONObject> wallBanners = new HashMap<Block, JSONObject>(); byte[] repeaterData = new byte[6]; HashMap<Integer, Integer> repeaterOrder = new HashMap<Integer, Integer>(); JSONArray arr; public TARDISRoomRunnable(TARDIS plugin, TARDISRoomData roomData, Player p) { this.plugin = plugin; this.l = roomData.getLocation(); this.s = roomData.getSchematic(); this.b = roomData.getBlock(); this.d = roomData.getDirection(); this.wall_type = roomData.getMiddleType(); this.wall_data = roomData.getMiddleData(); this.floor_type = roomData.getFloorType(); this.floor_data = roomData.getFloorData(); this.room = roomData.getRoom(); this.tardis_id = roomData.getTardis_id(); this.running = false; this.p = p; this.repeaterData[0] = (byte) 0; this.repeaterData[1] = (byte) 0; this.repeaterData[2] = (byte) 1; this.repeaterData[3] = (byte) 2; this.repeaterData[4] = (byte) 0; this.repeaterData[5] = (byte) 3; this.repeaterOrder.put(2, 3); this.repeaterOrder.put(3, 2); this.repeaterOrder.put(4, 5); this.repeaterOrder.put(5, 4); this.notThese.add(Material.CARROT); this.notThese.add(Material.COCOA); this.notThese.add(Material.CROPS); this.notThese.add(Material.LEVER); this.notThese.add(Material.MELON_STEM); this.notThese.add(Material.PISTON_EXTENSION); this.notThese.add(Material.POTATO); this.notThese.add(Material.PUMPKIN_STEM); this.notThese.add(Material.REDSTONE_TORCH_ON); this.notThese.add(Material.SUGAR_CANE_BLOCK); this.notThese.add(Material.TORCH); this.notThese.add(Material.WOODEN_DOOR); } /** * A runnable task that builds TARDIS rooms block by block. */ @SuppressWarnings("deprecation") @Override public void run() { // initialise if (!running) { level = 0; row = 0; col = 0; JSONObject dim = s.getJSONObject("dimensions"); arr = s.getJSONArray("input"); h = dim.getInt("height") - 1; w = dim.getInt("width") - 1; c = dim.getInt("length"); startx = l.getBlockX(); starty = l.getBlockY(); startz = l.getBlockZ(); resetx = startx; resety = starty; resetz = startz; world = l.getWorld(); running = true; grammar = (TARDISConstants.VOWELS.contains(room.substring(0, 1))) ? "an " + room : "a " + room; if (room.equals("GRAVITY") || room.equals("ANTIGRAVITY")) { grammar += " WELL"; } TARDISMessage.send(p, "ROOM_START", grammar); } if (level == h && row == w && col == (c - 1)) { // the entire schematic has been read :) if (iceblocks.size() > 0) { TARDISMessage.send(p, "ICE"); // set all the ice to water for (Block ice : iceblocks) { ice.setType(Material.STATIONARY_WATER); } iceblocks.clear(); } if (room.equals("BAKER") || room.equals("WOOD")) { // set the repeaters for (Map.Entry<Block, Byte> entry : mushroomblocks.entrySet()) { entry.getKey().setType(Material.DIODE_BLOCK_OFF); entry.getKey().setData(entry.getValue(), true); } mushroomblocks.clear(); } if (room.equals("ARBORETUM") || room.equals("GREENHOUSE")) { // plant the sugar cane for (Block cane : caneblocks) { cane.setType(Material.SUGAR_CANE_BLOCK); } caneblocks.clear(); // attach the cocoa for (Map.Entry<Block, Byte> entry : cocoablocks.entrySet()) { entry.getKey().setType(Material.COCOA); entry.getKey().setData(entry.getValue(), true); } cocoablocks.clear(); // plant the melon for (Block melon : melonblocks) { melon.setType(Material.MELON_STEM); } melonblocks.clear(); // plant the pumpkin for (Block pumpkin : pumpkinblocks) { pumpkin.setType(Material.PUMPKIN_STEM); } pumpkinblocks.clear(); plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { @Override public void run() { // plant the wheat for (Block wheat : wheatblocks) { wheat.setType(Material.CROPS); } wheatblocks.clear(); // plant the carrot for (Block carrot : carrotblocks) { carrot.setType(Material.CARROT); } carrotblocks.clear(); // plant the potato for (Block potato : potatoblocks) { potato.setType(Material.POTATO); } potatoblocks.clear(); } }, 5L); } if (room.equals("VILLAGE")) { // put doors on for (Map.Entry<Block, Byte> entry : doorblocks.entrySet()) { entry.getKey().setType(Material.WOODEN_DOOR); entry.getKey().setData(entry.getValue(), true); } doorblocks.clear(); } // put levers on for (Map.Entry<Block, Byte> entry : leverblocks.entrySet()) { entry.getKey().setTypeIdAndData(69, entry.getValue(), true); } leverblocks.clear(); // update lamp block states TARDISMessage.send(p, "ROOM_POWER"); for (Block lamp : lampblocks) { lamp.setType(Material.REDSTONE_LAMP_ON); } lampblocks.clear(); // put torches on for (Map.Entry<Block, Byte> entry : torchblocks.entrySet()) { entry.getKey().setTypeIdAndData(50, entry.getValue(), true); } torchblocks.clear(); // put redstone torches on for (Map.Entry<Block, Byte> entry : redstoneTorchblocks.entrySet()) { entry.getKey().setTypeIdAndData(76, entry.getValue(), true); } torchblocks.clear(); // set banners setBanners(176, standingBanners); setBanners(177, wallBanners); // remove the chunks, so they can unload as normal again if (chunkList.size() > 0) { for (Chunk ch : chunkList) { if (plugin.getConfig().getBoolean("creation.sky_biome")) { // refesh the cunk so ctm textures show //world.refreshChunk(ch.getX(), ch.getZ()); plugin.getTardisHelper().refreshChunk(ch); } plugin.getGeneralKeeper().getRoomChunkList().remove(ch); } } // cancel the task plugin.getServer().getScheduler().cancelTask(task); task = 0; String rname = (room.equals("GRAVITY") || room.equals("ANTIGRAVITY")) ? room + " WELL" : room; TARDISMessage.send(p, "ROOM_FINISHED", rname); } else { // place one block JSONObject v = arr.getJSONArray(level).getJSONArray(row).getJSONObject(col); type = Material.valueOf(v.getString("type")); data = v.getByte("data"); if (type.equals(Material.DROPPER)) { byte bit = data; switch (bit) { case 8: data = 0; break; case 9: data = 1; break; case 10: data = 2; break; case 11: data = 3; break; case 12: data = 4; break; case 13: data = 5; break; default: break; } } if (type.equals(Material.REDSTONE_WIRE)) { data = 0; } if (type.equals(Material.WOOL) && data == 7 && plugin.getConfig().getBoolean("creation.use_clay")) { type = Material.STAINED_CLAY; } if (type.equals(Material.WOOL) && data == 1) { if (wall_type.equals(Material.WOOL) && wall_data == 1 && plugin.getConfig().getBoolean("creation.use_clay")) { type = Material.STAINED_CLAY; } else { type = wall_type; } data = ((room.equals("GRAVITY") || room.equals("ANTIGRAVITY")) && wall_type.equals(Material.WOOL) && (wall_data == 5 || wall_data == 6)) ? 1 : wall_data; } if (type.equals(Material.WOOL) && data == 8) { if (floor_type.equals(Material.WOOL) && floor_data == 8 && plugin.getConfig().getBoolean("creation.use_clay")) { type = Material.STAINED_CLAY; } else { type = floor_type; } data = ((room.equals("GRAVITY") || room.equals("ANTIGRAVITY")) && floor_type.equals(Material.WOOL) && (floor_data == 5 || floor_data == 6)) ? 8 : floor_data; } QueryFactory qf = new QueryFactory(plugin); // set condenser if (type.equals(Material.CHEST) && room.equals("HARMONY")) { HashMap<String, Object> setc = new HashMap<String, Object>(); setc.put("condenser", world.getName() + ":" + startx + ":" + starty + ":" + startz); HashMap<String, Object> wherec = new HashMap<String, Object>(); wherec.put("tardis_id", tardis_id); qf.doUpdate("tardis", setc, wherec); } // set drop chest if (type.equals(Material.TRAPPED_CHEST) && room.equals("VAULT") && p.hasPermission("tardis.vault")) { // determine the min x, y, z coords int mx = startx % 16; if (mx < 0) { mx += 16; } int mz = startz % 16; if (mz < 0) { mz += 16; } int x = startx - mx; int y = starty - (starty % 16); int z = startz - mz; String pos = new Location(world, startx, starty, startz).toString(); HashMap<String, Object> setv = new HashMap<String, Object>(); setv.put("tardis_id", tardis_id); setv.put("location", pos); setv.put("x", x); setv.put("y", y); setv.put("z", z); qf.doInsert("vaults", setv); } // set farm if (type.equals(Material.MOB_SPAWNER) && room.equals("FARM")) { HashMap<String, Object> setf = new HashMap<String, Object>(); setf.put("farm", world.getName() + ":" + startx + ":" + starty + ":" + startz); HashMap<String, Object> wheref = new HashMap<String, Object>(); wheref.put("tardis_id", tardis_id); qf.doUpdate("tardis", setf, wheref); // replace with floor material type = (floor_type.equals(Material.WOOL) && floor_data == 8 && plugin.getConfig().getBoolean("creation.use_clay")) ? Material.STAINED_CLAY : floor_type; data = floor_data; } // set lazarus if (type.equals(Material.WOOD_PLATE) && room.equals("LAZARUS")) { String plate = (new Location(world, startx, starty, startz)).toString(); qf.insertControl(tardis_id, 19, plate, 0); } // set stable if (type.equals(Material.SOUL_SAND) && (room.equals("STABLE") || room.equals("VILLAGE") || room.equals("RENDERER") || room.equals("ZERO") || room.equals("HUTCH") || room.equals("IGLOO"))) { HashMap<String, Object> sets = new HashMap<String, Object>(); sets.put(room.toLowerCase(Locale.ENGLISH), world.getName() + ":" + startx + ":" + starty + ":" + startz); HashMap<String, Object> wheres = new HashMap<String, Object>(); wheres.put("tardis_id", tardis_id); qf.doUpdate("tardis", sets, wheres); // replace with correct block switch (ROOM.valueOf(room)) { case VILLAGE: type = Material.COBBLESTONE; data = 0; break; case HUTCH: case STABLE: type = Material.GRASS; data = 0; break; case IGLOO: type = Material.PACKED_ICE; data = 0; break; case ZERO: type = Material.CARPET; data = 6; break; default: type = Material.WOOL; data = 15; // add WorldGuard region if (plugin.isWorldGuardOnServer() && plugin.getConfig().getBoolean("preferences.use_worldguard")) { Location one = new Location(world, startx - 6, starty, startz - 6); Location two = new Location(world, startx + 6, starty + 8, startz + 6); plugin.getWorldGuardUtils().addRendererProtection(p.getName(), one, two); } break; } } // remember village doors if (type.equals(Material.WOODEN_DOOR) && room.equals("VILLAGE")) { Block door = world.getBlockAt(startx, starty, startz); doorblocks.put(door, data); } // remember torches if (type.equals(Material.TORCH)) { Block torch = world.getBlockAt(startx, starty, startz); torchblocks.put(torch, data); } // remember torches if (type.equals(Material.LEVER)) { Block lever = world.getBlockAt(startx, starty, startz); leverblocks.put(lever, data); } // remember redstone torches if (type.equals(Material.REDSTONE_TORCH_ON)) { Block torch = world.getBlockAt(startx, starty, startz); redstoneTorchblocks.put(torch, data); } // remember banners if (type.equals(Material.STANDING_BANNER) || type.equals(Material.WALL_BANNER)) { Block banner = world.getBlockAt(startx, starty, startz); JSONObject state = v.optJSONObject("banner"); if (state != null) { if (type.equals(Material.STANDING_BANNER)) { standingBanners.put(banner, state); } else { wallBanners.put(banner, state); } } } // set farmland hydrated if (type.equals(Material.SOIL) && data == 0) { data = (byte) 4; } if (room.equals("ARBORETUM") || room.equals("GREENHOUSE")) { // remember sugar cane if (type.equals(Material.SUGAR_CANE_BLOCK)) { Block cane = world.getBlockAt(startx, starty, startz); caneblocks.add(cane); } // remember cocoa if (type.equals(Material.COCOA)) { Block cocoa = world.getBlockAt(startx, starty, startz); cocoablocks.put(cocoa, data); } // remember wheat if (type.equals(Material.CROPS)) { Block crops = world.getBlockAt(startx, starty, startz); wheatblocks.add(crops); } // remember melon if (type.equals(Material.MELON_STEM)) { Block melon = world.getBlockAt(startx, starty, startz); melonblocks.add(melon); } // remember pumpkin if (type.equals(Material.PUMPKIN_STEM)) { Block pumpkin = world.getBlockAt(startx, starty, startz); pumpkinblocks.add(pumpkin); } // remember carrot if (type.equals(Material.CARROT)) { Block carrot = world.getBlockAt(startx, starty, startz); carrotblocks.add(carrot); } // remember potato if (type.equals(Material.POTATO)) { Block potato = world.getBlockAt(startx, starty, startz); potatoblocks.add(potato); } if (level == 4 && room.equals("GREENHOUSE")) { // set all the ice to water for (Block ice : iceblocks) { ice.setType(Material.STATIONARY_WATER); } iceblocks.clear(); } } if (room.equals("RAIL") && type.equals(Material.FENCE)) { // remember fence location so we can teleport the storage minecart String loc = world.getName() + ":" + startx + ":" + starty + ":" + startz; HashMap<String, Object> set = new HashMap<String, Object>(); set.put("rail", loc); HashMap<String, Object> where = new HashMap<String, Object>(); where.put("tardis_id", tardis_id); qf.doUpdate("tardis", set, where); } // always replace bedrock (the door space in ARS rooms) if (type.equals(Material.BEDROCK)) { if (checkRoomNextDoor(world.getBlockAt(startx, starty, startz))) { type = Material.AIR; data = (byte) 0; } else { type = (wall_type.equals(Material.WOOL) && wall_data == 1 && plugin.getConfig().getBoolean("creation.use_clay")) ? Material.STAINED_CLAY : wall_type; data = wall_data; } } // always clear the door blocks on the north and west sides of adjacent spaces if (type.equals(Material.PISTON_STICKY_BASE)) { // only the bottom pistons if (starty == (resety + 2)) { Block bottomdoorblock = null; // north if (startx == (resetx + 8) && startz == resetz) { bottomdoorblock = world.getBlockAt(startx, (starty + 2), (startz - 1)); } // west if (startx == resetx && startz == (resetz + 8)) { bottomdoorblock = world.getBlockAt((startx - 1), (starty + 2), startz); } if (bottomdoorblock != null) { Block topdoorblock = bottomdoorblock.getRelative(BlockFace.UP); bottomdoorblock.setType(Material.AIR); topdoorblock.setType(Material.AIR); } } } // always remove sponge if (type.equals(Material.SPONGE)) { type = Material.AIR; data = (byte) 0; } else { Block existing = world.getBlockAt(startx, starty, startz); if (!existing.getType().equals(Material.AIR)) { if (room.equals("GRAVITY") || room.equals("ANTIGRAVITY")) { switch (type) { case AIR: case WOOL: case SMOOTH_BRICK: break; default: type = existing.getType(); data = existing.getData(); break; } } else { type = existing.getType(); data = existing.getData(); } } } Chunk thisChunk = world.getChunkAt(world.getBlockAt(startx, starty, startz)); if (!plugin.getGeneralKeeper().getRoomChunkList().contains(thisChunk)) { plugin.getGeneralKeeper().getRoomChunkList().add(thisChunk); chunkList.add(thisChunk); } // if we're setting the biome to sky, do it now if (plugin.getConfig().getBoolean("creation.sky_biome") && level == 0) { world.setBiome(startx, startz, Biome.VOID); } if (!notThese.contains(type) && !(type.equals(Material.HUGE_MUSHROOM_2) && data == (byte) 15)) { if (type.equals(Material.STATIONARY_WATER)) { TARDISBlockSetters.setBlock(world, startx, starty, startz, 79, (byte) 0); } else { TARDISBlockSetters.setBlock(world, startx, starty, startz, type, data); } } // remember ice blocks if ((type.equals(Material.STATIONARY_WATER) || type.equals(Material.ICE)) && !room.equals("IGLOO")) { Block icy = world.getBlockAt(startx, starty, startz); iceblocks.add(icy); } // remember lamp blocks if (type.equals(Material.REDSTONE_LAMP_ON)) { Block lamp = world.getBlockAt(startx, starty, startz); lampblocks.add(lamp); } if (room.equals("GRAVITY") || room.equals("ANTIGRAVITY")) { String loc; if (type.equals(Material.WOOL) && data == 6) { // pink wool - gravity well down loc = new Location(world, startx, starty, startz).toString(); HashMap<String, Object> setd = new HashMap<String, Object>(); setd.put("tardis_id", tardis_id); setd.put("location", loc); setd.put("direction", 0); setd.put("distance", 0); setd.put("velocity", 0); qf.doInsert("gravity_well", setd); plugin.getGeneralKeeper().getGravityDownList().add(loc); } if (type.equals(Material.WOOL) && data == 5) { // light green wool - gravity well up loc = new Location(world, startx, starty, startz).toString(); HashMap<String, Object> setu = new HashMap<String, Object>(); setu.put("tardis_id", tardis_id); setu.put("location", loc); setu.put("direction", 1); setu.put("distance", 16); setu.put("velocity", 0.5); qf.doInsert("gravity_well", setu); Double[] values = {1D, 16D, 0.5D}; plugin.getGeneralKeeper().getGravityUpList().put(loc, values); } } if (room.equals("BAKER") || room.equals("WOOD")) { // remember the controls int secondary = (room.equals("BAKER")) ? 1 : 2; int r = 2; int ctype; String loc_str; List<Material> controls = Arrays.asList(Material.CAKE_BLOCK, Material.STONE_BUTTON, Material.HUGE_MUSHROOM_2, Material.WOOD_BUTTON); if (controls.contains(this.type)) { switch (this.type) { case STONE_BUTTON: // stone button - random ctype = 1; loc_str = TARDISLocationGetters.makeLocationStr(world, startx, starty, startz); break; case HUGE_MUSHROOM_2: // repeater ctype = repeaterOrder.get(r); loc_str = world.getName() + ":" + startx + ":" + starty + ":" + startz; Block rb = world.getBlockAt(startx, starty, startz); mushroomblocks.put(rb, repeaterData[r]); r++; break; case WOOD_BUTTON: // wood button - artron ctype = 6; loc_str = TARDISLocationGetters.makeLocationStr(world, startx, starty, startz); break; default: // cake - handbrake ctype = 0; loc_str = TARDISLocationGetters.makeLocationStr(world, startx, starty, startz); } qf.insertControl(tardis_id, ctype, loc_str, secondary); } } if (room.equals("ZERO")) { // remember the button String loc_str; if (type.equals(Material.WOOD_BUTTON)) { loc_str = TARDISLocationGetters.makeLocationStr(world, startx, starty, startz); qf.insertControl(tardis_id, 17, loc_str, 0); } } startz += 1; col++; if (col == c && row < w) { col = 0; startz = resetz; startx += 1; row++; } if (col == c && row == w && level < h) { col = 0; row = 0; startx = resetx; startz = resetz; starty += 1; int percent = TARDISNumberParsers.roundUp(level * 100, h); if (percent > 0) { TARDISMessage.send(p, "ROOM_PERCENT", room, String.format("%d", percent)); } level++; } } } private boolean checkRoomNextDoor(Block b) { if (b.getLocation().getBlockZ() < (resetz + 10) && !b.getRelative(BlockFace.EAST).getType().equals(Material.AIR)) { return true; } else if (!b.getRelative(BlockFace.SOUTH).getType().equals(Material.AIR)) { return true; } return false; } public void setTask(int task) { this.task = task; } }