Merge branch 'schematic-creation' into 1.12-WIP and fix conflicts

This commit is contained in:
Runemoro 2018-01-19 23:26:01 -05:00
commit 7c34879757
44 changed files with 411 additions and 84 deletions

View file

@ -1,11 +1,14 @@
package org.dimdev.ddutils.schem; package org.dimdev.ddutils.schem;
import com.flowpowered.math.vector.Vector3i;
import com.google.common.collect.ArrayListMultimap;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.properties.IProperty; import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityList;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagDouble; import net.minecraft.nbt.NBTTagDouble;
@ -13,6 +16,7 @@ import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString; import net.minecraft.nbt.NBTTagString;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
@ -38,11 +42,32 @@ public class Schematic {
public short length; public short length;
public int[] offset = {0, 0, 0}; public int[] offset = {0, 0, 0};
public int paletteMax; public int paletteMax;
public List<IBlockState> pallette = new ArrayList<>(); public List<IBlockState> palette = new ArrayList<>();
public int[][][] blockData; //[x][y][z] public int[][][] blockData; //[x][y][z]
public List<NBTTagCompound> tileEntities = new ArrayList<>(); public List<NBTTagCompound> tileEntities = new ArrayList<>();
public List<NBTTagCompound> entities = new ArrayList<>(); // Not in the specification, but we need this public List<NBTTagCompound> entities = new ArrayList<>(); // Not in the specification, but we need this
public Schematic() {
paletteMax = -1;
}
public Schematic(short width, short height, short length) {
this();
this.width = width;
this.height = height;
this.length = length;
blockData = new int[width][length][height];
palette.add(Blocks.AIR.getDefaultState());
paletteMax++;
creationDate = System.currentTimeMillis();
}
public Schematic(String name, String author, short width, short height, short length) {
this(width, height, length);
this.name = name;
this.author = author;
}
public static Schematic loadFromNBT(NBTTagCompound nbt) { public static Schematic loadFromNBT(NBTTagCompound nbt) {
Schematic schematic = new Schematic(); Schematic schematic = new Schematic();
schematic.version = nbt.getInteger("Version"); //Version is required schematic.version = nbt.getInteger("Version"); //Version is required
@ -102,12 +127,12 @@ public class Schematic {
String[] properties = stateString.split(","); String[] properties = stateString.split(",");
blockstate = getBlockStateWithProperties(block, properties); blockstate = getBlockStateWithProperties(block, properties);
} }
schematic.pallette.add(blockstate); //@todo, can we assume that a schematic file always has all palette integers used from 0 to pallettemax-1? schematic.palette.add(blockstate); //@todo, can we assume that a schematic file always has all palette integers used from 0 to pallettemax-1?
} }
if (nbt.hasKey("PaletteMax")) { //PaletteMax is not required if (nbt.hasKey("PaletteMax")) { //PaletteMax is not required
schematic.paletteMax = nbt.getInteger("PaletteMax"); schematic.paletteMax = nbt.getInteger("PaletteMax");
} else { } else {
schematic.paletteMax = schematic.pallette.size() - 1; schematic.paletteMax = schematic.palette.size() - 1;
} }
byte[] blockDataIntArray = nbt.getByteArray("BlockData"); //BlockData is required byte[] blockDataIntArray = nbt.getByteArray("BlockData"); //BlockData is required
@ -161,8 +186,8 @@ public class Schematic {
nbt.setInteger("PaletteMax", schematic.paletteMax); nbt.setInteger("PaletteMax", schematic.paletteMax);
NBTTagCompound paletteNBT = new NBTTagCompound(); NBTTagCompound paletteNBT = new NBTTagCompound();
for (int i = 0; i < schematic.pallette.size(); i++) { for (int i = 0; i < schematic.palette.size(); i++) {
IBlockState state = schematic.pallette.get(i); IBlockState state = schematic.palette.get(i);
String blockStateString = getBlockStateStringFromState(state); String blockStateString = getBlockStateStringFromState(state);
paletteNBT.setInteger(blockStateString, i); paletteNBT.setInteger(blockStateString, i);
} }
@ -247,9 +272,83 @@ public class Schematic {
return totalString; return totalString;
} }
public static void place(Schematic schematic, World world, int xBase, int yBase, int zBase) { // TODO: use the setBlockState method
public static Schematic createFromWorld(World world, Vector3i from, Vector3i to) {
Schematic schematic = new Schematic();
Vector3i min = from.min(to);
Vector3i max = from.max(to);
Vector3i dimensions = max.sub(min).add(1, 1, 1);
schematic.width = (short) dimensions.getX();
schematic.height = (short) dimensions.getY();
schematic.length = (short) dimensions.getZ();
schematic.blockData = new int[schematic.width][schematic.height][schematic.length];
ArrayListMultimap<IBlockState, BlockPos> states = ArrayListMultimap.create();
Set<String> mods = new HashSet<>();
for (int x = 0; x < dimensions.getX(); x++) {
for (int y = 0; y < dimensions.getY(); y++) {
for (int z = 0; z < dimensions.getZ(); z++) {
BlockPos pos = new BlockPos(min.getX() + x, min.getY() + y, min.getZ() + z);
IBlockState state = world.getBlockState(pos);
String id = getBlockStateStringFromState(state);
if (id.contains(":")) mods.add(id.split(":")[0]);
states.put(state, new BlockPos(x, y, z));
TileEntity tileEntity = world.getChunkFromBlockCoords(pos).getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK);
if (tileEntity != null) {
NBTTagCompound tileEntityNBT = tileEntity.serializeNBT();
tileEntityNBT.setInteger("x", tileEntityNBT.getInteger("x") - min.getX());
tileEntityNBT.setInteger("y", tileEntityNBT.getInteger("y") - min.getY());
tileEntityNBT.setInteger("z", tileEntityNBT.getInteger("z") - min.getZ());
schematic.tileEntities.add(tileEntityNBT);
}
}
}
}
IBlockState[] keys = states.keySet().toArray(new IBlockState[states.keySet().size()]);
for (int i = 0; i < keys.length; i++) {
for (BlockPos pos : states.get(keys[i])) {
schematic.blockData[pos.getX()][pos.getY()][pos.getZ()] = i;
}
schematic.palette.add(i, keys[i]);
}
for (Entity entity : world.getEntitiesInAABBexcluding(null, getBoundingBox(from, to), entity -> !(entity instanceof EntityPlayerMP))) {
NBTTagCompound entityNBT = entity.serializeNBT();
NBTTagList posNBT = (NBTTagList) entityNBT.getTag("Pos");
NBTTagList newPosNBT = new NBTTagList();
newPosNBT.appendTag(new NBTTagDouble(posNBT.getDoubleAt(0) - from.getX()));
newPosNBT.appendTag(new NBTTagDouble(posNBT.getDoubleAt(1) - from.getY()));
newPosNBT.appendTag(new NBTTagDouble(posNBT.getDoubleAt(2) - from.getZ()));
entityNBT.setTag("Pos", newPosNBT);
schematic.entities.add(entityNBT);
}
schematic.requiredMods = mods.toArray(new String[mods.size()]);
schematic.paletteMax = keys.length - 1;
schematic.creationDate = System.currentTimeMillis();
return schematic;
}
private static AxisAlignedBB getBoundingBox(Vector3i pos1, Vector3i pos2) {
return new AxisAlignedBB(new BlockPos(pos1.getX(), pos1.getY(), pos1.getZ()), new BlockPos(pos2.getX(), pos2.getY(), pos2.getZ()));
}
public static void place(Schematic schematic, World world, int xBase, int yBase, int zBase) { // TODO: check if entities and tileentities are within pocket bounds
// Place the schematic's blocks // Place the schematic's blocks
List<IBlockState> palette = schematic.pallette; List<IBlockState> palette = schematic.palette;
int[][][] blockData = schematic.blockData; int[][][] blockData = schematic.blockData;
Set<Chunk> changedChunks = new HashSet<>(); Set<Chunk> changedChunks = new HashSet<>();
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
@ -307,7 +406,7 @@ public class Schematic {
throw new RuntimeException("Schematic contained TileEntity " + schematicTileEntityId + " at " + pos + " but the TileEntity of that block (" + world.getBlockState(pos) + ") must be " + blockTileEntityId); throw new RuntimeException("Schematic contained TileEntity " + schematicTileEntityId + " at " + pos + " but the TileEntity of that block (" + world.getBlockState(pos) + ") must be " + blockTileEntityId);
} }
} else { } else {
throw new RuntimeException("Schematic contained TileEntity info at " + pos + "but the block there (" + world.getBlockState(pos) + ") has no TileEntity."); throw new RuntimeException("Schematic contained TileEntity info at " + pos + " but the block there (" + world.getBlockState(pos) + ") has no TileEntity.");
} }
} }
@ -327,4 +426,13 @@ public class Schematic {
world.spawnEntity(entity); world.spawnEntity(entity);
} }
} }
public void setBlockState(int x, int y, int z, IBlockState state) {
if (palette.contains(state)) {
blockData[x][y][z] = palette.indexOf(state); // TODO: optimize this (there must be some efficient list implementations)
} else {
palette.add(state);
blockData[x][y][z] = ++paletteMax;
}
}
} }

