diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index a6e3745b..afc1c35f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -1,9 +1,7 @@ package StevenDimDoors.mod_pocketDim; -import paulscode.sound.SoundSystem; import net.minecraft.block.Block; 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; @@ -14,15 +12,13 @@ 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.Event; 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.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.terraingen.InitMapGenEvent; import net.minecraftforge.event.world.WorldEvent; -import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; @@ -30,6 +26,7 @@ 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 StevenDimDoors.mod_pocketDim.world.fortresses.DDNetherFortressGenerator; import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -43,6 +40,15 @@ public class EventHookContainer this.properties = properties; } + @ForgeSubscribe(priority = EventPriority.LOW) + public void onMapGen(InitMapGenEvent event) + { + if (event.type == InitMapGenEvent.EventType.NETHER_BRIDGE) + { + event.newGen = new DDNetherFortressGenerator(); + } + } + @SideOnly(Side.CLIENT) @ForgeSubscribe public void onSoundLoad(SoundLoadEvent event) @@ -56,8 +62,8 @@ public class EventHookContainer event.manager.addSound(mod_pocketDim.modid+":riftClose.ogg"); event.manager.addSound(mod_pocketDim.modid+":riftDoor.ogg"); event.manager.addSound(mod_pocketDim.modid+":creepy.ogg"); - } + @SideOnly(Side.CLIENT) @ForgeSubscribe public void onSoundEffectResult(PlayBackgroundMusicEvent event) @@ -68,7 +74,6 @@ public class EventHookContainer } } - @ForgeSubscribe public void onPlayerEvent(PlayerInteractEvent event) { @@ -113,6 +118,7 @@ public class EventHookContainer } } } + @ForgeSubscribe public void onWorldLoad(WorldEvent.Load event) { @@ -129,7 +135,7 @@ public class EventHookContainer RiftRegenerator.regenerateRiftsInAllWorlds(); } - if(event.world!=null) + if (event.world != null) { this.playMusicForDim(event.world); } @@ -140,7 +146,8 @@ public class EventHookContainer { event.setCanceled(event.entity.worldObj.provider.dimensionId == properties.LimboDimensionID); } - @ForgeSubscribe(priority=EventPriority.HIGHEST) + + @ForgeSubscribe(priority = EventPriority.HIGHEST) public boolean LivingDeathEvent(LivingDeathEvent event) { Entity entity = event.entity; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 26fab1e9..3c61aa1e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -174,7 +174,9 @@ public class mod_pocketDim properties = DDProperties.initialize(new File(path)); //Now do other stuff - MinecraftForge.EVENT_BUS.register(new EventHookContainer(properties)); + EventHookContainer hooks = new EventHookContainer(properties); + MinecraftForge.EVENT_BUS.register(hooks); + MinecraftForge.TERRAIN_GEN_BUS.register(hooks); gatewayGenerator = new GatewayGenerator(properties); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java new file mode 100644 index 00000000..d8c149ef --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java @@ -0,0 +1,181 @@ +package StevenDimDoors.mod_pocketDim.world.fortresses; + +import java.util.List; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.StructureBoundingBox; +import net.minecraft.world.gen.structure.StructureComponent; +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.items.BaseItemDoor; + +public class ComponentNetherGateway extends StructureComponent +{ + // Note: In this case, it doesn't really matter which class we extend, since this class will + // never be passed to Minecraft. We just need an instance to have access to structure-building methods. + // If Forge supports adding custom fortress structures in the future, then we might have to change + // our class to extend ComponentNetherBridgeCrossing or something along those lines. ~SenseiKiwi + + public ComponentNetherGateway(int componentType, Random random, StructureBoundingBox bounds, int coordBaseMode) + { + super(componentType); + + this.boundingBox = bounds; + this.coordBaseMode = coordBaseMode; + } + + /** + * Creates and returns a new component piece. Or null if it could not find enough room to place it. + */ + public static ComponentNetherGateway createValidComponent(List components, Random random, int minX, int minY, int minZ, int coordBaseMode, int componentType) + { + StructureBoundingBox bounds = StructureBoundingBox.getComponentToAddBoundingBox(minX, minY, minZ, -2, 0, 0, 7, 9, 7, coordBaseMode); + return isAboveGround(bounds) && StructureComponent.findIntersecting(components, bounds) == null ? new ComponentNetherGateway(componentType, random, bounds, coordBaseMode) : null; + } + + public static ComponentNetherGateway createFromComponent(StructureComponent component, Random random) + { + // Create an instance of our gateway component using the same data as another component, + // likely a component that we intend to replace during generation + return new ComponentNetherGateway( component.getComponentType(), random, + component.getBoundingBox(), getCoordBaseMode(component)); + } + + private static int getCoordBaseMode(StructureComponent component) + { + // This is a hack to get the value of a component's coordBaseMode field. + // It's essentially the orientation of the component... with a weird name. + return component.func_143010_b().getInteger("O"); + } + + /** + * Checks if the bounding box's minY is > 10 + */ + protected static boolean isAboveGround(StructureBoundingBox par0StructureBoundingBox) + { + return par0StructureBoundingBox != null && par0StructureBoundingBox.minY > 10; + } + + /** + * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes Mineshafts at + * the end, it adds Fences... + */ + public boolean addComponentParts(World world, Random random, StructureBoundingBox bounds) + { + int NETHER_SLAB_METADATA = 6; + + // Set all the blocks in the area of the room to air + this.fillWithBlocks(world, bounds, 0, 2, 0, 6, 6, 6, 0, 0, false); + // Set up the platform under the gateway + this.fillWithBlocks(world, bounds, 0, 0, 0, 6, 1, 6, Block.netherBrick.blockID, Block.netherBrick.blockID, false); + + // Build the fence at the back of the room + this.fillWithBlocks(world, bounds, 1, 2, 6, 5, 2, 6, Block.netherBrick.blockID, Block.netherBrick.blockID, false); + this.fillWithBlocks(world, bounds, 1, 3, 6, 5, 3, 6, Block.netherFence.blockID, Block.netherFence.blockID, false); + + // Build the fences at the sides of the room + this.fillWithBlocks(world, bounds, 0, 2, 0, 0, 2, 6, Block.netherBrick.blockID, Block.netherBrick.blockID, false); + this.fillWithBlocks(world, bounds, 0, 3, 0, 0, 3, 6, Block.netherFence.blockID, Block.netherFence.blockID, false); + + this.fillWithBlocks(world, bounds, 6, 2, 0, 6, 2, 6, Block.netherBrick.blockID, Block.netherBrick.blockID, false); + this.fillWithBlocks(world, bounds, 6, 3, 0, 6, 3, 6, Block.netherFence.blockID, Block.netherFence.blockID, false); + + // Build the fence portions closest to the entrance + this.placeBlockAtCurrentPosition(world, Block.netherBrick.blockID, 0, 1, 2, 0, bounds); + this.placeBlockAtCurrentPosition(world, Block.netherFence.blockID, 0, 1, 3, 0, bounds); + + this.placeBlockAtCurrentPosition(world, Block.netherBrick.blockID, 0, 5, 2, 0, bounds); + this.placeBlockAtCurrentPosition(world, Block.netherFence.blockID, 0, 5, 3, 0, bounds); + + // Build the first layer of the gateway + this.fillWithBlocks(world, bounds, 1, 2, 2, 5, 2, 5, Block.netherBrick.blockID, Block.netherBrick.blockID, false); + this.fillWithMetadataBlocks(world, bounds, 1, 2, 1, 5, 2, 1, Block.stoneSingleSlab.blockID, NETHER_SLAB_METADATA, Block.stoneSingleSlab.blockID, NETHER_SLAB_METADATA, false); + + this.placeBlockAtCurrentPosition(world, Block.stoneSingleSlab.blockID, NETHER_SLAB_METADATA, 1, 2, 2, bounds); + this.placeBlockAtCurrentPosition(world, Block.stoneSingleSlab.blockID, NETHER_SLAB_METADATA, 5, 2, 2, bounds); + + // Build the second layer of the gateway + int orientation = this.getMetadataWithOffset(Block.stairsNetherBrick.blockID, 2); + this.fillWithBlocks(world, bounds, 2, 3, 3, 2, 3, 4, Block.netherBrick.blockID, Block.netherBrick.blockID, false); + this.fillWithBlocks(world, bounds, 4, 3, 3, 4, 3, 4, Block.netherBrick.blockID, Block.netherBrick.blockID, false); + this.placeBlockAtCurrentPosition(world, Block.netherBrick.blockID, 0, 3, 3, 4, bounds); + this.placeBlockAtCurrentPosition(world, Block.stairsNetherBrick.blockID, orientation, 3, 3, 5, bounds); + + // Build the third layer of the gateway + // We add 4 to get the rotated metadata for upside-down stairs + // because Minecraft only supports metadata rotations for normal stairs -_- + this.fillWithMetadataBlocks(world, bounds, 2, 4, 4, 4, 4, 4, Block.stairsNetherBrick.blockID, orientation, Block.stairsNetherBrick.blockID, orientation, false); + + this.placeBlockAtCurrentPosition(world, Block.stairsNetherBrick.blockID, this.getMetadataWithOffset(Block.stairsNetherBrick.blockID, 0) + 4, 2, 4, 3, bounds); + this.placeBlockAtCurrentPosition(world, Block.stairsNetherBrick.blockID, this.getMetadataWithOffset(Block.stairsNetherBrick.blockID, 1) + 4, 4, 4, 3, bounds); + + // Build the fourth layer of the gateway + this.placeBlockAtCurrentPosition(world, Block.netherBrick.blockID, 0, 3, 5, 3, bounds); + + this.placeBlockAtCurrentPosition(world, Block.netherrack.blockID, 0, 2, 5, 3, bounds); + this.placeBlockAtCurrentPosition(world, Block.stairsNetherBrick.blockID, this.getMetadataWithOffset(Block.stairsNetherBrick.blockID, 0) + 4, 1, 5, 3, bounds); + this.placeBlockAtCurrentPosition(world, Block.stairsNetherBrick.blockID, this.getMetadataWithOffset(Block.stairsNetherBrick.blockID, 3) + 4, 2, 5, 2, bounds); + this.placeBlockAtCurrentPosition(world, Block.stairsNetherBrick.blockID, this.getMetadataWithOffset(Block.stairsNetherBrick.blockID, 2) + 4, 2, 5, 4, bounds); + + this.placeBlockAtCurrentPosition(world, Block.netherrack.blockID, 0, 4, 5, 3, bounds); + this.placeBlockAtCurrentPosition(world, Block.stairsNetherBrick.blockID, this.getMetadataWithOffset(Block.stairsNetherBrick.blockID, 1) + 4, 5, 5, 3, bounds); + this.placeBlockAtCurrentPosition(world, Block.stairsNetherBrick.blockID, this.getMetadataWithOffset(Block.stairsNetherBrick.blockID, 3) + 4, 4, 5, 2, bounds); + this.placeBlockAtCurrentPosition(world, Block.stairsNetherBrick.blockID, this.getMetadataWithOffset(Block.stairsNetherBrick.blockID, 2) + 4, 4, 5, 4, bounds); + + // Build the top layer of the gateway + this.placeBlockAtCurrentPosition(world, Block.netherFence.blockID, 0, 3, 6, 3, bounds); + + this.placeBlockAtCurrentPosition(world, Block.fire.blockID, 0, 2, 6, 3, bounds); + this.placeBlockAtCurrentPosition(world, Block.netherFence.blockID, 0, 1, 6, 3, bounds); + this.placeBlockAtCurrentPosition(world, Block.netherFence.blockID, 0, 2, 6, 2, bounds); + this.placeBlockAtCurrentPosition(world, Block.netherFence.blockID, 0, 2, 6, 4, bounds); + + this.placeBlockAtCurrentPosition(world, Block.fire.blockID, 0, 4, 6, 3, bounds); + this.placeBlockAtCurrentPosition(world, Block.netherFence.blockID, 0, 5, 6, 3, bounds); + this.placeBlockAtCurrentPosition(world, Block.netherFence.blockID, 0, 4, 6, 2, bounds); + this.placeBlockAtCurrentPosition(world, Block.netherFence.blockID, 0, 4, 6, 4, bounds); + + // Place the transient door + int y = this.getYWithOffset(3); + int x = this.getXWithOffset(3, 3); + int z = this.getZWithOffset(3, 3); + DimLink link; + NewDimData dimension; + + // This function might run multiple times for a single component + // due to the way Minecraft handles structure generation! + if (bounds.isVecInside(x, y, z) && bounds.isVecInside(x, y + 1, z)) + { + orientation = this.getMetadataWithOffset(Block.doorWood.blockID, 1); + dimension = PocketManager.getDimensionData(world); + link = dimension.getLink(x, y + 1, z); + if (link == null) + { + link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); + } + BaseItemDoor.placeDoorBlock(world, x, y, z, orientation, mod_pocketDim.transientDoor); + } + + for (x = 0; x <= 6; ++x) + { + for (z = 0; z <= 6; ++z) + { + this.fillCurrentPositionBlocksDownwards(world, Block.netherBrick.blockID, 0, x, -1, z, bounds); + } + } + + return true; + } + + @Override + protected void func_143012_a(NBTTagCompound tag) { } + + @Override + protected void func_143011_b(NBTTagCompound tag) { } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDNetherFortressGenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDNetherFortressGenerator.java new file mode 100644 index 00000000..4c2ca7b2 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDNetherFortressGenerator.java @@ -0,0 +1,24 @@ +package StevenDimDoors.mod_pocketDim.world.fortresses; + +import net.minecraft.world.gen.structure.MapGenNetherBridge; +import net.minecraft.world.gen.structure.MapGenStructureIO; +import net.minecraft.world.gen.structure.StructureStart; + +public class DDNetherFortressGenerator extends MapGenNetherBridge +{ + public DDNetherFortressGenerator() + { + super(); + + // Register our custom StructureStart class with MapGenStructureIO + // If we don't do this, Minecraft will crash when a fortress tries to generate. + // Moreover, use Fortress as our structure identifier so that if DD is removed, + // fortresses will generate properly using Vanilla code. + MapGenStructureIO.func_143034_b(DDStructureNetherBridgeStart.class, "Fortress"); + } + + protected StructureStart getStructureStart(int chunkX, int chunkZ) + { + return new DDStructureNetherBridgeStart(this.worldObj, this.rand, chunkX, chunkZ); + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDStructureNetherBridgeStart.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDStructureNetherBridgeStart.java new file mode 100644 index 00000000..abf23db7 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDStructureNetherBridgeStart.java @@ -0,0 +1,145 @@ +package StevenDimDoors.mod_pocketDim.world.fortresses; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Random; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.ComponentNetherBridgeCrossing; +import net.minecraft.world.gen.structure.ComponentNetherBridgeThrone; +import net.minecraft.world.gen.structure.StructureBoundingBox; +import net.minecraft.world.gen.structure.StructureComponent; +import net.minecraft.world.gen.structure.StructureNetherBridgeStart; + +public class DDStructureNetherBridgeStart extends StructureNetherBridgeStart +{ + private static int GATEWAY_GENERATION_CHANCE = 1; + private static int MAX_GATEWAY_GENERATION_CHANCE = 3; + + private boolean hasGateway; + private int minX; + private int minY; + private int minZ; + + public DDStructureNetherBridgeStart() { } + + public DDStructureNetherBridgeStart(World world, Random random, int chunkX, int chunkZ) + { + // StructureNetherBridgeStart handles designing the fortress for us + super(world, random, chunkX, chunkZ); + + Iterator componentIterator; + StructureComponent component; + StructureBoundingBox bounds; + ArrayList spawnerRooms; + hasGateway = false; + + // Randomly decide whether to build a gateway in this fortress + if (random.nextInt(MAX_GATEWAY_GENERATION_CHANCE) < GATEWAY_GENERATION_CHANCE) + { + // Search for all the blaze spawners in a fortress + spawnerRooms = new ArrayList(); + componentIterator = this.components.iterator(); + while (componentIterator.hasNext()) + { + component = (StructureComponent) componentIterator.next(); + if (component instanceof ComponentNetherBridgeThrone) + { + spawnerRooms.add((ComponentNetherBridgeThrone) component); + } + } + + // If any spawner rooms were found, choose one to randomly replace + if (!spawnerRooms.isEmpty()) + { + hasGateway = true; + component = spawnerRooms.get(random.nextInt(spawnerRooms.size())); + // Store enough data to identify the room when it's going to be built later + bounds = component.getBoundingBox(); + minX = bounds.minX; + minY = bounds.minY; + minZ = bounds.minZ; + } + } + } + + @Override + public NBTTagCompound func_143021_a(int chunkX, int chunkZ) + { + // We override the function for writing NBT data to add our own gateway data + NBTTagCompound fortressTag = super.func_143021_a(chunkX, chunkZ); + + // Add a compound tag with our data + NBTTagCompound dimensionalTag = new NBTTagCompound(); + dimensionalTag.setBoolean("HasGateway", this.hasGateway); + if (hasGateway) + { + dimensionalTag.setInteger("GatewayMinX", this.minX); + dimensionalTag.setInteger("GatewayMinY", this.minY); + dimensionalTag.setInteger("GatewayMinZ", this.minZ); + } + fortressTag.setCompoundTag("DimensionalDoors", dimensionalTag); + + return fortressTag; + } + + @Override + public void func_143020_a(World world, NBTTagCompound fortressTag) + { + // We override the function for reading NBT data to load gateway data + super.func_143020_a(world, fortressTag); + + NBTTagCompound dimensionalTag = fortressTag.getCompoundTag("DimensionalDoors"); + if (dimensionalTag != null) + { + this.hasGateway = dimensionalTag.getBoolean("HasGateway"); + if (hasGateway) + { + minX = dimensionalTag.getInteger("GatewayMinX"); + minY = dimensionalTag.getInteger("GatewayMinY"); + minZ = dimensionalTag.getInteger("GatewayMinZ"); + } + } + } + + /** + * Keeps iterating Structure Pieces and spawning them until the checks tell it to stop + */ + public void generateStructure(World world, Random random, StructureBoundingBox generationBounds) + { + if (hasGateway) + { + // Use a modified version of Vanilla's fortress generation code + // Try to detect the room that we intend to replace with our gateway + Iterator iterator = this.components.iterator(); + + while (iterator.hasNext()) + { + StructureComponent component = (StructureComponent)iterator.next(); + StructureBoundingBox bounds = component.getBoundingBox(); + + if (bounds.intersectsWith(generationBounds)) + { + // Check if this is our replacement target + // Checking the location is enough because structures aren't allowed to have + // intersecting bounding boxes - nothing else can have these min coordinates. + if (bounds.minX == this.minX && bounds.minY == this.minY && bounds.minZ == this.minZ) + { + component = ComponentNetherGateway.createFromComponent(component, random); + } + // Now for the last bit of Vanilla's generation code + if (!component.addComponentParts(world, random, generationBounds)) + { + iterator.remove(); + } + } + } + } + else + { + // Just run the usual structure generation + super.generateStructure(world, random, generationBounds); + } + } +}