Schematic generation command

-Completed command to force-generate Dungeon Pocket Schematics using
their directory (/group) and name
-Schematics now inherrit their name from their file name if it's not set
in their NBT

Warning:
-Quite a few of the pockets themselves show errouneous behaviour when
you try to generate them.
This commit is contained in:
Mathijs Riezebos 2017-05-01 20:18:00 +02:00
parent 13296ffdb9
commit fa6d32cf0c
7 changed files with 142 additions and 26 deletions

View file

@ -61,7 +61,7 @@ public class Pocket {
return z; return z;
} }
int getEntranceDoorID() { public int getEntranceDoorID() {
if (riftIDs.isEmpty()) { if (riftIDs.isEmpty()) {
return -1; return -1;
} else if (riftIDs.size() == 1) { } else if (riftIDs.size() == 1) {

View file

@ -195,6 +195,10 @@ public class PocketRegistry {
//Fetching the pocket template //Fetching the pocket template
PocketTemplate pocketTemplate = getRandomPocketTemplate(typeID, depth, maxPocketSize); PocketTemplate pocketTemplate = getRandomPocketTemplate(typeID, depth, maxPocketSize);
return generatePocketAt(typeID, depth, origRiftLocation, pocketTemplate);
}
public Pocket generatePocketAt(EnumPocketType typeID, int depth, Location origRiftLocation, PocketTemplate pocketTemplate) {
//Getting the physical grid-location and the Overworld coordinates //Getting the physical grid-location and the Overworld coordinates
Location shortenedLocation = getGenerationlocation(nextUnusedIDs.get(typeID), typeID); Location shortenedLocation = getGenerationlocation(nextUnusedIDs.get(typeID), typeID);
int shortenedX = shortenedLocation.getPos().getX(); int shortenedX = shortenedLocation.getPos().getX();

View file

@ -30,14 +30,16 @@ public class PocketTemplate { //there is exactly one pocket placer for each diff
private final int size; private final int size;
private final EnumPocketType typeID; private final EnumPocketType typeID;
//selection parameters //selection parameters
private final String directoryName;
private final String variantName; private final String variantName;
private final int minDepth; private final int minDepth;
private final int maxDepth; private final int maxDepth;
private final int[] weights; //weights for chanced generation of dungeons per depth level | weights[0] is the weight for depth "minDepth" private final int[] weights; //weights for chanced generation of dungeons per depth level | weights[0] is the weight for depth "minDepth"
//this class should contain the actual schematic info, as well as some of the Json info (placement of Rifts and stuff) //this class should contain the actual schematic info, as well as some of the Json info (placement of Rifts and stuff)
public PocketTemplate(String variantName, Schematic schematic, int size, EnumPocketType typeID, public PocketTemplate(String directoryName, String variantName, Schematic schematic, int size,
int minDepth, int maxDepth, int[] weights) { EnumPocketType typeID, int minDepth, int maxDepth, int[] weights) {
this.directoryName = directoryName;
this.variantName = variantName; this.variantName = variantName;
this.weights = weights; //chance that this Pocket will get generated this.weights = weights; //chance that this Pocket will get generated
this.minDepth = minDepth; //pocket will only be generated from this Pocket-depth this.minDepth = minDepth; //pocket will only be generated from this Pocket-depth
@ -47,8 +49,9 @@ public class PocketTemplate { //there is exactly one pocket placer for each diff
this.typeID = typeID; this.typeID = typeID;
} }
public PocketTemplate(String variantName, int size, EnumPocketType typeID, int minDepth, int maxDepth, int[] weights) { public PocketTemplate(String directoryName, String variantName, int size,
this(variantName, null, size, typeID, minDepth, maxDepth, weights); EnumPocketType typeID, int minDepth, int maxDepth, int[] weights) {
this(directoryName, variantName, null, size, typeID, minDepth, maxDepth, weights);
} }
int getSize() { int getSize() {
@ -71,6 +74,10 @@ public class PocketTemplate { //there is exactly one pocket placer for each diff
return 0; //do not generate return 0; //do not generate
} }
String getDirName() {
return directoryName;
}
public String getName() { public String getName() {
return variantName; return variantName;
} }

View file

@ -432,4 +432,11 @@ public class RiftRegistry {
DDTileEntityBase rift = (DDTileEntityBase) rifts.get(riftID).getTileEntity(); DDTileEntityBase rift = (DDTileEntityBase) rifts.get(riftID).getTileEntity();
return rift.getPocketID(); return rift.getPocketID();
} }
/**
* @param ID the lastGeneratedEntranceDoorID to set
*/
public void setLastGeneratedEntranceDoorID(int ID) {
this.lastGeneratedEntranceDoorID = ID;
}
} }

View file

@ -25,8 +25,11 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
@ -42,7 +45,8 @@ public class SchematicHandler {
public static final SchematicHandler INSTANCE = new SchematicHandler(); public static final SchematicHandler INSTANCE = new SchematicHandler();
private PocketTemplate personalPocketTemplate; private PocketTemplate personalPocketTemplate;
private PocketTemplate publicPocketTemplate; private PocketTemplate publicPocketTemplate;
private List<PocketTemplate> dungeonTemplates; private List<PocketTemplate> dungeonTemplates; //@todo should this be a Map? Does it need to? It gets reloaded from scratch on ServerStart every time, so...
final private Map<String, Map<String, Integer>> dungeonNameMap = new HashMap();
//@todo, sort templates by depth over here? that'd mean that that doesn't have to be done on pocket placement each and every time //@todo, sort templates by depth over here? that'd mean that that doesn't have to be done on pocket placement each and every time
PocketTemplate getRandomDungeonPocketTemplate(int depth, int maxPocketSize) { PocketTemplate getRandomDungeonPocketTemplate(int depth, int maxPocketSize) {
@ -86,9 +90,36 @@ public class SchematicHandler {
} }
} }
} }
constructDungeonNameMap();
//Schematic.TempGenerateDefaultSchematics(); //Schematic.TempGenerateDefaultSchematics();
} }
private void constructDungeonNameMap() {
//init
dungeonNameMap.clear();
//to prevent having to use too many getters
String bufferedDirectory = null;
Map<String, Integer> bufferedMap = null;
for (PocketTemplate template : dungeonTemplates) {
String dirName = template.getDirName();
if (dirName != null && dirName.equals(bufferedDirectory)) { //null check not needed
bufferedMap.put(template.getName(), dungeonTemplates.indexOf(template));
} else {
bufferedDirectory = dirName;
if (dungeonNameMap.containsKey(dirName)) { //this will only happen if you have two json files referring to the same directory being loaded non-consecutively
bufferedMap = dungeonNameMap.get(dirName);
bufferedMap.put(template.getName(), dungeonTemplates.indexOf(template));
} else {
bufferedMap = new HashMap();
bufferedMap.put(template.getName(), dungeonTemplates.indexOf(template));
dungeonNameMap.put(dirName, bufferedMap);
}
}
}
}
private static List<PocketTemplate> loadTemplatesFromJson(String nameString, int maxPocketSize) { //depending on the "jSonType" value in the jSon, this might load several variations of a pocket at once, hence loadTemplate -->s<-- private static List<PocketTemplate> loadTemplatesFromJson(String nameString, int maxPocketSize) { //depending on the "jSonType" value in the jSon, this might load several variations of a pocket at once, hence loadTemplate -->s<--
InputStream jsonJarStream = DimDoors.class.getResourceAsStream("/assets/dimdoors/pockets/json/" + nameString + ".json"); InputStream jsonJarStream = DimDoors.class.getResourceAsStream("/assets/dimdoors/pockets/json/" + nameString + ".json");
String schematicJarDirectory = "/assets/dimdoors/pockets/schematic/"; String schematicJarDirectory = "/assets/dimdoors/pockets/schematic/";
@ -136,8 +167,9 @@ public class SchematicHandler {
List<PocketTemplate> validTemplates = getAllValidVariations(jsonTemplate, maxPocketSize); List<PocketTemplate> validTemplates = getAllValidVariations(jsonTemplate, maxPocketSize);
//DimDoors.log(SchematicHandler.class, "Checkpoint 4 reached; " + validTemplates.size() + " templates were loaded"); //DimDoors.log(SchematicHandler.class, "Checkpoint 4 reached; " + validTemplates.size() + " templates were loaded");
for (PocketTemplate template : validTemplates) { //it's okay to "tap" this for-loop, even if validTemplates is empty.
String subDirectory = jsonTemplate.get("directory").getAsString(); //get the subfolder in which the schematics are stored String subDirectory = jsonTemplate.get("directory").getAsString(); //get the subfolder in which the schematics are stored
for (PocketTemplate template : validTemplates) { //it's okay to "tap" this for-loop, even if validTemplates is empty.
String extendedTemplatelocation = subDirectory.equals("") ? template.getName() : subDirectory + "/" + template.getName(); //transform the filename accordingly String extendedTemplatelocation = subDirectory.equals("") ? template.getName() : subDirectory + "/" + template.getName(); //transform the filename accordingly
//Initialising the possible locations/formats for the schematic file //Initialising the possible locations/formats for the schematic file
@ -172,7 +204,7 @@ public class SchematicHandler {
Schematic schematic = null; Schematic schematic = null;
try { try {
schematicNBT = CompressedStreamTools.readCompressed(schematicDataStream); schematicNBT = CompressedStreamTools.readCompressed(schematicDataStream);
schematic = Schematic.loadFromNBT(schematicNBT); schematic = Schematic.loadFromNBT(schematicNBT, template.getName());
schematicDataStream.close(); schematicDataStream.close();
} catch (IOException ex) { } catch (IOException ex) {
Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Schematic file for " + template.getName() + " could not be read as a valid schematic NBT file.", ex); Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Schematic file for " + template.getName() + " could not be read as a valid schematic NBT file.", ex);
@ -201,9 +233,10 @@ public class SchematicHandler {
} }
private static List<PocketTemplate> getAllValidVariations(JsonObject jsonTemplate, int maxPocketSize) { private static List<PocketTemplate> getAllValidVariations(JsonObject jsonTemplate, int maxPocketSize) {
String jsonType = jsonTemplate.get("jsonType").getAsString(); final String directory = jsonTemplate.get("directory").getAsString();
EnumPocketType pocketType = EnumPocketType.getFromInt(jsonTemplate.get("pocketType").getAsInt()); final String jsonType = jsonTemplate.get("jsonType").getAsString();
JsonArray variations = jsonTemplate.getAsJsonArray("variations"); final EnumPocketType pocketType = EnumPocketType.getFromInt(jsonTemplate.get("pocketType").getAsInt());
final JsonArray variations = jsonTemplate.getAsJsonArray("variations");
List<PocketTemplate> pocketTemplates = new ArrayList(); List<PocketTemplate> pocketTemplates = new ArrayList();
JsonObject chosenVariation = null; //only applicable if jsonType == "Singular" JsonObject chosenVariation = null; //only applicable if jsonType == "Singular"
@ -247,7 +280,7 @@ public class SchematicHandler {
for (int j = 0; j < weightsJsonArray.size(); j++) { for (int j = 0; j < weightsJsonArray.size(); j++) {
weights[j] = weightsJsonArray.get(j).getAsInt(); weights[j] = weightsJsonArray.get(j).getAsInt();
} }
PocketTemplate pocketTemplate = new PocketTemplate(variantName, variationSize, pocketType, minDepth, maxDepth, weights); PocketTemplate pocketTemplate = new PocketTemplate(directory, variantName, variationSize, pocketType, minDepth, maxDepth, weights);
pocketTemplates.add(pocketTemplate); pocketTemplates.add(pocketTemplate);
} }
@ -268,6 +301,26 @@ public class SchematicHandler {
return publicPocketTemplate; return publicPocketTemplate;
} }
/**
* @param directory file directory of the template schematic
* @param name filename of the template schematic
* @return the dungeonTemplate that was loaded from folder {@code directory}
* with filename {@code name}
*/
public PocketTemplate getDungeonTemplate(String directory, String name) {
//@todo nullcheck on the parameters
int index = dungeonNameMap.get(directory).get(name);
return dungeonTemplates.get(index);
}
public ArrayList<String> getDungeonTemplateGroups() {
return new ArrayList(dungeonNameMap.keySet());
}
public ArrayList<String> getDungeonTemplateNames(String directory) {
return new ArrayList(dungeonNameMap.get(directory).keySet());
}
/** /**
* @return the dungeonTemplates * @return the dungeonTemplates
*/ */

View file

@ -1,7 +1,9 @@
package com.zixiken.dimdoors.shared.commands; package com.zixiken.dimdoors.shared.commands;
import com.zixiken.dimdoors.DimDoors;
import com.zixiken.dimdoors.shared.*; import com.zixiken.dimdoors.shared.*;
import com.zixiken.dimdoors.shared.tileentities.TileEntityDimDoor; import com.zixiken.dimdoors.shared.tileentities.TileEntityDimDoor;
import com.zixiken.dimdoors.shared.util.Location;
import net.minecraft.command.CommandBase; import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException; import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender; import net.minecraft.command.ICommandSender;
@ -13,7 +15,6 @@ import net.minecraft.world.World;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
public class PocketCommand extends CommandBase { public class PocketCommand extends CommandBase {
@ -32,7 +33,7 @@ public class PocketCommand extends CommandBase {
@Override @Override
public String getUsage(ICommandSender sender) { public String getUsage(ICommandSender sender) {
return "dimpocket <name>"; return "dimpocket <group> <name>";
} }
@Override @Override
@ -43,16 +44,60 @@ public class PocketCommand extends CommandBase {
@Override @Override
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
if(sender instanceof EntityPlayerMP) { if (sender instanceof EntityPlayerMP) {
EntityPlayerMP player = getCommandSenderAsPlayer(sender); EntityPlayerMP player = getCommandSenderAsPlayer(sender);
if (areArgumentsValid(args, player)) {
DimDoors.log(this.getClass(), "Executing command");
BlockPos pos = player.getPosition(); BlockPos pos = player.getPosition();
World world = player.world; World world = player.world;
Location playerLoc = new Location(world, pos);
TileEntityDimDoor newRift = (TileEntityDimDoor) world.getTileEntity(pos); PocketTemplate template = SchematicHandler.INSTANCE.getDungeonTemplate(args[0], args[1]);
Pocket pocket = PocketRegistry.INSTANCE.generatePocketAt(EnumPocketType.DUNGEON, 1, playerLoc, template);
int entranceDoorID = pocket.getEntranceDoorID();
RiftRegistry.INSTANCE.setLastGeneratedEntranceDoorID(entranceDoorID);
}
} else {
DimDoors.log(this.getClass(), "Not executing command, because it wasn't sent by a player.");
} }
} }
@Override
public List<String> getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos pos) { public List<String> getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos pos) {
return SchematicHandler.INSTANCE.getDungeonTemplates().stream().map(PocketTemplate::getName).collect(Collectors.toList()); if (args == null || args.length < 2) { //counts an empty ("") argument as an argument as well...
return SchematicHandler.INSTANCE.getDungeonTemplateGroups();
} else if (args.length == 2) {
return SchematicHandler.INSTANCE.getDungeonTemplateNames(args[0]);
} else if (args.length == 3) {
List<String> list = new ArrayList();
list.add("Remove_this");
return list;
} else {
List<String> list = new ArrayList();
list.add("No_seriously");
return list;
}
}
private boolean areArgumentsValid(String[] args, EntityPlayerMP player) {
if (args.length < 2) {
DimDoors.chat(player, "Too few arguments.");
return false;
} else if (args.length > 2) {
DimDoors.chat(player, "Too many arguments.");
return false;
} else { //exactly 2 arguments
if (!SchematicHandler.INSTANCE.getDungeonTemplateGroups().contains(args[0])) {
DimDoors.chat(player, "Group not found.");
return false;
} else if (!SchematicHandler.INSTANCE.getDungeonTemplateNames(args[0]).contains(args[1])) {
DimDoors.chat(player, "Schematic not found.");
return false;
} else {
DimDoors.chat(player, "Generating schematic " + args[1]);
return true;
}
}
} }
} }

View file

@ -56,9 +56,9 @@ public class Schematic {
private Schematic() { private Schematic() {
} }
public static Schematic loadFromNBT(NBTTagCompound nbt) { public static Schematic loadFromNBT(NBTTagCompound nbt, String parName) {
if (!nbt.hasKey("Version")) { if (!nbt.hasKey("Version")) {
return loadOldDimDoorSchematicFromNBT(nbt); return loadOldDimDoorSchematicFromNBT(nbt, parName);
} }
Schematic schematic = new Schematic(); Schematic schematic = new Schematic();
@ -70,9 +70,9 @@ public class Schematic {
if (nbt.hasKey("Author")) { //Author is not required if (nbt.hasKey("Author")) { //Author is not required
schematic.author = metadataCompound.getString("Author"); schematic.author = metadataCompound.getString("Author");
} }
if (nbt.hasKey("Name")) { //Name is not required //Name is not required (may be null)
schematic.schematicName = metadataCompound.getString("Name"); schematic.schematicName = (parName == null || parName.equals("")) && nbt.hasKey("Name") ? metadataCompound.getString("Name") : parName;
}
if (nbt.hasKey("Date")) { //Date is not required if (nbt.hasKey("Date")) { //Date is not required
schematic.creationDate = metadataCompound.getLong("Date"); schematic.creationDate = metadataCompound.getLong("Date");
} }
@ -308,12 +308,12 @@ public class Schematic {
return tileEntities; return tileEntities;
} }
public static Schematic loadOldDimDoorSchematicFromNBT(NBTTagCompound nbt) { //@todo, maybe make this a separate class, so values can be final so they HAVE TO be set in a newly designed constructor? public static Schematic loadOldDimDoorSchematicFromNBT(NBTTagCompound nbt, String parName) { //@todo, maybe make this a separate class, so values can be final so they HAVE TO be set in a newly designed constructor?
Schematic schematic = new Schematic(); Schematic schematic = new Schematic();
//schematic.version = 1; //already the default value //schematic.version = 1; //already the default value
//schematic.author = "DimDoors"; //already the default value //schematic.author = "DimDoors"; //already the default value
schematic.schematicName = "This schematic was converted from an MC 1.7.10 DimDoors schematic"; schematic.schematicName = parName.equals("") ? "Auto-converted-DimDoors-for-MC-1.7.10-schematic" : parName;
schematic.creationDate = System.currentTimeMillis(); schematic.creationDate = System.currentTimeMillis();
schematic.requiredMods = new String[]{DimDoors.MODID}; schematic.requiredMods = new String[]{DimDoors.MODID};