View file

@ -5,6 +5,7 @@ import org.dimdev.dimdoors.shared.commands.CommandPocket;
import org.dimdev.dimdoors.shared.commands.CommandDimTeleport; import org.dimdev.dimdoors.shared.commands.CommandDimTeleport;
import org.dimdev.dimdoors.shared.Config; import org.dimdev.dimdoors.shared.Config;
import org.dimdev.dimdoors.shared.CommonProxy; import org.dimdev.dimdoors.shared.CommonProxy;
import org.dimdev.dimdoors.shared.commands.CommandSaveSchem;
import org.dimdev.dimdoors.shared.items.ModItems; import org.dimdev.dimdoors.shared.items.ModItems;
import org.dimdev.dimdoors.shared.world.gateways.GatewayGenerator; import org.dimdev.dimdoors.shared.world.gateways.GatewayGenerator;
import lombok.Getter; import lombok.Getter;
@ -68,6 +69,7 @@ public class DimDoors {
private void registerCommands(FMLServerStartingEvent event) { private void registerCommands(FMLServerStartingEvent event) {
event.registerServerCommand(new CommandDimTeleport()); event.registerServerCommand(new CommandDimTeleport());
event.registerServerCommand(new CommandPocket()); event.registerServerCommand(new CommandPocket());
event.registerServerCommand(new CommandSaveSchem());
} }
public static void sendMessage(Entity entity, String text) { public static void sendMessage(Entity entity, String text) {

View file

@ -96,7 +96,8 @@ public class CommandPocket extends CommandBase {
TileEntityRift entrance = (TileEntityRift) player.world.getTileEntity(pocket.getEntrance().getPos()); TileEntityRift entrance = (TileEntityRift) player.world.getTileEntity(pocket.getEntrance().getPos());
entrance.teleportTo(player); entrance.teleportTo(player);
} else { } else {
TeleportUtils.teleport(player, new Location(player.world, pocket.getOrigin().add(30, 30, 30))); int size = (pocket.getSize() + 1) * 16;
TeleportUtils.teleport(player, new Location(player.world, pocket.getOrigin().add(size / 2, size / 2, size / 2)));
} }
} else { } else {
DimDoors.log.info("Not executing command /" + getName() + " because it wasn't sent by a player."); DimDoors.log.info("Not executing command /" + getName() + " because it wasn't sent by a player.");

View file

@ -0,0 +1,76 @@
package org.dimdev.dimdoors.shared.commands;
import com.flowpowered.math.vector.Vector3i;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString;
import org.dimdev.ddutils.schem.Schematic;
import org.dimdev.dimdoors.DimDoors;
import org.dimdev.dimdoors.shared.pockets.Pocket;
import org.dimdev.dimdoors.shared.pockets.PocketRegistry;
import org.dimdev.dimdoors.shared.pockets.SchematicHandler;
import org.dimdev.dimdoors.shared.world.pocketdimension.WorldProviderPocket;
import java.util.ArrayList;
import java.util.List;
public class CommandSaveSchem extends CommandBase {
private final List<String> aliases;
public CommandSaveSchem() {
aliases = new ArrayList<>();
aliases.add("saveschem");
}
@Override
public String getName() {
return "saveschem";
}
@Override
public String getUsage(ICommandSender sender) {
return "saveschem <name>";
}
@Override
public List<String> getAliases() {
return aliases;
}
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { // TODO: more pocket commands (replace pocket, get ID, teleport to pocket, etc.)
// Check that the number of arguments is correct
if (args.length != 1) {
sender.sendMessage(new TextComponentString("[DimDoors] Usage: /" + getUsage(sender)));
return;
}
// Execute only if it's a player
if (sender instanceof EntityPlayerMP) {
EntityPlayerMP player = getCommandSenderAsPlayer(sender);
if (!(player.world.provider instanceof WorldProviderPocket)) {
DimDoors.chat(player, "Current Dimension isn't a pocket dimension");
return;
}
Pocket pocket = PocketRegistry.instance(player.dimension).getPocketAt(player.getPosition());
Schematic schematic = Schematic.createFromWorld(player.world, toVector3i(pocket.getOrigin()), toVector3i(pocket.getOrigin()).add(Vector3i.from((pocket.getSize() + 1) * 16 - 1)));
schematic.name = args[0];
schematic.author = player.getName();
SchematicHandler.INSTANCE.saveSchematic(schematic, args[0]);
DimDoors.chat(player, "Pocket " + args[0] + " has been saved.");
} else {
DimDoors.log.info("Not executing command /" + getName() + " because it wasn't sent by a player.");
}
}
private Vector3i toVector3i(BlockPos pos) {
return Vector3i.from(pos.getX(), pos.getY(), pos.getZ());
}
}

View file

@ -29,7 +29,7 @@ import java.util.List;
@Saved @Getter protected int id; @Saved @Getter protected int id;
@Saved @Getter protected int x; // Grid x TODO: rename to gridX and gridY, or just convert to non-grid dependant coordinates @Saved @Getter protected int x; // Grid x TODO: rename to gridX and gridY, or just convert to non-grid dependant coordinates
@Saved @Getter protected int z; // Grid y @Saved @Getter protected int z; // Grid y
@Saved @Getter @Setter protected int size; // In chunks TODO: non chunk-based size, better bounds such as minX, minZ, maxX, maxZ, etc. @Saved @Getter @Setter protected int size; // TODO: size = sizeInChunks - 1 ???!!! TODO: non chunk-based size, better bounds such as minX, minZ, maxX, maxZ, etc.
@Saved @Getter @Setter protected VirtualLocation virtualLocation; @Saved @Getter @Setter protected VirtualLocation virtualLocation;
@Saved @Getter @Setter protected Location entrance; // TODO: move this to the rift registry (pocketlib) @Saved @Getter @Setter protected Location entrance; // TODO: move this to the rift registry (pocketlib)
@Saved @Getter protected List<Location> riftLocations; // TODO: convert to a list of all tile entities (for chests, and to make it independant of pocketlib) @Saved @Getter protected List<Location> riftLocations; // TODO: convert to a list of all tile entities (for chests, and to make it independant of pocketlib)

View file

@ -2,6 +2,7 @@ package org.dimdev.dimdoors.shared.pockets;
import com.google.common.collect.BiMap; import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap; import com.google.common.collect.HashBiMap;
import net.minecraft.world.World;
import org.dimdev.annotatednbt.Saved; import org.dimdev.annotatednbt.Saved;
import org.dimdev.annotatednbt.NBTSerializable; import org.dimdev.annotatednbt.NBTSerializable;
import org.dimdev.dimdoors.shared.Config; import org.dimdev.dimdoors.shared.Config;
@ -9,7 +10,6 @@ import org.dimdev.ddutils.math.GridUtils;
import org.dimdev.dimdoors.DimDoors; import org.dimdev.dimdoors.DimDoors;
import org.dimdev.ddutils.nbt.NBTUtils; import org.dimdev.ddutils.nbt.NBTUtils;
import org.dimdev.ddutils.WorldUtils; import org.dimdev.ddutils.WorldUtils;
import org.dimdev.dimdoors.shared.world.ModDimensions;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -21,6 +21,7 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.storage.MapStorage; import net.minecraft.world.storage.MapStorage;
import net.minecraft.world.storage.WorldSavedData; import net.minecraft.world.storage.WorldSavedData;
import org.dimdev.dimdoors.shared.world.pocketdimension.WorldProviderPocket;
@NBTSerializable public class @NBTSerializable public class
PocketRegistry extends WorldSavedData { // TODO: unregister pocket entrances, private pocket entrances/exits PocketRegistry extends WorldSavedData { // TODO: unregister pocket entrances, private pocket entrances/exits
@ -47,9 +48,13 @@ PocketRegistry extends WorldSavedData { // TODO: unregister pocket entrances, pr
} }
public static PocketRegistry instance(int dim) { public static PocketRegistry instance(int dim) {
if (!ModDimensions.isDimDoorsPocketDimension(dim)) throw new UnsupportedOperationException("PocketRegistry is only available for pocket dimensions!"); World world = WorldUtils.getWorld(dim);
MapStorage storage = WorldUtils.getWorld(dim).getPerWorldStorage(); if (!(world.provider instanceof WorldProviderPocket)) {
throw new UnsupportedOperationException("PocketRegistry is only available for pocket dimensions (asked for dim " + dim + ")!");
}
MapStorage storage = world.getPerWorldStorage();
PocketRegistry instance = (PocketRegistry) storage.getOrLoadData(PocketRegistry.class, DATA_NAME); PocketRegistry instance = (PocketRegistry) storage.getOrLoadData(PocketRegistry.class, DATA_NAME);
if (instance == null) { if (instance == null) {

View file

@ -34,7 +34,8 @@ import org.dimdev.dimdoors.shared.world.ModDimensions;
*/ */
public class SchematicHandler { public class SchematicHandler {
public static final SchematicHandler INSTANCE = new SchematicHandler(); // TODO: make static private static final String SAVED_POCKETS_GROUP_NAME = "saved_pockets";
public static final SchematicHandler INSTANCE = new SchematicHandler();
private List<PocketTemplate> templates; private List<PocketTemplate> templates;
private Map<String, Map<String, Integer>> nameMap; // group -> name -> index in templates private Map<String, Map<String, Integer>> nameMap; // group -> name -> index in templates
@ -44,7 +45,7 @@ public class SchematicHandler {
templates = new ArrayList<>(); templates = new ArrayList<>();
String[] names = {"default_dungeon_nether", "default_dungeon_normal", "default_private", "default_public"}; // TODO: don't hardcode String[] names = {"default_dungeon_nether", "default_dungeon_normal", "default_private", "default_public", "default_blank"}; // TODO: don't hardcode
for (String name : names) { for (String name : names) {
try { try {
URL resource = DimDoors.class.getResource("/assets/dimdoors/pockets/json/" + name + ".json"); URL resource = DimDoors.class.getResource("/assets/dimdoors/pockets/json/" + name + ".json");
@ -74,6 +75,21 @@ public class SchematicHandler {
DimDoors.log.error("Error reading file " + file.toURI() + ". The following exception occured: ", e); DimDoors.log.error("Error reading file " + file.toURI() + ". The following exception occured: ", e);
} }
} }
// Load saved schematics
File saveFolder = new File(Config.configurationFolder, "/schematics/saved");
if (saveFolder.exists()) {
for (File file : saveFolder.listFiles()) {
if (file.isDirectory() || !file.getName().endsWith(".schem")) continue;
try {
Schematic schematic = Schematic.loadFromNBT(CompressedStreamTools.readCompressed(new FileInputStream(file)));
templates.add(new PocketTemplate(SAVED_POCKETS_GROUP_NAME, file.getName(), null, null, null, schematic, -1, 0));
} catch (IOException e) {
DimDoors.log.error("Error reading schematic " + file.getName() + ": " + e);
}
}
}
constructNameMap(); constructNameMap();
DimDoors.log.info("Loaded " + templates.size() + " templates in " + (System.currentTimeMillis() - startTime) + " ms."); DimDoors.log.info("Loaded " + templates.size() + " templates in " + (System.currentTimeMillis() - startTime) + " ms.");
@ -205,6 +221,8 @@ public class SchematicHandler {
} }
} }
} }
nameMap.put(SAVED_POCKETS_GROUP_NAME, new HashMap<>());
} }
public Set<String> getTemplateGroups() { public Set<String> getTemplateGroups() {
@ -276,14 +294,14 @@ public class SchematicHandler {
return getRandomTemplate("public", -1, Math.min(Config.getPublicPocketSize(), PocketRegistry.instance(ModDimensions.getPublicDim()).getPublicPocketSize()), true); return getRandomTemplate("public", -1, Math.min(Config.getPublicPocketSize(), PocketRegistry.instance(ModDimensions.getPublicDim()).getPublicPocketSize()), true);
} }
public void saveSchematic(Schematic schematic, String name) { public void saveSchematic(Schematic schematic, String id) {
NBTTagCompound schematicNBT = Schematic.saveToNBT(schematic); NBTTagCompound schematicNBT = Schematic.saveToNBT(schematic);
File saveFolder = new File(Config.configurationFolder, "/Schematics/Saved"); File saveFolder = new File(Config.configurationFolder, "/schematics/saved");
if (!saveFolder.exists()) { if (!saveFolder.exists()) {
saveFolder.mkdirs(); saveFolder.mkdirs();
} }
File saveFile = new File(saveFolder.getAbsolutePath() + "/" + name + ".schem"); File saveFile = new File(saveFolder.getAbsolutePath() + "/" + id + ".schem");
try { try {
saveFile.createNewFile(); saveFile.createNewFile();
DataOutputStream schematicDataStream = new DataOutputStream(new FileOutputStream(saveFile)); DataOutputStream schematicDataStream = new DataOutputStream(new FileOutputStream(saveFile));
@ -293,5 +311,17 @@ public class SchematicHandler {
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Something went wrong while saving " + saveFile.getAbsolutePath() + " to disk.", ex); Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Something went wrong while saving " + saveFile.getAbsolutePath() + " to disk.", ex);
} }
if (!nameMap.containsKey(SAVED_POCKETS_GROUP_NAME)) {
nameMap.put(SAVED_POCKETS_GROUP_NAME, new HashMap<>());
}
Map<String, Integer> savedDungeons = nameMap.get(SAVED_POCKETS_GROUP_NAME);
if (savedDungeons.containsKey(id)) {
templates.remove((int) savedDungeons.remove(id));
}
templates.add(new PocketTemplate(SAVED_POCKETS_GROUP_NAME, id, null, null, null, schematic, -1, 0));
nameMap.get(SAVED_POCKETS_GROUP_NAME).put(id, templates.size() - 1);
} }
} }

View file

@ -95,7 +95,7 @@ public class RiftRegistry extends WorldSavedData {
// method rather than RiftSubregistry) and save each in the appropriate registry, we can't do this because it is not // method rather than RiftSubregistry) and save each in the appropriate registry, we can't do this because it is not
// always the case that all worlds will be saved at once. // always the case that all worlds will be saved at once.
@Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
if (riftRegistry == null) RiftRegistry.instance(); if (riftRegistry == null) riftRegistry = RiftRegistry.instance();
// Write rifts in this dimension // Write rifts in this dimension
NBTTagList riftsNBT = new NBTTagList(); NBTTagList riftsNBT = new NBTTagList();
NBTTagList pocketsNBT = new NBTTagList(); NBTTagList pocketsNBT = new NBTTagList();

View file

@ -3,7 +3,6 @@ package org.dimdev.dimdoors.shared.tools;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockDoor; import net.minecraft.block.BlockDoor;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.init.Bootstrap; import net.minecraft.init.Bootstrap;
import net.minecraft.item.EnumDyeColor; import net.minecraft.item.EnumDyeColor;
import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.CompressedStreamTools;
@ -19,6 +18,7 @@ import org.dimdev.ddutils.schem.Schematic;
import org.dimdev.dimdoors.DimDoors; import org.dimdev.dimdoors.DimDoors;
import org.dimdev.dimdoors.server.ServerProxy; import org.dimdev.dimdoors.server.ServerProxy;
import org.dimdev.dimdoors.shared.blocks.BlockDimensionalDoor; import org.dimdev.dimdoors.shared.blocks.BlockDimensionalDoor;
import org.dimdev.dimdoors.shared.blocks.BlockFabric;
import org.dimdev.dimdoors.shared.blocks.BlockFabricAncient; import org.dimdev.dimdoors.shared.blocks.BlockFabricAncient;
import org.dimdev.dimdoors.shared.blocks.ModBlocks; import org.dimdev.dimdoors.shared.blocks.ModBlocks;
import org.dimdev.dimdoors.shared.rifts.RiftDestination; import org.dimdev.dimdoors.shared.rifts.RiftDestination;
@ -73,102 +73,102 @@ public final class PocketSchematicGenerator {
} }
// Generate the schematics // Generate the schematics
List<Schematic> schematics = generatePocketSchematics(8); List<Schematic> schematics = generatePocketSchematics();
// Save the schematics // Save the schematics
boolean isPublic = true; String[] saveFolders = {"public/", "private/", "blank/", "blank/"};
int i = 0;
for (Schematic schematic : schematics) { for (Schematic schematic : schematics) {
NBTTagCompound schematicNBT = Schematic.saveToNBT(schematic); NBTTagCompound schematicNBT = Schematic.saveToNBT(schematic);
File saveFile = new File(schematicDir, (isPublic ? "public/" : "private/") + schematic.name + ".schem"); File saveFile = new File(schematicDir, saveFolders[i++ % saveFolders.length] + schematic.name + ".schem");
saveFile.getParentFile().mkdirs(); saveFile.getParentFile().mkdirs();
DataOutputStream schematicDataStream = new DataOutputStream(new FileOutputStream(saveFile)); DataOutputStream schematicDataStream = new DataOutputStream(new FileOutputStream(saveFile));
CompressedStreamTools.writeCompressed(schematicNBT, schematicDataStream); CompressedStreamTools.writeCompressed(schematicNBT, schematicDataStream);
schematicDataStream.flush(); schematicDataStream.flush();
schematicDataStream.close(); schematicDataStream.close();
isPublic = !isPublic;
} }
// TODO: also generate JSON files // TODO: also generate JSON files
} }
public static List<Schematic> generatePocketSchematics(int maxPocketSize) { public static List<Schematic> generatePocketSchematics() {
List<Schematic> schematics = new ArrayList<>(); List<Schematic> schematics = new ArrayList<>();
for (int pocketSize = 0; pocketSize < maxPocketSize; pocketSize++) { for (int pocketSize = 0; pocketSize < 8; pocketSize++) {
schematics.add(generatePocketSchematic( schematics.add(generateBlankWithDoor(
"public_pocket", // base name "public_pocket", // base name
pocketSize, // size pocketSize, // size
ModBlocks.ANCIENT_FABRIC.getDefaultState(), // outer wall ModBlocks.ANCIENT_FABRIC.getDefaultState(), // outer wall
ModBlocks.FABRIC.getDefaultState(), // inner wall ModBlocks.FABRIC.getDefaultState(), // inner wall
ModBlocks.DIMENSIONAL_DOOR, // door ModBlocks.DIMENSIONAL_DOOR, // door
PocketExitDestination.builder().build(),// exit rift destination PocketExitDestination.builder().build(),// exit rift destination
1)); // TODO: pass destination rather than just chaos weight LinkProperties.builder()
schematics.add(generatePocketSchematic( .groups(Collections.singleton(1))
.linksRemaining(1)
.entranceWeight(1)
.floatingWeight(1)
.build()));
schematics.add(generateBlankWithDoor(
"private_pocket", // base name "private_pocket", // base name
pocketSize, // size pocketSize, // size
ModBlocks.ANCIENT_FABRIC.getDefaultState().withProperty(BlockFabricAncient.COLOR, EnumDyeColor.WHITE), // outer wall ModBlocks.ANCIENT_FABRIC.getDefaultState().withProperty(BlockFabricAncient.COLOR, EnumDyeColor.WHITE), // outer wall
ModBlocks.FABRIC.getDefaultState().withProperty(BlockFabricAncient.COLOR, EnumDyeColor.WHITE), // inner wall ModBlocks.FABRIC.getDefaultState().withProperty(BlockFabricAncient.COLOR, EnumDyeColor.WHITE), // inner wall
ModBlocks.PERSONAL_DIMENSIONAL_DOOR, // door ModBlocks.PERSONAL_DIMENSIONAL_DOOR, // door
PrivatePocketExitDestination.builder().build(),// exit rift destination PrivatePocketExitDestination.builder().build(),// exit rift destination
0)); null));
schematics.add(generateBlank("blank_pocket",
pocketSize,
ModBlocks.ANCIENT_FABRIC.getDefaultState(),
ModBlocks.FABRIC.getDefaultState()));
schematics.add(generateFrame("void_pocket",
pocketSize,
ModBlocks.FABRIC.getDefaultState().withProperty(BlockFabric.COLOR, EnumDyeColor.LIGHT_BLUE)));
} }
return schematics; return schematics;
} }
private static Schematic generatePocketSchematic(String baseName, int pocketSize, IBlockState outerWallBlockState, IBlockState innerWallBlockState, BlockDimensionalDoor doorBlock, RiftDestination exitDest, float chaosWeight) { private static Schematic generateBlank(String baseName, int pocketSize, IBlockState outerWall, IBlockState innerWall) {
int size = (pocketSize + 1) * 16 - 1; // -1 so that the door can be centered short size = (short) ((pocketSize + 1) * 16 - 1); // -1 so that the door can be centered
// Set schematic info // Set schematic info
Schematic schematic = new Schematic(); Schematic schematic = new Schematic(baseName + "_" + pocketSize, "DimDoors", size, size, size);
schematic.version = 1; schematic.requiredMods = new String[] { DimDoors.MODID };
schematic.author = "Robijnvogel"; //@todo set in build.gradle ${modID}
schematic.name = baseName + "_" + pocketSize;
schematic.creationDate = System.currentTimeMillis();
schematic.requiredMods = new String[1];
schematic.requiredMods[0] = DimDoors.MODID;
schematic.width = (short) size;
schematic.height = (short) size;
schematic.length = (short) size;
schematic.offset = new int[]{0, 0, 0}; // TODO: center pockets
// Generate the pallette
schematic.paletteMax = 4;
schematic.pallette = new ArrayList<>();
schematic.pallette.add(Blocks.AIR.getDefaultState());
schematic.pallette.add(outerWallBlockState);
schematic.pallette.add(innerWallBlockState);
schematic.pallette.add(doorBlock.getDefaultState().withProperty(BlockDoor.HALF, BlockDoor.EnumDoorHalf.LOWER)); //bottom
schematic.pallette.add(doorBlock.getDefaultState().withProperty(BlockDoor.HALF, BlockDoor.EnumDoorHalf.UPPER)); //top
// Set block data // Set block data
schematic.blockData = new int[size][size][size]; //[x][y][z]
for (int x = 0; x < size; x++) { for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) { for (int y = 0; y < size; y++) {
for (int z = 0; z < size; z++) { for (int z = 0; z < size; z++) {
int layer = Collections.min(Arrays.asList(x, y, z, size - 1 - x, size - 1 - y, size - 1 - z)); int layer = Collections.min(Arrays.asList(x, y, z, size - 1 - x, size - 1 - y, size - 1 - z));
if (layer == 0) { if (layer == 0) {
schematic.blockData[x][y][z] = 1; // outer wall schematic.setBlockState(x, y, z, outerWall);
} else if (layer < 5) { } else if (layer < 5) {
schematic.blockData[x][y][z] = 2; // inner wall schematic.setBlockState(x, y, z, innerWall);
} else {
schematic.blockData[x][y][z] = 0; // air
} }
} }
} }
} }
schematic.blockData[(size - 1) / 2][5][4] = 3; // door bottom
schematic.blockData[(size - 1) / 2][6][4] = 4; // door top
// Generate the rift TileEntities return schematic;
}
private static Schematic generateBlankWithDoor(String baseName, int pocketSize, IBlockState outerWall, IBlockState innerWall, BlockDimensionalDoor doorBlock, RiftDestination exitDest, LinkProperties link) {
short size = (short) ((pocketSize + 1) * 16 - 1); // -1 so that the door can be centered
// Make the schematic
Schematic schematic = generateBlank(baseName, pocketSize, outerWall, innerWall);
// Add the door
schematic.setBlockState((size - 1) / 2, 5, 4, doorBlock.getDefaultState().withProperty(BlockDoor.HALF, BlockDoor.EnumDoorHalf.LOWER));
schematic.setBlockState((size - 1) / 2, 6, 4, doorBlock.getDefaultState().withProperty(BlockDoor.HALF, BlockDoor.EnumDoorHalf.UPPER));
// Set the rift entities
schematic.tileEntities = new ArrayList<>(); schematic.tileEntities = new ArrayList<>();
TileEntityEntranceRift rift = (TileEntityEntranceRift) doorBlock.createTileEntity(null, doorBlock.getDefaultState()); TileEntityEntranceRift rift = (TileEntityEntranceRift) doorBlock.createTileEntity(null, doorBlock.getDefaultState());
rift.setDestination(PocketEntranceDestination.builder() rift.setDestination(PocketEntranceDestination.builder()
.ifDestination(exitDest) .ifDestination(exitDest)
.build()); .build());
rift.setProperties(LinkProperties.builder() rift.setProperties(link);
.groups(Collections.singleton(1))
.linksRemaining(1)
.entranceWeight(chaosWeight)
.floatingWeight(chaosWeight)
.build());
rift.setPlaceRiftOnBreak(true); rift.setPlaceRiftOnBreak(true);
NBTTagCompound tileNBT = rift.serializeNBT(); NBTTagCompound tileNBT = rift.serializeNBT();
@ -179,4 +179,30 @@ public final class PocketSchematicGenerator {
return schematic; return schematic;
} }
private static Schematic generateFrame(String baseName, int chunkSize, IBlockState frame) {
short size = (short) ((chunkSize + 1) * 16 - 1); // -1 so that the door can be centered
// Set schematic info
Schematic schematic = new Schematic(baseName + "_" + chunkSize, "DimDoors", size, size, size);
schematic.requiredMods = new String[] { DimDoors.MODID };
// Set block data
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
for (int z = 0; z < size; z++) {
int sides = 0;
if (x == 0 || x == size - 1) sides++;
if (y == 0 || y == size - 1) sides++;
if (z == 0 || z == size - 1) sides++;
if (sides >= 2) {
schematic.setBlockState(x, y, z, frame);
}
}
}
}
return schematic;
}
} }

