package com.intellectualcrafters.plot.generator; import com.intellectualcrafters.configuration.ConfigurationSection; import com.intellectualcrafters.jnbt.CompoundTag; import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.object.BlockLoc; import com.intellectualcrafters.plot.object.PlotArea; import com.intellectualcrafters.plot.object.PlotBlock; import com.intellectualcrafters.plot.object.PlotId; import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.MathMan; import com.intellectualcrafters.plot.util.SchematicHandler; import com.intellectualcrafters.plot.util.SchematicHandler.Dimension; import com.intellectualcrafters.plot.util.SchematicHandler.Schematic; import java.io.File; import java.util.HashMap; import java.util.Map; public class HybridPlotWorld extends ClassicPlotWorld { public boolean ROAD_SCHEMATIC_ENABLED; public boolean PLOT_SCHEMATIC = false; public short PATH_WIDTH_LOWER; public short PATH_WIDTH_UPPER; public HashMap<Integer, char[]> G_SCH; public HashMap<Integer, HashMap<Integer, CompoundTag>> G_SCH_STATE; public HybridPlotWorld(String worldName, String id, IndependentPlotGenerator generator, PlotId min, PlotId max) { super(worldName, id, generator, min, max); } public static byte wrap(byte data, int start) { if ((data >= start) && (data < (start + 4))) { data = (byte) ((((data - start) + 2) & 3) + start); } return data; } public static byte wrap2(byte data, int start) { if ((data >= start) && (data < (start + 2))) { data = (byte) ((((data - start) + 1) & 1) + start); } return data; } // FIXME depends on block ids // Possibly make abstract? public static byte rotate(short id, byte data) { switch (id) { case 162: case 17: if (data >= 4 && data < 12) { if (data >= 8) { return (byte) (data - 4); } return (byte) (data + 4); } return data; case 26: // bed case 86: // pumpkin case 91: case 183: // fence gate case 184: case 185: case 186: case 187: case 107: data = wrap2(data, 0); data = wrap2(data, 2); data = wrap2(data, 4); data = wrap2(data, 6); return data; case 53: case 67: case 108: case 109: case 114: case 128: case 134: case 135: case 136: case 156: case 163: case 164: case 180: case 64: case 71: case 193: case 194: case 195: case 196: case 197: case 93: case 94: case 131: case 145: case 149: case 150: case 96: case 167: data = wrap(data, 0); data = wrap(data, 4); data = wrap(data, 8); data = wrap(data, 12); return data; case 28: case 66: case 157: case 27: data = wrap2(data, 0); data = wrap2(data, 3); if (data == 2) { data = 5; } else if (data == 5) { data = 2; } return data; case 23: case 29: case 33: case 158: case 54: case 130: case 146: case 61: case 62: case 65: case 68: case 144: data = wrap(data, 2); return data; case 143: case 77: data = wrap(data, 1); return data; default: return data; } } /** * <p>This method is called when a world loads. Make sure you set all your constants here. You are provided with the * configuration section for that specific world.</p> */ @Override public void loadConfiguration(ConfigurationSection config) { super.loadConfiguration(config); if ((this.ROAD_WIDTH & 1) == 0) { this.PATH_WIDTH_LOWER = (short) (Math.floor(this.ROAD_WIDTH / 2) - 1); } else { this.PATH_WIDTH_LOWER = (short) Math.floor(this.ROAD_WIDTH / 2); } if (this.ROAD_WIDTH == 0) { this.PATH_WIDTH_UPPER = (short) (this.SIZE + 1); } else { this.PATH_WIDTH_UPPER = (short) (this.PATH_WIDTH_LOWER + this.PLOT_WIDTH + 1); } try { setupSchematics(); } catch (Exception ignored) { PS.debug("&c - road schematics are disabled for this world."); } } @Override public boolean isCompatible(PlotArea plotArea) { if (!(plotArea instanceof SquarePlotWorld)) { return false; } return ((SquarePlotWorld) plotArea).PLOT_WIDTH == this.PLOT_WIDTH; } public void setupSchematics() { this.G_SCH = new HashMap<>(); File schematic1File = MainUtil.getFile(PS.get().IMP.getDirectory(), "schematics/GEN_ROAD_SCHEMATIC/" + this.worldname + "/sideroad.schematic"); File schematic2File = MainUtil.getFile(PS.get().IMP.getDirectory(), "schematics/GEN_ROAD_SCHEMATIC/" + this.worldname + "/intersection.schematic"); File schem3File = MainUtil.getFile(PS.get().IMP.getDirectory(), "schematics/GEN_ROAD_SCHEMATIC/" + this.worldname + "/plot.schematic"); Schematic schematic1 = SchematicHandler.manager.getSchematic(schematic1File); Schematic schematic2 = SchematicHandler.manager.getSchematic(schematic2File); Schematic schematic3 = SchematicHandler.manager.getSchematic(schem3File); int shift = this.ROAD_WIDTH / 2; int oddshift = (this.ROAD_WIDTH & 1) == 0 ? 0 : 1; int minY = Math.min(PLOT_HEIGHT, ROAD_HEIGHT); if (schematic3 != null) { this.PLOT_SCHEMATIC = true; short[] ids = schematic3.getIds(); byte[] datas = schematic3.getDatas(); Dimension d3 = schematic3.getSchematicDimension(); short w3 = (short) d3.getX(); short l3 = (short) d3.getZ(); short h3 = (short) d3.getY(); int centerShiftZ = 0; if (l3 < this.PLOT_WIDTH) { centerShiftZ = (this.PLOT_WIDTH - l3) / 2; } int centerShiftX = 0; if (w3 < this.PLOT_WIDTH) { centerShiftX = (this.PLOT_WIDTH - w3) / 2; } int startY = minY - PLOT_HEIGHT; for (short x = 0; x < w3; x++) { for (short z = 0; z < l3; z++) { for (short y = 0; y < h3; y++) { int index = (y * w3 * l3) + (z * w3) + x; short id = ids[index]; byte data = datas[index]; if (id != 0) { addOverlayBlock((short) (x + shift + oddshift + centerShiftX), (short) (y + startY), (short) (z + shift + oddshift + centerShiftZ), id, data, false, h3); } } } } HashMap<BlockLoc, CompoundTag> items = schematic3.getTiles(); if (!items.isEmpty()) { this.G_SCH_STATE = new HashMap<>(); for (Map.Entry<BlockLoc, CompoundTag> entry : items.entrySet()) { BlockLoc loc = entry.getKey(); short x = (short) (loc.x + shift + oddshift + centerShiftX); short z = (short) (loc.z + shift + oddshift + centerShiftZ); short y = (short) (loc.y + this.PLOT_HEIGHT); int pair = MathMan.pair(x, z); HashMap<Integer, CompoundTag> existing = this.G_SCH_STATE.get(pair); if (existing == null) { existing = new HashMap<>(); this.G_SCH_STATE.put(pair, existing); } existing.put((int) y, entry.getValue()); } } } if (schematic1 == null || schematic2 == null || this.ROAD_WIDTH == 0) { PS.debug(C.PREFIX + "&3 - schematic: &7false"); return; } this.ROAD_SCHEMATIC_ENABLED = true; // Do not populate road if using schematic population this.ROAD_BLOCK = PlotBlock.get(this.ROAD_BLOCK.id, (byte) 0); short[] ids1 = schematic1.getIds(); byte[] datas1 = schematic1.getDatas(); short[] ids2 = schematic2.getIds(); byte[] datas2 = schematic2.getDatas(); Dimension d1 = schematic1.getSchematicDimension(); short w1 = (short) d1.getX(); short l1 = (short) d1.getZ(); short h1 = (short) d1.getY(); Dimension d2 = schematic2.getSchematicDimension(); short w2 = (short) d2.getX(); short l2 = (short) d2.getZ(); short h2 = (short) d2.getY(); int startY = minY - ROAD_HEIGHT; for (short x = 0; x < w1; x++) { for (short z = 0; z < l1; z++) { for (short y = 0; y < h1; y++) { int index = (y * w1 * l1) + (z * w1) + x; short id = ids1[index]; byte data = datas1[index]; if (id != 0) { addOverlayBlock((short) (x - shift), (short) (y + startY), (short) (z + shift + oddshift), id, data, false, h1); addOverlayBlock((short) (z + shift + oddshift), (short) (y + startY), (short) (x - shift), id, data, true, h1); } } } } for (short x = 0; x < w2; x++) { for (short z = 0; z < l2; z++) { for (short y = 0; y < h2; y++) { int index = (y * w2 * l2) + (z * w2) + x; short id = ids2[index]; byte data = datas2[index]; if (id != 0) { addOverlayBlock((short) (x - shift), (short) (y + startY), (short) (z - shift), id, data, false, h2); } } } } } public void addOverlayBlock(short x, short y, short z, short id, byte data, boolean rotate, int height) { if (z < 0) { z += this.SIZE; } if (x < 0) { x += this.SIZE; } if (rotate) { byte newData = rotate(id, data); if (data != 0 || newData != 0) { data = newData; } } int pair = MathMan.pair(x, z); char[] existing = this.G_SCH.get(pair); if (existing == null) { existing = new char[height]; this.G_SCH.put(pair, existing); } if (id == 0) { data = 1; } existing[y] = (char) ((id << 4) + data); } }