diff --git a/StevenDimDoors/mod_pocketDim/DimData.java b/StevenDimDoors/mod_pocketDim/DimData.java index 8783e83..2da42b1 100644 --- a/StevenDimDoors/mod_pocketDim/DimData.java +++ b/StevenDimDoors/mod_pocketDim/DimData.java @@ -16,37 +16,37 @@ public class DimData implements Serializable public int dimID; public int depth; public int dimOrientation; - + public World world; - + public LinkData exitDimLink; - + public boolean isPocket; public boolean hasBeenFilled=false; public boolean hasDoor=false; public boolean isDimRandomRift=false; public DungeonGenerator dungeonGenerator = null; //public boolean isPrivatePocket = false; - public HashMap>> linksInThisDim=new HashMap(); + public HashMap>> linksInThisDim = new HashMap(); HashMap dimX; HashMap> dimY ; - + static final long serialVersionUID = 454342L; - + public DimData(int dimID, boolean isPocket, int depth, LinkData exitLinkData) { this.dimID=dimID; this.depth=depth; this.isPocket=isPocket; - + this.exitDimLink= exitLinkData; } - + public DimData(int dimID, boolean isPocket, int depth, int exitLinkDimID, int exitX, int exitY, int exitZ) { this(dimID, isPocket, depth, new LinkData(exitLinkDimID, exitX, exitY, exitZ)); } - + public LinkData findNearestRift(World world, int range, int x, int y, int z) { LinkData nearest=null; @@ -55,7 +55,7 @@ public class DimData implements Serializable int j=-range; int k=-range; DDProperties properties = DDProperties.instance(); - + while (i(); this.dimY=new HashMap>(); } - + this.dimX.put(link.locXCoord, link); this.dimY.put(link.locYCoord, dimX); this.linksInThisDim.put(link.locZCoord, dimY); - + //System.out.println("added link to dim "+this.dimID); return link; - + } - + public LinkData addLinkToDim( int destinationDimID, int locationXCoord, int locationYCoord, int locationZCoord, int destinationXCoord, int destinationYCoord, int destinationZCoord, int linkOrientation) { LinkData linkData= new LinkData(this.dimID, destinationDimID, locationXCoord, locationYCoord, locationZCoord, destinationXCoord, destinationYCoord,destinationZCoord,this.isPocket,linkOrientation); - + return this.addLinkToDim(linkData); } - + public boolean isLimbo() { return (this.dimID == DDProperties.instance().LimboDimensionID); } - + public void removeLinkAtCoords(LinkData link) { this.removeLinkAtCoords(link.locDimID, link.locXCoord, link.locYCoord, link.locZCoord); } - + public void removeLinkAtCoords(int locationID, int locationXCoord, int locationYCoord, int locationZCoord) { if (this.linksInThisDim.containsKey(locationZCoord)) { this.dimY=this.linksInThisDim.get(locationZCoord); - + if(this.dimY.containsKey(locationYCoord)) { this.dimX=this.dimY.get(locationYCoord); @@ -199,80 +199,59 @@ public class DimData implements Serializable this.dimX=new HashMap(); this.dimY=new HashMap>(); } - - + this.dimX.remove(locationXCoord); this.dimY.put(locationYCoord, dimX); this.linksInThisDim.put(locationZCoord, dimY); - - - - - - - - - } - + public LinkData findLinkAtCoords(int locationXCoord, int locationYCoord, int locationZCoord) { try { - if(this.linksInThisDim.containsKey(locationZCoord)) - { - this.dimY=this.linksInThisDim.get(locationZCoord); - - if(this.dimY.containsKey(locationYCoord)) + if(this.linksInThisDim.containsKey(locationZCoord)) { - this.dimX=this.dimY.get(locationYCoord); - - if(this.dimX.containsKey(locationXCoord)) + this.dimY=this.linksInThisDim.get(locationZCoord); + + if(this.dimY.containsKey(locationYCoord)) { - return this.dimX.get(locationXCoord); + this.dimX=this.dimY.get(locationYCoord); + + if(this.dimX.containsKey(locationXCoord)) + { + return this.dimX.get(locationXCoord); + } + } - } } - } catch(Exception E) { return null; } - - return null; - + return null; } - - - + public ArrayList printAllLinkData() { - ArrayList links = new ArrayList(); - if(this.linksInThisDim==null) + //TODO: We might want to modify this function, but I'm afraid of breaking something right now. + //To begin with, the name is wrong. This doesn't print anything! >_o ~SenseiKiwi + + ArrayList links = new ArrayList(); + if (this.linksInThisDim == null) { return links; } - for(HashMap> first : this.linksInThisDim.values()) + for (HashMap> first : this.linksInThisDim.values()) { - - - for(HashMap second : first.values()) + for (HashMap second : first.values()) { - - - for(LinkData linkData :second.values()) + for (LinkData linkData : second.values()) { links.add(linkData); } } - } - - - + } return links; } - - - } \ No newline at end of file diff --git a/StevenDimDoors/mod_pocketDim/LinkData.java b/StevenDimDoors/mod_pocketDim/LinkData.java index a701ace..eab4ec6 100644 --- a/StevenDimDoors/mod_pocketDim/LinkData.java +++ b/StevenDimDoors/mod_pocketDim/LinkData.java @@ -15,10 +15,7 @@ public class LinkData implements Serializable public int numberofChildren; public boolean isLocPocket; public int linkOrientation; - - - public int destDimID; public int locDimID; @@ -43,8 +40,7 @@ public class LinkData implements Serializable public LinkData(int locationDimID, int destinationDimID, int locationXCoord, int locationYCoord, int locationZCoord, int destinationXCoord, int destinationYCoord, int destinationZCoord, boolean isPocket,int orientation) { - - this.exists=true; + this.exists = true; this.locXCoord=locationXCoord; this.locYCoord=locationYCoord; this.locZCoord=locationZCoord; @@ -57,20 +53,16 @@ public class LinkData implements Serializable this.locDimID=locationDimID; this.isLocPocket=isPocket; this.linkOrientation=orientation; - - - } public String printLinkData() { + //TODO: Rewrite this to make it prettier. @_@ I'm afraid of changing it to ToString() on the off + //chance it'll cause explosions and sadness. Damn serialization! ~SenseiKiwi String linkInfo; - linkInfo=String.valueOf(this.locDimID)+"locDimID "+String.valueOf(this.locXCoord)+":locXCoord "+String.valueOf(this.locYCoord)+":locYCoord "+String.valueOf(this.locZCoord)+":locZCoord "; + linkInfo = String.valueOf(this.locDimID) + "locDimID "+String.valueOf(this.locXCoord)+":locXCoord "+String.valueOf(this.locYCoord)+":locYCoord "+String.valueOf(this.locZCoord)+":locZCoord "; linkInfo.concat("\n"+ String.valueOf(this.destDimID)+"DestDimID "+String.valueOf(this.destXCoord)+":destXCoord "+String.valueOf(this.destYCoord)+":destYCoord "+String.valueOf(this.destZCoord)+":destZCoord "); return linkInfo; - - - } } \ No newline at end of file diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index 0f36f83..84f2c06 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -1,9 +1,9 @@ package StevenDimDoors.mod_pocketDim.commands; +import java.io.File; import java.util.Collection; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.MathHelper; import StevenDimDoors.mod_pocketDim.DungeonGenerator; import StevenDimDoors.mod_pocketDim.LinkData; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; @@ -15,7 +15,7 @@ public class CommandCreateDungeonRift extends DDCommandBase private CommandCreateDungeonRift() { - super("dd-rift"); + super("dd-rift", ""); } public static CommandCreateDungeonRift instance() @@ -27,71 +27,101 @@ public class CommandCreateDungeonRift extends DDCommandBase } @Override - public void processCommand(EntityPlayer sender, String[] command) + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { DungeonHelper dungeonHelper = DungeonHelper.instance(); - if(command==null||sender.worldObj.isRemote) + if (sender.worldObj.isRemote) { - return; + return DDCommandResult.SUCCESS; + } + if (command.length == 0) + { + return DDCommandResult.TOO_FEW_ARGUMENTS; + } + if (command.length > 1) + { + return DDCommandResult.TOO_MANY_ARGUMENTS; } - LinkData link = new LinkData(sender.worldObj.provider.dimensionId, 0, - (int) sender.posX, - (int) sender.posY + 1, - (int) sender.posZ, - (int) sender.posX, - (int) sender.posY + 1, - (int) sender.posZ,true,3); - - if(command.length!=0&&command[0].equals("random")) - { - sender.sendChatToPlayer("Created dungeon rift"); - dimHelper.instance.createLink(link); - link = dimHelper.instance.createPocket(link,true, true); - } - else if (command.length != 0 && command[0].equals("list")) + if (command[0].equals("list")) { Collection dungeonNames = dungeonHelper.getDungeonNames(); for (String name : dungeonNames) { - getCommandSenderAsPlayer(sender).sendChatToPlayer(name); - } - } - else if(command.length!=0) - { - for(DungeonGenerator dungeonGen : dungeonHelper.registeredDungeons) - { - String dungeonName =dungeonGen.schematicPath.toLowerCase(); - - if(dungeonName.contains(command[0].toLowerCase())) - { - link = dimHelper.instance.createPocket(link,true, true); - dimHelper.dimList.get(link.destDimID).dungeonGenerator=dungeonGen; - sender.sendChatToPlayer("Genned dungeon " +dungeonName); - return; - } - } - for(DungeonGenerator dungeonGen : dungeonHelper.customDungeons) - { - String dungeonName =dungeonGen.schematicPath.toLowerCase(); - - if(dungeonName.contains(command[0].toLowerCase())) - { - link = dimHelper.instance.createPocket(link,true, true); - dimHelper.dimList.get(link.destDimID).dungeonGenerator=dungeonGen; - sender.sendChatToPlayer("Genned dungeon " +dungeonName); - return; - } - } - if(command!=null&&!command[0].equals("random")) - { - sender.sendChatToPlayer("could not find dungeon, 'list' for list of dungeons"); + sender.sendChatToPlayer(name); } + sender.sendChatToPlayer(""); } else { - sender.sendChatToPlayer("invalid arguments- 'random' for random dungeon, or 'list' for dungeon names"); + DungeonGenerator result; + int x = (int) sender.posX; + int y = (int) sender.posY; + int z = (int) sender.posZ; + LinkData link = new LinkData(sender.worldObj.provider.dimensionId, 0, x, y + 1, z, x, y + 1, z, true, 3); + + if (command[0].equals("random")) + { + dimHelper.instance.createLink(link); + link = dimHelper.instance.createPocket(link, true, true); + sender.sendChatToPlayer("Created a rift to a random dungeon (Dimension ID = " + link.destDimID + ")."); + } + else + { + result = findDungeonByPartialName(command[0], dungeonHelper.registeredDungeons); + if (result == null) + { + result = findDungeonByPartialName(command[0], dungeonHelper.customDungeons); + } + //Check if we found any matches + if (result != null) + { + //Create a rift to our selected dungeon and notify the player + link = dimHelper.instance.createPocket(link, true, true); + dimHelper.dimList.get(link.destDimID).dungeonGenerator = result; + sender.sendChatToPlayer("Created a rift to \"" + getSchematicName(result) + "\" dungeon (Dimension ID = " + link.destDimID + ")."); + } + else + { + //No matches! + return new DDCommandResult("Error: The specified dungeon was not found. Use 'list' to see a list of the available dungeons."); + } + } } + return DDCommandResult.SUCCESS; + } + + private DungeonGenerator findDungeonByPartialName(String query, Collection dungeons) + { + //Search for the shortest dungeon name that contains the lowercase query string. + String dungeonName; + String normalQuery = query.toLowerCase(); + DungeonGenerator bestMatch = null; + int matchLength = Integer.MAX_VALUE; + + for (DungeonGenerator dungeon : dungeons) + { + //We need to extract the file's name. Comparing against schematicPath could + //yield false matches if the query string is contained within the path. + + dungeonName = getSchematicName(dungeon).toLowerCase(); + if (dungeonName.length() < matchLength && dungeonName.contains(normalQuery)) + { + matchLength = dungeonName.length(); + bestMatch = dungeon; + } + } + return bestMatch; + } + + private static String getSchematicName(DungeonGenerator dungeon) + { + //TODO: Move this to DungeonHelper and use it for all schematic name parsing. + //In the future, we really should include the schematic's name as part of DungeonGenerator + //to avoid redoing this work constantly. + File schematic = new File(dungeon.schematicPath); + String fileName = schematic.getName(); + return fileName.substring(0, fileName.length() - DungeonHelper.SCHEMATIC_FILE_EXTENSION.length()); } } \ No newline at end of file diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java b/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java index 6f37790..0d27e8e 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java @@ -26,7 +26,7 @@ public class CommandDeleteAllLinks extends DDCommandBase } @Override - protected void processCommand(EntityPlayer sender, String[] command) + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { int linksRemoved=0; int targetDim; diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandDeleteDimensionData.java b/StevenDimDoors/mod_pocketDim/commands/CommandDeleteDimensionData.java index f80ad1a..7ba8f09 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandDeleteDimensionData.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandDeleteDimensionData.java @@ -26,7 +26,7 @@ public class CommandDeleteDimensionData extends DDCommandBase } @Override - protected void processCommand(EntityPlayer sender, String[] command) + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { int linksRemoved=0; int targetDim; diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java b/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java index 6bd020d..7537371 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java @@ -27,7 +27,7 @@ public class CommandDeleteRifts extends DDCommandBase } @Override - protected void processCommand(EntityPlayer sender, String[] command) + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { int linksRemoved=0; int targetDim; diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandEndDungeonCreation.java b/StevenDimDoors/mod_pocketDim/commands/CommandEndDungeonCreation.java index 6f49de7..a89abf1 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandEndDungeonCreation.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandEndDungeonCreation.java @@ -12,7 +12,9 @@ public class CommandEndDungeonCreation extends DDCommandBase private CommandEndDungeonCreation() { - super("dd-export"); + super("dd-export", new String[] { + " <'open' | 'closed'> [weight] ['override']", + " override" } ); } public static CommandEndDungeonCreation instance() @@ -24,57 +26,160 @@ public class CommandEndDungeonCreation extends DDCommandBase } @Override - protected void processCommand(EntityPlayer sender, String[] command) + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { + /* + * There are two versions of this command. One version takes 3 to 5 arguments consisting + * of the information needed for a proper schematic name and an optional override argument. + * The override argument only allows the user to export any dimension, even if it wasn't + * meant for custom dungeon creation. It does not allow the user to export a dungeon with + * invalid tags. + * + * If the user wishes to name his schematic in a different format, then he will have to use + * the 2-argument version of this command, which accepts a schematic name and a mandatory + * override argument. + */ + DungeonHelper dungeonHelper = DungeonHelper.instance(); - DDProperties properties = DDProperties.instance(); - if (!dungeonHelper.isCustomDungeon(sender.worldObj.provider.dimensionId)) + if (command.length < 2) { - if (command.length < 2) - { - sender.sendChatToPlayer("Must have started dungeon creation, use argument OVERRIDE to export anyway"); - return; - - } - - else if (!command[1].contains("OVERRIDE")) - { - sender.sendChatToPlayer("Must have started dungeon creation, use argument OVERRIDE to export anyway"); - return; - - } - + return DDCommandResult.TOO_FEW_ARGUMENTS; + } + if (command.length > 5) + { + return DDCommandResult.TOO_MANY_ARGUMENTS; } - int x = (int) sender.posX; - int y = (int) sender.posY; - int z = (int) sender.posZ; - - if (command.length == 0) + //Check if we received the 2-argument version + if (command.length == 2) { - sender.sendChatToPlayer("Must name file"); - } - else if(!sender.worldObj.isRemote) - { - //Check that the dungeon name is valid to prevent directory traversal and other forms of abuse - if (DungeonHelper.NamePattern.matcher(command[0]).matches()) + if (command[1].equalsIgnoreCase("override")) { - String exportPath = properties.CustomSchematicDirectory + "/" + command[0] + ".schematic"; - if (dungeonHelper.exportDungeon(sender.worldObj, x, y, z, exportPath)) + //Check that the schematic name is a legal name + if (DungeonHelper.SchematicNamePattern.matcher(command[0]).matches()) { - sender.sendChatToPlayer("Saved dungeon schematic in " + exportPath); - dungeonHelper.registerCustomDungeon(new File(exportPath)); + //Export the schematic + return exportDungeon(sender, command[0]); } else { - sender.sendChatToPlayer("Failed to save dungeon schematic!"); + //The schematic name contains illegal characters. Inform the user. + return new DDCommandResult("Error: Invalid schematic name. Please use only letters, numbers, dashes, and underscores."); } } else { - sender.sendChatToPlayer("Invalid schematic name. Please use only letters, numbers, and underscores."); + //The command is malformed in some way. Assume that the user meant to use + //the 3-argument version and report an error. + return DDCommandResult.TOO_FEW_ARGUMENTS; } } + + //The user must have used the 3-argument version of this command + //Check if the current dimension is a pocket for building custom dungeons or if the override argument was used. + if (!dungeonHelper.isCustomDungeon(sender.worldObj.provider.dimensionId) || + !command[command.length - 1].equalsIgnoreCase("override")) + { + //This dimension may not be exported without overriding! + return new DDCommandResult("Error: The current dimension was not made for dungeon creation. Use the 'override' argument to export anyway."); + } + + //TODO: Why do we check remoteness here but not before? And why not for the other export case? + //Something feels wrong... ~SenseiKiwi + + if (!sender.worldObj.isRemote) + { + //TODO: This validation should be in DungeonHelper or in another class. We should move it + //once the during the save file format rewrite. ~SenseiKiwi + + if (!dungeonHelper.validateDungeonType(command[0])) + { + return new DDCommandResult("Error: Invalid dungeon type. Please use one of the existing types."); + } + if (!DungeonHelper.DungeonNamePattern.matcher(command[1]).matches()) + { + return new DDCommandResult("Error: Invalid dungeon name. Please use only letters, numbers, and dashes."); + } + if (!command[2].equalsIgnoreCase("open") && !command[2].equalsIgnoreCase("closed")) + { + return new DDCommandResult("Error: Please specify whether the dungeon is 'open' or 'closed'."); + } + + //If there are no more argument, export the dungeon. + if (command.length == 3) + { + return exportDungeon(sender, join(command, "_", 0, 3)); + } + + //Validate the 4th argument, which might be the weight or might be "override". + try + { + int weight = Integer.parseInt(command[3]); + if (weight >= 0 && weight <= DungeonHelper.MAX_DUNGEON_WEIGHT) + { + return exportDungeon(sender, join(command, "_", 0, 4)); + } + } + catch (Exception e) + { + //The 4th argument could be "override", but only if it's the last argument. + //In that case, we assume the default dungeon weight. + if (command.length == 4 && command[3].equalsIgnoreCase("override")) + { + return exportDungeon(sender, join(command, "_", 0, 3)); + } + } + + //If we've reached this point, then we must have an invalid weight. + return new DDCommandResult("Invalid dungeon weight. Please specify a weight between 0 and " + DungeonHelper.MAX_DUNGEON_WEIGHT + ", inclusive."); + } + + return DDCommandResult.SUCCESS; + } + + private static DDCommandResult exportDungeon(EntityPlayer player, String name) + { + DDProperties properties = DDProperties.instance(); + DungeonHelper dungeonHelper = DungeonHelper.instance(); + + int x = (int) player.posX; + int y = (int) player.posY; + int z = (int) player.posZ; + String exportPath = properties.CustomSchematicDirectory + File.separator + name + ".schematic"; + if (dungeonHelper.exportDungeon(player.worldObj, x, y, z, exportPath)) + { + player.sendChatToPlayer("Saved dungeon schematic in " + exportPath); + dungeonHelper.registerCustomDungeon(new File(exportPath)); + return DDCommandResult.SUCCESS; + } + else + { + return new DDCommandResult("Error: Failed to save dungeon schematic!"); + } + } + + private static String join(String[] source, String delimiter, int start, int end) + { + //TODO: This function should be moved to a helper, but we have several single-function helpers as is. + //I find that to be worse than keeping this private. ~SenseiKiwi + + int index; + int length = 0; + StringBuilder buffer; + for (index = start; index < end; index++) + { + length += source[index].length(); + } + length += (end - start - 1) * delimiter.length(); + + buffer = new StringBuilder(length); + buffer.append(source[start]); + for (index = start + 1; index < end; index++) + { + buffer.append(delimiter); + buffer.append(source[index]); + } + return buffer.toString(); } } \ No newline at end of file diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandPrintDimensionData.java b/StevenDimDoors/mod_pocketDim/commands/CommandPrintDimensionData.java index ca235d2..7a8c5c0 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandPrintDimensionData.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandPrintDimensionData.java @@ -1,7 +1,6 @@ package StevenDimDoors.mod_pocketDim.commands; import java.util.ArrayList; -import java.util.Collection; import net.minecraft.entity.player.EntityPlayer; import StevenDimDoors.mod_pocketDim.DimData; @@ -14,7 +13,7 @@ public class CommandPrintDimensionData extends DDCommandBase private CommandPrintDimensionData() { - super("dd-dimensiondata"); + super("dd-dimensiondata", "[dimension number]"); } public static CommandPrintDimensionData instance() @@ -26,45 +25,45 @@ public class CommandPrintDimensionData extends DDCommandBase } @Override - protected void processCommand(EntityPlayer sender, String[] command) + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { int targetDim; - boolean shouldGo= true; + DimData dimData; - if(command.length==0) + if (command.length == 0) { - targetDim= sender.worldObj.provider.dimensionId; + targetDim = sender.worldObj.provider.dimensionId; } - else if(command.length==1) + else if (command.length == 1) { - targetDim = parseInt(sender, command[0]); - if(!dimHelper.dimList.containsKey(targetDim)) + try { - sender.sendChatToPlayer("Error- dim "+targetDim+" not registered"); - shouldGo=false; + targetDim = Integer.parseInt(command[0]); + } + catch (Exception ex) + { + return DDCommandResult.INVALID_DIMENSION_ID; } } else { - targetDim=0; - shouldGo=false; - sender.sendChatToPlayer("Error-Invalid argument, print_dim_data or blank for current dim"); + return DDCommandResult.TOO_MANY_ARGUMENTS; + } + + dimData = dimHelper.dimList.get(targetDim); + if (dimData == null) + { + return DDCommandResult.UNREGISTERED_DIMENSION; } - if(shouldGo) - { - if(dimHelper.dimList.containsKey(targetDim)) - { - DimData dimData = dimHelper.dimList.get(targetDim); - Collection links = new ArrayList(); - links.addAll( dimData.printAllLinkData()); + ArrayList links = dimData.printAllLinkData(); - for (LinkData link : links) - { - sender.sendChatToPlayer(link.printLinkData()); - } - sender.sendChatToPlayer("DimID= "+dimData.dimID+"Dim depth = "+dimData.depth); - } - } + sender.sendChatToPlayer("Dimension ID = " + dimData.dimID); + sender.sendChatToPlayer("Dimension Depth = " + dimData.depth); + for (LinkData link : links) + { + sender.sendChatToPlayer(link.printLinkData()); + } + return DDCommandResult.SUCCESS; } } diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandPruneDimensions.java b/StevenDimDoors/mod_pocketDim/commands/CommandPruneDimensions.java index 32e1dce..d58f0b4 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandPruneDimensions.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandPruneDimensions.java @@ -26,7 +26,7 @@ public class CommandPruneDimensions extends DDCommandBase } @Override - protected void processCommand(EntityPlayer sender, String[] command) + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { int numRemoved=0; ArrayList dimsWithLinks = new ArrayList(); diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandRegenPocket.java b/StevenDimDoors/mod_pocketDim/commands/CommandRegenPocket.java index fa63a66..b4d1feb 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandRegenPocket.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandRegenPocket.java @@ -26,7 +26,7 @@ public class CommandRegenPocket extends DDCommandBase } @Override - protected void processCommand(EntityPlayer sender, String[] command) + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { DungeonHelper dungeonHelper = DungeonHelper.instance(); DDProperties properties = DDProperties.instance(); diff --git a/StevenDimDoors/mod_pocketDim/commands/CommandStartDungeonCreation.java b/StevenDimDoors/mod_pocketDim/commands/CommandStartDungeonCreation.java index 4a645fd..39fbccf 100644 --- a/StevenDimDoors/mod_pocketDim/commands/CommandStartDungeonCreation.java +++ b/StevenDimDoors/mod_pocketDim/commands/CommandStartDungeonCreation.java @@ -10,7 +10,7 @@ public class CommandStartDungeonCreation extends DDCommandBase private CommandStartDungeonCreation() { - super("dd-create"); + super("dd-create", ""); } public static CommandStartDungeonCreation instance() @@ -22,10 +22,18 @@ public class CommandStartDungeonCreation extends DDCommandBase } @Override - protected void processCommand(EntityPlayer sender, String[] command) + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { + //TODO: Some commands have isRemote checks, some do not. Why? Can commands even run locally anyway? + //What does it mean when you run a command locally? ~SenseiKiwi + if (!sender.worldObj.isRemote) { + if (command.length > 0) + { + return DDCommandResult.TOO_MANY_ARGUMENTS; + } + //Place a door leading to a pocket dimension where the player is standing. //The pocket dimension will be serve as a room for the player to build a dungeon. int x = (int) sender.posX; @@ -34,7 +42,8 @@ public class CommandStartDungeonCreation extends DDCommandBase LinkData link = DungeonHelper.instance().createCustomDungeonDoor(sender.worldObj, x, y, z); //Notify the player - sender.sendChatToPlayer("Created a door to a pocket dimension (ID = " + link.destDimID + "). Please build your dungeon there."); + sender.sendChatToPlayer("Created a door to a pocket dimension (Dimension ID = " + link.destDimID + "). Please build your dungeon there."); } + return DDCommandResult.SUCCESS; } } \ No newline at end of file diff --git a/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java b/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java index 2197f5d..9a7c534 100644 --- a/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java +++ b/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java @@ -12,16 +12,25 @@ import cpw.mods.fml.common.event.FMLServerStartingEvent; public abstract class DDCommandBase extends CommandBase { private String name; + private String[] formats; - public DDCommandBase(String name) + public DDCommandBase(String name, String format) { this.name = name; + this.formats = new String[] { format }; } + public DDCommandBase(String name, String[] formats) + { + this.name = name; + this.formats = formats; + } + /* - * When overridden in a derived class, processes the command sent by the server. + * When overridden in a derived class, processes the command sent by the server + * and returns a status code and message for the result of the operation. */ - protected abstract void processCommand(EntityPlayer sender, String[] command); + protected abstract DDCommandResult processCommand(EntityPlayer sender, String[] command); public final String getCommandName() { @@ -43,6 +52,21 @@ public abstract class DDCommandBase extends CommandBase public final void processCommand(ICommandSender sender, String[] command) { //Forward the command - processCommand(getCommandSenderAsPlayer(sender), command); + EntityPlayer player = getCommandSenderAsPlayer(sender); + DDCommandResult result = processCommand(player, command); + + //If the command failed, send the player a status message. + if (result.failed()) + { + if (result.shouldPrintUsage()) + { + //Send the argument formats for this command + for (String format : formats) + { + player.sendChatToPlayer("Usage: " + name + " " + format); + } + } + player.sendChatToPlayer(result.getMessage()); + } } } diff --git a/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java b/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java new file mode 100644 index 0000000..c40a99e --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java @@ -0,0 +1,54 @@ +package StevenDimDoors.mod_pocketDim.commands; + +public class DDCommandResult { + + + public static final DDCommandResult SUCCESS = new DDCommandResult(0, "", false); + public static final DDCommandResult TOO_FEW_ARGUMENTS = new DDCommandResult(1, "Error: Too few arguments passed to the command", true); + public static final DDCommandResult TOO_MANY_ARGUMENTS = new DDCommandResult(2, "Error: Too many arguments passed to the command", true); + public static final DDCommandResult INVALID_DIMENSION_ID = new DDCommandResult(3, "Error: Invalid dimension ID", true); + public static final DDCommandResult UNREGISTERED_DIMENSION = new DDCommandResult(4, "Error: Dimension is not registered", false); + + public static final int CUSTOM_ERROR_CODE = -1; + + private int code; + private String message; + private boolean printUsage; + + private DDCommandResult(int code, String message, boolean printUsage) + { + this.code = code; + this.message = message; + this.printUsage = printUsage; + } + + public DDCommandResult(String message) + { + this(CUSTOM_ERROR_CODE, message, false); + } + + public DDCommandResult(String message, boolean printUsage) + { + this(CUSTOM_ERROR_CODE, message, printUsage); + } + + public boolean failed() + { + return (code != 0); + } + + public int getCode() + { + return code; + } + + public String getMessage() + { + return message; + } + + public boolean shouldPrintUsage() + { + return printUsage; + } +} diff --git a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index a996a3b..fd2f2ea 100644 --- a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -31,11 +31,12 @@ public class DungeonHelper { private static DungeonHelper instance = null; private static DDProperties properties = null; - public static final Pattern NamePattern = Pattern.compile("[A-Za-z0-9_\\-]+"); + public static final Pattern SchematicNamePattern = Pattern.compile("[A-Za-z0-9_\\-]+"); + public static final Pattern DungeonNamePattern = Pattern.compile("[A-Za-z0-9\\-]+"); - private static final String SCHEMATIC_FILE_EXTENSION = ".schematic"; + public static final String SCHEMATIC_FILE_EXTENSION = ".schematic"; private static final int DEFAULT_DUNGEON_WEIGHT = 100; - private static final int MAX_DUNGEON_WEIGHT = 10000; //Used to prevent overflows and math breaking down + public static final int MAX_DUNGEON_WEIGHT = 10000; //Used to prevent overflows and math breaking down private static final String HUB_DUNGEON_TYPE = "Hub"; private static final String TRAP_DUNGEON_TYPE = "Trap"; @@ -166,6 +167,12 @@ public class DungeonHelper return customDungeonStatus.containsKey(dimensionID); } + public boolean validateDungeonType(String type) + { + //Check if the dungeon type is valid + return dungeonTypeChecker.contains(type.toLowerCase()); + } + public boolean validateSchematicName(String name) { String[] dungeonData; @@ -184,7 +191,7 @@ public class DungeonHelper return false; //Check if the name is valid - if (!NamePattern.matcher(dungeonData[1]).matches()) + if (!SchematicNamePattern.matcher(dungeonData[1]).matches()) return false; //Check if the open/closed flag is present