diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java index d44624da3..3423c04ef 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; import java.util.Map; +import java.util.function.Function; import javax.annotation.Nullable; @@ -50,8 +51,7 @@ public class BukkitBlockRegistry extends BundledBlockRegistry { if (type == null) { type = Material.AIR; } - return materialMap.computeIfAbsent(type, - material -> new BukkitBlockMaterial(BukkitBlockRegistry.super.getMaterial(blockType), material)); + return materialMap.computeIfAbsent(type, m -> new BukkitBlockMaterial(BukkitBlockRegistry.super.getMaterial(blockType), m)); } @Nullable @@ -72,6 +72,18 @@ public class BukkitBlockRegistry extends BundledBlockRegistry { this.material = bukkitMaterial; } + @Override + public boolean isAir() { + switch (material) { + case AIR: + case CAVE_AIR: + case VOID_AIR: + return true; + default: + return false; + } + } + @Override public boolean isSolid() { return material.isSolid(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java index 542f7f794..6181395ec 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java @@ -179,7 +179,10 @@ public class Fawe { } public static void debugPlain(String s) { - if (INSTANCE != null) { + Actor actor = Request.request().getActor(); + if (actor != null) { + actor.print(BBC.color(s)); + } else if (INSTANCE != null) { INSTANCE.IMP.debug(s); } else { System.out.println(BBC.stripColor(BBC.color(s))); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/TaskManager.java b/worldedit-core/src/main/java/com/boydti/fawe/util/TaskManager.java index 2663924e8..12681e38f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/TaskManager.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/TaskManager.java @@ -404,9 +404,9 @@ public abstract class TaskManager { MainUtil.handleError(neverHappens); } finally { running.set(false); - } - synchronized (function) { - function.notifyAll(); + synchronized (function) { + function.notifyAll(); + } } } }; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java index 57e917386..36f80aa9b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java @@ -10,6 +10,8 @@ import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BlockMaterial; +import com.sk89q.worldedit.util.command.binding.Text; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; @@ -533,6 +535,36 @@ public class TextureUtil implements TextureHolder{ return colorDistance(red1, green1, blue1, c2); } + public static void main(String[] args) throws IOException { + File tf = new File("1.13.jar"); + ZipFile zipFile = new ZipFile(tf); + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + System.out.println(entries.nextElement().getName()); + } +// TextureUtil tu = new TextureUtil(new File(".")); +// tu.loadModTextures(); + } + + private BufferedImage readImage(ZipFile zipFile, String name) throws IOException { + ZipEntry entry = getEntry(zipFile, name); + if (entry != null) { + try (InputStream is = zipFile.getInputStream(entry)) { + return ImageIO.read(is); + } + } + return null; + } + + private ZipEntry getEntry(ZipFile file, String path) { + ZipEntry entry = file.getEntry(path); + if (entry == null) { + path = path.replace("/", File.separator); + entry = file.getEntry(path); + } + return entry; + } + public void loadModTextures() throws IOException { Int2ObjectOpenHashMap colorMap = new Int2ObjectOpenHashMap<>(); Int2ObjectOpenHashMap distanceMap = new Int2ObjectOpenHashMap<>(); @@ -545,224 +577,188 @@ public class TextureUtil implements TextureHolder{ return name.endsWith(".jar"); } }); - if (files.length == 0) { - throw new FileNotFoundException("Please create a `FastAsyncWorldEdit/textures` folder with `.minecraft/versions` jar or mods in it." + - "If the file exists, please make sure the server has read access to the directory"); - } - for (File file : files) { - ZipFile zipFile = new ZipFile(file); - - // Get all the groups in the current jar - // The vanilla textures are in `assets/minecraft` - // A jar may contain textures for multiple mods - Set mods = new HashSet(); - { - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - String name = entry.getName(); - Path path = Paths.get(name); - if (path.startsWith("assets" + File.separator)) { - String[] split = path.toString().split(Pattern.quote(File.separator)); - if (split.length > 1) { - String modId = split[1]; - mods.add(modId); - } - } - continue; - } + for (BlockType blockType : BlockTypes.values) { + BlockMaterial material = blockType.getMaterial(); + if (!material.isSolid() || !material.isFullCube()) continue; + int color = material.getMapColor(); + if (color != 0) { + colorMap.put((int) blockType.getInternalId(), (Integer) color); } - String modelsDir = "assets" + File.separator + "%1$s" + File.separator + "models" + File.separator + "block" + File.separator + "%2$s.json"; - String texturesDir = "assets" + File.separator + "%1$s" + File.separator + "textures" + File.separator + "blocks" + File.separator + "%2$s.json"; + } + if (files.length == 0) { + Fawe.debug("Please create a `FastAsyncWorldEdit/textures` folder with `.minecraft/versions/1.13.jar` jar or mods in it. If the file exists, please make sure the server has read access to the directory"); + } else { + for (File file : files) { + ZipFile zipFile = new ZipFile(file); - Type typeToken = new TypeToken>() {}.getType(); - - for (BlockType blockType : BlockTypes.values) { - if (!blockType.getMaterial().isFullCube()) continue; - - String id = blockType.getId(); - String[] split = id.split(":", 2); - String name = split.length == 1 ? id : split[1]; - String nameSpace = split.length == 1 ? "minecraft" : split[0]; - - Map texturesMap = new ConcurrentHashMap<>(); - { // Read models - String modelFileName = String.format(modelsDir, nameSpace, name); - ZipEntry entry = zipFile.getEntry(modelFileName); - if (entry == null) continue; - - try (InputStream is = zipFile.getInputStream(entry)) { //Read from a file, or a HttpRequest, or whatever. - JsonReader reader = new JsonReader(new InputStreamReader(is, "UTF-8")); - Map root = gson.fromJson(reader, typeToken); - Map textures = (Map) root.get("textures"); - - if (textures == null) continue; - Set models = new HashSet<>(); - // Get models - for (Map.Entry stringObjectEntry : textures.entrySet()) { - Object value = stringObjectEntry.getValue(); - if (value instanceof String) { - models.add((String) value); - } else if (value instanceof Map) { - value = ((Map) value).get("model"); - if (value != null) models.add((String) value); + // Get all the groups in the current jar + // The vanilla textures are in `assets/minecraft` + // A jar may contain textures for multiple mods + Set mods = new HashSet(); + { + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + String name = entry.getName(); + Path path = Paths.get(name); + if (path.startsWith("assets" + File.separator)) { + String[] split = path.toString().split(Pattern.quote(File.separator)); + if (split.length > 1) { + String modId = split[1]; + mods.add(modId); } } - if (models.size() == 1) { - // get textures - } - // If texturs size == 1 - // Put texture in map + continue; } } -// // Try to match the textures to a block -// Int2ObjectOpenHashMap idMap = new Int2ObjectOpenHashMap<>(); -// HashSet map2 = new HashSet<>(); -// for (String id : bundled.stateMap.keySet()) { -// if (id.startsWith(modId)) { -// BlockType block = bundled.findByState(id); -// BundledBlockData.BlockEntry state = bundled.findById(block.getId()); -// if (FaweCache.hasNBT(block.getId())) { -// continue; -// } -// // Ignore non blocks -// if (!state.material.isFullCube() && !state.material.isRenderedAsNormalBlock()) { -// switch (block.getId()) { -// case 20: -// case 95: -// break; -// default: -// continue; -// } -// } else if (!state.material.isFullCube() || !state.material.isRenderedAsNormalBlock()) { -// switch (block.getId()) { -// case 165: -// case 52: -// continue; -// } -// } -// if (state.material.getLightValue() != 0) { -// continue; -// } -// id = id.substring(modId.length() + 1).replaceAll(":", "_"); -// String texture = texturesMap.remove(id); -// if (texture == null) { -// texture = texturesMap.remove(alphabetize(id)); -// } -// if (texture != null) { -// int combined = block.getCombined(); -// switch (block.getId()) { -// case 17: -// case 162: -// combined += 12; -// break; -// case 43: -// combined += 8; -// break; -// } -// idMap.putIfAbsent(combined, texture); -// } -// } -// } -// { // Calculate the colors for each block -// for (Int2ObjectMap.Entry entry : idMap.int2ObjectEntrySet()) { -// int combined = entry.getIntKey(); -// String path = texturesDir + "/" + entry.getValue() + ".png"; -// ZipEntry textureEntry = zipFile.getEntry(path); -// try (InputStream is = zipFile.getInputStream(textureEntry)) { -// BufferedImage image = ImageIO.read(is); -// int color = ImageUtil.getColor(image); -// long distance = getDistance(image, color); -// if (combined == BlockTypesMYCELIUM << 4) distance = Long.MAX_VALUE; -// distanceMap.put((int) combined, (Long) distance); -// colorMap.put((int) combined, (Integer) color); -// } -// } -// } + String modelsDir = "assets/%1$s/models/block/%2$s.json"; + String texturesDir = "assets/%1$s/textures/%2$s.png"; + + Type typeToken = new TypeToken>() { + }.getType(); + + for (BlockType blockType : BlockTypes.values) { + if (!blockType.getMaterial().isFullCube()) continue; + int combined = blockType.getInternalId(); + String id = blockType.getId(); + String[] split = id.split(":", 2); + String name = split.length == 1 ? id : split[1]; + String nameSpace = split.length == 1 ? "minecraft" : split[0]; + + Map texturesMap = new ConcurrentHashMap<>(); + { // Read models + String modelFileName = String.format(modelsDir, nameSpace, name); + ZipEntry entry = getEntry(zipFile, modelFileName); + if (entry == null) { + System.out.println("Cannot find " + modelFileName + " in " + file); + continue; + } + + String textureFileName; + try (InputStream is = zipFile.getInputStream(entry)) { + JsonReader reader = new JsonReader(new InputStreamReader(is, "UTF-8")); + Map root = gson.fromJson(reader, typeToken); + Map textures = (Map) root.get("textures"); + + if (textures == null) continue; + Set models = new HashSet<>(); + // Get models + for (Map.Entry stringObjectEntry : textures.entrySet()) { + Object value = stringObjectEntry.getValue(); + if (value instanceof String) { + models.add((String) value); + } else if (value instanceof Map) { + value = ((Map) value).get("model"); + if (value != null) models.add((String) value); + } + } + if (models.size() != 1) continue; + + textureFileName = String.format(texturesDir, nameSpace, models.iterator().next()); + } + + BufferedImage image = readImage(zipFile, textureFileName); + if (image == null) { + System.out.println("Cannot find " + textureFileName); + continue; + } + int color = ImageUtil.getColor(image); + long distance = getDistance(image, color); + distanceMap.put((int) combined, (Long) distance); + colorMap.put((int) combined, (Integer) color); + } + } + { + Integer grass = null; + { + String grassFileName = String.format(texturesDir, "minecraft", "grass_block_top"); + BufferedImage image = readImage(zipFile, grassFileName); + if (image != null) { + grass = ImageUtil.getColor(image); + } + } + if (grass != null) { + // assets\minecraft\textures\colormap + ZipEntry grassEntry = getEntry(zipFile, "assets/minecraft/textures/colormap/grass_block.png"); + if (grassEntry != null) { + try (InputStream is = zipFile.getInputStream(grassEntry)) { + BufferedImage image = ImageIO.read(is); + // Update biome colors + for (int i = 0; i < biomes.length; i++) { + BiomeColor biome = biomes[i]; + float adjTemp = MathMan.clamp(biome.temperature, 0.0f, 1.0f); + float adjRainfall = MathMan.clamp(biome.rainfall, 0.0f, 1.0f) * adjTemp; + int x = (int) (255 - adjTemp * 255); + int z = (int) (255 - adjRainfall * 255); + biome.grass = image.getRGB(x, z); + } + } + // swampland: perlin - avoid + biomes[6].grass = 0; + biomes[134].grass = 0; + // roofed forest: averaged w/ 0x28340A + biomes[29].grass = multiplyColor(biomes[29].grass, 0x28340A + (255 << 24)); + biomes[157].grass = multiplyColor(biomes[157].grass, 0x28340A + (255 << 24)); + // mesa : 0x90814D + biomes[37].grass = 0x90814D + (255 << 24); + biomes[38].grass = 0x90814D + (255 << 24); + biomes[39].grass = 0x90814D + (255 << 24); + biomes[165].grass = 0x90814D + (255 << 24); + biomes[166].grass = 0x90814D + (255 << 24); + biomes[167].grass = 0x90814D + (255 << 24); + List valid = new ArrayList<>(); + for (int i = 0; i < biomes.length; i++) { + BiomeColor biome = biomes[i]; +// biome.grass = multiplyColor(biome.grass, grass); + if (biome.grass != 0 && !biome.name.equalsIgnoreCase("Unknown Biome")) { + valid.add(biome); + } + biome.grassCombined = multiplyColor(grass, biome.grass); + } + this.validBiomes = valid.toArray(new BiomeColor[valid.size()]); + + { + ArrayList uniqueColors = new ArrayList<>(); + Set uniqueBiomesColors = new IntArraySet(); + for (BiomeColor color : validBiomes) { + if (uniqueBiomesColors.add(color.grass)) { + uniqueColors.add(color); + } + } + int count = 0; + int count2 = 0; + uniqueBiomesColors.clear(); + + LongArrayList layerIds = new LongArrayList(); + LongArrayList layerColors = new LongArrayList(); + for (int i = 0; i < uniqueColors.size(); i++) { + for (int j = i; j < uniqueColors.size(); j++) { + for (int k = j; k < uniqueColors.size(); k++) { + BiomeColor c1 = uniqueColors.get(i); + BiomeColor c2 = uniqueColors.get(j); + BiomeColor c3 = uniqueColors.get(k); + int average = averageColor(c1.grass, c2.grass, c3.grass); + if (uniqueBiomesColors.add(average)) { + count++; + layerColors.add((long) average); + layerIds.add((long) ((c1.id) + (c2.id << 8) + (c3.id << 16))); + } + } + } + } + + validMixBiomeColors = new int[layerColors.size()]; + for (int i = 0; i < layerColors.size(); i++) + validMixBiomeColors[i] = (int) layerColors.getLong(i); + validMixBiomeIds = layerIds.toLongArray(); + } + } + + } + } +// Close the file + zipFile.close(); } -// { -// Integer grass = colorMap.remove(FaweCache.getCombined(BlockTypesGRASS, 0)); -// if (grass != null) { -// blockColors[FaweCache.getCombined(BlockTypesGRASS, 0)] = grass; -// // assets\minecraft\textures\colormap -// ZipEntry grassEntry = zipFile.getEntry("assets/minecraft/textures/colormap/grass.png"); -// if (grassEntry != null) { -// try (InputStream is = zipFile.getInputStream(grassEntry)) { -// BufferedImage image = ImageIO.read(is); -// for (int i = 0; i < biomes.length; i++) { -// BiomeColor biome = biomes[i]; -// float adjTemp = MathMan.clamp(biome.temperature, 0.0f, 1.0f); -// float adjRainfall = MathMan.clamp(biome.rainfall, 0.0f, 1.0f) * adjTemp; -// int x = (int) (255 - adjTemp * 255); -// int z = (int) (255 - adjRainfall * 255); -// int color = image.getRGB(x, z); -// biome.grass = color; -// } -// } -// // swampland: perlin - avoid -// biomes[6].grass = 0; -// biomes[134].grass = 0; -// // roofed forest: averaged w/ 0x28340A -// biomes[29].grass = multiplyColor(biomes[29].grass, 0x28340A + (255 << 24)); -// biomes[157].grass = multiplyColor(biomes[157].grass, 0x28340A + (255 << 24)); -// // mesa : 0x90814D -// biomes[37].grass = 0x90814D + (255 << 24); -// biomes[38].grass = 0x90814D + (255 << 24); -// biomes[39].grass = 0x90814D + (255 << 24); -// biomes[165].grass = 0x90814D + (255 << 24); -// biomes[166].grass = 0x90814D + (255 << 24); -// biomes[167].grass = 0x90814D + (255 << 24); -// List valid = new ArrayList<>(); -// for (int i = 0; i < biomes.length; i++) { -// BiomeColor biome = biomes[i]; -//// biome.grass = multiplyColor(biome.grass, grass); -// if (biome.grass != 0 && !biome.name.equalsIgnoreCase("Unknown Biome")) { -// valid.add(biome); -// } -// biome.grassCombined = multiplyColor(grass, biome.grass); -// } -// this.validBiomes = valid.toArray(new BiomeColor[valid.size()]); -// -// { -// ArrayList uniqueColors = new ArrayList<>(); -// Set uniqueBiomesColors = new IntArraySet(); -// for (BiomeColor color : validBiomes) { -// if (uniqueBiomesColors.add(color.grass)) { -// uniqueColors.add(color); -// } -// } -// int count = 0; -// int count2 = 0; -// uniqueBiomesColors.clear(); -// -// LongArrayList layerIds = new LongArrayList(); -// LongArrayList layerColors = new LongArrayList(); -// for (int i = 0; i < uniqueColors.size(); i++) { -// for (int j = i; j < uniqueColors.size(); j++) { -// for (int k = j; k < uniqueColors.size(); k++) { -// BiomeColor c1 = uniqueColors.get(i); -// BiomeColor c2 = uniqueColors.get(j); -// BiomeColor c3 = uniqueColors.get(k); -// int average = averageColor(c1.grass, c2.grass, c3.grass); -// if (uniqueBiomesColors.add(average)) { -// count++; -// layerColors.add((long) average); -// layerIds.add((long) ((c1.id) + (c2.id << 8) + (c3.id << 16))); -// } -// } -// } -// } -// -// validMixBiomeColors = new int[layerColors.size()]; -// for (int i = 0; i < layerColors.size(); i++) validMixBiomeColors[i] = (int) layerColors.getLong(i); -// validMixBiomeIds = layerIds.toLongArray(); -// } -// } -// -// } -// } - // Close the file - zipFile.close(); } } // Convert the color map to a simple array diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 92617b693..4d85bee3f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -1026,7 +1026,7 @@ public class LocalSession implements TextureHolder { public void setTool(BaseItem item, @Nullable Tool tool, Player player) throws InvalidToolBindException { ItemTypes type = item.getType(); - if (!type.hasBlockType() && type.getBlockType().getMaterial().isAir()) { + if (type.hasBlockType() && type.getBlockType().getMaterial().isAir()) { throw new InvalidToolBindException(type, "Blocks can't be used"); } else if (type == config.wandItem) { throw new InvalidToolBindException(type, "Already used for the wand"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java index 008f38719..39c851431 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java @@ -39,18 +39,13 @@ import java.util.Objects; import javax.annotation.Nullable; /** - * Represents a mutable "snapshot" of a block. + * Represents a "snapshot" of a block with NBT Data. * *

An instance of this block contains all the information needed to * accurately reproduce the block, provided that the instance was * made correctly. In some implementations, it may not be possible to get a * snapshot of blocks correctly, so, for example, the NBT data for a block * may be missing.

- * - *

A peculiar detail of this class is that it accepts {@code -1} as a - * valid data value. This is due to legacy reasons: WorldEdit uses -1 - * as a "wildcard" block value, even though a {@link Mask} would be - * more appropriate.

*/ public class BaseBlock extends BlockState { private BlockState blockState; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockMaterial.java index fce762bcf..72a1b59f0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BlockMaterial.java @@ -163,4 +163,10 @@ public interface BlockMaterial { * @return If it has a container */ boolean hasContainer(); + + /** + * Get the map color + * @return or 0 + */ + int getMapColor(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java index 998c87fd5..436d42104 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java @@ -19,11 +19,15 @@ package com.sk89q.worldedit.command.tool; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.util.*; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.TreeGenerator; /** * Plants a tree. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java index ca4244c75..e42df8d1e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java @@ -224,7 +224,8 @@ public class DefaultBlockParser extends InputParser { state = item.getType().getBlockType().getDefaultState(); nbt = item.getNbtData(); } else { - state = BlockTypes.parse(typeString.toLowerCase()).getDefaultState(); + BlockTypes type = BlockTypes.parse(typeString.toLowerCase()); + state = type.getDefaultState(); if (state == null) { throw new NoMatchException("Does not match a valid block type: '" + input + "'"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index 0cf0590f5..4d1341c04 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -406,6 +406,7 @@ public final class CommandManager { // exceptions without writing a hook into every dispatcher, we need to unwrap these // exceptions and rethrow their converted form, if their is one. try { + Request.request().setActor(finalActor); Object result = dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]); } catch (Throwable t) { // Use the exception converter to convert the exception if any of its causes diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/Request.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/Request.java index 8bb5d7354..ef26a05f1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/Request.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/Request.java @@ -21,6 +21,8 @@ package com.sk89q.worldedit.session.request; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.world.World; import javax.annotation.Nullable; @@ -37,6 +39,9 @@ public final class Request { World world; private @Nullable + Actor actor; + private + @Nullable LocalSession session; private @Nullable @@ -81,6 +86,15 @@ public final class Request { return null; } + @Nullable + public Actor getActor() { + return actor; + } + + public void setActor(@Nullable Actor actor) { + this.actor = actor; + } + /** * Get the request session. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java new file mode 100644 index 000000000..93dc8a90c --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java @@ -0,0 +1,177 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.report; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import java.util.*; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class DataReport implements Report { + + private final String title; + private final List lines = Lists.newArrayList(); + + public DataReport(String title) { + checkNotNull(title, "title"); + this.title = title; + } + + public void append(String key, String message) { + checkNotNull(key, "key"); + lines.add(new Line(key, message)); + } + + public void append(String key, String message, Object... values) { + checkNotNull(message, "values"); + checkNotNull(values, "values"); + append(key, String.format(message, values)); + } + + public void append(String key, byte value) { + append(key, String.valueOf(value)); + } + + public void append(String key, short value) { + append(key, String.valueOf(value)); + } + + public void append(String key, int value) { + append(key, String.valueOf(value)); + } + + public void append(String key, long value) { + append(key, String.valueOf(value)); + } + + public void append(String key, float value) { + append(key, String.valueOf(value)); + } + + public void append(String key, double value) { + append(key, String.valueOf(value)); + } + + public void append(String key, boolean value) { + append(key, String.valueOf(value)); + } + + public void append(String key, char value) { + append(key, String.valueOf(value)); + } + + public void append(String key, Object value) { + append(key, getStringValue(value, Sets.newHashSet())); + } + + private static String getStringValue(Object value, Set seen) { + if (seen.contains(value)) { + return ""; + } else { + seen.add(value); + } + + if (value instanceof Object[]) { + value = Arrays.asList(value); + } + + if (value instanceof Collection) { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for (Object entry : (Collection) value) { + if (first) { + first = false; + } else { + builder.append("\n"); + } + builder.append(getStringValue(entry, Sets.newHashSet(seen))); + } + return builder.toString(); + } else if (value instanceof Map) { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for (Map.Entry entry : ((Map) value).entrySet()) { + if (first) { + first = false; + } else { + builder.append("\n"); + } + + String key = getStringValue(entry.getKey(), Sets.newHashSet(seen)).replaceAll("[\r\n]", ""); + if (key.length() > 60) { + key = key.substring(0, 60) + "..."; + } + + builder + .append(key) + .append(": ") + .append(getStringValue(entry.getValue(), Sets.newHashSet(seen))); + } + return builder.toString(); + } else { + return String.valueOf(value); + } + } + + @Override + public String getTitle() { + return title; + } + + @Override + public String toString() { + if (!lines.isEmpty()) { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for (Line line : lines) { + if (first) { + first = false; + } else { + builder.append("\n"); + } + builder.append(line.key).append(": "); + if (line.value == null) { + builder.append("null"); + } else if (line.value.contains("\n")) { + builder.append("\n"); + builder.append(line.value.replaceAll("(?m)^", "\t")); + } else { + builder.append(line.value); + } + } + return builder.toString(); + } else { + return "No data."; + } + } + + private static class Line { + private final String key; + private final String value; + + public Line(String key, String value) { + this.key = key; + this.value = value; + } + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/Report.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/Report.java new file mode 100644 index 000000000..877bf2b83 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/Report.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.report; + +public interface Report { + + String getTitle(); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/ReportList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/ReportList.java new file mode 100644 index 000000000..25128375b --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/ReportList.java @@ -0,0 +1,186 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.report; + +import com.google.common.collect.Lists; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +public class ReportList implements Report, List { + + private final String title; + private final List reports = Lists.newArrayList(); + + public ReportList(String title) { + this.title = title; + } + + @Override + public String getTitle() { + return title; + } + + @Override + public int size() { + return reports.size(); + } + + @Override + public boolean isEmpty() { + return reports.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return reports.contains(o); + } + + @Override + public Iterator iterator() { + return reports.iterator(); + } + + @Override + public Object[] toArray() { + return reports.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return reports.toArray(a); + } + + @Override + public boolean add(Report report) { + return reports.add(report); + } + + @Override + public boolean remove(Object o) { + return reports.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return reports.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + return reports.addAll(c); + } + + @Override + public boolean addAll(int index, Collection c) { + return reports.addAll(index, c); + } + + @Override + public boolean removeAll(Collection c) { + return reports.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return reports.retainAll(c); + } + + @Override + public void clear() { + reports.clear(); + } + + @Override + public boolean equals(Object o) { + return reports.equals(o); + } + + @Override + public int hashCode() { + return reports.hashCode(); + } + + @Override + public Report get(int index) { + return reports.get(index); + } + + @Override + public Report set(int index, Report element) { + return reports.set(index, element); + } + + @Override + public void add(int index, Report element) { + reports.add(index, element); + } + + @Override + public Report remove(int index) { + return reports.remove(index); + } + + @Override + public int indexOf(Object o) { + return reports.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return reports.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return reports.listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return reports.listIterator(index); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return reports.subList(fromIndex, toIndex); + } + + @Override + public String toString() { + if (!reports.isEmpty()) { + StringBuilder builder = new StringBuilder(); + for (Report report : reports) { + builder.append("================================\n") + .append(report.getTitle()) + .append("\n================================") + .append("\n\n") + .append(report.toString()) + .append("\n\n"); + } + return builder.toString(); + } else { + return "No reports."; + } + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/ShallowObjectReport.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/ShallowObjectReport.java new file mode 100644 index 000000000..b94b63e65 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/ShallowObjectReport.java @@ -0,0 +1,58 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.report; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ShallowObjectReport extends DataReport { + + private static final Logger log = Logger.getLogger(ShallowObjectReport.class.getCanonicalName()); + + public ShallowObjectReport(String title, Object object) { + super(title); + checkNotNull(object, "object"); + + Class type = object.getClass(); + + for (Field field : type.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + + if (field.getAnnotation(Unreported.class) != null) { + continue; + } + + field.setAccessible(true); + try { + Object value = field.get(object); + append(field.getName(), String.valueOf(value)); + } catch (IllegalAccessException e) { + log.log(Level.WARNING, "Failed to get value of '" + field.getName() + "' on " + type); + } + } + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/StackTraceReport.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/StackTraceReport.java new file mode 100644 index 000000000..224a87e70 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/StackTraceReport.java @@ -0,0 +1,64 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.report; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class StackTraceReport implements Report { + + private final StackTraceElement[] stackTrace; + + public StackTraceReport(StackTraceElement[] stackTrace) { + checkNotNull(stackTrace, "stackTrace"); + this.stackTrace = stackTrace; + } + + @Override + public String getTitle() { + return "Stack Trace"; + } + + @Override + public String toString() { + if (stackTrace.length > 0) { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for (StackTraceElement element : stackTrace) { + if (first) { + first = false; + } else { + builder.append("\n"); + } + builder.append(element.getClassName()) + .append(".") + .append(element.getMethodName()) + .append("() (") + .append(element.getFileName()) + .append(":") + .append(element.getLineNumber()) + .append(")"); + } + return builder.toString(); + } else { + return "No stack trace available."; + } + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/SystemInfoReport.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/SystemInfoReport.java new file mode 100644 index 000000000..91f14c2fd --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/SystemInfoReport.java @@ -0,0 +1,91 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.report; + +import java.lang.management.*; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class SystemInfoReport extends DataReport { + + public SystemInfoReport() { + super("System Information"); + + Runtime runtime = Runtime.getRuntime(); + RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); + ClassLoadingMXBean classLoadingBean = ManagementFactory.getClassLoadingMXBean(); + List gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); + OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); + ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); + + append("Java", "%s %s (%s)", + System.getProperty("java.vendor"), + System.getProperty("java.version"), + System.getProperty("java.vendor.url")); + append("Operating System", "%s %s (%s)", + System.getProperty("os.name"), + System.getProperty("os.version"), + System.getProperty("os.arch")); + append("Available Processors", runtime.availableProcessors()); + append("Free Memory", runtime.freeMemory() / 1024 / 1024 + " MB"); + append("Max Memory", runtime.maxMemory() / 1024 / 1024 + " MB"); + append("Total Memory", runtime.totalMemory() / 1024 / 1024 + " MB"); + append("System Load Average", osBean.getSystemLoadAverage()); + append("Java Uptime", TimeUnit.MINUTES.convert(runtimeBean.getUptime(), TimeUnit.MILLISECONDS) + " minutes"); + + DataReport startup = new DataReport("Startup"); + startup.append("Input Arguments", runtimeBean.getInputArguments()); + append(startup.getTitle(), startup); + + DataReport vm = new DataReport("Virtual Machine"); + vm.append("Name", runtimeBean.getVmName()); + vm.append("Vendor", runtimeBean.getVmVendor()); + vm.append("Version", runtimeBean.getVmVendor()); + append(vm.getTitle(), vm); + + DataReport spec = new DataReport("Specification"); + spec.append("Name", runtimeBean.getSpecName()); + spec.append("Vendor", runtimeBean.getSpecVendor()); + spec.append("Version", runtimeBean.getSpecVersion()); + append(spec.getTitle(), spec); + + DataReport classLoader = new DataReport("Class Loader"); + classLoader.append("Loaded Class Count", classLoadingBean.getLoadedClassCount()); + classLoader.append("Total Loaded Class Count", classLoadingBean.getTotalLoadedClassCount()); + classLoader.append("Unloaded Class Count", classLoadingBean.getUnloadedClassCount()); + append(classLoader.getTitle(), classLoader); + + DataReport gc = new DataReport("Garbage Collectors"); + for (GarbageCollectorMXBean bean : gcBeans) { + DataReport thisGC = new DataReport(bean.getName()); + thisGC.append("Collection Count", bean.getCollectionCount()); + thisGC.append("Collection Time", bean.getCollectionTime() + "ms"); + gc.append(thisGC.getTitle(), thisGC); + } + append(gc.getTitle(), gc); + + DataReport threads = new DataReport("Threads"); + for (ThreadInfo threadInfo : threadBean.dumpAllThreads(false, false)) { + threads.append("#" + threadInfo.getThreadId() + " " + threadInfo.getThreadName(), threadInfo.getThreadState()); + } + append(threads.getTitle(), threads); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/Unreported.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/Unreported.java new file mode 100644 index 000000000..c10161932 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/Unreported.java @@ -0,0 +1,33 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.report; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates properties that should not be exposed in the report. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Unreported { +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index 407e0ecd9..b57cc8e99 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -24,8 +24,11 @@ import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; +<<<<<<< HEAD import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; +======= +>>>>>>> refs/remotes/sk89q/master import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.LazyBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -37,6 +40,13 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.biome.BaseBiome; +<<<<<<< HEAD +======= +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; +>>>>>>> refs/remotes/sk89q/master import com.sk89q.worldedit.world.weather.WeatherType; import java.util.Collections; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java index 59a2809b9..c2fd00ff6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java @@ -20,14 +20,14 @@ package com.sk89q.worldedit.world.registry; import com.google.common.io.Resources; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; +import com.google.gson.*; import com.google.gson.reflect.TypeToken; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BlockMaterial; import com.sk89q.worldedit.util.gson.VectorAdapter; import java.io.IOException; +import java.lang.reflect.Type; import java.net.URL; import java.nio.charset.Charset; import java.util.HashMap; @@ -75,6 +75,18 @@ public class BundledBlockData { private void loadFromResource() throws IOException { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector.class, new VectorAdapter()); + gsonBuilder.registerTypeAdapter(int.class, new JsonDeserializer() { + @Override + public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonPrimitive primitive = (JsonPrimitive) json; + if (primitive.isString()) { + String value = primitive.getAsString(); + if (value.charAt(0) == '#') return Integer.parseInt(value.substring(1), 16); + return Integer.parseInt(value); + } + return primitive.getAsInt(); + } + }); Gson gson = gsonBuilder.create(); URL url = BundledBlockData.class.getResource("blocks.json"); if (url == null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java index fa9f23934..f02409495 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java @@ -178,7 +178,11 @@ public class LegacyMapper { private BlockState getBlock(int combinedId) { if (combinedId < blockArr.length) { - return BlockState.get(blockArr[combinedId]); + try { + return BlockState.get(blockArr[combinedId]); + } catch (IndexOutOfBoundsException ignore) { + return null; + } } Integer extra = extraId4DataToStateId.get(combinedId); if (extra == null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java index 5968986b5..d3421bb6e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java @@ -40,6 +40,15 @@ public class PassthroughBlockMaterial implements BlockMaterial { } } + @Override + public int getMapColor() { + if (blockMaterial == null) { + return 0; + } else { + return blockMaterial.getMapColor(); + } + } + @Override public boolean isFullCube() { if (blockMaterial == null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java index 5aa1dc494..0358444dc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleBlockMaterial.java @@ -43,6 +43,7 @@ class SimpleBlockMaterial implements BlockMaterial { private boolean hasContainer; private int lightOpacity; private boolean isAir; + private int mapColor; @Override public boolean isAir() { @@ -53,6 +54,15 @@ class SimpleBlockMaterial implements BlockMaterial { isAir = air; } + @Override + public int getMapColor() { + return mapColor; + } + + public void setMapColor(int mapColor) { + this.mapColor = mapColor; + } + @Override public int getLightOpacity() { return lightOpacity; diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index b7bf6cd76..e5cbcaf4d 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -93,6 +93,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Random; +import java.util.UUID; import javax.annotation.Nullable;