THE UPDATE
Merging months of dev work into master. The update is playable, but untested.
This commit is contained in:
32
StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java
Normal file
32
StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package StevenDimDoors.mod_pocketDim.helpers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.ForgeChunkManager;
|
||||
import net.minecraftforge.common.ForgeChunkManager.LoadingCallback;
|
||||
import net.minecraftforge.common.ForgeChunkManager.Ticket;
|
||||
import StevenDimDoors.mod_pocketDim.IChunkLoader;
|
||||
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
|
||||
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoorGold;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
|
||||
public class ChunkLoaderHelper implements LoadingCallback
|
||||
{
|
||||
|
||||
@Override
|
||||
public void ticketsLoaded(List<Ticket> tickets, World world)
|
||||
{
|
||||
for (Ticket ticket : tickets)
|
||||
{
|
||||
int goldDimDoorX = ticket.getModData().getInteger("goldDimDoorX");
|
||||
int goldDimDoorY = ticket.getModData().getInteger("goldDimDoorY");
|
||||
int goldDimDoorZ = ticket.getModData().getInteger("goldDimDoorZ");
|
||||
IChunkLoader tile = (IChunkLoader) world.getBlockTileEntity(goldDimDoorX, goldDimDoorY, goldDimDoorZ);
|
||||
tile.forceChunkLoading(ticket,goldDimDoorX,goldDimDoorZ);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
83
StevenDimDoors/mod_pocketDim/helpers/Compactor.java
Normal file
83
StevenDimDoors/mod_pocketDim/helpers/Compactor.java
Normal file
@@ -0,0 +1,83 @@
|
||||
package StevenDimDoors.mod_pocketDim.helpers;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
|
||||
import StevenDimDoors.mod_pocketDim.core.DimLink;
|
||||
import StevenDimDoors.mod_pocketDim.core.IDimRegistrationCallback;
|
||||
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
|
||||
import StevenDimDoors.mod_pocketDim.core.NewDimData;
|
||||
import StevenDimDoors.mod_pocketDim.util.Point4D;
|
||||
|
||||
public class Compactor
|
||||
{
|
||||
|
||||
private static class DimComparator implements Comparator<NewDimData>
|
||||
{
|
||||
@Override
|
||||
public int compare(NewDimData a, NewDimData b)
|
||||
{
|
||||
return a.id() - b.id();
|
||||
}
|
||||
}
|
||||
|
||||
public static void write(Collection<? extends NewDimData> values, DataOutputStream output) throws IOException
|
||||
{
|
||||
// SenseiKiwi: Just encode the data straight up for now. I'll implement fancier compression later.
|
||||
output.writeInt(values.size());
|
||||
for (NewDimData dimension : values)
|
||||
{
|
||||
output.writeInt(dimension.id());
|
||||
output.writeInt(dimension.root().id());
|
||||
output.writeInt(dimension.linkCount());
|
||||
for (DimLink link : dimension.links())
|
||||
{
|
||||
Point4D.write(link.source(), output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Note to self: the root ID can be "compressed" by grouping
|
||||
// dimensions by their root ID and then only sending it once
|
||||
|
||||
/*
|
||||
// To compress the dimension IDs, we'll sort them by ID
|
||||
// and write the _difference_ between their ID numbers.
|
||||
NewDimData[] dimensions = new NewDimData[values.size()];
|
||||
dimensions = values.toArray(dimensions);
|
||||
Arrays.sort(dimensions, new DimComparator());
|
||||
*/
|
||||
}
|
||||
|
||||
public static void readDimensions(DataInputStream input, IDimRegistrationCallback callback) throws IOException
|
||||
{
|
||||
// Read in the dimensions one by one. Make sure we register root dimensions before
|
||||
// attempting to register the dimensions under them.
|
||||
|
||||
HashSet<Integer> rootIDs = new HashSet<Integer>();
|
||||
|
||||
int dimCount = input.readInt();
|
||||
for (int k = 0; k < dimCount; k++)
|
||||
{
|
||||
int id = input.readInt();
|
||||
int rootID = input.readInt();
|
||||
|
||||
if (rootIDs.add(rootID))
|
||||
{
|
||||
callback.registerDimension(rootID, rootID);
|
||||
}
|
||||
// Don't check if (id != rootID) - we want to retrieve the reference anyway
|
||||
NewDimData dimension = callback.registerDimension(id, rootID);
|
||||
int linkCount = input.readInt();
|
||||
for (int h = 0; h < linkCount; h++)
|
||||
{
|
||||
Point4D source = Point4D.read(input);
|
||||
dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.CLIENT_SIDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,40 +20,24 @@ import java.util.regex.Pattern;
|
||||
import net.minecraft.util.WeightedRandom;
|
||||
import net.minecraft.world.World;
|
||||
import StevenDimDoors.mod_pocketDim.DDProperties;
|
||||
import StevenDimDoors.mod_pocketDim.DimData;
|
||||
import StevenDimDoors.mod_pocketDim.DungeonGenerator;
|
||||
import StevenDimDoors.mod_pocketDim.LinkData;
|
||||
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
|
||||
import StevenDimDoors.mod_pocketDim.core.DimLink;
|
||||
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
|
||||
import StevenDimDoors.mod_pocketDim.core.NewDimData;
|
||||
import StevenDimDoors.mod_pocketDim.core.PocketManager;
|
||||
import StevenDimDoors.mod_pocketDim.dungeon.DungeonData;
|
||||
import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic;
|
||||
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack;
|
||||
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfig;
|
||||
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfigReader;
|
||||
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType;
|
||||
import StevenDimDoors.mod_pocketDim.items.itemDimDoor;
|
||||
import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor;
|
||||
import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException;
|
||||
import StevenDimDoors.mod_pocketDim.util.FileFilters;
|
||||
import StevenDimDoors.mod_pocketDim.util.WeightedContainer;
|
||||
|
||||
public class DungeonHelper
|
||||
{
|
||||
//TODO: File-handling functionality should be spun off to a helper class later
|
||||
private static class DirectoryFilter implements FileFilter
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File file)
|
||||
{
|
||||
return file.isDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
private static class SchematicFileFilter implements FileFilter
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File file)
|
||||
{
|
||||
return file.isFile() && file.getName().endsWith(SCHEMATIC_FILE_EXTENSION);
|
||||
}
|
||||
}
|
||||
|
||||
private static DungeonHelper instance = null;
|
||||
private static DDProperties properties = null;
|
||||
|
||||
@@ -62,8 +46,6 @@ public class DungeonHelper
|
||||
|
||||
public static final String SCHEMATIC_FILE_EXTENSION = ".schematic";
|
||||
|
||||
private static final String DEFAULT_UP_SCHEMATIC_PATH = "/schematics/core/simpleStairsUp.schematic";
|
||||
private static final String DEFAULT_DOWN_SCHEMATIC_PATH = "/schematics/core/simpleStairsDown.schematic";
|
||||
private static final String DEFAULT_ERROR_SCHEMATIC_PATH = "/schematics/core/somethingBroke.schematic";
|
||||
private static final String DUNGEON_CREATION_GUIDE_SOURCE_PATH = "/mods/DimDoors/text/How_to_add_dungeons.txt";
|
||||
private static final String RUINS_PACK_PATH = "/schematics/ruins";
|
||||
@@ -86,16 +68,14 @@ public class DungeonHelper
|
||||
public static final short MAX_DUNGEON_HEIGHT = MAX_DUNGEON_WIDTH;
|
||||
public static final short MAX_DUNGEON_LENGTH = MAX_DUNGEON_WIDTH;
|
||||
|
||||
private ArrayList<DungeonGenerator> untaggedDungeons = new ArrayList<DungeonGenerator>();
|
||||
private ArrayList<DungeonGenerator> registeredDungeons = new ArrayList<DungeonGenerator>();
|
||||
private ArrayList<DungeonData> untaggedDungeons = new ArrayList<DungeonData>();
|
||||
private ArrayList<DungeonData> registeredDungeons = new ArrayList<DungeonData>();
|
||||
|
||||
private DungeonPack RuinsPack;
|
||||
private HashMap<String, DungeonPack> dungeonPackMapping = new HashMap<String, DungeonPack>();
|
||||
private ArrayList<DungeonPack> dungeonPackList = new ArrayList<DungeonPack>();
|
||||
|
||||
private DungeonGenerator defaultUp;
|
||||
private DungeonGenerator defaultDown;
|
||||
private DungeonGenerator defaultError;
|
||||
private DungeonData defaultError;
|
||||
|
||||
private DungeonHelper()
|
||||
{
|
||||
@@ -227,47 +207,34 @@ public class DungeonHelper
|
||||
}
|
||||
}
|
||||
|
||||
public List<DungeonGenerator> getRegisteredDungeons()
|
||||
public List<DungeonData> getRegisteredDungeons()
|
||||
{
|
||||
return Collections.unmodifiableList(this.registeredDungeons);
|
||||
}
|
||||
|
||||
public List<DungeonGenerator> getUntaggedDungeons()
|
||||
public List<DungeonData> getUntaggedDungeons()
|
||||
{
|
||||
return Collections.unmodifiableList(this.untaggedDungeons);
|
||||
}
|
||||
|
||||
public DungeonGenerator getDefaultErrorDungeon()
|
||||
public DungeonData getDefaultErrorDungeon()
|
||||
{
|
||||
return defaultError;
|
||||
}
|
||||
|
||||
public DungeonGenerator getDefaultUpDungeon()
|
||||
{
|
||||
return defaultUp;
|
||||
}
|
||||
|
||||
public DungeonGenerator getDefaultDownDungeon()
|
||||
{
|
||||
return defaultDown;
|
||||
}
|
||||
|
||||
public DungeonPack getDungeonPack(String name)
|
||||
{
|
||||
//TODO: This function might be obsolete after the new save format is implemented.
|
||||
return dungeonPackMapping.get(name.toUpperCase());
|
||||
}
|
||||
|
||||
public DungeonPack getDimDungeonPack(int dimensionID)
|
||||
private DungeonPack getDimDungeonPack(NewDimData data)
|
||||
{
|
||||
//FIXME: This function is a workaround to our current dungeon data limitations. Modify later.
|
||||
//The upcoming save format change and code overhaul will make this obsolete.
|
||||
|
||||
DungeonPack pack;
|
||||
DungeonGenerator generator = dimHelper.dimList.get(dimensionID).dungeonGenerator;
|
||||
if (generator != null)
|
||||
DungeonData dungeon = data.dungeon();
|
||||
if (dungeon != null)
|
||||
{
|
||||
pack = generator.getDungeonType().Owner;
|
||||
pack = dungeon.dungeonType().Owner;
|
||||
|
||||
//Make sure the pack isn't null. This can happen for dungeons with the special UNKNOWN type.
|
||||
if (pack == null)
|
||||
@@ -277,7 +244,7 @@ public class DungeonHelper
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dimensionID == NETHER_DIMENSION_ID)
|
||||
if (data.id() == NETHER_DIMENSION_ID)
|
||||
{
|
||||
//TODO: Change this to the nether-side pack later ^_^
|
||||
pack = RuinsPack;
|
||||
@@ -290,21 +257,20 @@ public class DungeonHelper
|
||||
return pack;
|
||||
}
|
||||
|
||||
public LinkData createCustomDungeonDoor(World world, int x, int y, int z)
|
||||
public DimLink createCustomDungeonDoor(World world, int x, int y, int z)
|
||||
{
|
||||
//Create a link above the specified position. Link to a new pocket dimension.
|
||||
LinkData link = new LinkData(world.provider.dimensionId, 0, x, y + 1, z, x, y + 1, z, true, 3);
|
||||
link = dimHelper.instance.createPocket(link, true, false);
|
||||
NewDimData dimension = PocketManager.getDimensionData(world);
|
||||
DimLink link = dimension.createLink(x, y + 1, z, LinkTypes.POCKET,3);
|
||||
|
||||
//Place a Warp Door linked to that pocket
|
||||
itemDimDoor.placeDoorBlock(world, x, y, z, 3, mod_pocketDim.ExitDoor);
|
||||
ItemDimensionalDoor.placeDoorBlock(world, x, y, z, 3, mod_pocketDim.warpDoor);
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
public boolean validateDungeonType(String type, DungeonPack pack)
|
||||
{
|
||||
//Check if the dungeon type is valid
|
||||
return pack.isKnownType(type);
|
||||
}
|
||||
|
||||
@@ -370,10 +336,10 @@ public class DungeonHelper
|
||||
int weight = (dungeonData.length == 4) ? Integer.parseInt(dungeonData[3]) : DEFAULT_DUNGEON_WEIGHT;
|
||||
|
||||
//Add this custom dungeon to the list corresponding to its type
|
||||
DungeonGenerator generator = new DungeonGenerator(weight, path, isOpen, dungeonType);
|
||||
DungeonData dungeon = new DungeonData(path, isInternal, dungeonType, isOpen, weight);
|
||||
|
||||
pack.addDungeon(generator);
|
||||
registeredDungeons.add(generator);
|
||||
pack.addDungeon(dungeon);
|
||||
registeredDungeons.add(dungeon);
|
||||
if (verbose)
|
||||
{
|
||||
System.out.println("Registered dungeon: " + name);
|
||||
@@ -385,7 +351,7 @@ public class DungeonHelper
|
||||
{
|
||||
System.out.println("The following dungeon name is invalid for its given pack. It will not be generated naturally: " + schematicPath);
|
||||
}
|
||||
untaggedDungeons.add(new DungeonGenerator(DEFAULT_DUNGEON_WEIGHT, path, true, DungeonType.UNKNOWN_TYPE));
|
||||
untaggedDungeons.add(new DungeonData(path, isInternal, DungeonType.UNKNOWN_TYPE, true, DEFAULT_DUNGEON_WEIGHT));
|
||||
System.out.println("Registered untagged dungeon: " + name);
|
||||
}
|
||||
}
|
||||
@@ -403,7 +369,7 @@ public class DungeonHelper
|
||||
File[] packFiles;
|
||||
ArrayList<String> packFilePaths;
|
||||
File directory = new File(path);
|
||||
SchematicFileFilter schematicFileFilter = new SchematicFileFilter();
|
||||
FileFilter schematicFileFilter = new FileFilters.FileExtensionFilter(SCHEMATIC_FILE_EXTENSION);
|
||||
|
||||
//Check that the Ruins pack has been loaded
|
||||
if (RuinsPack == null)
|
||||
@@ -427,7 +393,7 @@ public class DungeonHelper
|
||||
schematics = null; //Release memory
|
||||
|
||||
//Load the custom dungeon packs
|
||||
packDirectories = directory.listFiles(new DirectoryFilter());
|
||||
packDirectories = directory.listFiles(new FileFilters.DirectoryFilter());
|
||||
if (packDirectories != null)
|
||||
{
|
||||
//Loop through each directory, which is assumed to be a dungeon pack
|
||||
@@ -462,9 +428,7 @@ public class DungeonHelper
|
||||
{
|
||||
//Register the core schematics
|
||||
//These are used for debugging and in case of unusual errors while loading dungeons
|
||||
defaultUp = new DungeonGenerator(DEFAULT_DUNGEON_WEIGHT, DEFAULT_UP_SCHEMATIC_PATH, true, DungeonType.UNKNOWN_TYPE);
|
||||
defaultDown = new DungeonGenerator(DEFAULT_DUNGEON_WEIGHT, DEFAULT_DOWN_SCHEMATIC_PATH, true, DungeonType.UNKNOWN_TYPE);
|
||||
defaultError = new DungeonGenerator(DEFAULT_DUNGEON_WEIGHT, DEFAULT_ERROR_SCHEMATIC_PATH, true, DungeonType.UNKNOWN_TYPE);
|
||||
defaultError = new DungeonData(DEFAULT_ERROR_SCHEMATIC_PATH, true, DungeonType.UNKNOWN_TYPE, true, DEFAULT_DUNGEON_WEIGHT);
|
||||
|
||||
//Open the list of dungeons packaged with our mod and register their schematics
|
||||
registerBundledPack(BUNDLED_RUINS_LIST_PATH, RUINS_PACK_PATH, "Ruins", reader);
|
||||
@@ -530,9 +494,10 @@ public class DungeonHelper
|
||||
}
|
||||
}
|
||||
|
||||
public void generateDungeonLink(LinkData inbound, DungeonPack pack, Random random)
|
||||
public DungeonData selectDungeon(NewDimData dimension, Random random)
|
||||
{
|
||||
DungeonGenerator selection;
|
||||
DungeonPack pack = getDimDungeonPack(dimension);
|
||||
DungeonData selection;
|
||||
DungeonPackConfig config;
|
||||
DungeonPack selectedPack;
|
||||
|
||||
@@ -546,13 +511,13 @@ public class DungeonHelper
|
||||
{
|
||||
//Calculate the chance of switching to a different pack type
|
||||
int packSwitchChance;
|
||||
if (dimHelper.dimList.get(inbound.locDimID).depth == 0)
|
||||
if (dimension.depth() == 1)
|
||||
{
|
||||
packSwitchChance = START_PACK_SWITCH_CHANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
packSwitchChance = MIN_PACK_SWITCH_CHANCE + (getPackDepth(inbound, pack) - 1) * PACK_SWITCH_CHANCE_PER_LEVEL;
|
||||
packSwitchChance = MIN_PACK_SWITCH_CHANCE + dimension.parent().packDepth() * PACK_SWITCH_CHANCE_PER_LEVEL;
|
||||
}
|
||||
|
||||
//Decide randomly whether to switch packs or not
|
||||
@@ -564,7 +529,7 @@ public class DungeonHelper
|
||||
}
|
||||
|
||||
//Pick the next dungeon
|
||||
selection = selectedPack.getNextDungeon(inbound, random);
|
||||
selection = selectedPack.getNextDungeon(dimension, random);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -580,7 +545,7 @@ public class DungeonHelper
|
||||
selection = defaultError;
|
||||
}
|
||||
}
|
||||
dimHelper.instance.getDimData(inbound.destDimID).dungeonGenerator = selection;
|
||||
return selection;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -621,16 +586,16 @@ public class DungeonHelper
|
||||
return sortedNames;
|
||||
}
|
||||
|
||||
private static ArrayList<String> parseDungeonNames(ArrayList<DungeonGenerator> dungeons)
|
||||
private static ArrayList<String> parseDungeonNames(ArrayList<DungeonData> dungeons)
|
||||
{
|
||||
String name;
|
||||
File schematic;
|
||||
ArrayList<String> names = new ArrayList<String>(dungeons.size());
|
||||
|
||||
for (DungeonGenerator dungeon : dungeons)
|
||||
for (DungeonData dungeon : dungeons)
|
||||
{
|
||||
//Retrieve the file name and strip off the file extension
|
||||
schematic = new File(dungeon.schematicPath);
|
||||
schematic = new File(dungeon.schematicPath());
|
||||
name = schematic.getName();
|
||||
name = name.substring(0, name.length() - SCHEMATIC_FILE_EXTENSION.length());
|
||||
names.add(name);
|
||||
@@ -638,102 +603,48 @@ public class DungeonHelper
|
||||
return names;
|
||||
}
|
||||
|
||||
public static ArrayList<DungeonGenerator> getDungeonChainHistory(DimData dimData, DungeonPack pack, int maxSize)
|
||||
public static ArrayList<DungeonData> getDungeonChainHistory(NewDimData dimension, DungeonPack pack, int maxSize)
|
||||
{
|
||||
//TODO: I've improved this code for the time being. However, searching across links is a flawed approach. A player could
|
||||
//manipulate the output of this function by setting up links to mislead our algorithm or by removing links.
|
||||
//Dimensions MUST have built-in records of their parent dimensions in the future. ~SenseiKiwi
|
||||
|
||||
ArrayList<DungeonGenerator> history = new ArrayList<DungeonGenerator>();
|
||||
DimData tailDim = dimData;
|
||||
boolean found = true;
|
||||
|
||||
if (dimData.dungeonGenerator == null || dimData.dungeonGenerator.getDungeonType().Owner != pack || maxSize < 1)
|
||||
if (dimension == null)
|
||||
{
|
||||
//The initial dimension is already outside our pack. Return an empty list.
|
||||
return history;
|
||||
throw new IllegalArgumentException("dimension cannot be null.");
|
||||
}
|
||||
history.add(dimData.dungeonGenerator);
|
||||
|
||||
for (int count = 1; count < maxSize && found; count++)
|
||||
int count = 0;
|
||||
NewDimData tail = dimension;
|
||||
DungeonData dungeon = tail.dungeon();
|
||||
ArrayList<DungeonData> history = new ArrayList<DungeonData>();
|
||||
|
||||
while (count < maxSize && dungeon != null && dungeon.dungeonType().Owner == pack)
|
||||
{
|
||||
found = false;
|
||||
for (LinkData link : tailDim.getLinksInDim())
|
||||
{
|
||||
DimData neighbor = dimHelper.instance.getDimData(link.destDimID);
|
||||
if (neighbor.depth == tailDim.depth - 1 && neighbor.dungeonGenerator != null &&
|
||||
neighbor.dungeonGenerator.getDungeonType().Owner == pack)
|
||||
{
|
||||
tailDim = neighbor;
|
||||
history.add(tailDim.dungeonGenerator);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
history.add(dungeon);
|
||||
tail = tail.parent();
|
||||
dungeon = tail.dungeon();
|
||||
count++;
|
||||
}
|
||||
return history;
|
||||
}
|
||||
|
||||
private static int getPackDepth(LinkData inbound, DungeonPack pack)
|
||||
public static ArrayList<DungeonData> getFlatDungeonTree(NewDimData dimension, int maxSize)
|
||||
{
|
||||
//TODO: I've improved this code for the time being. However, searching across links is a flawed approach. A player could
|
||||
//manipulate the output of this function by setting up links to mislead our algorithm or by removing links.
|
||||
//Dimensions MUST have built-in records of their parent dimensions in the future. ~SenseiKiwi
|
||||
//Dimensions should also just keep track of pack depth internally.
|
||||
NewDimData root = dimension;
|
||||
ArrayList<DungeonData> dungeons = new ArrayList<DungeonData>();
|
||||
Queue<NewDimData> pendingDimensions = new LinkedList<NewDimData>();
|
||||
|
||||
int packDepth = 1;
|
||||
DimData tailDim = dimHelper.dimList.get(inbound.destDimID);
|
||||
boolean found;
|
||||
|
||||
do
|
||||
{
|
||||
found = false;
|
||||
for (LinkData link : tailDim.getLinksInDim())
|
||||
{
|
||||
DimData neighbor = dimHelper.instance.getDimData(link.destDimID);
|
||||
if (neighbor.depth == tailDim.depth - 1 && neighbor.dungeonGenerator != null &&
|
||||
neighbor.dungeonGenerator.getDungeonType().Owner == pack)
|
||||
{
|
||||
tailDim = neighbor;
|
||||
found = true;
|
||||
packDepth++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (found);
|
||||
|
||||
return packDepth;
|
||||
}
|
||||
|
||||
public static ArrayList<DungeonGenerator> getFlatDungeonTree(DimData dimData, int maxSize)
|
||||
{
|
||||
//TODO: I've improved this code for the time being. However, searching across links is a flawed approach. A player could
|
||||
//manipulate the output of this function by setting up links to mislead our algorithm or by removing links.
|
||||
//Dimensions MUST have built-in records of their parent dimensions in the future. ~SenseiKiwi
|
||||
|
||||
dimHelper helper = dimHelper.instance;
|
||||
ArrayList<DungeonGenerator> dungeons = new ArrayList<DungeonGenerator>();
|
||||
DimData root = helper.getDimData(helper.getLinkDataFromCoords(dimData.exitDimLink.destXCoord, dimData.exitDimLink.destYCoord, dimData.exitDimLink.destZCoord, dimData.exitDimLink.destDimID).destDimID);
|
||||
HashSet<DimData> checked = new HashSet<DimData>();
|
||||
Queue<DimData> pendingDimensions = new LinkedList<DimData>();
|
||||
|
||||
if (root.dungeonGenerator == null)
|
||||
if (root.dungeon() == null)
|
||||
{
|
||||
return dungeons;
|
||||
}
|
||||
pendingDimensions.add(root);
|
||||
checked.add(root);
|
||||
|
||||
while (dungeons.size() < maxSize && !pendingDimensions.isEmpty())
|
||||
{
|
||||
DimData current = pendingDimensions.remove();
|
||||
for (LinkData link : current.getLinksInDim())
|
||||
NewDimData current = pendingDimensions.remove();
|
||||
for (NewDimData child : current.children())
|
||||
{
|
||||
DimData child = helper.getDimData(link.destDimID);
|
||||
if (child.depth == current.depth + 1 && child.dungeonGenerator != null && checked.add(child))
|
||||
if (child.dungeon() != null)
|
||||
{
|
||||
dungeons.add(child.dungeonGenerator);
|
||||
dungeons.add(child.dungeon());
|
||||
pendingDimensions.add(child);
|
||||
}
|
||||
if (dungeons.size() == maxSize)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,41 +1,23 @@
|
||||
package StevenDimDoors.mod_pocketDim.helpers;
|
||||
|
||||
import StevenDimDoors.mod_pocketDim.LinkData;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
import StevenDimDoors.mod_pocketDim.Point3D;
|
||||
|
||||
public class yCoordHelper
|
||||
{
|
||||
private static final int MAXIMUM_UNCOVERED_Y = 245;
|
||||
|
||||
public static int getFirstUncovered(LinkData pointerLink)
|
||||
{
|
||||
return yCoordHelper.getFirstUncovered(
|
||||
pointerLink.destDimID,
|
||||
pointerLink.destXCoord,
|
||||
pointerLink.destYCoord,
|
||||
pointerLink.destZCoord);
|
||||
}
|
||||
|
||||
public static int getFirstUncovered(int worldID, int x, int yStart, int z)
|
||||
{ return getFirstUncovered(worldID, x, yStart, z, false); }
|
||||
|
||||
public static int getFirstUncovered(int worldID, int x, int yStart, int z, boolean fromTop)
|
||||
{
|
||||
if (dimHelper.getWorld(worldID) == null ||
|
||||
dimHelper.getWorld(worldID).provider == null)
|
||||
{
|
||||
dimHelper.initDimension(worldID);
|
||||
}
|
||||
|
||||
return yCoordHelper.getFirstUncovered(dimHelper.getWorld(worldID), x, yStart, z, fromTop);
|
||||
}
|
||||
private yCoordHelper() { }
|
||||
|
||||
public static int getFirstUncovered(World world, int x, int yStart, int z)
|
||||
{ return getFirstUncovered(world, x, yStart, z, false); }
|
||||
{
|
||||
return getFirstUncovered(world, x, yStart, z, false);
|
||||
}
|
||||
|
||||
public static int getFirstUncovered(World world, int x, int yStart, int z, boolean fromTop)
|
||||
{
|
||||
@@ -43,21 +25,23 @@ public class yCoordHelper
|
||||
|
||||
int localX = x < 0 ? (x % 16) + 16 : (x % 16);
|
||||
int localZ = z < 0 ? (z % 16) + 16 : (z % 16);
|
||||
int height = MAXIMUM_UNCOVERED_Y; //world.getHeight();
|
||||
int height = MAXIMUM_UNCOVERED_Y;
|
||||
int y;
|
||||
|
||||
if(!fromTop)
|
||||
if (!fromTop)
|
||||
{
|
||||
boolean covered = true;
|
||||
for (y = yStart; y < height && covered; y++)
|
||||
{
|
||||
covered = IsCoveredBlock(chunk, localX, y - 1, localZ) || IsCoveredBlock(chunk, localX, y, localZ);
|
||||
covered = isCoveredBlock(chunk, localX, y - 1, localZ) || isCoveredBlock(chunk, localX, y, localZ);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean covered = false;
|
||||
for (y = MAXIMUM_UNCOVERED_Y; y > 1 && !covered; y--)
|
||||
{
|
||||
covered = IsCoveredBlock(chunk, localX, y - 1, localZ);
|
||||
covered = isCoveredBlock(chunk, localX, y - 1, localZ);
|
||||
}
|
||||
if (!covered) y = 63;
|
||||
y++;
|
||||
@@ -66,7 +50,7 @@ public class yCoordHelper
|
||||
return y;
|
||||
}
|
||||
|
||||
public static boolean IsCoveredBlock(Chunk chunk, int localX, int y, int localZ)
|
||||
public static boolean isCoveredBlock(Chunk chunk, int localX, int y, int localZ)
|
||||
{
|
||||
int blockID;
|
||||
Block block;
|
||||
@@ -86,4 +70,228 @@ public class yCoordHelper
|
||||
material = block.blockMaterial;
|
||||
return (material.isLiquid() || !material.isReplaceable());
|
||||
}
|
||||
|
||||
public static Point3D findSafeCubeUp(World world, int x, int startY, int z)
|
||||
{
|
||||
// Search for a 3x3x3 cube of air with blocks underneath
|
||||
// We can also match against a 3x2x3 box with
|
||||
// We shift the search area into the bounds of a chunk for the sake of simplicity,
|
||||
// so that we don't need to worry about working across chunks.
|
||||
|
||||
int localX = x < 0 ? (x % 16) + 16 : (x % 16);
|
||||
int localZ = z < 0 ? (z % 16) + 16 : (z % 16);
|
||||
int cornerX = x - localX;
|
||||
int cornerZ = z - localZ;
|
||||
localX = MathHelper.clamp_int(localX, 1, 14);
|
||||
localZ = MathHelper.clamp_int(localZ, 1, 14);
|
||||
|
||||
Chunk chunk = initializeChunkArea(world, x >> 4, z >> 4);
|
||||
|
||||
int height = world.getActualHeight();
|
||||
int y, dx, dz, blockID;
|
||||
boolean isSafe;
|
||||
Block block;
|
||||
|
||||
// Initialize layers to a huge negative number so that we won't
|
||||
// consider an area as usable unless it gets reset to 0 first
|
||||
// when we find a foundation upon which to build.
|
||||
int layers = -1000000;
|
||||
|
||||
// Check if a 3x3 layer of blocks is empty
|
||||
// If we find a layer that contains replaceable blocks, it can
|
||||
// serve as the base where we'll place the player and door.
|
||||
for (y = Math.max(startY - 1, 0); y < height; y++)
|
||||
{
|
||||
isSafe = true;
|
||||
for (dx = -1; dx <= 1 && isSafe; dx++)
|
||||
{
|
||||
for (dz = -1; dz <= 1 && isSafe; dz++)
|
||||
{
|
||||
blockID = chunk.getBlockID(localX + dx, y, localZ + dz);
|
||||
if (blockID != 0)
|
||||
{
|
||||
block = Block.blocksList[blockID];
|
||||
if (!block.blockMaterial.isReplaceable())
|
||||
{
|
||||
isSafe = false;
|
||||
}
|
||||
layers = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isSafe)
|
||||
{
|
||||
layers++;
|
||||
if (layers == 3)
|
||||
{
|
||||
return new Point3D(localX + cornerX, y - 2, localZ + cornerZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Point3D findSafeCubeDown(World world, int x, int startY, int z)
|
||||
{
|
||||
// Search for a 3x3x3 cube of air with blocks underneath
|
||||
// We can also match against a 3x2x3 box with
|
||||
// We shift the search area into the bounds of a chunk for the sake of simplicity,
|
||||
// so that we don't need to worry about working across chunks.
|
||||
|
||||
int localX = x < 0 ? (x % 16) + 16 : (x % 16);
|
||||
int localZ = z < 0 ? (z % 16) + 16 : (z % 16);
|
||||
int cornerX = x - localX;
|
||||
int cornerZ = z - localZ;
|
||||
localX = MathHelper.clamp_int(localX, 1, 14);
|
||||
localZ = MathHelper.clamp_int(localZ, 1, 14);
|
||||
|
||||
Chunk chunk = initializeChunkArea(world, x >> 4, z >> 4);
|
||||
|
||||
int height = world.getActualHeight();
|
||||
int y, dx, dz, blockID;
|
||||
boolean isSafe;
|
||||
boolean hasBlocks;
|
||||
Block block;
|
||||
int layers = 0;
|
||||
|
||||
// Check if a 3x3 layer of blocks is empty
|
||||
// If we find a layer that contains replaceable blocks, it can
|
||||
// serve as the base where we'll place the player and door.
|
||||
for (y = Math.min(startY + 2, height - 1); y >= 0; y--)
|
||||
{
|
||||
isSafe = true;
|
||||
hasBlocks = false;
|
||||
for (dx = -1; dx <= 1 && isSafe; dx++)
|
||||
{
|
||||
for (dz = -1; dz <= 1 && isSafe; dz++)
|
||||
{
|
||||
blockID = chunk.getBlockID(localX + dx, y, localZ + dz);
|
||||
if (blockID != 0)
|
||||
{
|
||||
block = Block.blocksList[blockID];
|
||||
if (!block.blockMaterial.isReplaceable())
|
||||
{
|
||||
if (layers >= 3)
|
||||
{
|
||||
return new Point3D(localX + cornerX, y + 1, localZ + cornerZ);
|
||||
}
|
||||
isSafe = false;
|
||||
}
|
||||
hasBlocks = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isSafe)
|
||||
{
|
||||
layers++;
|
||||
if (hasBlocks)
|
||||
{
|
||||
if (layers >= 3)
|
||||
{
|
||||
return new Point3D(localX + cornerX, y, localZ + cornerZ);
|
||||
}
|
||||
layers = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Chunk initializeChunkArea(World world, int chunkX, int chunkZ)
|
||||
{
|
||||
// We initialize a 3x3 area of chunks instead of just initializing
|
||||
// the target chunk because things generated in adjacent chunks
|
||||
// (e.g. trees) might intrude into the target chunk.
|
||||
|
||||
IChunkProvider provider = world.getChunkProvider();
|
||||
Chunk target = provider.loadChunk(chunkX, chunkZ);
|
||||
for (int dx = -1; dx <= 1; dx++)
|
||||
{
|
||||
for (int dz = -1; dz <= 1; dz++)
|
||||
{
|
||||
if (!provider.chunkExists(chunkX + dx, chunkZ + dz))
|
||||
{
|
||||
provider.loadChunk(chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
public static Point3D findDropPoint(World world, int x, int startY, int z)
|
||||
{
|
||||
// Find a simple 2-block-high air gap
|
||||
// Search across a 3x3 column
|
||||
final int GAP_HEIGHT = 2;
|
||||
|
||||
int localX = x < 0 ? (x % 16) + 16 : (x % 16);
|
||||
int localZ = z < 0 ? (z % 16) + 16 : (z % 16);
|
||||
int cornerX = x - localX;
|
||||
int cornerZ = z - localZ;
|
||||
localX = MathHelper.clamp_int(localX, 1, 14);
|
||||
localZ = MathHelper.clamp_int(localZ, 1, 14);
|
||||
|
||||
Chunk chunk = initializeChunkArea(world, x >> 4, z >> 4);
|
||||
|
||||
int y, dx, dz, index;
|
||||
int height = world.getActualHeight();
|
||||
int[] gaps = new int[9];
|
||||
|
||||
// Check 3x3 layers of blocks for air spaces
|
||||
for (y = Math.min(startY, height - 1); y > 0; y--)
|
||||
{
|
||||
for (dx = -1, index = 0; dx <= 1; dx++)
|
||||
{
|
||||
for (dz = -1; dz <= 1; dz++, index++)
|
||||
{
|
||||
if (chunk.getBlockID(localX + dx, y, localZ + dz) != 0)
|
||||
{
|
||||
gaps[index] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gaps[index]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if an acceptable gap exists in the center of the search column
|
||||
if (gaps[index / 2] == GAP_HEIGHT)
|
||||
{
|
||||
return new Point3D(localX + cornerX, y + GAP_HEIGHT - 1, localZ + cornerZ);
|
||||
}
|
||||
// Check the other positions in the column
|
||||
for (dx = -1, index = 0; dx <= 1; dx++)
|
||||
{
|
||||
for (dz = -1; dz <= 1; dz++, index++)
|
||||
{
|
||||
if (gaps[index] == GAP_HEIGHT)
|
||||
{
|
||||
return new Point3D(localX + cornerX + dx, y + GAP_HEIGHT - 1, localZ + cornerZ + dz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int adjustDestinationY(int y, int worldHeight, int entranceY, int dungeonHeight)
|
||||
{
|
||||
//The goal here is to guarantee that the dungeon fits within the vertical bounds
|
||||
//of the world while shifting it as little as possible.
|
||||
int destY = y;
|
||||
|
||||
//Is the top of the dungeon going to be at Y < worldHeight?
|
||||
int pocketTop = (dungeonHeight - 1) + destY - entranceY;
|
||||
if (pocketTop >= worldHeight)
|
||||
{
|
||||
destY = (worldHeight - 1) - (dungeonHeight - 1) + entranceY;
|
||||
}
|
||||
|
||||
//Is the bottom of the dungeon at Y >= 0?
|
||||
if (destY < entranceY)
|
||||
{
|
||||
destY = entranceY;
|
||||
}
|
||||
return destY;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user