Created build.gradle

Restructured folder structure for ForgeGradle

Signed-off-by: deathrat <deathrat43@gmail.com>
This commit is contained in:
deathrat
2013-12-17 03:35:59 -05:00
parent 602b55111f
commit 505b182af9
335 changed files with 38 additions and 29 deletions

View File

@@ -0,0 +1,10 @@
DimDoors
========
Dimensional Doors for Minecraft
Adds several items that allow the player to move between and create dimensions
see the MC forum topic for details
http://www.minecraftforum.net/topic/1650007-147-dimensional-doors-v110-physics-what-physics-updated-with-fancy-opengl/

View File

@@ -0,0 +1,42 @@
package StevenDimDoors.mod_pocketDim;
import net.minecraft.entity.Entity;
import net.minecraft.world.Teleporter;
import net.minecraft.world.WorldServer;
public class BlankTeleporter extends Teleporter
{
public BlankTeleporter(WorldServer par1WorldServer)
{
super(par1WorldServer);
}
/**
* Create a new portal near an entity.
*/
@Override
public void placeInPortal(Entity par1Entity, double par2, double par4, double par6, float par8)
{
}
public void setEntityPosition(Entity entity, double x, double y, double z)
{
entity.lastTickPosX = entity.prevPosX = entity.posX = x;
entity.lastTickPosY = entity.prevPosY = entity.posY = y + entity.yOffset;
entity.lastTickPosZ = entity.prevPosZ = entity.posZ = z;
entity.setPosition(x, y, z);
}
@Override
public void removeStalePortalLocations(long par1)
{
}
}

View File

@@ -0,0 +1,17 @@
package StevenDimDoors.mod_pocketDim;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraftforge.client.IRenderHandler;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class CloudRenderBlank extends IRenderHandler
{
@Override
@SideOnly(Side.CLIENT)
public void render(float partialTicks, WorldClient world, Minecraft mc)
{
}
}

View File

@@ -0,0 +1,135 @@
package StevenDimDoors.mod_pocketDim;
import java.io.File;
import java.io.FileOutputStream;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.network.IGuiHandler;
public class CommonProxy implements IGuiHandler
{
public static String BLOCK_PNG = "/PocketBlockTextures.png";
public static String ITEM_PNG = "/PocketItemTextures.png";
public static String RIFT_PNG = "/RIFT.png";
public static String RIFT2_PNG = "/RIFT2.png";
public static String WARP_PNG = "/WARP.png";
public void registerRenderers()
{
}
public void registerEntity(Class <? extends Entity > entity, String entityname, int id, Object mod, int trackingrange, int updateFreq, boolean updatevelo)
{
}
@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z)
{
return null;
}
@Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z)
{
return null;
}
public void loadTextures()
{
}
public void writeNBTToFile(World world)
{
boolean flag = true;
try
{
File dataStore = world.getSaveHandler().getMapFileFromName("idcounts");
String dirFolder = dataStore.getCanonicalPath();
dirFolder = dirFolder.replace("idcounts.dat", "");
if (!flag)
{
dirFolder.replace("saves/", FMLCommonHandler.instance().getMinecraftServerInstance().getFolderName());
}
File file = new File(dirFolder, "GGMData.dat");
if (!file.exists())
{
file.createNewFile();
}
FileOutputStream fileoutputstream = new FileOutputStream(file);
NBTTagCompound nbttagcompound = new NBTTagCompound();
CompressedStreamTools.writeCompressed(nbttagcompound, fileoutputstream);
fileoutputstream.close();
}
catch (Exception exception)
{
// exception.printStackTrace();
if (!(exception instanceof NullPointerException))
{
}
flag = false;
}
}
public void readNBTFromFile(World world)
{
boolean flag = true;
try
{
File dataStore = world.getSaveHandler().getMapFileFromName("idcounts");
String dirFolder = dataStore.getCanonicalPath();
dirFolder = dirFolder.replace("idcounts.dat", "");
if (!flag)
{
dirFolder.replace("saves/", FMLCommonHandler.instance().getMinecraftServerInstance().getFolderName());
}
File file = new File(dirFolder, "GGMData.dat");
if (!file.exists())
{
file.createNewFile();
FileOutputStream fileoutputstream = new FileOutputStream(file);
NBTTagCompound nbttagcompound = new NBTTagCompound();
CompressedStreamTools.writeCompressed(nbttagcompound, fileoutputstream);
fileoutputstream.close();
}
/*FileInputStream fileinputstream = new FileInputStream(file);
NBTTagCompound nbttagcompound = CompressedStreamTools.readCompressed(fileinputstream);
fileinputstream.close();*/
}
catch (Exception exception)
{
// exception.printStackTrace();
if (!(exception instanceof NullPointerException))
{
}
flag = false;
}
}
public void printStringClient(String string)
{
}
}

View File

@@ -0,0 +1,68 @@
package StevenDimDoors.mod_pocketDim;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.NetLoginHandler;
import net.minecraft.network.packet.NetHandler;
import net.minecraft.network.packet.Packet1Login;
import net.minecraft.network.packet.Packet250CustomPayload;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.integrated.IntegratedServer;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import cpw.mods.fml.common.network.IConnectionHandler;
import cpw.mods.fml.common.network.Player;
public class ConnectionHandler implements IConnectionHandler
{
@Override
public String connectionReceived(NetLoginHandler netHandler, INetworkManager manager)
{
try
{
Packet250CustomPayload packet = new Packet250CustomPayload();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream writer = new DataOutputStream(buffer);
writer.writeByte(PacketConstants.CLIENT_JOIN_PACKET_ID);
PocketManager.writePacket(writer);
writer.close();
packet.channel = PacketConstants.CHANNEL_NAME;
packet.data = buffer.toByteArray();
packet.length = packet.data.length;
manager.addToSendQueue(packet);
}
catch (IOException e)
{
//This shouldn't happen...
e.printStackTrace();
}
return null;
}
@Override
public void connectionOpened(NetHandler netClientHandler, String server, int port, INetworkManager manager) { }
@Override
public void connectionOpened(NetHandler netClientHandler,MinecraftServer server, INetworkManager manager) { }
@Override
public void connectionClosed(INetworkManager manager)
{
if(PocketManager.isConnected)
{
PocketManager.unload();
}
}
@Override
public void clientLoggedIn(NetHandler clientHandler, INetworkManager manager, Packet1Login login) { }
@Override
public void playerLoggedIn(Player player, NetHandler netHandler, INetworkManager manager)
{
//Send information about all the registered dimensions and links to the client
}
}

View File

@@ -0,0 +1,135 @@
package StevenDimDoors.mod_pocketDim;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import cpw.mods.fml.common.registry.GameRegistry;
import static StevenDimDoors.mod_pocketDim.mod_pocketDim.*;
public class CraftingManager
{
public static void registerRecipies()
{
Item coreCraftingItem = Item.enderPearl;
if(properties.enableServerMode)
{
coreCraftingItem = itemWorldThread;
}
if (properties.CraftingDimensionalDoorAllowed)
{
GameRegistry.addRecipe(new ItemStack(itemDimDoor, 1), new Object[]
{
" ", "yxy", " ", 'x', coreCraftingItem, 'y', Item.doorIron
});
GameRegistry.addRecipe(new ItemStack(itemDimDoor, 1), new Object[]
{
" ", "yxy", " ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorIron
});
}
if(properties.CraftingUnstableDoorAllowed)
{
GameRegistry.addRecipe(new ItemStack(itemChaosDoor, 1), new Object[]
{
" ", "yxy", " ", 'x', Item.eyeOfEnder, 'y', mod_pocketDim.itemDimDoor
});
}
if(properties.CraftingWarpDoorAllowed)
{
GameRegistry.addRecipe(new ItemStack(itemExitDoor, 1), new Object[]
{
" ", "yxy", " ", 'x', coreCraftingItem, 'y', Item.doorWood
});
GameRegistry.addRecipe(new ItemStack(itemExitDoor, 1), new Object[]
{
" ", "yxy", " ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorWood
});
}
if(properties.CraftingTransTrapdoorAllowed)
{
GameRegistry.addRecipe(new ItemStack(transTrapdoor, 1), new Object[]
{
" y ", " x ", " y ", 'x', coreCraftingItem, 'y', Block.trapdoor
});
GameRegistry.addRecipe(new ItemStack(transTrapdoor, 1), new Object[]
{
" y ", " x ", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Block.trapdoor
});
}
if(properties.CraftingRiftSignatureAllowed)
{
GameRegistry.addRecipe(new ItemStack(itemLinkSignature, 1), new Object[]
{
" y ", "yxy", " y ", 'x', coreCraftingItem, 'y', Item.ingotIron
});
GameRegistry.addRecipe(new ItemStack(itemLinkSignature, 1), new Object[]
{
" y ", "yxy", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotIron
});
}
if(properties.CraftingRiftRemoverAllowed)
{
GameRegistry.addRecipe(new ItemStack(itemRiftRemover, 1), new Object[]
{
" y ", "yxy", " y ", 'x', coreCraftingItem, 'y', Item.ingotGold
});
GameRegistry.addRecipe(new ItemStack(itemRiftRemover, 1), new Object[]
{
"yyy", "yxy", "yyy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotGold
});
}
if (properties.CraftingRiftBladeAllowed)
{
GameRegistry.addRecipe(new ItemStack(itemRiftBlade, 1), new Object[]
{
" x ", " x ", " y ", 'x', coreCraftingItem, 'y',mod_pocketDim.itemRiftRemover
});
}
if (properties.CraftingStableFabricAllowed)
{
GameRegistry.addRecipe(new ItemStack(itemStableFabric, 1), new Object[]
{
"yyy", "yxy", "yyy", 'x', coreCraftingItem, 'y', mod_pocketDim.itemWorldThread
});
}
if (properties.CraftingStabilizedRiftSignatureAllowed)
{
GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStabilizedLinkSignature,1), new Object[]
{
" y ", "yxy", " y ", 'x', mod_pocketDim.itemLinkSignature, 'y', mod_pocketDim.itemStableFabric
});
}
if (properties.CraftingGoldDimDoorAllowed)
{
GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldDimDoor,1), new Object[]
{
" x ", " y ", " x ", 'x', mod_pocketDim.itemGoldDoor, 'y', Item.eyeOfEnder
});
}
if (properties.CraftingGoldDoorAllowed)
{
GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldDoor,1), new Object[]
{
"yy ", "yy ", "yy ", 'y', Item.ingotGold
});
GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldDoor,1), new Object[]
{
" yy", " yy", " yy", 'y', Item.ingotGold
});
}
}
}

View File

@@ -0,0 +1,212 @@
package StevenDimDoors.mod_pocketDim;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.WeightedRandom;
import net.minecraft.util.WeightedRandomChestContent;
import net.minecraftforge.common.ChestGenHooks;
/*
* Registers a category of loot chests for Dimensional Doors in Forge.
*/
public class DDLoot {
//These are the categories of loot to be merged into our chests
static final String[] chestSources = new String[] {
ChestGenHooks.MINESHAFT_CORRIDOR,
ChestGenHooks.PYRAMID_DESERT_CHEST,
ChestGenHooks.PYRAMID_JUNGLE_CHEST,
ChestGenHooks.STRONGHOLD_CORRIDOR,
ChestGenHooks.STRONGHOLD_CROSSING,
ChestGenHooks.VILLAGE_BLACKSMITH,
ChestGenHooks.DUNGEON_CHEST
};
public static final String DIMENSIONAL_DUNGEON_CHEST = "dimensionalDungeonChest";
public static ChestGenHooks DungeonChestInfo = null;
private static final int CHEST_SIZE = 5;
private static final int COMMON_LOOT_WEIGHT = 9; //1 less than weight of iron ingots
private static final int UNCOMMON_LOOT_WEIGHT = 4; //1 less than weight of iron armor
private static final int RARE_LOOT_WEIGHT = 1; //Same weight as music discs, golden apple
private static final int DUNGEON_CHEST_WEIGHT_INFLATION = 10; // (weight of iron ingots in dungeon) / (weight of iron ingots in other chests)
private DDLoot() { }
public static void registerInfo()
{
DDProperties properties = DDProperties.instance();
//Register the dimensional dungeon chest with ChestGenHooks. This isn't necessary, but allows
//other mods to add their own loot to our chests if they know our loot category, without having
//to interface with our code.
DungeonChestInfo = ChestGenHooks.getInfo(DIMENSIONAL_DUNGEON_CHEST);
DungeonChestInfo.setMin(CHEST_SIZE);
DungeonChestInfo.setMax(CHEST_SIZE);
//Merge the item lists from source chests
//This means chests will include future loot as Minecraft updates! ^_^
ArrayList<WeightedRandomChestContent> items = mergeCategories(chestSources);
//Add any enabled DD loot to the list of items
addContent(properties.FabricOfRealityLootEnabled, items, mod_pocketDim.blockDimWall.blockID, 8, 32, COMMON_LOOT_WEIGHT);
addContent(properties.DimensionalDoorLootEnabled, items, mod_pocketDim.itemDimDoor.itemID, UNCOMMON_LOOT_WEIGHT);
addContent(properties.WarpDoorLootEnabled, items, mod_pocketDim.itemExitDoor.itemID, UNCOMMON_LOOT_WEIGHT);
addContent(properties.TransTrapdoorLootEnabled, items, mod_pocketDim.transTrapdoor.blockID, UNCOMMON_LOOT_WEIGHT);
addContent(properties.RiftSignatureLootEnabled, items, mod_pocketDim.itemLinkSignature.itemID, UNCOMMON_LOOT_WEIGHT);
addContent(properties.StableFabricLootEnabled, items, mod_pocketDim.itemStableFabric.itemID, UNCOMMON_LOOT_WEIGHT);
addContent(properties.RiftRemoverLootEnabled, items, mod_pocketDim.itemRiftRemover.itemID, UNCOMMON_LOOT_WEIGHT);
addContent(properties.UnstableDoorLootEnabled, items, mod_pocketDim.itemChaosDoor.itemID, RARE_LOOT_WEIGHT);
addContent(properties.StabilizedRiftSignatureLootEnabled, items, mod_pocketDim.itemStabilizedLinkSignature.itemID, RARE_LOOT_WEIGHT);
addContent(properties.RiftBladeLootEnabled, items, mod_pocketDim.itemRiftBlade.itemID, RARE_LOOT_WEIGHT);
//Add all the items to our dungeon chest
addItemsToContainer(DungeonChestInfo, items);
}
private static ArrayList<WeightedRandomChestContent> mergeCategories(String[] categories)
{
//Retrieve the items of each container category and merge the lists together. If two matching items
//are found, choose the item with the minimum weight. Special checks are included for DUNGEON_CHEST
//because the items in that category have strange weights that are incompatible with all other
//chest categories.
Random random = new Random();
HashMap<Integer, WeightedRandomChestContent> container = new HashMap<Integer, WeightedRandomChestContent>();
for (String category : categories)
{
WeightedRandomChestContent[] items = ChestGenHooks.getItems(category, random);
for (WeightedRandomChestContent item : items)
{
ItemStack stack = item.theItemId;
int id = stack.itemID;
int subtype = stack.getItem().getHasSubtypes() ? stack.getItemDamage() : 0;
//Correct the weights of Vanilla dungeon chests (DUNGEON_CHEST)
//Comparing by String references is valid here since they should match!
if (category == ChestGenHooks.DUNGEON_CHEST)
{
//It's okay to modify the weights directly. These are copies of instances,
//not direct references. It won't affect Vanilla chests.
item.itemWeight /= DUNGEON_CHEST_WEIGHT_INFLATION;
if (item.itemWeight == 0)
item.itemWeight = 1;
}
//Generate an identifier for this item using its item ID and damage value,
//if it has subtypes. This solves the issue of matching items that have
//the same item ID but different subtypes (e.g. wood planks, dyes).
int key = ((subtype & 0xFFFF) << 16) + ((id & 0xFFFF) << 16);
WeightedRandomChestContent other = container.get(key);
if (other == null)
{
//This item has not been seen before. Simply add it to the container.
container.put(key, item);
}
else
{
//This item conflicts with an existing entry. Replace that entry
//if our current item has a lower weight.
if (item.itemWeight < other.itemWeight)
{
container.put(key, item);
}
}
}
}
//I've added a minor hack here to make enchanted books more common
//If this is necessary for more items, create an override table and use that
//rather than hardcoding the changes below
final int enchantedBookID = Item.enchantedBook.itemID;
for (WeightedRandomChestContent item : container.values())
{
if (item.theItemId.itemID == enchantedBookID)
{
item.itemWeight = 4;
break;
}
}
//Return merged list
return new ArrayList<WeightedRandomChestContent>( container.values() );
}
private static void addContent(boolean include, ArrayList<WeightedRandomChestContent> items,
int itemID, int weight)
{
if (include)
items.add(new WeightedRandomChestContent(itemID, 0, 1, 1, weight));
}
private static void addContent(boolean include, ArrayList<WeightedRandomChestContent> items,
int itemID, int minAmount, int maxAmount, int weight)
{
if (include)
items.add(new WeightedRandomChestContent(itemID, 0, minAmount, maxAmount, weight));
}
private static void addItemsToContainer(ChestGenHooks container, ArrayList<WeightedRandomChestContent> items)
{
//System.out.println("Preparing Chest Stuff");
for (WeightedRandomChestContent item : items)
{
container.addItem(item);
//Uncomment this code to print out loot and weight pairs
//System.out.println(item.theItemId.getDisplayName() + "\t" + item.itemWeight);
}
}
public static void generateChestContents(ChestGenHooks chestInfo, IInventory inventory, Random random)
{
//This is a custom version of net.minecraft.util.WeightedRandomChestContent.generateChestContents()
//It's designed to avoid the following bugs in MC 1.5:
//1. The randomized filling algorithm will sometimes overwrite item stacks with other stacks
//2. If multiple enchanted books appear, then they will have the same enchantment
//The prime number below is used for choosing chest slots in a seemingly-random pattern. Its value
//was selected specifically to achieve a spread-out distribution for chests with up to 104 slots.
//Choosing a prime number ensures that our increments are relatively-prime to the chest size, which
//means we'll cover all the slots before repeating any. This is mathematically guaranteed.
final int primeOffset = 239333;
int count = chestInfo.getCount(random);
int size = inventory.getSizeInventory();
WeightedRandomChestContent[] content = chestInfo.getItems(random);
for (int k = 0; k < count; k++)
{
WeightedRandomChestContent selection = (WeightedRandomChestContent)WeightedRandom.getRandomItem(random, content);
//Call getChestGenBase() to make sure we generate a different enchantment for books.
//Don't just use a condition to check if the item is an instance of ItemEnchantedBook because
//we don't know if other mods might add items that also need to be regenerated.
selection = selection.theItemId.getItem().getChestGenBase(chestInfo, random, selection);
ItemStack[] stacks = ChestGenHooks.generateStacks(random, selection.theItemId, selection.theMinimumChanceToGenerateItem, selection.theMaximumChanceToGenerateItem);
for (ItemStack item : stacks)
{
int limit = size;
int index = random.nextInt(size);
while (limit > 0 && inventory.getStackInSlot(index) != null)
{
limit--;
index = (index + primeOffset) % size;
}
inventory.setInventorySlotContents(index, item);
}
}
}
}

View File

@@ -0,0 +1,275 @@
package StevenDimDoors.mod_pocketDim;
import java.io.File;
import net.minecraftforge.common.Configuration;
import StevenDimDoors.mod_pocketDim.ticking.MonolithSpawner;
import StevenDimDoors.mod_pocketDim.world.GatewayGenerator;
public class DDProperties
{
/**
* Block IDs
*/
public final int UnstableDoorID;
public final int DimensionalDoorID;
public final int GoldDoorID;
public final int GoldDimDoorID;
public final int WarpDoorID;
public final int TransTrapdoorID;
public final int TransientDoorID;
public final int FabricBlockID;
public final int RiftBlockID;
/**
* World Generation Block IDs
*/
public final int LimboBlockID;
public final int PermaFabricBlockID;
/**
* Item IDs
*/
public final int RiftBladeItemID;
public final int RiftSignatureItemID;
public final int GoldDimDoorItemID;
public final int GoldDoorItemID;
public final int RiftRemoverItemID;
public final int StableFabricItemID;
public final int StabilizedRiftSignatureItemID;
public final int DimensionalDoorItemID;
public final int UnstableDoorItemID;
public final int WarpDoorItemID;
public final int ItemWorldThreadID;
/**
* Other IDs
*/
public final int LimboBiomeID;
public final int PocketBiomeID;
public final int LimboDimensionID;
public final int LimboProviderID;
public final int PocketProviderID;
public final int DoorRenderEntityID;
public final int MonolithEntityID;
/**
* Crafting Flags
*/
public final boolean CraftingDimensionalDoorAllowed;
public final boolean CraftingWarpDoorAllowed;
public final boolean CraftingRiftSignatureAllowed;
public final boolean CraftingRiftRemoverAllowed;
public final boolean CraftingUnstableDoorAllowed;
public final boolean CraftingRiftBladeAllowed;
public final boolean CraftingTransTrapdoorAllowed;
public final boolean CraftingStabilizedRiftSignatureAllowed;
public final boolean CraftingStableFabricAllowed;
public final boolean CraftingGoldDimDoorAllowed;
public final boolean CraftingGoldDoorAllowed;
/**
* Loot Flags
*/
public final boolean DimensionalDoorLootEnabled;
public final boolean WarpDoorLootEnabled;
public final boolean UnstableDoorLootEnabled;
public final boolean TransTrapdoorLootEnabled;
public final boolean RiftSignatureLootEnabled;
public final boolean RiftRemoverLootEnabled;
public final boolean StabilizedRiftSignatureLootEnabled;
public final boolean RiftBladeLootEnabled;
public final boolean StableFabricLootEnabled;
public final boolean FabricOfRealityLootEnabled;
/**
* Other Flags
*/
public final boolean enableServerMode;
public final boolean WorldRiftGenerationEnabled;
public final boolean RiftSpreadEnabled;
public final boolean RiftGriefingEnabled;
public final boolean RiftsSpawnEndermenEnabled;
public final boolean LimboEnabled;
public final boolean HardcoreLimboEnabled;
public final boolean LimboReturnsInventoryEnabled;
public final boolean DoorRenderingEnabled;
public final boolean TNFREAKINGT_Enabled;
/**
* Other
*/
public final int NonTntWeight;
public final int ClusterGenerationChance;
public final int GatewayGenerationChance;
public final int MonolithSpawningChance;
public final int LimboReturnRange;
public final String CustomSchematicDirectory;
//Singleton instance
private static DDProperties instance = null;
//Path for custom dungeons within configuration directory
private final String CUSTOM_SCHEMATIC_SUBDIRECTORY = "/DimDoors_Custom_schematics";
//Names of categories
private final String CATEGORY_SERVERMODE = "server mode";
private final String CATEGORY_CRAFTING = "crafting";
private final String CATEGORY_ENTITY = "entity";
private final String CATEGORY_DIMENSION = "dimension";
private final String CATEGORY_PROVIDER = "provider";
private final String CATEGORY_BIOME = "biome";
private final String CATEGORY_LOOT = "loot";
private DDProperties(File configFile)
{
//Load the configuration. This must be done in the constructor, even though I'd rather have a separate
//function, because "blank final" variables must be initialized within the constructor.
CustomSchematicDirectory = configFile.getParent() + CUSTOM_SCHEMATIC_SUBDIRECTORY;
Configuration config = new Configuration(configFile);
config.load();
CraftingDimensionalDoorAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Dimensional Door", true).getBoolean(true);
CraftingWarpDoorAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Warp Door", true).getBoolean(true);
CraftingUnstableDoorAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Unstable Door", true).getBoolean(true);
CraftingTransTrapdoorAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Transdimensional Trapdoor", true).getBoolean(true);
CraftingRiftSignatureAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Rift Signature", true).getBoolean(true);
CraftingRiftRemoverAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Rift Remover", true).getBoolean(true);
CraftingStabilizedRiftSignatureAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Stabilized Rift Signature", true).getBoolean(true);
CraftingRiftBladeAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Rift Blade", true).getBoolean(true);
CraftingStableFabricAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Stable Fabric", true).getBoolean(true);
CraftingGoldDimDoorAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Golden Dimensional Door", true).getBoolean(true);
CraftingGoldDoorAllowed = config.get(CATEGORY_CRAFTING, "Allow Golden Door", true).getBoolean(true);
DimensionalDoorLootEnabled = config.get(CATEGORY_LOOT, "Enable Dimensional Door Loot", true).getBoolean(true);
WarpDoorLootEnabled = config.get(CATEGORY_LOOT, "Enable Warp Door Loot", false).getBoolean(false);
UnstableDoorLootEnabled = config.get(CATEGORY_LOOT, "Enable Unstable Door Loot", false).getBoolean(false);
TransTrapdoorLootEnabled = config.get(CATEGORY_LOOT, "Enable Transdimensional Trapdoor Loot", false).getBoolean(false);
RiftSignatureLootEnabled = config.get(CATEGORY_LOOT, "Enable Rift Signature Loot", true).getBoolean(true);
RiftRemoverLootEnabled = config.get(CATEGORY_LOOT, "Enable Rift Remover Loot", true).getBoolean(true);
StabilizedRiftSignatureLootEnabled = config.get(CATEGORY_LOOT, "Enable Stabilized Rift Signature Loot", false).getBoolean(false);
RiftBladeLootEnabled = config.get(CATEGORY_LOOT, "Enable Rift Blade Loot", true).getBoolean(true);
StableFabricLootEnabled = config.get(CATEGORY_LOOT, "Enable Stable Fabric Loot", false).getBoolean(false);
FabricOfRealityLootEnabled = config.get(CATEGORY_LOOT, "Enable Fabric of Reality Loot", true).getBoolean(true);
RiftGriefingEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Rift Griefing", true,
"Sets whether rifts destroy blocks around them or not").getBoolean(true);
RiftSpreadEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Rift Spread", true,
"Sets whether rifts create more rifts when they are near other rifts").getBoolean(true);
RiftsSpawnEndermenEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Endermen Spawning from Rifts", true,
"Sets whether groups of connected rifts will spawn Endermen").getBoolean(true);
LimboEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Limbo", true,
"Sets whether the Limbo dimension is activated").getBoolean(true);
LimboReturnsInventoryEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Limbo Returns Inventory", true,
"Sets whether players keep their inventories upon dying and respawning in Limbo").getBoolean(true);
HardcoreLimboEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Hardcore Limbo", false,
"Sets whether players that die in Limbo will respawn there").getBoolean(false);
LimboReturnRange = config.get(Configuration.CATEGORY_GENERAL, "Limbo Return Range", 500,
"Sets the farthest distance that Limbo can send you upon returning to the Overworld").getInt();
DoorRenderingEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Door Rendering", true).getBoolean(true);
TNFREAKINGT_Enabled = config.get(Configuration.CATEGORY_GENERAL, "EXPLOSIONS!!???!!!?!?!!", false).getBoolean(false);
NonTntWeight = config.get(Configuration.CATEGORY_GENERAL, "HOWMUCHTNT", 25,
"Weighs the chance that a block will not be TNT. Must be greater than or equal to 0. " +
"EXPLOSIONS must be set to true for this to have any effect.").getInt();
enableServerMode = config.get(CATEGORY_SERVERMODE, "Server Mode", false,
"Enables servermode, changing all crafting recipies to require stabilized fabric. " +
"Stabilized fabric, in turn, requires the item World Thread, which is not craftable or obtainable at all. "+
"It is up to the server manager on how to distribute it.").getBoolean(false);
DoorRenderEntityID=config.get(CATEGORY_ENTITY, "Door Render Entity ID", 89).getInt();
MonolithEntityID = config.get(CATEGORY_ENTITY, "Monolith Entity ID", 125).getInt();
DimensionalDoorID = config.getBlock("Dimensional Door Block ID", 1970).getInt();
TransTrapdoorID = config.getBlock("Transdimensional Trapdoor Block ID", 1971).getInt();
FabricBlockID =config.getBlock("Fabric Of Reality Block ID", 1973).getInt();
WarpDoorID = config.getBlock("Warp Door Block ID", 1975).getInt();
RiftBlockID = config.getBlock("Rift Block ID", 1977).getInt();
UnstableDoorID = config.getBlock("Unstable Door Block ID", 1978).getInt();
TransientDoorID = config.getBlock("Transient Door Block ID", 1979).getInt();
GoldDoorID = config.getBlock("Gold Door Block ID", 1980).getInt();
GoldDimDoorID = config.getBlock("Gold Dim Door Block ID", 1981).getInt();
WarpDoorItemID = config.getItem("Warp Door Item ID", 5670).getInt();
RiftRemoverItemID = config.getItem("Rift Remover Item ID", 5671).getInt();
StableFabricItemID = config.getItem("Stable Fabric Item ID", 5672).getInt();
UnstableDoorItemID = config.getItem("Unstable Door Item ID", 5673).getInt();
DimensionalDoorItemID = config.getItem("Dimensional Door Item ID", 5674).getInt();
RiftSignatureItemID = config.getItem("Rift Signature Item ID", 5675).getInt();
RiftBladeItemID = config.getItem("Rift Blade Item ID", 5676).getInt();
StabilizedRiftSignatureItemID = config.getItem("Stabilized Rift Signature Item ID", 5677).getInt();
GoldDoorItemID = config.getItem("Gold Door Item ID", 5678).getInt();
GoldDimDoorItemID = config.getItem("Gold Dim Door Item ID", 5679).getInt();
ItemWorldThreadID = config.getItem("World Thread Item ID", 5680).getInt();
LimboBlockID = config.getTerrainBlock("World Generation Block IDs - must be less than 256", "Limbo Block ID", 217,
"Blocks used for the terrain in Limbo").getInt();
PermaFabricBlockID = config.getTerrainBlock("World Generation Block IDs - must be less than 256",
"Perma Fabric Block ID", 220, "Blocks used for enclosing pocket dimensions").getInt();
LimboDimensionID = config.get(CATEGORY_DIMENSION, "Limbo Dimension ID", -23).getInt();
PocketProviderID = config.get(CATEGORY_PROVIDER, "Pocket Provider ID", 24).getInt();
LimboProviderID = config.get(CATEGORY_PROVIDER, "Limbo Provider ID", 13).getInt();
WorldRiftGenerationEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Rift World Generation", true,
"Sets whether dungeon rifts generate in dimensions other than Limbo").getBoolean(true);
MonolithSpawningChance = config.get(Configuration.CATEGORY_GENERAL, "Monolith Spawning Chance", 28,
"Sets the chance (out of " + MonolithSpawner.MAX_MONOLITH_SPAWNING_CHANCE + ") that Monoliths will " +
"spawn in a given Limbo chunk. The default chance is 28.").getInt();
ClusterGenerationChance = config.get(Configuration.CATEGORY_GENERAL, "Cluster Generation Chance", 2,
"Sets the chance (out of " + GatewayGenerator.MAX_CLUSTER_GENERATION_CHANCE + ") that a cluster of rifts will " +
"generate in a given chunk. The default chance is 2.").getInt();
GatewayGenerationChance = config.get(Configuration.CATEGORY_GENERAL, "Gateway Generation Chance", 15,
"Sets the chance (out of " + GatewayGenerator.MAX_GATEWAY_GENERATION_CHANCE + ") that a Rift Gateway will " +
"generate in a given chunk. The default chance is 15.").getInt();
LimboBiomeID = config.get(CATEGORY_BIOME, "Limbo Biome ID", 251).getInt();
PocketBiomeID = config.get(CATEGORY_BIOME, "Pocket Biome ID", 250).getInt();
config.save();
//Unfortunately, there are users out there who have been misconfiguring the worldgen blocks to have IDs above 255.
//This leads to disastrous and cryptic errors in other areas of Minecraft. To prevent headaches, we'll throw
//an exception here if the blocks have invalid IDs.
if (LimboBlockID > 255 || PermaFabricBlockID > 255)
{
throw new IllegalStateException("World generation blocks MUST have block IDs less than 256. Fix your configuration!");
}
}
public static DDProperties initialize(File configFile)
{
if (instance == null)
instance = new DDProperties(configFile);
else
throw new IllegalStateException("Cannot initialize DDProperties twice");
return instance;
}
public static DDProperties instance()
{
if (instance == null)
{
//This is to prevent some frustrating bugs that could arise when classes
//are loaded in the wrong order. Trust me, I had to squash a few...
throw new IllegalStateException("Instance of DDProperties requested before initialization");
}
return instance;
}
}

View File

@@ -0,0 +1,257 @@
package StevenDimDoors.mod_pocketDim;
/**Class that contains all the information about a specific dim that is pertienent to Dim Doors. Holds all the rifts present in the dim sorted by x,y,z and
* wether or not the dim is a pocket or not, along with its depth.
* @Return
*/
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
@Deprecated
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 Object dungeonGenerator = null;
//public boolean isPrivatePocket = false;
public HashMap<Integer, HashMap<Integer, HashMap<Integer, LinkData>>> linksInThisDim = new HashMap();
HashMap<Integer, LinkData> dimX;
HashMap<Integer, HashMap<Integer, LinkData>> 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;
float distance=range+1;
int i=-range;
int j=-range;
int k=-range;
DDProperties properties = DDProperties.instance();
while (i<range)
{
while (j<range)
{
while (k<range)
{
if (world.getBlockId(x+i, y+j, z+k) == properties.RiftBlockID && MathHelper.abs(i)+MathHelper.abs(j)+MathHelper.abs(k)<distance)
{
if(MathHelper.abs(i)+MathHelper.abs(j)+MathHelper.abs(k)!=0)
{
nearest=this.findLinkAtCoords(x+i, y+j, z+k);
distance=MathHelper.abs(i)+MathHelper.abs(j)+MathHelper.abs(k);
}
}
k++;
}
k=-range;
j++;
}
j=-range;
i++;
}
return nearest;
}
public ArrayList findRiftsInRange(World world, int range, int x, int y, int z)
{
LinkData nearest=null;
ArrayList rifts = new ArrayList();
int i=-range;
int j=-range;
int k=-range;
DDProperties properties = DDProperties.instance();
while (i<range)
{
while (j<range)
{
while (k<range)
{
if(world.getBlockId(x+i, y+j, z+k)==properties.RiftBlockID)
{
if(MathHelper.abs(i)+MathHelper.abs(j)+MathHelper.abs(k)!=0)
{
nearest=this.findLinkAtCoords(x+i, y+j, z+k);
if(nearest!=null)
{
rifts.add(nearest);
}
}
}
k++;
}
k=-range;
j++;
}
j=-range;
i++;
}
return rifts;
}
public LinkData addLinkToDim(LinkData link)
{
if(this.linksInThisDim.containsKey(link.locZCoord))
{
this.dimY=this.linksInThisDim.get(link.locZCoord);
if(this.dimY.containsKey(link.locYCoord))
{
this.dimX=this.dimY.get(link.locYCoord);
}
else
{
this.dimX=new HashMap<Integer, LinkData>();
}
}
else
{
this.dimX=new HashMap<Integer, LinkData>();
this.dimY=new HashMap<Integer, HashMap<Integer, LinkData>>();
}
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);
}
else
{
this.dimX=new HashMap<Integer, LinkData>();
}
}
else
{
this.dimX=new HashMap<Integer, LinkData>();
this.dimY=new HashMap<Integer, HashMap<Integer, LinkData>>();
}
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))
{
this.dimX=this.dimY.get(locationYCoord);
if(this.dimX.containsKey(locationXCoord))
{
return this.dimX.get(locationXCoord);
}
}
}
}
catch(Exception E)
{
return null;
}
return null;
}
public ArrayList<LinkData> getLinksInDim()
{
//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<LinkData> links = new ArrayList<LinkData>();
if (this.linksInThisDim == null)
{
return links;
}
for (HashMap<Integer, HashMap<Integer, LinkData>> first : this.linksInThisDim.values())
{
for (HashMap<Integer, LinkData> second : first.values())
{
for (LinkData linkData : second.values())
{
links.add(linkData);
}
}
}
return links;
}
}

View File

@@ -0,0 +1,85 @@
package StevenDimDoors.mod_pocketDim;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack;
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType;
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
@Deprecated
public class DungeonGenerator implements Serializable
{
//This static field is hax so that I don't have to add an instance field to DungeonGenerator to support DungeonType.
//Otherwise it would have to be serializable and all sorts of problems would arise.
private static final HashMap<DungeonGenerator, DungeonType> dungeonTypes = new HashMap<DungeonGenerator, DungeonType>();
public int weight;
public String schematicPath;
public ArrayList<HashMap> sideRifts = new ArrayList<HashMap>();
public LinkData exitLink;
public boolean isOpen;
public int sideDoorsSoFar=0;
public int exitDoorsSoFar=0;
public int deadEndsSoFar=0;
public DungeonGenerator(int weight, String schematicPath, boolean isOpen, DungeonType dungeonType)
{
this.weight = weight;
this.schematicPath = schematicPath;
this.isOpen = isOpen;
dungeonTypes.put(this, dungeonType); //Hax...
}
public DungeonType getDungeonType()
{
DungeonType type = dungeonTypes.get(this);
if (type == null)
{
//Infer the dungeon's type from its file name
//There is minimal risk of us applying this to untagged dungeons and this'll be phased out
//when we get the new save format.
try
{
File file = new File(schematicPath);
String typeName = file.getName().split("_")[0];
String packName = file.getParentFile().getName();
DungeonPack pack = DungeonHelper.instance().getDungeonPack(packName);
if (pack == null)
{
pack = DungeonHelper.instance().getDungeonPack("ruins");
}
type = pack.getType(typeName);
}
catch (Exception e) { }
if (type == null)
{
type = DungeonType.UNKNOWN_TYPE;
}
dungeonTypes.put(this, type);
}
return type;
}
@Override
public int hashCode()
{
return (schematicPath != null) ? schematicPath.hashCode() : 0;
}
@Override
public boolean equals(Object other)
{
return equals((DungeonGenerator) other);
}
public boolean equals(DungeonGenerator other)
{
return ((this.schematicPath != null && this.schematicPath.equals(other.schematicPath)) ||
(this.schematicPath == other.schematicPath));
}
}

View File

@@ -0,0 +1,140 @@
package StevenDimDoors.mod_pocketDim;
import paulscode.sound.SoundSystem;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPool;
import net.minecraft.client.audio.SoundPoolEntry;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChunkCoordinates;
import net.minecraft.world.World;
import net.minecraftforge.client.event.sound.PlayBackgroundMusicEvent;
import net.minecraftforge.client.event.sound.SoundLoadEvent;
import net.minecraftforge.event.EventPriority;
import net.minecraftforge.event.ForgeSubscribe;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingFallEvent;
import net.minecraftforge.event.world.WorldEvent;
import StevenDimDoors.mod_pocketDim.core.DDTeleporter;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.ticking.RiftRegenerator;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.world.LimboProvider;
import StevenDimDoors.mod_pocketDim.world.PocketProvider;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class EventHookContainer
{
private final DDProperties properties;
public EventHookContainer(DDProperties properties)
{
this.properties = properties;
}
@SideOnly(Side.CLIENT)
@ForgeSubscribe
public void onSoundLoad(SoundLoadEvent event)
{
event.manager.addSound(mod_pocketDim.modid+":monk.ogg");
event.manager.addSound(mod_pocketDim.modid+":crack.ogg");
event.manager.addSound(mod_pocketDim.modid+":tearing.ogg");
event.manager.addSound(mod_pocketDim.modid+":rift.ogg");
event.manager.addSound(mod_pocketDim.modid+":riftStart.ogg");
event.manager.addSound(mod_pocketDim.modid+":riftEnd.ogg");
event.manager.addSound(mod_pocketDim.modid+":riftClose.ogg");
event.manager.addSound(mod_pocketDim.modid+":riftDoor.ogg");
event.manager.addMusic(mod_pocketDim.modid+":creepy.ogg");
}
@SideOnly(Side.CLIENT)
@ForgeSubscribe
public void onSoundEffectResult(PlayBackgroundMusicEvent event)
{
if (FMLClientHandler.instance().getClient().thePlayer.worldObj.provider.dimensionId==mod_pocketDim.properties.LimboDimensionID);
{
this.playMusicForDim(FMLClientHandler.instance().getClient().thePlayer.worldObj);
}
}
@ForgeSubscribe
public void onWorldLoad(WorldEvent.Load event)
{
// We need to initialize PocketManager here because onServerAboutToStart fires before we can
// use DimensionManager and onServerStarting fires after the game tries to generate terrain.
// If a gateway tries to generate before PocketManager has initialized, we get a crash.
if (!PocketManager.isLoaded())
{
PocketManager.load();
}
if (PocketManager.isLoaded())
{
RiftRegenerator.regenerateRiftsInAllWorlds();
}
this.playMusicForDim(event.world);
}
@ForgeSubscribe
public void onPlayerFall(LivingFallEvent event)
{
event.setCanceled(event.entity.worldObj.provider.dimensionId == properties.LimboDimensionID);
}
@ForgeSubscribe(priority=EventPriority.HIGHEST)
public boolean LivingDeathEvent(LivingDeathEvent event)
{
Entity entity = event.entity;
if (entity instanceof EntityPlayer && properties.LimboEnabled &&
entity.worldObj.provider instanceof PocketProvider)
{
EntityPlayer player = (EntityPlayer) entity;
if (!properties.LimboReturnsInventoryEnabled)
{
player.inventory.clearInventory(-1, -1);
}
ChunkCoordinates coords = LimboProvider.getLimboSkySpawn(player.worldObj.rand);
Point4D destination = new Point4D((int) (coords.posX+entity.posX), coords.posY, (int) (coords.posZ+entity.posZ ), mod_pocketDim.properties.LimboDimensionID);
DDTeleporter.teleportEntity(player, destination, false);
player.setHealth(player.getMaxHealth());
event.setCanceled(true);
return false;
}
return true;
}
@ForgeSubscribe
public void onWorldSave(WorldEvent.Save event)
{
if (event.world.provider.dimensionId == 0)
{
PocketManager.save();
}
}
public void playMusicForDim(World world)
{
if(world.isRemote)
{
SoundManager sndManager = FMLClientHandler.instance().getClient().sndManager;
if(world.provider instanceof LimboProvider)
{
sndManager.sndSystem.stop("BgMusic");
SoundPoolEntry soundPoolEntry = sndManager.soundPoolMusic.getRandomSoundFromSoundPool(mod_pocketDim.modid+":creepy");
if(soundPoolEntry!=null)
{
sndManager.sndSystem.backgroundMusic("LimboMusic", soundPoolEntry.getSoundUrl(), soundPoolEntry.getSoundName(), false);
sndManager.sndSystem.play("LimboMusic");
}
}
else if(!(world.provider instanceof LimboProvider))
{
sndManager.sndSystem.stop("LimboMusic");
}
}
}
}

View File

@@ -0,0 +1,8 @@
package StevenDimDoors.mod_pocketDim;
import net.minecraftforge.common.ForgeChunkManager.Ticket;
public interface IChunkLoader
{
public void forceChunkLoading(Ticket ticket,int x, int z);
}

View File

@@ -0,0 +1,68 @@
package StevenDimDoors.mod_pocketDim;
import java.io.Serializable;
@Deprecated
public class LinkData implements Serializable
{
public int locXCoord;
public int locYCoord;
public int locZCoord;
public int destXCoord;
public int destYCoord;
public int destZCoord;
public int numberofChildren;
public boolean isLocPocket;
public int linkOrientation;
public int destDimID;
public int locDimID;
public boolean exists=false;
public boolean hasGennedDoor=false;
static final long serialVersionUID = 45544342L;
public LinkData()
{
this.exists=false;
}
public LinkData(int exitLinkDimID, int exitX, int exitY, int exitZ)
{
this.destDimID=exitLinkDimID;
this.destXCoord=exitX;
this.destYCoord=exitY;
this.destZCoord=exitZ;
}
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.locXCoord=locationXCoord;
this.locYCoord=locationYCoord;
this.locZCoord=locationZCoord;
this.destXCoord=destinationXCoord;
this.destYCoord=destinationYCoord;
this.destZCoord=destinationZCoord;
this.destDimID=destinationDimID;
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.concat("\n"+ String.valueOf(this.destDimID)+"DestDimID "+String.valueOf(this.destXCoord)+":destXCoord "+String.valueOf(this.destYCoord)+":destYCoord "+String.valueOf(this.destZCoord)+":destZCoord ");
return linkInfo;
}
}

View File

@@ -0,0 +1,44 @@
package StevenDimDoors.mod_pocketDim;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.util.logging.Logger;
@SuppressWarnings("unused")
public class ObjectSaveInputStream extends ObjectInputStream {
// private static Logger logger = LoggerFactory.getLogger(ObjectSaveInputStream.class);
public ObjectSaveInputStream(InputStream in) throws IOException {
super(in);
}
@Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
ObjectStreamClass resultClassDescriptor = super.readClassDescriptor(); // initially streams descriptor
Class<?> localClass; // the class in the local JVM that this descriptor represents.
try {
localClass = Class.forName(resultClassDescriptor.getName());
} catch (ClassNotFoundException e) {
// logger.error("No local class for " + resultClassDescriptor.getName(), e);
return resultClassDescriptor;
}
ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass);
if (localClassDescriptor != null) { // only if class implements serializable
final long localSUID = localClassDescriptor.getSerialVersionUID();
final long streamSUID = resultClassDescriptor.getSerialVersionUID();
if (streamSUID != localSUID) { // check for serialVersionUID mismatch.
final StringBuffer s = new StringBuffer("Overriding serialized class version mismatch: ");
s.append("local serialVersionUID = ").append(localSUID);
s.append(" stream serialVersionUID = ").append(streamSUID);
Exception e = new InvalidClassException(s.toString());
// logger.error("Potentially Fatal Deserialization Operation.", e);
resultClassDescriptor = localClassDescriptor; // Use local class descriptor for deserialization
}
}
return resultClassDescriptor;
}
}

View File

@@ -0,0 +1,16 @@
package StevenDimDoors.mod_pocketDim;
public class PacketConstants
{
private PacketConstants() { }
public static final String CHANNEL_NAME = "DimDoorsPackets";
public static final byte CLIENT_JOIN_PACKET_ID = 1;
public static final byte CREATE_DIM_PACKET_ID = 2;
public static final byte DELETE_DIM_PACKET_ID = 3;
public static final byte CREATE_LINK_PACKET_ID = 4;
public static final byte DELETE_LINK_PACKET_ID = 5;
public static final byte CLIENT_LOGIN_DIM_REGISTER = 6;
}

View File

@@ -0,0 +1,126 @@
package StevenDimDoors.mod_pocketDim;
import java.io.Serializable;
import StevenDimDoors.mod_pocketDim.util.Point4D;
public class Point3D implements Serializable {
private static final long serialVersionUID = -9044026830605287190L;
private int x;
private int y;
private int z;
public Point3D(int x, int y,int z)
{
this.x = x;
this.y = y;
this.z = z;
}
public Point3D(Point4D point)
{
this.x = point.getX();
this.y = point.getY();
this.z = point.getZ();
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getZ()
{
return z;
}
public int setX(int x)
{
return this.x = x;
}
public int setY(int y)
{
return this.y = y;
}
public int setZ(int z)
{
return this.z = z;
}
@Override
public Point3D clone()
{
return new Point3D(x, y, z);
}
public int[] toIntArray()
{
return new int[]{x,y,z};
}
public boolean equals(Point3D other)
{
if (other == null)
return false;
if (this == other)
return true;
return (this.x == other.x && this.y == other.y && this.z == other.z);
}
@Override
public boolean equals(Object other)
{
return equals((Point3D) other);
}
@Override
public int hashCode()
{
//Time for some witchcraft.
//The code here is inspired by a discussion on Stack Overflow regarding hash codes for 3D.
//Source: http://stackoverflow.com/questions/9858376/hashcode-for-3d-integer-coordinates-with-high-spatial-coherence
//I believe that most of the time, any points we might be hashing will be in close proximity to each other.
//For instance, points that are within the same chunk or within a few neighboring chunks. Only the low-order
//bits of each component would differ. I'll use 8 bits from Y and the 12 bits from X and Z. ~SenseiKiwi
int bit;
int hash;
int index;
hash = 0;
index = 0;
for (bit = 0; bit < 8; bit++)
{
hash |= ((y >> bit) & 1) << index;
index++;
hash |= ((x >> bit) & 1) << index;
index++;
hash |= ((z >> bit) & 1) << index;
index++;
}
for (; bit < 12; bit++)
{
hash |= ((x >> bit) & 1) << index;
index++;
hash |= ((z >> bit) & 1) << index;
index++;
}
return hash;
}
@Override
public String toString()
{
return "(" + x + ", " + y + ", " + z + ")";
}
}

View File

@@ -0,0 +1,102 @@
package StevenDimDoors.mod_pocketDim;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.packet.Packet250CustomPayload;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.watcher.ClientDimData;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher;
import cpw.mods.fml.common.network.IPacketHandler;
import cpw.mods.fml.common.network.PacketDispatcher;
import cpw.mods.fml.common.network.Player;
public class ServerPacketHandler implements IPacketHandler
{
public ServerPacketHandler()
{
PocketManager.registerDimWatcher(new DimWatcher());
PocketManager.registerLinkWatcher(new LinkWatcher());
}
@Override
public void onPacketData(INetworkManager manager, Packet250CustomPayload packet, Player player) { }
private static class DimWatcher implements IUpdateWatcher<ClientDimData>
{
@Override
public void onCreated(ClientDimData message)
{
sendDimPacket(PacketConstants.CREATE_DIM_PACKET_ID, message);
}
@Override
public void onDeleted(ClientDimData message)
{
sendDimPacket(PacketConstants.DELETE_DIM_PACKET_ID, message);
}
}
private static class LinkWatcher implements IUpdateWatcher<ClientLinkData>
{
@Override
public void onCreated(ClientLinkData message)
{
sendLinkPacket(PacketConstants.CREATE_LINK_PACKET_ID, message);
}
@Override
public void onDeleted(ClientLinkData message)
{
sendLinkPacket(PacketConstants.DELETE_LINK_PACKET_ID, message);
}
}
private static void sendDimPacket(byte id, ClientDimData data)
{
try
{
Packet250CustomPayload packet = new Packet250CustomPayload();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream writer = new DataOutputStream(buffer);
writer.writeByte(id);
data.write(writer);
writer.close();
packet.channel = PacketConstants.CHANNEL_NAME;
packet.data = buffer.toByteArray();
packet.length = packet.data.length;
PacketDispatcher.sendPacketToAllPlayers(packet);
}
catch (IOException e)
{
//This shouldn't happen...
e.printStackTrace();
}
}
private static void sendLinkPacket(byte id, ClientLinkData message)
{
try
{
Packet250CustomPayload packet = new Packet250CustomPayload();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream writer = new DataOutputStream(buffer);
writer.writeByte(id);
message.write(writer);
writer.close();
packet.channel = PacketConstants.CHANNEL_NAME;
packet.data = buffer.toByteArray();
packet.length = packet.data.length;
PacketDispatcher.sendPacketToAllPlayers(packet);
}
catch (IOException e)
{
//This shouldn't happen...
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,137 @@
package StevenDimDoors.mod_pocketDim;
import java.util.List;
import java.util.Random;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.DamageSource;
public class Spells
{
public EntityPlayer player;
public int spellID;
public int castingTime=0;
public int fireCastTime=40;
public int smokeCastTime=5;
public int plagueCastTime=5;
public Random rand= new Random();
public int fireSpell=1;
public int smokeVanish=2;
public int enderPush=3;
public int flood=4;
public int nightVision=5;
public int heal = 6;
public int plague = 7;
public int butcher = 8;
public Spells(EntityPlayer player, int spellID)
{
this.spellID=spellID;
this.player=player;
}
public boolean cast()
{
this.castingTime++;
if(this.spellID==this.fireSpell)
{
return this.castFire();
}
if(this.spellID==this.smokeVanish)
{
return this.castSmoke();
}
return false;
}
public boolean castSmoke()
{
if(!this.player.isPotionActive(Potion.invisibility))
{
this.player.addPotionEffect(new PotionEffect(Potion.invisibility.id, 2 * 200, 200));
}
if(this.castingTime<this.smokeCastTime)
{
for(int i = 0; i<16;i++)
{
this.player.worldObj.spawnParticle("largesmoke", this.player.posX+this.rand.nextDouble()-.5, this.player.posY+(this.rand.nextDouble()-.5)*2, this.player.posZ+this.rand.nextDouble()-.5,
this.rand.nextGaussian()/50,this.rand.nextGaussian()/50,this.rand.nextGaussian()/50);
}
return true;
}
else return false;
}
public boolean castFire()
{
if(this.castingTime<this.fireCastTime)
{
for(int i = 0; i<50;i++)
{
this.player.worldObj.spawnParticle("flame", this.player.posX+this.rand.nextDouble()-.5, this.player.posY+this.rand.nextDouble()-.5, this.player.posZ+this.rand.nextDouble()-.5,
(this.rand.nextDouble()-.5)/3, (this.rand.nextDouble()-.5)/3, (this.rand.nextDouble()-.5/3));
this.player.worldObj.spawnParticle("flame", this.player.posX+this.rand.nextDouble()-.5, this.player.posY+this.rand.nextDouble()-.5, this.player.posZ+this.rand.nextDouble()-.5,
(this.rand.nextDouble()-.5), (this.rand.nextDouble()-.45)/2, (this.rand.nextDouble()-.5));
this.player.worldObj.spawnParticle("flame", this.player.posX+this.rand.nextDouble()-.5, this.player.posY+this.rand.nextDouble()-.5, this.player.posZ+this.rand.nextDouble()-.5,
(this.rand.nextDouble()-.5)/10, (this.rand.nextDouble()-.45)/20, (this.rand.nextDouble()-.5)/10);
this.player.worldObj.spawnParticle("flame", this.player.posX+this.rand.nextDouble()-.5, this.player.posY+this.rand.nextDouble()-.5, this.player.posZ+this.rand.nextDouble()-.5,
(this.rand.nextDouble()-.5)*2, (this.rand.nextDouble()-.45), (this.rand.nextDouble()-.5)*2);
}
}
List<Entity> list = player.worldObj.getEntitiesWithinAABBExcludingEntity(player,AxisAlignedBB.getBoundingBox( player.posX-7, player.posY-3, player.posZ-7, player.posX+7, player.posY+7, player.posZ+7));
for(Entity entity : list)
{
entity.setFire(3);
entity.attackEntityFrom(DamageSource.lava, 2);
}
return true;
}
/**
public boolean castEnderPush()
{
}
public boolean castFlood()
{
}
public boolean castNightVision()
{
}
public boolean castPlague()
{
}
**/
}

View File

@@ -0,0 +1,432 @@
package StevenDimDoors.mod_pocketDim.blocks;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Icon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.DDTeleporter;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.schematic.BlockRotator;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SuppressWarnings("deprecation")
public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEntityProvider
{
protected final DDProperties properties;
private Icon blockIconBottom;
public BaseDimDoor(int blockID, Material material, DDProperties properties)
{
super(blockID, material);
this.properties = properties;
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName()+"_top");
this.blockIconBottom = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName()+"_bottom");
}
@Override
@SideOnly(Side.CLIENT)
/**
* From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
*/
public Icon getIcon(int par1, int par2)
{
return this.blockIcon;
}
@Override
public void onEntityCollidedWithBlock(World world, int x, int y, int z, Entity entity)
{
this.enterDimDoor(world, x, y, z, entity);
}
@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, float hitY, float hitZ)
{
boolean shouldOpen=true;
//System.out.println(String.valueOf(par1World.getBlockMetadata(par2, par3, par4)));
if(player.inventory.getCurrentItem()!=null)
{
if(player.inventory.getCurrentItem().getItem() == mod_pocketDim.itemRiftBlade)
{
shouldOpen = false;
if (!world.isRemote && world.getBlockId(x, y-1, z) == this.blockID)
{
int var12 = MathHelper.floor_double((player.rotationYaw+90) * 4.0F / 360.0F + 0.5D) & 3;
if (world.getBlockMetadata(x, y-1, z) == var12)
{
var12 = BlockRotator.transformMetadata(var12, 1, this.blockID);
}
world.setBlockMetadataWithNotify(x, y-1, z, var12, 2);
}
if (!world.isRemote && world.getBlockId(x, y+1, z) == this.blockID)
{
int var12 = MathHelper.floor_double((player.rotationYaw+90) * 4.0F / 360.0F + 0.5D) & 3;
if(world.getBlockMetadata(x, y, z)==var12)
{
var12 = BlockRotator.transformMetadata(var12, 1, this.blockID);
}
world.setBlockMetadataWithNotify(x, y, z, var12, 2);
}
world.playAuxSFXAtEntity(player, 1001, x, y, z, 0);
if (!shouldOpen && !world.isRemote)
{
player.inventory.getCurrentItem().damageItem(5, player);
}
}
}
if(shouldOpen)
{
int var10 = this.getFullMetadata(world, x, y, z);
int var11 = var10 & 7;
var11 ^= 4;
if ((var10 & 8) == 0)
{
world.setBlockMetadataWithNotify(x, y, z, var11,2);
world.markBlockRangeForRenderUpdate(x, y, z, x, y, z);
}
else
{
world.setBlockMetadataWithNotify(x, y - 1, z, var11,2);
world.markBlockRangeForRenderUpdate(x, y - 1, z, x, y, z);
}
world.playAuxSFXAtEntity(player, 1003, x, y, z, 0);
return true;
}
else
{
return false;
}
}
@Override
public void onBlockAdded(World world, int x, int y, int z)
{
//FIXME: We need to set door generation flags on the tile entities. Ignoring that for now. ~SenseiKiwi
this.placeLink(world, x, y, z);
world.setBlockTileEntity(x, y, z, this.createNewTileEntity(world));
this.updateAttachedTile(world, x, y, z);
}
/**
* Retrieves the block texture to use based on the display side. Args: iBlockAccess, x, y, z, side
*/
@Override
@SideOnly(Side.CLIENT)
public Icon getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
{
if(par1IBlockAccess.getBlockId(par2, par3-1, par4) == this.blockID)
{
return this.blockIcon;
}
else
{
return blockIconBottom;
}
}
//Called to update the render information on the tile entity. Could probably implement a data watcher,
//but this works fine and is more versatile I think.
public BaseDimDoor updateAttachedTile(World world, int x, int y, int z)
{
TileEntity tile = world.getBlockTileEntity(x, y, z);
if (tile instanceof TileEntityDimDoor)
{
TileEntityDimDoor dimTile = (TileEntityDimDoor) tile;
dimTile.openOrClosed = PocketManager.getLink(x, y, z, world.provider.dimensionId) != null;
dimTile.orientation = this.getFullMetadata(world, x, y, z) & 7;
}
return this;
}
/**
* Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two
* adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
*/
@Override
public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
{
TileEntityDimDoor tile = (TileEntityDimDoor) par1World.getBlockTileEntity(par2, par3, par4);
tile.openOrClosed = this.isDoorOpen( par1World, par2, par3, par4);
tile.orientation = this.getFullMetadata(par1World, par2, par3, par4) & 7;
}
@Override
public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
{
this.setDoorRotation(this.getFullMetadata(par1IBlockAccess, par2, par3, par4));
}
public void setDoorRotation(int par1)
{
float var2 = 0.1875F;
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 2.0F, 1.0F);
int var3 = par1 & 3;
boolean var4 = (par1 & 4) != 0;
boolean var5 = (par1 & 16) != 0;
if (var3 == 0)
{
if (var4)
{
if (!var5)
{
this.setBlockBounds(0.001F, 0.0F, 0.0F, 1.0F, 1.0F, var2);
}
else
{
this.setBlockBounds(0.001F, 0.0F, 1.0F - var2, 1.0F, 1.0F, 1.0F);
}
}
else
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, var2, 1.0F, 1.0F);
}
}
else if (var3 == 1)
{
if (var4)
{
if (!var5)
{
this.setBlockBounds(1.0F - var2, 0.0F, 0.001F, 1.0F, 1.0F, 1.0F);
}
else
{
this.setBlockBounds(0.0F, 0.0F, 0.001F, var2, 1.0F, 1.0F);
}
}
else
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, var2);
}
}
else if (var3 == 2)
{
if (var4)
{
if (!var5)
{
this.setBlockBounds(0.0F, 0.0F, 1.0F - var2, .99F, 1.0F, 1.0F);
}
else
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, .99F, 1.0F, var2);
}
}
else
{
this.setBlockBounds(1.0F - var2, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
}
else if (var3 == 3)
{
if (var4)
{
if (!var5)
{
this.setBlockBounds(0.0F, 0.0F, 0.0F, var2, 1.0F, 0.99F);
}
else
{
this.setBlockBounds(1.0F - var2, 0.0F, 0.0F, 1.0F, 1.0F, 0.99F);
}
}
else
{
this.setBlockBounds(0.0F, 0.0F, 1.0F - var2, 1.0F, 1.0F, 1.0F);
}
}
}
/**
* Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
* their own) Args: x, y, z, neighbor blockID
*/
@Override
public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
{
int var6 = par1World.getBlockMetadata(par2, par3, par4);
if ((var6 & 8) == 0)
{
boolean var7 = false;
if (par1World.getBlockId(par2, par3 + 1, par4) != this.blockID)
{
par1World.setBlock(par2, par3, par4, 0);
var7 = true;
}
/**
if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4))
{
par1World.setBlockWithNotify(par2, par3, par4, 0);
var7 = true;
if (par1World.getBlockId(par2, par3 + 1, par4) == this.blockID)
{
par1World.setBlockWithNotify(par2, par3 + 1, par4, 0);
}
}
**/
if (var7)
{
if (!par1World.isRemote)
{
this.dropBlockAsItem(par1World, par2, par3, par4, properties.DimensionalDoorID, 0);
}
}
else
{
boolean var8 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4);
if ((var8 || par5 > 0 && Block.blocksList[par5].canProvidePower()) && par5 != this.blockID)
{
this.onPoweredBlockChange(par1World, par2, par3, par4, var8);
}
}
}
else
{
if (par1World.getBlockId(par2, par3 - 1, par4) != this.blockID)
{
par1World.setBlock(par2, par3, par4, 0);
}
if (par5 > 0 && par5 != this.blockID)
{
this.onNeighborBlockChange(par1World, par2, par3 - 1, par4, par5);
}
}
}
/**
* only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
*/
@Override
@SideOnly(Side.CLIENT)
public int idPicked(World par1World, int par2, int par3, int par4)
{
return this.getDrops();
}
@Override
public int idDropped(int par1, Random par2Random, int par3)
{
return (par1 & 8) != 0 ? 0 : (getDrops());
}
/**
* Called when the block is attempted to be harvested
*/
@Override
public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer)
{
if (par6EntityPlayer.capabilities.isCreativeMode && (par5 & 8) != 0 && par1World.getBlockId(par2, par3 - 1, par4) == this.blockID)
{
par1World.setBlock(par2, par3 - 1, par4, 0);
}
}
@Override
public TileEntity createNewTileEntity(World world)
{
return new TileEntityDimDoor();
}
@Override
public void enterDimDoor(World world, int x, int y, int z, Entity entity)
{
// FX entities dont exist on the server
if (world.isRemote)
{
return;
}
// Check that this is the top block of the door
if (world.getBlockId(x, y - 1, z) == this.blockID)
{
int metadata = world.getBlockMetadata(x, y - 1, z);
boolean canUse = isDoorOpen(metadata);
if (canUse && entity instanceof EntityPlayer)
{
// Dont check for non-player entites
canUse = isEntityFacingDoor(metadata, (EntityLivingBase) entity);
}
if (canUse)
{
// Teleport the entity through the link, if it exists
DimLink link = PocketManager.getLink(x, y, z, world.provider.dimensionId);
if (link != null)
{
DDTeleporter.traverseDimDoor(world, link, entity, this);
}
// Close the door only after the entity goes through
// so players don't have it slam in their faces.
this.onPoweredBlockChange(world, x, y, z, false);
}
}
else if (world.getBlockId(x, y + 1, z) == this.blockID)
{
enterDimDoor(world, x, y + 1, z, entity);
}
}
@Override
public int getDrops()
{
return this.blockID;
}
protected static boolean isDoorOpen(int metadata)
{
return (metadata & 4) != 0;
}
protected static boolean isEntityFacingDoor(int metadata, EntityLivingBase entity)
{
// Although any entity has the proper fields for this check,
// we should only apply it to living entities since things
// like Minecarts might come in backwards.
int direction = MathHelper.floor_double((entity.rotationYaw + 90) * 4.0F / 360.0F + 0.5D) & 3;
return ((metadata & 3) == direction);
}
}

View File

@@ -0,0 +1,142 @@
package StevenDimDoors.mod_pocketDim.blocks;
import java.util.List;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Icon;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class BlockDimWall extends Block
{
private static final float SUPER_HIGH_HARDNESS = 10000000000000F;
private static final float SUPER_EXPLOSION_RESISTANCE = 18000000F;
private Icon[] blockIcon = new Icon[2];
public BlockDimWall(int blockID, int j, Material par2Material)
{
super(blockID, Material.ground);
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
}
@Override
public float getBlockHardness(World world, int x, int y, int z)
{
if (world.getBlockMetadata(x, y, z) == 0)
{
return this.blockHardness;
}
else
{
return SUPER_HIGH_HARDNESS;
}
}
@Override
public float getExplosionResistance(Entity entity, World world, int x, int y, int z, double explosionX, double explosionY, double explosionZ)
{
if (world.getBlockMetadata(x, y, z) == 0)
{
return super.getExplosionResistance(entity, world, x, y, z, explosionX, explosionY, explosionZ);
}
else
{
return SUPER_EXPLOSION_RESISTANCE;
}
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon[0] = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName());
this.blockIcon[1] = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName() + "Perm");
}
@SideOnly(Side.CLIENT)
@Override
public Icon getIcon(int par1, int par2)
{
return (par2 != 1) ? blockIcon[0] : blockIcon[1];
}
@Override
public int damageDropped(int metadata)
{
//Return 0 to avoid dropping Ancient Fabric even if the player somehow manages to break it
return 0;
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
@SideOnly(Side.CLIENT)
public void getSubBlocks(int unknown, CreativeTabs tab, List subItems)
{
for (int ix = 0; ix < 2; ix++)
{
subItems.add(new ItemStack(this, 1, ix));
}
}
@Override
public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) {}
@Override
protected boolean canSilkHarvest()
{
return true;
}
@Override
public int quantityDropped(Random par1Random)
{
return 0;
}
/**
* replaces the block clicked with the held block, instead of placing the block on top of it. Shift click to disable.
*/
@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer entityPlayer, int par6, float par7, float par8, float par9)
{
//Check if the metadata value is 0 -- we don't want the user to replace Ancient Fabric
if (entityPlayer.getCurrentEquippedItem() != null && world.getBlockMetadata(x, y, z) == 0)
{
Item playerEquip = entityPlayer.getCurrentEquippedItem().getItem();
if (playerEquip instanceof ItemBlock)
{
// SenseiKiwi: Using getBlockID() rather than the raw itemID is critical.
// Some mods may override that function and use item IDs outside the range
// of the block list.
int blockID = ((ItemBlock) playerEquip).getBlockID();
Block block = Block.blocksList[blockID];
if (!Block.isNormalCube(blockID) || block instanceof BlockContainer || blockID == this.blockID)
{
return false;
}
if (!world.isRemote)
{
if (!entityPlayer.capabilities.isCreativeMode)
{
entityPlayer.getCurrentEquippedItem().stackSize--;
}
world.setBlock(x, y, z, entityPlayer.getCurrentEquippedItem().itemID, entityPlayer.getCurrentEquippedItem().getItemDamage(), 0);
}
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,100 @@
package StevenDimDoors.mod_pocketDim.blocks;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.DDTeleporter;
import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper;
import StevenDimDoors.mod_pocketDim.util.Point4D;
public class BlockDimWallPerm extends Block
{
private static final Random random = new Random();
private static DDProperties properties = null;
public BlockDimWallPerm(int i, int j, Material par2Material)
{
super(i, Material.ground);
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
if (properties == null)
properties = DDProperties.instance();
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName());
}
@Override
public int quantityDropped(Random par1Random)
{
return 0;
}
@Override
public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) {}
/**
* Only matters if the player is in limbo, acts to teleport the player from limbo back to dim 0
*/
@Override
public void onEntityWalking(World world, int x, int y, int z, Entity entity)
{
if (!world.isRemote && world.provider.dimensionId == properties.LimboDimensionID)
{
World overworld = DimensionManager.getWorld(0);
if (overworld != null && entity instanceof EntityPlayerMP)
{
EntityPlayer player = (EntityPlayer) entity;
player.fallDistance = 0;
int rangeLimit = properties.LimboReturnRange / 2;
int destinationX = x + MathHelper.getRandomIntegerInRange(random, -rangeLimit, rangeLimit);
int destinationZ = z + MathHelper.getRandomIntegerInRange(random, -rangeLimit, rangeLimit);
//make sure I am in the middle of a chunk, and not on a boundary, so it doesn't load the chunk next to me
destinationX = destinationX + (destinationX >> 4);
destinationZ = destinationZ + (destinationZ >> 4);
int destinationY = yCoordHelper.getFirstUncovered(overworld, destinationX, 63, destinationZ, true);
//FIXME: Shouldn't we make the player's destination safe BEFORE teleporting him?!
//player.setPositionAndUpdate( x, y, z );
Point4D destination = new Point4D(destinationX, destinationY, destinationZ, 0);
DDTeleporter.teleportEntity(player, destination, false);
//player.setPositionAndUpdate( x, y, z );
// Make absolutely sure the player doesn't spawn inside blocks, though to be honest this shouldn't ever have to be a problem...
overworld.setBlockToAir(destinationX, destinationY, destinationZ);
overworld.setBlockToAir(destinationX, destinationY + 1, destinationZ);
for (int xc = -3; xc < 4; xc++)
{
for (int zc = -3; zc < 4; zc++)
{
if (Math.abs(xc) + Math.abs(zc) < random.nextInt(3) + 2 ||
Math.abs(xc) + Math.abs(zc) < random.nextInt(3) + 3)
{
overworld.setBlock(destinationX + xc, destinationY - 1, destinationZ + zc, properties.LimboBlockID);
}
}
}
//FIXME: Why do we do this repeatedly? We also set the fall distance at the start...
player.setPositionAndUpdate( destinationX, destinationY, destinationZ );
player.fallDistance = 0;
}
}
}
}

View File

@@ -0,0 +1,61 @@
package StevenDimDoors.mod_pocketDim.blocks;
import java.util.Random;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.item.Item;
import net.minecraft.util.Icon;
import net.minecraft.world.IBlockAccess;
public class BlockDoorGold extends BlockDoor
{
private Icon blockIconBottom;
@SuppressWarnings("unused") // ??
private DDProperties properties;
public BlockDoorGold(int par1, Material par2Material,DDProperties properties)
{
super(par1, par2Material);
this.properties=properties;
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName()+"_top");
this.blockIconBottom = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName()+"_bottom");
}
public int idDropped(int par1, Random par2Random, int par3)
{
return mod_pocketDim.itemGoldDoor.itemID;
}
@Override
public Icon getIcon(int par1, int par2)
{
return this.blockIcon;
}
@Override
@SideOnly(Side.CLIENT)
public Icon getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
{
if(par1IBlockAccess.getBlockId(par2, par3-1, par4) == this.blockID)
{
return this.blockIcon;
}
else
{
return blockIconBottom;
}
}
}

View File

@@ -0,0 +1,50 @@
package StevenDimDoors.mod_pocketDim.blocks;
import StevenDimDoors.mod_pocketDim.DDProperties;
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.tileentities.TileEntityDimDoorGold;
import net.minecraft.block.material.Material;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
@SuppressWarnings("deprecation")
public class BlockGoldDimDoor extends BaseDimDoor
{
public BlockGoldDimDoor(int blockID, Material material,
DDProperties properties) {
super(blockID, material, properties);
}
@Override
public void placeLink(World world, int x, int y, int z)
{
if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID)
{
NewDimData dimension = PocketManager.getDimensionData(world);
DimLink link = dimension.getLink(x, y, z);
if (link == null)
{
dimension.createLink(x, y, z, LinkTypes.POCKET,world.getBlockMetadata(x, y - 1, z));
}
}
}
@Override
public int getDrops()
{
return mod_pocketDim.itemGoldDoor.itemID;
}
@Override
public TileEntity createNewTileEntity(World world)
{
return new TileEntityDimDoorGold();
}
}

View File

@@ -0,0 +1,64 @@
package StevenDimDoors.mod_pocketDim.blocks;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.util.Icon;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.ticking.LimboDecay;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class BlockLimbo extends Block
{
private final int limboDimensionID;
private final LimboDecay decay;
public BlockLimbo(int i, int j, Material par2Material, int limboDimensionID, LimboDecay decay)
{
super(i, Material.ground);
this.limboDimensionID = limboDimensionID;
this.decay = decay;
this.setTickRandomly(true);
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
}
/**
* Retrieves the block texture to use based on the display side. Args: iBlockAccess, x, y, z, side
*/
@SideOnly(Side.CLIENT)
@Override
public Icon getBlockTexture(IBlockAccess blockAccess, int x, int y, int z, int side)
{
return this.getIcon(side, blockAccess.getBlockMetadata(x, y, z));
}
@Override
public void registerIcons(IconRegister iconRegister)
{
this.blockIcon = iconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName());
}
@Override
public Icon getIcon(int par1, int par2)
{
return this.blockIcon;
}
/**
* If the block is in Limbo, attempt to decay surrounding blocks upon receiving a random update tick.
*/
@Override
public void updateTick(World world, int x, int y, int z, Random random)
{
//Make sure this block is in Limbo
if (world.provider.dimensionId == limboDimensionID)
{
decay.applySpreadDecay(world, x, y, z);
}
}
}

View File

@@ -0,0 +1,370 @@
package StevenDimDoors.mod_pocketDim.blocks;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift;
import StevenDimDoors.mod_pocketDimClient.ClosingRiftFX;
import StevenDimDoors.mod_pocketDimClient.GoggleRiftFX;
import StevenDimDoors.mod_pocketDimClient.RiftFX;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class BlockRift extends BlockContainer
{
private static final float MIN_IMMUNE_HARDNESS = 200.0F;
private static final int BLOCK_DESTRUCTION_RANGE = 4;
private static final int BLOCK_DESTRUCTION_VOLUME = (int) Math.pow(2 * BLOCK_DESTRUCTION_RANGE + 1, 3);
private static final int MAX_BLOCK_SEARCH_CHANCE = 100;
private static final int BLOCK_SEARCH_CHANCE = 50;
private static final int MAX_BLOCK_DESTRUCTION_CHANCE = 100;
private static final int BLOCK_DESTRUCTION_CHANCE = 50;
private final DDProperties properties;
private final ArrayList<Integer> blocksImmuneToRift;
public BlockRift(int i, int j, Material par2Material, DDProperties properties)
{
super(i, par2Material);
this.setTickRandomly(true);
this.properties = properties;
this.blocksImmuneToRift = new ArrayList<Integer>();
this.blocksImmuneToRift.add(properties.FabricBlockID);
this.blocksImmuneToRift.add(properties.PermaFabricBlockID);
this.blocksImmuneToRift.add(properties.DimensionalDoorID);
this.blocksImmuneToRift.add(properties.WarpDoorID);
this.blocksImmuneToRift.add(properties.TransTrapdoorID);
this.blocksImmuneToRift.add(properties.UnstableDoorID);
this.blocksImmuneToRift.add(properties.RiftBlockID);
this.blocksImmuneToRift.add(properties.TransientDoorID);
this.blocksImmuneToRift.add(properties.GoldDimDoorID);
this.blocksImmuneToRift.add(properties.GoldDoorID);
this.blocksImmuneToRift.add(Block.blockIron.blockID);
this.blocksImmuneToRift.add(Block.blockDiamond.blockID);
this.blocksImmuneToRift.add(Block.blockEmerald.blockID);
this.blocksImmuneToRift.add(Block.blockGold.blockID);
this.blocksImmuneToRift.add(Block.blockLapis.blockID);
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName());
}
//sends a packet informing the client that there is a link present so it renders properly. (when placed)
@Override
public void onBlockAdded(World par1World, int par2, int par3, int par4)
{
try
{
// PacketHandler.onLinkCreatedPacket(dimHelper.instance.getLinkDataFromCoords(par2, par3, par4, par1World));
}
catch(Exception e)
{
e.printStackTrace();
}
// this.updateTick(par1World, par2, par3, par4, new Random());
}
@Override
public boolean isCollidable()
{
return false;
}
@Override
public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) {}
@Override
public boolean isOpaqueCube()
{
return false;
}
/**
* Returns whether this block is collideable based on the arguments passed in Args: blockMetaData, unknownFlag
*/
@Override
public boolean canCollideCheck(int par1, boolean par2)
{
return par2;
}
/**
* Returns Returns true if the given side of this block type should be rendered (if it's solid or not), if the
* adjacent block is at the given coordinates. Args: blockAccess, x, y, z, side
*/
@Override
public boolean isBlockSolid(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
{
return true;
}
//this doesnt do anything yet.
@Override
public int getRenderType()
{
if(mod_pocketDim.isPlayerWearingGoogles)
{
return 0;
}
return 8;
}
/**
* Returns true if the given side of this block type should be rendered, if the adjacent block is at the given
* coordinates. Args: blockAccess, x, y, z, side
*/
@Override
@SideOnly(Side.CLIENT)
public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
{
return true;
}
/**
* Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
* cleared to be reused)
*/
@Override
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
{
return null;
}
//function that regulates how many blocks it eats/ how fast it eats them.
@Override
public void updateTick(World world, int x, int y, int z, Random random)
{
if (properties.RiftGriefingEnabled && !world.isRemote &&
PocketManager.getLink(x, y, z, world.provider.dimensionId) != null)
{
//Randomly decide whether to search for blocks to destroy. This reduces the frequency of search operations,
//moderates performance impact, and controls the apparent speed of block destruction.
if (random.nextInt(MAX_BLOCK_SEARCH_CHANCE) < BLOCK_SEARCH_CHANCE &&
((TileEntityRift) world.getBlockTileEntity(x, y, z)).isNearRift )
{
destroyNearbyBlocks(world, x, y, z, random);
}
}
}
private void destroyNearbyBlocks(World world, int x, int y, int z, Random random)
{
HashMap<Point3D, Integer> pointDistances = new HashMap<Point3D, Integer>(BLOCK_DESTRUCTION_VOLUME);
Queue<Point3D> points = new LinkedList<Point3D>();
//Perform a breadth-first search outwards from the point at which the rift is located. Record the distances
//of the points we visit to stop the search at its maximum range.
pointDistances.put(new Point3D(x, y, z), 0);
addAdjacentBlocks(x, y, z, 0, pointDistances, points);
while (!points.isEmpty())
{
Point3D current = points.remove();
int distance = pointDistances.get(current);
//If the current block is air, continue searching. Otherwise, try destroying the block.
if (world.isAirBlock(current.getX(), current.getY(), current.getZ()))
{
//Make sure we stay within the search range
if (distance < BLOCK_DESTRUCTION_RANGE)
{
addAdjacentBlocks(current.getX(), current.getY(), current.getZ(), distance, pointDistances, points);
}
}
else
{
//Check if the current block is immune to destruction by rifts. If not, randomly decide whether to destroy it.
//The randomness makes it so the destroyed area appears "noisy" if the rift is exposed to a large surface.
if (!isBlockImmune(world, current.getX(), current.getY(), current.getZ()) &&
random.nextInt(MAX_BLOCK_DESTRUCTION_CHANCE) < BLOCK_DESTRUCTION_CHANCE)
{
world.setBlockToAir(current.getX(), current.getY(), current.getZ());
}
}
}
}
private void addAdjacentBlocks(int x, int y, int z, int distance, HashMap<Point3D, Integer> pointDistances, Queue<Point3D> points)
{
Point3D[] neighbors = new Point3D[] {
new Point3D(x - 1, y, z),
new Point3D(x + 1, y, z),
new Point3D(x, y - 1, z),
new Point3D(x, y + 1, z),
new Point3D(x, y, z - 1),
new Point3D(x, y, z + 1)
};
for (int index = 0; index < neighbors.length; index++)
{
if (!pointDistances.containsKey(neighbors[index]))
{
pointDistances.put(neighbors[index], distance + 1);
points.add(neighbors[index]);
}
}
}
/**
* regulates the render effect, especially when multiple rifts start to link up. Has 3 main parts- Grows toward and away from nearest rft, bends toward it, and a randomization function
*/
@Override
@SideOnly(Side.CLIENT)
public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random rand)
{
int count;
//growth in the direction towards the nearby rift
float xGrowth=0;
float yGrowth=0;
float zGrowth=0;
//growth away from the nearby rift
float xGrowthn=0;
float yGrowthn=0;
float zGrowthn=0;
//how far the particles are away from original rift. Used to decrease noise the farther they are away.
float xChange = 0;
float yChange = 0;
float zChange = 0;
TileEntityRift tile = (TileEntityRift)par1World.getBlockTileEntity(par2, par3, par4);
float Xoffset=0;
float Yoffset=0;
float Zoffset=0;
for (count = 0; count < 12 && tile!=null; ++count)
{
//TODO change to a switch statement for clarity
if(tile.xOffset>0)
{
if(rand.nextInt(tile.xOffset)==0)
{
xGrowth =xGrowth+.15F*tile.xOffset;
}
}
else if(tile.xOffset<0)
{
if(rand.nextInt(-tile.xOffset)==0)
{
xGrowthn =xGrowthn-.15F*-tile.xOffset;
}
}
if(tile.yOffset>0)
{
if(rand.nextInt(tile.yOffset)==0)
{
yGrowth =yGrowth+.15F*tile.yOffset;
}
}
else if(tile.yOffset<0)
{
if(rand.nextInt(-tile.yOffset)==0)
{
yGrowthn =yGrowthn-.15F*-tile.yOffset;
}
}
if(tile.zOffset>0)
{
if(rand.nextInt(tile.zOffset)==0)
{
zGrowth =zGrowth+.15F*tile.zOffset;
}
}
else if(tile.zOffset<0)
{
if(rand.nextInt(-tile.zOffset)==0)
{
zGrowthn =zGrowthn-.15F*-tile.zOffset;
}
}
xChange=(float) ((xGrowth+xGrowthn)+rand.nextGaussian()*.05F);
yChange=(float) ((yGrowth+yGrowthn)+rand.nextGaussian()*.05F);
zChange=(float) ((zGrowth+zGrowthn)+rand.nextGaussian()*.05F);
Xoffset= ((0.25F/(1+Math.abs(xChange))));
Yoffset= ((0.25F/(1+Math.abs(yChange))));
Zoffset= ((0.25F/(1+Math.abs(zChange))));
FMLClientHandler.instance().getClient().effectRenderer.addEffect(new RiftFX(par1World,par2+.5+xChange+Xoffset*rand.nextGaussian(), par3+.5+yChange+Yoffset*rand.nextGaussian() , par4+.5+zChange+Zoffset*rand.nextGaussian(), rand.nextGaussian() * 0.001D, rand.nextGaussian() * 0.001D, rand.nextGaussian() * 0.001D, FMLClientHandler.instance().getClient().effectRenderer));
FMLClientHandler.instance().getClient().effectRenderer.addEffect(new RiftFX(par1World,par2+.5-xChange-Xoffset*rand.nextGaussian(), par3+.5-yChange-Yoffset*rand.nextGaussian() , par4+.5-zChange-Zoffset*rand.nextGaussian(), rand.nextGaussian() * 0.001D, rand.nextGaussian() * 0.001D, rand.nextGaussian() * 0.001D, FMLClientHandler.instance().getClient().effectRenderer));
if(rand.nextBoolean())
{
//renders an extra little blob on top of the actual rift location so its easier to find. Eventually will only render if the player has the goggles.
FMLClientHandler.instance().getClient().effectRenderer.addEffect(new GoggleRiftFX(par1World,par2+.5, par3+.5, par4+.5, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, FMLClientHandler.instance().getClient().effectRenderer));
}
if(tile.shouldClose)
{
//renders an opposite color effect if it is being closed by the rift remover
FMLClientHandler.instance().getClient().effectRenderer.addEffect(new ClosingRiftFX(par1World,par2+.5, par3+.5, par4+.5, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, FMLClientHandler.instance().getClient().effectRenderer));
}
}
}
public boolean isBlockImmune(World world, int x, int y, int z)
{
Block block = Block.blocksList[world.getBlockId(x, y, z)];
if (block != null)
{
float hardness = block.getBlockHardness(world, x, y, z);
return (hardness < 0 || hardness >= MIN_IMMUNE_HARDNESS || blocksImmuneToRift.contains(block.blockID));
}
return false;
}
@Override
public int idPicked(World par1World, int par2, int par3, int par4)
{
return 0;
}
@Override
public int idDropped(int par1, Random par2Random, int par3)
{
return 0;
}
@Override
public TileEntity createNewTileEntity(World var1)
{
return new TileEntityRift();
}
}

View File

@@ -0,0 +1,40 @@
package StevenDimDoors.mod_pocketDim.blocks;
import net.minecraft.block.material.Material;
import net.minecraft.item.Item;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
@SuppressWarnings("deprecation")
public class DimensionalDoor extends BaseDimDoor
{
public DimensionalDoor(int blockID, Material material, DDProperties properties)
{
super(blockID, material, properties);
}
@Override
public void placeLink(World world, int x, int y, int z)
{
if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID)
{
NewDimData dimension = PocketManager.getDimensionData(world);
DimLink link = dimension.getLink(x, y, z);
if (link == null)
{
dimension.createLink(x, y, z, LinkTypes.POCKET,world.getBlockMetadata(x, y - 1, z));
}
}
}
@Override
public int getDrops()
{
return Item.doorIron.itemID;
}
}

View File

@@ -0,0 +1,13 @@
package StevenDimDoors.mod_pocketDim.blocks;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
public interface IDimDoor
{
public void enterDimDoor(World world, int x, int y, int z, Entity entity);
public void placeLink(World world, int x, int y, int z);
public int getDrops();
}

View File

@@ -0,0 +1,121 @@
package StevenDimDoors.mod_pocketDim.blocks;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockTrapDoor;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.Entity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.DDTeleporter;
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.tileentities.TileEntityTransTrapdoor;
@SuppressWarnings("deprecation")
public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntityProvider
{
public TransTrapdoor(int blockID, Material material)
{
super(blockID, material);
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName());
}
//Teleports the player to the exit link of that dimension, assuming it is a pocket
@Override
public void onEntityCollidedWithBlock(World world, int x, int y, int z, Entity entity)
{
enterDimDoor(world, x, y, z, entity);
}
@Override
public void enterDimDoor(World world, int x, int y, int z, Entity entity)
{
if (!world.isRemote && isTrapdoorOpen(world.getBlockMetadata(x, y, z)))
{
this.onPoweredBlockChange(world, x, y, z, false);
DimLink link = PocketManager.getLink(x, y, z, world);
if (link != null)
{
DDTeleporter.traverseDimDoor(world, link, entity,this);
}
}
}
@Override
public void onBlockAdded(World world, int x, int y, int z)
{
this.placeLink(world, x, y, z);
world.setBlockTileEntity(x, y, z, this.createNewTileEntity(world));
this.updateAttachedTile(world, x, y, z);
}
@Override
public void updateTick(World world, int x, int y, int z, Random random)
{
TileEntityTransTrapdoor tile = (TileEntityTransTrapdoor) world.getBlockTileEntity(x, y, z);
tile.hasRift = PocketManager.getLink(x, y, z, world) != null;
}
@Override
public TileEntity createNewTileEntity(World world)
{
return new TileEntityTransTrapdoor();
}
public void updateAttachedTile(World world, int x, int y, int z)
{
TileEntity tile = world.getBlockTileEntity(x, y, z);
if (tile instanceof TileEntityTransTrapdoor)
{
TileEntityTransTrapdoor trapdoorTile = (TileEntityTransTrapdoor) tile;
trapdoorTile.hasRift = (PocketManager.getLink(x, y, z, world) != null);
}
}
@Override
public void placeLink(World world, int x, int y, int z)
{
if (!world.isRemote)
{
NewDimData dimension = PocketManager.getDimensionData(world);
DimLink link = dimension.getLink(x, y, z);
if (link == null && dimension.isPocketDimension())
{
dimension.createLink(x, y, z, LinkTypes.UNSAFE_EXIT,0);
}
}
}
@Override
public int idDropped(int metadata, Random random, int fortuneLevel)
{
return getDrops();
}
@Override
public int getDrops()
{
return Block.trapdoor.blockID;
}
public static boolean isTrapdoorSetLow(int metadata)
{
return (metadata & 8) == 0;
}
}

View File

@@ -0,0 +1,103 @@
package StevenDimDoors.mod_pocketDim.blocks;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.core.DDTeleporter;
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 net.minecraft.block.material.Material;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.World;
@SuppressWarnings("deprecation")
public class TransientDoor extends BaseDimDoor
{
public TransientDoor(int blockID, Material material, DDProperties properties)
{
super(blockID, material, properties);
}
@Override
public void enterDimDoor(World world, int x, int y, int z, Entity entity)
{
// We need to ignore particle entities
if (world.isRemote)
{
return;
}
// Check that this is the top block of the door
if (world.getBlockId(x, y - 1, z) == this.blockID)
{
boolean canUse = true;
int metadata = world.getBlockMetadata(x, y - 1, z);
if (canUse && entity instanceof EntityPlayer)
{
// Don't check for non-living entities since it might not work right
canUse = BaseDimDoor.isEntityFacingDoor(metadata, (EntityLivingBase) entity);
}
if (canUse)
{
// Teleport the entity through the link, if it exists
DimLink link = PocketManager.getLink(x, y, z, world.provider.dimensionId);
if (link != null)
{
DDTeleporter.traverseDimDoor(world, link, entity, this);
// Turn the door into a rift AFTER teleporting the player.
// The door's orientation may be necessary for the teleport.
world.setBlock(x, y, z, properties.RiftBlockID);
world.setBlockToAir(x, y - 1, z);
}
}
}
else if (world.getBlockId(x, y + 1, z) == this.blockID)
{
enterDimDoor(world, x, y + 1, z, entity);
}
}
@Override
public void placeLink(World world, int x, int y, int z)
{
if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID)
{
NewDimData dimension = PocketManager.getDimensionData(world);
DimLink link = dimension.getLink(x, y, z);
if (link == null && dimension.isPocketDimension())
{
dimension.createLink(x, y, z, LinkTypes.SAFE_EXIT,world.getBlockMetadata(x, y - 1, z));
}
}
}
@Override
public int getDrops()
{
return 0;
}
@Override
public boolean isCollidable()
{
return false;
}
@Override
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
{
return null;
}
@Override
public int getRenderType()
{
return 8;
}
}

View File

@@ -0,0 +1,32 @@
package StevenDimDoors.mod_pocketDim.blocks;
import net.minecraft.block.material.Material;
import net.minecraft.item.Item;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
public class UnstableDoor extends BaseDimDoor
{
public UnstableDoor(int blockID, Material material, DDProperties properties)
{
super(blockID, material, properties);
}
@Override
public void placeLink(World world, int x, int y, int z)
{
if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID)
{
NewDimData dimension = PocketManager.getDimensionData(world);
dimension.createLink(x, y, z, LinkTypes.RANDOM,world.getBlockMetadata(x, y - 1, z));
}
}
@Override
public int getDrops()
{
return Item.doorIron.itemID;
}
}

View File

@@ -0,0 +1,39 @@
package StevenDimDoors.mod_pocketDim.blocks;
import net.minecraft.block.material.Material;
import net.minecraft.item.Item;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
@SuppressWarnings("deprecation")
public class WarpDoor extends BaseDimDoor
{
public WarpDoor(int blockID, Material material, DDProperties properties)
{
super(blockID, material, properties);
}
@Override
public void placeLink(World world, int x, int y, int z)
{
if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID)
{
NewDimData dimension = PocketManager.getDimensionData(world);
DimLink link = dimension.getLink(x, y, z);
if (link == null && dimension.isPocketDimension())
{
dimension.createLink(x, y, z, LinkTypes.SAFE_EXIT,world.getBlockMetadata(x, y - 1, z));
}
}
}
@Override
public int getDrops()
{
return Item.doorWood.itemID;
}
}

View File

@@ -0,0 +1,140 @@
package StevenDimDoors.mod_pocketDim.commands;
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.helpers.DungeonHelper;
import StevenDimDoors.mod_pocketDim.world.PocketBuilder;
import java.util.Collection;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.MathHelper;
@SuppressWarnings("deprecation")
public class CommandCreateDungeonRift extends DDCommandBase
{
private static CommandCreateDungeonRift instance = null;
private CommandCreateDungeonRift()
{
super("dd-rift", "<dungeon name | 'list' | 'random'>");
}
public static CommandCreateDungeonRift instance()
{
if (instance == null)
instance = new CommandCreateDungeonRift();
return instance;
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "Usage: /dd-rift <dungeon name>\r\n" +
" /dd-rift list\r\n" +
" /dd-rift random";
}
@Override
protected DDCommandResult processCommand(EntityPlayer sender, String[] command)
{
NewDimData dimension;
DungeonHelper dungeonHelper = DungeonHelper.instance();
if (sender.worldObj.isRemote)
{
return DDCommandResult.SUCCESS;
}
if (command.length == 0)
{
return DDCommandResult.TOO_FEW_ARGUMENTS;
}
if (command.length > 1)
{
return DDCommandResult.TOO_MANY_ARGUMENTS;
}
if (command[0].equals("list"))
{
Collection<String> dungeonNames = dungeonHelper.getDungeonNames();
for (String name : dungeonNames)
{
sendChat(sender,(name));
}
sendChat(sender,(""));
}
else
{
DimLink link;
DungeonData result;
int x = MathHelper.floor_double(sender.posX);
int y = MathHelper.floor_double(sender.posY);
int z = MathHelper.floor_double (sender.posZ);
int orientation = MathHelper.floor_double((sender.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3;
if (command[0].equals("random"))
{
dimension = PocketManager.getDimensionData(sender.worldObj);
link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON,orientation);
sender.worldObj.setBlock(x, y + 1, z,mod_pocketDim.blockRift.blockID,0,3);
sendChat(sender,("Created a rift to a random dungeon."));
}
else
{
result = findDungeonByPartialName(command[0], dungeonHelper.getRegisteredDungeons());
if (result == null)
{
result = findDungeonByPartialName(command[0], dungeonHelper.getUntaggedDungeons());
}
//Check if we found any matches
if (result != null)
{
//Create a rift to our selected dungeon and notify the player
//TODO currently crashes, need to create the dimension first
dimension = PocketManager.getDimensionData(sender.worldObj);
link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON,orientation);
PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, result);
sender.worldObj.setBlock(x, y + 1, z,mod_pocketDim.blockRift.blockID,0,3);
sendChat(sender,("Created a rift to \"" + result.schematicName() + "\" dungeon (Dimension ID = " + link.destination().getDimension() + ")."));
}
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 DungeonData findDungeonByPartialName(String query, Collection<DungeonData> dungeons)
{
//Search for the shortest dungeon name that contains the lowercase query string.
String dungeonName;
String normalQuery = query.toLowerCase();
DungeonData bestMatch = null;
int matchLength = Integer.MAX_VALUE;
for (DungeonData 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 = dungeon.schematicName().toLowerCase();
if (dungeonName.length() < matchLength && dungeonName.contains(normalQuery))
{
matchLength = dungeonName.length();
bestMatch = dungeon;
}
}
return bestMatch;
}
}

View File

@@ -0,0 +1,54 @@
package StevenDimDoors.mod_pocketDim.commands;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
public class CommandCreatePocket extends DDCommandBase
{
private static CommandCreatePocket instance = null;
private CommandCreatePocket()
{
super("dd-create", "");
}
public static CommandCreatePocket instance()
{
if (instance == null)
instance = new CommandCreatePocket();
return instance;
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "Usage: /dd-create";
}
@Override
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 serve as a room for the player to build a dungeon.
int x = (int) sender.posX;
int y = (int) sender.posY;
int z = (int) sender.posZ;
DungeonHelper.instance().createCustomDungeonDoor(sender.worldObj, x, y, z);
//Notify the player
sendChat(sender,("Created a door to a pocket dimension. Please build your dungeon there."));
}
return DDCommandResult.SUCCESS;
}
}

View File

@@ -0,0 +1,74 @@
package StevenDimDoors.mod_pocketDim.commands;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import java.util.ArrayList;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
@SuppressWarnings("deprecation")
public class CommandDeleteAllLinks extends DDCommandBase
{
private static CommandDeleteAllLinks instance = null;
private CommandDeleteAllLinks()
{
super("dd-deletelinks", "???");
}
public static CommandDeleteAllLinks instance()
{
if (instance == null)
instance = new CommandDeleteAllLinks();
return instance;
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "Usage: /dd-deletelinks <targetDimensionID>";
}
@Override
protected DDCommandResult processCommand(EntityPlayer sender, String[] command)
{
int linksRemoved=0;
int targetDim;
boolean shouldGo= true;
if(command.length==1)
{
targetDim = parseInt(sender, command[0]);
}
else
{
targetDim=0;
shouldGo=false;
sendChat(sender, ("Error-Invalid argument, delete_all_links <targetDimID>"));
}
if(shouldGo)
{
NewDimData dim = PocketManager.getDimensionData(targetDim);
ArrayList<DimLink> linksInDim = dim.getAllLinks();
for (DimLink link : linksInDim)
{
World targetWorld = PocketManager.loadDimension(targetDim);
targetWorld.setBlock(link.source().getX(), link.source().getY(), link.source().getZ(), 0);
dim.deleteLink(link);
//TODO Probably should check what the block is, but thats annoying so Ill do it later.
linksRemoved++;
}
sendChat(sender,("Removed " + linksRemoved + " links."));
}
return DDCommandResult.SUCCESS; //TEMPORARY HACK
}
}

View File

@@ -0,0 +1,76 @@
package StevenDimDoors.mod_pocketDim.commands;
import java.util.ArrayList;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
@SuppressWarnings("deprecation")
public class CommandDeleteRifts extends DDCommandBase
{
private static CommandDeleteRifts instance = null;
private CommandDeleteRifts()
{
super("dd-???", "???");
}
public static CommandDeleteRifts instance()
{
if (instance == null)
instance = new CommandDeleteRifts();
return instance;
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "Usage: /dd-??? <dimension ID>";
}
@Override
protected DDCommandResult processCommand(EntityPlayer sender, String[] command)
{
int linksRemoved=0;
int targetDim;
boolean shouldGo= true;
if(command.length==1)
{
targetDim = parseInt(sender, command[0]);
}
else
{
targetDim=0;
shouldGo=false;
sendChat(sender,("Error-Invalid argument, delete_all_links <targetDimID>"));
}
if(shouldGo)
{
NewDimData dim = PocketManager.getDimensionData(targetDim);
ArrayList<DimLink> linksInDim = dim.getAllLinks();
for (DimLink link : linksInDim)
{
World targetWorld = PocketManager.loadDimension(targetDim);
if(sender.worldObj.getBlockId(link.source().getX(), link.source().getY(), link.source().getZ())==mod_pocketDim.blockRift.blockID)
{
targetWorld.setBlock(link.source().getX(), link.source().getY(), link.source().getZ(), 0);
linksRemoved++;
dim.deleteLink(link);
}
}
sendChat(sender,("Removed " + linksRemoved + " rifts."));
}
return DDCommandResult.SUCCESS; //TEMPORARY HACK
}
}

View File

@@ -0,0 +1,176 @@
package StevenDimDoors.mod_pocketDim.commands;
import java.io.File;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
public class CommandExportDungeon extends DDCommandBase
{
private static CommandExportDungeon instance = null;
private CommandExportDungeon()
{
super("dd-export", new String[] {
"<dungeon type> <dungeon name> <'open' | 'closed'> [weight]",
"<schematic name> override" } );
}
public static CommandExportDungeon instance()
{
if (instance == null)
instance = new CommandExportDungeon();
return instance;
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "Usage: /dd-export <dungeon type> <dungeon name> open <weight>\r\n" +
" /dd-export <dungeon type> <dungeon name> closed <weight>\r\n" +
" /dd-export <schematic name> override";
}
@Override
protected DDCommandResult processCommand(EntityPlayer sender, String[] command)
{
/*
* There are two versions of this command. One version takes 3 to 4 arguments consisting
* of the information needed for a proper schematic name.
*
* 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();
if (command.length < 2)
{
return DDCommandResult.TOO_FEW_ARGUMENTS;
}
if (command.length > 4)
{
return DDCommandResult.TOO_MANY_ARGUMENTS;
}
//Check if we received the 2-argument version
if (command.length == 2)
{
if (command[1].equalsIgnoreCase("override"))
{
//Check that the schematic name is a legal name
if (DungeonHelper.SCHEMATIC_NAME_PATTERN.matcher(command[0]).matches())
{
//Export the schematic
return exportDungeon(sender, command[0]);
}
else
{
//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
{
//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
//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
//during the save file format rewrite. ~SenseiKiwi
if (!dungeonHelper.validateDungeonType(command[0], dungeonHelper.getDungeonPack("ruins")))
{
return new DDCommandResult("Error: Invalid dungeon type. Please use one of the existing types.");
}
if (!DungeonHelper.DUNGEON_NAME_PATTERN.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 arguments, export the dungeon.
if (command.length == 3)
{
return exportDungeon(sender, join(command, "_", 0, 3));
}
else
{
//Validate the weight argument
try
{
int weight = Integer.parseInt(command[3]);
if (weight >= DungeonHelper.MIN_DUNGEON_WEIGHT && weight <= DungeonHelper.MAX_DUNGEON_WEIGHT)
{
return exportDungeon(sender, join(command, "_", 0, 4));
}
}
catch (Exception e) { }
}
//If we've reached this point, then we must have an invalid weight.
return new DDCommandResult("Invalid dungeon weight. Please specify a weight between "
+ DungeonHelper.MIN_DUNGEON_WEIGHT + " 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))
{
sendChat(player,("Saved dungeon schematic in " + exportPath));
dungeonHelper.registerDungeon(exportPath, dungeonHelper.getDungeonPack("ruins"), false, true);
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();
}
}

View File

@@ -0,0 +1,97 @@
package StevenDimDoors.mod_pocketDim.commands;
import java.util.ArrayList;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
@SuppressWarnings("deprecation")
public class CommandResetDungeons extends DDCommandBase
{
private static CommandResetDungeons instance = null;
private CommandResetDungeons()
{
super("dd-resetdungeons", "");
}
public static CommandResetDungeons instance()
{
if (instance == null)
instance = new CommandResetDungeons();
return instance;
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "/dd-resetdungeons";
}
@Override
protected DDCommandResult processCommand(EntityPlayer sender, String[] command)
{
if(sender.worldObj.isRemote)
{
return DDCommandResult.SUCCESS;
}
if (command.length > 0)
{
return DDCommandResult.TOO_FEW_ARGUMENTS;
}
int dungeonCount = 0;
int resetCount = 0;
ArrayList<Integer> dimsToDelete = new ArrayList<Integer>();
ArrayList<Integer> dimsToFix = new ArrayList<Integer>();
for (NewDimData data : PocketManager.getDimensions())
{
if(DimensionManager.getWorld(data.id())==null&&data.isDungeon())
{
resetCount++;
dungeonCount++;
dimsToDelete.add(data.id());
}
else if(data.isDungeon())
{
dimsToFix.add(data.id());
dungeonCount++;
for(DimLink link : data.links())
{
if(link.linkType()==LinkTypes.REVERSE)
{
data.createLink(link.source(), LinkTypes.DUNGEON_EXIT, link.orientation());
}
if(link.linkType()==LinkTypes.DUNGEON)
{
data.createLink(link.source(), LinkTypes.DUNGEON, link.orientation());
}
}
}
}
for(Integer dimID:dimsToDelete)
{
PocketManager.deletePocket(PocketManager.getDimensionData(dimID), true);
}
/**
* temporary workaround
*/
for(Integer dimID: dimsToFix)
{
PocketManager.getDimensionData(dimID).setParentToRoot();
}
//TODO- for some reason the parent field of loaded dimenions get reset to null if I call .setParentToRoot() before I delete the pockets.
//TODO implement blackList
//Notify the user of the results
sendChat(sender,("Reset complete. " + resetCount + " out of " + dungeonCount + " dungeons were reset."));
return DDCommandResult.SUCCESS;
}
}

View File

@@ -0,0 +1,95 @@
package StevenDimDoors.mod_pocketDim.commands;
import StevenDimDoors.mod_pocketDim.core.DDTeleporter;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import java.util.Arrays;
import java.util.List;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.common.DimensionManager;
public class CommandTeleportPlayer extends DDCommandBase
{
private static CommandTeleportPlayer instance = null;
private CommandTeleportPlayer()
{
super("dd-tp", new String[] {"<Player Name> <Dimension ID> <X Coord> <Y Coord> <Z Coord>"} );
}
public static CommandTeleportPlayer instance()
{
if (instance == null)
{
instance = new CommandTeleportPlayer();
}
return instance;
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "Usage: /dd-tp <player name> <dimension id> <x> <y> <z>";
}
/**
* TODO- Change to accept variety of input, like just coords, just dim ID, or two player names.
*/
@Override
protected DDCommandResult processCommand(EntityPlayer sender, String[] command)
{
List<Integer> dimensionIDs = Arrays.asList(DimensionManager.getStaticDimensionIDs()); //Gets list of all registered dimensions, regardless if loaded or not
EntityPlayer targetPlayer = sender;
int dimDestinationID = sender.worldObj.provider.dimensionId;
if(command.length == 5)
{
for(int i= 1; i <5;i++)
{
if(!isInteger(command[i]))
{
return DDCommandResult.INVALID_ARGUMENTS;
}
}
if(sender.worldObj.getPlayerEntityByName(command[0])!=null) //Gets the targeted player
{
targetPlayer = sender.worldObj.getPlayerEntityByName(command[0]);
}
else
{
return DDCommandResult.INVALID_ARGUMENTS;
}
dimDestinationID=Integer.parseInt(command[1]);//gets the target dim ID from the command string
if(!dimensionIDs.contains(dimDestinationID))
{
return DDCommandResult.INVALID_DIMENSION_ID;
}
PocketManager.loadDimension(dimDestinationID);
Point4D destination = new Point4D(Integer.parseInt(command[2]),Integer.parseInt(command[3]),Integer.parseInt(command[4]),dimDestinationID);
DDTeleporter.teleportEntity(targetPlayer, destination, false);
}
else
{
return DDCommandResult.INVALID_ARGUMENTS;
}
return DDCommandResult.SUCCESS;
}
public boolean isInteger( String input )
{
try
{
Integer.parseInt( input );
return true;
}
catch(Exception e )
{
return false;
}
}
}

View File

@@ -0,0 +1,83 @@
package StevenDimDoors.mod_pocketDim.commands;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatMessageComponent;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
/*
* An abstract base class for our Dimensional Doors commands. This cleans up the code a little and provides
* some convenience improvements.
*/
public abstract class DDCommandBase extends CommandBase
{
private String name;
private String[] formats;
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
* and returns a status code and message for the result of the operation.
*/
protected abstract DDCommandResult processCommand(EntityPlayer sender, String[] command);
@Override
public final String getCommandName()
{
return name;
}
/*
* Registers the command at server startup.
*/
public void register(FMLServerStartingEvent event)
{
event.registerServerCommand(this);
}
/*
* Method invoked by the server to execute a command. The call is forwarded to a derived class
* to provide the sending player directly.
*/
@Override
public final void processCommand(ICommandSender sender, String[] command)
{
//Forward the 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)
{
sendChat(player,("Usage: " + name + " " + format));
}
}
sendChat(player,(result.getMessage()));
}
}
public static void sendChat(EntityPlayer player, String message)
{
ChatMessageComponent cmp = new ChatMessageComponent();
cmp.addText(message);
player.sendChatToPlayer(cmp);
}
}

View File

@@ -0,0 +1,55 @@
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 DDCommandResult INVALID_ARGUMENTS = new DDCommandResult(5, "Error: Invalid arguments passed to the command.", true);
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;
}
}

View File

@@ -0,0 +1,700 @@
package StevenDimDoors.mod_pocketDim.core;
import java.util.ArrayList;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.item.EntityMinecart;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.packet.Packet41EntityEffect;
import net.minecraft.network.packet.Packet43Experience;
import net.minecraft.network.packet.Packet9Respawn;
import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper;
import StevenDimDoors.mod_pocketDim.items.BaseItemDoor;
import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor;
import StevenDimDoors.mod_pocketDim.schematic.BlockRotator;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.world.PocketBuilder;
import cpw.mods.fml.common.registry.GameRegistry;
@SuppressWarnings("deprecation")
public class DDTeleporter
{
private static final Random random = new Random();
private static final int END_DIMENSION_ID = 1;
private static final int MAX_ROOT_SHIFT_CHANCE = 100;
private static final int START_ROOT_SHIFT_CHANCE = 0;
private static final int ROOT_SHIFT_CHANCE_PER_LEVEL = 5;
public static int cooldown = 0;
private DDTeleporter() { }
/**Checks if the destination supplied is valid, ie, filled by any non-replaceable block.
*
* @param entity
* @param world
* @param destination
* @param properties
* @return
*/
public static boolean CheckDestination(Entity entity, WorldServer world, Point4D destination,DDProperties properties)
{
int x = destination.getX();
int y = destination.getY();
int z = destination.getZ();
int blockIDTop;
int blockIDBottom;
Point3D point;
int orientation;
orientation = getDestinationOrientation(destination, properties);
entity.rotationYaw = (orientation * 90) + 90;
switch (orientation)
{
case 0:
point= new Point3D(MathHelper.floor_double(x - 0.5), y - 1, MathHelper.floor_double(z + 0.5));
break;
case 1:
point= new Point3D(MathHelper.floor_double(x + 0.5), y - 1, MathHelper.floor_double(z - 0.5));
break;
case 2:
point = new Point3D(MathHelper.floor_double(x + 1.5), y - 1, MathHelper.floor_double(z + 0.5));
break;
case 3:
point = new Point3D(MathHelper.floor_double(x + 0.5), y - 1, MathHelper.floor_double(z + 1.5));
break;
default:
point = new Point3D(x, y - 1, z);
break;
}
blockIDBottom = world.getBlockId(point.getX(), point.getY(), point.getZ());
blockIDTop = world.getBlockId(point.getX(), point.getY()+1, point.getZ());
if(!(Block.blocksList[blockIDBottom]==null))
{
if(!Block.blocksList[blockIDBottom].isBlockReplaceable(world, point.getX(), point.getY(), point.getZ()))
{
return false;
}
}
if(!(Block.blocksList[blockIDTop]==null))
{
if(!Block.blocksList[blockIDTop].isBlockReplaceable(world, point.getX(), point.getY()+1, point.getZ()))
{
return false;
}
}
return true;
}
private static void placeInPortal(Entity entity, WorldServer world, Point4D destination, DDProperties properties, boolean checkOrientation)
{
int x = destination.getX();
int y = destination.getY();
int z = destination.getZ();
int orientation;
if (checkOrientation)
{
orientation = getDestinationOrientation(destination, properties);
entity.rotationYaw = (orientation * 90) + 90;
}
else
{
//Teleport the entity to the precise destination point
orientation = -1;
}
if(!CheckDestination(entity, world, destination, properties))
{
if(entity instanceof EntityPlayerMP)
{
EntityPlayer player = (EntityPlayer) entity;
player.rotationYaw=(orientation * 90)+90;
switch (orientation)
{
case 0:
player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5);
break;
case 1:
player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5);
break;
case 2:
player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5);
break;
case 3:
player.setPositionAndUpdate(x + 0.5, y - 1, z + .5);
break;
default:
player.setPositionAndUpdate(x, y - 1, z);
break;
}
}
}
if (entity instanceof EntityPlayer)
{
EntityPlayer player = (EntityPlayer) entity;
switch (orientation)
{
case 0:
player.setPositionAndUpdate(x - 0.5, y - 1, z + 0.5);
break;
case 1:
player.setPositionAndUpdate(x + 0.5, y - 1, z - 0.5);
break;
case 2:
player.setPositionAndUpdate(x + 1.5, y - 1, z + 0.5);
break;
case 3:
player.setPositionAndUpdate(x + 0.5, y - 1, z + 1.5);
break;
default:
player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5);
break;
}
}
else if (entity instanceof EntityMinecart)
{
entity.motionX = 0;
entity.motionZ = 0;
entity.motionY = 0;
switch (orientation)
{
case 0:
DDTeleporter.setEntityPosition(entity, x - 0.5, y, z + 0.5);
entity.motionX = -0.39;
entity.worldObj.updateEntityWithOptionalForce(entity, false);
break;
case 1:
DDTeleporter.setEntityPosition(entity, x + 0.5, y, z - 0.5);
entity.motionZ = -0.39;
entity.worldObj.updateEntityWithOptionalForce(entity, false);
break;
case 2:
DDTeleporter.setEntityPosition(entity, x + 1.5, y, z + 0.5);
entity.motionX = 0.39;
entity.worldObj.updateEntityWithOptionalForce(entity, false);
break;
case 3:
DDTeleporter.setEntityPosition(entity, x + 0.5, y, z + 1.5 );
entity.motionZ = 0.39;
entity.worldObj.updateEntityWithOptionalForce(entity, false);
break;
default:
DDTeleporter.setEntityPosition(entity, x + 0.5, y, z + 0.5);
entity.worldObj.updateEntityWithOptionalForce(entity, false);
break;
}
}
else
{
switch (orientation)
{
case 0:
setEntityPosition(entity, x - 0.5, y, z + 0.5);
break;
case 1:
setEntityPosition(entity, x + 0.5, y, z - 0.5);
break;
case 2:
setEntityPosition(entity, x + 1.5, y, z + 0.5);
break;
case 3:
setEntityPosition(entity, x + 0.5, y, z + 1.5);
break;
default:
setEntityPosition(entity, x + 0.5, y, z + 0.5);
break;
}
}
}
private static void setEntityPosition(Entity entity, double x, double y, double z)
{
entity.lastTickPosX = entity.prevPosX = entity.posX = x;
entity.lastTickPosY = entity.prevPosY = entity.posY = y + entity.yOffset;
entity.lastTickPosZ = entity.prevPosZ = entity.posZ = z;
entity.setPosition(x, y, z);
}
private static int getDestinationOrientation(Point4D door, DDProperties properties)
{
World world = DimensionManager.getWorld(door.getDimension());
if (world == null)
{
throw new IllegalStateException("The destination world should be loaded!");
}
//Check if the block below that point is actually a door
int blockID = world.getBlockId(door.getX(), door.getY() - 1, door.getZ());
if (blockID != properties.DimensionalDoorID && blockID != properties.WarpDoorID &&
blockID != properties.TransientDoorID && blockID != properties.UnstableDoorID
&& blockID != properties.GoldDimDoorID)
{
//Return the pocket's orientation instead
return PocketManager.getDimensionData(door.getDimension()).orientation();
}
//Return the orientation portion of its metadata
return world.getBlockMetadata(door.getX(), door.getY() - 1, door.getZ()) & 3;
}
public static Entity teleportEntity(Entity entity, Point4D destination, boolean checkOrientation)
{
if (entity == null)
{
throw new IllegalArgumentException("entity cannot be null.");
}
if (destination == null)
{
throw new IllegalArgumentException("destination cannot be null.");
}
//This beautiful teleport method is based off of xCompWiz's teleport function.
WorldServer oldWorld = (WorldServer) entity.worldObj;
WorldServer newWorld;
EntityPlayerMP player = (entity instanceof EntityPlayerMP) ? (EntityPlayerMP) entity : null;
DDProperties properties = DDProperties.instance();
// Is something riding? Handle it first.
if (entity.riddenByEntity != null)
{
return teleportEntity(entity.riddenByEntity, destination, checkOrientation);
}
// Are we riding something? Dismount and tell the mount to go first.
Entity cart = entity.ridingEntity;
if (cart != null)
{
entity.mountEntity(null);
cart = teleportEntity(cart, destination, checkOrientation);
// We keep track of both so we can remount them on the other side.
}
// Determine if our destination is in another realm.
boolean difDest = entity.dimension != destination.getDimension();
if (difDest)
{
// Destination isn't loaded? Then we need to load it.
newWorld = PocketManager.loadDimension(destination.getDimension());
}
else
{
newWorld = oldWorld;
}
// GreyMaria: What is this even accomplishing? We're doing the exact same thing at the end of this all.
// TODO Check to see if this is actually vital.
DDTeleporter.placeInPortal(entity, newWorld, destination, properties, checkOrientation);
if (difDest) // Are we moving our target to a new dimension?
{
if(player != null) // Are we working with a player?
{
// We need to do all this special stuff to move a player between dimensions.
// Set the new dimension and inform the client that it's moving to a new world.
player.dimension = destination.getDimension();
player.playerNetServerHandler.sendPacketToPlayer(new Packet9Respawn(player.dimension, (byte)player.worldObj.difficultySetting, newWorld.getWorldInfo().getTerrainType(), newWorld.getHeight(), player.theItemInWorldManager.getGameType()));
// GreyMaria: Used the safe player entity remover before.
// This should fix an apparently unreported bug where
// the last non-sleeping player leaves the Overworld
// for a pocket dimension, causing all sleeping players
// to remain asleep instead of progressing to day.
((WorldServer)entity.worldObj).getPlayerManager().removePlayer(player);
oldWorld.removePlayerEntityDangerously(player);
player.isDead = false;
// Creates sanity by ensuring that we're only known to exist where we're supposed to be known to exist.
oldWorld.getPlayerManager().removePlayer(player);
newWorld.getPlayerManager().addPlayer(player);
player.theItemInWorldManager.setWorld(newWorld);
// Synchronize with the server so the client knows what time it is and what it's holding.
player.mcServer.getConfigurationManager().updateTimeAndWeatherForPlayer(player, newWorld);
player.mcServer.getConfigurationManager().syncPlayerInventory(player);
for(Object potionEffect : player.getActivePotionEffects())
{
PotionEffect effect = (PotionEffect)potionEffect;
player.playerNetServerHandler.sendPacketToPlayer(new Packet41EntityEffect(player.entityId, effect));
}
player.playerNetServerHandler.sendPacketToPlayer(new Packet43Experience(player.experience, player.experienceTotal, player.experienceLevel));
}
// Creates sanity by removing the entity from its old location's chunk entity list, if applicable.
int entX = entity.chunkCoordX;
int entZ = entity.chunkCoordZ;
if ((entity.addedToChunk) && (oldWorld.getChunkProvider().chunkExists(entX, entZ)))
{
oldWorld.getChunkFromChunkCoords(entX, entZ).removeEntity(entity);
oldWorld.getChunkFromChunkCoords(entX, entZ).isModified = true;
}
// Memory concerns.
oldWorld.onEntityRemoved(entity);
if (player == null) // Are we NOT working with a player?
{
NBTTagCompound entityNBT = new NBTTagCompound();
entity.isDead = false;
entity.writeMountToNBT(entityNBT);
entity.isDead = true;
entity = EntityList.createEntityFromNBT(entityNBT, newWorld);
if (entity == null)
{
// TODO FIXME IMPLEMENT NULL CHECKS THAT ACTUALLY DO SOMETHING.
/*
* shit ourselves in an organized fashion, preferably
* in a neat pile instead of all over our users' games
*/
}
}
// Finally, respawn the entity in its new home.
newWorld.spawnEntityInWorld(entity);
entity.setWorld(newWorld);
}
entity.worldObj.updateEntityWithOptionalForce(entity, false);
// Hey, remember me? It's time to remount.
if (cart != null)
{
// Was there a player teleported? If there was, it's important that we update shit.
if (player != null)
{
entity.worldObj.updateEntityWithOptionalForce(entity, true);
}
entity.mountEntity(cart);
}
// Did we teleport a player? Load the chunk for them.
if (player != null)
{
newWorld.getChunkProvider().loadChunk(MathHelper.floor_double(entity.posX) >> 4, MathHelper.floor_double(entity.posZ) >> 4);
// Tell Forge we're moving its players so everyone else knows.
// Let's try doing this down here in case this is what's killing NEI.
GameRegistry.onPlayerChangedDimension((EntityPlayer)entity);
}
DDTeleporter.placeInPortal(entity, newWorld, destination, properties, checkOrientation);
return entity;
}
/**
* Primary function used to teleport the player using doors. Performs numerous null checks, and also generates the destination door/pocket if it has not done so already.
* Also ensures correct orientation relative to the door.
* @param world - world the player is currently in
* @param link - the link the player is using to teleport; sends the player to its destination
* @param player - the instance of the player to be teleported
*/
public static void traverseDimDoor(World world, DimLink link, Entity entity, Block door)
{
if (world == null)
{
throw new IllegalArgumentException("world cannot be null.");
}
if (link == null)
{
throw new IllegalArgumentException("link cannot be null.");
}
if (entity == null)
{
throw new IllegalArgumentException("entity cannot be null.");
}
if (world.isRemote)
{
return;
}
if (cooldown == 0 || entity instanceof EntityPlayer)
{
cooldown = 2 + random.nextInt(2);
}
else
{
return;
}
if (!initializeDestination(link, DDProperties.instance(),door))
{
return;
}
if (link.linkType() == LinkTypes.RANDOM)
{
Point4D randomDestination = getRandomDestination();
if (randomDestination != null)
{
entity = teleportEntity(entity, randomDestination, true);
entity.worldObj.playSoundEffect(entity.posX, entity.posY, entity.posZ, "mob.endermen.portal", 1.0F, 1.0F);
}
}
else
{
buildExitDoor(door, link, DDProperties.instance());
entity = teleportEntity(entity, link.destination(), link.linkType() != LinkTypes.UNSAFE_EXIT);
entity.worldObj.playSoundEffect(entity.posX, entity.posY, entity.posZ, "mob.endermen.portal", 1.0F, 1.0F);
}
}
private static boolean initializeDestination(DimLink link, DDProperties properties, Block door)
{
if (link.hasDestination())
{
if(PocketManager.isBlackListed(link.destination().getDimension()))
{
link=PocketManager.getDimensionData(link.source().getDimension()).createLink(link.link.point,LinkTypes.SAFE_EXIT,link.link.orientation);
}
else
{
return true;
}
}
// Check the destination type and respond accordingly
switch (link.linkType())
{
case LinkTypes.DUNGEON:
return PocketBuilder.generateNewDungeonPocket(link, properties);
case LinkTypes.POCKET:
return PocketBuilder.generateNewPocket(link, properties,door);
case LinkTypes.SAFE_EXIT:
return generateSafeExit(link, properties);
case LinkTypes.DUNGEON_EXIT:
return generateDungeonExit(link, properties);
case LinkTypes.UNSAFE_EXIT:
return generateUnsafeExit(link);
case LinkTypes.NORMAL:
case LinkTypes.REVERSE:
case LinkTypes.RANDOM:
return true;
default:
throw new IllegalArgumentException("link has an unrecognized link type.");
}
}
private static Point4D getRandomDestination()
{
// Our aim is to return a random link's source point
// so that a link of type RANDOM can teleport a player there.
// Restrictions:
// 1. Ignore links with their source inside a pocket dimension.
// 2. Ignore links with link type RANDOM.
// Iterate over the root dimensions. Pocket dimensions cannot be roots.
// Don't just pick a random root and a random link within that root
// because we want to have unbiased selection among all links.
ArrayList<Point4D> matches = new ArrayList<Point4D>();
for (NewDimData dimension : PocketManager.getRootDimensions())
{
for (DimLink link : dimension.getAllLinks())
{
if (link.linkType() != LinkTypes.RANDOM)
{
matches.add(link.source());
}
}
}
// Pick a random point, if any is available
if (!matches.isEmpty())
{
return matches.get( random.nextInt(matches.size()) );
}
else
{
return null;
}
}
private static boolean generateUnsafeExit(DimLink link)
{
// An unsafe exit teleports the user to the first available air space
// in the pocket's root dimension. X and Z are kept roughly the same
// as the source location, but Y is set by searching down. We don't
// place a platform at the destination. We also don't place a reverse
// link at the destination, so it's a one-way trip. Good luck!
// To avoid loops, don't generate a destination if the player is
// already in a non-pocket dimension.
NewDimData current = PocketManager.getDimensionData(link.link.point.getDimension());
if (current.isPocketDimension())
{
Point4D source = link.source();
World world = PocketManager.loadDimension(current.root().id());
if (world == null)
{
return false;
}
Point3D destination = yCoordHelper.findDropPoint(world, source.getX(), source.getY() + 1, source.getZ());
if (destination != null)
{
current.root().setDestination(link, destination.getX(), destination.getY(), destination.getZ());
return true;
}
}
return false;
}
private static void buildExitDoor(Block door,DimLink link, DDProperties prop)
{
World startWorld = PocketManager.loadDimension(link.source().getDimension());
World destWorld = PocketManager.loadDimension(link.destination().getDimension());
TileEntity doorTE = startWorld.getBlockTileEntity(link.source().getX(), link.source().getY(), link.link.point.getZ());
if(doorTE instanceof TileEntityDimDoor)
{
if((TileEntityDimDoor.class.cast(doorTE).hasGennedPair))
{
return;
}
TileEntityDimDoor.class.cast(doorTE).hasGennedPair=true;
Block blockToReplace = Block.blocksList[destWorld.getBlockId(link.destination().getX(), link.destination().getY(), link.destination().getZ())];
if(!destWorld.isAirBlock(link.destination().getX(), link.destination().getY(), link.destination().getZ()))
{
if(!blockToReplace.isBlockReplaceable(destWorld, link.destination().getX(), link.destination().getY(), link.destination().getZ()))
{
return;
}
}
BaseItemDoor.placeDoorBlock(destWorld, link.destination().getX(), link.destination().getY()-1, link.destination().getZ(),link.getDestinationOrientation(), door);
TileEntity doorDestTE = startWorld.getBlockTileEntity(link.destination().getX(), link.destination().getY(), link.destination().getZ());
if(doorDestTE instanceof TileEntityDimDoor)
{
TileEntityDimDoor.class.cast(doorDestTE).hasGennedPair=true;
}
}
}
private static boolean generateSafeExit(DimLink link, DDProperties properties)
{
NewDimData current = PocketManager.getDimensionData(link.link.point.getDimension());
return generateSafeExit(current.root(), link, properties);
}
private static boolean generateDungeonExit(DimLink link, DDProperties properties)
{
// A dungeon exit acts the same as a safe exit, but has the chance of
// taking the user to any non-pocket dimension, excluding Limbo and The End.
NewDimData current = PocketManager.getDimensionData(link.link.point.getDimension());
ArrayList<NewDimData> roots = PocketManager.getRootDimensions();
int shiftChance = START_ROOT_SHIFT_CHANCE + ROOT_SHIFT_CHANCE_PER_LEVEL * (current.packDepth() - 1);
if (random.nextInt(MAX_ROOT_SHIFT_CHANCE) < shiftChance)
{
for (int attempts = 0; attempts < 10; attempts++)
{
NewDimData selection = roots.get( random.nextInt(roots.size()) );
if (selection.id() != END_DIMENSION_ID &&
selection.id() != properties.LimboDimensionID &&
selection != current.root())
{
return generateSafeExit(selection, link, properties);
}
}
}
// Yes, this could lead you back into Limbo. That's intentional.
return generateSafeExit(current.root(), link, properties);
}
private static boolean generateSafeExit(NewDimData destinationDim, DimLink link, DDProperties properties)
{
// A safe exit attempts to place a Warp Door in a dimension with
// some precautions to protect the player. The X and Z coordinates
// are fixed to match the source (mostly - may be shifted a little),
// but the Y coordinate is chosen by searching for the nearest
// a safe location to place the door.
Point4D source = link.source();
World world = PocketManager.loadDimension(destinationDim.id());
if (world == null)
{
return false;
}
int startY = source.getY() - 2;
Point3D destination;
Point3D locationUp = yCoordHelper.findSafeCubeUp(world, source.getX(), startY, source.getZ());
Point3D locationDown = yCoordHelper.findSafeCubeDown(world, source.getX(), startY, source.getZ());
if (locationUp == null)
{
destination = locationDown;
}
else if (locationDown == null)
{
destination = locationUp;
}
else if (locationUp.getY() - startY <= startY - locationDown.getY())
{
destination = locationUp;
}
else
{
destination = locationDown;
}
if (destination != null)
{
// Set up a 3x3 platform at the destination
int x = destination.getX();
int y = destination.getY();
int z = destination.getZ();
for (int dx = -1; dx <= 1; dx++)
{
for (int dz = -1; dz <= 1; dz++)
{
world.setBlock(x + dx, y, z + dz, properties.FabricBlockID);
}
}
// Create a reverse link for returning
int orientation = getDestinationOrientation(source, properties);
NewDimData sourceDim = PocketManager.getDimensionData(link.source().getDimension());
DimLink reverse = destinationDim.createLink(x, y + 2, z, LinkTypes.REVERSE,orientation);
sourceDim.setDestination(reverse, source.getX(), source.getY(), source.getZ());
// Set up the warp door at the destination
orientation = BlockRotator.transformMetadata(orientation, 2, properties.WarpDoorID);
ItemDimensionalDoor.placeDoorBlock(world, x, y + 1, z, orientation, mod_pocketDim.warpDoor);
// Complete the link to the destination
// This comes last so the destination isn't set unless everything else works first
destinationDim.setDestination(link, x, y + 2, z);
}
return (destination != null);
}
}

View File

@@ -0,0 +1,96 @@
package StevenDimDoors.mod_pocketDim.core;
import java.util.LinkedList;
import java.util.List;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData;
public abstract class DimLink
{
protected ClientLinkData link;
protected DimLink parent;
protected LinkTail tail;
protected List<DimLink> children;
protected DimLink(ClientLinkData link, DimLink parent)
{
if (parent.link.point.getDimension() != link.point.getDimension())
{
// Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails
throw new IllegalArgumentException("source and parent.source must have the same dimension.");
}
this.parent = parent;
this.link = link;
this.tail = parent.tail;
this.children = new LinkedList<DimLink>();
parent.children.add(this);
}
protected DimLink(ClientLinkData link, int linkType)
{
if ((linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX) && linkType != LinkTypes.CLIENT_SIDE)
{
throw new IllegalArgumentException("The specified link type is invalid.");
}
this.parent = null;
this.link = link;
this.tail = new LinkTail(linkType, null);
this.children = new LinkedList<DimLink>();
}
public Point4D source()
{
return link.point;
}
public int orientation()
{
return link.orientation;
}
public ClientLinkData link()
{
return link;
}
public Point4D destination()
{
return tail.getDestination();
}
public int getDestinationOrientation()
{
return PocketManager.getLink(link.point.getX(), link.point.getY(), link.point.getZ(), link.point.getDimension()).link().orientation;
}
public boolean hasDestination()
{
return (tail.getDestination() != null);
}
public Iterable<DimLink> children()
{
return children;
}
public int childCount()
{
return children.size();
}
public DimLink parent()
{
return parent;
}
public int linkType()
{
return tail.getLinkType();
}
public String toString()
{
return link.point + " -> " + (hasDestination() ? destination() : "");
}
}

View File

@@ -0,0 +1,6 @@
package StevenDimDoors.mod_pocketDim.core;
public interface IDimRegistrationCallback
{
public NewDimData registerDimension(int dimensionID, int rootID);
}

View File

@@ -0,0 +1,32 @@
package StevenDimDoors.mod_pocketDim.core;
import StevenDimDoors.mod_pocketDim.util.Point4D;
class LinkTail
{
private Point4D destination;
private int linkType;
public LinkTail(int linkType, Point4D destination)
{
this.linkType = linkType;
this.destination = destination;
}
public Point4D getDestination() {
return destination;
}
public void setDestination(Point4D destination) {
this.destination = destination;
}
public int getLinkType() {
return linkType;
}
public void setLinkType(int linkType) {
this.linkType = linkType;
}
}

View File

@@ -0,0 +1,21 @@
package StevenDimDoors.mod_pocketDim.core;
public class LinkTypes
{
private LinkTypes() { }
public static final int ENUM_MIN = 0;
public static final int ENUM_MAX = 7;
public static final int CLIENT_SIDE = -1337;
// WARNING: Don't modify these values carelessly or you'll risk breaking links in existing worlds!
public static final int NORMAL = 0;
public static final int POCKET = 1;
public static final int DUNGEON = 2;
public static final int RANDOM = 3;
public static final int DUNGEON_EXIT = 4;
public static final int SAFE_EXIT = 5;
public static final int UNSAFE_EXIT = 6;
public static final int REVERSE = 7;
}

View File

@@ -0,0 +1,553 @@
package StevenDimDoors.mod_pocketDim.core;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.dungeon.DungeonData;
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher;
@SuppressWarnings("deprecation")
public abstract class NewDimData
{
private static class InnerDimLink extends DimLink
{
public InnerDimLink(Point4D source, DimLink parent,int orientation)
{
super(new ClientLinkData(source, orientation), parent);
}
public InnerDimLink(Point4D source, int linkType, int orientation)
{
super(new ClientLinkData(source, orientation), linkType);
}
public void setDestination(int x, int y, int z, NewDimData dimension)
{
tail.setDestination(new Point4D(x, y, z, dimension.id()));
}
public void clear()
{
//Release children
for (DimLink child : children)
{
((InnerDimLink) child).parent = null;
}
children.clear();
//Release parent
if (parent != null)
{
parent.children.remove(this);
}
parent = null;
link = null;
tail = new LinkTail(0, null);
}
public boolean overwrite(InnerDimLink nextParent,int orientation)
{
if (nextParent == null)
{
throw new IllegalArgumentException("nextParent cannot be null.");
}
if (this == nextParent)
{
//Ignore this request silently
return false;
}
if (nextParent.link.point.getDimension() != link.point.getDimension())
{
// Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails
throw new IllegalArgumentException("source and parent.source must have the same dimension.");
}
//Release children
for (DimLink child : children)
{
((InnerDimLink) child).parent = null;
}
children.clear();
//Release parent
if (parent != null)
{
parent.children.remove(this);
}
//Attach to new parent
parent = nextParent;
tail = nextParent.tail;
nextParent.children.add(this);
this.link.orientation=orientation;
return true;
}
public void overwrite(int linkType, int orientation)
{
//Release children
for (DimLink child : children)
{
((InnerDimLink) child).parent = null;
}
children.clear();
//Release parent
if (parent != null)
{
parent.children.remove(this);
}
//Attach to new parent
parent = null;
tail = new LinkTail(linkType, null);
//Set new orientation
this.link.orientation=orientation;
}
}
protected static Random random = new Random();
protected int id;
protected Map<Point4D, InnerDimLink> linkMapping;
protected List<InnerDimLink> linkList;
protected boolean isDungeon;
protected boolean isFilled;
protected int depth;
protected int packDepth;
protected NewDimData parent;
protected NewDimData root;
protected List<NewDimData> children;
protected Point4D origin;
protected int orientation;
protected DungeonData dungeon;
protected IUpdateWatcher<ClientLinkData> linkWatcher;
protected NewDimData(int id, NewDimData parent, boolean isPocket, boolean isDungeon,
IUpdateWatcher<ClientLinkData> linkWatcher)
{
// The isPocket flag is redundant. It's meant as an integrity safeguard.
if (isPocket && (parent == null))
{
throw new NullPointerException("Dimensions can be pocket dimensions if and only if they have a parent dimension.");
}
if (isDungeon && !isPocket)
{
throw new IllegalArgumentException("A dimensional dungeon must also be a pocket dimension.");
}
this.id = id;
this.linkMapping = new TreeMap<Point4D, InnerDimLink>(); //Should be stored in oct tree -- temporary solution
this.linkList = new ArrayList<InnerDimLink>(); //Should be stored in oct tree -- temporary solution
this.children = new ArrayList<NewDimData>();
this.parent = parent;
this.packDepth = 0;
this.isDungeon = isDungeon;
this.isFilled = false;
this.orientation = 0;
this.origin = null;
this.dungeon = null;
this.linkWatcher = linkWatcher;
//Register with parent
if (parent != null)
{
//We don't need to raise an update event for adding a child because the child's creation will be signaled.
this.root = parent.root;
this.depth = parent.depth + 1;
parent.children.add(this);
}
else
{
this.root = this;
this.depth = 0;
}
}
protected NewDimData(int id, NewDimData root)
{
// This constructor is meant for client-side code only
if (root == null)
{
throw new IllegalArgumentException("root cannot be null.");
}
this.id = id;
this.linkMapping = new TreeMap<Point4D, InnerDimLink>(); //Should be stored in oct tree -- temporary solution
this.linkList = new ArrayList<InnerDimLink>(); //Should be stored in oct tree -- temporary solution
this.children = new ArrayList<NewDimData>();
this.parent = null;
this.packDepth = 0;
this.isDungeon = false;
this.isFilled = false;
this.orientation = 0;
this.origin = null;
this.dungeon = null;
this.linkWatcher = null;
this.depth = 0;
this.root = root;
}
public DimLink findNearestRift(World world, int range, int x, int y, int z)
{
//TODO: Rewrite this later to use an octtree
//Sanity check...
if (world.provider.dimensionId != id)
{
throw new IllegalArgumentException("Attempted to search for links in a World instance for a different dimension!");
}
//Note: Only detect rifts at a distance > 1, so we ignore the rift
//that called this function and any adjacent rifts.
DimLink nearest = null;
DimLink link;
int distance;
int minDistance = Integer.MAX_VALUE;
int i, j, k;
DDProperties properties = DDProperties.instance();
for (i = -range; i <= range; i++)
{
for (j = -range; j <= range; j++)
{
for (k = -range; k <= range; k++)
{
distance = getAbsoluteSum(i, j, k);
if (distance > 1 && distance < minDistance && world.getBlockId(x + i, y + j, z + k) == properties.RiftBlockID)
{
link = getLink(x+i, y+j, z+k);
if (link != null)
{
nearest = link;
minDistance = distance;
}
}
}
}
}
return nearest;
}
private static int getAbsoluteSum(int i, int j, int k)
{
return Math.abs(i) + Math.abs(j) + Math.abs(k);
}
public DimLink createLink(int x, int y, int z, int linkType,int orientation)
{
return createLink(new Point4D(x, y, z, id), linkType,orientation);
}
public DimLink createLink(Point4D source, int linkType,int orientation)
{
//Return an existing link if there is one to avoid creating multiple links starting at the same point.
InnerDimLink link = linkMapping.get(source);
if (link == null)
{
link = new InnerDimLink(source, linkType,orientation);
linkMapping.put(source, link);
linkList.add(link);
}
else
{
link.overwrite(linkType,orientation);
}
//Link created!
if(linkType!=LinkTypes.CLIENT_SIDE)
{
linkWatcher.onCreated(link.link);
}
return link;
}
public DimLink createChildLink(int x, int y, int z, DimLink parent)
{
if (parent == null)
{
throw new IllegalArgumentException("parent cannot be null.");
}
return createChildLink(new Point4D(x, y, z, id), (InnerDimLink) parent);
}
private DimLink createChildLink(Point4D source, InnerDimLink parent)
{
//To avoid having multiple links at a single point, if we find an existing link then we overwrite
//its destination data instead of creating a new instance.
InnerDimLink link = linkMapping.get(source);
if (link == null)
{
link = new InnerDimLink(source, parent, parent.link.orientation);
linkMapping.put(source, link);
linkList.add(link);
//Link created!
linkWatcher.onCreated(link.link);
}
else
{
if (link.overwrite(parent, parent.link.orientation))
{
//Link created!
linkWatcher.onCreated(link.link);
}
}
return link;
}
public boolean deleteLink(DimLink link)
{
if (link.source().getDimension() != id)
{
throw new IllegalArgumentException("Attempted to delete a link from another dimension.");
}
InnerDimLink target = linkMapping.remove(link.source());
if (target != null)
{
linkList.remove(target);
//Raise deletion event
linkWatcher.onDeleted(target.link);
target.clear();
}
return (target != null);
}
public boolean deleteLink(int x, int y, int z)
{
Point4D location = new Point4D(x, y, z, id);
InnerDimLink target = linkMapping.remove(location);
if (target != null)
{
linkList.remove(target);
//Raise deletion event
//TODO why is source null here?
if(target.link!=null)
{
linkWatcher.onDeleted(target.link);
}
target.clear();
}
return (target != null);
}
public DimLink getLink(int x, int y, int z)
{
Point4D location = new Point4D(x, y, z, id);
return linkMapping.get(location);
}
public DimLink getLink(Point3D location)
{
return linkMapping.get(new Point4D(location.getX(),location.getY(),location.getZ(),this.id));
}
public DimLink getLink(Point4D location)
{
if (location.getDimension() != id)
return null;
return linkMapping.get(location);
}
public ArrayList<DimLink> getAllLinks()
{
ArrayList<DimLink> results = new ArrayList<DimLink>(linkMapping.size());
results.addAll(linkMapping.values());
return results;
}
public boolean isPocketDimension()
{
return (root != this);
}
public boolean isDungeon()
{
return isDungeon;
}
public boolean isFilled()
{
return isFilled;
}
public void setFilled(boolean isFilled)
{
this.isFilled = isFilled;
}
public int id()
{
return id;
}
public int depth()
{
return depth;
}
public int packDepth()
{
return packDepth;
}
public Point4D origin()
{
return origin;
}
public NewDimData parent()
{
return parent;
}
public NewDimData root()
{
return root;
}
public int orientation()
{
return orientation;
}
public DungeonData dungeon()
{
return dungeon;
}
public boolean isInitialized()
{
return (origin != null);
}
public int linkCount()
{
return linkList.size();
}
public Iterable<NewDimData> children()
{
return children;
}
public Iterable<? extends DimLink> links()
{
return linkList;
}
public void initializeDungeon(int originX, int originY, int originZ, int orientation, DimLink incoming, DungeonData dungeon)
{
if (!isDungeon)
{
throw new IllegalStateException("Cannot invoke initializeDungeon() on a non-dungeon dimension.");
}
if (isInitialized())
{
throw new IllegalStateException("The dimension has already been initialized.");
}
if (orientation < 0 || orientation > 3)
{
throw new IllegalArgumentException("orientation must be between 0 and 3, inclusive.");
}
setDestination(incoming, originX, originY, originZ);
this.origin = incoming.destination();
this.orientation = orientation;
this.dungeon = dungeon;
this.packDepth = calculatePackDepth(parent, dungeon);
}
/**
* effectivly moves the dungeon to the 'top' of a chain as far as dungeon generation is concerend.
*/
public void setParentToRoot()
{
this.depth=1;
this.parent=this.root;
this.root.children.add(this);
}
public static int calculatePackDepth(NewDimData parent, DungeonData current)
{
DungeonData predecessor = parent.dungeon();
if (current == null)
{
throw new IllegalArgumentException("current cannot be null.");
}
if (predecessor == null)
{
return 1;
}
DungeonPack predOwner = predecessor.dungeonType().Owner;
DungeonPack currentOwner = current.dungeonType().Owner;
if (currentOwner == null)
{
return 1;
}
if (predOwner == null)
{
return 1;
}
if (predOwner == currentOwner)
{
return parent.packDepth + 1;
}
else
{
return 1;
}
}
public void initializePocket(int originX, int originY, int originZ, int orientation, DimLink incoming)
{
if (!isPocketDimension())
{
throw new IllegalStateException("Cannot invoke initializePocket() on a non-pocket dimension.");
}
if (isInitialized())
{
throw new IllegalStateException("The dimension has already been initialized.");
}
setDestination(incoming, originX, originY, originZ);
this.origin = incoming.destination();
this.orientation = orientation;
}
public void setDestination(DimLink incoming, int x, int y, int z)
{
InnerDimLink link = (InnerDimLink) incoming;
link.setDestination(x, y, z, this);
}
public DimLink getRandomLink()
{
if (linkMapping.isEmpty())
{
throw new IllegalStateException("There are no links to select from in this dimension.");
}
if (linkList.size() > 1)
{
return linkList.get(random.nextInt(linkList.size()));
}
else
{
return linkList.get(0);
}
}
}

View File

@@ -0,0 +1,710 @@
package StevenDimDoors.mod_pocketDim.core;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import cpw.mods.fml.common.FMLCommonHandler;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.helpers.Compactor;
import StevenDimDoors.mod_pocketDim.helpers.DeleteFolder;
import StevenDimDoors.mod_pocketDim.saving.DDSaveHandler;
import StevenDimDoors.mod_pocketDim.saving.IPackable;
import StevenDimDoors.mod_pocketDim.saving.OldSaveImporter;
import StevenDimDoors.mod_pocketDim.saving.PackedDimData;
import StevenDimDoors.mod_pocketDim.saving.PackedDungeonData;
import StevenDimDoors.mod_pocketDim.saving.PackedLinkData;
import StevenDimDoors.mod_pocketDim.saving.PackedLinkTail;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.watcher.ClientDimData;
import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateSource;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher;
import StevenDimDoors.mod_pocketDim.watcher.UpdateWatcherProxy;
/**
* This class regulates all the operations involving the storage and manipulation of dimensions. It handles saving dim data, teleporting the player, and
* creating/registering new dimensions as well as loading old dimensions on startup
*/
@SuppressWarnings("deprecation")
public class PocketManager
{
private static class InnerDimData extends NewDimData implements IPackable<PackedDimData>
{
// This class allows us to instantiate NewDimData indirectly without exposing
// a public constructor from NewDimData. It's meant to stop us from constructing
// instances of NewDimData going through PocketManager. In turn, that enforces
// that any link destinations must be real dimensions controlled by PocketManager.
public InnerDimData(int id, InnerDimData parent, boolean isPocket, boolean isDungeon,
IUpdateWatcher<ClientLinkData> linkWatcher)
{
super(id, parent, isPocket, isDungeon, linkWatcher);
}
public InnerDimData(int id, InnerDimData root)
{
// This constructor is meant for client-side code only
super(id, root);
}
public void clear()
{
// If this dimension has a parent, remove it from its parent's list of children
if (parent != null)
{
parent.children.remove(this);
}
// Remove this dimension as the parent of its children
for (NewDimData child : children)
{
child.parent = null;
}
// Clear all fields
id = Integer.MIN_VALUE;
linkMapping.clear();
linkMapping = null;
linkList.clear();
linkList = null;
children.clear();
children = null;
isDungeon = false;
isFilled = false;
depth = Integer.MIN_VALUE;
packDepth = Integer.MIN_VALUE;
origin = null;
orientation = Integer.MIN_VALUE;
dungeon = null;
linkWatcher = null;
}
@Override
public String name()
{
return String.valueOf(id);
}
@Override
public PackedDimData pack()
{
ArrayList<Integer> ChildIDs = new ArrayList<Integer>();
ArrayList<PackedLinkData> Links = new ArrayList<PackedLinkData>();
ArrayList<PackedLinkTail> Tails = new ArrayList<PackedLinkTail>();
PackedDungeonData packedDungeon=null;
if(this.dungeon!=null)
{
packedDungeon= new PackedDungeonData(dungeon.weight(), dungeon.isOpen(), dungeon.isInternal(),
dungeon.schematicPath(), dungeon.schematicName(), dungeon.dungeonType().Name,
dungeon.dungeonType().Owner.getName());
}
//Make a list of children
for(NewDimData data : this.children)
{
ChildIDs.add(data.id);
}
for(DimLink link:this.links())
{
ArrayList<Point3D> children = new ArrayList<Point3D>();
Point3D parentPoint = new Point3D(-1,-1,-1);
if(link.parent!=null)
{
parentPoint=link.parent.link.point.toPoint3D();
}
for(DimLink childLink : link.children)
{
children.add(childLink.source().toPoint3D());
}
PackedLinkTail tail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType());
Links.add(new PackedLinkData(link.link.point,parentPoint,tail,link.link.orientation,children));
PackedLinkTail tempTail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType());
if(Tails.contains(tempTail))
{
Tails.add(tempTail);
}
}
int parentID=this.id;
Point3D originPoint=new Point3D(0,0,0);
if(this.parent!=null)
{
parentID = this.parent.id;
}
if(this.origin!=null)
{
originPoint=this.origin.toPoint3D();
}
return new PackedDimData(this.id, depth, this.packDepth, parentID, this.root().id(), orientation,
isDungeon, isFilled,packedDungeon, originPoint, ChildIDs, Links, Tails);
// FIXME: IMPLEMENTATION PLZTHX
//I tried
}
}
private static class ClientLinkWatcher implements IUpdateWatcher<ClientLinkData>
{
@Override
public void onCreated(ClientLinkData link)
{
Point4D source = link.point;
NewDimData dimension = getDimensionData(source.getDimension());
dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.CLIENT_SIDE,link.orientation);
}
@Override
public void onDeleted(ClientLinkData link)
{
Point4D source = link.point;
NewDimData dimension = getDimensionData(source.getDimension());
dimension.deleteLink(source.getX(), source.getY(), source.getZ());
}
}
private static class ClientDimWatcher implements IUpdateWatcher<ClientDimData>
{
@Override
public void onCreated(ClientDimData data)
{
registerClientDimension(data.ID, data.RootID);
}
@Override
public void onDeleted(ClientDimData data)
{
deletePocket(getDimensionData(data.ID), false);
}
}
private static class DimRegistrationCallback implements IDimRegistrationCallback
{
// We use this class to provide Compactor with the ability to send us dim data without
// having to instantiate a bunch of data containers and without exposing an "unsafe"
// creation method for anyone to call. Integrity protection for the win! It's like
// exposing a private constructor ONLY to a very specific trusted class.
@Override
public NewDimData registerDimension(int dimensionID, int rootID)
{
return registerClientDimension(dimensionID, rootID);
}
}
private static int OVERWORLD_DIMENSION_ID = 0;
private static volatile boolean isLoading = false;
private static volatile boolean isLoaded = false;
private static volatile boolean isSaving = false;
/**
* Set as true if we are a client that has connected to a dedicated server
*/
public static volatile boolean isConnected = false;
private static final UpdateWatcherProxy<ClientLinkData> linkWatcher = new UpdateWatcherProxy<ClientLinkData>();
private static final UpdateWatcherProxy<ClientDimData> dimWatcher = new UpdateWatcherProxy<ClientDimData>();
private static ArrayList<NewDimData> rootDimensions = null;
//HashMap that maps all the dimension IDs registered with DimDoors to their DD data.
private static HashMap<Integer, InnerDimData> dimensionData = null;
//ArrayList that stores the dimension IDs of any dimension that has been deleted.
private static ArrayList<Integer> dimensionIDBlackList = null;
public static boolean isLoaded()
{
return isLoaded;
}
/**
* simple method called on startup to register all dims saved in the dim list. Only tries to register pocket dims, though. Also calls load()
* @return
*/
public static void load()
{
if (isLoaded)
{
throw new IllegalStateException("Pocket dimensions have already been loaded!");
}
if (isLoading)
{
return;
}
isLoading = true;
dimensionData = new HashMap<Integer, InnerDimData>();
rootDimensions = new ArrayList<NewDimData>();
dimensionIDBlackList = new ArrayList<Integer>();
if(FMLCommonHandler.instance().getEffectiveSide().isClient())
{
//Shouldnt try to load everything if we are a client
//This was preventing onPacket from loading properly
isLoading=false;
return;
}
//Register Limbo
DDProperties properties = DDProperties.instance();
registerDimension(properties.LimboDimensionID, null, false, false);
loadInternal();
//Register pocket dimensions
registerPockets(properties);
isLoaded = true;
isLoading = false;
}
public static boolean registerPackedDimData(PackedDimData packedData)
{
InnerDimData dimData;
if(packedData.ID==packedData.ParentID)
{
dimData = new InnerDimData(packedData.ID, null, false, false, linkWatcher);
dimData.root=dimData;
dimData.parent=dimData;
dimData.isFilled=packedData.IsFilled;
dimData.origin = new Point4D(packedData.Origin.getX(),packedData.Origin.getY(),packedData.Origin.getZ(),packedData.ID);
PocketManager.rootDimensions.add(dimData);
}
else
{
InnerDimData test = PocketManager.dimensionData.get(packedData.ParentID);
dimData = new InnerDimData(packedData.ID, test,true, packedData.IsDungeon, linkWatcher);
dimData.isFilled=packedData.IsFilled;
dimData.origin = new Point4D(packedData.Origin.getX(),packedData.Origin.getY(),packedData.Origin.getZ(),packedData.ID);
dimData.root=PocketManager.getDimensionData(packedData.RootID);
if(packedData.DungeonData!=null)
{
dimData.dungeon=DDSaveHandler.unpackDungeonData(packedData.DungeonData);
}
}
PocketManager.dimensionData.put(dimData.id, dimData);
dimWatcher.onCreated(new ClientDimData(dimData));
return true;
}
public static boolean deletePocket(NewDimData target, boolean deleteFolder)
{
// We can't delete the dimension if it's currently loaded or if it's not actually a pocket.
// We cast to InnerDimData so that if anyone tries to be a smartass and create their
// own version of NewDimData, this will throw an exception.
InnerDimData dimension = (InnerDimData) target;
if (dimension.isPocketDimension() && DimensionManager.getWorld(dimension.id()) == null)
{
if (deleteFolder)
{
deleteDimensionFolder(target);
}
dimensionIDBlackList.add(dimension.id);
deleteDimensionData(dimension.id);
return true;
}
return false;
}
private static boolean deleteDimensionFolder(NewDimData target)
{
InnerDimData dimension = (InnerDimData) target;
if (dimension.isPocketDimension() && DimensionManager.getWorld(dimension.id()) == null)
{
File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/pocketDimID" + dimension.id());
DeleteFolder.deleteFolder(saveDirectory);
return true;
}
return false;
}
private static boolean deleteDimensionData(int dimensionID)
{
if(dimensionData.containsKey(dimensionID)&& DimensionManager.getWorld(dimensionID) == null)
{
NewDimData target = PocketManager.getDimensionData(dimensionID);
InnerDimData dimension = (InnerDimData) target;
dimensionData.remove(dimensionID);
// Raise the dim deleted event
dimWatcher.onDeleted(new ClientDimData(dimension));
dimension.clear();
return true;
}
return false;
}
private static void registerPockets(DDProperties properties)
{
for (NewDimData dimension : dimensionData.values())
{
if (dimension.isPocketDimension())
{
try
{
DimensionManager.registerDimension(dimension.id(), properties.PocketProviderID);
}
catch (Exception e)
{
System.err.println("Could not register pocket dimension #" + dimension.id() + ". Probably caused by a version update/save data corruption/other mods.");
e.printStackTrace();
}
}
}
}
private static void unregisterPockets()
{
for (NewDimData dimension : dimensionData.values())
{
if (dimension.isPocketDimension())
{
try
{
DimensionManager.unregisterDimension(dimension.id());
}
catch (Exception e)
{
System.err.println("An unexpected error occurred while unregistering pocket dimension #" + dimension.id() + ":");
e.printStackTrace();
}
}
}
for(Integer dimID : dimensionIDBlackList)
{
try
{
DimensionManager.unregisterDimension(dimID);
}
catch (Exception e)
{
System.err.println("An unexpected error occurred while unregistering blacklisted dim #" + dimID + ":");
e.printStackTrace();
}
}
}
/**
* loads the dim data from the saved hashMap. Also handles compatibility with old saves, see OldSaveHandler
*/
private static void loadInternal()
{
System.out.println(!FMLCommonHandler.instance().getSide().isClient());
File saveDir = DimensionManager.getCurrentSaveRootDirectory();
if (saveDir != null)
{
//Try to import data from old DD versions
//TODO - remove this code in a few versions
File oldSaveData = new File(saveDir+"/DimensionalDoorsData");
if(oldSaveData.exists())
{
try
{
System.out.println("Importing old DD save data...");
OldSaveImporter.importOldSave(oldSaveData);
oldSaveData.delete();
System.out.println("Import Succesful!");
}
catch (Exception e)
{
//TODO handle fail cases
System.out.println("Import failed!");
e.printStackTrace();
}
return;
}
// Load save data
System.out.println("Loading Dimensional Doors save data...");
if (DDSaveHandler.loadAll())
{
System.out.println("Loaded successfully!");
}
}
}
public static void save()
{
if (!isLoaded)
{
return;
}
World world = DimensionManager.getWorld(OVERWORLD_DIMENSION_ID);
if (world == null || world.isRemote || DimensionManager.getCurrentSaveRootDirectory() == null)
{
return;
}
//Check this last to make sure we set the flag shortly after.
if (isSaving)
{
return;
}
isSaving = true;
try
{
System.out.println("Writing Dimensional Doors save data...");
if ( DDSaveHandler.saveAll(dimensionData.values(),dimensionIDBlackList) )
{
System.out.println("Saved successfully!");
}
}
catch (Exception e)
{
// Wrap the exception in a RuntimeException so functions that call
// PocketManager.save() don't need to catch it. We want MC to
// crash if something really bad happens rather than ignoring it!
throw new RuntimeException(e);
}
finally
{
isSaving = false;
}
}
public static WorldServer loadDimension(int id)
{
WorldServer world = DimensionManager.getWorld(id);
if (world == null)
{
DimensionManager.initDimension(id);
world = DimensionManager.getWorld(id);
}
else if (world.provider == null)
{
DimensionManager.initDimension(id);
world = DimensionManager.getWorld(id);
}
return world;
}
public static NewDimData registerDimension(World world)
{
return registerDimension(world.provider.dimensionId, null, false, false);
}
public static NewDimData registerPocket(NewDimData parent, boolean isDungeon)
{
if (parent == null)
{
throw new IllegalArgumentException("parent cannot be null. A pocket dimension must always have a parent dimension.");
}
DDProperties properties = DDProperties.instance();
int dimensionID = DimensionManager.getNextFreeDimId();
DimensionManager.registerDimension(dimensionID, properties.PocketProviderID);
return registerDimension(dimensionID, (InnerDimData) parent, true, isDungeon);
}
private static NewDimData registerDimension(int dimensionID, InnerDimData parent, boolean isPocket, boolean isDungeon)
{
if (dimensionData.containsKey(dimensionID))
{
throw new IllegalArgumentException("Cannot register a dimension with ID = " + dimensionID + " because it has already been registered.");
}
//TODO blacklist stuff probably should happen here
InnerDimData dimension = new InnerDimData(dimensionID, parent, isPocket, isDungeon, linkWatcher);
dimensionData.put(dimensionID, dimension);
if (!dimension.isPocketDimension())
{
rootDimensions.add(dimension);
}
dimWatcher.onCreated(new ClientDimData(dimension));
return dimension;
}
private static NewDimData registerClientDimension(int dimensionID, int rootID)
{
// No need to raise events heres since this code should only run on the client side
// getDimensionData() always handles root dimensions properly, even if the weren't defined before
// SenseiKiwi: I'm a little worried about how getDimensionData will raise
// an event when it creates any root dimensions... Needs checking later.
InnerDimData root = (InnerDimData) getDimensionData(rootID);
InnerDimData dimension;
if (rootID != dimensionID)
{
dimension = dimensionData.get(dimensionID);
if (dimension == null)
{
dimension = new InnerDimData(dimensionID, root);
dimensionData.put(dimension.id(), dimension);
}
}
else
{
dimension = root;
}
if(dimension.isPocketDimension())
{
//Im registering pocket dims here. I *think* we can assume that if its a pocket and we are
//registering its dim data, we also need to register it with forge.
DimensionManager.registerDimension(dimensionID, mod_pocketDim.properties.PocketProviderID);
}
return dimension;
}
public static NewDimData getDimensionData(World world)
{
return getDimensionData(world.provider.dimensionId);
}
public static NewDimData getDimensionData(int dimensionID)
{
//Retrieve the data for a dimension. If we don't have a record for that dimension,
//assume it's a non-pocket dimension that hasn't been initialized with us before
//and create a NewDimData instance for it.
//Any pocket dimension must be listed with PocketManager to have a dimension ID
//assigned, so it's safe to assume that any unknown dimensions don't belong to us.
if(PocketManager.dimensionData == null)
{
System.out.println("Something odd happend during shutdown");
}
NewDimData dimension = PocketManager.dimensionData.get(dimensionID);
if (dimension == null)
{
dimension = registerDimension(dimensionID, null, false, false);
}
return dimension;
}
public static Iterable<? extends NewDimData> getDimensions()
{
return dimensionData.values();
}
@SuppressWarnings("unchecked")
public static ArrayList<NewDimData> getRootDimensions()
{
return (ArrayList<NewDimData>) rootDimensions.clone();
}
public static void unload()
{
System.out.println("Unloading Pocket Dimensions...");
if (!isLoaded)
{
throw new IllegalStateException("Pocket dimensions have already been unloaded!");
}
save();
unregisterPockets();
dimensionData = null;
rootDimensions = null;
isLoaded = false;
isConnected = false;
}
public static DimLink getLink(int x, int y, int z, World world)
{
return getLink(x, y, z, world.provider.dimensionId);
}
public static DimLink getLink(Point4D point)
{
return getLink(point.getX(), point.getY(), point.getZ(), point.getDimension());
}
public static DimLink getLink(int x, int y, int z, int dimensionID)
{
NewDimData dimension = dimensionData.get(dimensionID);
if (dimension != null)
{
return dimension.getLink(x, y, z);
}
else
{
return null;
}
}
public static boolean isBlackListed(int dimensionID)
{
return PocketManager.dimensionIDBlackList.contains(dimensionID);
}
public static void registerDimWatcher(IUpdateWatcher<ClientDimData> watcher)
{
dimWatcher.registerReceiver(watcher);
}
public static boolean unregisterDimWatcher(IUpdateWatcher<ClientDimData> watcher)
{
return dimWatcher.unregisterReceiver(watcher);
}
public static void registerLinkWatcher(IUpdateWatcher<ClientLinkData> watcher)
{
linkWatcher.registerReceiver(watcher);
}
public static boolean unregisterLinkWatcher(IUpdateWatcher<ClientLinkData> watcher)
{
return linkWatcher.unregisterReceiver(watcher);
}
public static void getWatchers(IUpdateSource updateSource)
{
updateSource.registerWatchers(new ClientDimWatcher(), new ClientLinkWatcher());
}
public static void writePacket(DataOutputStream output) throws IOException
{
// Write a very compact description of our dimensions and links to be sent to a client
Compactor.write(dimensionData.values(), output);
}
public static boolean isRegisteredInternally(int dimensionID)
{
return dimensionData.containsKey(dimensionID);
}
public static void createAndRegisterBlacklist(List<Integer> blacklist)
{
//TODO - create a special blacklist provider
for(Integer dimID : blacklist)
{
PocketManager.dimensionIDBlackList.add(dimID);
DimensionManager.registerDimension(dimID, DDProperties.instance().PocketProviderID);
}
}
public static void readPacket(DataInputStream input) throws IOException
{
//TODO- figure out why this is getting called so frequently
if (isLoaded)
{
return;
}
if (isLoading)
{
throw new IllegalStateException("Pocket dimensions are already loading!");
}
// Load compacted client-side dimension data
load();
Compactor.readDimensions(input, new DimRegistrationCallback());
// Register pocket dimensions
DDProperties properties = DDProperties.instance();
isLoaded = true;
isLoading = false;
isConnected = true;
}
}

View File

@@ -0,0 +1,78 @@
package StevenDimDoors.mod_pocketDim.dungeon;
import java.io.FileNotFoundException;
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType;
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException;
public class DungeonData
{
private final int weight;
private final boolean isOpen;
private final boolean isInternal;
private final String schematicPath;
private final String schematicName;
private final DungeonType dungeonType;
public DungeonData(String schematicPath, boolean isInternal, DungeonType dungeonType, boolean isOpen, int weight)
{
this.schematicPath = schematicPath;
this.schematicName = getSchematicName(schematicPath);
this.dungeonType = dungeonType;
this.isInternal = isInternal;
this.isOpen = isOpen;
this.weight = weight;
}
private static String getSchematicName(String schematicPath)
{
int indexA = schematicPath.lastIndexOf('\\');
int indexB = schematicPath.lastIndexOf('/');
indexA = Math.max(indexA, indexB) + 1;
return schematicPath.substring(indexA, schematicPath.length() - DungeonHelper.SCHEMATIC_FILE_EXTENSION.length());
}
public int weight()
{
return weight;
}
public boolean isOpen()
{
return isOpen;
}
public boolean isInternal()
{
return isInternal;
}
public String schematicPath()
{
return schematicPath;
}
public DungeonType dungeonType()
{
return dungeonType;
}
public String schematicName()
{
return schematicName;
}
public DungeonSchematic loadSchematic() throws InvalidSchematicException, FileNotFoundException
{
if (isInternal)
{
return DungeonSchematic.readFromResource(schematicPath);
}
else
{
return DungeonSchematic.readFromFile(schematicPath);
}
}
}

View File

@@ -0,0 +1,343 @@
package StevenDimDoors.mod_pocketDim.dungeon;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeMap;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.Point3D;
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.schematic.BlockRotator;
import StevenDimDoors.mod_pocketDim.schematic.CompoundFilter;
import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException;
import StevenDimDoors.mod_pocketDim.schematic.ReplacementFilter;
import StevenDimDoors.mod_pocketDim.schematic.Schematic;
import StevenDimDoors.mod_pocketDim.ticking.MobMonolith;
import StevenDimDoors.mod_pocketDim.ticking.MonolithSpawner;
import StevenDimDoors.mod_pocketDim.util.Point4D;
public class DungeonSchematic extends Schematic {
private static final short MAX_VANILLA_BLOCK_ID = 158;
private static final short STANDARD_FABRIC_OF_REALITY_ID = 1973;
private static final short STANDARD_ETERNAL_FABRIC_ID = 220;
private static final short STANDARD_WARP_DOOR_ID = 1975;
private static final short STANDARD_DIMENSIONAL_DOOR_ID = 1970;
private static final short MONOLITH_SPAWN_MARKER_ID = (short) Block.endPortalFrame.blockID;
private static final short EXIT_DOOR_MARKER_ID = (short) Block.sandStone.blockID;
private int orientation;
private Point3D entranceDoorLocation;
private ArrayList<Point3D> exitDoorLocations;
private ArrayList<Point3D> dimensionalDoorLocations;
private ArrayList<Point3D> monolithSpawnLocations;
private static final short[] MOD_BLOCK_FILTER_EXCEPTIONS = new short[] {
STANDARD_FABRIC_OF_REALITY_ID,
STANDARD_ETERNAL_FABRIC_ID,
STANDARD_WARP_DOOR_ID,
STANDARD_DIMENSIONAL_DOOR_ID
};
private DungeonSchematic(Schematic source)
{
super(source);
}
public int getOrientation()
{
return orientation;
}
public Point3D getEntranceDoorLocation()
{
return entranceDoorLocation.clone();
}
private DungeonSchematic()
{
//Used to create a dummy instance for readFromResource()
super((short) 0, (short) 0, (short) 0, null, null, null);
}
public static DungeonSchematic readFromFile(String schematicPath) throws FileNotFoundException, InvalidSchematicException
{
return readFromFile(new File(schematicPath));
}
public static DungeonSchematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException
{
// TODO: fix resource leak
return readFromStream(new FileInputStream(schematicFile));
}
public static DungeonSchematic readFromResource(String resourcePath) throws InvalidSchematicException
{
//We need an instance of a class in the mod to retrieve a resource
DungeonSchematic empty = new DungeonSchematic();
InputStream schematicStream = empty.getClass().getResourceAsStream(resourcePath);
return readFromStream(schematicStream);
}
public static DungeonSchematic readFromStream(InputStream schematicStream) throws InvalidSchematicException
{
return new DungeonSchematic(Schematic.readFromStream(schematicStream));
}
public void applyImportFilters(DDProperties properties)
{
//Search for special blocks (warp doors, dim doors, and end portal frames that mark Monolith spawn points)
SpecialBlockFinder finder = new SpecialBlockFinder(STANDARD_WARP_DOOR_ID, STANDARD_DIMENSIONAL_DOOR_ID,
MONOLITH_SPAWN_MARKER_ID, EXIT_DOOR_MARKER_ID);
applyFilter(finder);
//Flip the entrance's orientation to get the dungeon's orientation
orientation = BlockRotator.transformMetadata(finder.getEntranceOrientation(), 2, Block.doorWood.blockID);
entranceDoorLocation = finder.getEntranceDoorLocation();
exitDoorLocations = finder.getExitDoorLocations();
dimensionalDoorLocations = finder.getDimensionalDoorLocations();
monolithSpawnLocations = finder.getMonolithSpawnLocations();
//Filter out mod blocks except some of our own
CompoundFilter standardizer = new CompoundFilter();
standardizer.addFilter(new ModBlockFilter(MAX_VANILLA_BLOCK_ID, MOD_BLOCK_FILTER_EXCEPTIONS,
(short) properties.FabricBlockID, (byte) 0));
//Also convert standard DD block IDs to local versions
Map<Short, Short> mapping = getAssignedToStandardIDMapping(properties);
for (Entry<Short, Short> entry : mapping.entrySet())
{
if (entry.getKey() != entry.getValue())
{
standardizer.addFilter(new ReplacementFilter(entry.getValue(), entry.getKey()));
}
}
applyFilter(standardizer);
}
public void applyExportFilters(DDProperties properties)
{
//Check if some block IDs assigned by Forge differ from our standard IDs
//If so, change the IDs to standard values
CompoundFilter standardizer = new CompoundFilter();
Map<Short, Short> mapping = getAssignedToStandardIDMapping(properties);
for (Entry<Short, Short> entry : mapping.entrySet())
{
if (entry.getKey() != entry.getValue())
{
standardizer.addFilter(new ReplacementFilter(entry.getKey(), entry.getValue()));
}
}
//Filter out mod blocks except some of our own
//This comes after ID standardization because the mod block filter relies on standardized IDs
standardizer.addFilter(new ModBlockFilter(MAX_VANILLA_BLOCK_ID, MOD_BLOCK_FILTER_EXCEPTIONS,
STANDARD_FABRIC_OF_REALITY_ID, (byte) 0));
applyFilter(standardizer);
}
private Map<Short, Short> getAssignedToStandardIDMapping(DDProperties properties)
{
//If we ever need this broadly or support other mods, this should be moved to a separate class
TreeMap<Short, Short> mapping = new TreeMap<Short, Short>();
mapping.put((short) properties.FabricBlockID, STANDARD_FABRIC_OF_REALITY_ID);
mapping.put((short) properties.PermaFabricBlockID, STANDARD_ETERNAL_FABRIC_ID);
mapping.put((short) properties.WarpDoorID, STANDARD_WARP_DOOR_ID);
mapping.put((short) properties.DimensionalDoorID, STANDARD_DIMENSIONAL_DOOR_ID);
return mapping;
}
public static DungeonSchematic copyFromWorld(World world, int x, int y, int z, short width, short height, short length, boolean doCompactBounds)
{
return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds));
}
public void copyToWorld(World world, Point3D pocketCenter, int targetOrientation, DimLink entryLink, Random random)
{
//TODO: This function is an improvised solution so we can get the release moving. In the future,
//we should generalize block transformations and implement support for them at the level of Schematic,
//then just use that support from DungeonSchematic instead of making this local fix.
//It might be easiest to support transformations using a WorldOperation
final int turnAngle = targetOrientation - this.orientation;
int index;
int count;
int blockID;
int blockMeta;
int dx, dy, dz;
Point3D pocketPoint = new Point3D(0, 0, 0);
//Copy blocks and metadata into the world
index = 0;
for (dy = 0; dy < height; dy++)
{
for (dz = 0; dz < length; dz++)
{
for (dx = 0; dx < width; dx++)
{
pocketPoint.setX(dx);
pocketPoint.setY(dy);
pocketPoint.setZ(dz);
blockID = blocks[index];
BlockRotator.transformPoint(pocketPoint, entranceDoorLocation, turnAngle, pocketCenter);
blockMeta = BlockRotator.transformMetadata(metadata[index], turnAngle, blockID);
//In the future, we might want to make this more efficient by building whole chunks at a time
setBlockDirectly(world, pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), blockID, blockMeta);
index++;
}
}
}
//Copy tile entities into the world
count = tileEntities.tagCount();
for (index = 0; index < count; index++)
{
NBTTagCompound tileTag = (NBTTagCompound) tileEntities.tagAt(index);
//Rewrite its location to be in world coordinates
pocketPoint.setX(tileTag.getInteger("x"));
pocketPoint.setY(tileTag.getInteger("y"));
pocketPoint.setZ(tileTag.getInteger("z"));
BlockRotator.transformPoint(pocketPoint, entranceDoorLocation, turnAngle, pocketCenter);
tileTag.setInteger("x", pocketPoint.getX());
tileTag.setInteger("y", pocketPoint.getY());
tileTag.setInteger("z", pocketPoint.getZ());
//Load the tile entity and put it in the world
world.setBlockTileEntity(pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), TileEntity.createAndLoadEntity(tileTag));
}
setUpDungeon(PocketManager.getDimensionData(world), world, pocketCenter, turnAngle, entryLink, random);
}
private void setUpDungeon(NewDimData dimension, World world, Point3D pocketCenter, int turnAngle, DimLink entryLink, Random random)
{
//Transform dungeon corners
Point3D minCorner = new Point3D(0, 0, 0);
Point3D maxCorner = new Point3D(width - 1, height - 1, length - 1);
transformCorners(entranceDoorLocation, pocketCenter, turnAngle, minCorner, maxCorner);
//Fill empty chests and dispensers
FillContainersOperation filler = new FillContainersOperation(random);
filler.apply(world, minCorner, maxCorner);
//Set up entrance door rift
createEntranceReverseLink(dimension, pocketCenter, entryLink, world);
//Set up link data for dimensional doors
for (Point3D location : dimensionalDoorLocations)
{
createDimensionalDoorLink(dimension, location, entranceDoorLocation, turnAngle, pocketCenter,world);
}
//Set up link data for exit door
for (Point3D location : exitDoorLocations)
{
createExitDoorLink(world, dimension, location, entranceDoorLocation, turnAngle, pocketCenter);
}
//Remove end portal frames and spawn Monoliths, if allowed
boolean canSpawn = MonolithSpawner.isMobSpawningAllowed();
for (Point3D location : monolithSpawnLocations)
{
spawnMonolith(world, location, entranceDoorLocation, turnAngle, pocketCenter, canSpawn);
}
}
private static void transformCorners(Point3D schematicEntrance, Point3D pocketCenter, int turnAngle, Point3D minCorner, Point3D maxCorner)
{
int temp;
BlockRotator.transformPoint(minCorner, schematicEntrance, turnAngle, pocketCenter);
BlockRotator.transformPoint(maxCorner, schematicEntrance, turnAngle, pocketCenter);
if (minCorner.getX() > maxCorner.getX())
{
temp = minCorner.getX();
minCorner.setX(maxCorner.getX());
maxCorner.setX(temp);
}
if (minCorner.getY() > maxCorner.getY())
{
temp = minCorner.getY();
minCorner.setY(maxCorner.getY());
maxCorner.setY(temp);
}
if (minCorner.getZ() > maxCorner.getZ())
{
temp = minCorner.getZ();
minCorner.setZ(maxCorner.getZ());
maxCorner.setZ(temp);
}
}
private static void createEntranceReverseLink(NewDimData dimension, Point3D pocketCenter, DimLink entryLink,World world)
{
int orientation = world.getBlockMetadata(pocketCenter.getX(), pocketCenter.getY()-1, pocketCenter.getZ());
DimLink reverseLink = dimension.createLink(pocketCenter.getX(), pocketCenter.getY(), pocketCenter.getZ(), LinkTypes.REVERSE,orientation);
Point4D destination = entryLink.source();
NewDimData prevDim = PocketManager.getDimensionData(destination.getDimension());
prevDim.setDestination(reverseLink, destination.getX(), destination.getY(), destination.getZ());
}
private static void createExitDoorLink(World world, NewDimData dimension, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter)
{
//Transform the door's location to the pocket coordinate system
Point3D location = point.clone();
BlockRotator.transformPoint(location, entrance, rotation, pocketCenter);
int orientation = world.getBlockMetadata(location.getX(), location.getY()-1, location.getZ());
dimension.createLink(location.getX(), location.getY(), location.getZ(), LinkTypes.DUNGEON_EXIT,orientation);
//Replace the sandstone block under the exit door with the same block as the one underneath it
int x = location.getX();
int y = location.getY() - 3;
int z = location.getZ();
if (y >= 0)
{
int blockID = world.getBlockId(x, y, z);
int metadata = world.getBlockMetadata(x, y, z);
setBlockDirectly(world, x, y + 1, z, blockID, metadata);
}
}
private static void createDimensionalDoorLink(NewDimData dimension, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter,World world)
{
//Transform the door's location to the pocket coordinate system
Point3D location = point.clone();
BlockRotator.transformPoint(location, entrance, rotation, pocketCenter);
int orientation = world.getBlockMetadata(location.getX(), location.getY()-1, location.getZ());
dimension.createLink(location.getX(), location.getY(), location.getZ(), LinkTypes.DUNGEON,orientation);
}
private static void spawnMonolith(World world, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter, boolean canSpawn)
{
//Transform the frame block's location to the pocket coordinate system
Point3D location = point.clone();
BlockRotator.transformPoint(location, entrance, rotation, pocketCenter);
//Remove frame block
setBlockDirectly(world, location.getX(), location.getY(), location.getZ(), 0, 0);
//Spawn Monolith
if (canSpawn)
{
Entity mob = new MobMonolith(world);
mob.setLocationAndAngles(location.getX(), location.getY(), location.getZ(), 1, 1);
world.spawnEntityInWorld(mob);
}
}
}

View File

@@ -0,0 +1,72 @@
package StevenDimDoors.mod_pocketDim.dungeon;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDLoot;
import StevenDimDoors.mod_pocketDim.schematic.WorldOperation;
public class FillContainersOperation extends WorldOperation
{
private Random random;
public FillContainersOperation(Random random)
{
super("FillContainersOperation");
this.random = random;
}
@Override
protected boolean applyToBlock(World world, int x, int y, int z)
{
int blockID = world.getBlockId(x, y, z);
//Fill empty chests and dispensers
if (Block.blocksList[blockID] instanceof BlockContainer)
{
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
//Fill chests
if (tileEntity instanceof TileEntityChest)
{
TileEntityChest chest = (TileEntityChest) tileEntity;
if (isInventoryEmpty(chest))
{
DDLoot.generateChestContents(DDLoot.DungeonChestInfo, chest, random);
}
}
//Fill dispensers
if (tileEntity instanceof TileEntityDispenser)
{
TileEntityDispenser dispenser = (TileEntityDispenser) tileEntity;
if (isInventoryEmpty(dispenser))
{
dispenser.addItem(new ItemStack(Item.arrow, 64));
}
}
}
return true;
}
private static boolean isInventoryEmpty(IInventory inventory)
{
int size = inventory.getSizeInventory();
for (int index = 0; index < size; index++)
{
if (inventory.getStackInSlot(index) != null)
{
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,51 @@
package StevenDimDoors.mod_pocketDim.dungeon;
import net.minecraft.block.Block;
import StevenDimDoors.mod_pocketDim.schematic.SchematicFilter;
public class ModBlockFilter extends SchematicFilter {
private short maxVanillaBlockID;
private short[] exceptions;
private short replacementBlockID;
private byte replacementMetadata;
public ModBlockFilter(short maxVanillaBlockID, short[] exceptions, short replacementBlockID, byte replacementMetadata)
{
super("ModBlockFilter");
this.maxVanillaBlockID = maxVanillaBlockID;
this.exceptions = exceptions;
this.replacementBlockID = replacementBlockID;
this.replacementMetadata = replacementMetadata;
}
@Override
protected boolean applyToBlock(int index, short[] blocks, byte[] metadata)
{
int k;
short currentID = blocks[index];
if (currentID > maxVanillaBlockID || (currentID != 0 && Block.blocksList[currentID] == null))
{
//This might be a mod block. Check if an exception exists.
for (k = 0; k < exceptions.length; k++)
{
if (currentID == exceptions[k])
{
//Exception found, not considered a mod block
return false;
}
}
//No matching exception found. Replace the block.
blocks[index] = replacementBlockID;
metadata[index] = replacementMetadata;
return true;
}
return false;
}
@Override
protected boolean terminates()
{
return false;
}
}

View File

@@ -0,0 +1,115 @@
package StevenDimDoors.mod_pocketDim.dungeon;
import java.util.ArrayList;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.schematic.Schematic;
import StevenDimDoors.mod_pocketDim.schematic.SchematicFilter;
public class SpecialBlockFinder extends SchematicFilter {
private short warpDoorID;
private short dimensionalDoorID;
private short monolithSpawnMarkerID;
private short exitMarkerID;
private int entranceOrientation;
private Schematic schematic;
private Point3D entranceDoorLocation;
private ArrayList<Point3D> exitDoorLocations;
private ArrayList<Point3D> dimensionalDoorLocations;
private ArrayList<Point3D> monolithSpawnLocations;
public SpecialBlockFinder(short warpDoorID, short dimensionalDoorID, short monolithSpawnMarkerID, short exitMarkerID)
{
super("SpecialBlockFinder");
this.warpDoorID = warpDoorID;
this.dimensionalDoorID = dimensionalDoorID;
this.monolithSpawnMarkerID = monolithSpawnMarkerID;
this.exitMarkerID = exitMarkerID;
this.entranceDoorLocation = null;
this.entranceOrientation = 0;
this.exitDoorLocations = new ArrayList<Point3D>();
this.dimensionalDoorLocations = new ArrayList<Point3D>();
this.monolithSpawnLocations = new ArrayList<Point3D>();
this.schematic = null;
}
public int getEntranceOrientation() {
return entranceOrientation;
}
public Point3D getEntranceDoorLocation() {
return entranceDoorLocation;
}
public ArrayList<Point3D> getExitDoorLocations() {
return exitDoorLocations;
}
public ArrayList<Point3D> getDimensionalDoorLocations() {
return dimensionalDoorLocations;
}
public ArrayList<Point3D> getMonolithSpawnLocations() {
return monolithSpawnLocations;
}
@Override
protected boolean initialize(Schematic schematic, short[] blocks, byte[] metadata)
{
this.schematic = schematic;
return true;
}
@Override
protected boolean applyToBlock(int index, short[] blocks, byte[] metadata)
{
int indexBelow;
int indexDoubleBelow;
if (blocks[index] == monolithSpawnMarkerID)
{
monolithSpawnLocations.add(schematic.calculatePoint(index));
return true;
}
if (blocks[index] == dimensionalDoorID)
{
indexBelow = schematic.calculateIndexBelow(index);
if (indexBelow >= 0 && blocks[indexBelow] == dimensionalDoorID)
{
dimensionalDoorLocations.add(schematic.calculatePoint(index));
return true;
}
else
{
return false;
}
}
if (blocks[index] == warpDoorID)
{
indexBelow = schematic.calculateIndexBelow(index);
if (indexBelow >= 0 && blocks[indexBelow] == warpDoorID)
{
indexDoubleBelow = schematic.calculateIndexBelow(indexBelow);
if (indexDoubleBelow >= 0 && blocks[indexDoubleBelow] == exitMarkerID)
{
exitDoorLocations.add(schematic.calculatePoint(index));
return true;
}
else if (entranceDoorLocation == null)
{
entranceDoorLocation = schematic.calculatePoint(index);
entranceOrientation = (metadata[indexBelow] & 3);
return true;
}
}
}
return false;
}
@Override
protected boolean terminates()
{
return false;
}
}

View File

@@ -0,0 +1,90 @@
package StevenDimDoors.mod_pocketDim.dungeon.pack;
import java.util.ArrayList;
import java.util.HashMap;
import StevenDimDoors.mod_pocketDim.util.WeightedContainer;
public class DungeonChainRule
{
private final int[] condition;
private final ArrayList<WeightedContainer<DungeonType>> products;
public DungeonChainRule(DungeonChainRuleDefinition source, HashMap<String, DungeonType> nameToTypeMapping)
{
ArrayList<String> conditionNames = source.getCondition();
ArrayList<WeightedContainer<String>> productNames = source.getProducts();
//Validate the data, just in case
if (conditionNames == null)
{
throw new NullPointerException("source cannot have null conditions");
}
if (productNames == null)
{
throw new NullPointerException("source cannot have null products");
}
if (productNames.isEmpty())
{
throw new IllegalArgumentException("products cannot be an empty list");
}
for (WeightedContainer<String> product : productNames)
{
//Check for weights less than 1. Those could cause Minecraft's random selection algorithm to throw an exception.
//At the very least, they're useless values.
if (product.itemWeight < 1)
{
throw new IllegalArgumentException("products cannot contain items with weights less than 1");
}
}
//Obtain the IDs of dungeon types in reverse order. Reverse order makes comparing against chain histories easy.
condition = new int[conditionNames.size()];
for (int src = 0, dst = condition.length - 1; src < condition.length; src++, dst--)
{
condition[dst] = nameToTypeMapping.get(conditionNames.get(src)).ID;
}
products = new ArrayList<WeightedContainer<DungeonType>>(productNames.size());
for (WeightedContainer<String> product : productNames)
{
products.add(new WeightedContainer<DungeonType>(nameToTypeMapping.get(product.getData()), product.itemWeight ));
}
}
public int length()
{
return condition.length;
}
public boolean evaluate(int[] typeHistory)
{
if (typeHistory.length >= condition.length)
{
for (int k = 0; k < condition.length; k++)
{
if (condition[k] != 0 && typeHistory[k] != condition[k])
{
return false;
}
}
return true;
}
else
{
return false;
}
}
public ArrayList<WeightedContainer<DungeonType>> products()
{
//Create a deep copy of the internal list of products. That way, if the list is modified externally,
//it won't affect the reference copy inside this rule.
ArrayList<WeightedContainer<DungeonType>> copy = new ArrayList<WeightedContainer<DungeonType>>(products.size());
for (WeightedContainer<DungeonType> container : products)
{
copy.add(container.clone());
}
return copy;
}
}

View File

@@ -0,0 +1,47 @@
package StevenDimDoors.mod_pocketDim.dungeon.pack;
import java.util.ArrayList;
import StevenDimDoors.mod_pocketDim.util.WeightedContainer;
public class DungeonChainRuleDefinition
{
private ArrayList<String> conditions;
private ArrayList<WeightedContainer<String>> products;
public DungeonChainRuleDefinition(ArrayList<String> conditions, ArrayList<WeightedContainer<String>> products)
{
//Validate the arguments, just in case
if (conditions == null)
{
throw new NullPointerException("conditions cannot be null");
}
if (products.isEmpty())
{
throw new IllegalArgumentException("products cannot be an empty list");
}
for (WeightedContainer<String> product : products)
{
//Check for weights less than 1. Those could cause Minecraft's random selection algorithm to throw an exception.
//At the very least, they're useless values.
if (product.itemWeight < 1)
{
throw new IllegalArgumentException("products cannot contain items with weights less than 1");
}
}
this.conditions = conditions;
this.products = products;
}
public ArrayList<String> getCondition()
{
return conditions;
}
public ArrayList<WeightedContainer<String>> getProducts()
{
return products;
}
}

View File

@@ -0,0 +1,263 @@
package StevenDimDoors.mod_pocketDim.dungeon.pack;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Random;
import net.minecraft.util.WeightedRandom;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.dungeon.DungeonData;
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
import StevenDimDoors.mod_pocketDim.util.WeightedContainer;
public class DungeonPack
{
//There is no precaution against having a dungeon type removed from a config file after dungeons of that type
//have been generated. That would likely cause one or two problems. It's hard to guard against when I don't know
//what the save format will be like completely. How should this class behave if it finds a "disowned" type?
//The ID numbers would be a problem since it couldn't have a valid number, since it wasn't initialized by the pack instance.
//FIXME: Do not release this code as an update without dealing with disowned types!
private static final int MAX_HISTORY_LENGTH = 30;
private final String name;
private final HashMap<String, DungeonType> nameToTypeMapping;
private final ArrayList<ArrayList<DungeonData>> groupedDungeons;
private final ArrayList<DungeonData> allDungeons;
private final DungeonPackConfig config;
private final int maxRuleLength;
private final ArrayList<DungeonChainRule> rules;
public DungeonPack(DungeonPackConfig config)
{
config.validate();
this.config = config.clone(); //Store a clone of the config so that the caller can't change it externally later
this.name = config.getName();
int index;
int maxLength = 0;
int typeCount = config.getTypeNames().size();
this.allDungeons = new ArrayList<DungeonData>();
this.nameToTypeMapping = new HashMap<String, DungeonType>(typeCount);
this.groupedDungeons = new ArrayList<ArrayList<DungeonData>>(typeCount);
this.groupedDungeons.add(allDungeons); //Make sure the list of all dungeons is placed at index 0
this.nameToTypeMapping.put(DungeonType.WILDCARD_TYPE.Name, DungeonType.WILDCARD_TYPE);
index = 1;
for (String typeName : config.getTypeNames())
{
String standardName = typeName.toUpperCase();
this.nameToTypeMapping.put(standardName, new DungeonType(this, standardName, index));
this.groupedDungeons.add(new ArrayList<DungeonData>());
index++;
}
//Construct optimized rules from definitions
ArrayList<DungeonChainRuleDefinition> definitions = config.getRules();
this.rules = new ArrayList<DungeonChainRule>(definitions.size());
for (DungeonChainRuleDefinition definition : definitions)
{
DungeonChainRule rule = new DungeonChainRule(definition, nameToTypeMapping);
this.rules.add(rule);
if (maxLength < rule.length())
{
maxLength = rule.length();
}
}
this.maxRuleLength = maxLength;
//Remove unnecessary references to save a little memory - we won't need them here
this.config.setRules(null);
this.config.setTypeNames(null);
}
public String getName()
{
return name;
}
public DungeonPackConfig getConfig()
{
return config.clone();
}
public boolean isEmpty()
{
return allDungeons.isEmpty();
}
public DungeonType getType(String typeName)
{
DungeonType result = nameToTypeMapping.get(typeName.toUpperCase());
if (result.Owner == this) //Filter out the wildcard dungeon type
{
return result;
}
else
{
return null;
}
}
public boolean isKnownType(String typeName)
{
return (this.getType(typeName) != null);
}
public void addDungeon(DungeonData dungeon)
{
//Make sure this dungeon really belongs in this pack
DungeonType type = dungeon.dungeonType();
if (type.Owner == this)
{
allDungeons.add(dungeon);
groupedDungeons.get(type.ID).add(dungeon);
}
else
{
throw new IllegalArgumentException("The dungeon type of generator must belong to this instance of DungeonPack.");
}
}
public DungeonData getNextDungeon(NewDimData dimension, Random random)
{
if (allDungeons.isEmpty())
{
return null;
}
//Retrieve a list of the previous dungeons in this chain.
//If we're not going to check for duplicates in chains, restrict the length of the history to the length
//of the longest rule we have. Getting any more data would be useless. This optimization could be significant
//for dungeon packs that can extend arbitrarily deep. We should probably set a reasonable limit anyway.
int maxSearchLength = config.allowDuplicatesInChain() ? maxRuleLength : MAX_HISTORY_LENGTH;
ArrayList<DungeonData> history = DungeonHelper.getDungeonChainHistory(dimension.parent(), this, maxSearchLength);
return getNextDungeon(history, random);
}
private DungeonData getNextDungeon(ArrayList<DungeonData> history, Random random)
{
//Extract the dungeon types that have been used from history and convert them into an array of IDs
int index;
int[] typeHistory = new int[history.size()];
HashSet<DungeonData> excludedDungeons = null;
for (index = 0; index < typeHistory.length; index++)
{
typeHistory[index] = history.get(index).dungeonType().ID;
}
for (DungeonChainRule rule : rules)
{
if (rule.evaluate(typeHistory))
{
//Pick a random dungeon type to be generated next based on the rule's products
ArrayList<WeightedContainer<DungeonType>> products = rule.products();
DungeonType nextType;
do
{
nextType = getRandomDungeonType(random, products, groupedDungeons);
if (nextType != null)
{
//Initialize the set of excluded dungeons if needed
if (excludedDungeons == null && !config.allowDuplicatesInChain())
{
excludedDungeons = new HashSet<DungeonData>(history);
}
//List which dungeons are allowed
ArrayList<DungeonData> candidates;
ArrayList<DungeonData> group = groupedDungeons.get(nextType.ID);
if (excludedDungeons != null && !excludedDungeons.isEmpty())
{
candidates = new ArrayList<DungeonData>(group.size());
for (DungeonData dungeon : group)
{
if (!excludedDungeons.contains(dungeon))
{
candidates.add(dungeon);
}
}
}
else
{
candidates = group;
}
if (!candidates.isEmpty())
{
return getRandomDungeon(random, candidates);
}
//If we've reached this point, then a dungeon was not selected. Discard the type and try again.
products.remove(nextType);
}
}
while (nextType != null);
}
}
//None of the rules were applicable. Simply return a random dungeon.
return getRandomDungeon(random);
}
public DungeonData getRandomDungeon(Random random)
{
if (!allDungeons.isEmpty())
{
return getRandomDungeon(random, allDungeons);
}
else
{
return null;
}
}
private static DungeonType getRandomDungeonType(Random random, Collection<WeightedContainer<DungeonType>> types,
ArrayList<ArrayList<DungeonData>> groupedDungeons)
{
//TODO: Make this faster? This algorithm runs in quadratic time in the worst case because of the random-selection
//process and the removal search. Might be okay for normal use, though. ~SenseiKiwi
//Pick a random dungeon type based on weights. Repeat this process until a non-empty group is found or all groups are checked.
while (!types.isEmpty())
{
//Pick a random dungeon type
@SuppressWarnings("unchecked")
WeightedContainer<DungeonType> resultContainer = (WeightedContainer<DungeonType>) WeightedRandom.getRandomItem(random, types);
//Check if there are any dungeons of that type
DungeonType selectedType = resultContainer.getData();
if (!groupedDungeons.get(selectedType.ID).isEmpty())
{
//Choose this type
return selectedType;
}
else
{
//We can't use this type because there are no dungeons of this type
//Remove it from the list of types and try again
types.remove(resultContainer);
}
}
//We have run out of types to try
return null;
}
private static DungeonData getRandomDungeon(Random random, Collection<DungeonData> dungeons)
{
//Use Minecraft's WeightedRandom to select our dungeon. =D
ArrayList<WeightedContainer<DungeonData>> weights =
new ArrayList<WeightedContainer<DungeonData>>(dungeons.size());
for (DungeonData dungeon : dungeons)
{
weights.add(new WeightedContainer<DungeonData>(dungeon, dungeon.weight()));
}
@SuppressWarnings("unchecked")
WeightedContainer<DungeonData> resultContainer = (WeightedContainer<DungeonData>) WeightedRandom.getRandomItem(random, weights);
return (resultContainer != null) ? resultContainer.getData() : null;
}
}

View File

@@ -0,0 +1,126 @@
package StevenDimDoors.mod_pocketDim.dungeon.pack;
import java.util.ArrayList;
public class DungeonPackConfig
{
private String name;
private ArrayList<String> typeNames;
private boolean allowDuplicatesInChain;
private boolean allowPackChangeIn;
private boolean allowPackChangeOut;
private boolean distortDoorCoordinates;
private int packWeight;
private ArrayList<DungeonChainRuleDefinition> rules;
public DungeonPackConfig() { }
@SuppressWarnings("unchecked")
private DungeonPackConfig(DungeonPackConfig source)
{
this.name = (source.name != null) ? source.name : null;
this.typeNames = (source.typeNames != null) ? (ArrayList<String>) source.typeNames.clone() : null;
this.allowDuplicatesInChain = source.allowDuplicatesInChain;
this.allowPackChangeIn = source.allowPackChangeIn;
this.allowPackChangeOut = source.allowPackChangeOut;
this.distortDoorCoordinates = source.distortDoorCoordinates;
this.packWeight = source.packWeight;
this.rules = (source.rules != null) ? (ArrayList<DungeonChainRuleDefinition>) source.rules.clone() : null;
}
public void validate()
{
if (this.name == null)
throw new NullPointerException("name cannot be null");
if (this.typeNames == null)
throw new NullPointerException("typeNames cannot be null");
if (this.rules == null)
throw new NullPointerException("rules cannot be null");
}
@Override
public DungeonPackConfig clone()
{
return new DungeonPackConfig(this);
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public ArrayList<String> getTypeNames()
{
return typeNames;
}
public void setTypeNames(ArrayList<String> typeNames)
{
this.typeNames = typeNames;
}
public boolean allowDuplicatesInChain()
{
return allowDuplicatesInChain;
}
public void setAllowDuplicatesInChain(boolean value)
{
allowDuplicatesInChain = value;
}
public void setRules(ArrayList<DungeonChainRuleDefinition> rules)
{
this.rules = rules;
}
public ArrayList<DungeonChainRuleDefinition> getRules()
{
return rules;
}
public boolean allowPackChangeIn()
{
return allowPackChangeIn;
}
public void setAllowPackChangeIn(boolean value)
{
this.allowPackChangeIn = value;
}
public boolean allowPackChangeOut()
{
return allowPackChangeOut;
}
public void setAllowPackChangeOut(boolean value)
{
this.allowPackChangeOut = value;
}
public int getPackWeight()
{
return packWeight;
}
public void setPackWeight(int packWeight)
{
this.packWeight = packWeight;
}
public boolean doDistortDoorCoordinates()
{
return distortDoorCoordinates;
}
public void setDistortDoorCoordinates(boolean value)
{
this.distortDoorCoordinates = value;
}
}

View File

@@ -0,0 +1,412 @@
package StevenDimDoors.mod_pocketDim.dungeon.pack;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import StevenDimDoors.mod_pocketDim.util.BaseConfigurationProcessor;
import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException;
import StevenDimDoors.mod_pocketDim.util.WeightedContainer;
import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.common.primitives.Ints;
public class DungeonPackConfigReader extends BaseConfigurationProcessor<DungeonPackConfig>
{
private interface ILineProcessor
{
public void process(String line, DungeonPackConfig config) throws ConfigurationProcessingException;
}
//Note: These constants aren't static so that the memory will be released once
//we're done using it an instance. These aren't objects that we need to hold
//onto throughout the lifetime of MC, only at loading time.
private final int CONFIG_VERSION = 1;
private final int LOOKAHEAD_LIMIT = 1024;
private final int MAX_PRODUCT_WEIGHT = 10000;
private final int MIN_PRODUCT_WEIGHT = 1;
private final int DEFAULT_PRODUCT_WEIGHT = 100;
private final int MAX_DUNGEON_PACK_WEIGHT = 10000;
private final int MIN_DUNGEON_PACK_WEIGHT = 1;
private final int DEFAULT_DUNGEON_PACK_WEIGHT = 100;
private final int MAX_CONDITION_LENGTH = 20;
private final int MAX_PRODUCT_COUNT = MAX_CONDITION_LENGTH;
private final String COMMENT_MARKER = "##";
private final Pattern DUNGEON_TYPE_PATTERN = Pattern.compile("[A-Za-z0-9_\\-]{1,20}");
private final Splitter WHITESPACE_SPLITTER = Splitter.on(CharMatcher.WHITESPACE).omitEmptyStrings();
private final String SETTING_SEPARATOR = "=";
private final String RULE_SEPARATOR = "->";
private final String WEIGHT_SEPARATOR = "#";
public DungeonPackConfigReader() { }
@SuppressWarnings("resource")
@Override
public DungeonPackConfig readFromStream(InputStream inputStream) throws ConfigurationProcessingException
{
BufferedReader reader = null;
try
{
DungeonPackConfig config = new DungeonPackConfig();
reader = new BufferedReader(new InputStreamReader(inputStream));
//Check the config format version
int version = readVersion(reader);
if (version != CONFIG_VERSION)
{
throw new ConfigurationProcessingException("The dungeon pack config has an incompatible version.");
}
config.setTypeNames(new ArrayList<String>());
config.setRules(new ArrayList<DungeonChainRuleDefinition>());
//Read the dungeon types
if (findSection("Types", reader))
{
processLines(reader, config, new DungeonTypeProcessor());
}
//Load default settings
config.setAllowDuplicatesInChain(true);
config.setAllowPackChangeIn(true);
config.setAllowPackChangeOut(true);
config.setDistortDoorCoordinates(false);
config.setPackWeight(DEFAULT_DUNGEON_PACK_WEIGHT);
//Read the settings section
if (findSection("Settings", reader))
{
processLines(reader, config, new DungeonSettingsParser());
}
//Read the rules section
if (findSection("Rules", reader))
{
processLines(reader, config, new RuleDefinitionParser());
}
return config;
}
catch (ConfigurationProcessingException ex)
{
throw ex;
}
catch (Exception ex)
{
throw new ConfigurationProcessingException("An unexpected error occurred while trying to read the configuration file.", ex);
}
finally
{
if (reader != null)
{
try
{
reader.close();
}
catch (IOException ex) { }
}
}
}
private int readVersion(BufferedReader reader) throws ConfigurationProcessingException, IOException
{
String firstLine = reader.readLine();
String[] parts = firstLine.split("\\s", 0);
Integer version = null;
if (parts.length == 2 && parts[0].equalsIgnoreCase("version"))
{
version = Ints.tryParse(parts[1]);
}
if (version == null)
{
throw new ConfigurationProcessingException("Could not parse the config format version.");
}
return version;
}
private void processLines(BufferedReader reader, DungeonPackConfig config, ILineProcessor processor) throws IOException, ConfigurationProcessingException
{
String line;
while (reader.ready())
{
reader.mark(LOOKAHEAD_LIMIT);
line = reader.readLine();
if (!line.startsWith(COMMENT_MARKER))
{
line = line.trim();
if (line.length() > 0)
{
if (line.endsWith(":"))
{
//Consider this line a section header, reset the reader to undo consuming it
reader.reset();
break;
}
else
{
processor.process(line, config);
}
}
}
}
}
private boolean findSection(String name, BufferedReader reader) throws IOException, ConfigurationProcessingException
{
boolean found = false;
boolean matched = false;
String line = null;
String label = name + ":";
//Find the next section header
//Ignore blank lines and comment lines, stop for headers, and throw an exception for anything else
while (!found && reader.ready())
{
reader.mark(LOOKAHEAD_LIMIT);
line = reader.readLine();
if (!line.startsWith(COMMENT_MARKER))
{
line = line.trim();
if (line.length() > 0)
{
if (line.endsWith(":"))
{
//Consider this line a section header
found = true;
matched = line.equalsIgnoreCase(label);
}
else
{
//This line is invalid
throw new ConfigurationProcessingException("The dungeon pack config has an incorrect line where a section was expected: " + line);
}
}
}
}
//Check if the header matches the one we're looking for.
//If it doesn't match, undo consuming the line so it can be read later.
if (found && !matched)
{
reader.reset();
}
return found;
}
private class DungeonTypeProcessor implements ILineProcessor
{
@Override
public void process(String line, DungeonPackConfig config) throws ConfigurationProcessingException
{
List<String> typeNames = config.getTypeNames();
//Check if the dungeon type has a name that meets our restrictions
if (DUNGEON_TYPE_PATTERN.matcher(line).matches())
{
//Ignore duplicate dungeon types
line = line.toUpperCase();
if (!typeNames.contains(line))
{
typeNames.add(line);
}
}
else
{
throw new ConfigurationProcessingException("The dungeon pack config has a dungeon type with illegal characters in its name: " + line);
}
}
}
private class DungeonSettingsParser implements ILineProcessor
{
@Override
public void process(String line, DungeonPackConfig config) throws ConfigurationProcessingException
{
//The various settings that we support will be hardcoded here.
//In the future, if we get more settings, then this should be
//refactored to use a more lookup-driven approach.
boolean valid = true;
String[] settingParts = line.split(SETTING_SEPARATOR, 2);
if (settingParts.length == 2)
{
try
{
String name = settingParts[0].trim();
String value = settingParts[1].trim();
if (name.equalsIgnoreCase("AllowDuplicatesInChain"))
{
config.setAllowDuplicatesInChain(parseBoolean(value));
}
else if (name.equalsIgnoreCase("AllowPackChangeOut"))
{
config.setAllowPackChangeOut(parseBoolean(value));
}
else if (name.equalsIgnoreCase("AllowPackChangeIn"))
{
config.setAllowPackChangeIn(parseBoolean(value));
}
else if (name.equalsIgnoreCase("DistortDoorCoordinates"))
{
config.setDistortDoorCoordinates(parseBoolean(value));
}
else if (name.equalsIgnoreCase("PackWeight"))
{
int weight = Integer.parseInt(value);
if (weight >= MIN_DUNGEON_PACK_WEIGHT && weight <= MAX_DUNGEON_PACK_WEIGHT)
{
config.setPackWeight(weight);
}
else
{
valid = false;
}
}
else
{
valid = false;
}
}
catch (Exception e)
{
valid = false;
}
}
else
{
valid = false;
}
if (!valid)
{
throw new ConfigurationProcessingException("The dungeon pack config has an invalid setting: " + line);
}
}
}
private class RuleDefinitionParser implements ILineProcessor
{
@Override
public void process(String definition, DungeonPackConfig config) throws ConfigurationProcessingException
{
String[] ruleParts;
String[] productParts;
String ruleCondition;
String ruleProduct;
ArrayList<String> condition;
ArrayList<WeightedContainer<String>> products;
List<String> typeNames = config.getTypeNames();
ruleParts = definition.toUpperCase().split(RULE_SEPARATOR, -1);
if (ruleParts.length != 2)
{
throw new ConfigurationProcessingException("The dungeon pack config has an invalid rule: " + definition);
}
ruleCondition = ruleParts[0];
ruleProduct = ruleParts[1];
condition = new ArrayList<String>();
products = new ArrayList<WeightedContainer<String>>();
for (String typeName : WHITESPACE_SPLITTER.split(ruleCondition))
{
if (isKnownDungeonType(typeName, typeNames))
{
condition.add(typeName);
}
else
{
throw new ConfigurationProcessingException("The dungeon pack config has a rule condition with an unknown dungeon type: " + typeName);
}
if (condition.size() > MAX_CONDITION_LENGTH)
{
throw new ConfigurationProcessingException("The dungeon pack config has a rule condition that is too long: " + definition);
}
}
for (String product : WHITESPACE_SPLITTER.split(ruleProduct))
{
Integer weight;
String typeName;
productParts = product.split(WEIGHT_SEPARATOR, -1);
if (productParts.length > 2 || productParts.length == 0)
{
throw new ConfigurationProcessingException("The dungeon pack config has a rule with an invalid product: " + product);
}
typeName = productParts[0];
if (isKnownDungeonType(typeName, typeNames))
{
if (productParts.length > 1)
{
weight = Ints.tryParse(productParts[1]);
if (weight == null || (weight > MAX_PRODUCT_WEIGHT) || (weight < MIN_PRODUCT_WEIGHT))
{
throw new ConfigurationProcessingException("The dungeon pack config has a rule with an invalid product weight: " + product);
}
}
else
{
weight = DEFAULT_PRODUCT_WEIGHT;
}
products.add(new WeightedContainer<String>(typeName, weight));
}
else
{
throw new ConfigurationProcessingException("The dungeon pack config has an unknown dungeon type in a rule: " + typeName);
}
if (products.size() > MAX_PRODUCT_COUNT)
{
throw new ConfigurationProcessingException("The dungeon pack config has a rule with too many products: " + definition);
}
}
if (products.isEmpty())
{
throw new ConfigurationProcessingException("The dungeon pack config has a rule with no products: " + definition);
}
config.getRules().add( new DungeonChainRuleDefinition(condition, products) );
}
}
private static boolean isKnownDungeonType(String typeName, List<String> typeNames)
{
return typeName.equals(DungeonType.WILDCARD_TYPE.Name) || typeNames.contains(typeName);
}
private static boolean parseBoolean(String value)
{
if (value.equalsIgnoreCase("true"))
return true;
if (value.equalsIgnoreCase("false"))
return false;
throw new IllegalArgumentException("The boolean value must be either \"true\" or \"false\", ignoring case.");
}
@Override
public boolean canWrite()
{
return false;
}
@Override
public void writeToStream(OutputStream outputStream, DungeonPackConfig data) throws ConfigurationProcessingException
{
throw new UnsupportedOperationException("DungeonPackConfigReader does not support writing.");
}
}

View File

@@ -0,0 +1,48 @@
package StevenDimDoors.mod_pocketDim.dungeon.pack;
public class DungeonType implements Comparable<DungeonType>
{
public static final DungeonType WILDCARD_TYPE = new DungeonType(null, "?", 0);
public static final DungeonType UNKNOWN_TYPE = new DungeonType(null, "!", -1);
public final DungeonPack Owner;
public final String Name;
public final int ID;
public DungeonType(DungeonPack owner, String name, int id)
{
Owner = owner;
Name = name;
this.ID = id;
}
@Override
public int compareTo(DungeonType other)
{
return this.ID - other.ID;
}
@Override
public boolean equals(Object other)
{
return equals((DungeonType) other);
}
public boolean equals(DungeonType other)
{
if (this == other)
return true;
if (this == null || other == null)
return false;
return (this.ID == other.ID);
}
@Override
public int hashCode()
{
final int prime = 2039;
return prime * ID;
}
}

View File

@@ -0,0 +1,412 @@
package StevenDimDoors.mod_pocketDim.helpers;
import java.util.HashMap;
import net.minecraft.block.Block;
public class BlockRotationHelper
{
public HashMap<Integer,HashMap<Integer,HashMap<Integer,Integer>>> rotationMappings = new HashMap<Integer,HashMap<Integer,HashMap<Integer,Integer>>>();
public BlockRotationHelper()
{
this.InitializeRotationMap();
}
public void InitializeRotationMap()
{
HashMap<Integer,HashMap<Integer, Integer>> orientation0 = new HashMap<Integer,HashMap<Integer, Integer>>();
HashMap<Integer,Integer> stairs0 = new HashMap<Integer,Integer>();
stairs0.put(0, 2);
stairs0.put(1, 3);
stairs0.put(2, 1);
stairs0.put(3, 0);
stairs0.put(7, 4);
stairs0.put(6, 5);
stairs0.put(5, 7);
stairs0.put(4, 6);
HashMap<Integer,Integer> chestsLadders0 = new HashMap<Integer,Integer>();
chestsLadders0.put(2, 5);
chestsLadders0.put(3, 4);
chestsLadders0.put(4, 2);
chestsLadders0.put(5, 3);
HashMap<Integer,Integer> vine0 = new HashMap<Integer,Integer>();
vine0.put(1, 2);
vine0.put(2, 4);
vine0.put(4, 8);
vine0.put(8, 1);
HashMap<Integer,Integer> leverButtonTorch0 = new HashMap<Integer,Integer>();
leverButtonTorch0.put(12, 9);
leverButtonTorch0.put(11, 10);
leverButtonTorch0.put(10, 12);
leverButtonTorch0.put(9, 11);
leverButtonTorch0.put(2, 4);
leverButtonTorch0.put(3, 2);
leverButtonTorch0.put(1, 3);
leverButtonTorch0.put(4, 1);
HashMap<Integer,Integer> pistonDropperDispenser0 = new HashMap<Integer,Integer>();
pistonDropperDispenser0.put(4, 2);
pistonDropperDispenser0.put(5, 3);
pistonDropperDispenser0.put(13, 11);
pistonDropperDispenser0.put(3, 4);
pistonDropperDispenser0.put(2, 5);
pistonDropperDispenser0.put(11, 12);
pistonDropperDispenser0.put(10, 13);
pistonDropperDispenser0.put(12, 10);
HashMap<Integer,Integer> repeaterComparatorDoorTripwire0 = new HashMap<Integer,Integer>();
repeaterComparatorDoorTripwire0.put(0, 1);
repeaterComparatorDoorTripwire0.put(1, 2);
repeaterComparatorDoorTripwire0.put(2, 3);
repeaterComparatorDoorTripwire0.put(3, 0);
repeaterComparatorDoorTripwire0.put(4, 5);
repeaterComparatorDoorTripwire0.put(5, 6);
repeaterComparatorDoorTripwire0.put(6, 7);
repeaterComparatorDoorTripwire0.put(7, 4);
repeaterComparatorDoorTripwire0.put(8, 9);
repeaterComparatorDoorTripwire0.put(9, 10);
repeaterComparatorDoorTripwire0.put(10, 11);
repeaterComparatorDoorTripwire0.put(11, 8);
repeaterComparatorDoorTripwire0.put(12, 13);
repeaterComparatorDoorTripwire0.put(13, 14);
repeaterComparatorDoorTripwire0.put(14, 15);
repeaterComparatorDoorTripwire0.put(15, 12);
HashMap<Integer,Integer> rails0 = new HashMap<Integer,Integer>();
rails0.put(0, 1);
rails0.put(1, 0);
rails0.put(8, 9);
rails0.put(9, 6);
rails0.put(6, 7);
rails0.put(7, 8);
HashMap<Integer,Integer> railsSpecial0 = new HashMap<Integer,Integer>();
railsSpecial0.put(0, 1);
railsSpecial0.put(1, 0);
railsSpecial0.put(8, 9);
railsSpecial0.put(9, 8);
HashMap<Integer,HashMap<Integer, Integer>> orientation1 = new HashMap<Integer,HashMap<Integer, Integer>>();
HashMap<Integer,Integer> stairs1 = new HashMap<Integer,Integer>();
stairs1.put(0, 1);
stairs1.put(1, 0);
stairs1.put(2, 3);
stairs1.put(3, 2);
stairs1.put(7, 6);
stairs1.put(6, 7);
stairs1.put(5, 4);
stairs1.put(4, 5);
HashMap<Integer,Integer> chestsLadders1 = new HashMap<Integer,Integer>();
chestsLadders1.put(2, 3);
chestsLadders1.put(3, 2);
chestsLadders1.put(4, 5);
chestsLadders1.put(5, 4);
HashMap<Integer,Integer> vine1 = new HashMap<Integer,Integer>();
vine1.put(1, 4);
vine1.put(2, 8);
vine1.put(4, 1);
vine1.put(8, 2);
HashMap<Integer,Integer> leverButtonTorch1 = new HashMap<Integer,Integer>();
leverButtonTorch1.put(12, 9);
leverButtonTorch1.put(11, 10);
leverButtonTorch1.put(10, 12);
leverButtonTorch1.put(9, 11);
leverButtonTorch1.put(2, 4);
leverButtonTorch1.put(3, 2);
leverButtonTorch1.put(1, 3);
leverButtonTorch1.put(4, 1);
HashMap<Integer,Integer> pistonDropperDispenser1 = new HashMap<Integer,Integer>();
pistonDropperDispenser1.put(12, 11);
pistonDropperDispenser1.put(11, 12);
pistonDropperDispenser1.put(10, 9);
pistonDropperDispenser1.put(9, 10);
pistonDropperDispenser1.put(2, 1);
pistonDropperDispenser1.put(3, 4);
pistonDropperDispenser1.put(1, 2);
pistonDropperDispenser1.put(4,3);
HashMap<Integer,Integer> repeaterComparatorDoorTripwire1 = new HashMap<Integer,Integer>();
repeaterComparatorDoorTripwire1.put(0, 2);
repeaterComparatorDoorTripwire1.put(1, 3);
repeaterComparatorDoorTripwire1.put(2, 0);
repeaterComparatorDoorTripwire1.put(3, 1);
repeaterComparatorDoorTripwire1.put(4, 6);
repeaterComparatorDoorTripwire1.put(5, 7);
repeaterComparatorDoorTripwire1.put(6, 4);
repeaterComparatorDoorTripwire1.put(7, 5);
repeaterComparatorDoorTripwire1.put(8, 10);
repeaterComparatorDoorTripwire1.put(9, 11);
repeaterComparatorDoorTripwire1.put(10, 8);
repeaterComparatorDoorTripwire1.put(11, 9);
repeaterComparatorDoorTripwire1.put(12, 14);
repeaterComparatorDoorTripwire1.put(13, 15);
repeaterComparatorDoorTripwire1.put(14, 12);
repeaterComparatorDoorTripwire1.put(15, 13);
HashMap<Integer,Integer> rails1 = new HashMap<Integer,Integer>();
rails1.put(0, 0);
rails1.put(1, 1);
rails1.put(8, 6);
rails1.put(9, 7);
rails1.put(6, 8);
rails1.put(7, 9);
HashMap<Integer,Integer> railsSpecial1 = new HashMap<Integer,Integer>();
railsSpecial1.put(1, 1);
railsSpecial1.put(0, 0);
railsSpecial1.put(8, 8);
railsSpecial1.put(9, 9);
HashMap<Integer,HashMap<Integer, Integer>> orientation2 = new HashMap<Integer,HashMap<Integer, Integer>>();
HashMap<Integer,Integer> stairs2 = new HashMap<Integer,Integer>();
stairs2.put(2, 0);
stairs2.put(3, 1);
stairs2.put(1, 2);
stairs2.put(0, 3);
stairs2.put(4, 7);
stairs2.put(5, 6);
stairs2.put(7, 5);
stairs2.put(6, 4);
HashMap<Integer,Integer> chestsLadders2 = new HashMap<Integer,Integer>();
chestsLadders2.put(2, 4);
chestsLadders2.put(3, 5);
chestsLadders2.put(4, 3);
chestsLadders2.put(5, 2);
HashMap<Integer,Integer> vine2 = new HashMap<Integer,Integer>();
vine2.put(1, 8);
vine2.put(2, 1);
vine2.put(4, 2);
vine2.put(8, 4);
HashMap<Integer,Integer> leverButtonTorch2 = new HashMap<Integer,Integer>();
leverButtonTorch2.put(9, 12);
leverButtonTorch2.put(10, 11);
leverButtonTorch2.put(12, 10);
leverButtonTorch2.put(11, 9);
leverButtonTorch2.put(4, 2);
leverButtonTorch2.put(2, 3);
leverButtonTorch2.put(3, 1);
leverButtonTorch2.put(1, 4);
HashMap<Integer,Integer> pistonDropperDispenser2 = new HashMap<Integer,Integer>();
pistonDropperDispenser2.put(2, 4);
pistonDropperDispenser2.put(3, 5);
pistonDropperDispenser2.put(11, 13);
pistonDropperDispenser2.put(10, 12);
pistonDropperDispenser2.put(4, 3);
pistonDropperDispenser2.put(5, 2);
pistonDropperDispenser2.put(12, 11);
pistonDropperDispenser2.put(13,10);
HashMap<Integer,Integer> repeaterComparatorDoorTripwire2 = new HashMap<Integer,Integer>();
repeaterComparatorDoorTripwire2.put(1, 0);
repeaterComparatorDoorTripwire2.put(2, 1);
repeaterComparatorDoorTripwire2.put(3, 2);
repeaterComparatorDoorTripwire2.put(0, 3);
repeaterComparatorDoorTripwire2.put(5, 4);
repeaterComparatorDoorTripwire2.put(6, 5);
repeaterComparatorDoorTripwire2.put(7, 6);
repeaterComparatorDoorTripwire2.put(4, 7);
repeaterComparatorDoorTripwire2.put(9, 8);
repeaterComparatorDoorTripwire2.put(10, 9);
repeaterComparatorDoorTripwire2.put(11, 10);
repeaterComparatorDoorTripwire2.put(8, 11);
repeaterComparatorDoorTripwire2.put(13, 12);
repeaterComparatorDoorTripwire2.put(14, 13);
repeaterComparatorDoorTripwire2.put(15, 14);
repeaterComparatorDoorTripwire2.put(12, 15);
HashMap<Integer,Integer> rails2 = new HashMap<Integer,Integer>();
rails2.put(0, 1);
rails2.put(1, 0);
rails2.put(8, 7);
rails2.put(9, 8);
rails2.put(6, 9);
rails2.put(7, 6);
HashMap<Integer,Integer> railsSpecial2 = new HashMap<Integer,Integer>();
railsSpecial2.put(0, 1);
railsSpecial2.put(1, 0);
railsSpecial2.put(8, 9);
railsSpecial2.put(9, 8);
orientation0.put(Block.stairsBrick.blockID, stairs0);
orientation0.put(Block.stairsCobblestone.blockID, stairs0);
orientation0.put(Block.stairsNetherBrick.blockID, stairs0);
orientation0.put(Block.stairsNetherQuartz.blockID, stairs0);
orientation0.put(Block.stairsSandStone.blockID, stairs0);
orientation0.put(Block.stairsStoneBrick.blockID, stairs0);
orientation0.put(Block.stairsWoodBirch.blockID, stairs0);
orientation0.put(Block.stairsWoodJungle.blockID, stairs0);
orientation0.put(Block.stairsWoodOak.blockID, stairs0);
orientation0.put(Block.stairsWoodSpruce.blockID, stairs0);
orientation0.put(Block.stairsBrick.blockID, stairs0);
orientation0.put(Block.vine.blockID, vine0);
orientation0.put(Block.chest.blockID, chestsLadders0);
orientation0.put(Block.chestTrapped.blockID, chestsLadders0);
orientation0.put(Block.ladder.blockID, chestsLadders0);
orientation0.put(Block.lever.blockID, leverButtonTorch0);
orientation0.put(Block.stoneButton.blockID, leverButtonTorch0);
orientation0.put(Block.woodenButton.blockID, leverButtonTorch0);
orientation0.put(Block.torchRedstoneActive.blockID, leverButtonTorch0);
orientation0.put(Block.torchRedstoneIdle.blockID, leverButtonTorch0);
orientation0.put(Block.torchWood.blockID, leverButtonTorch0);
orientation0.put(Block.pistonBase.blockID,pistonDropperDispenser0);
orientation0.put(Block.pistonExtension.blockID,pistonDropperDispenser0);
orientation0.put(Block.pistonMoving.blockID,pistonDropperDispenser0);
orientation0.put(Block.pistonStickyBase.blockID,pistonDropperDispenser0);
orientation0.put(Block.dropper.blockID,pistonDropperDispenser0);
orientation0.put(Block.dispenser.blockID,pistonDropperDispenser0);
orientation0.put(Block.redstoneComparatorActive.blockID,pistonDropperDispenser0);
orientation0.put(Block.redstoneComparatorIdle.blockID,pistonDropperDispenser0);
orientation0.put(Block.redstoneRepeaterActive.blockID,pistonDropperDispenser0);
orientation0.put(Block.redstoneRepeaterIdle.blockID,pistonDropperDispenser0);
orientation0.put(Block.doorWood.blockID,pistonDropperDispenser0);
orientation0.put(Block.doorIron.blockID,pistonDropperDispenser0);
orientation0.put(Block.tripWireSource.blockID,pistonDropperDispenser0);
orientation0.put(Block.railDetector.blockID,railsSpecial0);
orientation0.put(Block.railActivator.blockID,railsSpecial0);
orientation0.put(Block.railPowered.blockID,railsSpecial0);
orientation0.put(Block.rail.blockID,rails0);
orientation1.put(Block.stairsBrick.blockID, stairs1);
orientation1.put(Block.stairsCobblestone.blockID, stairs1);
orientation1.put(Block.stairsNetherBrick.blockID, stairs1);
orientation1.put(Block.stairsNetherQuartz.blockID, stairs1);
orientation1.put(Block.stairsSandStone.blockID, stairs1);
orientation1.put(Block.stairsStoneBrick.blockID, stairs1);
orientation1.put(Block.stairsWoodBirch.blockID, stairs1);
orientation1.put(Block.stairsWoodJungle.blockID, stairs1);
orientation1.put(Block.stairsWoodOak.blockID, stairs1);
orientation1.put(Block.stairsWoodSpruce.blockID, stairs1);
orientation1.put(Block.stairsBrick.blockID, stairs1);
orientation1.put(Block.vine.blockID, vine1);
orientation1.put(Block.chest.blockID, chestsLadders1);
orientation1.put(Block.chestTrapped.blockID, chestsLadders1);
orientation1.put(Block.ladder.blockID, chestsLadders1);
orientation1.put(Block.lever.blockID, leverButtonTorch1);
orientation1.put(Block.stoneButton.blockID, leverButtonTorch1);
orientation1.put(Block.woodenButton.blockID, leverButtonTorch1);
orientation1.put(Block.torchRedstoneActive.blockID, leverButtonTorch1);
orientation1.put(Block.torchRedstoneIdle.blockID, leverButtonTorch1);
orientation1.put(Block.torchWood.blockID, leverButtonTorch1);
orientation1.put(Block.pistonBase.blockID,pistonDropperDispenser1);
orientation1.put(Block.pistonExtension.blockID,pistonDropperDispenser1);
orientation1.put(Block.pistonMoving.blockID,pistonDropperDispenser1);
orientation1.put(Block.pistonStickyBase.blockID,pistonDropperDispenser1);
orientation1.put(Block.dropper.blockID,pistonDropperDispenser1);
orientation1.put(Block.dispenser.blockID,pistonDropperDispenser1);
orientation1.put(Block.redstoneComparatorActive.blockID,pistonDropperDispenser1);
orientation1.put(Block.redstoneComparatorIdle.blockID,pistonDropperDispenser1);
orientation1.put(Block.redstoneRepeaterActive.blockID,pistonDropperDispenser1);
orientation1.put(Block.redstoneRepeaterIdle.blockID,pistonDropperDispenser1);
orientation1.put(Block.doorWood.blockID,pistonDropperDispenser1);
orientation1.put(Block.doorIron.blockID,pistonDropperDispenser1);
orientation1.put(Block.tripWireSource.blockID,pistonDropperDispenser1);
orientation1.put(Block.railDetector.blockID,railsSpecial1);
orientation1.put(Block.railActivator.blockID,railsSpecial1);
orientation1.put(Block.railPowered.blockID,railsSpecial1);
orientation1.put(Block.rail.blockID,rails1);
orientation2.put(Block.stairsBrick.blockID, stairs2);
orientation2.put(Block.stairsCobblestone.blockID, stairs2);
orientation2.put(Block.stairsNetherBrick.blockID, stairs2);
orientation2.put(Block.stairsNetherQuartz.blockID, stairs2);
orientation2.put(Block.stairsSandStone.blockID, stairs2);
orientation2.put(Block.stairsStoneBrick.blockID, stairs2);
orientation2.put(Block.stairsWoodBirch.blockID, stairs2);
orientation2.put(Block.stairsWoodJungle.blockID, stairs2);
orientation2.put(Block.stairsWoodOak.blockID, stairs2);
orientation2.put(Block.stairsWoodSpruce.blockID, stairs2);
orientation2.put(Block.stairsBrick.blockID, stairs2);
orientation2.put(Block.vine.blockID, vine2);
orientation2.put(Block.chest.blockID, chestsLadders2);
orientation2.put(Block.chestTrapped.blockID, chestsLadders2);
orientation2.put(Block.ladder.blockID, chestsLadders2);
orientation2.put(Block.lever.blockID, leverButtonTorch2);
orientation2.put(Block.stoneButton.blockID, leverButtonTorch2);
orientation2.put(Block.woodenButton.blockID, leverButtonTorch2);
orientation2.put(Block.torchRedstoneActive.blockID, leverButtonTorch2);
orientation2.put(Block.torchRedstoneIdle.blockID, leverButtonTorch2);
orientation2.put(Block.torchWood.blockID, leverButtonTorch2);
orientation2.put(Block.pistonBase.blockID,pistonDropperDispenser2);
orientation2.put(Block.pistonExtension.blockID,pistonDropperDispenser2);
orientation2.put(Block.pistonMoving.blockID,pistonDropperDispenser2);
orientation2.put(Block.pistonStickyBase.blockID,pistonDropperDispenser2);
orientation2.put(Block.dropper.blockID,pistonDropperDispenser2);
orientation2.put(Block.dispenser.blockID,pistonDropperDispenser2);
orientation2.put(Block.redstoneComparatorActive.blockID,pistonDropperDispenser2);
orientation2.put(Block.redstoneComparatorIdle.blockID,pistonDropperDispenser2);
orientation2.put(Block.redstoneRepeaterActive.blockID,pistonDropperDispenser2);
orientation2.put(Block.redstoneRepeaterIdle.blockID,pistonDropperDispenser2);
orientation2.put(Block.doorWood.blockID,pistonDropperDispenser2);
orientation2.put(Block.doorIron.blockID,pistonDropperDispenser2);
orientation2.put(Block.tripWireSource.blockID,pistonDropperDispenser2);
orientation2.put(Block.railDetector.blockID,railsSpecial2);
orientation2.put(Block.railActivator.blockID,railsSpecial2);
orientation2.put(Block.railPowered.blockID,railsSpecial2);
orientation2.put(Block.rail.blockID,rails2);
this.rotationMappings.put(2, orientation2);
this.rotationMappings.put(1, orientation1);
this.rotationMappings.put(0, orientation0);
}
public int getRotatedBlock(int metaData, int desiredOrientation, int blockID)
{
if(this.rotationMappings.containsKey(desiredOrientation))
{
if(this.rotationMappings.get(desiredOrientation).containsKey(blockID))
{
if(this.rotationMappings.get(desiredOrientation).get(blockID).containsKey(metaData))
{
return this.rotationMappings.get(desiredOrientation).get(blockID).get(metaData);
}
}
}
return metaData ;
}
}

View File

@@ -0,0 +1,62 @@
package StevenDimDoors.mod_pocketDim.helpers;
import StevenDimDoors.mod_pocketDim.IChunkLoader;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
import java.io.File;
import java.util.List;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.ForgeChunkManager;
import net.minecraftforge.common.ForgeChunkManager.LoadingCallback;
import net.minecraftforge.common.ForgeChunkManager.Ticket;
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");
if(world.getBlockId(goldDimDoorX, goldDimDoorY, goldDimDoorZ)!=mod_pocketDim.properties.GoldDimDoorID)
{
ForgeChunkManager.releaseTicket(ticket);
}
else
{
IChunkLoader tile = (IChunkLoader) world.getBlockTileEntity(goldDimDoorX, goldDimDoorY, goldDimDoorZ);
tile.forceChunkLoading(ticket,goldDimDoorX,goldDimDoorZ);
}
}
}
public static void loadChunkForcedWorlds(FMLServerStartingEvent event)
{
for(NewDimData data : PocketManager.getDimensions())
{
if(data.isPocketDimension())
{
String chunkDir = DimensionManager.getCurrentSaveRootDirectory()+"/DimensionalDoors/pocketDimID" + data.id();
File file = new File(chunkDir);
if(file.exists())
{
if(ForgeChunkManager.savedWorldHasForcedChunkTickets(file))
{
PocketManager.loadDimension(data.id());
}
}
}
}
}
}

View File

@@ -0,0 +1,87 @@
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;
import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData;
public class Compactor
{
@SuppressWarnings("unused") // ?
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);
output.writeInt(link.orientation());
}
}
// 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++)
{
ClientLinkData link = ClientLinkData.read(input);
Point4D source = link.point;
dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.CLIENT_SIDE,link.orientation);
}
}
}
}

View File

@@ -0,0 +1,32 @@
package StevenDimDoors.mod_pocketDim.helpers;
import java.io.File;
public class DeleteFolder
{
public static boolean deleteFolder(File file)
{
try
{
File[] files = file.listFiles();
if(files==null)
{
file.delete();
return true;
}
for(File inFile : files)
{
DeleteFolder.deleteFolder(inFile);
}
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
return true;
}
}

View File

@@ -0,0 +1,659 @@
package StevenDimDoors.mod_pocketDim.helpers;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.regex.Pattern;
import net.minecraft.util.WeightedRandom;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
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.ItemDimensionalDoor;
import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException;
import StevenDimDoors.mod_pocketDim.util.FileFilters;
import StevenDimDoors.mod_pocketDim.util.WeightedContainer;
public class DungeonHelper
{
private static DungeonHelper instance = null;
private static DDProperties properties = null;
public static final Pattern SCHEMATIC_NAME_PATTERN = Pattern.compile("[A-Za-z0-9_\\-]+");
public static final Pattern DUNGEON_NAME_PATTERN = Pattern.compile("[A-Za-z0-9\\-]+");
public static final String SCHEMATIC_FILE_EXTENSION = ".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";
private static final String BUNDLED_RUINS_LIST_PATH = "/schematics/ruins.txt";
private static final String STANDARD_CONFIG_FILE_NAME = "rules.txt";
private static final int NETHER_DIMENSION_ID = -1;
private static final int MIN_PACK_SWITCH_CHANCE = 0;
private static final int PACK_SWITCH_CHANCE_PER_LEVEL = 1;
private static final int MAX_PACK_SWITCH_CHANCE = 500;
private static final int START_PACK_SWITCH_CHANCE = MAX_PACK_SWITCH_CHANCE / 9;
private static final int DEFAULT_DUNGEON_WEIGHT = 100;
public static final int MIN_DUNGEON_WEIGHT = 1; //Prevents MC's random selection algorithm from throwing an exception
public static final int MAX_DUNGEON_WEIGHT = 10000; //Used to prevent overflows and math breaking down
private static final int MAX_EXPORT_RADIUS = 50;
public static final short MAX_DUNGEON_WIDTH = 2 * MAX_EXPORT_RADIUS + 1;
public static final short MAX_DUNGEON_HEIGHT = MAX_DUNGEON_WIDTH;
public static final short MAX_DUNGEON_LENGTH = MAX_DUNGEON_WIDTH;
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 DungeonData defaultError;
private DungeonHelper()
{
//Load our reference to the DDProperties singleton
if (properties == null)
properties = DDProperties.instance();
registerDungeons();
}
public static DungeonHelper initialize()
{
if (instance == null)
{
instance = new DungeonHelper();
}
else
{
throw new IllegalStateException("Cannot initialize DungeonHelper twice");
}
return instance;
}
public static DungeonHelper instance()
{
if (instance == null)
{
//This is to prevent some frustrating bugs that could arise when classes
//are loaded in the wrong order. Trust me, I had to squash a few...
throw new IllegalStateException("Instance of DungeonHelper requested before initialization");
}
return instance;
}
private void registerDungeons()
{
File file = new File(properties.CustomSchematicDirectory);
if (file.exists() || file.mkdir())
{
copyfile.copyFile(DUNGEON_CREATION_GUIDE_SOURCE_PATH, file.getAbsolutePath() + "/How_to_add_dungeons.txt");
}
DungeonPackConfigReader reader = new DungeonPackConfigReader();
registerBundledDungeons(reader);
registerCustomDungeons(properties.CustomSchematicDirectory, reader);
}
private static DungeonPackConfig loadDungeonPackConfig(String configPath, String name, boolean isInternal, DungeonPackConfigReader reader)
{
try
{
DungeonPackConfig config;
if (isInternal)
{
config = reader.readFromResource(configPath);
}
else
{
config = reader.readFromFile(configPath);
}
config.setName(name);
return config;
}
catch (FileNotFoundException e)
{
System.err.println("Could not find a dungeon pack config file: " + configPath);
}
catch (Exception e) // handles IOException and ConfigurationProcessingException
{
System.err.println(e.getMessage());
if (e.getCause() != null)
{
System.err.println(e.getCause());
}
}
return null;
}
private void registerDungeonPack(String directory, Iterable<String> schematics, boolean isInternal, boolean verbose, DungeonPackConfigReader reader)
{
//First determine the pack's name and validate it
File packDirectory = new File(directory);
String name = packDirectory.getName().toUpperCase();
//TODO: ADD VALIDATION HERE?
//Check for naming conflicts
//That could happen if a user has a custom pack with a name that conflicts with a bundled pack,
//or if a user is running Linux and has two directories with names differing only by capitalization.
DungeonPack pack = dungeonPackMapping.get(name);
if (pack == null)
{
//Load the pack's configuration file
String configPath;
if (isInternal)
{
configPath = directory + "/" + STANDARD_CONFIG_FILE_NAME;
}
else
{
configPath = directory + File.separator + STANDARD_CONFIG_FILE_NAME;
}
DungeonPackConfig config = loadDungeonPackConfig(configPath, name, isInternal, reader);
if (config == null)
{
System.err.println("Could not load config file: " + configPath);
return;
}
//Register the pack
pack = new DungeonPack(config);
dungeonPackMapping.put(name, pack);
dungeonPackList.add(pack);
}
else
{
//Show a warning that there is a naming conflict but keep going. People can use this to extend
//our built-in packs with custom schematics without tampering with our mod's JAR file.
System.err.println("A dungeon pack has the same name as another pack that has already been loaded: " + directory);
System.err.println("We will try to load its schematics but will not check its config file.");
}
//Register the dungeons! ^_^
for (String schematicPath : schematics)
{
registerDungeon(schematicPath, pack, isInternal, verbose);
}
}
public List<DungeonData> getRegisteredDungeons()
{
return Collections.unmodifiableList(this.registeredDungeons);
}
public List<DungeonData> getUntaggedDungeons()
{
return Collections.unmodifiableList(this.untaggedDungeons);
}
public DungeonData getDefaultErrorDungeon()
{
return defaultError;
}
public DungeonPack getDungeonPack(String name)
{
//TODO: This function might be obsolete after the new save format is implemented.
return dungeonPackMapping.get(name.toUpperCase());
}
private DungeonPack getDimDungeonPack(NewDimData data)
{
DungeonPack pack;
DungeonData dungeon = data.dungeon();
if (dungeon != null)
{
pack = dungeon.dungeonType().Owner;
//Make sure the pack isn't null. This can happen for dungeons with the special UNKNOWN type.
if (pack == null)
{
pack = RuinsPack;
}
}
else
{
if (data.id() == NETHER_DIMENSION_ID)
{
//TODO: Change this to the nether-side pack later ^_^
pack = RuinsPack;
}
else
{
pack = RuinsPack;
}
}
return pack;
}
public DimLink createCustomDungeonDoor(World world, int x, int y, int z)
{
//Create a link above the specified position. Link to a new pocket dimension.
NewDimData dimension = PocketManager.getDimensionData(world);
DimLink link = dimension.createLink(x, y + 1, z, LinkTypes.POCKET,3);
//Place a Warp Door linked to that pocket
ItemDimensionalDoor.placeDoorBlock(world, x, y, z, 3, mod_pocketDim.warpDoor);
return link;
}
public boolean validateDungeonType(String type, DungeonPack pack)
{
return pack.isKnownType(type);
}
public boolean validateSchematicName(String name, DungeonPack pack)
{
String[] dungeonData;
if (!name.endsWith(SCHEMATIC_FILE_EXTENSION))
return false;
dungeonData = name.substring(0, name.length() - SCHEMATIC_FILE_EXTENSION.length()).split("_");
//Check for a valid number of parts
if (dungeonData.length < 3 || dungeonData.length > 4)
return false;
//Check if the dungeon type is valid
if (!validateDungeonType(dungeonData[0], pack))
return false;
//Check if the name is valid
if (!SCHEMATIC_NAME_PATTERN.matcher(dungeonData[1]).matches())
return false;
//Check if the open/closed flag is present
if (!dungeonData[2].equalsIgnoreCase("open") && !dungeonData[2].equalsIgnoreCase("closed"))
return false;
//If the weight is present, check that it is valid
if (dungeonData.length == 4)
{
try
{
int weight = Integer.parseInt(dungeonData[3]);
if (weight < MIN_DUNGEON_WEIGHT || weight > MAX_DUNGEON_WEIGHT)
return false;
}
catch (NumberFormatException e)
{
//Not a number
return false;
}
}
return true;
}
public void registerDungeon(String schematicPath, DungeonPack pack, boolean isInternal, boolean verbose)
{
//We use schematicPath as the real path for internal files (inside our JAR) because it seems
//that File tries to interpret it as a local drive path and mangles it.
File schematicFile = new File(schematicPath);
String name = schematicFile.getName();
String path = isInternal ? schematicPath : schematicFile.getAbsolutePath();
try
{
if (validateSchematicName(name, pack))
{
//Strip off the file extension while splitting the file name
String[] dungeonData = name.substring(0, name.length() - SCHEMATIC_FILE_EXTENSION.length()).split("_");
DungeonType dungeonType = pack.getType(dungeonData[0]);
boolean isOpen = dungeonData[2].equalsIgnoreCase("open");
int weight = (dungeonData.length == 4) ? Integer.parseInt(dungeonData[3]) : DEFAULT_DUNGEON_WEIGHT;
//Add this custom dungeon to the list corresponding to its type
DungeonData dungeon = new DungeonData(path, isInternal, dungeonType, isOpen, weight);
pack.addDungeon(dungeon);
registeredDungeons.add(dungeon);
if (verbose)
{
System.out.println("Registered dungeon: " + name);
}
}
else
{
if (verbose)
{
System.out.println("The following dungeon name is invalid for its given pack. It will not be generated naturally: " + schematicPath);
}
untaggedDungeons.add(new DungeonData(path, isInternal, DungeonType.UNKNOWN_TYPE, true, DEFAULT_DUNGEON_WEIGHT));
System.out.println("Registered untagged dungeon: " + name);
}
}
catch (Exception e)
{
System.err.println("Failed to register dungeon: " + name);
e.printStackTrace();
}
}
private void registerCustomDungeons(String path, DungeonPackConfigReader reader)
{
File[] schematics;
File[] packDirectories;
File[] packFiles;
ArrayList<String> packFilePaths;
File directory = new File(path);
FileFilter schematicFileFilter = new FileFilters.FileExtensionFilter(SCHEMATIC_FILE_EXTENSION);
//Check that the Ruins pack has been loaded
if (RuinsPack == null)
{
throw new IllegalStateException("Cannot register custom dungeons without first loading the Ruins dungeon pack.");
}
//Load stray dungeons directly in the custom dungeons folder
schematics = directory.listFiles(schematicFileFilter);
if (schematics != null)
{
for (File schematicFile : schematics)
{
registerDungeon(schematicFile.getPath(), RuinsPack, false, true);
}
}
else
{
System.err.println("Could not retrieve the list of schematics stored in the custom dungeons directory!");
}
schematics = null; //Release memory
//Load the custom dungeon packs
packDirectories = directory.listFiles(new FileFilters.DirectoryFilter());
if (packDirectories != null)
{
//Loop through each directory, which is assumed to be a dungeon pack
for (File packDirectory : packDirectories)
{
//List the schematics within the dungeon pack directory
packFiles = packDirectory.listFiles(schematicFileFilter);
if (packFiles != null)
{
//Copy the pack files' paths into an ArrayList for use with registerDungeonPack()
packFilePaths = new ArrayList<String>(packFiles.length);
for (File packFile : packFiles)
{
packFilePaths.add(packFile.getPath());
}
registerDungeonPack(packDirectory.getAbsolutePath(), packFilePaths, false, true, reader);
}
else
{
System.err.println("Could not retrieve the list of schematics in a dungeon pack: " + packDirectory.getPath());
}
}
}
else
{
System.err.println("Could not retrieve the list of dungeon pack directories in the custom dungeons directory!");
}
}
private void registerBundledDungeons(DungeonPackConfigReader reader)
{
//Register the core schematics
//These are used for debugging and in case of unusual errors while loading dungeons
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);
RuinsPack = getDungeonPack("Ruins");
System.out.println("Finished registering bundled dungeon packs");
}
private void registerBundledPack(String listPath, String packPath, String name, DungeonPackConfigReader reader)
{
System.out.println("Registering bundled dungeon pack: " + name);
InputStream listStream = this.getClass().getResourceAsStream(listPath);
// chance of leak?
if (listStream == null)
{
System.err.println("Unable to open list of bundled dungeon schematics for " + name);
return;
}
try
{
//Read the list of schematics that come with a bundled pack
BufferedReader listReader = new BufferedReader(new InputStreamReader(listStream));
ArrayList<String> schematics = new ArrayList<String>();
String schematicPath = listReader.readLine();
while (schematicPath != null)
{
schematicPath = schematicPath.trim();
if (!schematicPath.isEmpty())
{
schematics.add(schematicPath);
}
schematicPath = listReader.readLine();
}
listReader.close();
//Register the pack
registerDungeonPack(packPath, schematics, true, false, reader);
}
catch (Exception e)
{
System.err.println("An exception occurred while reading the list of bundled dungeon schematics for " + name);
e.printStackTrace();
}
}
public boolean exportDungeon(World world, int centerX, int centerY, int centerZ, String exportPath)
{
//Write schematic data to a file
try
{
DungeonSchematic dungeon = DungeonSchematic.copyFromWorld(world,
centerX - MAX_EXPORT_RADIUS, centerY - MAX_EXPORT_RADIUS, centerZ - MAX_EXPORT_RADIUS,
MAX_DUNGEON_WIDTH, MAX_DUNGEON_HEIGHT, MAX_DUNGEON_LENGTH, true);
dungeon.applyExportFilters(properties);
dungeon.writeToFile(exportPath);
return true;
}
catch(Exception e)
{
e.printStackTrace();
return false;
}
}
public DungeonData selectDungeon(NewDimData dimension, Random random)
{
DungeonPack pack = getDimDungeonPack(dimension);
DungeonData selection;
DungeonPackConfig config;
DungeonPack selectedPack;
try
{
config = pack.getConfig();
selectedPack = pack;
//Are we allowed to switch to another dungeon pack?
if (config.allowPackChangeOut())
{
//Calculate the chance of switching to a different pack type
int packSwitchChance;
if (dimension.depth() == 1)
{
packSwitchChance = START_PACK_SWITCH_CHANCE;
}
else
{
packSwitchChance = MIN_PACK_SWITCH_CHANCE + dimension.parent().packDepth() * PACK_SWITCH_CHANCE_PER_LEVEL;
}
//Decide randomly whether to switch packs or not
if (random.nextInt(MAX_PACK_SWITCH_CHANCE) < packSwitchChance)
{
//Find another pack
selectedPack = getRandomDungeonPack(pack, random);
}
}
//Pick the next dungeon
selection = selectedPack.getNextDungeon(dimension, random);
}
catch (Exception e)
{
System.err.println("An exception occurred while selecting a dungeon:");
e.printStackTrace();
if (!pack.isEmpty())
{
selection = pack.getRandomDungeon(random);
}
else
{
selection = defaultError;
}
}
return selection;
}
@SuppressWarnings("unchecked")
private DungeonPack getRandomDungeonPack(DungeonPack current, Random random)
{
DungeonPack selection = current;
ArrayList<WeightedContainer<DungeonPack>> packs = new ArrayList<WeightedContainer<DungeonPack>>(dungeonPackList.size());
//Load up a list of weighted items with any usable dungeon packs that is not the current pack
for (DungeonPack pack : dungeonPackList)
{
DungeonPackConfig config = pack.getConfig();
if (pack != current && config.allowPackChangeIn() && !pack.isEmpty())
{
packs.add(new WeightedContainer<DungeonPack>(pack, config.getPackWeight()));
}
}
if (!packs.isEmpty())
{
//Pick a random dungeon pack
selection = ((WeightedContainer<DungeonPack>) WeightedRandom.getRandomItem(random, packs)).getData();
}
return selection;
}
public Collection<String> getDungeonNames() {
//Use a HashSet to guarantee that all dungeon names will be distinct.
//This shouldn't be necessary if we keep proper lists without repetitions,
//but it's a fool-proof workaround.
HashSet<String> dungeonNames = new HashSet<String>();
dungeonNames.addAll( parseDungeonNames(registeredDungeons) );
dungeonNames.addAll( parseDungeonNames(untaggedDungeons) );
//Sort dungeon names alphabetically
ArrayList<String> sortedNames = new ArrayList<String>(dungeonNames);
Collections.sort(sortedNames, String.CASE_INSENSITIVE_ORDER);
return sortedNames;
}
private static ArrayList<String> parseDungeonNames(ArrayList<DungeonData> dungeons)
{
String name;
File schematic;
ArrayList<String> names = new ArrayList<String>(dungeons.size());
for (DungeonData dungeon : dungeons)
{
//Retrieve the file name and strip off the file extension
schematic = new File(dungeon.schematicPath());
name = schematic.getName();
name = name.substring(0, name.length() - SCHEMATIC_FILE_EXTENSION.length());
names.add(name);
}
return names;
}
public static ArrayList<DungeonData> getDungeonChainHistory(NewDimData dimension, DungeonPack pack, int maxSize)
{
if (dimension == null)
{
throw new IllegalArgumentException("dimension cannot be null.");
}
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)
{
history.add(dungeon);
tail = tail.parent();
dungeon = tail.dungeon();
count++;
}
return history;
}
public static ArrayList<DungeonData> getFlatDungeonTree(NewDimData dimension, int maxSize)
{
NewDimData root = dimension;
ArrayList<DungeonData> dungeons = new ArrayList<DungeonData>();
Queue<NewDimData> pendingDimensions = new LinkedList<NewDimData>();
if (root.dungeon() == null)
{
return dungeons;
}
pendingDimensions.add(root);
while (dungeons.size() < maxSize && !pendingDimensions.isEmpty())
{
NewDimData current = pendingDimensions.remove();
for (NewDimData child : current.children())
{
if (child.dungeon() != null)
{
dungeons.add(child.dungeon());
pendingDimensions.add(child);
}
if (dungeons.size() == maxSize)
{
break;
}
}
}
return dungeons;
}
}

View File

@@ -0,0 +1,35 @@
package StevenDimDoors.mod_pocketDim.helpers;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
public class copyfile
{
public static boolean copyFile(String ori, String dest)
{
try
{
//Note: For this to work properly, you must use getClass() on an instance of the class,
//not on the value obtained from .class. That was what caused this code to fail before.
//SchematicLoader didn't have this problem because we used instances of it.
InputStream in = mod_pocketDim.instance.getClass().getResourceAsStream(ori);
OutputStream out = new FileOutputStream(dest);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
catch (Exception e)
{
System.out.println("Unable to get resource: " + ori);
return false;
}
return true;
}
}

View File

@@ -0,0 +1,297 @@
package StevenDimDoors.mod_pocketDim.helpers;
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;
private yCoordHelper() { }
public static int getFirstUncovered(World world, int x, int yStart, int z)
{
return getFirstUncovered(world, x, yStart, z, false);
}
public static int getFirstUncovered(World world, int x, int yStart, int z, boolean fromTop)
{
Chunk chunk = world.getChunkProvider().loadChunk(x >> 4, z >> 4);
int localX = x < 0 ? (x % 16) + 16 : (x % 16);
int localZ = z < 0 ? (z % 16) + 16 : (z % 16);
int height = MAXIMUM_UNCOVERED_Y;
int y;
if (!fromTop)
{
boolean covered = true;
for (y = yStart; y < height && covered; y++)
{
covered = isCoveredBlock(chunk, localX, y - 1, localZ) || isCoveredBlock(chunk, localX, y, localZ);
}
}
else
{
boolean covered = false;
for (y = MAXIMUM_UNCOVERED_Y; y > 1 && !covered; y--)
{
covered = isCoveredBlock(chunk, localX, y - 1, localZ);
}
if (!covered) y = 63;
y++;
}
return y;
}
public static boolean isCoveredBlock(Chunk chunk, int localX, int y, int localZ)
{
int blockID;
Block block;
Material material;
if (y < 0)
return false;
blockID = chunk.getBlockID(localX, y, localZ);
if (blockID == 0)
return false;
block = Block.blocksList[blockID];
if (block == null)
return false;
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;
}
}

View File

@@ -0,0 +1,119 @@
package StevenDimDoors.mod_pocketDim.items;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemDoor;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
public abstract class BaseItemDoor extends ItemDoor
{
private static DDProperties properties = null;
public BaseItemDoor(int itemID, Material material)
{
super(itemID, material);
this.setMaxStackSize(64);
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
if (properties == null)
properties = DDProperties.instance();
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName().replace("item.", ""));
}
@SuppressWarnings({ "rawtypes" })
@Override
public abstract void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4);
@Override
public abstract boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ);
public static boolean tryItemUse(Block doorBlock, ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, boolean requireLink, boolean reduceStack)
{
// Only place doors on top of blocks - check if we're targeting the top side
if (side == 1 && !world.isRemote)
{
int blockID = world.getBlockId(x, y, z);
if (blockID != 0)
{
if (!Block.blocksList[blockID].isBlockReplaceable(world, x, y, z))
{
y++;
}
}
if (canPlace(world, x, y, z) && canPlace(world, x, y + 1, z) &&
player.canPlayerEdit(x, y, z, side, stack) && player.canPlayerEdit(x, y + 1, z, side, stack) &&
(!requireLink || PocketManager.getLink(x, y + 1, z, world) != null)&&stack.stackSize>0)
{
int orientation = MathHelper.floor_double((player.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3;
placeDoorBlock(world, x, y, z, orientation, doorBlock);
if (!player.capabilities.isCreativeMode && reduceStack)
{
stack.stackSize--;
}
return true;
}
}
return false;
}
@Override
public abstract ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player);
public boolean tryPlacingDoor(Block doorBlock, World world, EntityPlayer player, ItemStack item)
{
if (world.isRemote)
{
return false;
}
MovingObjectPosition hit = this.getMovingObjectPositionFromPlayer(player.worldObj, player, true);
if (hit != null)
{
if (world.getBlockId(hit.blockX, hit.blockY, hit.blockZ) == properties.RiftBlockID)
{
DimLink link = PocketManager.getLink(hit.blockX, hit.blockY, hit.blockZ, world.provider.dimensionId);
if (link != null)
{
int x = hit.blockX;
int y = hit.blockY;
int z = hit.blockZ;
if (player.canPlayerEdit(x, y, z, hit.sideHit, item) && player.canPlayerEdit(x, y - 1, z, hit.sideHit, item))
{
if (canPlace(world, x, y, z) && canPlace(world, x, y - 1, z))
{
int orientation = MathHelper.floor_double(((player.rotationYaw + 180.0F) * 4.0F / 360.0F) - 0.5D) & 3;
placeDoorBlock(world, x, y - 1, z, orientation, doorBlock);
return true;
}
}
}
}
}
return false;
}
public static boolean canPlace(World world, int x, int y, int z)
{
int id = world.getBlockId(x, y, z);
return (id == properties.RiftBlockID || id == 0 || Block.blocksList[id].blockMaterial.isReplaceable());
}
}

View File

@@ -0,0 +1,34 @@
package StevenDimDoors.mod_pocketDim.items;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
public class ItemBlockDimWall extends ItemBlock
{
private final static String[] subNames = {"Fabric of Reality", "Ancient Fabric"};
public ItemBlockDimWall(int par1)
{
super(par1);
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
setHasSubtypes(true);
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName().replace("tile.", ""));
}
@Override
public int getMetadata (int damageValue)
{
return damageValue;
}
public String getUnlocalizedName(ItemStack par1ItemStack)
{
return subNames[this.getDamage(par1ItemStack)];
}
}

View File

@@ -0,0 +1,48 @@
package StevenDimDoors.mod_pocketDim.items;
import java.util.List;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
public class ItemDimensionalDoor extends BaseItemDoor
{
public ItemDimensionalDoor(int itemID, Material material)
{
super(itemID, material);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4)
{
par3List.add("Place on the block under a rift");
par3List.add("to activate that rift or place");
par3List.add("anywhere else to create a");
par3List.add("pocket dimension.");
}
@Override
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player)
{
if (!world.isRemote)
{
if (tryPlacingDoor(mod_pocketDim.dimensionalDoor, world, player, stack) &&
!player.capabilities.isCreativeMode)
{
stack.stackSize--;
}
}
return stack;
}
@Override
public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y,
int z, int par7, float par8, float par9, float par10)
{
return tryItemUse(mod_pocketDim.dimensionalDoor, stack, player, world, x, y, z, par7, false, true);
}
}

View File

@@ -0,0 +1,52 @@
package StevenDimDoors.mod_pocketDim.items;
import java.util.List;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
public class ItemGoldDimDoor extends BaseItemDoor
{
public ItemGoldDimDoor(int itemID, Material material) {
super(itemID, material);
// TODO Auto-generated constructor stub
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4)
{
par3List.add("Similar to a Iron Dim Door");
par3List.add("But if present in a pocket dim");
par3List.add("it will keep it loaded.");
}
@Override
public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y,
int z, int par7, float par8, float par9, float par10)
{
return tryItemUse(mod_pocketDim.goldDimDoor, stack, player, world, x, y, z, par7, false, true);
}
@Override
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player)
{
if (!world.isRemote)
{
if (tryPlacingDoor(mod_pocketDim.goldDimDoor, world, player, stack) &&
!player.capabilities.isCreativeMode)
{
stack.stackSize--;
}
}
return stack;
}
}

View File

@@ -0,0 +1,58 @@
package StevenDimDoors.mod_pocketDim.items;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemDoor;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
public class ItemGoldDoor extends ItemDoor
{
public ItemGoldDoor(int par1, Material par2Material)
{
super(par1, par2Material);
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName().replace("item.", ""));
}
@Override
public boolean onItemUse(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, World par3World, int par4, int par5, int par6, int par7, float par8, float par9, float par10)
{
if (par7 != 1)
{
return false;
}
else
{
++par5;
Block block = mod_pocketDim.goldDoor;
if (par2EntityPlayer.canPlayerEdit(par4, par5, par6, par7, par1ItemStack) && par2EntityPlayer.canPlayerEdit(par4, par5 + 1, par6, par7, par1ItemStack))
{
if (!block.canPlaceBlockAt(par3World, par4, par5, par6))
{
return false;
}
else
{
int i1 = MathHelper.floor_double((par2EntityPlayer.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3;
placeDoorBlock(par3World, par4, par5, par6, i1, block);
--par1ItemStack.stackSize;
return true;
}
}
else
{
return false;
}
}
}
}

View File

@@ -0,0 +1,230 @@
package StevenDimDoors.mod_pocketDim.items;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.EnumToolMaterial;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import com.google.common.collect.Multimap;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class ItemRiftBlade extends ItemSword
{
private final DDProperties properties;
public ItemRiftBlade(int itemID, EnumToolMaterial material, DDProperties properties)
{
super(itemID, material);
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
this.setMaxStackSize(1);
this.setMaxDamage(500);
this.hasSubtypes = false;
this.properties = properties;
}
@Override
@SideOnly(Side.CLIENT)
public boolean isFull3D()
{
return true;
}
@Override
public float getStrVsBlock(ItemStack par1ItemStack, Block par2Block)
{
if (par2Block.blockID == Block.web.blockID)
{
return 15.0F;
}
else
{
Material material = par2Block.blockMaterial;
return material != Material.plants && material != Material.vine && material != Material.coral && material != Material.leaves && material != Material.pumpkin ? 1.0F : 1.5F;
}
}
@Override
public Multimap getItemAttributeModifiers()
{
Multimap multimap = super.getItemAttributeModifiers();
multimap.put(SharedMonsterAttributes.attackDamage.getAttributeUnlocalizedName(), new AttributeModifier(field_111210_e, "Weapon modifier", (double)7, 0));
return multimap;
}
@Override
@SideOnly(Side.CLIENT)
public boolean hasEffect(ItemStack par1ItemStack)
{
return true;
}
@Override
public boolean hitEntity(ItemStack par1ItemStack, EntityLivingBase par2EntityLiving, EntityLivingBase par3EntityLiving)
{
par1ItemStack.damageItem(1, par3EntityLiving);
return true;
}
@Override
public MovingObjectPosition getMovingObjectPositionFromPlayer(World par1World, EntityPlayer par2EntityPlayer, boolean par3)
{
float var4 = 1.0F;
float var5 = par2EntityPlayer.prevRotationPitch + (par2EntityPlayer.rotationPitch - par2EntityPlayer.prevRotationPitch) * var4;
float var6 = par2EntityPlayer.prevRotationYaw + (par2EntityPlayer.rotationYaw - par2EntityPlayer.prevRotationYaw) * var4;
double var7 = par2EntityPlayer.prevPosX + (par2EntityPlayer.posX - par2EntityPlayer.prevPosX) * var4;
double var9 = par2EntityPlayer.prevPosY + (par2EntityPlayer.posY - par2EntityPlayer.prevPosY) * var4 + 1.62D - par2EntityPlayer.yOffset;
double var11 = par2EntityPlayer.prevPosZ + (par2EntityPlayer.posZ - par2EntityPlayer.prevPosZ) * var4;
Vec3 var13 = par1World.getWorldVec3Pool().getVecFromPool(var7, var9, var11);
float var14 = MathHelper.cos(-var6 * 0.017453292F - (float)Math.PI);
float var15 = MathHelper.sin(-var6 * 0.017453292F - (float)Math.PI);
float var16 = -MathHelper.cos(-var5 * 0.017453292F);
float var17 = MathHelper.sin(-var5 * 0.017453292F);
float var18 = var15 * var16;
float var20 = var14 * var16;
double var21 = 5.0D;
if (par2EntityPlayer instanceof EntityPlayerMP)
{
var21 = 7;
}
Vec3 var23 = var13.addVector(var18 * var21, var17 * var21, var20 * var21);
return par1World.rayTraceBlocks_do_do(var13, var23, true, false);
}
private boolean teleportToEntity(ItemStack item, Entity par1Entity, EntityPlayer holder)
{
Vec3 var2 = holder.worldObj.getWorldVec3Pool().getVecFromPool(holder.posX - par1Entity.posX, holder.boundingBox.minY + holder.height / 2.0F - par1Entity.posY + par1Entity.getEyeHeight(), holder.posZ - par1Entity.posZ);
double cooef =( var2.lengthVector()-2.5)/var2.lengthVector();
var2.xCoord*=cooef;
var2.yCoord*=cooef;
var2.zCoord*=cooef;
double var5 = holder.posX - var2.xCoord;
double var9 = holder.posZ - var2.zCoord;
double var7 = MathHelper.floor_double(holder.posY - var2.yCoord) ;
int var14 = MathHelper.floor_double(var5);
int var15 = MathHelper.floor_double(var7);
int var16 = MathHelper.floor_double(var9);
while(!holder.worldObj.isAirBlock(var14, var15, var16))
{
var15++;
}
var7=var15;
holder.setPositionAndUpdate(var5, var7, var9);
holder.playSound("mob.endermen.portal", 1.0F, 1.0F);
holder.worldObj.playSoundEffect(holder.posX, holder.posY, holder.posZ, "mob.endermen.portal", 1.0F, 1.0F);
return true;
}
@Override
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player)
{
if (!world.isRemote)
{
@SuppressWarnings("unchecked")
List<EntityLiving> list = world.getEntitiesWithinAABB(EntityLiving.class, AxisAlignedBB.getBoundingBox(player.posX-8,player.posY-8, player.posZ-8, player.posX+8,player.posY+8, player.posZ+8));
list.remove(player);
for (EntityLiving ent : list)
{
Vec3 var3 = player.getLook(1.0F).normalize();
Vec3 var4 = player.worldObj.getWorldVec3Pool().getVecFromPool(ent.posX - player.posX, ent.boundingBox.minY + (ent.height) / 2.0F - ( player.posY + player.getEyeHeight()), ent.posZ - player.posZ);
double var5 = var4.lengthVector();
var4 = var4.normalize();
double var7 = var3.dotProduct(var4);
if( (var7+.1) > 1.0D - 0.025D / var5 ? player.canEntityBeSeen(ent) : false)
{
teleportToEntity(stack, ent, player);
stack.damageItem(3, player);
return stack;
}
}
MovingObjectPosition hit = this.getMovingObjectPositionFromPlayer(world, player, false);
if (hit != null)
{
int x = hit.blockX;
int y = hit.blockY;
int z = hit.blockZ;
if (world.getBlockId(x, y, z) == properties.RiftBlockID)
{
if (PocketManager.getLink(x, y, z, world) != null)
{
if (player.canPlayerEdit(x, y, z, hit.sideHit, stack) &&
player.canPlayerEdit(x, y + 1, z, hit.sideHit, stack))
{
int orientation = MathHelper.floor_double((player.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3;
if (BaseItemDoor.canPlace(world, x, y, z) &&
BaseItemDoor.canPlace(world, x, y - 1, z))
{
ItemDimensionalDoor.placeDoorBlock(world, x, y - 1, z, orientation, mod_pocketDim.transientDoor);
player.worldObj.playSoundAtEntity(player,mod_pocketDim.modid+":riftDoor", 0.6f, 1);
stack.damageItem(3, player);
return stack;
}
}
}
}
}
player.setItemInUse(stack, this.getMaxItemUseDuration(stack));
}
return stack;
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName());
}
/**
* Return whether this item is repairable in an anvil.
*/
@Override
public boolean getIsRepairable(ItemStack par1ItemStack, ItemStack par2ItemStack)
{
//Don't include a call to super.getIsRepairable()!
//That would cause this sword to accept gold as a repair material (since we set material = Gold).
return mod_pocketDim.itemStableFabric.itemID == par2ItemStack.itemID ? true : false;
}
/**
* allows items to add custom lines of information to the mouseover description
*/
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
@SideOnly(Side.CLIENT)
public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4)
{
par3List.add("Creates temporary doors");
par3List.add("on rifts, rotates doors,");
par3List.add("and has a teleport attack.");
}
}

View File

@@ -0,0 +1,18 @@
package StevenDimDoors.mod_pocketDim.items;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.EnumArmorMaterial;
import net.minecraft.item.ItemArmor;
public class ItemRiftGoggles extends ItemArmor
{
public ItemRiftGoggles(int par1, int par2, int par3)
{
super(par1, EnumArmorMaterial.IRON, par1, par1);
this.setCreativeTab(CreativeTabs.tabRedstone);
// this.setIconIndex(Item.doorWood.getIconFromDamage(0));
}
}

View File

@@ -0,0 +1,245 @@
package StevenDimDoors.mod_pocketDim.items;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor;
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.util.Point4D;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class ItemRiftSignature extends Item
{
public ItemRiftSignature(int itemID)
{
super(itemID);
this.setMaxStackSize(1);
this.setMaxDamage(0);
this.hasSubtypes = true;
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
}
@SideOnly(Side.CLIENT)
@Override
public boolean hasEffect(ItemStack stack)
{
//Make the item glow if it has one endpoint stored
return (stack.getItemDamage() != 0);
}
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName());
}
@Override
public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ)
{
//TODO- recognize doors and intelligently place rifts on them.
// We must use onItemUseFirst() instead of onItemUse() because Minecraft checks
// whether the user is in creative mode after calling onItemUse() and undoes any
// damage we might set to indicate the rift sig has been activated. Otherwise,
// we would need to rely on checking NBT tags for hasEffect() and that function
// gets called constantly. Avoiding NBT lookups reduces our performance impact.
// Return false on the client side to pass this request to the server
if (world.isRemote)
{
return false;
}
y += 2; //Increase y by 2 to place the rift at head level
if (!player.canPlayerEdit(x, y, z, side, stack))
{
return true;
}
int adjustedY = adjustYForSpecialBlocks(world,x,y,z);
Point4DOrientation source = getSource(stack);
int orientation = MathHelper.floor_double((double) ((player.rotationYaw + 180.0F) * 4.0F / 360.0F) - 0.5D) & 3;
if (source != null)
{
//The link was used before and already has an endpoint stored. Create links connecting the two endpoints.
NewDimData sourceDimension = PocketManager.getDimensionData(source.getDimension());
NewDimData destinationDimension = PocketManager.getDimensionData(world);
DimLink link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.NORMAL,source.getOrientation());
DimLink reverse = destinationDimension.createLink(x, adjustedY, z, LinkTypes.NORMAL,orientation);
destinationDimension.setDestination(link, x, adjustedY, z);
sourceDimension.setDestination(reverse, source.getX(), source.getY(), source.getZ());
//Try placing a rift at the destination point
if (!mod_pocketDim.blockRift.isBlockImmune(world, x, adjustedY, z))
{
world.setBlock(x, adjustedY, z, mod_pocketDim.blockRift.blockID);
}
//Try placing a rift at the source point, but check if its world is loaded first
World sourceWorld = DimensionManager.getWorld(sourceDimension.id());
if (sourceWorld != null &&
!mod_pocketDim.blockRift.isBlockImmune(sourceWorld, source.getX(), source.getY(), source.getZ()))
{
sourceWorld.setBlock(source.getX(), source.getY(), source.getZ(), mod_pocketDim.blockRift.blockID);
}
if (!player.capabilities.isCreativeMode)
{
stack.stackSize--;
}
clearSource(stack);
mod_pocketDim.sendChat(player,("Rift Created"));
world.playSoundAtEntity(player,mod_pocketDim.modid+":riftEnd", 0.6f, 1);
}
else
{
//The link signature has not been used. Store its current target as the first location.
setSource(stack, x, adjustedY, z,orientation, PocketManager.getDimensionData(world));
mod_pocketDim.sendChat(player,("Location Stored in Rift Signature"));
world.playSoundAtEntity(player,mod_pocketDim.modid+":riftStart", 0.6f, 1);
}
return true;
}
/**
* allows items to add custom lines of information to the mouseover description
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@SideOnly(Side.CLIENT)
public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4)
{
Point4DOrientation source = getSource(par1ItemStack);
if (source != null)
{
par3List.add("Leads to (" + source.getX() + ", " + source.getY() + ", " + source.getZ() + ") at dimension #" + source.getDimension());
}
else
{
par3List.add("First click stores a location;");
par3List.add("second click creates a pair of");
par3List.add("rifts linking the two locations.");
}
}
/**
* Makes the rift placement account for replaceable blocks and doors.
* @param world
* @param x
* @param y
* @param z
* @return the adjusted y coord
*/
public static int adjustYForSpecialBlocks(World world, int x, int y, int z)
{
y=y-2;//get the block the player actually clicked on
Block block = Block.blocksList[world.getBlockId(x, y, z)];
if(block.isBlockReplaceable(world, x, y, z))
{
return y+1;//move block placement down (-2+1) one so its directly over things like snow
}
if(block instanceof BaseDimDoor)
{
if(world.getBlockId(x, y-1, z)==block.blockID&&world.getBlockMetadata(x, y, z)==8)
{
return y;//move rift placement down two so its in the right place on the door.
}
return y+1;
}
return y+2;
}
public static void setSource(ItemStack itemStack, int x, int y, int z, int orientation, NewDimData dimension)
{
NBTTagCompound tag = new NBTTagCompound();
tag.setInteger("linkX", x);
tag.setInteger("linkY", y);
tag.setInteger("linkZ", z);
tag.setInteger("orientation", orientation);
tag.setInteger("linkDimID", dimension.id());
itemStack.setTagCompound(tag);
itemStack.setItemDamage(1);
}
public static void clearSource(ItemStack itemStack)
{
//Don't just set the tag to null since there may be other data there (e.g. for renamed items)
NBTTagCompound tag = itemStack.getTagCompound();
tag.removeTag("linkX");
tag.removeTag("linkY");
tag.removeTag("linkZ");
tag.removeTag("orientation");
tag.removeTag("linkDimID");
itemStack.setItemDamage(0);
}
public static Point4DOrientation getSource(ItemStack itemStack)
{
if (itemStack.getItemDamage() != 0)
{
if (itemStack.hasTagCompound())
{
NBTTagCompound tag = itemStack.getTagCompound();
Integer x = tag.getInteger("linkX");
Integer y = tag.getInteger("linkY");
Integer z = tag.getInteger("linkZ");
Integer orientation = tag.getInteger("orientation");
Integer dimID = tag.getInteger("linkDimID");
if (x != null && y != null && z != null && dimID != null)
{
return new Point4DOrientation(x, y, z,orientation, dimID);
}
}
itemStack.setItemDamage(0);
}
return null;
}
static class Point4DOrientation
{
private Point4D point;
private int orientation;
Point4DOrientation(int x, int y, int z, int orientation, int dimID)
{
this.point= new Point4D(x,y,z,dimID);
this.orientation=orientation;
}
int getX()
{
return point.getX();
}
int getY()
{
return point.getY();
}
int getZ()
{
return point.getZ();
}
int getDimension()
{
return point.getDimension();
}
int getOrientation()
{
return orientation;
}
}
}

View File

@@ -0,0 +1,126 @@
package StevenDimDoors.mod_pocketDim.items;
import java.util.List;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
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.util.Point4D;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class ItemStabilizedRiftSignature extends ItemRiftSignature
{
public ItemStabilizedRiftSignature(int itemID)
{
super(itemID);
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName().replace("item.", ""));
}
@Override
public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ)
{
// Return false on the client side to pass this request to the server
if (world.isRemote)
{
return false;
}
// We don't check for replaceable blocks. The user can deal with that. <_<
y += 2; //Increase y by 2 to place the rift at head level
if (!player.canPlayerEdit(x, y, z, side, stack))
{
return true;
}
Point4DOrientation source = getSource(stack);
int adjustedY = adjustYForSpecialBlocks(world,x,y,z);
// Check if the Stabilized Rift Signature has been initialized
int orientation = MathHelper.floor_double((player.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3;
if (source != null)
{
// Yes, it's initialized. Check if the player is in creative
// or if the player can pay an Ender Pearl to create a rift.
if (!player.capabilities.isCreativeMode && !player.inventory.hasItem(Item.enderPearl.itemID))
{
mod_pocketDim.sendChat(player,"You don't have any Ender Pearls!");
// I won't do this, but this is the chance to localize chat
// messages sent to the player; look at ChatMessageComponent
// and how MFR does it with items like the safari net launcher
return true;
}
//The link was used before and already has an endpoint stored. Create links connecting the two endpoints.
NewDimData sourceDimension = PocketManager.getDimensionData(source.getDimension());
NewDimData destinationDimension = PocketManager.getDimensionData(world);
DimLink link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.NORMAL,source.getOrientation());
DimLink reverse = destinationDimension.createLink(x, adjustedY, z, LinkTypes.NORMAL,orientation);
destinationDimension.setDestination(link, x, adjustedY, z);
sourceDimension.setDestination(reverse, source.getX(), source.getY(), source.getZ());
//Try placing a rift at the destination point
if (!mod_pocketDim.blockRift.isBlockImmune(world, x, adjustedY, z))
{
world.setBlock(x, adjustedY, z, mod_pocketDim.blockRift.blockID);
}
//Try placing a rift at the source point, but check if its world is loaded first
World sourceWorld = DimensionManager.getWorld(sourceDimension.id());
if (sourceWorld != null &&
!mod_pocketDim.blockRift.isBlockImmune(sourceWorld, source.getX(), source.getY(), source.getZ()))
{
sourceWorld.setBlock(source.getX(), source.getY(), source.getZ(), mod_pocketDim.blockRift.blockID);
}
if (!player.capabilities.isCreativeMode)
{
player.inventory.consumeInventoryItem(Item.enderPearl.itemID);
}
mod_pocketDim.sendChat(player,"Rift Created");
world.playSoundAtEntity(player,"mods.DimDoors.sfx.riftEnd", 0.6f, 1);
}
else
{
//The link signature has not been used. Store its current target as the first location.
setSource(stack, x, adjustedY, z, orientation, PocketManager.getDimensionData(world));
mod_pocketDim.sendChat(player,"Location Stored in Rift Signature");
world.playSoundAtEntity(player,"mods.DimDoors.sfx.riftStart", 0.6f, 1);
}
return true;
}
/**
* allows items to add custom lines of information to the mouseover description
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@SideOnly(Side.CLIENT)
@Override
public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4)
{
Point4DOrientation source = getSource(par1ItemStack);
if (source != null)
{
par3List.add("Leads to (" + source.getX() + ", " + source.getY() + ", " + source.getZ() + ") at dimension #" + source.getDimension());
}
else
{
par3List.add("First click stores a location,");
par3List.add("second click creates two rifts");
par3List.add("that link the locations together.");
}
}
}

View File

@@ -0,0 +1,20 @@
package StevenDimDoors.mod_pocketDim.items;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.item.Item;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
public class ItemStableFabric extends Item
{
public ItemStableFabric(int itemID, int par2)
{
super(itemID);
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName().replace("item.", ""));
}
}

View File

@@ -0,0 +1,45 @@
package StevenDimDoors.mod_pocketDim.items;
import java.util.List;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
public class ItemUnstableDoor extends BaseItemDoor
{
public ItemUnstableDoor(int itemID, Material material)
{
super(itemID, material);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4)
{
par3List.add("Caution: Leads to random destination");
}
@Override
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player)
{
if (!world.isRemote)
{
if (tryPlacingDoor(mod_pocketDim.unstableDoor, world, player, stack) &&
!player.capabilities.isCreativeMode)
{
stack.stackSize--;
}
}
return stack;
}
@Override
public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y,
int z, int par7, float par8, float par9, float par10)
{
return tryItemUse(mod_pocketDim.unstableDoor, stack, player, world, x, y, z, par7, false, true);
}
}

View File

@@ -0,0 +1,48 @@
package StevenDimDoors.mod_pocketDim.items;
import java.util.List;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
public class ItemWarpDoor extends BaseItemDoor
{
public ItemWarpDoor(int itemID, Material material)
{
super(itemID, material);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4)
{
par3List.add("Place on the block under");
par3List.add("a rift to create a portal,");
par3List.add("or place anywhere in a");
par3List.add("pocket dimension to exit.");
}
@Override
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player)
{
if (!world.isRemote)
{
if (tryPlacingDoor(mod_pocketDim.warpDoor, world, player, stack) &&
!player.capabilities.isCreativeMode)
{
stack.stackSize--;
}
}
return stack;
}
@Override
public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y,
int z, int par7, float par8, float par9, float par10)
{
return tryItemUse(mod_pocketDim.warpDoor, stack, player, world, x, y, z, par7, false, true);
}
}

View File

@@ -0,0 +1,20 @@
package StevenDimDoors.mod_pocketDim.items;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.item.Item;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
public class ItemWorldThread extends Item
{
public ItemWorldThread(int itemID)
{
super(itemID);
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName().replace("item.", ""));
}
}

View File

@@ -0,0 +1,137 @@
package StevenDimDoors.mod_pocketDim.items;
import java.util.List;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class itemRiftRemover extends Item
{
public itemRiftRemover(int itemID, Material par2Material)
{
super(itemID);
this.setMaxStackSize(1);
this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab);
this.setMaxDamage(4);
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName());
}
@Override
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player)
{
// We invoke PlayerControllerMP.onPlayerRightClick() from here so that Minecraft
// will invoke onItemUseFirst() on the client side. We'll tell it to pass the
// request to the server, which will make sure that rift-related changes are
// reflected on the server.
if (!world.isRemote)
{
return stack;
}
MovingObjectPosition hit = this.getMovingObjectPositionFromPlayer(world, player, true);
if (hit != null)
{
int hx = hit.blockX;
int hy = hit.blockY;
int hz = hit.blockZ;
NewDimData dimension = PocketManager.getDimensionData(world);
DimLink link = dimension.getLink(hx, hy, hz);
if (world.getBlockId(hx, hy, hz) == mod_pocketDim.blockRift.blockID && link != null &&
player.canPlayerEdit(hx, hy, hz, hit.sideHit, stack))
{
// Invoke onPlayerRightClick()
FMLClientHandler.instance().getClient().playerController.onPlayerRightClick(
player, world, stack, hx, hy, hz, hit.sideHit, hit.hitVec);
}
}
return stack;
}
@Override
public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ)
{
// We want to use onItemUseFirst() here so that this code will run on the server side,
// so we don't need the client to send link-related updates to the server. Still,
// check whether we have a rift in sight before passing the request over.
// On integrated servers, the link won't be removed immediately because of the rift
// removal animation. That means we'll have a chance to check for the link before
// it's deleted. Otherwise the Rift Remover's durability wouldn't drop.
MovingObjectPosition hit = this.getMovingObjectPositionFromPlayer(world, player, true);
if (hit != null)
{
x = hit.blockX;
y = hit.blockY;
z = hit.blockZ;
NewDimData dimension = PocketManager.getDimensionData(world);
DimLink link = dimension.getLink(x, y, z);
if (world.getBlockId(x, y, z) == mod_pocketDim.blockRift.blockID && link != null &&
player.canPlayerEdit(x, y, z, side, stack))
{
// Tell the rift's tile entity to do its removal animation
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
if (tileEntity != null && tileEntity instanceof TileEntityRift)
{
((TileEntityRift) tileEntity).shouldClose = true;
tileEntity.onInventoryChanged();
}
else if (!world.isRemote)
{
// Only set the block to air on the server side so that we don't
// tell the server to remove the rift block before it can use the
// Rift Remover. Otherwise, it won't know to reduce durability.
world.setBlockToAir(x, y, z);
}
if (world.isRemote)
{
// Tell the server about this
return false;
}
else
{
if (!player.capabilities.isCreativeMode)
{
stack.damageItem(1, player);
}
player.worldObj.playSoundAtEntity(player, mod_pocketDim.modid+":riftClose", 0.8f, 1);
}
}
}
return true;
}
/**
* allows items to add custom lines of information to the mouseover description
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@SideOnly(Side.CLIENT)
@Override
public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4)
{
par3List.add("Use near exposed rift");
par3List.add("to remove it and");
par3List.add("any nearby rifts.");
}
}

View File

@@ -0,0 +1,341 @@
package StevenDimDoors.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.blocks.BlockDimWall;
import StevenDimDoors.mod_pocketDim.blocks.BlockDimWallPerm;
import StevenDimDoors.mod_pocketDim.blocks.BlockDoorGold;
import StevenDimDoors.mod_pocketDim.blocks.BlockGoldDimDoor;
import StevenDimDoors.mod_pocketDim.blocks.BlockLimbo;
import StevenDimDoors.mod_pocketDim.blocks.BlockRift;
import StevenDimDoors.mod_pocketDim.blocks.DimensionalDoor;
import StevenDimDoors.mod_pocketDim.blocks.TransTrapdoor;
import StevenDimDoors.mod_pocketDim.blocks.TransientDoor;
import StevenDimDoors.mod_pocketDim.blocks.UnstableDoor;
import StevenDimDoors.mod_pocketDim.blocks.WarpDoor;
import StevenDimDoors.mod_pocketDim.commands.CommandCreateDungeonRift;
import StevenDimDoors.mod_pocketDim.commands.CommandCreatePocket;
import StevenDimDoors.mod_pocketDim.commands.CommandDeleteAllLinks;
import StevenDimDoors.mod_pocketDim.commands.CommandDeleteRifts;
import StevenDimDoors.mod_pocketDim.commands.CommandExportDungeon;
import StevenDimDoors.mod_pocketDim.commands.CommandResetDungeons;
import StevenDimDoors.mod_pocketDim.commands.CommandTeleportPlayer;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.helpers.ChunkLoaderHelper;
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
import StevenDimDoors.mod_pocketDim.items.ItemBlockDimWall;
import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor;
import StevenDimDoors.mod_pocketDim.items.ItemGoldDimDoor;
import StevenDimDoors.mod_pocketDim.items.ItemGoldDoor;
import StevenDimDoors.mod_pocketDim.items.ItemRiftBlade;
import StevenDimDoors.mod_pocketDim.items.ItemRiftSignature;
import StevenDimDoors.mod_pocketDim.items.ItemStabilizedRiftSignature;
import StevenDimDoors.mod_pocketDim.items.ItemStableFabric;
import StevenDimDoors.mod_pocketDim.items.ItemUnstableDoor;
import StevenDimDoors.mod_pocketDim.items.ItemWarpDoor;
import StevenDimDoors.mod_pocketDim.items.ItemWorldThread;
import StevenDimDoors.mod_pocketDim.items.itemRiftRemover;
import StevenDimDoors.mod_pocketDim.ticking.CommonTickHandler;
import StevenDimDoors.mod_pocketDim.ticking.LimboDecay;
import StevenDimDoors.mod_pocketDim.ticking.MobMonolith;
import StevenDimDoors.mod_pocketDim.ticking.MonolithSpawner;
import StevenDimDoors.mod_pocketDim.ticking.RiftRegenerator;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoorGold;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor;
import StevenDimDoors.mod_pocketDim.world.BiomeGenLimbo;
import StevenDimDoors.mod_pocketDim.world.BiomeGenPocket;
import StevenDimDoors.mod_pocketDim.world.GatewayGenerator;
import StevenDimDoors.mod_pocketDim.world.LimboProvider;
import StevenDimDoors.mod_pocketDim.world.PocketProvider;
import StevenDimDoors.mod_pocketDimClient.ClientPacketHandler;
import StevenDimDoors.mod_pocketDimClient.ClientTickHandler;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
import cpw.mods.fml.common.event.FMLServerStoppingEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.network.NetworkMod.SidedPacketHandler;
import cpw.mods.fml.common.registry.EntityRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
import cpw.mods.fml.common.registry.TickRegistry;
import cpw.mods.fml.relauncher.Side;
import java.io.File;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.EntityEggInfo;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumToolMaterial;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ChatMessageComponent;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.ForgeChunkManager;
import net.minecraftforge.common.MinecraftForge;
@Mod(modid = mod_pocketDim.modid, name = "Dimensional Doors", version = mod_pocketDim.version)
@NetworkMod(clientSideRequired = true, serverSideRequired = false, connectionHandler=ConnectionHandler.class,
clientPacketHandlerSpec =
@SidedPacketHandler(channels = {PacketConstants.CHANNEL_NAME}, packetHandler = ClientPacketHandler.class),
serverPacketHandlerSpec =
@SidedPacketHandler(channels = {PacketConstants.CHANNEL_NAME}, packetHandler = ServerPacketHandler.class))
public class mod_pocketDim
{
public static final String version = "$VERSION$";
public static final String modid = "dimdoors";
//need to clean up
@SidedProxy(clientSide = "StevenDimDoors.mod_pocketDimClient.ClientProxy", serverSide = "StevenDimDoors.mod_pocketDim.CommonProxy")
public static CommonProxy proxy;
@Instance("PocketDimensions")
public static mod_pocketDim instance = new mod_pocketDim();
public static Block transientDoor;
public static Block warpDoor;
public static Block goldDoor;
public static Block goldDimDoor;
public static Block unstableDoor;
public static Block blockLimbo;
public static DimensionalDoor dimensionalDoor;
public static Block blockDimWall;
public static TransTrapdoor transTrapdoor;
public static Block blockDimWallPerm;
public static BlockRift blockRift;
public static Item itemGoldDimDoor;
public static Item itemGoldDoor;
public static Item itemWorldThread;
public static Item itemRiftBlade;
public static Item itemDimDoor;
public static Item itemExitDoor;
public static Item itemRiftRemover;
public static Item itemLinkSignature;
public static Item itemStableFabric;
public static Item itemChaosDoor;
public static Item itemStabilizedLinkSignature;
public static BiomeGenBase limboBiome;
public static BiomeGenBase pocketBiome;
public static boolean isPlayerWearingGoogles = false;
public static DDProperties properties;
public static MonolithSpawner spawner; //Added this field temporarily. Will be refactored out later.
public static GatewayGenerator riftGen;
public static CreativeTabs dimDoorsCreativeTab = new CreativeTabs("dimDoorsCreativeTab")
{
@Override
public ItemStack getIconItemStack()
{
return new ItemStack(mod_pocketDim.itemDimDoor, 1, 0);
}
@Override
public String getTranslatedTabLabel()
{
return "Dimensional Doors";
}
};
@EventHandler
public void onPreInitialization(FMLPreInitializationEvent event)
{
instance = this;
//This should be the FIRST thing that gets done.
String path = event.getSuggestedConfigurationFile().getAbsolutePath().replace(modid, "DimDoors");
properties = DDProperties.initialize(new File(path));
//Now do other stuff
MinecraftForge.EVENT_BUS.register(new EventHookContainer(properties));
riftGen = new GatewayGenerator(properties);
}
@SuppressWarnings("unused")
@EventHandler
public void onInitialization(FMLInitializationEvent event)
{
CommonTickHandler commonTickHandler = new CommonTickHandler();
TickRegistry.registerTickHandler(new ClientTickHandler(), Side.CLIENT);
TickRegistry.registerTickHandler(commonTickHandler, Side.SERVER);
//MonolithSpawner should be initialized before any provider instances are created
//Register the other regular tick receivers as well
spawner = new MonolithSpawner(commonTickHandler, properties);
new RiftRegenerator(commonTickHandler); //No need to store the reference
LimboDecay decay = new LimboDecay(commonTickHandler, properties);
transientDoor = new TransientDoor(properties.TransientDoorID, Material.iron, properties).setHardness(1.0F) .setUnlocalizedName("transientDoor");
goldDimDoor = new BlockGoldDimDoor(properties.GoldDimDoorID, Material.iron, properties).setHardness(1.0F) .setUnlocalizedName("dimDoorGold");
goldDoor = new BlockDoorGold(properties.GoldDoorID, Material.iron, properties).setHardness(0.1F).setUnlocalizedName("doorGold");
blockDimWall = new BlockDimWall(properties.FabricBlockID, 0, Material.iron).setLightValue(1.0F).setHardness(0.1F).setUnlocalizedName("blockDimWall");
blockDimWallPerm = (new BlockDimWallPerm(properties.PermaFabricBlockID, 0, Material.iron)).setLightValue(1.0F).setBlockUnbreakable().setResistance(6000000.0F).setUnlocalizedName("blockDimWallPerm");
warpDoor = new WarpDoor(properties.WarpDoorID, Material.wood, properties).setHardness(1.0F) .setUnlocalizedName("dimDoorWarp");
blockRift = (BlockRift) (new BlockRift(properties.RiftBlockID, 0, Material.air, properties).setHardness(1.0F) .setUnlocalizedName("rift"));
blockLimbo = new BlockLimbo(properties.LimboBlockID, 15, Material.iron, properties.LimboDimensionID, decay).setHardness(.2F).setUnlocalizedName("BlockLimbo").setLightValue(.0F);
unstableDoor = (new UnstableDoor(properties.UnstableDoorID, Material.iron, properties).setHardness(.2F).setUnlocalizedName("chaosDoor").setLightValue(.0F) );
dimensionalDoor = (DimensionalDoor) (new DimensionalDoor(properties.DimensionalDoorID, Material.iron, properties).setHardness(1.0F).setResistance(2000.0F) .setUnlocalizedName("dimDoor"));
transTrapdoor = (TransTrapdoor) (new TransTrapdoor(properties.TransTrapdoorID, Material.wood).setHardness(1.0F) .setUnlocalizedName("dimHatch"));
itemGoldDimDoor = (new ItemGoldDimDoor(properties.GoldDimDoorItemID, Material.iron)).setUnlocalizedName("itemGoldDimDoor");
itemGoldDoor = (new ItemGoldDoor(properties.GoldDoorID, Material.wood)).setUnlocalizedName("itemGoldDoor");
itemDimDoor = (new ItemDimensionalDoor(properties.DimensionalDoorItemID, Material.iron)).setUnlocalizedName("itemDimDoor");
itemExitDoor = (new ItemWarpDoor(properties.WarpDoorItemID, Material.wood)).setUnlocalizedName("itemDimDoorWarp");
itemLinkSignature = (new ItemRiftSignature(properties.RiftSignatureItemID)).setUnlocalizedName("itemLinkSignature");
itemRiftRemover = (new itemRiftRemover(properties.RiftRemoverItemID, Material.wood)).setUnlocalizedName("itemRiftRemover");
itemStableFabric = (new ItemStableFabric(properties.StableFabricItemID, 0)).setUnlocalizedName("itemStableFabric");
itemChaosDoor = (new ItemUnstableDoor(properties.UnstableDoorItemID, Material.iron)).setUnlocalizedName("itemChaosDoor");
itemRiftBlade = (new ItemRiftBlade(properties.RiftBladeItemID, EnumToolMaterial.GOLD, properties)).setUnlocalizedName("ItemRiftBlade");
itemStabilizedLinkSignature = (new ItemStabilizedRiftSignature(properties.StabilizedRiftSignatureItemID)).setUnlocalizedName("itemStabilizedRiftSig");
itemWorldThread = (new ItemWorldThread(properties.ItemWorldThreadID)).setUnlocalizedName("itemWorldThread");
mod_pocketDim.limboBiome= (new BiomeGenLimbo(properties.LimboBiomeID));
mod_pocketDim.pocketBiome= (new BiomeGenPocket(properties.PocketBiomeID));
GameRegistry.registerWorldGenerator(mod_pocketDim.riftGen);
GameRegistry.registerBlock(goldDoor, "Golden Door");
GameRegistry.registerBlock(goldDimDoor, "Golden Dimensional Door");
GameRegistry.registerBlock(unstableDoor, "Unstable Door");
GameRegistry.registerBlock(warpDoor, "Warp Door");
GameRegistry.registerBlock(blockRift, "Rift");
GameRegistry.registerBlock(blockLimbo, "Unraveled Fabric");
GameRegistry.registerBlock(dimensionalDoor, "Dimensional Door");
GameRegistry.registerBlock(transTrapdoor,"Transdimensional Trapdoor");
GameRegistry.registerBlock(blockDimWallPerm, "Fabric of RealityPerm");
GameRegistry.registerBlock(transientDoor, "transientDoor");
GameRegistry.registerBlock(blockDimWall, ItemBlockDimWall.class, "Fabric of Reality");
DimensionManager.registerProviderType(properties.PocketProviderID, PocketProvider.class, false);
DimensionManager.registerProviderType(properties.LimboProviderID, LimboProvider.class, false);
DimensionManager.registerDimension(properties.LimboDimensionID, properties.LimboProviderID);
LanguageRegistry.addName(goldDoor, "Golden Door");
LanguageRegistry.addName(goldDimDoor, "Golden Dimensional Door");
LanguageRegistry.addName(transientDoor , "transientDoor");
LanguageRegistry.addName(blockRift , "Rift");
LanguageRegistry.addName(blockLimbo , "Unraveled Fabric");
LanguageRegistry.addName(warpDoor , "Warp Door");
LanguageRegistry.addName(unstableDoor , "Unstable Door");
LanguageRegistry.addName(blockDimWall , "Fabric of Reality");
LanguageRegistry.addName(blockDimWallPerm , "Eternal Fabric");
LanguageRegistry.addName(dimensionalDoor, "Dimensional Door");
LanguageRegistry.addName(transTrapdoor, "Transdimensional Trapdoor");
LanguageRegistry.addName(itemExitDoor, "Warp Door");
LanguageRegistry.addName(itemLinkSignature , "Rift Signature");
LanguageRegistry.addName(itemGoldDoor, "Golden Door");
LanguageRegistry.addName(itemGoldDimDoor , "Golden Dimensional Door");
LanguageRegistry.addName(itemStabilizedLinkSignature, "Stabilized Rift Signature");
LanguageRegistry.addName(itemRiftRemover , "Rift Remover");
LanguageRegistry.addName(itemStableFabric , "Stable Fabric");
LanguageRegistry.addName(itemChaosDoor , "Unstable Door");
LanguageRegistry.addName(itemDimDoor, "Dimensional Door");
LanguageRegistry.addName(itemRiftBlade , "Rift Blade");
LanguageRegistry.addName(itemWorldThread, "World Thread");
/**
* Add names for multiblock inventory item
*/
LanguageRegistry.addName(new ItemStack(blockDimWall, 1, 0), "Fabric of Reality");
LanguageRegistry.addName(new ItemStack(blockDimWall, 1, 1), "Ancient Fabric");
LanguageRegistry.instance().addStringLocalization("itemGroup.dimDoorsCustomTab", "en_US", "Dimensional Doors Items");
GameRegistry.registerTileEntity(TileEntityDimDoor.class, "TileEntityDimDoor");
GameRegistry.registerTileEntity(TileEntityRift.class, "TileEntityRift");
GameRegistry.registerTileEntity(TileEntityTransTrapdoor.class, "TileEntityDimHatch");
GameRegistry.registerTileEntity(TileEntityDimDoorGold.class, "TileEntityDimDoorGold");
EntityRegistry.registerModEntity(MobMonolith.class, "Monolith", properties.MonolithEntityID, this, 70, 1, true);
EntityList.IDtoClassMapping.put(properties.MonolithEntityID, MobMonolith.class);
EntityList.entityEggs.put(properties.MonolithEntityID, new EntityEggInfo(properties.MonolithEntityID, 0, 0xffffff));
LanguageRegistry.instance().addStringLocalization("entity.DimDoors.Obelisk.name", "Monolith");
CraftingManager.registerRecipies();
DungeonHelper.initialize();
proxy.loadTextures();
proxy.registerRenderers();
}
@EventHandler
public void onPostInitialization(FMLPostInitializationEvent event)
{
ForgeChunkManager.setForcedChunkLoadingCallback(instance, new ChunkLoaderHelper());
//Register loot chests
DDLoot.registerInfo();
}
@EventHandler
public void onServerStopping(FMLServerStoppingEvent event)
{
try
{
PocketManager.unload();
}
catch (Exception e)
{
e.printStackTrace();
}
}
@EventHandler
public void onServerStarting(FMLServerStartingEvent event)
{
//TODO- load dims with forced chunks on server startup here
CommandResetDungeons.instance().register(event);
CommandCreateDungeonRift.instance().register(event);
CommandDeleteAllLinks.instance().register(event);
//CommandDeleteDimensionData.instance().register(event);
CommandDeleteRifts.instance().register(event);
CommandExportDungeon.instance().register(event);
//CommandPrintDimensionData.instance().register(event);
//CommandPruneDimensions.instance().register(event);
CommandCreatePocket.instance().register(event);
CommandTeleportPlayer.instance().register(event);
try
{
ChunkLoaderHelper.loadChunkForcedWorlds(event);
}
catch(Exception e)
{
System.out.println("Loading chunkloaders failed");
}
}
public static void sendChat(EntityPlayer player, String message)
{
ChatMessageComponent cmp = new ChatMessageComponent();
cmp.addText(message);
player.sendChatToPlayer(cmp);
}
}

View File

@@ -0,0 +1,77 @@
package StevenDimDoors.mod_pocketDim.saving;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import StevenDimDoors.mod_pocketDim.util.BaseConfigurationProcessor;
import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException;
public class BlacklistProcessor extends BaseConfigurationProcessor<List<Integer>>
{
@Override
public List<Integer> readFromStream(InputStream inputStream) throws ConfigurationProcessingException
{
try
{
JsonReader reader = new JsonReader(new InputStreamReader(inputStream, "UTF-8"));
List<Integer> data = this.createBlacklistFromJson(reader);
reader.close();
return data;
}
catch (IOException e)
{
e.printStackTrace();
throw new ConfigurationProcessingException("Could not read blacklist");
}
}
private List<Integer> createBlacklistFromJson(JsonReader reader) throws IOException
{
List<Integer> blacklist;
blacklist = this.createIntListFromJson(reader);
return blacklist;
}
@Override
public void writeToStream(OutputStream outputStream, List<Integer> data) throws ConfigurationProcessingException
{
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.setPrettyPrinting().create();
try
{
outputStream.write(gson.toJson(data).getBytes("UTF-8"));
outputStream.close();
}
catch (IOException e)
{
// not sure if this is kosher, we need it to explode, but not by throwing the IO exception.
throw new ConfigurationProcessingException("Incorrectly formatted save data");
}
}
private List<Integer> createIntListFromJson(JsonReader reader) throws IOException
{
List<Integer> list = new ArrayList<Integer>();
reader.beginArray();
while(reader.peek()!= JsonToken.END_ARRAY)
{
list.add(reader.nextInt());
}
reader.endArray();
return list;
}
}

View File

@@ -0,0 +1,321 @@
package StevenDimDoors.mod_pocketDim.saving;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.Point3D;
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.pack.DungeonPack;
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType;
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException;
import StevenDimDoors.mod_pocketDim.util.FileFilters;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import com.google.common.io.Files;
public class DDSaveHandler
{
public static boolean loadAll()
{
// SenseiKiwi: Loading up our save data is not as simple as just reading files.
// To properly restore dimensions, we need to make sure we always load
// a dimension's parent and root before trying to load it. We'll use
// topological sorting to determine the order in which to recreate the
// dimension objects such that we respect those dependencies.
// Links must be loaded after instantiating all the dimensions and must
// be checked against our dimension blacklist.
// Don't surround this code with try-catch. Our mod should crash if an error
// occurs at this level, since it could lead to some nasty problems.
String basePath = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/";
File dataDirectory = new File(basePath);
// Check if the folder exists. If it doesn't, just return.
if (!dataDirectory.exists())
{
return true;
}
// Load the dimension blacklist
File blacklistFile = new File(basePath+"blacklist.txt");
if(blacklistFile.exists())
{
BlacklistProcessor blacklistReader = new BlacklistProcessor();
List<Integer> blacklist = readBlacklist(blacklistFile,blacklistReader);
PocketManager.createAndRegisterBlacklist(blacklist);
}
// List any dimension data files and read each dimension
DimDataProcessor reader = new DimDataProcessor();
List<PackedDimData> packedDims = new ArrayList<PackedDimData>();
FileFilter dataFileFilter = new FileFilters.RegexFileFilter("dim_-?\\d+\\.txt");
File[] dataFiles = dataDirectory.listFiles(dataFileFilter);
for (File dataFile : dataFiles)
{
PackedDimData packedDim = readDimension(dataFile, reader);
packedDims.add(packedDim);
}
List<PackedLinkData> linksToUnpack = new ArrayList<PackedLinkData>();
//get the grand list of all links to unpack
for(PackedDimData packedDim : packedDims)
{
linksToUnpack.addAll(packedDim.Links);
}
return unpackDimData(packedDims)&&unpackLinkData(linksToUnpack);
}
/**
* Takes a list of packedDimData and rebuilds the DimData for it
* @param packedDims
* @return
*/
public static boolean unpackDimData(List<PackedDimData> packedDims)
{
List<PackedDimData> unpackedDims = new ArrayList<PackedDimData>();
//Load roots
for(PackedDimData packedDim : packedDims)
{
if(packedDim.ParentID==packedDim.ID)
{
PocketManager.registerPackedDimData(packedDim);
unpackedDims.add(packedDim);
}
}
packedDims.removeAll(unpackedDims);
unpackedDims.clear();
//Load the pockets
while(!packedDims.isEmpty())
{
for(PackedDimData packedDim : packedDims)
{
if(PocketManager.isRegisteredInternally(packedDim.ParentID))
{
PocketManager.registerPackedDimData(packedDim);
unpackedDims.add(packedDim);
}
else
{
//break here gracefully
}
}
packedDims.removeAll(unpackedDims);
unpackedDims.clear();
}
return true;
}
public static boolean unpackLinkData(List<PackedLinkData> linksToUnpack)
{
Point3D fakePoint = new Point3D(-1,-1,-1);
List<PackedLinkData> unpackedLinks = new ArrayList<PackedLinkData>();
/**
* sort through the list, unpacking links that do not have parents.
*/
//TODO- what we have a loop of links?
for(PackedLinkData packedLink : linksToUnpack)
{
if(packedLink.parent.equals(fakePoint))
{
NewDimData data = PocketManager.getDimensionData(packedLink.source.getDimension());
int linkType = packedLink.tail.linkType;
if((linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX) && linkType != LinkTypes.CLIENT_SIDE)
{
linkType = LinkTypes.NORMAL;
}
@SuppressWarnings("deprecation")
DimLink link = data.createLink(packedLink.source, linkType, packedLink.orientation);
Point4D destination = packedLink.tail.destination;
if(destination!=null)
{
PocketManager.getDimensionData(destination.getDimension()).setDestination(link, destination.getX(),destination.getY(),destination.getZ());
}
unpackedLinks.add(packedLink);
}
}
linksToUnpack.removeAll(unpackedLinks);
//unpack remaining children
while(!linksToUnpack.isEmpty())
{
for(PackedLinkData packedLink : linksToUnpack)
{
NewDimData data = PocketManager.getDimensionData(packedLink.source.getDimension());
if(data.getLink(packedLink.parent)!=null)
{
data.createChildLink(packedLink.source.getX(), packedLink.source.getY(), packedLink.source.getZ(), data.getLink(packedLink.parent));
}
unpackedLinks.add(packedLink);
}
linksToUnpack.removeAll(unpackedLinks);
}
return true;
}
private static PackedDimData readDimension(File dataFile, DimDataProcessor reader)
{
try
{
return reader.readFromFile(dataFile);
}
catch (Exception e)
{
System.err.println("Could not read dimension data from: " + dataFile.getAbsolutePath());
System.err.println("The following error occurred:");
printException(e, false);
return null;
}
}
public static boolean saveAll(Iterable<? extends IPackable<PackedDimData>> dimensions, List<Integer> blacklist) throws IOException
{
// Create the data directory for our dimensions
// Don't catch exceptions here. If we can't create this folder,
// the mod should crash to let the user know early on.
String basePath = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/";
File basePathFile = new File(basePath);
Files.createParentDirs(basePathFile);
basePathFile.mkdir();
BlacklistProcessor blacklistReader = new BlacklistProcessor();
writeBlacklist(blacklist, blacklistReader,basePath);
FileFilter dataFileFilter = new FileFilters.RegexFileFilter("dim_-?\\d+\\.txt");
//TODO Deal with temp files correctly
File[] dataFiles = basePathFile.listFiles(dataFileFilter);
for (File dataFile : dataFiles)
{
dataFile.delete();
}
basePathFile = null;
basePath += "dim_";
boolean succeeded = true;
DimDataProcessor writer = new DimDataProcessor();
for (IPackable<PackedDimData> dimension : dimensions)
{
succeeded &= writeDimension(dimension, writer, basePath);
}
return succeeded;
}
private static boolean writeBlacklist(List<Integer> blacklist, BlacklistProcessor writer, String basePath)
{
try
{
File tempFile = new File(basePath + "blacklist.tmp");
File saveFile = new File(basePath + "blacklist.txt");
writer.writeToFile(tempFile, blacklist);
saveFile.delete();
tempFile.renameTo(saveFile);
return true;
}
catch (Exception e)
{
System.err.println("Could not save blacklist. The following error occurred:");
printException(e, true);
return false;
}
}
private static boolean writeDimension(IPackable<PackedDimData> dimension, DimDataProcessor writer, String basePath)
{
try
{
File tempFile = new File(basePath + (dimension.name() + ".tmp"));
File saveFile = new File(basePath + (dimension.name() + ".txt"));
writer.writeToFile(tempFile, dimension.pack());
saveFile.delete();
tempFile.renameTo(saveFile);
return true;
}
catch (Exception e)
{
System.err.println("Could not save data for dimension #" + dimension.name() + ". The following error occurred:");
printException(e, true);
return false;
}
}
private static void printException(Exception e, boolean verbose)
{
if (e.getCause() == null)
{
if (verbose)
{
e.printStackTrace();
}
else
{
System.err.println(e.getMessage());
}
}
else
{
System.out.println(e.getMessage());
System.err.println("Caused by an underlying error:");
if (verbose)
{
e.getCause().printStackTrace();
}
else
{
System.err.println(e.getCause().getMessage());
}
}
}
//TODO - make this more robust
public static DungeonData unpackDungeonData(PackedDungeonData packedDungeon)
{
for(DungeonData data : DungeonHelper.instance().getRegisteredDungeons())
{
if(data.schematicName().equals(packedDungeon.SchematicName))
{
return data;
}
}
return null;
}
public static List<Integer> readBlacklist(File blacklistFile, BlacklistProcessor reader)
{
try
{
return reader.readFromFile(blacklistFile);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,300 @@
package StevenDimDoors.mod_pocketDim.saving;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.util.BaseConfigurationProcessor;
import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException;
import StevenDimDoors.mod_pocketDim.util.Point4D;
public class DimDataProcessor extends BaseConfigurationProcessor<PackedDimData>
{
@Override
public PackedDimData readFromStream(InputStream inputStream)
throws ConfigurationProcessingException
{
try
{
JsonReader reader = new JsonReader(new InputStreamReader(inputStream, "UTF-8"));
PackedDimData data = this.createDImDataFromJson(reader);
reader.close();
return data;
}
catch (IOException e)
{
e.printStackTrace();
throw new ConfigurationProcessingException("Could not read packedDimData");
}
}
@Override
public void writeToStream(OutputStream outputStream, PackedDimData data)
throws ConfigurationProcessingException
{
/** Print out dimData using the GSON built in serializer. I dont feel bad doing this because
* 1- We can read it
* 2- We are manually reading the data in.
* 3- The error messages tell us exactly where its failing, so its easy to fix
*/
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.setPrettyPrinting().create();
try
{
outputStream.write(gson.toJson(data).getBytes("UTF-8"));
outputStream.close();
}
catch (IOException e)
{
// not sure if this is kosher, we need it to explode, but not by throwing the IO exception.
throw new ConfigurationProcessingException("Incorrectly formatted save data");
}
}
/**
* Nightmare method that takes a JsonReader pointed at a serialized instance of PackedDimData
* @param reader
* @return
* @throws IOException
*/
public PackedDimData createDImDataFromJson(JsonReader reader) throws IOException
{
int ID;
boolean IsDungeon;
boolean IsFilled;
int Depth;
int PackDepth;
int ParentID;
int RootID;
PackedDungeonData Dungeon = null;
Point3D Origin;
int Orientation;
List<Integer> ChildIDs;
List<PackedLinkData> Links;
List<PackedLinkTail> Tails = new ArrayList<PackedLinkTail>();
reader.beginObject();
reader.nextName();
if (reader.nextLong() != PackedDimData.SAVE_DATA_VERSION_ID)
{
throw new IOException("Save data version mismatch");
}
reader.nextName();
ID = reader.nextInt();
reader.nextName();
IsDungeon = reader.nextBoolean();
reader.nextName();
IsFilled = reader.nextBoolean();
reader.nextName();
Depth = reader.nextInt();
reader.nextName();
PackDepth = reader.nextInt();
reader.nextName();
ParentID=reader.nextInt();
reader.nextName();
RootID= reader.nextInt();
if(reader.nextName().equals("DungeonData"))
{
Dungeon = createDungeonDataFromJson(reader);
reader.nextName();
}
Origin = createPointFromJson(reader);
reader.nextName();
Orientation = reader.nextInt();
reader.nextName();
ChildIDs = this.createIntListFromJson(reader);
reader.nextName();
Links = this.createLinksListFromJson(reader);
return new PackedDimData(ID, Depth, PackDepth, ParentID, RootID, Orientation, IsDungeon, IsFilled, Dungeon, Origin, ChildIDs, Links, Tails);
}
private Point3D createPointFromJson(JsonReader reader) throws IOException
{
reader.beginObject();
reader.nextName();
int x = reader.nextInt();
reader.nextName();
int y = reader.nextInt();
reader.nextName();
int z = reader.nextInt();
reader.endObject();
return new Point3D(x,y,z);
}
private Point4D createPoint4DFromJson(JsonReader reader) throws IOException
{
reader.beginObject();
reader.nextName();
int x = reader.nextInt();
reader.nextName();
int y = reader.nextInt();
reader.nextName();
int z = reader.nextInt();
reader.nextName();
int dimension = reader.nextInt();
reader.endObject();
return new Point4D(x,y,z,dimension);
}
private List<Integer> createIntListFromJson(JsonReader reader) throws IOException
{
List<Integer> list = new ArrayList<Integer>();
reader.beginArray();
while (reader.peek() != JsonToken.END_ARRAY)
{
list.add(reader.nextInt());
}
reader.endArray();
return list;
}
private List<PackedLinkData> createLinksListFromJson(JsonReader reader) throws IOException
{
List<PackedLinkData> list = new ArrayList<PackedLinkData>();
reader.beginArray();
while (reader.peek() != JsonToken.END_ARRAY)
{
list.add(createLinkDataFromJson(reader));
}
reader.endArray();
return list;
}
private PackedLinkData createLinkDataFromJson(JsonReader reader) throws IOException
{
Point4D source;
Point3D parent;
PackedLinkTail tail;
int orientation;
List<Point3D> children = new ArrayList<Point3D>();
reader.beginObject();
reader.nextName();
source = this.createPoint4DFromJson(reader);
reader.nextName();
parent = this.createPointFromJson(reader);
reader.nextName();
tail = this.createLinkTailFromJson(reader);
reader.nextName();
orientation = reader.nextInt();
reader.nextName();
reader.beginArray();
while (reader.peek() != JsonToken.END_ARRAY)
{
children.add(this.createPointFromJson(reader));
}
reader.endArray();
reader.endObject();
return new PackedLinkData(source, parent, tail, orientation, children);
}
private PackedDungeonData createDungeonDataFromJson(JsonReader reader) throws IOException
{
int Weight;
boolean IsOpen;
boolean IsInternal;
String SchematicPath;
String SchematicName;
String DungeonTypeName;
String DungeonPackName;
reader.beginObject();
@SuppressWarnings("unused")
JsonToken test = reader.peek();
if(reader.peek() == JsonToken.END_OBJECT)
{
return null;
}
reader.nextName();
Weight=reader.nextInt();
reader.nextName();
IsOpen=reader.nextBoolean();
reader.nextName();
IsInternal=reader.nextBoolean();
reader.nextName();
SchematicPath=reader.nextString();
reader.nextName();
SchematicName=reader.nextString();
reader.nextName();
DungeonTypeName=reader.nextString();
reader.nextName();
DungeonPackName=reader.nextString();
reader.endObject();
return new PackedDungeonData(Weight, IsOpen, IsInternal, SchematicPath, SchematicName, DungeonTypeName, DungeonPackName);
}
private PackedLinkTail createLinkTailFromJson(JsonReader reader) throws IOException
{
Point4D destination = null;
int linkType;
reader.beginObject();
reader.nextName();
@SuppressWarnings("unused")
JsonToken test = reader.peek();
if (reader.peek() == JsonToken.BEGIN_OBJECT)
{
destination = this.createPoint4DFromJson(reader);
reader.nextName();
}
linkType = reader.nextInt();
reader.endObject();
return new PackedLinkTail(destination, linkType);
}
}

View File

@@ -0,0 +1,7 @@
package StevenDimDoors.mod_pocketDim.saving;
public interface IPackable<T>
{
public String name();
public T pack();
}

View File

@@ -0,0 +1,73 @@
package StevenDimDoors.mod_pocketDim.saving;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import StevenDimDoors.mod_pocketDim.DimData;
import StevenDimDoors.mod_pocketDim.LinkData;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.ObjectSaveInputStream;
import StevenDimDoors.mod_pocketDim.util.Point4D;
public class OldSaveImporter
{
public static void importOldSave(File file) throws IOException, ClassNotFoundException
{
FileInputStream saveFile = new FileInputStream(file);
ObjectSaveInputStream save = new ObjectSaveInputStream(saveFile);
HashMap comboSave =((HashMap) save.readObject());
save.close();
List<PackedLinkData> allPackedLinks = new ArrayList<PackedLinkData>();
List<PackedDimData> newPackedDimData = new ArrayList<PackedDimData>();
HashMap<Integer, DimData> dimMap;
try
{
dimMap = (HashMap<Integer, DimData>) comboSave.get("dimList");
}
catch(Exception e)
{
System.out.println("Could not import old save data");
return;
}
for(DimData data : dimMap.values())
{
List<PackedLinkData> newPackedLinkData = new ArrayList<PackedLinkData>();
List<Integer> childDims = new ArrayList<Integer>();
for(LinkData link : data.getLinksInDim())
{
Point4D source = new Point4D(link.locXCoord,link.locYCoord,link.locZCoord,link.locDimID);
Point4D destintion = new Point4D(link.destXCoord,link.destYCoord,link.destZCoord,link.destDimID);
PackedLinkTail tail = new PackedLinkTail(destintion, link.linkOrientation);
List<Point3D> children = new ArrayList<Point3D>();
PackedLinkData newPackedLink = new PackedLinkData(source, new Point3D(-1,-1,-1), tail, link.linkOrientation,children);
newPackedLinkData.add(newPackedLink);
allPackedLinks.add(newPackedLink);
}
PackedDimData dim = new PackedDimData(data.dimID, data.depth, data.depth, data.exitDimLink.locDimID, data.exitDimLink.locDimID, 0, data.dungeonGenerator!=null, data.hasBeenFilled, null, new Point3D(0,64,0), childDims, newPackedLinkData, null);
newPackedDimData.add(dim);
DDSaveHandler.unpackDimData(newPackedDimData);
DDSaveHandler.unpackLinkData(allPackedLinks);
}
}
}

View File

@@ -0,0 +1,46 @@
package StevenDimDoors.mod_pocketDim.saving;
import java.util.List;
import StevenDimDoors.mod_pocketDim.Point3D;
public class PackedDimData
{
// These fields will be public since this is a simple data container
public final static long SAVE_DATA_VERSION_ID = 982405775L;
public final long SAVE_DATA_VERSION_ID_INSTANCE = SAVE_DATA_VERSION_ID;
public final int ID;
public final boolean IsDungeon;
public final boolean IsFilled;
public final int Depth;
public final int PackDepth;
public final int ParentID;
public final int RootID;
public final PackedDungeonData DungeonData;
public final Point3D Origin;
public final int Orientation;
public final List<Integer> ChildIDs;
public final List<PackedLinkData> Links;
public final List<PackedLinkTail> Tails;
// FIXME Missing dungeon data, not sure how to include it
public PackedDimData(int id, int depth, int packDepth, int parentID, int rootID, int orientation,
boolean isDungeon, boolean isFilled,PackedDungeonData dungeonData, Point3D origin, List<Integer> childIDs, List<PackedLinkData> links,
List<PackedLinkTail> tails)
{
ID = id;
Depth = depth;
PackDepth = packDepth;
ParentID = parentID;
RootID = rootID;
Orientation = orientation;
IsDungeon = isDungeon;
IsFilled = isFilled;
DungeonData = dungeonData;
Origin = origin;
ChildIDs = childIDs;
Links = links;
Tails = tails;
}
}

View File

@@ -0,0 +1,23 @@
package StevenDimDoors.mod_pocketDim.saving;
public class PackedDungeonData
{
public final int Weight;
public final boolean IsOpen;
public final boolean IsInternal;
public final String SchematicPath;
public final String SchematicName;
public final String DungeonTypeName;
public final String DungeonPackName;
public PackedDungeonData(int weight, boolean isOpen, boolean isInternal, String schematicPath, String schematicName, String dungeonTypeName, String dungeonPackName)
{
this.Weight= weight;
this.IsOpen=isOpen;
this.IsInternal=isInternal;
this.SchematicName=schematicName;
this.SchematicPath=schematicPath;
this.DungeonTypeName=dungeonTypeName;
this.DungeonPackName=dungeonPackName;
}
}

View File

@@ -0,0 +1,24 @@
package StevenDimDoors.mod_pocketDim.saving;
import java.util.List;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.util.Point4D;
public class PackedLinkData
{
public final Point4D source;
public final Point3D parent;
public final PackedLinkTail tail;
public final int orientation;
public final List<Point3D> children;
public PackedLinkData(Point4D source, Point3D parent, PackedLinkTail tail, int orientation, List<Point3D> children)
{
this.source=source;
this.parent=parent;
this.tail=tail;
this.orientation=orientation;
this.children=children;
}
}

View File

@@ -0,0 +1,16 @@
package StevenDimDoors.mod_pocketDim.saving;
import StevenDimDoors.mod_pocketDim.util.Point4D;
public class PackedLinkTail
{
public final Point4D destination;
public final int linkType;
public PackedLinkTail(Point4D destination, int linkType)
{
this.destination=destination;
this.linkType=linkType;
}
}

View File

@@ -0,0 +1,495 @@
package StevenDimDoors.mod_pocketDim.schematic;
import net.minecraft.block.Block;
import net.minecraft.block.BlockComparator;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.BlockRedstoneRepeater;
import net.minecraft.block.BlockStairs;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
public class BlockRotator
{
//This class is temporary. It's just a place in which to hold the old block rotation and transformation code
//until we can rewrite it.
public final static int EAST_DOOR_METADATA = 0;
private final static int BLOCK_ID_COUNT = 4096;
//Provides a fast lookup table for whether blocks have orientations
private final static boolean[] hasOrientations = new boolean[BLOCK_ID_COUNT];
static
{
hasOrientations[Block.dispenser.blockID] = true;
hasOrientations[Block.stairsStoneBrick.blockID] = true;
hasOrientations[Block.lever.blockID] = true;
hasOrientations[Block.stoneButton.blockID] = true;
hasOrientations[Block.redstoneRepeaterIdle.blockID] = true;
hasOrientations[Block.redstoneRepeaterActive.blockID] = true;
hasOrientations[Block.tripWireSource.blockID] = true;
hasOrientations[Block.torchWood.blockID] = true;
hasOrientations[Block.torchRedstoneIdle.blockID] = true;
hasOrientations[Block.torchRedstoneActive.blockID] = true;
hasOrientations[Block.doorIron.blockID] = true;
hasOrientations[Block.doorWood.blockID] = true;
hasOrientations[Block.pistonBase.blockID] = true;
hasOrientations[Block.pistonStickyBase.blockID] = true;
hasOrientations[Block.pistonExtension.blockID] = true;
hasOrientations[Block.redstoneComparatorIdle.blockID] = true;
hasOrientations[Block.redstoneComparatorActive.blockID] = true;
hasOrientations[Block.signPost.blockID] = true;
hasOrientations[Block.signWall.blockID] = true;
hasOrientations[Block.skull.blockID] = true;
hasOrientations[Block.ladder.blockID] = true;
hasOrientations[Block.vine.blockID] = true;
hasOrientations[Block.anvil.blockID] = true;
hasOrientations[Block.chest.blockID] = true;
hasOrientations[Block.chestTrapped.blockID] = true;
hasOrientations[Block.hopperBlock.blockID] = true;
hasOrientations[Block.stairsNetherBrick.blockID] = true;
hasOrientations[Block.stairsCobblestone.blockID] = true;
hasOrientations[Block.stairsNetherQuartz.blockID] = true;
hasOrientations[Block.stairsSandStone.blockID] = true;
hasOrientations[Block.stairsBrick.blockID] = true;
hasOrientations[Block.stairsWoodBirch.blockID] = true;
hasOrientations[Block.stairsWoodOak.blockID] = true;
hasOrientations[Block.stairsWoodJungle.blockID] = true;
hasOrientations[Block.stairsWoodSpruce.blockID] = true;
hasOrientations[Block.wood.blockID] = true;
hasOrientations[Block.blockNetherQuartz.blockID] = true;
hasOrientations[Block.railPowered.blockID] = true;
hasOrientations[Block.railDetector.blockID] = true;
hasOrientations[Block.railActivator.blockID] = true;
hasOrientations[Block.rail.blockID] = true;
hasOrientations[mod_pocketDim.dimensionalDoor.blockID] = true;
hasOrientations[mod_pocketDim.warpDoor.blockID] = true;
}
public static int transformMetadata(int metadata, int turns, int blockID)
{
//I changed rotations to reduce the monstrous code we had. It might be
//slightly less efficient, but it's easier to maintain for now. ~SenseiKiwi
//Correct negative turns and get the minimum number of rotations needed
turns += 1 << 16;
turns %= 4;
if (hasOrientations[blockID])
{
while (turns > 0)
{
metadata = rotateMetadataBy90(metadata, blockID);
turns--;
}
}
return metadata;
}
private static int rotateMetadataBy90(int metadata, int blockID)
{
//TODO: Replace this horrible function with something prettier. We promise we will for the next version,
//after switching to MC 1.6. PADRE, PLEASE FORGIVE OUR SINS.
if (blockID == Block.wood.blockID)
{
if (metadata >= 4 && metadata < 12)
{
metadata = (metadata % 8) + 4;
}
}
else if (blockID == Block.blockNetherQuartz.blockID)
{
if (metadata == 3 || metadata == 4)
{
metadata = (metadata - 2) % 2 + 3;
}
}
else if (blockID == Block.railPowered.blockID || blockID == Block.railDetector.blockID || blockID == Block.railActivator.blockID)
{
switch (metadata)
{
//Powered Track/Detector Track/Activator Track (off)
case 0:
metadata = 1;
break;
case 1:
metadata = 0;
break;
case 2:
metadata = 5;
break;
case 3:
metadata = 4;
break;
case 4:
metadata = 2;
break;
case 5:
metadata = 3;
break;
//Powered Track/Detector Track/Activator Track (on)
case 8:
metadata = 9;
break;
case 9:
metadata = 8;
break;
case 10:
metadata = 13;
break;
case 11:
metadata = 12;
break;
case 12:
metadata = 10;
break;
case 13:
metadata = 11;
break;
}
}
else if (blockID==Block.rail.blockID)
{
switch (metadata)
{
case 0:
metadata = 1;
break;
case 1:
metadata = 0;
break;
case 8:
metadata = 9;
break;
case 9:
metadata = 6;
break;
case 6:
metadata = 7;
break;
case 7:
metadata = 8;
break;
}
}
else if (Block.blocksList[blockID] instanceof BlockStairs)
{
switch (metadata)
{
case 0:
metadata = 2;
break;
case 1:
metadata = 3;
break;
case 2:
metadata = 1;
break;
case 3:
metadata = 0;
break;
case 7:
metadata = 4;
break;
case 6:
metadata = 5;
break;
case 5:
metadata = 7;
break;
case 4:
metadata = 6;
break;
}
}
else if (blockID == Block.chest.blockID || blockID == Block.chestTrapped.blockID || blockID == Block.ladder.blockID || blockID == Block.hopperBlock.blockID)
{
switch (metadata)
{
case 2:
metadata = 5;
break;
case 3:
metadata = 4;
break;
case 4:
metadata = 2;
break;
case 5:
metadata = 3;
break;
}
}
else if (blockID==Block.vine.blockID)
{
switch (metadata)
{
case 1:
metadata = 2;
break;
case 2:
metadata = 4;
break;
case 4:
metadata = 8;
break;
case 8:
metadata = 1;
break;
}
}
else if (blockID==Block.signWall.blockID)
{
switch (metadata)
{
case 3:
metadata = 4;
break;
case 2:
metadata = 5;
break;
case 4:
metadata = 2;
break;
case 5:
metadata = 3;
break;
}
}
else if (blockID==Block.signPost.blockID)
{
switch (metadata)
{
case 0:
metadata = 4;
break;
case 1:
metadata = 5;
break;
case 2:
metadata = 6;
break;
case 3:
metadata = 7;
break;
case 4:
metadata = 8;
break;
case 5:
metadata = 9;
break;
case 6:
metadata = 10;
break;
case 7:
metadata = 11;
break;
case 8:
metadata = 12;
break;
case 9:
metadata = 13;
break;
case 10:
metadata = 14;
break;
case 11:
metadata = 15;
break;
case 12:
metadata = 0;
break;
case 13:
metadata = 1;
break;
case 14:
metadata = 2;
break;
case 15:
metadata = 3;
break;
}
}
else if(blockID== Block.lever.blockID||blockID== Block.stoneButton.blockID||blockID== Block.woodenButton.blockID||blockID== Block.torchWood.blockID||blockID== Block.torchRedstoneIdle.blockID||blockID== Block.torchRedstoneActive.blockID)
{
switch (metadata)
{
case 12:
metadata = 9;
break;
case 11:
metadata = 10;
break;
case 10:
metadata = 12;
break;
case 9:
metadata = 11;
break;
case 2:
metadata = 4;
break;
case 3:
metadata = 2;
break;
case 1:
metadata = 3;
break;
case 4:
metadata = 1;
break;
}
}
else if(blockID== Block.pistonBase.blockID||blockID==Block.pistonExtension.blockID||blockID==Block.pistonStickyBase.blockID||blockID==Block.dispenser.blockID||blockID==Block.dropper.blockID)
{
switch (metadata)
{
case 4:
metadata = 2;
break;
case 5:
metadata = 3;
break;
case 13:
metadata = 11;
break;
case 12:
metadata = 10;
break;
case 3:
metadata = 4;
break;
case 2:
metadata = 5;
break;
case 11:
metadata = 12;
break;
case 10:
metadata = 13;
break;
}
}
else if (Block.blocksList[blockID] instanceof BlockRedstoneRepeater || Block.blocksList[blockID] instanceof BlockDoor || blockID== Block.tripWireSource.blockID || Block.blocksList[blockID] instanceof BlockComparator)
{
switch (metadata)
{
case 0:
metadata = 1;
break;
case 1:
metadata = 2;
break;
case 2:
metadata = 3;
break;
case 3:
metadata = 0;
break;
case 4:
metadata = 5;
break;
case 5:
metadata = 6;
break;
case 6:
metadata = 7;
break;
case 7:
metadata = 4;
break;
case 8:
metadata = 9;
break;
case 9:
metadata = 10;
break;
case 10:
metadata = 11;
break;
case 11:
metadata = 8;
break;
case 12:
metadata = 13;
break;
case 13:
metadata = 14;
break;
case 14:
metadata = 15;
break;
case 15:
metadata = 12;
break;
}
}
return metadata;
}
public static void transformPoint(Point3D position, Point3D srcOrigin, int angle, Point3D destOrigin)
{
//This function receives a position (e.g. point in schematic space), translates it relative
//to a source coordinate system (e.g. the point that will be the center of a schematic),
//then rotates and translates it to obtain the corresponding point in a destination
//coordinate system (e.g. the location of the entry rift in the pocket being generated).
//The result is returned by overwriting the original position so that new object references
//aren't needed. That way, repeated use of this function will not incur as much overhead.
//Position is only overwritten at the end, so it's okay to provide it as srcOrigin or destOrigin as well.
int tx = position.getX() - srcOrigin.getX();
int ty = position.getY() - srcOrigin.getY();
int tz = position.getZ() - srcOrigin.getZ();
//"int angle" specifies a rotation consistent with Minecraft's orientation system.
//That means each increment of 1 in angle would be a 90-degree clockwise turn.
//Given a starting direction A and a destination direction B, the rotation would be
//calculated by (B - A).
//Adjust angle into the expected range
if (angle < 0)
{
int correction = -(angle / 4);
angle = angle + 4 * (correction + 1);
}
angle = angle % 4;
int rx;
int rz;
switch (angle)
{
case 0: //No rotation
rx = tx;
rz = tz;
break;
case 1: //90 degrees clockwise
rx = -tz;
rz = tx;
break;
case 2: //180 degrees
rx = -tx;
rz = -tz;
break;
case 3: //270 degrees clockwise
rx = tz;
rz = -tx;
break;
default: //This should never happen
throw new IllegalStateException("Invalid angle value. This should never happen!");
}
position.setX( rx + destOrigin.getX() );
position.setY( ty + destOrigin.getY() );
position.setZ( rz + destOrigin.getZ() );
}
}

View File

@@ -0,0 +1,74 @@
package StevenDimDoors.mod_pocketDim.schematic;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.Point3D;
public class CompactBoundsOperation extends WorldOperation
{
private int minX;
private int minY;
private int minZ;
private int maxX;
private int maxY;
private int maxZ;
public CompactBoundsOperation()
{
super("CompactBoundsOperation");
}
@Override
protected boolean initialize(World world, int x, int y, int z, int width, int height, int length)
{
minX = Integer.MAX_VALUE;
minY = Integer.MAX_VALUE;
minZ = Integer.MAX_VALUE;
maxX = x;
maxY = y;
maxZ = z;
return true;
}
@Override
protected boolean applyToBlock(World world, int x, int y, int z)
{
//This could be done more efficiently, but honestly, this is the simplest approach and it
//makes it easy for us to verify that the code is correct.
if (!world.isAirBlock(x, y, z))
{
maxX = x > maxX ? x : maxX;
maxZ = z > maxZ ? z : maxZ;
maxY = y > maxY ? y : maxY;
minX = x < minX ? x : minX;
minZ = z < minZ ? z : minZ;
minY = y < minY ? y : minY;
}
return true;
}
@Override
protected boolean finish()
{
if (minX == Integer.MAX_VALUE)
{
//The whole search space was empty!
//Compact the space to a single block.
minX = maxX;
minY = maxY;
minZ = maxZ;
return false;
}
return true;
}
public Point3D getMaxCorner()
{
return new Point3D(maxX, maxY, maxZ);
}
public Point3D getMinCorner()
{
return new Point3D(minX, minY, minZ);
}
}

View File

@@ -0,0 +1,58 @@
package StevenDimDoors.mod_pocketDim.schematic;
import java.util.ArrayList;
public class CompoundFilter extends SchematicFilter {
private ArrayList<SchematicFilter> filters;
public CompoundFilter()
{
super("CompoundFilter");
filters = new ArrayList<SchematicFilter>();
}
public void addFilter(SchematicFilter filter)
{
filters.add(filter);
}
@Override
protected boolean initialize(Schematic schematic, short[] blocks, byte[] metadata)
{
for (SchematicFilter filter : filters)
{
if (!filter.initialize(schematic, blocks, metadata))
{
return false;
}
}
return !filters.isEmpty();
}
@Override
protected boolean finish()
{
for (SchematicFilter filter : filters)
{
if (!filter.finish())
{
return false;
}
}
return true;
}
@Override
protected boolean applyToBlock(int index, short[] blocks, byte[] metadata)
{
for (SchematicFilter filter : filters)
{
if (filter.applyToBlock(index, blocks, metadata))
{
return filter.terminates();
}
}
return false;
}
}

View File

@@ -0,0 +1,21 @@
package StevenDimDoors.mod_pocketDim.schematic;
public class InvalidSchematicException extends Exception {
private static final long serialVersionUID = -1011044077455149932L;
public InvalidSchematicException()
{
super();
}
public InvalidSchematicException(String message)
{
super(message);
}
public InvalidSchematicException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@@ -0,0 +1,76 @@
package StevenDimDoors.mod_pocketDim.schematic;
public class ReplacementFilter extends SchematicFilter {
private short targetBlock;
private byte targetMetadata;
private boolean matchMetadata;
private short replacementBlock;
private byte replacementMetadata;
private boolean changeMetadata;
public ReplacementFilter(short targetBlock, byte targetMetadata, short replacementBlock, byte replacementMetadata)
{
super("ReplacementFilter");
this.targetBlock = targetBlock;
this.targetMetadata = targetMetadata;
this.matchMetadata = true;
this.replacementBlock = replacementBlock;
this.replacementMetadata = replacementMetadata;
this.changeMetadata = true;
}
public ReplacementFilter(short targetBlock, short replacementBlock, byte replacementMetadata)
{
super("ReplacementFilter");
this.targetBlock = targetBlock;
this.matchMetadata = false;
this.replacementBlock = replacementBlock;
this.replacementMetadata = replacementMetadata;
this.changeMetadata = true;
}
public ReplacementFilter(short targetBlock, byte targetMetadata, short replacementBlock)
{
super("ReplacementFilter");
this.targetBlock = targetBlock;
this.targetMetadata = targetMetadata;
this.matchMetadata = true;
this.replacementBlock = replacementBlock;
this.changeMetadata = false;
}
public ReplacementFilter(short targetBlock, short replacementBlock)
{
super("ReplacementFilter");
this.targetBlock = targetBlock;
this.matchMetadata = false;
this.replacementBlock = replacementBlock;
this.changeMetadata = false;
}
@Override
protected boolean applyToBlock(int index, short[] blocks, byte[] metadata)
{
if (blocks[index] == targetBlock)
{
if ((matchMetadata && metadata[index] == targetMetadata) || !matchMetadata)
{
blocks[index] = replacementBlock;
if (changeMetadata)
{
metadata[index] = replacementMetadata;
}
return true;
}
}
return false;
}
@Override
protected boolean terminates()
{
return false;
}
}

View File

@@ -0,0 +1,435 @@
package StevenDimDoors.mod_pocketDim.schematic;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import net.minecraft.block.Block;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import StevenDimDoors.mod_pocketDim.Point3D;
/**
* Represents an MC schematic and provides functions for loading, storing, and manipulating schematics.
* This functionality has no dependencies to Dimensional Doors.
*/
public class Schematic {
protected short width;
protected short height;
protected short length;
protected short[] blocks;
protected byte[] metadata;
protected NBTTagList tileEntities;
protected Schematic(short width, short height, short length, short[] blocks, byte[] metadata, NBTTagList tileEntities)
{
this.width = width;
this.height = height;
this.length = length;
this.blocks = blocks;
this.metadata = metadata;
this.tileEntities = tileEntities;
}
protected Schematic(Schematic source)
{
//Shallow copy constructor - critical for code reuse in derived classes since
//source's fields will be inaccessible if the derived class is in another package.
this.width = source.width;
this.height = source.height;
this.length = source.length;
this.blocks = source.blocks;
this.metadata = source.metadata;
this.tileEntities = source.tileEntities;
}
public int calculateIndex(int x, int y, int z)
{
if (x < 0 || x >= width)
throw new IndexOutOfBoundsException("x must be non-negative and less than width");
if (y < 0 || y >= height)
throw new IndexOutOfBoundsException("y must be non-negative and less than height");
if (z < 0 || z >= length)
throw new IndexOutOfBoundsException("z must be non-negative and less than length");
return (y * width * length + z * width + x);
}
public Point3D calculatePoint(int index)
{
int y = index / (width * length);
index -= y * width * length;
int z = index / width;
index -= z * width;
int x = index;
return new Point3D(x, y, z);
}
public int calculateIndexBelow(int index)
{
return index - (width * length);
}
public short getWidth()
{
return width;
}
public short getHeight()
{
return height;
}
public short getLength()
{
return length;
}
public short getBlockID(int x, int y, int z)
{
return blocks[calculateIndex(x, y, z)];
}
public byte getBlockMetadata(int x, int y, int z)
{
return metadata[calculateIndex(x, y, z)];
}
public NBTTagList getTileEntities()
{
return (NBTTagList) tileEntities.copy();
}
public static Schematic readFromFile(String schematicPath) throws FileNotFoundException, InvalidSchematicException
{
return readFromFile(new File(schematicPath));
}
public static Schematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException
{
// TODO: fix resource leaks here
return readFromStream(new FileInputStream(schematicFile));
}
public static Schematic readFromResource(String resourcePath) throws InvalidSchematicException
{
//We need an instance of a class in the mod to retrieve a resource
Schematic empty = new Schematic((short) 0, (short) 0, (short) 0, null, null, null);
InputStream schematicStream = empty.getClass().getResourceAsStream(resourcePath);
return readFromStream(schematicStream);
}
public static Schematic readFromStream(InputStream schematicStream) throws InvalidSchematicException
{
short width;
short height;
short length;
int volume;
int pairs;
byte[] metadata = null; //block metadata
byte[] lowBits = null; //first 8 bits of the block IDs
byte[] highBits = null; //additional 4 bits of the block IDs
short[] blocks = null; //list of combined block IDs
NBTTagList tileEntities = null; //storage for tile entities in NBT form
NBTTagCompound schematicTag; //the NBT data extracted from the schematic file
boolean hasExtendedBlockIDs; //indicates whether the schematic contains extended block IDs
try
{
try
{
schematicTag = CompressedStreamTools.readCompressed(schematicStream);
schematicStream.close(); //readCompressed() probably closes the stream anyway, but close again to be sure.
}
catch (Exception ex)
{
throw new InvalidSchematicException("The schematic could not be decoded.");
}
//load size of schematic to generate
width = schematicTag.getShort("Width");
height = schematicTag.getShort("Height");
length = schematicTag.getShort("Length");
volume = width * length * height;
if (width < 0)
throw new InvalidSchematicException("The schematic cannot have a negative width.");
if (height < 0)
throw new InvalidSchematicException("The schematic cannot have a negative height.");
if (length < 0)
throw new InvalidSchematicException("The schematic cannot have a negative length.");
//load block info
lowBits = schematicTag.getByteArray("Blocks");
highBits = schematicTag.getByteArray("AddBlocks");
metadata = schematicTag.getByteArray("Data");
hasExtendedBlockIDs = (highBits.length != 0);
if (volume != lowBits.length)
throw new InvalidSchematicException("The schematic has data for fewer blocks than its dimensions indicate.");
if (volume != metadata.length)
throw new InvalidSchematicException("The schematic has metadata for fewer blocks than its dimensions indicate.");
if (volume > 2 * highBits.length && hasExtendedBlockIDs)
throw new InvalidSchematicException("The schematic has extended block IDs for fewer blocks than its dimensions indicate.");
blocks = new short[volume];
if (hasExtendedBlockIDs)
{
//Combine the split block IDs into a single value
pairs = volume - (volume & 1);
int index;
for (index = 0; index < pairs; index += 2)
{
blocks[index] = (short) (((highBits[index >> 1] & 0x0F) << 8) + (lowBits[index] & 0xFF));
blocks[index + 1] = (short) (((highBits[index >> 1] & 0xF0) << 4) + (lowBits[index + 1] & 0xFF));
}
if (index < volume)
{
blocks[index] = lowBits[index >> 1];
}
}
else
{
//Copy the blockIDs
for (int index = 0; index < volume; index++)
{
blocks[index] = (short) (lowBits[index] & 0xFF);
}
}
//Get the list of tile entities
tileEntities = schematicTag.getTagList("TileEntities");
Schematic result = new Schematic(width, height, length, blocks, metadata, tileEntities);
return result;
}
catch (InvalidSchematicException ex)
{
//Throw the exception again to pass it to the caller.
throw ex;
}
catch (Exception ex)
{
throw new InvalidSchematicException("An unexpected error occurred while trying to decode the schematic.", ex);
}
}
public static Schematic copyFromWorld(World world, int x, int y, int z, short width, short height, short length, boolean doCompactBounds)
{
if (doCompactBounds)
{
//Adjust the vertical bounds to reasonable values if necessary
int worldHeight = world.getHeight();
int fixedY = (y < 0) ? 0 : y;
int fixedHeight = height + y - fixedY;
if (fixedHeight + fixedY >= worldHeight)
{
fixedHeight = worldHeight - fixedY;
}
//Compact the area to be copied to remove empty borders
CompactBoundsOperation compactor = new CompactBoundsOperation();
compactor.apply(world, x, fixedY, z, width, fixedHeight, length);
Point3D minCorner = compactor.getMinCorner();
Point3D maxCorner = compactor.getMaxCorner();
short compactWidth = (short) (maxCorner.getX() - minCorner.getX() + 1);
short compactHeight = (short) (maxCorner.getY() - minCorner.getY() + 1);
short compactLength = (short) (maxCorner.getZ() - minCorner.getZ() + 1);
return copyFromWorld(world, minCorner.getX(), minCorner.getY(), minCorner.getZ(),
compactWidth, compactHeight, compactLength);
}
else
{
return copyFromWorld(world, x, y, z, width, height, length);
}
}
private static Schematic copyFromWorld(World world, int x, int y, int z, short width, short height, short length)
{
//Short and sweet ^_^
WorldCopyOperation copier = new WorldCopyOperation();
copier.apply(world, x, y, z, width, height, length);
return new Schematic(width, height, length, copier.getBlockIDs(), copier.getMetadata(), copier.getTileEntities());
}
private static boolean encodeBlockIDs(short[] blocks, byte[] lowBits, byte[] highBits)
{
int index;
int length = blocks.length - (blocks.length & 1);
boolean hasHighBits = false;
for (index = 0; index < length; index += 2)
{
highBits[index >> 1] = (byte) (((blocks[index] >> 8) & 0x0F) + ((blocks[index + 1] >> 4) & 0xF0));
hasHighBits |= (highBits[index >> 1] != 0);
}
if (index < blocks.length)
{
highBits[index >> 1] = (byte) ((blocks[index] >> 8) & 0x0F);
hasHighBits |= (highBits[index >> 1] != 0);
}
for (index = 0; index < blocks.length; index++)
{
lowBits[index] = (byte) (blocks[index] & 0xFF);
}
return hasHighBits;
}
public NBTTagCompound writeToNBT()
{
return writeToNBT(true);
}
protected NBTTagCompound writeToNBT(boolean copyTileEntities)
{
return writeToNBT(width, height, length, blocks, metadata, tileEntities, copyTileEntities);
}
protected static NBTTagCompound writeToNBT(short width, short height, short length, short[] blocks, byte[] metadata,
NBTTagList tileEntities, boolean copyTileEntities)
{
//This is the main storage function. Schematics are really compressed NBT tags, so if we can generate
//the tags, most of the work is done. All the other storage functions will rely on this one.
NBTTagCompound schematicTag = new NBTTagCompound("Schematic");
schematicTag.setShort("Width", width);
schematicTag.setShort("Length", length);
schematicTag.setShort("Height", height);
schematicTag.setTag("Entities", new NBTTagList());
schematicTag.setString("Materials", "Alpha");
byte[] lowBits = new byte[blocks.length];
byte[] highBits = new byte[(blocks.length >> 1) + (blocks.length & 1)];
boolean hasExtendedIDs = encodeBlockIDs(blocks, lowBits, highBits);
schematicTag.setByteArray("Blocks", lowBits);
schematicTag.setByteArray("Data", metadata);
if (hasExtendedIDs)
{
schematicTag.setByteArray("AddBlocks", highBits);
}
if (copyTileEntities)
{
//Used when the result of this function will be passed outside this class.
//Avoids exposing the private field to external modifications.
schematicTag.setTag("TileEntities", tileEntities.copy());
}
else
{
//Used when the result of this function is for internal use.
//It's more efficient not to copy the tags unless it's needed.
schematicTag.setTag("TileEntities", tileEntities);
}
return schematicTag;
}
public void writeToFile(String schematicPath) throws IOException
{
writeToFile(new File(schematicPath));
}
public void writeToFile(File schematicFile) throws IOException
{
FileOutputStream outputStream = new FileOutputStream(schematicFile);
CompressedStreamTools.writeCompressed(writeToNBT(false), outputStream);
//writeCompressed() probably closes the stream on its own - call close again just in case.
//Closing twice will not throw an exception.
outputStream.close();
}
public boolean applyFilter(SchematicFilter filter)
{
return filter.apply(this, this.blocks, this.metadata);
}
public void copyToWorld(World world, int x, int y, int z)
{
//This isn't implemented as a WorldOperation because it doesn't quite fit the structure of those operations.
//It's not worth the trouble in this case.
int index;
int count;
int dx, dy, dz;
//Copy blocks and metadata into the world
index = 0;
for (dy = 0; dy < height; dy++)
{
for (dz = 0; dz < length; dz++)
{
for (dx = 0; dx < width; dx++)
{
//In the future, we might want to make this more efficient by building whole chunks at a time
setBlockDirectly(world, x + dx, y + dy, z + dz, blocks[index], metadata[index]);
index++;
}
}
}
//Copy tile entities into the world
count = tileEntities.tagCount();
for (index = 0; index < count; index++)
{
NBTTagCompound tileTag = (NBTTagCompound) tileEntities.tagAt(index);
//Rewrite its location to be in world coordinates
dx = tileTag.getInteger("x") + x;
dy = tileTag.getInteger("y") + y;
dz = tileTag.getInteger("z") + z;
tileTag.setInteger("x", dx);
tileTag.setInteger("y", dy);
tileTag.setInteger("z", dz);
//Load the tile entity and put it in the world
world.setBlockTileEntity(dx, dy, dz, TileEntity.createAndLoadEntity(tileTag));
}
}
protected static void setBlockDirectly(World world, int x, int y, int z, int blockID, int metadata)
{
if (blockID != 0 && Block.blocksList[blockID] == null)
{
return;
}
int cX = x >> 4;
int cZ = z >> 4;
int cY = y >> 4;
Chunk chunk;
int localX = (x % 16) < 0 ? (x % 16) + 16 : (x % 16);
int localZ = (z % 16) < 0 ? (z % 16) + 16 : (z % 16);
ExtendedBlockStorage extBlockStorage;
try
{
chunk = world.getChunkFromChunkCoords(cX, cZ);
extBlockStorage = chunk.getBlockStorageArray()[cY];
if (extBlockStorage == null)
{
extBlockStorage = new ExtendedBlockStorage(cY << 4, !world.provider.hasNoSky);
chunk.getBlockStorageArray()[cY] = extBlockStorage;
}
extBlockStorage.setExtBlockID(localX, y & 15, localZ, blockID);
extBlockStorage.setExtBlockMetadata(localX, y & 15, localZ, metadata);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,56 @@
package StevenDimDoors.mod_pocketDim.schematic;
public class SchematicFilter {
private String name;
protected SchematicFilter(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public boolean apply(Schematic schematic, short[] blocks, byte[] metadata)
{
if (!initialize(schematic, blocks, metadata))
return false;
for (int index = 0; index < blocks.length; index++)
{
if (applyToBlock(index, blocks, metadata) && terminates())
return false;
}
return finish();
}
protected boolean initialize(Schematic schematic, short[] blocks, byte[] metadata)
{
return true;
}
protected boolean applyToBlock(int index, short[] blocks, byte[] metadata)
{
return true;
}
protected boolean finish()
{
return true;
}
protected boolean terminates()
{
return true;
}
@Override
public String toString()
{
return name;
}
}

View File

@@ -0,0 +1,76 @@
package StevenDimDoors.mod_pocketDim.schematic;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
public class WorldCopyOperation extends WorldOperation
{
private int originX;
private int originY;
private int originZ;
private int index;
private short[] blockIDs;
private byte[] metadata;
private NBTTagList tileEntities;
public WorldCopyOperation()
{
super("WorldCopyOperation");
blockIDs = null;
metadata = null;
tileEntities = null;
}
@Override
protected boolean initialize(World world, int x, int y, int z, int width, int height, int length)
{
index = 0;
originX = x;
originY = y;
originZ = z;
blockIDs = new short[width * height * length];
metadata = new byte[width * height * length];
tileEntities = new NBTTagList();
return true;
}
@Override
protected boolean applyToBlock(World world, int x, int y, int z)
{
blockIDs[index] = (short) world.getBlockId(x, y, z);
metadata[index] = (byte) world.getBlockMetadata(x, y, z);
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
if (tileEntity != null)
{
//Extract tile entity data
NBTTagCompound tileTag = new NBTTagCompound();
tileEntity.writeToNBT(tileTag);
//Translate the tile entity's position from the world's coordinate system
//to the schematic's coordinate system.
tileTag.setInteger("x", x - originX);
tileTag.setInteger("y", y - originY);
tileTag.setInteger("z", z - originZ);
tileEntities.appendTag(tileTag);
}
index++; //This works assuming the loops in WorldOperation are done in YZX order
return true;
}
public short[] getBlockIDs()
{
return blockIDs;
}
public byte[] getMetadata()
{
return metadata;
}
public NBTTagList getTileEntities()
{
return tileEntities;
}
}

View File

@@ -0,0 +1,76 @@
package StevenDimDoors.mod_pocketDim.schematic;
import StevenDimDoors.mod_pocketDim.Point3D;
import net.minecraft.world.World;
public abstract class WorldOperation {
private String name;
public WorldOperation(String name)
{
this.name = name;
}
protected boolean initialize(World world, int x, int y, int z, int width, int height, int length)
{
return true;
}
protected abstract boolean applyToBlock(World world, int x, int y, int z);
protected boolean finish()
{
return true;
}
public boolean apply(World world, Point3D minCorner, Point3D maxCorner)
{
int x = minCorner.getX();
int y = minCorner.getY();
int z = minCorner.getZ();
int width = maxCorner.getX() - x + 1;
int height = maxCorner.getY() - y + 1;
int length = maxCorner.getZ() - z + 1;
return apply(world, x, y, z, width, height, length);
}
public boolean apply(World world, int x, int y, int z, int width, int height, int length)
{
if (!initialize(world, x, y, z, width, height, length))
return false;
int cx, cy, cz;
int limitX = x + width;
int limitY = y + height;
int limitZ = z + length;
//The order of these loops is important. Don't change it! It's used to avoid calculating
//indeces in some schematic operations. The proper order is YZX.
for (cy = y; cy < limitY; cy++)
{
for (cz = z; cz < limitZ; cz++)
{
for (cx = x; cx < limitX; cx++)
{
if (!applyToBlock(world, cx, cy, cz))
return false;
}
}
}
return finish();
}
public String getName()
{
return name;
}
@Override
public String toString()
{
return name;
}
}

View File

@@ -0,0 +1,76 @@
package StevenDimDoors.mod_pocketDim.ticking;
import java.util.ArrayList;
import java.util.EnumSet;
import StevenDimDoors.mod_pocketDim.core.DDTeleporter;
import cpw.mods.fml.common.ITickHandler;
import cpw.mods.fml.common.TickType;
public class CommonTickHandler implements ITickHandler, IRegularTickSender
{
private static final String PROFILING_LABEL = "Dimensional Doors: Common Tick";
private int tickCount = 0;
private ArrayList<RegularTickReceiverInfo> receivers;
public CommonTickHandler()
{
this.receivers = new ArrayList<RegularTickReceiverInfo>();
}
@Override
public void registerForTicking(IRegularTickReceiver receiver, int interval, boolean onTickStart)
{
RegularTickReceiverInfo info = new RegularTickReceiverInfo(receiver, interval, onTickStart);
receivers.add(info);
}
@Override
public void tickStart(EnumSet<TickType> type, Object... tickData)
{
if (type.equals(EnumSet.of(TickType.SERVER)))
{
for (RegularTickReceiverInfo info : receivers)
{
if (info.OnTickStart && tickCount % info.Interval == 0)
{
info.RegularTickReceiver.notifyTick();
}
}
}
//TODO: Stuck this in here because it's already rather hackish.
//We should standardize this as an IRegularTickReceiver in the future. ~SenseiKiwi
if (DDTeleporter.cooldown > 0)
{
DDTeleporter.cooldown--;
}
}
@Override
public void tickEnd(EnumSet<TickType> type, Object... tickData)
{
for (RegularTickReceiverInfo info : receivers)
{
if (!info.OnTickStart && tickCount % info.Interval == 0)
{
info.RegularTickReceiver.notifyTick();
}
}
tickCount++; //There is no need to reset the counter. Let it overflow.
}
@Override
public EnumSet<TickType> ticks()
{
return EnumSet.of(TickType.SERVER);
}
@Override
public String getLabel()
{
return PROFILING_LABEL; //Used for profiling!
}
}

View File

@@ -0,0 +1,10 @@
package StevenDimDoors.mod_pocketDim.ticking;
public interface IRegularTickReceiver {
/**
* This method is called periodically to execute code based on ticks elapsed.
*/
public void notifyTick();
}

Some files were not shown because too many files have changed in this diff Show More