diff --git a/WorldPainter/WPCore/src/main/java/org/pepsoft/minecraft/Constants.java b/WorldPainter/WPCore/src/main/java/org/pepsoft/minecraft/Constants.java index e2132006d..b39ae8f28 100644 --- a/WorldPainter/WPCore/src/main/java/org/pepsoft/minecraft/Constants.java +++ b/WorldPainter/WPCore/src/main/java/org/pepsoft/minecraft/Constants.java @@ -634,6 +634,7 @@ private Constants() { public static final String TAG_PALETTE = "Palette"; /** Lower case variant. */ public static final String TAG_PALETTE_ = "palette"; + public static final String TAG_PALETTES_ = "palettes"; public static final String TAG_NAME = "Name"; public static final String TAG_PROPERTIES = "Properties"; public static final String TAG_SNAPSHOT = "Snapshot"; diff --git a/WorldPainter/WPCore/src/main/java/org/pepsoft/worldpainter/layers/bo2/Structure.java b/WorldPainter/WPCore/src/main/java/org/pepsoft/worldpainter/layers/bo2/Structure.java index 51bb09d19..3aca96eb9 100644 --- a/WorldPainter/WPCore/src/main/java/org/pepsoft/worldpainter/layers/bo2/Structure.java +++ b/WorldPainter/WPCore/src/main/java/org/pepsoft/worldpainter/layers/bo2/Structure.java @@ -1,6 +1,8 @@ package org.pepsoft.worldpainter.layers.bo2; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; import org.jnbt.*; import org.pepsoft.minecraft.Entity; import org.pepsoft.minecraft.Material; @@ -22,17 +24,31 @@ * Created by Pepijn on 26-6-2016. */ public class Structure extends AbstractObject implements Bo2ObjectProvider { - private Structure(CompoundTag root, String name, Map blocks, List entities, List tileEntities) { + private Structure(CompoundTag root, String name, List> blocks, List entities, Map> tileEntities) { this.root = root; this.name = name; - this.blocks = blocks; + this.blocks = null; // TODO remove in a future update (3.0 release) + this.palettes = blocks; this.entities = entities; this.tileEntities = tileEntities; + this.rng = new Random(); } @Override public WPObject getObject() { return this; + /* TODO: add support for selecting palettes + int size = this.blocks.size(); + if (size == 1) + return this; + + Map> blocks = Maps.newHashMap(); + Map> tiles = Maps.newHashMap(); + int index = rng.nextInt(size); + blocks.put(0, this.blocks.get(index)); + tiles.put(0, this.tileEntities.get(index)); + return new Structure(root, name, blocks, entities, tiles); + */ } @Override @@ -42,7 +58,7 @@ public List getAllObjects() { @Override public void setSeed(long seed) { - // Do nothing + this.rng.setSeed(seed); } @Override @@ -65,16 +81,16 @@ public Point3i getDimensions() { @Override public Material getMaterial(int x, int y, int z) { - return blocks.get(new Point3i(x, y, z)); + return palettes.get(0).get(new Point3i(x, y, z)); } @Override public boolean getMask(int x, int y, int z) { if (getAttribute(ATTRIBUTE_IGNORE_AIR)) { - Material material = blocks.get(new Point3i(x, y, z)); + Material material = palettes.get(0).get(new Point3i(x, y, z)); return (material != null) && (material != AIR); } else { - return blocks.containsKey(new Point3i(x, y, z)); + return palettes.get(0).containsKey(new Point3i(x, y, z)); } } @@ -85,7 +101,7 @@ public List getEntities() { @Override public List getTileEntities() { - return tileEntities; + return tileEntities.get(0); } @Override @@ -139,10 +155,29 @@ public static Structure load(String objectName, InputStream inputStream) throws root = (CompoundTag) in.readTag(); } - // Load the palette + // Load the palette(s) ListTag paletteTag = (ListTag) root.getTag(TAG_PALETTE_); - Material[] palette = new Material[paletteTag.getValue().size()]; - for (int i = 0; i < palette.length; i++) { + ArrayList palettes = new ArrayList<>(); + if (paletteTag != null) { + // single palette + palettes.add(paletteTag); + } else { + // assume use of multiple palettes + paletteTag = (ListTag) root.getTag(TAG_PALETTES_); + for (int i = 0; i < paletteTag.getValue().size(); i++) { + palettes.add((ListTag)paletteTag.getValue().get(i)); + } + } + + // Load the blocks and tile entities + List> blocks = new ArrayList<>(); + Map> tileEntities = Maps.newHashMap(); + ListTag blocksTag = (ListTag) root.getTag(TAG_BLOCKS_); + + for (int i = 0; i < palettes.size(); i++) { + paletteTag = palettes.get(i); + Material[] palette = new Material[paletteTag.getValue().size()]; + CompoundTag entryTag = (CompoundTag) paletteTag.getValue().get(i); String name = ((StringTag) entryTag.getTag(TAG_NAME)).getValue(); CompoundTag propertiesTag = (CompoundTag) entryTag.getTag(TAG_PROPERTIES); @@ -150,27 +185,28 @@ public static Structure load(String objectName, InputStream inputStream) throws ? propertiesTag.getValue().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> ((StringTag) entry.getValue()).getValue())) : null; palette[i] = Material.get(name, properties); - } - // Load the blocks and tile entities - Map blocks = new HashMap<>(); - ListTag blocksTag = (ListTag) root.getTag(TAG_BLOCKS_); - List tileEntities = new ArrayList<>(); - for (CompoundTag blockTag: blocksTag.getValue()) { - List posTags = ((ListTag) blockTag.getTag(TAG_POS_)).getValue(); - int x = posTags.get(0).getValue(); - int y = posTags.get(2).getValue(); - int z = posTags.get(1).getValue(); - blocks.put(new Point3i(x, y, z), palette[((IntTag) blockTag.getTag(TAG_STATE_)).getValue()]); - CompoundTag nbtTag = (CompoundTag) blockTag.getTag(TAG_NBT_); - if (nbtTag != null) { - // This block is a tile entity - TileEntity tileEntity = TileEntity.fromNBT(nbtTag); - tileEntity.setX(x); - tileEntity.setY(z); - tileEntity.setZ(y); - tileEntities.add(tileEntity); + Map tempBlocks = Maps.newHashMap(); + List tempTiles = new ArrayList<>(); + for (CompoundTag blockTag: blocksTag.getValue()) { + List posTags = ((ListTag) blockTag.getTag(TAG_POS_)).getValue(); + int x = posTags.get(0).getValue(); + int y = posTags.get(2).getValue(); + int z = posTags.get(1).getValue(); + tempBlocks.put(new Point3i(x, y, z), palette[((IntTag) blockTag.getTag(TAG_STATE_)).getValue()]); + CompoundTag nbtTag = (CompoundTag) blockTag.getTag(TAG_NBT_); + if (nbtTag != null) { + // This block is a tile entity + TileEntity tileEntity = TileEntity.fromNBT(nbtTag); + tileEntity.setX(x); + tileEntity.setY(z); + tileEntity.setZ(y); + tempTiles.add(tileEntity); + } } + + blocks.add(tempBlocks); + tileEntities.put(i, tempTiles); } // Load the entities @@ -182,18 +218,28 @@ public static Structure load(String objectName, InputStream inputStream) throws // Remove palette, blocks and entities from the tag so we don't waste space root.setTag(TAG_PALETTE_, null); + root.setTag(TAG_PALETTES_, null); root.setTag(TAG_BLOCKS_, null); root.setTag(TAG_ENTITIES_, null); - return new Structure(root, objectName, blocks, (! entities.isEmpty()) ? ImmutableList.copyOf(entities) : null, (! tileEntities.isEmpty()) ? ImmutableList.copyOf(tileEntities) : null); + return new Structure(root, objectName, blocks, (! entities.isEmpty()) ? ImmutableList.copyOf(entities) : null, (! tileEntities.isEmpty()) ? ImmutableMap.copyOf(tileEntities) : null); + } + + private Object readResolve() { + if (blocks != null) { // old versions have non-null blocks field + return new Structure(root, name, new ArrayList<>(Collections.singletonList(blocks)), entities, tileEntities); + } + return this; } private final CompoundTag root; - private final Map blocks; + @Deprecated private final Map blocks; + private final List> palettes; private String name; private Map attributes; private final List entities; - private final List tileEntities; + private final Map> tileEntities; + private Random rng; public static final AttributeKey ATTRIBUTE_IGNORE_AIR = new AttributeKey<>("Structure.ignoreAir", true);