diff --git a/gradle.properties b/gradle.properties index 96153bb..e077b8c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -85,6 +85,11 @@ accessTransformersFile = malisisdoors_at.cfg # Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! usesMixins = false +# Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main. +# This can speed up compile times thanks to not running the mixin annotation processor on all input sources. +# Mixin classes will have access to "main" classes, but not the other way around. +separateMixinSourceSet = + # Adds some debug arguments like verbose output and class export. usesMixinDebug = false @@ -117,9 +122,15 @@ minimizeShadowedDependencies = true # If disabled, won't rename the shadowed classes. relocateShadowedDependencies = true -# Adds the GTNH maven, CurseMaven, IC2/Player maven, and some more well-known 1.7.10 repositories. +# Adds CurseMaven, Modrinth, and some more well-known 1.7.10 repositories. includeWellKnownRepositories = true +# A list of repositories to exclude from the includeWellKnownRepositories setting. Should be a space separated +# list of strings, with the acceptable keys being(case does not matter): +# cursemaven +# modrinth +excludeWellKnownRepositories = + # Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven. # Authenticate with the MAVEN_USER and MAVEN_PASSWORD environment variables. # If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle. diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a80b22c..09523c0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle b/settings.gradle index c52d518..242692e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,7 +17,7 @@ pluginManagement { } plugins { - id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.19' + id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.26' } diff --git a/src/main/java/net/malisis/core/block/MalisisBlock.java b/src/main/java/net/malisis/core/block/MalisisBlock.java index 760fcd5..ade35aa 100644 --- a/src/main/java/net/malisis/core/block/MalisisBlock.java +++ b/src/main/java/net/malisis/core/block/MalisisBlock.java @@ -70,7 +70,6 @@ public void registerBlockIcons(IIconRegister reg) { super.registerBlockIcons(reg); } - @Override public AxisAlignedBB[] getBoundingBox(IBlockAccess world, int x, int y, int z, BoundingBoxType type) { return new AxisAlignedBB[] { AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ) }; } @@ -85,9 +84,16 @@ public void addCollisionBoxesToList(World world, int x, int y, int z, AxisAligne @Override public MovingObjectPosition collisionRayTrace(World world, int x, int y, int z, Vec3 src, Vec3 dest) { + this.setBlockBoundsBasedOnState(world, x, y, z); return new RaytraceBlock(world, src, dest, x, y, z).trace(); } + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World worldIn, int x, int y, int z) { + this.setBlockBoundsBasedOnState(worldIn, x, y, z); + return super.getCollisionBoundingBoxFromPool(worldIn, x, y, z); + } + @Override public AxisAlignedBB getSelectedBoundingBoxFromPool(World world, int x, int y, int z) { AxisAlignedBB[] aabbs = getBoundingBox(world, x, y, z, BoundingBoxType.SELECTION); diff --git a/src/main/java/net/malisis/core/client/gui/GuiRenderer.java b/src/main/java/net/malisis/core/client/gui/GuiRenderer.java index 0ec1b5b..1cf3a3d 100644 --- a/src/main/java/net/malisis/core/client/gui/GuiRenderer.java +++ b/src/main/java/net/malisis/core/client/gui/GuiRenderer.java @@ -29,6 +29,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderItem; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumChatFormatting; @@ -294,9 +295,9 @@ public void drawRectangle(float x, float y, float z, float width, float height, */ public void drawTooltip(UITooltip tooltip) { if (tooltip != null) { - t.startDrawingQuads(); + this.tessellator.startDrawingQuads(); tooltip.draw(this, mouseX, mouseY, partialTick); - t.draw(); + this.tessellator.draw(); } } @@ -445,7 +446,7 @@ public void drawItemStack(ItemStack itemStack, int x, int y, String label, EnumC if (label == null) label = ""; if (format != null) label = format + label; - t.draw(); + this.tessellator.draw(); RenderHelper.enableGUIStandardItemLighting(); GL11.glEnable(GL12.GL_RESCALE_NORMAL); @@ -471,7 +472,7 @@ public void drawItemStack(ItemStack itemStack, int x, int y, String label, EnumC currentTexture = null; bindDefaultTexture(); - t.startDrawingQuads(); + this.tessellator.startDrawingQuads(); } /** @@ -481,9 +482,9 @@ public void drawItemStack(ItemStack itemStack, int x, int y, String label, EnumC */ public void renderPickedItemStack(ItemStack itemStack) { if (itemStack == null) return; - + this.tessellator = Tessellator.instance; itemRenderer.zLevel = 100; - t.startDrawingQuads(); + this.tessellator.startDrawingQuads(); drawItemStack( itemStack, mouseX - 8, @@ -491,7 +492,7 @@ public void renderPickedItemStack(ItemStack itemStack) { null, itemStack.stackSize == 0 ? EnumChatFormatting.YELLOW : null, false); - t.draw(); + this.tessellator.draw(); itemRenderer.zLevel = 0; } diff --git a/src/main/java/net/malisis/core/renderer/MalisisRenderer.java b/src/main/java/net/malisis/core/renderer/MalisisRenderer.java index df6d82e..4f1e479 100644 --- a/src/main/java/net/malisis/core/renderer/MalisisRenderer.java +++ b/src/main/java/net/malisis/core/renderer/MalisisRenderer.java @@ -25,6 +25,7 @@ import net.malisis.core.renderer.font.FontRenderOptions; import net.malisis.core.renderer.font.MalisisFont; import net.malisis.core.renderer.icon.MalisisIcon; +import net.malisis.doors.door.tileentity.DoorTileEntity; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityClientPlayerMP; @@ -78,7 +79,7 @@ public class MalisisRenderer extends TileEntitySpecialRenderer /** Id of this {@link MalisisRenderer}. */ protected int renderId = -1; /** Tessellator reference. */ - protected Tessellator t = Tessellator.instance; + protected Tessellator tessellator = Tessellator.instance; /** Current world reference (ISBRH/TESR/IRWL). */ protected IBlockAccess world; /** RenderBlocks reference (ISBRH). */ @@ -131,7 +132,6 @@ public class MalisisRenderer extends TileEntitySpecialRenderer */ public MalisisRenderer() { this.renderId = RenderingRegistry.getNextAvailableRenderId(); - this.t = Tessellator.instance; } /** @@ -264,6 +264,7 @@ public void set(ItemRenderType type, ItemStack itemStack) { */ @Override public void renderInventoryBlock(Block block, int metadata, int modelId, RenderBlocks renderer) { + this.tessellator = Tessellator.instance; set(block, metadata); renderBlocks = renderer; prepare(RenderType.ISBRH_INVENTORY); @@ -286,6 +287,7 @@ public void renderInventoryBlock(Block block, int metadata, int modelId, RenderB @Override public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + this.tessellator = Tessellator.instance; set(world, block, x, y, z, world.getBlockMetadata(x, y, z)); tileEntity = world.getTileEntity(x, y, z); renderBlocks = renderer; @@ -347,6 +349,7 @@ public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRe */ @Override public void renderItem(ItemRenderType type, ItemStack item, Object... data) { + this.tessellator = Tessellator.instance; set(type, item); prepare(RenderType.ITEM_INVENTORY); render(); @@ -367,26 +370,30 @@ public void renderItem(ItemRenderType type, ItemStack item, Object... data) { */ @Override public void renderTileEntityAt(TileEntity te, double x, double y, double z, float partialTick) { - set(te, partialTick); - prepare(RenderType.TESR_WORLD, x, y, z); - render(); - if (getBlockDamage) { - destroyBlockProgress = getBlockDestroyProgress(); - if (destroyBlockProgress != null) { - next(); - - GL11.glEnable(GL11.GL_BLEND); - OpenGlHelper.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO); - GL11.glAlphaFunc(GL11.GL_GREATER, 0); - GL11.glColor4f(1.0F, 1.0F, 1.0F, 0.5F); - - t.disableColor(); - renderDestroyProgress(); - next(); - GL11.glDisable(GL11.GL_BLEND); + if (te instanceof DoorTileEntity && ((DoorTileEntity) te).shouldRender()) { + this.tessellator = Tessellator.instance; + set(te, partialTick); + prepare(RenderType.TESR_WORLD, x, y, z); + render(); + if (getBlockDamage) { + destroyBlockProgress = getBlockDestroyProgress(); + if (destroyBlockProgress != null) { + + next(); + + GL11.glEnable(GL11.GL_BLEND); + OpenGlHelper.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO); + GL11.glAlphaFunc(GL11.GL_GREATER, 0); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 0.5F); + + this.tessellator.disableColor(); + renderDestroyProgress(); + next(); + GL11.glDisable(GL11.GL_BLEND); + } } + clean(); } - clean(); } // #end TESR @@ -404,6 +411,7 @@ public boolean shouldRender(RenderWorldLastEvent event, IBlockAccess world) { @Override public void renderWorldLastEvent(RenderWorldLastEvent event, IBlockAccess world) { + this.tessellator = Tessellator.instance; set(world); partialTick = event.partialTicks; renderGlobal = event.context; @@ -486,7 +494,7 @@ public void startDrawing() { */ public void startDrawing(int drawMode) { if (isDrawing()) draw(); - t.startDrawing(drawMode); + this.tessellator.startDrawing(drawMode); this.drawMode = drawMode; } @@ -520,7 +528,7 @@ public void next(int drawMode) { * Triggers a draw. */ public void draw() { - if (isDrawing()) t.draw(); + if (isDrawing()) this.tessellator.draw(); } /** @@ -554,7 +562,7 @@ public void tessellatorShift() { if (isShifted) return; isShifted = true; - t.addTranslation(x, y, z); + this.tessellator.addTranslation(x, y, z); } /** @@ -564,7 +572,7 @@ public void tessellatorUnshift() { if (!isShifted) return; isShifted = false; - t.addTranslation(-x, -y, -z); + this.tessellator.addTranslation(-x, -y, -z); } /** @@ -656,6 +664,7 @@ public void render() { public void renderDestroyProgress() { if (destroyBlockProgress != null) overrideTexture = damagedIcons[destroyBlockProgress.getPartialBlockDamage()]; // enableBlending(); + this.tessellator = Tessellator.instance; render(); } @@ -731,7 +740,10 @@ protected void drawFace(Face f, RenderParameters faceParams) { // use normals if available if ((renderType == RenderType.ITEM_INVENTORY || renderType == RenderType.ISBRH_INVENTORY || params.useNormals.get()) && params.direction.get() != null) - t.setNormal(params.direction.get().offsetX, params.direction.get().offsetY, params.direction.get().offsetZ); + this.tessellator.setNormal( + params.direction.get().offsetX, + params.direction.get().offsetY, + params.direction.get().offsetZ); baseBrightness = getBaseBrightness(); @@ -772,12 +784,12 @@ protected void drawVertex(Vertex vertex, int number) { // alpha if (!params.usePerVertexAlpha.get()) vertex.setAlpha(params.alpha.get()); - t.setColorRGBA_I(vertex.getColor(), vertex.getAlpha()); - t.setBrightness(vertex.getBrightness()); + this.tessellator.setColorRGBA_I(vertex.getColor(), vertex.getAlpha()); + this.tessellator.setBrightness(vertex.getBrightness()); if (params.useTexture.get()) - t.addVertexWithUV(vertex.getX(), vertex.getY(), vertex.getZ(), vertex.getU(), vertex.getV()); - else t.addVertex(vertex.getX(), vertex.getY(), vertex.getZ()); + this.tessellator.addVertexWithUV(vertex.getX(), vertex.getY(), vertex.getZ(), vertex.getU(), vertex.getV()); + else this.tessellator.addVertex(vertex.getX(), vertex.getY(), vertex.getZ()); vertexDrawn = true; } diff --git a/src/main/java/net/malisis/core/util/ComplexAxisAlignedBoundingBox.java b/src/main/java/net/malisis/core/util/ComplexAxisAlignedBoundingBox.java new file mode 100644 index 0000000..a45b69d --- /dev/null +++ b/src/main/java/net/malisis/core/util/ComplexAxisAlignedBoundingBox.java @@ -0,0 +1,109 @@ +package net.malisis.core.util; + +import static net.minecraft.util.Vec3.createVectorHelper; + +import net.minecraft.util.Vec3; +import net.minecraftforge.common.util.ForgeDirection; + +import org.apache.commons.lang3.tuple.Pair; + +public class ComplexAxisAlignedBoundingBox { + + public enum Axis { + X, + Y, + Z + }; + + private static final int[] cos = { 1, 0, -1, 0 }; + private static final int[] sin = { 0, 1, 0, -1 }; + + public Vec3[][] flatSurfaces; + public Pair[] verticals; + + public static ComplexAxisAlignedBoundingBox defaultComplexBoundingBox = new ComplexAxisAlignedBoundingBox( + new Vec3[][] { + { createVectorHelper(0, 0, 0), createVectorHelper(0, 0, 1), createVectorHelper(1, 0, 1), + createVectorHelper(1, 0, 0) }, // bottom face + { createVectorHelper(0, 1, 0), createVectorHelper(0, 1, 1), createVectorHelper(1, 1, 1), + createVectorHelper(1, 1, 0) }, // top face + }, + new Pair[] { Pair.of(createVectorHelper(0, 0, 0), createVectorHelper(0, 1, 0)), + Pair.of(createVectorHelper(1, 0, 0), createVectorHelper(1, 1, 0)), + Pair.of(createVectorHelper(0, 0, 1), createVectorHelper(0, 1, 1)), + Pair.of(createVectorHelper(1, 0, 1), createVectorHelper(1, 1, 1)) }); + + public ComplexAxisAlignedBoundingBox(Vec3[][] flatSurfaces, Pair[] verticals) { + this.flatSurfaces = flatSurfaces; + this.verticals = verticals; + } + + public void addOffset(double x, double y, double z) { + for (Vec3[] face : flatSurfaces) { + for (Vec3 vec : face) { + vec.xCoord += x; + vec.yCoord += y; + vec.zCoord += z; + } + } + + for (Pair vertical : verticals) { + Vec3 start = vertical.getLeft(); + Vec3 end = vertical.getRight(); + + start.xCoord += x; + start.yCoord += y; + start.zCoord += z; + + end.xCoord += x; + end.yCoord += y; + end.zCoord += z; + } + } + + /** + * Rotates the ComplexAxisAlignedBoundingBox by the given angle around the specified axis. + */ + public void rotate(ForgeDirection dir, Axis axis) { + int angle = getAngle(dir); + // Rotate flat surfaces + for (int i = 0; i < flatSurfaces.length; i++) { + for (int j = 0; j < flatSurfaces[i].length; j++) { + flatSurfaces[i][j] = rotateVec(flatSurfaces[i][j], angle, axis); + } + } + + // Rotate verticals + for (int i = 0; i < verticals.length; i++) { + Vec3 start = verticals[i].getLeft(); + Vec3 end = verticals[i].getRight(); + verticals[i] = Pair.of(rotateVec(start, angle, axis), rotateVec(end, angle, axis)); + } + } + + private Vec3 rotateVec(Vec3 vec, int angle, Axis axis) { + int a = angle % 4; + if (a < 0) a += 4; + int s = sin[a]; + int c = cos[a]; + + double x = vec.xCoord; + double y = vec.yCoord; + double z = vec.zCoord; + + return switch (axis) { + case X -> createVectorHelper(x, y * c - z * s, y * s + z * c); + case Y -> createVectorHelper(x * c - z * s, y, x * s + z * c); + case Z -> createVectorHelper(x * c - y * s, x * s + y * c, z); + }; + } + + private static int getAngle(ForgeDirection dir) { + return switch (dir) { + case EAST -> 1; + case SOUTH -> 2; + case WEST -> 3; + default -> 0; + }; + } +} diff --git a/src/main/java/net/malisis/doors/MalisisDoors.java b/src/main/java/net/malisis/doors/MalisisDoors.java index 2441f3e..7484b9b 100644 --- a/src/main/java/net/malisis/doors/MalisisDoors.java +++ b/src/main/java/net/malisis/doors/MalisisDoors.java @@ -28,6 +28,7 @@ import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod.EventHandler; 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; @@ -86,6 +87,11 @@ public void preInit(FMLPreInitializationEvent event) { proxy.initRenderers(); } + @EventHandler + public void init(FMLInitializationEvent event) { + proxy.initEventHandlers(); + } + @EventHandler public void postInit(FMLPostInitializationEvent event) { proxy.initFonts(); @@ -130,6 +136,8 @@ public static class Blocks { public static Block ironTrapDoor; public static Block slidingTrapDoor; public static Block saloonDoor; + public static Block collisionHelperBlockMedieval; + public static Block collisionHelperBlockCarriage; } public static class Items { diff --git a/src/main/java/net/malisis/doors/Registers.java b/src/main/java/net/malisis/doors/Registers.java index b90987c..595df2b 100644 --- a/src/main/java/net/malisis/doors/Registers.java +++ b/src/main/java/net/malisis/doors/Registers.java @@ -27,6 +27,7 @@ import net.malisis.doors.block.VanishingDiamondBlock; import net.malisis.doors.door.DoorDescriptor; import net.malisis.doors.door.block.BigDoor; +import net.malisis.doors.door.block.CollisionHelperBlock; import net.malisis.doors.door.block.CustomDoor; import net.malisis.doors.door.block.FenceGate; import net.malisis.doors.door.block.FenceGate.Type; @@ -50,6 +51,7 @@ import net.malisis.doors.door.tileentity.DoorTileEntity; import net.malisis.doors.door.tileentity.FenceGateTileEntity; import net.malisis.doors.door.tileentity.ForcefieldTileEntity; +import net.malisis.doors.door.tileentity.MultiTile; import net.malisis.doors.door.tileentity.RustyHatchTileEntity; import net.malisis.doors.door.tileentity.SaloonDoorTileEntity; import net.malisis.doors.entity.BlockMixerTileEntity; @@ -114,6 +116,8 @@ public static void init() { registerForcefieldDoor(); + registerCollisionHelperBlocks(); + GameRegistry.registerTileEntity(DoorTileEntity.class, "doorTileEntity"); GameRegistry.registerTileEntity(TrapDoorTileEntity.class, "trapDoorTileEntity"); GameRegistry.registerTileEntity(FenceGateTileEntity.class, "fenceGateTileEntity"); @@ -463,4 +467,23 @@ private static void registerForcefieldDoor() { 'E', Items.comparator); } + + private static void registerCollisionHelperBlocks() { + collisionHelperBlockMedieval = new CollisionHelperBlock(BigDoor.Type.MEDIEVAL); + GameRegistry.registerBlock( + collisionHelperBlockMedieval, + collisionHelperBlockMedieval.getUnlocalizedName() + .substring(5) + "_" + + BigDoor.Type.MEDIEVAL); + + collisionHelperBlockCarriage = new CollisionHelperBlock(BigDoor.Type.CARRIAGE); + GameRegistry.registerBlock( + collisionHelperBlockCarriage, + collisionHelperBlockCarriage.getUnlocalizedName() + .substring(5) + "_" + + BigDoor.Type.CARRIAGE); + + GameRegistry.registerTileEntity(MultiTile.class, "collisionHelperTileEntity"); + + } } diff --git a/src/main/java/net/malisis/doors/door/block/BigDoor.java b/src/main/java/net/malisis/doors/door/block/BigDoor.java index cfd8a95..6e15404 100644 --- a/src/main/java/net/malisis/doors/door/block/BigDoor.java +++ b/src/main/java/net/malisis/doors/door/block/BigDoor.java @@ -13,30 +13,40 @@ package net.malisis.doors.door.block; -import java.util.ArrayList; +import static net.minecraft.util.MathHelper.abs; +import static net.minecraft.util.Vec3.createVectorHelper; import net.malisis.core.block.BoundingBoxType; import net.malisis.core.block.MalisisBlock; import net.malisis.core.util.AABBUtils; import net.malisis.core.util.BlockState; +import net.malisis.core.util.ComplexAxisAlignedBoundingBox; import net.malisis.core.util.EntityUtils; import net.malisis.core.util.TileEntityUtils; import net.malisis.doors.MalisisDoors; import net.malisis.doors.MalisisDoors.Items; import net.malisis.doors.door.tileentity.BigDoorTileEntity; +import net.malisis.doors.door.tileentity.IMultiBlock; +import net.minecraft.block.Block; import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.Vec3; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; +import org.apache.commons.lang3.tuple.Pair; + /** * @author Ordinastie * @@ -45,6 +55,7 @@ public class BigDoor extends MalisisBlock implements ITileEntityProvider { public enum Type { + DEFAULT("carriage_door", net.minecraft.init.Items.wooden_door), CARRIAGE("carriage_door", net.minecraft.init.Items.wooden_door), MEDIEVAL("medieval_door", Items.doorSpruceItem); @@ -57,6 +68,31 @@ private Type(String name, Item door) { } } + private final Vec3[][] selectionOpenHoriztonalFaces = new Vec3[][] { + { createVectorHelper(0, 5, 1), createVectorHelper(0, 5, 1 - Door.DOOR_WIDTH), + createVectorHelper(4, 5, 1 - Door.DOOR_WIDTH), createVectorHelper(4, 5, 1) }, // bottom face + { createVectorHelper(.5, 4, 1), createVectorHelper(.5, 4, 1 - Door.DOOR_WIDTH), + createVectorHelper(3.5, 4, 1 - Door.DOOR_WIDTH), createVectorHelper(3.5, 4, 1) }, // top face + { createVectorHelper(0, 4, 1 - Door.DOOR_WIDTH), createVectorHelper(0, 4, -.5), createVectorHelper(.5, 4, -.5), + createVectorHelper(.5, 4, 1 - Door.DOOR_WIDTH) }, + { createVectorHelper(3.5, 4, 1 - Door.DOOR_WIDTH), createVectorHelper(4, 4, 1 - Door.DOOR_WIDTH), + createVectorHelper(4, 4, -.5), createVectorHelper(3.5, 4, -.5) }, + { createVectorHelper(0, 0, 1), createVectorHelper(0, 0, -.5), createVectorHelper(.5, 0, -.5), + createVectorHelper(.5, 0, 1) }, + { createVectorHelper(3.5, 0, 1), createVectorHelper(4, 0, 1), createVectorHelper(4, 0, -.5), + createVectorHelper(3.5, 0, -.5) } }; + private final Pair[] selectionOpenVerticals = new Pair[] { + Pair.of(createVectorHelper(0, 0, 1), createVectorHelper(0, 5, 1)), + Pair.of(createVectorHelper(4, 0, 1), createVectorHelper(4, 5, 1)), + Pair.of(createVectorHelper(.5, 0, 1), createVectorHelper(.5, 4, 1)), + Pair.of(createVectorHelper(3.5, 0, 1), createVectorHelper(3.5, 4, 1)), + Pair.of(createVectorHelper(0, 0, -.5), createVectorHelper(0, 4, -.5)), + Pair.of(createVectorHelper(.5, 0, -.5), createVectorHelper(.5, 4, -.5)), + Pair.of(createVectorHelper(3.5, 0, -.5), createVectorHelper(3.5, 4, -.5)), + Pair.of(createVectorHelper(4, 0, -.5), createVectorHelper(4, 4, -.5)), + Pair.of(createVectorHelper(0, 4, 1 - Door.DOOR_WIDTH), createVectorHelper(0, 5, 1 - Door.DOOR_WIDTH)), + Pair.of(createVectorHelper(4, 4, 1 - Door.DOOR_WIDTH), createVectorHelper(4, 5, 1 - Door.DOOR_WIDTH)) }; + public static int renderId; public static int renderPass = -1; private AxisAlignedBB defaultBoundingBox = AxisAlignedBB.getBoundingBox(0, 0, 1 - Door.DOOR_WIDTH, 4, 5, 1); @@ -93,24 +129,75 @@ public boolean canPlaceBlockOnSide(World world, int x, int y, int z, int side) { } @Override - public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase player, ItemStack itemStack) { - ForgeDirection dir = EntityUtils.getEntityFacing(player); + public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase livingEntity, ItemStack itemStack) { + ForgeDirection dir = EntityUtils.getEntityFacing(livingEntity); int metadata = Door.dirToInt(dir); world.setBlockMetadataWithNotify(x, y, z, metadata, 2); BigDoorTileEntity te = TileEntityUtils.getTileEntity(BigDoorTileEntity.class, world, x, y, z); - if (te != null) te.setFrameState(BlockState.fromNBT(itemStack.getTagCompound())); + if (te != null) { + te.setFrameState(BlockState.fromNBT(itemStack.getTagCompound())); + if (checkAreaClearForDoor(world, x, y, z, metadata)) { + te.onCreate(x, y, z, metadata); + } else { + world.setBlockToAir(x, y, z); + if (!world.isRemote && livingEntity instanceof EntityPlayerMP player) { + player.addChatMessage(new ChatComponentText("There's no room for the door!")); + if (!player.capabilities.isCreativeMode) { + final ItemStack doorBlock = new ItemStack(this, 1, 0); + final EntityItem entityitem = player.dropPlayerItemWithRandomChoice(doorBlock, false); + entityitem.delayBeforeCanPickup = 0; + entityitem.func_145797_a(player.getCommandSenderName()); + } + } + } + } + } + + private boolean checkAreaClearForDoor(World world, int x, int y, int z, int meta) { + boolean validSpot = true; + boolean widthDirectionFlag = meta % 2 == 0; + int xStep = meta == 3 ? -1 : 1; + int zStep = meta == 0 ? -1 : 1; + int xMax = widthDirectionFlag ? 1 : 4; + int zMax = widthDirectionFlag ? 4 : 1; + + for (int yLoc = 0; yLoc < 5; yLoc++) { + for (int xLoc = 0; abs(xLoc) < xMax; xLoc += xStep) { + for (int zLoc = 0; abs(zLoc) < zMax; zLoc += zStep) { + if (!(yLoc == 0 && zLoc == 0 && xLoc == 0)) { + final Block potentialSpot = world.getBlock(x + xLoc, y + yLoc, z + zLoc); + if (!potentialSpot.getMaterial() + .isReplaceable()) { + validSpot = false; + } + } + } + } + } + return validSpot; + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int meta) { + final int buildHeight = world.getHeight() - 6; // No reason to have the door right at world height + if (y > buildHeight) { + return; + } + TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity instanceof IMultiBlock) { + ((IMultiBlock) tileEntity).onDestroy(tileEntity, meta); + } + super.breakBlock(world, x, y, z, block, meta); } @Override public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, float hitY, float hitZ) { if (world.isRemote) return true; - BigDoorTileEntity te = TileEntityUtils.getTileEntity(BigDoorTileEntity.class, world, x, y, z); if (te == null) return true; - - te.openOrCloseDoor(); + te.onBlockActivated(world, x, y, z, player); return true; } @@ -125,7 +212,8 @@ public AxisAlignedBB[] getBoundingBox(IBlockAccess world, int x, int y, int z, B if (type == BoundingBoxType.RENDER) { aabbs[0].minZ = -.5F; } else if ((type == BoundingBoxType.COLLISION || type == BoundingBoxType.CHUNKCOLLISION - || type == BoundingBoxType.RAYTRACE) && (te.isOpened() || te.isMoving())) { + || type == BoundingBoxType.RAYTRACE + || type == BoundingBoxType.SELECTION) && (te.isOpened() || te.isMoving())) { aabbs = new AxisAlignedBB[] { AxisAlignedBB.getBoundingBox(0, 0, -0.5F, 0.5F, 4, 1), AxisAlignedBB.getBoundingBox(3.5F, 0, -0.5F, 4, 4, 1), AxisAlignedBB.getBoundingBox(0, 4, 1 - Door.DOOR_WIDTH, 4, 5, 1) }; @@ -134,24 +222,49 @@ public AxisAlignedBB[] getBoundingBox(IBlockAccess world, int x, int y, int z, B return AABBUtils.rotate(aabbs, Door.intToDir(te.getDirection())); } - @Override - public TileEntity createNewTileEntity(World world, int metadata) { - return new BigDoorTileEntity(); - } + public ComplexAxisAlignedBoundingBox getComplexBoundingBoxWithOffset(IBlockAccess world, int x, int y, int z, + BoundingBoxType type) { + BigDoorTileEntity te = TileEntityUtils.getTileEntity(BigDoorTileEntity.class, world, x, y, z); + if (te == null) return ComplexAxisAlignedBoundingBox.defaultComplexBoundingBox; - @SuppressWarnings("deprecation") - @Override - public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { - if (!player.capabilities.isCreativeMode) { - BigDoorTileEntity te = TileEntityUtils.getTileEntity(BigDoorTileEntity.class, world, x, y, z); - if (te != null) dropBlockAsItem(world, x, y, z, te.getDroppedItemStack()); + if (type == BoundingBoxType.SELECTION && (te.isOpened() || te.isMoving())) { + Vec3[][] clonedFlatSurfaces = new Vec3[selectionOpenHoriztonalFaces.length][]; + for (int i = 0; i < selectionOpenHoriztonalFaces.length; i++) { + clonedFlatSurfaces[i] = new Vec3[selectionOpenHoriztonalFaces[i].length]; + for (int j = 0; j < selectionOpenHoriztonalFaces[i].length; j++) { + Vec3 vec = selectionOpenHoriztonalFaces[i][j]; + clonedFlatSurfaces[i][j] = createVectorHelper(vec.xCoord, vec.yCoord, vec.zCoord); + } + } + + Pair[] clonedVerticals = new Pair[selectionOpenVerticals.length]; + for (int i = 0; i < selectionOpenVerticals.length; i++) { + Vec3 left = selectionOpenVerticals[i].getLeft(); + Vec3 right = selectionOpenVerticals[i].getRight(); + clonedVerticals[i] = Pair.of( + createVectorHelper(left.xCoord, left.yCoord, left.zCoord), + createVectorHelper(right.xCoord, right.yCoord, right.zCoord)); + } + + ComplexAxisAlignedBoundingBox CAABB = new ComplexAxisAlignedBoundingBox( + clonedFlatSurfaces, + clonedVerticals); + CAABB.rotate(Door.intToDir(te.getDirection()), ComplexAxisAlignedBoundingBox.Axis.Y); + // Offset needed post-rotation + switch (Door.intToDir(te.getDirection())) { + case EAST -> CAABB.addOffset(x + 1, y, z); + case NORTH -> CAABB.addOffset(x, y, z); + case SOUTH -> CAABB.addOffset(x + 1, y, z + 1); + case WEST -> CAABB.addOffset(x, y, z + 1); + } + return CAABB; } - return super.removedByPlayer(world, player, x, y, z); + return ComplexAxisAlignedBoundingBox.defaultComplexBoundingBox; } @Override - public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { - return new ArrayList(); + public TileEntity createNewTileEntity(World world, int metadata) { + return new BigDoorTileEntity(this.type); } @Override @@ -169,6 +282,21 @@ public int getRenderType() { return renderId; } + public BigDoor.Type getType() { + return type; + } + + @Override + public void setBlockBoundsBasedOnState(IBlockAccess world, int x, int y, int z) { + this.setBlockBounds( + (float) defaultBoundingBox.minX, + (float) defaultBoundingBox.minY, + (float) defaultBoundingBox.minZ, + (float) defaultBoundingBox.maxX, + (float) defaultBoundingBox.maxY, + (float) defaultBoundingBox.maxZ); + } + @Override public int getRenderBlockPass() { return 1; diff --git a/src/main/java/net/malisis/doors/door/block/CollisionHelperBlock.java b/src/main/java/net/malisis/doors/door/block/CollisionHelperBlock.java new file mode 100644 index 0000000..9e22cf8 --- /dev/null +++ b/src/main/java/net/malisis/doors/door/block/CollisionHelperBlock.java @@ -0,0 +1,284 @@ +package net.malisis.doors.door.block; + +import java.util.List; +import java.util.Random; + +import net.malisis.core.block.BoundingBoxType; +import net.malisis.core.util.ComplexAxisAlignedBoundingBox; +import net.malisis.doors.MalisisDoors; +import net.malisis.doors.door.tileentity.BigDoorTileEntity; +import net.malisis.doors.door.tileentity.MultiTile; +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.ITileEntityProvider; +import net.minecraft.block.material.Material; +import net.minecraft.client.particle.EffectRenderer; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.IIcon; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.Explosion; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public class CollisionHelperBlock extends BlockContainer implements ITileEntityProvider { + + public BigDoor.Type type; + + private IIcon[] fakeIcons; + + // This class serves at the invisible collision blocks to help BigDoor with collisions + public CollisionHelperBlock(BigDoor.Type type) { + super(Material.wood); + this.setHardness(1.0F); + this.setStepSound(Block.soundTypeWood); + this.setBlockTextureName(type.name + "_collisionHelper"); + this.type = type; + this.setBlockName(type.name + "_collisionHelper"); + } + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister register) { + this.fakeIcons = new IIcon[2]; + this.fakeIcons[0] = register.registerIcon(MalisisDoors.modid + ":" + BigDoor.Type.CARRIAGE); + this.fakeIcons[1] = register.registerIcon(MalisisDoors.modid + ":" + BigDoor.Type.MEDIEVAL); + + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(int side, int meta) { + return switch (meta) { + case 0 -> this.fakeIcons[0]; + case 1 -> this.fakeIcons[1]; + default -> this.fakeIcons[0]; + }; + } + + @Override + public boolean canDropFromExplosion(Explosion par1Explosion) { + return false; + } + + @Override + public boolean canPlaceBlockOnSide(World world, int x, int y, int z, int side) { + if (side != 1) return false; + + ForgeDirection dir = ForgeDirection.getOrientation(side) + .getOpposite(); + return world.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ) + .isSideSolid(world, x, y, z, dir); + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer EntityPlayer, int par6, float subx, + float suby, float subz) { + final MultiTile tileEntity = ((MultiTile) world.getTileEntity(x, y, z)); + return tileEntity.onBlockActivated(world, x, y, z, EntityPlayer); + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int meta) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity instanceof MultiTile) { + ((MultiTile) tileEntity).onBlockRemoval(); + } + super.breakBlock(world, x, y, z, block, meta); + } + + @Override + public void setBlockBoundsBasedOnState(IBlockAccess world, int x, int y, int z) { + final int meta = world.getBlockMetadata(x, y, z); + + switch (meta) { + case 0: // 3 Pixels wide on the east side of the block + this.setBlockBounds(1.0F - Door.DOOR_WIDTH, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + break; + case 1: // 3 Pixels wide on the south side of the block + this.setBlockBounds(0.0F, 0.0F, 1.0F - Door.DOOR_WIDTH, 1.0F, 1.0F, 1.0F); + break; + case 2: // 3 Pixels wide on the west side of the block + this.setBlockBounds(0.0F, 0.0F, 0.0F, Door.DOOR_WIDTH, 1.0F, 1.0F); + break; + case 3: // 3 Pixels wide on the north side of the block + this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, Door.DOOR_WIDTH); + break; + case 4: // 8 Pixels wide on the east side of the block + this.setBlockBounds(0.5F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + break; + case 5: // 8 Pixels wide on the south side of the block + this.setBlockBounds(0.0F, 0.0F, 0.5F, 1.0F, 1.0F, 1.0F); + break; + case 6: // 8 Pixels wide on the west side of the block + this.setBlockBounds(0.0F, 0.0F, 0.0F, 0.5F, 1.0F, 1.0F); + break; + case 7: // 8 Pixels wide on the north side of the block + this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.5F); + break; + case 8: // Quarter of a block on north-west corner of the block + this.setBlockBounds(0.0F, 0.0F, 0.0F, 0.5F, 1.0F, 0.5F); + break; + case 9: // Quarter of a block on north-east corner of the block + this.setBlockBounds(0.5F, 0.0F, 0.0F, 1.0F, 1.0F, 0.5F); + break; + case 10: // Quarter of a block on south-east corner of the block + this.setBlockBounds(0.5F, 0.0F, 0.5F, 1.0F, 1.0F, 1.0F); + break; + case 11: // Quarter of a block on the south-west corner of the block + this.setBlockBounds(0.0F, 0.0F, 0.5F, 0.5F, 1.0F, 1.0F); + break; + } + } + + @Override + public void addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB axisalignedbb, + List list, Entity entity) { + setBlockBoundsBasedOnState(world, x, y, z); + super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, list, entity); + } + + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) { + this.setBlockBoundsBasedOnState(world, x, y, z); + return super.getCollisionBoundingBoxFromPool(world, x, y, z); + } + + @Override + public AxisAlignedBB getSelectedBoundingBoxFromPool(World world, int x, int y, int z) { + this.setBlockBoundsBasedOnState(world, x, y, z); + MultiTile thisTE = ((MultiTile) world.getTileEntity(x, y, z)); + Block mainBlock = world.getBlock(thisTE.mainBlockX, thisTE.mainBlockY, thisTE.mainBlockZ); + if (mainBlock instanceof BigDoor) { + return mainBlock + .getSelectedBoundingBoxFromPool(world, thisTE.mainBlockX, thisTE.mainBlockY, thisTE.mainBlockZ); + } + return super.getSelectedBoundingBoxFromPool(world, x, y, z); + } + + public ComplexAxisAlignedBoundingBox getComplexBoundingBox(World world, int x, int y, int z) { + this.setBlockBoundsBasedOnState(world, x, y, z); + MultiTile TE = getTileEntity(world, x, y, z); + BigDoor mainBlock = getMainBlock(world, x, y, z); + return mainBlock.getComplexBoundingBoxWithOffset( + world, + TE.mainBlockX, + TE.mainBlockY, + TE.mainBlockZ, + BoundingBoxType.SELECTION); + } + + public BigDoor getMainBlock(World world, int x, int y, int z) { + MultiTile cTE = this.getTileEntity(world, x, y, z); + return (BigDoor) world.getBlock(cTE.mainBlockX, cTE.mainBlockY, cTE.mainBlockZ); + } + + public BigDoorTileEntity getMainTileEntity(World world, int x, int y, int z) { + MultiTile cTE = this.getTileEntity(world, x, y, z); + return (BigDoorTileEntity) world.getTileEntity(cTE.mainBlockX, cTE.mainBlockY, cTE.mainBlockZ); + } + + public MultiTile getTileEntity(World world, int x, int y, int z) { + return (MultiTile) world.getTileEntity(x, y, z); + } + + @Override + public TileEntity createNewTileEntity(World worldIn, int meta) { + return new MultiTile(); + } + + @Override + public float getBlockHardness(World world, int x, int y, int z) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity instanceof MultiTile) { + final int mainX = ((MultiTile) tileEntity).mainBlockX; + final int mainY = ((MultiTile) tileEntity).mainBlockY; + final int mainZ = ((MultiTile) tileEntity).mainBlockZ; + return world.getBlock(mainX, mainY, mainZ) + .getBlockHardness(world, mainX, mainY, mainZ); + } + return this.blockHardness; + } + + @Override + public int quantityDropped(Random par1Random) { + return 0; + } + + @Override + public int getRenderType() { + return -1; + } + + @Override + public boolean renderAsNormalBlock() { + return false; + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public boolean shouldSideBeRendered(IBlockAccess worldIn, int x, int y, int z, int side) { + return false; + } + + public void makeCollisionHelperBlock(World world, int x, int y, int z, int meta, int xMain, int yMain, int zMain, + int metaMain) { + world.setBlock(x, y, z, this, meta, 3); + MultiTile tile = (MultiTile) world.getTileEntity(x, y, z); + tile.setMainBlock(xMain, yMain, zMain); + tile.setMainBlockMeta(metaMain); + } + + @SuppressWarnings("deprecation") + @Override + public ItemStack getPickBlock(MovingObjectPosition target, World world, int x, int y, int z) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity instanceof MultiTile multiTileEntity) { + if (multiTileEntity.mainBlockSet) { + final Block mainBlock = world + .getBlock(multiTileEntity.mainBlockX, multiTileEntity.mainBlockY, multiTileEntity.mainBlockZ); + if (Blocks.air != mainBlock) { + return mainBlock.getPickBlock( + target, + world, + multiTileEntity.mainBlockX, + multiTileEntity.mainBlockY, + multiTileEntity.mainBlockZ); + } + } + } + + return null; + } + + @SideOnly(Side.CLIENT) + @Override + public boolean addDestroyEffects(World world, int x, int y, int z, int meta, EffectRenderer effectRenderer) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity instanceof MultiTile multiTileEntity) { + if (multiTileEntity.mainBlockSet) { + final Block mainBlock = world + .getBlock(multiTileEntity.mainBlockX, multiTileEntity.mainBlockY, multiTileEntity.mainBlockZ); + if (Blocks.air != mainBlock) { + return world + .getBlock(multiTileEntity.mainBlockX, multiTileEntity.mainBlockY, multiTileEntity.mainBlockZ) + .addDestroyEffects(world, x, y, z, meta, effectRenderer); + } + } + } + return super.addDestroyEffects(world, x, y, z, meta, effectRenderer); + } +} diff --git a/src/main/java/net/malisis/doors/door/multiBlock/MultiBlueprint.java b/src/main/java/net/malisis/doors/door/multiBlock/MultiBlueprint.java new file mode 100644 index 0000000..3cbf3c1 --- /dev/null +++ b/src/main/java/net/malisis/doors/door/multiBlock/MultiBlueprint.java @@ -0,0 +1,139 @@ +package net.malisis.doors.door.multiBlock; + +import java.util.Map; + +import org.joml.Vector3i; + +public class MultiBlueprint { + + public enum RotationDegrees { + ROT90, + ROT180, + ROT270, + } + + public final static int MB = Integer.MAX_VALUE; // Main Block + public final static int EMPTY = -1; + public final static int RM = Integer.MIN_VALUE; + + public int[][][] bluePrint; + public Vector3i startingLocation; + public int yLength; + public int xLength; + public int zLength; + private Map metaMap; + + public MultiBlueprint(int[][][] print, Map metaMap, Vector3i startingLocation) { + this.yLength = print.length; + this.xLength = print[0].length; + this.zLength = print[0][0].length; + this.bluePrint = print; + this.metaMap = metaMap; + this.startingLocation = startingLocation; + } + + public void rotate(RotationDegrees angle) { + int[][][] rotatedPrint = new int[bluePrint.length][bluePrint.length][bluePrint.length]; + switch (angle) { + case ROT90 -> { + for (int i = 0; i < bluePrint.length; i++) { + rotatedPrint[i] = rotate90Clockwise(bluePrint[i]); + } + } + case ROT180 -> { + for (int i = 0; i < bluePrint.length; i++) { + rotatedPrint[i] = rotate180Clockwise(bluePrint[i]); + } + } + case ROT270 -> { + for (int i = 0; i < bluePrint.length; i++) { + rotatedPrint[i] = rotate270Clockwise(bluePrint[i]); + + } + } + } + convertMeta(rotatedPrint, angle); + this.bluePrint = rotatedPrint; + } + + private int[][] rotate90Clockwise(int[][] matrix) { + return transpose(reverseColumns(matrix)); + } + + private int[][] rotate180Clockwise(int[][] matrix) { + return reverseColumns(reverseRows(matrix)); + } + + private int[][] rotate270Clockwise(int[][] matrix) { + return transpose(reverseRows(matrix)); + } + + private void convertMeta(int[][][] mat, RotationDegrees angle) { + int conversionInfo = angle.ordinal(); + for (int i = 0; i < mat.length; i++) { + for (int j = 0; j < mat[i].length; j++) { + for (int k = 0; k < mat[i][j].length; k++) { + int[] newState = metaMap.get(mat[i][j][k]); + if (newState == null) { + if (mat[i][j][k] == MB) { + this.startingLocation = new Vector3i(j, i, k); + } + } else { + mat[i][j][k] = newState[conversionInfo]; + } + } + } + } + } + + private int[][] transpose(int[][] matrix) { + int rows = matrix.length; + int cols = matrix[0].length; + int[][] transposed = new int[cols][rows]; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + transposed[j][i] = matrix[i][j]; + } + } + return transposed; + } + + private int[][] reverseColumns(int[][] matrix) { + return multiplyMatrices(generateRowReversalMatrix(matrix.length), matrix); + } + + private int[][] reverseRows(int[][] matrix) { + return multiplyMatrices(matrix, generateRowReversalMatrix(matrix[0].length)); + } + + private int[][] generateRowReversalMatrix(int size) { + int[][] matrix = new int[size][size]; + for (int i = 0; i < size; i++) { + matrix[i][size - 1 - i] = 1; + } + return matrix; + } + + private int[][] multiplyMatrices(int[][] A, int[][] B) { + int rowsA = A.length; + int rowsB = B.length; + int colsA = A[0].length; + int colsB = B[0].length; + + if (colsA != rowsB) { + throw new IllegalArgumentException( + "Number of columns in Matrix A must be equal to number of rows in Matrix B."); + } + + int[][] result = new int[rowsA][colsB]; + for (int i = 0; i < rowsA; i++) { + for (int j = 0; j < colsB; j++) { + result[i][j] = 0; + for (int k = 0; k < colsA; k++) { + result[i][j] += A[i][k] * B[k][j]; + } + } + } + return result; + } +} diff --git a/src/main/java/net/malisis/doors/door/renderer/BigDoorRenderer.java b/src/main/java/net/malisis/doors/door/renderer/BigDoorRenderer.java index 370b98e..63a8090 100644 --- a/src/main/java/net/malisis/doors/door/renderer/BigDoorRenderer.java +++ b/src/main/java/net/malisis/doors/door/renderer/BigDoorRenderer.java @@ -94,7 +94,7 @@ private void renderTileEntity() { tileEntity.getTimer() .getStart()); - if (tileEntity.getMovement() != null) { + if (tileEntity.getMovement() != null && (tileEntity.isMoving() || tileEntity.isOpened())) { Animation[] anims = tileEntity.getMovement() .getAnimations(tileEntity, model, rp); ar.animate(anims); diff --git a/src/main/java/net/malisis/doors/door/tests/MultiBlueprintTest.java b/src/main/java/net/malisis/doors/door/tests/MultiBlueprintTest.java new file mode 100644 index 0000000..1175ef7 --- /dev/null +++ b/src/main/java/net/malisis/doors/door/tests/MultiBlueprintTest.java @@ -0,0 +1,23 @@ +// package net.malisis.doors.door.tests; +// +// +// import net.malisis.doors.door.multiBlock.MultiBlueprint; +// +// public class MultiBlueprintTest { +// +// private MultiBlueprint blueprint; +// +// @BeforeEach +// public void setUp() {// Set up before each test +// } +// +// @Test +// public void testAddition() { +// +// } +// +// @Test +// public void testSubtraction() { +// +// } +// } diff --git a/src/main/java/net/malisis/doors/door/tileentity/BigDoorTileEntity.java b/src/main/java/net/malisis/doors/door/tileentity/BigDoorTileEntity.java index 290c378..a45e129 100644 --- a/src/main/java/net/malisis/doors/door/tileentity/BigDoorTileEntity.java +++ b/src/main/java/net/malisis/doors/door/tileentity/BigDoorTileEntity.java @@ -13,54 +13,121 @@ package net.malisis.doors.door.tileentity; +import static net.malisis.doors.door.multiBlock.MultiBlueprint.MB; +import static net.malisis.doors.door.multiBlock.MultiBlueprint.RM; + +import java.util.HashMap; +import java.util.Map; + import net.malisis.core.MalisisCore; import net.malisis.core.block.BoundingBoxType; import net.malisis.core.util.BlockState; import net.malisis.core.util.MultiBlock; +import net.malisis.doors.MalisisDoors; import net.malisis.doors.door.DoorDescriptor; import net.malisis.doors.door.DoorRegistry; import net.malisis.doors.door.DoorState; import net.malisis.doors.door.block.BigDoor; +import net.malisis.doors.door.block.CollisionHelperBlock; import net.malisis.doors.door.block.Door; import net.malisis.doors.door.movement.CarriageDoorMovement; +import net.malisis.doors.door.multiBlock.MultiBlueprint; import net.malisis.doors.door.sound.CarriageDoorSound; +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; +import org.joml.Vector3i; + import com.google.common.base.Objects; /** * @author Ordinastie * */ -public class BigDoorTileEntity extends DoorTileEntity { +public class BigDoorTileEntity extends MultiTile implements IMultiBlock, IBluePrint { private boolean delete = false; private boolean processed = true; private ForgeDirection direction = ForgeDirection.NORTH; + private final Block defaultBorderBlock = Blocks.stonebrick; + private BlockState frameState = new BlockState(defaultBorderBlock); + private Boolean changingState = false; + private final int[][][] openPrint = { { { 10, -1, -1, 9 }, { MB, RM, RM, 7 }, }, + { { 10, -1, -1, 9 }, { 5, RM, RM, 7 }, }, { { 10, -1, -1, 9 }, { 5, RM, RM, 7 }, }, + { { 10, -1, -1, 9 }, { 5, RM, RM, 7 }, }, { { -1, -1, -1, -1 }, { 0, 0, 0, 0 }, } }; + + private final int[][][] closedPrint = { { { RM, -1, -1, RM }, { MB, 0, 0, 0 }, }, + { { RM, -1, -1, RM }, { 0, 0, 0, 0 }, }, { { RM, -1, -1, RM }, { 0, 0, 0, 0 }, }, + { { RM, -1, -1, RM }, { 0, 0, 0, 0 }, }, { { RM, -1, -1, RM }, { 0, 0, 0, 0 }, } }; + + // This map defines how to choose the next meta based on a rotation. + Map metaMap = new HashMap<>() { - private BlockState frameState; + { + put(0, new int[] { 1, 2, 3 }); + put(1, new int[] { 2, 3, 0 }); + put(2, new int[] { 3, 0, 1 }); + put(3, new int[] { 0, 1, 2 }); + put(4, new int[] { 5, 6, 7 }); + put(5, new int[] { 6, 7, 4 }); + put(6, new int[] { 7, 4, 5 }); + put(7, new int[] { 4, 5, 6 }); + put(8, new int[] { 9, 10, 11 }); + put(9, new int[] { 10, 11, 8 }); + put(10, new int[] { 11, 8, 9 }); + put(11, new int[] { 8, 9, 10 }); + } + }; + + private final MultiBlueprint closedBlueprint = new MultiBlueprint(closedPrint, metaMap, new Vector3i(1, 0, 0)); + private final MultiBlueprint openBlueprint = new MultiBlueprint(openPrint, metaMap, new Vector3i(1, 0, 0)); + private BigDoor.Type type; public BigDoorTileEntity() { + this.type = BigDoor.Type.DEFAULT; DoorDescriptor descriptor = new DoorDescriptor(); descriptor.setMovement(DoorRegistry.getMovement(CarriageDoorMovement.class)); descriptor.setSound(DoorRegistry.getSound(CarriageDoorSound.class)); descriptor.setDoubleDoor(false); descriptor.setOpeningTime(20); setDescriptor(descriptor); + } - frameState = new BlockState(Blocks.quartz_block); + public BigDoorTileEntity(BigDoor.Type type) { + this.type = type; + DoorDescriptor descriptor = new DoorDescriptor(); + descriptor.setMovement(DoorRegistry.getMovement(CarriageDoorMovement.class)); + descriptor.setSound(DoorRegistry.getSound(CarriageDoorSound.class)); + descriptor.setDoubleDoor(false); + descriptor.setOpeningTime(20); + setDescriptor(descriptor); } public BlockState getFrameState() { return frameState; } + @Override public void setFrameState(BlockState state) { if (state != null) frameState = state; + this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); + this.markDirty(); + } + + @Override + public void setFrameState(Block block) { + this.setFrameState(new BlockState(block)); } @Override @@ -80,12 +147,7 @@ public boolean isPowered() { @Override public void setDoorState(DoorState newState) { - boolean moving = this.moving; - BlockState state = null; - if (getWorldObj() != null) { - state = new BlockState(xCoord, yCoord, zCoord, getBlockType()); - } - + this.onStateChange(newState); super.setDoorState(newState); } @@ -122,14 +184,22 @@ public void readFromNBT(NBTTagCompound tag) { direction = mb.getDirection(); processed = false; } - - frameState = Objects.firstNonNull(BlockState.fromNBT(tag), new BlockState(Blocks.quartz_block)); + int typeInt = tag.getInteger("type"); + switch (typeInt) { + case 0, 1: + this.type = BigDoor.Type.CARRIAGE; + break; + case 2: + this.type = BigDoor.Type.MEDIEVAL; + break; + } + this.frameState = Objects.firstNonNull(BlockState.fromNBT(tag), new BlockState(defaultBorderBlock)); } @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); - + nbt.setInteger("type", this.type.ordinal()); BlockState.toNBT(nbt, frameState); } @@ -139,4 +209,316 @@ public AxisAlignedBB getRenderBoundingBox() { .getBoundingBox(getWorldObj(), xCoord, yCoord, zCoord, BoundingBoxType.RENDER)[0] .offset(xCoord, yCoord, zCoord); } + + @Override + public boolean onActivated(EntityPlayer entityPlayer) { + if (!this.worldObj.isRemote) { + if (hasRoomToOpenOrClose()) { + this.openOrCloseDoor(); + } else { + entityPlayer.addChatMessage(new ChatComponentText("There's no room for the door to open or close!")); + } + } + return true; + } + + private boolean hasRoomToOpenOrClose() { + int meta = this.getBlockMetadata() % 4; // We don't care if it's closed or open we just want to know what + // direction it's facing + return switch (this.state) { + case CLOSED -> doorsCanSwingOpen(meta); + case OPENED, OPENING -> doorsCanClose(meta); + case CLOSING -> true; + }; + } + + // Check if there's nothing inside of the doors. + private boolean doorsCanClose(int meta) { + switch (meta) { + case 0: + for (int yRel = 0; yRel < 4; yRel++) { + if (worldObj.getBlock(xCoord, yCoord + yRel, zCoord - 1) != Blocks.air) { + return false; + } + if (worldObj.getBlock(xCoord, yCoord + yRel, zCoord - 2) != Blocks.air) { + return false; + } + } + break; + case 1: + for (int yRel = 0; yRel < 4; yRel++) { + if (worldObj.getBlock(xCoord + 1, yCoord + yRel, zCoord) != Blocks.air) { + return false; + } + if (worldObj.getBlock(xCoord + 2, yCoord + yRel, zCoord) != Blocks.air) { + return false; + } + } + break; + case 2: + for (int yRel = 0; yRel < 4; yRel++) { + if (worldObj.getBlock(xCoord, yCoord + yRel, zCoord + 1) != Blocks.air) { + return false; + } + if (worldObj.getBlock(xCoord, yCoord + yRel, zCoord + 2) != Blocks.air) { + return false; + } + } + break; + case 3: + for (int yRel = 0; yRel < 4; yRel++) { + if (worldObj.getBlock(xCoord - 1, yCoord + yRel, zCoord) != Blocks.air) { + return false; + } + if (worldObj.getBlock(xCoord - 2, yCoord + yRel, zCoord) != Blocks.air) { + return false; + } + } + break; + } + return true; + } + + private boolean doorsCanSwingOpen(int meta) { + switch (meta) { + case 0: + for (int yRel = 0; yRel < 4; yRel++) { + if (worldObj.getBlock(xCoord - 1, yCoord + yRel, zCoord) != Blocks.air) { + return false; + } + if (worldObj.getBlock(xCoord - 1, yCoord + yRel, zCoord - 3) != Blocks.air) { + return false; + } + } + break; + case 1: + for (int yRel = 0; yRel < 4; yRel++) { + if (worldObj.getBlock(xCoord, yCoord + yRel, zCoord - 1) != Blocks.air) { + return false; + } + if (worldObj.getBlock(xCoord + 3, yCoord + yRel, zCoord - 1) != Blocks.air) { + return false; + } + } + break; + case 2: + for (int yRel = 0; yRel < 4; yRel++) { + if (worldObj.getBlock(xCoord + 1, yCoord + yRel, zCoord) != Blocks.air) { + return false; + } + if (worldObj.getBlock(xCoord + 1, yCoord + yRel, zCoord + 3) != Blocks.air) { + return false; + } + } + break; + case 3: + for (int yRel = 0; yRel < 4; yRel++) { + if (worldObj.getBlock(xCoord, yCoord + yRel, zCoord + 1) != Blocks.air) { + return false; + } + if (worldObj.getBlock(xCoord + 3, yCoord + yRel, zCoord + 1) != Blocks.air) { + return false; + } + } + break; + } + return true; + } + + @Override + public void onCreate(int x, int y, int z, int meta) { + this.markDirty(); + final int buildHeight = this.worldObj.getHeight() - 6; // No reason to have the door right at world height + + if (y > buildHeight) { + return; + } + this.setMainBlock(x, y, z); + this.mainBlockSet = true; + placeBluePrint(this.worldObj, x, y, z, meta, false); + + } + + // This blocks meta is not to be trusted for state. I eventually need to look into why this is but it breaks stuff + // to try to use the meta. Use this.state instead. + @Override + public void onDestroy(TileEntity callingBlock, int meta) { + if (!this.changingState) { + int metaToUse = meta; + if ((this.state == DoorState.OPENING || this.state == DoorState.CLOSING || this.state == DoorState.OPENED) + && metaToUse < 4) { + metaToUse += 4; + } else if (this.state == DoorState.CLOSED && metaToUse > 3) { + metaToUse -= 4; + } + this.changingState = true; + removeBluePrint(this.worldObj, xCoord, yCoord, zCoord, metaToUse, callingBlock); + this.changingState = false; + } + } + + // This method is a little complex because unless the door is fully closed I want players to be able to go through + // the door. + public void onStateChange(DoorState newState) { + if (this.state == newState) return; + if (getWorldObj() == null) return; // On startup the worldObj is null for some reason + int meta = this.getBlockMetadata(); + if (newState == DoorState.OPENING) { + this.changingState = true; + if (meta < 4) meta = (meta + 4) % 8; + placeBluePrint(this.worldObj, xCoord, yCoord, zCoord, meta, true); + this.changingState = false; + } else if (newState == DoorState.CLOSED) { + this.changingState = true; + if (meta > 3) meta -= 4; + placeBluePrint(this.worldObj, xCoord, yCoord, zCoord, meta, true); + this.changingState = false; + } + } + + @Override + public boolean shouldRender() { + return true; + } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbtTag = new NBTTagCompound(); + this.writeToNBT(nbtTag); + return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 1, nbtTag); + } + + @Override + public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { + super.onDataPacket(net, pkt); + NBTTagCompound packetData = pkt.func_148857_g(); + this.setFrameState(BlockState.fromNBT(packetData)); + } + + @Override + public void placeBluePrint(World world, int x, int y, int z, int meta, boolean removeBlockInWay) { + MultiBlueprint print = (meta < 4 ? this.closedBlueprint : this.openBlueprint); + switch (meta) { + case 0, 4: + this.bluePrintPlacerHelper(world, x, y, z, print, removeBlockInWay); + break; + case 1, 5: + print.rotate(MultiBlueprint.RotationDegrees.ROT90); + this.bluePrintPlacerHelper(world, x, y, z, print, removeBlockInWay); + print.rotate(MultiBlueprint.RotationDegrees.ROT270); + break; + case 2, 6: + print.rotate(MultiBlueprint.RotationDegrees.ROT180); + this.bluePrintPlacerHelper(world, x, y, z, print, removeBlockInWay); + print.rotate(MultiBlueprint.RotationDegrees.ROT180); + break; + case 3, 7: + print.rotate(MultiBlueprint.RotationDegrees.ROT270); + this.bluePrintPlacerHelper(world, x, y, z, print, removeBlockInWay); + print.rotate(MultiBlueprint.RotationDegrees.ROT90); + break; + } + } + + private void bluePrintPlacerHelper(World world, int x, int y, int z, MultiBlueprint print, + boolean removeBlockInWay) { + int mainBlockRelativeX = print.startingLocation.x; + int mainBlockRelativeY = print.startingLocation.y; + int mainBlockRelativeZ = print.startingLocation.z; + for (int j = 0; j < print.bluePrint.length; j++) // y + { + for (int i = 0; i < print.bluePrint[0].length; i++) // x + { + for (int k = 0; k < print.bluePrint[0][0].length; k++) // z + { + if (!(i == mainBlockRelativeX && j == mainBlockRelativeY && k == mainBlockRelativeZ) + && print.bluePrint[j][i][k] > -1) { + + switch (this.type) { + case CARRIAGE -> ((CollisionHelperBlock) MalisisDoors.Blocks.collisionHelperBlockCarriage) + .makeCollisionHelperBlock( + world, + x - mainBlockRelativeX + i, + y - mainBlockRelativeY + j, + z + mainBlockRelativeZ - k, + print.bluePrint[j][i][k], + this.xCoord, + this.yCoord, + this.zCoord, + this.getBlockMetadata()); + case MEDIEVAL -> ((CollisionHelperBlock) MalisisDoors.Blocks.collisionHelperBlockMedieval) + .makeCollisionHelperBlock( + world, + x - mainBlockRelativeX + i, + y - mainBlockRelativeY + j, + z + mainBlockRelativeZ - k, + print.bluePrint[j][i][k], + this.xCoord, + this.yCoord, + this.zCoord, + this.getBlockMetadata()); + } + } else if (print.bluePrint[j][i][k] == Integer.MIN_VALUE && removeBlockInWay) { + world.setBlockToAir( + x - mainBlockRelativeX + i, + y - mainBlockRelativeY + j, + z + mainBlockRelativeZ - k); + } + } + } + } + } + + @Override + public void removeBluePrint(World world, int x, int y, int z, int meta, TileEntity callingBlock) { + MultiBlueprint print = (meta < 4 ? this.closedBlueprint : this.openBlueprint); + switch (meta) { + case 0, 4: + this.bluePrintRemovalHelper(world, x, y, z, print, callingBlock); + break; + case 1, 5: + print.rotate(MultiBlueprint.RotationDegrees.ROT90); + this.bluePrintRemovalHelper(world, x, y, z, print, callingBlock); + print.rotate(MultiBlueprint.RotationDegrees.ROT270); + break; + case 2, 6: + print.rotate(MultiBlueprint.RotationDegrees.ROT180); + this.bluePrintRemovalHelper(world, x, y, z, print, callingBlock); + print.rotate(MultiBlueprint.RotationDegrees.ROT180); + break; + case 3, 7: + print.rotate(MultiBlueprint.RotationDegrees.ROT270); + this.bluePrintRemovalHelper(world, x, y, z, print, callingBlock); + print.rotate(MultiBlueprint.RotationDegrees.ROT90); + break; + } + } + + private void bluePrintRemovalHelper(World world, int x, int y, int z, MultiBlueprint print, + TileEntity callingBlock) { + + Block blockToDrop = this.type == BigDoor.Type.CARRIAGE ? MalisisDoors.Blocks.carriageDoor + : MalisisDoors.Blocks.medievalDoor; + int mainBlockRelativeX = print.startingLocation.x; + int mainBlockRelativeY = print.startingLocation.y; + int mainBlockRelativeZ = print.startingLocation.z; + for (int j = 0; j < print.bluePrint.length; j++) // y + { + for (int i = 0; i < print.bluePrint[0].length; i++) // x + { + for (int k = 0; k < print.bluePrint[0][0].length; k++) // z + { + if (print.bluePrint[j][i][k] == MB) { + ((MultiTile) callingBlock).dropMainBlockAtLocation(blockToDrop); + } + if (print.bluePrint[j][i][k] > -1) { + world.setBlockToAir( + x - mainBlockRelativeX + i, + y - mainBlockRelativeY + j, + z + mainBlockRelativeZ - k); + } + } + } + } + } } diff --git a/src/main/java/net/malisis/doors/door/tileentity/DoorTileEntity.java b/src/main/java/net/malisis/doors/door/tileentity/DoorTileEntity.java index 5e93714..e4fc58b 100644 --- a/src/main/java/net/malisis/doors/door/tileentity/DoorTileEntity.java +++ b/src/main/java/net/malisis/doors/door/tileentity/DoorTileEntity.java @@ -111,6 +111,10 @@ public boolean isReversed() { return (getBlockMetadata() & Door.FLAG_REVERSED) != 0; } + public boolean shouldRender() { + return true; + } + public boolean isPowered() { return getWorldObj().isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord) || getWorldObj().isBlockIndirectlyGettingPowered(xCoord, yCoord + 1, zCoord); diff --git a/src/main/java/net/malisis/doors/door/tileentity/IBluePrint.java b/src/main/java/net/malisis/doors/door/tileentity/IBluePrint.java new file mode 100644 index 0000000..3858888 --- /dev/null +++ b/src/main/java/net/malisis/doors/door/tileentity/IBluePrint.java @@ -0,0 +1,11 @@ +package net.malisis.doors.door.tileentity; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public interface IBluePrint { + + public void placeBluePrint(World world, int x, int y, int z, int meta, boolean removeBlockInWay); + + public void removeBluePrint(World world, int x, int y, int z, int meta, TileEntity callingBlock); +} diff --git a/src/main/java/net/malisis/doors/door/tileentity/IMultiBlock.java b/src/main/java/net/malisis/doors/door/tileentity/IMultiBlock.java new file mode 100644 index 0000000..375d078 --- /dev/null +++ b/src/main/java/net/malisis/doors/door/tileentity/IMultiBlock.java @@ -0,0 +1,30 @@ +package net.malisis.doors.door.tileentity; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; + +public interface IMultiBlock { + + /** + * Called when activated + */ + boolean onActivated(EntityPlayer entityPlayer); + + /** + * Called when this multiblock is created + * + * @param x - placed x coord + * @param y - placed y coord + * @param z - placed z coord' + * @param meta - meta of the placed door + */ + void onCreate(int x, int y, int z, int meta); + + /** + * Called when one of the multiblocks of this block is destroyed + * + * @param callingBlock - The tile entity who called the onDestroy function + */ + void onDestroy(TileEntity callingBlock, int meta); + +} diff --git a/src/main/java/net/malisis/doors/door/tileentity/MultiTile.java b/src/main/java/net/malisis/doors/door/tileentity/MultiTile.java new file mode 100644 index 0000000..57f9dd0 --- /dev/null +++ b/src/main/java/net/malisis/doors/door/tileentity/MultiTile.java @@ -0,0 +1,121 @@ +package net.malisis.doors.door.tileentity; + +import net.malisis.core.util.BlockState; +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public class MultiTile extends DoorTileEntity { + + public int mainBlockX; + public int mainBlockY; + public int mainBlockZ; + public int mainBlockMeta; + public boolean mainBlockSet; + + public void setMainBlock(int x, int y, int z) { + this.mainBlockX = x; + this.mainBlockY = y; + this.mainBlockZ = z; + this.mainBlockSet = true; + this.markDirty(); + if (!this.worldObj.isRemote) { + this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); + } + } + + public void onBlockRemoval() { + TileEntity mainBlock = getMainBlockTile(); + if (mainBlock != null) { + if (mainBlock instanceof IMultiBlock) { + ((IMultiBlock) mainBlock).onDestroy(this, this.mainBlockMeta); + } + } + } + + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player) { + world.markBlockForUpdate(x, y, z); + TileEntity mainBlock = getMainBlockTile(); + if (mainBlock instanceof IMultiBlock) { + return ((IMultiBlock) mainBlock).onActivated(player); + } + return true; + } + + public TileEntity getMainBlockTile() { + + return this.worldObj.getTileEntity(this.mainBlockX, this.mainBlockY, this.mainBlockZ); + } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbtTag = new NBTTagCompound(); + this.writeToNBT(nbtTag); + return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 1, nbtTag); + } + + @Override + public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { + super.onDataPacket(net, pkt); + NBTTagCompound packetData = pkt.func_148857_g(); + this.mainBlockX = packetData.getInteger("mainBlockX"); + this.mainBlockY = packetData.getInteger("mainBlockY"); + this.mainBlockZ = packetData.getInteger("mainBlockZ"); + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + nbt.setInteger("mainBlockX", this.mainBlockX); + nbt.setInteger("mainBlockY", this.mainBlockY); + nbt.setInteger("mainBlockZ", this.mainBlockZ); + nbt.setInteger("mainBlockMeta", this.mainBlockMeta); + nbt.setBoolean("mainBlockSet", this.mainBlockSet); + + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + this.mainBlockX = nbt.getInteger("mainBlockX"); + this.mainBlockY = nbt.getInteger("mainBlockY"); + this.mainBlockZ = nbt.getInteger("mainBlockZ"); + this.mainBlockMeta = nbt.getInteger("mainBlockMeta"); + this.mainBlockSet = nbt.getBoolean("mainBlockSet"); + } + + @Override + public boolean shouldRender() { + return false; + } + + public void setFrameState(Block block) { + TileEntity mainTile = this.getMainBlockTile(); + if (mainTile instanceof BigDoorTileEntity bigDoorMainTile) { + bigDoorMainTile.setFrameState(block); + } + } + + public void setFrameState(BlockState blockState) { + TileEntity mainTile = this.getMainBlockTile(); + if (mainTile instanceof BigDoorTileEntity bigDoorTileEntity) { + bigDoorTileEntity.setFrameState(blockState); + } + } + + public void dropMainBlockAtLocation(Block block) { + if (mainBlockSet) { + int meta = this.getBlockMetadata(); + block.dropBlockAsItem(this.worldObj, xCoord, yCoord, zCoord, meta, 0); + } + } + + public void setMainBlockMeta(int meta) { + this.mainBlockMeta = meta; + } +} diff --git a/src/main/java/net/malisis/doors/event/DoorEventHandlerClient.java b/src/main/java/net/malisis/doors/event/DoorEventHandlerClient.java new file mode 100644 index 0000000..eb2a011 --- /dev/null +++ b/src/main/java/net/malisis/doors/event/DoorEventHandlerClient.java @@ -0,0 +1,51 @@ +package net.malisis.doors.event; + +import net.malisis.doors.door.DoorState; +import net.malisis.doors.door.block.CollisionHelperBlock; +import net.malisis.doors.door.tileentity.DoorTileEntity; +import net.malisis.doors.door.tileentity.MultiTile; +import net.malisis.doors.renderer.CustomDoorBoundingBoxRenderer; +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.World; +import net.minecraftforge.client.event.DrawBlockHighlightEvent; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; + +public class DoorEventHandlerClient extends DoorEventHandlerCommon { + + public CustomDoorBoundingBoxRenderer cdbbRenderer = new CustomDoorBoundingBoxRenderer(); + + @SubscribeEvent + public void onDrawBlockHighlight(DrawBlockHighlightEvent event) { + World world = event.player.worldObj; + if (world.isRemote) { + MovingObjectPosition target = event.target; + + if (target.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { + int x = target.blockX; + int y = target.blockY; + int z = target.blockZ; + Block block = world.getBlock(x, y, z); + + if (block instanceof CollisionHelperBlock) { + MultiTile cTE = ((MultiTile) world.getTileEntity(x, y, z)); + TileEntity mainDoorTE = cTE.getMainBlockTile(); + if (mainDoorTE instanceof DoorTileEntity) { + DoorState state = ((DoorTileEntity) mainDoorTE).getState(); + if (state == DoorState.OPENED || state == DoorState.OPENING || state == DoorState.CLOSING) { + event.setCanceled(true); + cdbbRenderer.renderOpenDoorBoundingBox( + world, + (CollisionHelperBlock) block, + event.player, + event.partialTicks, + target); + } + } + } + } + } + } +} diff --git a/src/main/java/net/malisis/doors/event/DoorEventHandlerCommon.java b/src/main/java/net/malisis/doors/event/DoorEventHandlerCommon.java new file mode 100644 index 0000000..1da6263 --- /dev/null +++ b/src/main/java/net/malisis/doors/event/DoorEventHandlerCommon.java @@ -0,0 +1,54 @@ +package net.malisis.doors.event; + +import net.malisis.doors.door.tileentity.MultiTile; +import net.malisis.doors.network.FrameUpdateMessage; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; + +import org.lwjgl.input.Keyboard; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; + +public class DoorEventHandlerCommon { + + @SubscribeEvent + public void PlayerInteractEvent(PlayerInteractEvent event) { + TileEntity tileEntity = getTileEntityLookingAt(event.entityPlayer); + if (event.entityPlayer.isSneaking() && event.action.equals(PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) + && tileEntity instanceof MultiTile multiTile + && Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) { + ItemStack heldStack = event.entityPlayer.getHeldItem(); + if (heldStack != null) { + Block block = Block.getBlockFromItem(heldStack.getItem()); + int damageValue = heldStack.getItemDamage(); + if (block != null) { + event.setCanceled(true); + FrameUpdateMessage.SendFrameUpdateMessage(multiTile, block, damageValue); + } + } + } + } + + private TileEntity getTileEntityLookingAt(EntityPlayer player) { + Minecraft mc = Minecraft.getMinecraft(); + double maxReach = mc.playerController.getBlockReachDistance(); + Vec3 eyePosition = player.getPosition(1.0F); + Vec3 lookVector = player.getLook(1.0F); + Vec3 endPosition = eyePosition + .addVector(lookVector.xCoord * maxReach, lookVector.yCoord * maxReach, lookVector.zCoord * maxReach); + MovingObjectPosition rayTraceResult = mc.theWorld.rayTraceBlocks(eyePosition, endPosition); + if (rayTraceResult != null && rayTraceResult.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { + int blockX = rayTraceResult.blockX; + int blockY = rayTraceResult.blockY; + int blockZ = rayTraceResult.blockZ; + return mc.theWorld.getTileEntity(blockX, blockY, blockZ); + } + return null; + } +} diff --git a/src/main/java/net/malisis/doors/network/FrameUpdateMessage.java b/src/main/java/net/malisis/doors/network/FrameUpdateMessage.java new file mode 100644 index 0000000..7433506 --- /dev/null +++ b/src/main/java/net/malisis/doors/network/FrameUpdateMessage.java @@ -0,0 +1,86 @@ +package net.malisis.doors.network; + +import net.malisis.core.network.MalisisMessage; +import net.malisis.core.util.BlockState; +import net.malisis.doors.MalisisDoors; +import net.malisis.doors.door.tileentity.MultiTile; +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import cpw.mods.fml.relauncher.Side; +import io.netty.buffer.ByteBuf; + +@MalisisMessage +public class FrameUpdateMessage implements IMessageHandler { + + public FrameUpdateMessage() { + MalisisDoors.network.registerMessage(this, FrameUpdateMessage.Packet.class, Side.SERVER); + } + + @Override + public IMessage onMessage(FrameUpdateMessage.Packet message, MessageContext ctx) { + World world = ctx.getServerHandler().playerEntity.worldObj; + TileEntity tileEntity = world.getTileEntity(message.blockX, message.blockY, message.blockZ); + BlockState blockState = new BlockState( + message.blockX, + message.blockY, + message.blockZ, + message.block, + message.blockDamage); + if (tileEntity instanceof MultiTile bigDoorTE) { + bigDoorTE.setFrameState(blockState); + } + return null; + } + + public static void SendFrameUpdateMessage(TileEntity te, Block block, int damage) { + FrameUpdateMessage.Packet packet = new FrameUpdateMessage.Packet( + block, + te.xCoord, + te.yCoord, + te.zCoord, + damage); + MalisisDoors.network.sendToServer(packet); + } + + public static class Packet implements IMessage { + + private int blockX; + private int blockY; + private int blockZ; + private Block block; + private int blockDamage; + + public Packet() {} + + public Packet(Block block, int x, int y, int z, int damage) { + this.block = block; + this.blockX = x; + this.blockY = y; + this.blockZ = z; + this.blockDamage = damage; + } + + @Override + public void fromBytes(ByteBuf buf) { + this.blockX = buf.readInt(); + this.blockY = buf.readInt(); + this.blockZ = buf.readInt(); + this.block = Block.getBlockById(buf.readInt()); + this.blockDamage = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(this.blockX); + buf.writeInt(this.blockY); + buf.writeInt(this.blockZ); + buf.writeInt(Block.getIdFromBlock(this.block)); + buf.writeInt(this.blockDamage); + } + } +} diff --git a/src/main/java/net/malisis/doors/proxy/ClientProxy.java b/src/main/java/net/malisis/doors/proxy/ClientProxy.java index 035955d..8f7e522 100644 --- a/src/main/java/net/malisis/doors/proxy/ClientProxy.java +++ b/src/main/java/net/malisis/doors/proxy/ClientProxy.java @@ -28,6 +28,7 @@ import net.malisis.doors.door.tileentity.SaloonDoorTileEntity; import net.malisis.doors.entity.GarageDoorTileEntity; import net.malisis.doors.entity.VanishingTileEntity; +import net.malisis.doors.event.DoorEventHandlerClient; import net.malisis.doors.renderer.GarageDoorRenderer; import net.malisis.doors.renderer.MixedBlockRenderer; import net.malisis.doors.renderer.RustyLadderRenderer; @@ -37,6 +38,7 @@ import net.malisis.doors.trapdoor.tileentity.TrapDoorTileEntity; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.MinecraftForge; public class ClientProxy implements IProxy { @@ -100,4 +102,9 @@ public void initFonts() { ResourceLocation rl = new ResourceLocation(MalisisDoors.modid + ":fonts/digital-7 (mono).ttf"); MalisisDoors.digitalFont = new MalisisFont(rl); } + + @Override + public void initEventHandlers() { + MinecraftForge.EVENT_BUS.register(new DoorEventHandlerClient()); + } } diff --git a/src/main/java/net/malisis/doors/proxy/IProxy.java b/src/main/java/net/malisis/doors/proxy/IProxy.java index 61f6c74..93512f0 100644 --- a/src/main/java/net/malisis/doors/proxy/IProxy.java +++ b/src/main/java/net/malisis/doors/proxy/IProxy.java @@ -19,7 +19,9 @@ */ public interface IProxy { - public void initRenderers(); + void initRenderers(); - public void initFonts(); + void initFonts(); + + void initEventHandlers(); } diff --git a/src/main/java/net/malisis/doors/proxy/ServerProxy.java b/src/main/java/net/malisis/doors/proxy/ServerProxy.java index 6549236..b433e40 100644 --- a/src/main/java/net/malisis/doors/proxy/ServerProxy.java +++ b/src/main/java/net/malisis/doors/proxy/ServerProxy.java @@ -13,6 +13,9 @@ package net.malisis.doors.proxy; +import net.malisis.doors.event.DoorEventHandlerCommon; +import net.minecraftforge.common.MinecraftForge; + /** * @author Ordinastie * @@ -24,4 +27,9 @@ public void initRenderers() {} @Override public void initFonts() {} + + @Override + public void initEventHandlers() { + MinecraftForge.EVENT_BUS.register(new DoorEventHandlerCommon()); + } } diff --git a/src/main/java/net/malisis/doors/renderer/CustomDoorBoundingBoxRenderer.java b/src/main/java/net/malisis/doors/renderer/CustomDoorBoundingBoxRenderer.java new file mode 100644 index 0000000..b746acd --- /dev/null +++ b/src/main/java/net/malisis/doors/renderer/CustomDoorBoundingBoxRenderer.java @@ -0,0 +1,89 @@ +package net.malisis.doors.renderer; + +import net.malisis.core.util.ComplexAxisAlignedBoundingBox; +import net.malisis.doors.door.block.CollisionHelperBlock; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; + +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.opengl.GL11; + +public class CustomDoorBoundingBoxRenderer { + + public void renderOpenDoorBoundingBox(World world, CollisionHelperBlock block, EntityPlayer player, + float partialTicks, MovingObjectPosition target) { + GL11.glEnable(GL11.GL_BLEND); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + GL11.glColor4f(0.0F, 0.0F, 0.0F, 0.4F); + GL11.glLineWidth(2.0F); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glDepthMask(false); + float f1 = 0.002F; + + block.setBlockBoundsBasedOnState(world, target.blockX, target.blockY, target.blockZ); + double d0 = player.lastTickPosX + (player.posX - player.lastTickPosX) * (double) partialTicks; + double d1 = player.lastTickPosY + (player.posY - player.lastTickPosY) * (double) partialTicks; + double d2 = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * (double) partialTicks; + + ComplexAxisAlignedBoundingBox CAABB = block + .getComplexBoundingBox(world, target.blockX, target.blockY, target.blockZ); + + CAABB.addOffset(-d0, -d1, -d2); + + renderComplexAABB(CAABB, -1); + + GL11.glDepthMask(true); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + public static void renderComplexAABB(ComplexAxisAlignedBoundingBox CAABB, int color) { + Tessellator tessellator = Tessellator.instance; + if (color != -1) { + tessellator.setColorOpaque_I(color); + } + renderHorizontalFaces(CAABB.flatSurfaces, tessellator); + renderVerticals(CAABB.verticals, tessellator); + } + + private static void renderVerticals(Pair[] lines, Tessellator tessellator) { + tessellator.startDrawing(1); + for (Pair line : lines) { + tessellator.addVertex(line.getRight().xCoord, line.getRight().yCoord, line.getRight().zCoord); + tessellator.addVertex(line.getLeft().xCoord, line.getLeft().yCoord, line.getLeft().zCoord); + } + tessellator.draw(); + } + + private static void renderHorizontalFaces(Vec3[][] faces, Tessellator tessellator) { + for (Vec3[] face : faces) { + tessellator.startDrawing(3); + for (Vec3 vertex : face) { + tessellator.addVertex(vertex.xCoord, vertex.yCoord, vertex.zCoord); + } + tessellator.addVertex(face[0].xCoord, face[0].yCoord, face[0].zCoord); + tessellator.draw(); + } + } + + public static void drawOutlineBoundingBoxWithMultipleBoxes(AxisAlignedBB AABB, int color) { + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawing(3); + + if (color != -1) { + tessellator.setColorOpaque_I(color); + } + + tessellator.addVertex(AABB.minX, AABB.minY, AABB.minZ); + tessellator.addVertex(AABB.maxX, AABB.minY, AABB.minZ); + tessellator.addVertex(AABB.maxX, AABB.minY, AABB.maxZ); + tessellator.addVertex(AABB.minX, AABB.minY, AABB.maxZ); + tessellator.addVertex(AABB.minX, AABB.minY, AABB.minZ); + tessellator.draw(); + } +}