View file

@ -57,7 +57,7 @@ public final class SchematicConverter {
byte[] blockIdArray = nbt.getByteArray("Blocks"); byte[] blockIdArray = nbt.getByteArray("Blocks");
byte[] addId = nbt.getByteArray("AddBlocks"); byte[] addId = nbt.getByteArray("AddBlocks");
Map<Integer, Byte> palletteMap = new HashMap<>(); // block ID -> pallette index Map<Integer, Byte> palletteMap = new HashMap<>(); // block ID -> palette index
byte currentPalletteIndex = 0; byte currentPalletteIndex = 0;
for (int i = 0; i < blockIdArray.length; i++) { for (int i = 0; i < blockIdArray.length; i++) {
int id; int id;
@ -96,13 +96,9 @@ public final class SchematicConverter {
if (id != 0 && block.getBlock().getRegistryName().toString().equals("minecraft:air")) { if (id != 0 && block.getBlock().getRegistryName().toString().equals("minecraft:air")) {
throw new RuntimeException("Unknown ID " + id + " in schematic " + schematicId); throw new RuntimeException("Unknown ID " + id + " in schematic " + schematicId);
} }
if (block.equals(Blocks.IRON_DOOR)) { if (block.equals(Blocks.IRON_DOOR)) block = ModBlocks.DIMENSIONAL_DOOR.getDefaultState();
block = ModBlocks.DIMENSIONAL_DOOR.getDefaultState(); if (block.equals(Blocks.OAK_DOOR)) block = ModBlocks.WARP_DIMENSIONAL_DOOR.getDefaultState();
} schematic.palette.add(block);
if (block.equals(Blocks.OAK_DOOR)) {
block = ModBlocks.WARP_DIMENSIONAL_DOOR.getDefaultState();
}
schematic.pallette.add(block);
palletteMap.put(id, currentPalletteIndex); palletteMap.put(id, currentPalletteIndex);
blockIdArray[i] = currentPalletteIndex; blockIdArray[i] = currentPalletteIndex;
currentPalletteIndex++; currentPalletteIndex++;
@ -139,7 +135,7 @@ public final class SchematicConverter {
int blockInt = blockIdArray[x + z * schematic.width + y * schematic.width * schematic.length]; //according to the documentation on https://github.com/SpongePowered/Schematic-Specification/blob/master/versions/schematic-1.md int blockInt = blockIdArray[x + z * schematic.width + y * schematic.width * schematic.length]; //according to the documentation on https://github.com/SpongePowered/Schematic-Specification/blob/master/versions/schematic-1.md
int metadata = dataIntArray[x + z * schematic.width + y * schematic.width * schematic.length]; //according to the documentation on https://github.com/SpongePowered/Schematic-Specification/blob/master/versions/schematic-1.md int metadata = dataIntArray[x + z * schematic.width + y * schematic.width * schematic.length]; //according to the documentation on https://github.com/SpongePowered/Schematic-Specification/blob/master/versions/schematic-1.md
IBlockState baseState = schematic.pallette.get(blockInt); //this is the default blockstate except for ancient fabric IBlockState baseState = schematic.palette.get(blockInt); //this is the default blockstate except for ancient fabric
if (baseState == baseState.getBlock().getDefaultState() || baseState.getBlock().equals(ModBlocks.FABRIC) || baseState.getBlock().equals(ModBlocks.ANCIENT_FABRIC)) { //should only be false if {@code baseState} is ancient fabric if (baseState == baseState.getBlock().getDefaultState() || baseState.getBlock().equals(ModBlocks.FABRIC) || baseState.getBlock().equals(ModBlocks.ANCIENT_FABRIC)) { //should only be false if {@code baseState} is ancient fabric
IBlockState blockState; IBlockState blockState;
if (baseState.getBlock().equals(ModBlocks.FABRIC) || baseState.getBlock().equals(ModBlocks.ANCIENT_FABRIC)) { if (baseState.getBlock().equals(ModBlocks.FABRIC) || baseState.getBlock().equals(ModBlocks.ANCIENT_FABRIC)) {
@ -147,12 +143,12 @@ public final class SchematicConverter {
} else { } else {
blockState = baseState.getBlock().getStateFromMeta(metadata); blockState = baseState.getBlock().getStateFromMeta(metadata);
} }
if (schematic.pallette.contains(blockState)) { //check whether or not this blockstate is already in the list if (schematic.palette.contains(blockState)) { //check whether or not this blockstate is already in the list
blockInt = schematic.pallette.indexOf(blockState); blockInt = schematic.palette.indexOf(blockState);
} else { } else {
schematic.pallette.add(blockState); schematic.palette.add(blockState);
//DimDoors.log.info("New blockstate detected. Original blockInt = " + blockInt + " and blockState is " + blockState); //DimDoors.log.info("New blockstate detected. Original blockInt = " + blockInt + " and blockState is " + blockState);
blockInt = schematic.pallette.size() - 1; blockInt = schematic.palette.size() - 1;
} }
Block block = blockState.getBlock(); Block block = blockState.getBlock();
if (block.equals(Blocks.DIAMOND_BLOCK)) { if (block.equals(Blocks.DIAMOND_BLOCK)) {
@ -175,7 +171,7 @@ public final class SchematicConverter {
} else if (block.equals(Blocks.END_PORTAL_FRAME)) { } else if (block.equals(Blocks.END_PORTAL_FRAME)) {
monoliths++; monoliths++;
// I think it's safe to assume that air is present // I think it's safe to assume that air is present
blockInt = schematic.pallette.indexOf(Blocks.AIR.getDefaultState()); blockInt = schematic.palette.indexOf(Blocks.AIR.getDefaultState());
EntityMonolith monolith = new EntityMonolith(null); EntityMonolith monolith = new EntityMonolith(null);
EnumFacing facing = blockState.getValue(BlockEndPortalFrame.FACING); EnumFacing facing = blockState.getValue(BlockEndPortalFrame.FACING);
monolith.setLocationAndAngles(x + 0.5d, y, z + 0.5d, facing.getHorizontalAngle(), 0); monolith.setLocationAndAngles(x + 0.5d, y, z + 0.5d, facing.getHorizontalAngle(), 0);
@ -200,7 +196,7 @@ public final class SchematicConverter {
.weightMaximum(100) .weightMaximum(100)
.newRiftWeight(1).build()); .newRiftWeight(1).build());
} else if (block.equals(ModBlocks.WARP_DIMENSIONAL_DOOR)) { } else if (block.equals(ModBlocks.WARP_DIMENSIONAL_DOOR)) {
IBlockState stateBelow = schematic.pallette.get(schematic.blockData[x][y - 1][z]); IBlockState stateBelow = schematic.palette.get(schematic.blockData[x][y - 1][z]);
if (stateBelow.getBlock().equals(Blocks.SANDSTONE)) { if (stateBelow.getBlock().equals(Blocks.SANDSTONE)) {
sandstoneDoors++; sandstoneDoors++;
rift.setProperties(null); // TODO: this should be removed once the linking equations are made symmetric rift.setProperties(null); // TODO: this should be removed once the linking equations are made symmetric
@ -248,8 +244,18 @@ public final class SchematicConverter {
schematic.tileEntities.add(rift.serializeNBT()); schematic.tileEntities.add(rift.serializeNBT());
} }
} }
if (blockState.getBlock().equals(Blocks.END_PORTAL_FRAME)) {
monoliths++;
// I think it's safe to assume that air is present
blockInt = schematic.palette.indexOf(Blocks.AIR.getDefaultState());
EntityMonolith monolith = new EntityMonolith(null);
EnumFacing facing = blockState.getValue(BlockEndPortalFrame.FACING);
monolith.setLocationAndAngles(x + 0.5d, y, z + 0.5d, facing.getHorizontalAngle(), 0);
schematic.entities.add(monolith.serializeNBT());
}
} else { // if this is ancient fabric } else { // if this is ancient fabric
blockInt = schematic.pallette.indexOf(baseState); blockInt = schematic.palette.indexOf(baseState);
} }
assert blockInt >= 0; assert blockInt >= 0;
schematic.blockData[x][y][z] = blockInt; schematic.blockData[x][y][z] = blockInt;
@ -259,7 +265,7 @@ public final class SchematicConverter {
if (!nbt.getTag("Entities").hasNoTags()) { if (!nbt.getTag("Entities").hasNoTags()) {
throw new RuntimeException("Schematic contains entities, but those aren't implemented in the conversion code"); throw new RuntimeException("Schematic contains entities, but those aren't implemented in the conversion code");
} }
schematic.paletteMax = schematic.pallette.size() - 1; schematic.paletteMax = schematic.palette.size() - 1;
DimDoors.log.info(schematicId + "," + ironDoors + "," + woodDoors + "," + sandstoneDoors + "," + monoliths + "," + DimDoors.log.info(schematicId + "," + ironDoors + "," + woodDoors + "," + sandstoneDoors + "," + monoliths + "," +
chests + "," + dispensers + "," + diamondBlocks + "," + goldBlocks + "," + ironBlocks); chests + "," + dispensers + "," + diamondBlocks + "," + goldBlocks + "," + ironBlocks);

View file

@ -23,7 +23,9 @@ public final class ModDimensions {
@Getter private static int privateDim; @Getter private static int privateDim;
@Getter private static int publicDim; @Getter private static int publicDim;
@Getter private static int dungeonDim; @Getter private static int dungeonDim;
@Getter private static int dungeonMakingDim;
@SuppressWarnings("UnusedAssignment")
public static void registerDimensions() { public static void registerDimensions() {
// TODO: more than 1 dimension/dimension type // TODO: more than 1 dimension/dimension type
int dim = Config.getBaseDim(); int dim = Config.getBaseDim();
@ -31,10 +33,12 @@ public final class ModDimensions {
privateDim = dim++; privateDim = dim++;
publicDim = dim++; publicDim = dim++;
dungeonDim = dim++; dungeonDim = dim++;
dungeonMakingDim = dim++;
DimensionManager.registerDimension(limboDim, LIMBO); DimensionManager.registerDimension(limboDim, LIMBO);
DimensionManager.registerDimension(privateDim, PRIVATE); DimensionManager.registerDimension(privateDim, PRIVATE);
DimensionManager.registerDimension(publicDim, PUBLIC); DimensionManager.registerDimension(publicDim, PUBLIC);
DimensionManager.registerDimension(dungeonDim, DUNGEON); DimensionManager.registerDimension(dungeonDim, DUNGEON);
DimensionManager.registerDimension(dungeonMakingDim, DUNGEON);
} }
public static boolean isDimDoorsPocketDimension(int id) { public static boolean isDimDoorsPocketDimension(int id) {

View file

@ -0,0 +1,69 @@
{
"group": "blank",
"pockets": [
{
"id": "blank_pocket_0",
"size": 0
},
{
"id": "blank_pocket_1",
"size": 1
},
{
"id": "blank_pocket_2",
"size": 2
},
{
"id": "blank_pocket_3",
"size": 3
},
{
"id": "blank_pocket_4",
"size": 4
},
{
"id": "blank_pocket_5",
"size": 5
},
{
"id": "blank_pocket_6",
"size": 6
},
{
"id": "blank_pocket_7",
"size": 7
},
{
"id": "void_pocket_0",
"size": 0
},
{
"id": "void_pocket_1",
"size": 1
},
{
"id": "void_pocket_2",
"size": 2
},
{
"id": "void_pocket_3",
"size": 3
},
{
"id": "void_pocket_4",
"size": 4
},
{
"id": "void_pocket_5",
"size": 5
},
{
"id": "void_pocket_6",
"size": 6
},
{
"id": "void_pocket_7",
"size": 7
}
]
}