From d8d3fa4fc9d320e342c9ed65383f5d7394305665 Mon Sep 17 00:00:00 2001 From: Runemoro Date: Fri, 19 Jan 2018 18:49:27 -0500 Subject: [PATCH] Fix /saveschem and support loading schematics from save folder --- .../org/dimdev/ddutils/schem/Schematic.java | 55 +++++++++++-------- .../shared/commands/CommandSaveSchem.java | 24 ++++---- .../dimdoors/shared/pockets/Pocket.java | 2 +- .../shared/pockets/PocketRegistry.java | 11 +++- .../shared/pockets/SchematicHandler.java | 38 +++++++++++-- .../dimdoors/shared/world/ModDimensions.java | 4 ++ 6 files changed, 90 insertions(+), 44 deletions(-) diff --git a/src/main/java/org/dimdev/ddutils/schem/Schematic.java b/src/main/java/org/dimdev/ddutils/schem/Schematic.java index 7c587111..b14112be 100644 --- a/src/main/java/org/dimdev/ddutils/schem/Schematic.java +++ b/src/main/java/org/dimdev/ddutils/schem/Schematic.java @@ -2,7 +2,6 @@ package org.dimdev.ddutils.schem; import com.flowpowered.math.vector.Vector3i; import com.google.common.collect.ArrayListMultimap; -import javafx.geometry.BoundingBox; import net.minecraft.block.Block; import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.BlockStateContainer; @@ -252,14 +251,12 @@ public class Schematic { return totalString; } - public static Schematic createFromWorld(String name, String author, World world, Vector3i pos1, Vector3i pos2) { + public static Schematic createFromWorld(World world, Vector3i from, Vector3i to) { Schematic schematic = new Schematic(); - schematic.author = author; - schematic.name = name; - Vector3i min = pos1.min(pos2); - Vector3i max = pos1.max(pos2); - Vector3i dimensions = max.sub(min); + 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(); @@ -273,38 +270,50 @@ public class Schematic { 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); + 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)); + if (id.contains(":")) mods.add(id.split(":")[0]); + states.put(state, new BlockPos(x, y, z)); - Optional.ofNullable(world.getTileEntity(pos)).ifPresent(tileEntity -> schematic.tileEntities.add(tileEntity.serializeNBT())); + 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[0]); + 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])) { + for (BlockPos pos : states.get(keys[i])) { schematic.blockData[pos.getX()][pos.getY()][pos.getZ()] = i; } schematic.pallette.add(i, keys[i]); } - for(Entity entity : world.getEntitiesInAABBexcluding(null, getBoundingBox(pos1, pos2), entity -> !(entity instanceof EntityPlayerMP))) { - try { - schematic.entities.add(entity.serializeNBT()); - System.out.println(entity.getName() + " has serialized. Skipping."); - } catch (Exception e) { - System.out.println(entity.getName() + " has failed to serialize. Skipping."); - } + 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[0]); + schematic.requiredMods = mods.toArray(new String[mods.size()]); schematic.paletteMax = keys.length; schematic.creationDate = System.currentTimeMillis(); @@ -315,7 +324,7 @@ public class Schematic { 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) { + 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 List palette = schematic.pallette; int[][][] blockData = schematic.blockData; @@ -375,7 +384,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); } } 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."); } } diff --git a/src/main/java/org/dimdev/dimdoors/shared/commands/CommandSaveSchem.java b/src/main/java/org/dimdev/dimdoors/shared/commands/CommandSaveSchem.java index 2059b136..784ffc0c 100644 --- a/src/main/java/org/dimdev/dimdoors/shared/commands/CommandSaveSchem.java +++ b/src/main/java/org/dimdev/dimdoors/shared/commands/CommandSaveSchem.java @@ -8,14 +8,12 @@ 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.Location; -import org.dimdev.ddutils.TeleportUtils; -import org.dimdev.ddutils.WorldUtils; import org.dimdev.ddutils.schem.Schematic; import org.dimdev.dimdoors.DimDoors; -import org.dimdev.dimdoors.shared.pockets.*; -import org.dimdev.dimdoors.shared.rifts.TileEntityRift; -import org.dimdev.dimdoors.shared.world.ModDimensions; +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; @@ -46,27 +44,27 @@ public class CommandSaveSchem extends CommandBase { @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) { + 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(ModDimensions.isDimDoorsPocketDimension(player.world)) { - player.sendMessage(new TextComponentString("Current Dimension isn't a pocket dimension")); + 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(args[0], player.getName(), player.world, toVector3i(pocket.getOrigin()), toVector3i(pocket.getOrigin()).add(Vector3i.from(pocket.getSize()*16))); + Schematic schematic = Schematic.createFromWorld(player.world, toVector3i(pocket.getOrigin()), toVector3i(pocket.getOrigin()).add(Vector3i.from((pocket.getSize() + 1) * 16))); + 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."); } diff --git a/src/main/java/org/dimdev/dimdoors/shared/pockets/Pocket.java b/src/main/java/org/dimdev/dimdoors/shared/pockets/Pocket.java index caf5f815..de6d86b9 100644 --- a/src/main/java/org/dimdev/dimdoors/shared/pockets/Pocket.java +++ b/src/main/java/org/dimdev/dimdoors/shared/pockets/Pocket.java @@ -29,7 +29,7 @@ import java.util.List; @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 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 Location entrance; // TODO: move this to the rift registry (pocketlib) @Saved @Getter protected List riftLocations; // TODO: convert to a list of all tile entities (for chests, and to make it independant of pocketlib) diff --git a/src/main/java/org/dimdev/dimdoors/shared/pockets/PocketRegistry.java b/src/main/java/org/dimdev/dimdoors/shared/pockets/PocketRegistry.java index 6a7b2435..a7e8a634 100644 --- a/src/main/java/org/dimdev/dimdoors/shared/pockets/PocketRegistry.java +++ b/src/main/java/org/dimdev/dimdoors/shared/pockets/PocketRegistry.java @@ -2,6 +2,7 @@ package org.dimdev.dimdoors.shared.pockets; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; +import net.minecraft.world.World; import org.dimdev.annotatednbt.Saved; import org.dimdev.annotatednbt.NBTSerializable; import org.dimdev.dimdoors.shared.Config; @@ -9,7 +10,6 @@ import org.dimdev.ddutils.math.GridUtils; import org.dimdev.dimdoors.DimDoors; import org.dimdev.ddutils.nbt.NBTUtils; import org.dimdev.ddutils.WorldUtils; -import org.dimdev.dimdoors.shared.world.ModDimensions; import java.util.HashMap; import java.util.Map; @@ -21,6 +21,7 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.BlockPos; import net.minecraft.world.storage.MapStorage; import net.minecraft.world.storage.WorldSavedData; +import org.dimdev.dimdoors.shared.world.pocketdimension.WorldProviderPocket; @NBTSerializable public class 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) { - 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); if (instance == null) { diff --git a/src/main/java/org/dimdev/dimdoors/shared/pockets/SchematicHandler.java b/src/main/java/org/dimdev/dimdoors/shared/pockets/SchematicHandler.java index 6bcdbb84..0de9b0e7 100644 --- a/src/main/java/org/dimdev/dimdoors/shared/pockets/SchematicHandler.java +++ b/src/main/java/org/dimdev/dimdoors/shared/pockets/SchematicHandler.java @@ -33,7 +33,8 @@ import org.dimdev.dimdoors.shared.world.ModDimensions; */ 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 templates; private Map> nameMap; // group -> name -> index in templates @@ -71,6 +72,21 @@ public class SchematicHandler { 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(); DimDoors.log.info("Loaded " + templates.size() + " templates."); @@ -202,6 +218,8 @@ public class SchematicHandler { } } } + + nameMap.put(SAVED_POCKETS_GROUP_NAME, new HashMap<>()); } public Set getTemplateGroups() { @@ -273,14 +291,14 @@ public class SchematicHandler { 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); - File saveFolder = new File(Config.configurationFolder, "/Schematics/Saved"); + File saveFolder = new File(Config.configurationFolder, "/schematics/saved"); if (!saveFolder.exists()) { saveFolder.mkdirs(); } - File saveFile = new File(saveFolder.getAbsolutePath() + "/" + name + ".schem"); + File saveFile = new File(saveFolder.getAbsolutePath() + "/" + id + ".schem"); try { saveFile.createNewFile(); DataOutputStream schematicDataStream = new DataOutputStream(new FileOutputStream(saveFile)); @@ -290,5 +308,17 @@ public class SchematicHandler { } catch (IOException 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 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); } } diff --git a/src/main/java/org/dimdev/dimdoors/shared/world/ModDimensions.java b/src/main/java/org/dimdev/dimdoors/shared/world/ModDimensions.java index 9682afdf..b67a2c69 100644 --- a/src/main/java/org/dimdev/dimdoors/shared/world/ModDimensions.java +++ b/src/main/java/org/dimdev/dimdoors/shared/world/ModDimensions.java @@ -23,7 +23,9 @@ public final class ModDimensions { @Getter private static int privateDim; @Getter private static int publicDim; @Getter private static int dungeonDim; + @Getter private static int dungeonMakingDim; + @SuppressWarnings("UnusedAssignment") public static void registerDimensions() { // TODO: more than 1 dimension/dimension type int dim = Config.getBaseDim(); @@ -31,10 +33,12 @@ public final class ModDimensions { privateDim = dim++; publicDim = dim++; dungeonDim = dim++; + dungeonMakingDim = dim++; DimensionManager.registerDimension(limboDim, LIMBO); DimensionManager.registerDimension(privateDim, PRIVATE); DimensionManager.registerDimension(publicDim, PUBLIC); DimensionManager.registerDimension(dungeonDim, DUNGEON); + DimensionManager.registerDimension(dungeonMakingDim, DUNGEON); } public static boolean isDimDoorsPocketDimension(int id) {