Fix /saveschem and support loading schematics from save folder

This commit is contained in:
Runemoro 2018-01-19 18:49:27 -05:00
parent 9fa97d6ff2
commit d8d3fa4fc9
6 changed files with 90 additions and 44 deletions

View file

@ -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<IBlockState> 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.");
}
}

View file

@ -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.");
}

View file

@ -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<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.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) {

View file

@ -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<PocketTemplate> templates;
private Map<String, Map<String, Integer>> 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<String> 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<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

@ -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) {