forked from LogBlock/LogBlock
Not every material has a BlockData
This commit is contained in:
@ -20,6 +20,16 @@ public class MaterialConverter {
|
||||
private static String[] idToBlockState = new String[10];
|
||||
private static HashMap<String, Integer> blockStateToID = new HashMap<>();
|
||||
private static int nextBlockStateId;
|
||||
|
||||
private static HashMap<String, Material> materialKeyToMaterial = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (Material m : Material.values()) {
|
||||
if (!m.name().startsWith("LEGACY_") && m.getKey() != null) {
|
||||
materialKeyToMaterial.put(m.getKey().toString(), m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static int getOrAddMaterialId(NamespacedKey nameSpaceKey) {
|
||||
return getOrAddMaterialId(nameSpaceKey.toString());
|
||||
@ -80,7 +90,11 @@ public class MaterialConverter {
|
||||
}
|
||||
|
||||
public static Material getMaterial(int materialId) {
|
||||
return getBlockData(materialId, -1).getMaterial();
|
||||
String material = idToMaterial[materialId];
|
||||
if (materialId >= 0) {
|
||||
material = material + idToBlockState[materialId];
|
||||
}
|
||||
return materialKeyToMaterial.get(material);
|
||||
}
|
||||
|
||||
public static void initializeMaterials(Connection connection) throws SQLException {
|
||||
|
@ -1,288 +1,291 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.Bisected.Half;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Bed;
|
||||
import org.bukkit.block.data.type.Bed.Part;
|
||||
import org.bukkit.block.data.type.Door;
|
||||
import org.bukkit.block.data.type.Piston;
|
||||
import org.bukkit.block.data.type.PistonHead;
|
||||
import org.bukkit.block.data.type.TechnicalPiston.Type;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.dontRollback;
|
||||
import static de.diddiz.LogBlock.config.Config.replaceAnyway;
|
||||
import static de.diddiz.util.BukkitUtils.*;
|
||||
import static org.bukkit.Bukkit.getLogger;
|
||||
|
||||
public class WorldEditor implements Runnable {
|
||||
private final LogBlock logblock;
|
||||
private final Queue<Edit> edits = new LinkedBlockingQueue<Edit>();
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* The player responsible for editing the world, used to report progress
|
||||
*/
|
||||
private CommandSender sender;
|
||||
private int taskID;
|
||||
private int successes = 0, blacklistCollisions = 0;
|
||||
private long elapsedTime = 0;
|
||||
public LookupCacheElement[] errors;
|
||||
|
||||
public WorldEditor(LogBlock logblock, World world) {
|
||||
this.logblock = logblock;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return edits.size();
|
||||
}
|
||||
|
||||
public int getSuccesses() {
|
||||
return successes;
|
||||
}
|
||||
|
||||
public int getErrors() {
|
||||
return errors.length;
|
||||
}
|
||||
|
||||
public int getBlacklistCollisions() {
|
||||
return blacklistCollisions;
|
||||
}
|
||||
|
||||
|
||||
public void setSender(CommandSender sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public void queueEdit(int x, int y, int z, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess item) {
|
||||
edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, type, typeData, signtext, item));
|
||||
}
|
||||
|
||||
public long getElapsedTime() {
|
||||
return elapsedTime;
|
||||
}
|
||||
|
||||
synchronized public void start() throws Exception {
|
||||
final long start = System.currentTimeMillis();
|
||||
taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1);
|
||||
if (taskID == -1) {
|
||||
throw new Exception("Failed to schedule task");
|
||||
}
|
||||
try {
|
||||
this.wait();
|
||||
} catch (final InterruptedException ex) {
|
||||
throw new Exception("Interrupted");
|
||||
}
|
||||
elapsedTime = System.currentTimeMillis() - start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void run() {
|
||||
final List<WorldEditorException> errorList = new ArrayList<WorldEditorException>();
|
||||
int counter = 0;
|
||||
float size = edits.size();
|
||||
while (!edits.isEmpty() && counter < 100) {
|
||||
try {
|
||||
switch (edits.poll().perform()) {
|
||||
case SUCCESS:
|
||||
successes++;
|
||||
break;
|
||||
case BLACKLISTED:
|
||||
blacklistCollisions++;
|
||||
break;
|
||||
case NO_ACTION:
|
||||
break;
|
||||
}
|
||||
} catch (final WorldEditorException ex) {
|
||||
errorList.add(ex);
|
||||
} catch (final Exception ex) {
|
||||
getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex);
|
||||
}
|
||||
counter++;
|
||||
if (sender != null) {
|
||||
float percentage = ((size - edits.size()) / size) * 100.0F;
|
||||
if (percentage % 20 == 0) {
|
||||
sender.sendMessage(ChatColor.GOLD + "[LogBlock]" + ChatColor.YELLOW + " Rollback progress: " + percentage + "%" +
|
||||
" Blocks edited: " + counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (edits.isEmpty()) {
|
||||
logblock.getServer().getScheduler().cancelTask(taskID);
|
||||
if (errorList.size() > 0) {
|
||||
try {
|
||||
final File file = new File("plugins/LogBlock/error/WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log");
|
||||
file.getParentFile().mkdirs();
|
||||
final PrintWriter writer = new PrintWriter(file);
|
||||
for (final LookupCacheElement err : errorList) {
|
||||
writer.println(err.getMessage());
|
||||
}
|
||||
writer.close();
|
||||
} catch (final Exception ex) {
|
||||
}
|
||||
}
|
||||
errors = errorList.toArray(new WorldEditorException[errorList.size()]);
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
private static enum PerformResult {
|
||||
SUCCESS, BLACKLISTED, NO_ACTION
|
||||
}
|
||||
|
||||
private class Edit extends BlockChange {
|
||||
public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess ca) {
|
||||
super(time, loc, actor, replaced, replaceData, type, typeData, signtext, ca);
|
||||
}
|
||||
|
||||
PerformResult perform() throws WorldEditorException {
|
||||
BlockData replacedBlock = MaterialConverter.getBlockData(this.replacedMaterial, replacedData);
|
||||
BlockData setBlock = MaterialConverter.getBlockData(this.typeMaterial, typeData);
|
||||
// action: set to replaced
|
||||
|
||||
if (dontRollback.contains(replacedBlock.getMaterial())) {
|
||||
return PerformResult.BLACKLISTED;
|
||||
}
|
||||
final Block block = loc.getBlock();
|
||||
if (replacedBlock.getMaterial() == Material.AIR && block.getType() == Material.AIR) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
final BlockState state = block.getState();
|
||||
if (!world.isChunkLoaded(block.getChunk())) {
|
||||
world.loadChunk(block.getChunk());
|
||||
}
|
||||
if (setBlock.equals(replacedBlock)) {
|
||||
if (setBlock.getMaterial() == Material.AIR) {
|
||||
block.setType(Material.AIR);
|
||||
} else if (ca != null) {
|
||||
if (state instanceof InventoryHolder) {
|
||||
int leftover;
|
||||
try {
|
||||
leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove);
|
||||
// Special-case blocks which might be double chests
|
||||
if (leftover > 0 && (setBlock.getMaterial() == Material.CHEST || setBlock.getMaterial() == Material.TRAPPED_CHEST)) {
|
||||
for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) {
|
||||
if (block.getRelative(face).getType() == setBlock.getMaterial()) {
|
||||
ItemStack remaining = new ItemStack(ca.itemStack);
|
||||
remaining.setAmount(leftover);
|
||||
leftover = modifyContainer(block.getRelative(face).getState(), remaining, !ca.remove);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Exception ex) {
|
||||
throw new WorldEditorException(ex.getMessage(), block.getLocation());
|
||||
}
|
||||
if (leftover > 0 && ca.remove) {
|
||||
throw new WorldEditorException("Not enough space left in " + block.getType(), block.getLocation());
|
||||
}
|
||||
}
|
||||
} else if (!block.getBlockData().equals(replacedBlock)) {
|
||||
block.setBlockData(replacedBlock);
|
||||
} else {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
if (block.getType() != setBlock.getMaterial() && !replaceAnyway.contains(block.getType())) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
if (state instanceof InventoryHolder) {
|
||||
((InventoryHolder) state).getInventory().clear();
|
||||
state.update();
|
||||
}
|
||||
block.setBlockData(replacedBlock);
|
||||
BlockData newData = block.getBlockData();
|
||||
|
||||
final Material curtype = block.getType();
|
||||
if (signtext != null && (curtype == Material.SIGN || curtype == Material.WALL_SIGN)) {
|
||||
final Sign sign = (Sign) block.getState();
|
||||
final String[] lines = signtext.split("\0", 4);
|
||||
if (lines.length < 4) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sign.setLine(i, lines[i]);
|
||||
}
|
||||
if (!sign.update()) {
|
||||
throw new WorldEditorException("Failed to update signtext of " + block.getType(), block.getLocation());
|
||||
}
|
||||
} else if (newData instanceof Bed) {
|
||||
final Bed bed = (Bed) newData;
|
||||
final Block secBlock = bed.getPart() == Part.HEAD ? block.getRelative(bed.getFacing().getOppositeFace()) : block.getRelative(bed.getFacing());
|
||||
if (secBlock.isEmpty()) {
|
||||
Bed bed2 = (Bed) bed.clone();
|
||||
bed2.setPart(bed.getPart() == Part.HEAD ? Part.FOOT : Part.HEAD);
|
||||
secBlock.setBlockData(bed2);
|
||||
}
|
||||
} else if (newData instanceof Door) {
|
||||
final Door door = (Door) newData;
|
||||
final Block secBlock = door.getHalf() == Half.TOP ? block.getRelative(BlockFace.DOWN) : block.getRelative(BlockFace.UP);
|
||||
if (secBlock.isEmpty()) {
|
||||
Door door2 = (Door) door.clone();
|
||||
door2.setHalf(door.getHalf() == Half.TOP ? Half.BOTTOM : Half.TOP);
|
||||
secBlock.setBlockData(door2);
|
||||
}
|
||||
} else if ((curtype == Material.PISTON || curtype == Material.STICKY_PISTON)) {
|
||||
Piston piston = (Piston) newData;
|
||||
if (piston.isExtended()) {
|
||||
final Block secBlock = block.getRelative(piston.getFacing());
|
||||
if (secBlock.isEmpty()) {
|
||||
PistonHead head = (PistonHead) Material.PISTON_HEAD.createBlockData();
|
||||
head.setFacing(piston.getFacing());
|
||||
head.setType(curtype == Material.PISTON ? Type.NORMAL : Type.STICKY);
|
||||
secBlock.setBlockData(head);
|
||||
}
|
||||
}
|
||||
} else if (curtype == Material.PISTON_HEAD) {
|
||||
PistonHead head = (PistonHead) newData;
|
||||
final Block secBlock = block.getRelative(head.getFacing().getOppositeFace());
|
||||
if (secBlock.isEmpty()) {
|
||||
Piston piston = (Piston) (head.getType() == Type.NORMAL ? Material.PISTON : Material.STICKY_PISTON).createBlockData();
|
||||
piston.setFacing(head.getFacing());
|
||||
piston.setExtended(true);
|
||||
secBlock.setBlockData(piston);
|
||||
}
|
||||
}
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class WorldEditorException extends Exception implements LookupCacheElement {
|
||||
private final Location loc;
|
||||
|
||||
public WorldEditorException(Material typeBefore, Material typeAfter, Location loc) {
|
||||
this("Failed to replace " + typeBefore.name() + " with " + typeAfter.name(), loc);
|
||||
}
|
||||
|
||||
public WorldEditorException(String msg, Location loc) {
|
||||
super(msg + " at " + loc.getWorld().getName() + ":" + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ());
|
||||
this.loc = loc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return loc;
|
||||
}
|
||||
}
|
||||
}
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.Bisected.Half;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Bed;
|
||||
import org.bukkit.block.data.type.Bed.Part;
|
||||
import org.bukkit.block.data.type.Door;
|
||||
import org.bukkit.block.data.type.Piston;
|
||||
import org.bukkit.block.data.type.PistonHead;
|
||||
import org.bukkit.block.data.type.TechnicalPiston.Type;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static de.diddiz.LogBlock.config.Config.dontRollback;
|
||||
import static de.diddiz.LogBlock.config.Config.replaceAnyway;
|
||||
import static de.diddiz.util.BukkitUtils.*;
|
||||
import static org.bukkit.Bukkit.getLogger;
|
||||
|
||||
public class WorldEditor implements Runnable {
|
||||
private final LogBlock logblock;
|
||||
private final Queue<Edit> edits = new LinkedBlockingQueue<Edit>();
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* The player responsible for editing the world, used to report progress
|
||||
*/
|
||||
private CommandSender sender;
|
||||
private int taskID;
|
||||
private int successes = 0, blacklistCollisions = 0;
|
||||
private long elapsedTime = 0;
|
||||
public LookupCacheElement[] errors;
|
||||
|
||||
public WorldEditor(LogBlock logblock, World world) {
|
||||
this.logblock = logblock;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return edits.size();
|
||||
}
|
||||
|
||||
public int getSuccesses() {
|
||||
return successes;
|
||||
}
|
||||
|
||||
public int getErrors() {
|
||||
return errors.length;
|
||||
}
|
||||
|
||||
public int getBlacklistCollisions() {
|
||||
return blacklistCollisions;
|
||||
}
|
||||
|
||||
|
||||
public void setSender(CommandSender sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public void queueEdit(int x, int y, int z, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess item) {
|
||||
edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, type, typeData, signtext, item));
|
||||
}
|
||||
|
||||
public long getElapsedTime() {
|
||||
return elapsedTime;
|
||||
}
|
||||
|
||||
synchronized public void start() throws Exception {
|
||||
final long start = System.currentTimeMillis();
|
||||
taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1);
|
||||
if (taskID == -1) {
|
||||
throw new Exception("Failed to schedule task");
|
||||
}
|
||||
try {
|
||||
this.wait();
|
||||
} catch (final InterruptedException ex) {
|
||||
throw new Exception("Interrupted");
|
||||
}
|
||||
elapsedTime = System.currentTimeMillis() - start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void run() {
|
||||
final List<WorldEditorException> errorList = new ArrayList<WorldEditorException>();
|
||||
int counter = 0;
|
||||
float size = edits.size();
|
||||
while (!edits.isEmpty() && counter < 100) {
|
||||
try {
|
||||
switch (edits.poll().perform()) {
|
||||
case SUCCESS:
|
||||
successes++;
|
||||
break;
|
||||
case BLACKLISTED:
|
||||
blacklistCollisions++;
|
||||
break;
|
||||
case NO_ACTION:
|
||||
break;
|
||||
}
|
||||
} catch (final WorldEditorException ex) {
|
||||
errorList.add(ex);
|
||||
} catch (final Exception ex) {
|
||||
getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex);
|
||||
}
|
||||
counter++;
|
||||
if (sender != null) {
|
||||
float percentage = ((size - edits.size()) / size) * 100.0F;
|
||||
if (percentage % 20 == 0) {
|
||||
sender.sendMessage(ChatColor.GOLD + "[LogBlock]" + ChatColor.YELLOW + " Rollback progress: " + percentage + "%" +
|
||||
" Blocks edited: " + counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (edits.isEmpty()) {
|
||||
logblock.getServer().getScheduler().cancelTask(taskID);
|
||||
if (errorList.size() > 0) {
|
||||
try {
|
||||
final File file = new File("plugins/LogBlock/error/WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log");
|
||||
file.getParentFile().mkdirs();
|
||||
final PrintWriter writer = new PrintWriter(file);
|
||||
for (final LookupCacheElement err : errorList) {
|
||||
writer.println(err.getMessage());
|
||||
}
|
||||
writer.close();
|
||||
} catch (final Exception ex) {
|
||||
}
|
||||
}
|
||||
errors = errorList.toArray(new WorldEditorException[errorList.size()]);
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
private static enum PerformResult {
|
||||
SUCCESS, BLACKLISTED, NO_ACTION
|
||||
}
|
||||
|
||||
private class Edit extends BlockChange {
|
||||
public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess ca) {
|
||||
super(time, loc, actor, replaced, replaceData, type, typeData, signtext, ca);
|
||||
}
|
||||
|
||||
PerformResult perform() throws WorldEditorException {
|
||||
BlockData replacedBlock = MaterialConverter.getBlockData(this.replacedMaterial, replacedData);
|
||||
BlockData setBlock = MaterialConverter.getBlockData(this.typeMaterial, typeData);
|
||||
if (replacedBlock == null || setBlock == null) {
|
||||
throw new WorldEditorException("Could not parse the material", loc.clone());
|
||||
}
|
||||
// action: set to replaced
|
||||
|
||||
if (dontRollback.contains(replacedBlock.getMaterial())) {
|
||||
return PerformResult.BLACKLISTED;
|
||||
}
|
||||
final Block block = loc.getBlock();
|
||||
if (replacedBlock.getMaterial() == Material.AIR && block.getType() == Material.AIR) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
final BlockState state = block.getState();
|
||||
if (!world.isChunkLoaded(block.getChunk())) {
|
||||
world.loadChunk(block.getChunk());
|
||||
}
|
||||
if (setBlock.equals(replacedBlock)) {
|
||||
if (setBlock.getMaterial() == Material.AIR) {
|
||||
block.setType(Material.AIR);
|
||||
} else if (ca != null) {
|
||||
if (state instanceof InventoryHolder) {
|
||||
int leftover;
|
||||
try {
|
||||
leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove);
|
||||
// Special-case blocks which might be double chests
|
||||
if (leftover > 0 && (setBlock.getMaterial() == Material.CHEST || setBlock.getMaterial() == Material.TRAPPED_CHEST)) {
|
||||
for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) {
|
||||
if (block.getRelative(face).getType() == setBlock.getMaterial()) {
|
||||
ItemStack remaining = new ItemStack(ca.itemStack);
|
||||
remaining.setAmount(leftover);
|
||||
leftover = modifyContainer(block.getRelative(face).getState(), remaining, !ca.remove);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Exception ex) {
|
||||
throw new WorldEditorException(ex.getMessage(), block.getLocation());
|
||||
}
|
||||
if (leftover > 0 && ca.remove) {
|
||||
throw new WorldEditorException("Not enough space left in " + block.getType(), block.getLocation());
|
||||
}
|
||||
}
|
||||
} else if (!block.getBlockData().equals(replacedBlock)) {
|
||||
block.setBlockData(replacedBlock);
|
||||
} else {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
if (block.getType() != setBlock.getMaterial() && !replaceAnyway.contains(block.getType())) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
if (state instanceof InventoryHolder) {
|
||||
((InventoryHolder) state).getInventory().clear();
|
||||
state.update();
|
||||
}
|
||||
block.setBlockData(replacedBlock);
|
||||
BlockData newData = block.getBlockData();
|
||||
|
||||
final Material curtype = block.getType();
|
||||
if (signtext != null && (curtype == Material.SIGN || curtype == Material.WALL_SIGN)) {
|
||||
final Sign sign = (Sign) block.getState();
|
||||
final String[] lines = signtext.split("\0", 4);
|
||||
if (lines.length < 4) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sign.setLine(i, lines[i]);
|
||||
}
|
||||
if (!sign.update()) {
|
||||
throw new WorldEditorException("Failed to update signtext of " + block.getType(), block.getLocation());
|
||||
}
|
||||
} else if (newData instanceof Bed) {
|
||||
final Bed bed = (Bed) newData;
|
||||
final Block secBlock = bed.getPart() == Part.HEAD ? block.getRelative(bed.getFacing().getOppositeFace()) : block.getRelative(bed.getFacing());
|
||||
if (secBlock.isEmpty()) {
|
||||
Bed bed2 = (Bed) bed.clone();
|
||||
bed2.setPart(bed.getPart() == Part.HEAD ? Part.FOOT : Part.HEAD);
|
||||
secBlock.setBlockData(bed2);
|
||||
}
|
||||
} else if (newData instanceof Door) {
|
||||
final Door door = (Door) newData;
|
||||
final Block secBlock = door.getHalf() == Half.TOP ? block.getRelative(BlockFace.DOWN) : block.getRelative(BlockFace.UP);
|
||||
if (secBlock.isEmpty()) {
|
||||
Door door2 = (Door) door.clone();
|
||||
door2.setHalf(door.getHalf() == Half.TOP ? Half.BOTTOM : Half.TOP);
|
||||
secBlock.setBlockData(door2);
|
||||
}
|
||||
} else if ((curtype == Material.PISTON || curtype == Material.STICKY_PISTON)) {
|
||||
Piston piston = (Piston) newData;
|
||||
if (piston.isExtended()) {
|
||||
final Block secBlock = block.getRelative(piston.getFacing());
|
||||
if (secBlock.isEmpty()) {
|
||||
PistonHead head = (PistonHead) Material.PISTON_HEAD.createBlockData();
|
||||
head.setFacing(piston.getFacing());
|
||||
head.setType(curtype == Material.PISTON ? Type.NORMAL : Type.STICKY);
|
||||
secBlock.setBlockData(head);
|
||||
}
|
||||
}
|
||||
} else if (curtype == Material.PISTON_HEAD) {
|
||||
PistonHead head = (PistonHead) newData;
|
||||
final Block secBlock = block.getRelative(head.getFacing().getOppositeFace());
|
||||
if (secBlock.isEmpty()) {
|
||||
Piston piston = (Piston) (head.getType() == Type.NORMAL ? Material.PISTON : Material.STICKY_PISTON).createBlockData();
|
||||
piston.setFacing(head.getFacing());
|
||||
piston.setExtended(true);
|
||||
secBlock.setBlockData(piston);
|
||||
}
|
||||
}
|
||||
return PerformResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class WorldEditorException extends Exception implements LookupCacheElement {
|
||||
private final Location loc;
|
||||
|
||||
public WorldEditorException(Material typeBefore, Material typeAfter, Location loc) {
|
||||
this("Failed to replace " + typeBefore.name() + " with " + typeAfter.name(), loc);
|
||||
}
|
||||
|
||||
public WorldEditorException(String msg, Location loc) {
|
||||
super(msg + " at " + loc.getWorld().getName() + ":" + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ());
|
||||
this.loc = loc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return loc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user