From 4f2618d03b28c813b6379b02f732a09e328b90fe Mon Sep 17 00:00:00 2001 From: sisyphussy Date: Sun, 21 Sep 2025 16:33:05 +0200 Subject: [PATCH] Dynamism Tablet Rewrite (#65) Co-authored-by: Martin Robertz --- dependencies.gradle | 4 +- gradle.properties | 2 +- .../tile/RenderTileAnimationTablet.java | 61 +- .../tinkerer/common/ThaumicTinkerer.java | 2 + .../common/block/BlockAnimationTablet.java | 79 +- .../block/tile/tablet/TabletFakePlayer.java | 190 ++++- .../tile/tablet/TileAnimationTablet.java | 785 +++++++++--------- .../tinkerer/common/registry/TTRegistry.java | 3 + .../early/AccessorItemInWorldManager.java | 13 + .../preloader/ThaumicTLoaderContainer.java | 4 +- 10 files changed, 637 insertions(+), 506 deletions(-) create mode 100644 src/main/java/thaumic/tinkerer/mixins/early/AccessorItemInWorldManager.java diff --git a/dependencies.gradle b/dependencies.gradle index 5cb0b291..d3ee7e40 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,7 +1,7 @@ // Add your dependencies here dependencies { - api('com.github.GTNewHorizons:Baubles-Expanded:2.1.14-GTNH:dev') + api('com.github.GTNewHorizons:Baubles-Expanded:2.1.15-GTNH:dev') api('thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev') api('com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-686-GTNH:api') api('com.github.GTNewHorizons:ThaumicBoots:1.4.14:dev') { @@ -19,7 +19,7 @@ dependencies { compileOnly('com.github.GTNewHorizons:CodeChickenCore:1.4.7:dev') {transitive=false} compileOnly('com.github.GTNewHorizons:OpenComputers:1.11.19-GTNH:api') {transitive=false} compileOnly('net.industrial-craft:industrialcraft-2:2.2.828-experimental:api') {transitive=false} - compileOnly("com.github.GTNewHorizons:GT5-Unofficial:5.09.51.457:dev") {transitive=false} + compileOnly("com.github.GTNewHorizons:GT5-Unofficial:5.09.51.457:dev") compileOnly('curse.maven:computercraft-67504:2269339') compileOnly('curse.maven:cofh-core-69162:2388751') diff --git a/gradle.properties b/gradle.properties index 650b0352..5a63cc68 100644 --- a/gradle.properties +++ b/gradle.properties @@ -41,7 +41,7 @@ developmentEnvironmentUserName = Developer # Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8. # See https://github.com/bsideup/jabel for details on how this works. -enableModernJavaSyntax = false +enableModernJavaSyntax = true # Enables injecting missing generics into the decompiled source code for a better coding experience. # Turns most publicly visible List, Map, etc. into proper List, Map types. diff --git a/src/main/java/thaumic/tinkerer/client/render/tile/RenderTileAnimationTablet.java b/src/main/java/thaumic/tinkerer/client/render/tile/RenderTileAnimationTablet.java index e85a2b29..b2f8c2db 100644 --- a/src/main/java/thaumic/tinkerer/client/render/tile/RenderTileAnimationTablet.java +++ b/src/main/java/thaumic/tinkerer/client/render/tile/RenderTileAnimationTablet.java @@ -47,12 +47,18 @@ public class RenderTileAnimationTablet extends TileEntitySpecialRenderer { int rotation = meta == 2 ? 270 : meta == 3 ? 90 : meta == 4 ? 0 : 180; + GL11.glColor4f(1F, 1F, 1F, 1F); + GL11.glPushMatrix(); GL11.glTranslated(d0, d1, d2); - renderOverlay(tile, overlayCenter, -1, false, false, 0.65, 0.13F, 0F); - if (tile.leftClick) renderOverlay(tile, overlayLeft, 1, false, true, 1, 0.13F, 0F); - else renderOverlay(tile, overlayRight, 1, false, true, 1, 0.131F, 0F); - renderOverlay(tile, overlayIndent, 0, false, false, 0.5F, 0.13F, rotation + 90F); + GL11.glDepthMask(false); + GL11.glDisable(GL11.GL_LIGHTING); + renderOverlay(tile, overlayCenter, -1, false, 0.65, 0.13F, partialTicks); + if (tile.leftClick) renderOverlay(tile, overlayLeft, 1, true, 1, 0.13F, partialTicks); + else renderOverlay(tile, overlayRight, 1, true, 1, 0.131F, partialTicks); + renderIndents(tile, rotation + 90F); + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glDepthMask(true); GL11.glRotatef(rotation, 0F, 1F, 0F); GL11.glTranslated(0.1, 0.2 + Math.cos(System.currentTimeMillis() / 600D) / 18F, 0.5); @@ -60,9 +66,10 @@ public class RenderTileAnimationTablet extends TileEntitySpecialRenderer { GL11.glTranslatef(translations[0], translations[1], translations[2]); GL11.glScalef(0.8F, 0.8F, 0.8F); GL11.glTranslatef(0.5F, 0F, 0.5F); - GL11.glRotatef(tile.swingProgress, 0F, 0F, 1F); + float swingProgress = tile.getRenderSwingProgress(partialTicks); + GL11.glRotatef(swingProgress, 0F, 0F, 1F); GL11.glTranslatef(-0.5F, 0F, -0.5F); - GL11.glTranslatef(-tile.swingProgress / 250F, tile.swingProgress / 1000F, 0F); + GL11.glTranslatef(-swingProgress / 250F, swingProgress / 1000F, 0F); GL11.glRotatef((float) Math.cos(System.currentTimeMillis() / 400F) * 5F, 1F, 0F, 1F); renderItem(tile); GL11.glPopMatrix(); @@ -72,6 +79,8 @@ public class RenderTileAnimationTablet extends TileEntitySpecialRenderer { ItemStack stack = tablet.getStackInSlot(0); if (stack != null) { EntityItem entityitem = new EntityItem(tablet.getWorldObj(), 0.0D, 0.0D, 0.0D, stack); + entityitem.worldObj = tablet.getWorldObj(); + int stackSize = entityitem.getEntityItem().stackSize; entityitem.getEntityItem().stackSize = 1; entityitem.hoverStart = 0.0F; GL11.glPushMatrix(); @@ -81,25 +90,24 @@ public class RenderTileAnimationTablet extends TileEntitySpecialRenderer { RenderItem.renderInFrame = true; RenderManager.instance.renderEntityWithPosYaw(entityitem, 0.0D, 0.0D, 0.0D, 0.0F, 0.0F); RenderItem.renderInFrame = false; + GL11.glPopMatrix(); + entityitem.getEntityItem().stackSize = stackSize; } } - private void renderOverlay(TileAnimationTablet tablet, ResourceLocation texture, int rotationMod, - boolean useLighting, boolean useBlend, double size, float height, float forceDeg) { + private void renderOverlay(TileAnimationTablet tablet, ResourceLocation texture, int rotationMod, boolean useBlend, + double size, float height, float partialTicks) { Minecraft mc = ClientHelper.minecraft(); mc.renderEngine.bindTexture(texture); GL11.glPushMatrix(); - GL11.glDepthMask(false); - if (!useLighting) GL11.glDisable(GL11.GL_LIGHTING); if (useBlend) { GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); } GL11.glTranslatef(0.5F, height, 0.5F); - float deg = rotationMod == 0 ? forceDeg : (float) (tablet.ticksExisted * rotationMod % 360F); + float deg = (tablet.getTicksExisted(partialTicks) * rotationMod % 360F); GL11.glRotatef(deg, 0F, 1F, 0F); - GL11.glColor4f(1F, 1F, 1F, 1F); Tessellator tess = Tessellator.instance; double size1 = size / 2; double size2 = -size1; @@ -109,8 +117,33 @@ public class RenderTileAnimationTablet extends TileEntitySpecialRenderer { tess.addVertexWithUV(size1, 0, size2, 1, 0); tess.addVertexWithUV(size2, 0, size2, 0, 0); tess.draw(); - GL11.glDepthMask(true); - if (!useLighting) GL11.glEnable(GL11.GL_LIGHTING); + GL11.glPopMatrix(); + } + + private void renderIndents(TileAnimationTablet tablet, float forceDeg) { + Minecraft mc = ClientHelper.minecraft(); + mc.renderEngine.bindTexture(overlayIndent); + GL11.glPushMatrix(); + GL11.glTranslatef(0.5F, (float) 0.13, 0.5F); + GL11.glRotatef(forceDeg, 0F, 1F, 0F); + Tessellator tess = Tessellator.instance; + final double size1 = 0.25; + final double size2 = -0.25; + tess.startDrawingQuads(); + tess.addVertexWithUV(size2, 0, size1, 0, 1); + tess.addVertexWithUV(size1, 0, size1, 1, 1); + tess.addVertexWithUV(size1, 0, size2, 1, 0); + tess.addVertexWithUV(size2, 0, size2, 0, 0); + tess.draw(); + int acceleration = tablet.getWorldAcceleratorBonus(); + if (acceleration != 0) { + GL11.glRotatef(90, -1, 0, 0); + GL11.glScalef(0.02f, -0.02f, 0.02f); + final String s = 'x' + Integer.toString(acceleration); + final int width = mc.fontRenderer.getStringWidth(s); + GL11.glTranslatef(-width / 2f, 10f + mc.fontRenderer.FONT_HEIGHT / 2f, 0); + mc.fontRenderer.drawString(s, 0, 0, 0xFFFFFF); + } GL11.glPopMatrix(); } } diff --git a/src/main/java/thaumic/tinkerer/common/ThaumicTinkerer.java b/src/main/java/thaumic/tinkerer/common/ThaumicTinkerer.java index f47ddfa5..1425b513 100644 --- a/src/main/java/thaumic/tinkerer/common/ThaumicTinkerer.java +++ b/src/main/java/thaumic/tinkerer/common/ThaumicTinkerer.java @@ -57,6 +57,7 @@ public class ThaumicTinkerer { public static TTCommonProxy proxy; public static boolean isBootsActive = false; + public static boolean gtLoaded; public static final String BOOTS = "thaumicboots"; public static CommonProxy tcProxy; @@ -80,6 +81,7 @@ public class ThaumicTinkerer { if (Loader.isModLoaded(BOOTS)) { isBootsActive = true; } + gtLoaded = Loader.isModLoaded("gregtech"); } @EventHandler diff --git a/src/main/java/thaumic/tinkerer/common/block/BlockAnimationTablet.java b/src/main/java/thaumic/tinkerer/common/block/BlockAnimationTablet.java index e84a2cb1..49cabe3c 100644 --- a/src/main/java/thaumic/tinkerer/common/block/BlockAnimationTablet.java +++ b/src/main/java/thaumic/tinkerer/common/block/BlockAnimationTablet.java @@ -44,6 +44,7 @@ import thaumic.tinkerer.common.block.tile.tablet.TileAnimationTablet; import thaumic.tinkerer.common.lib.LibBlockNames; import thaumic.tinkerer.common.lib.LibGuiIDs; import thaumic.tinkerer.common.lib.LibResearch; +import thaumic.tinkerer.common.registry.TTRegistry; import thaumic.tinkerer.common.registry.ThaumicTinkererArcaneRecipe; import thaumic.tinkerer.common.registry.ThaumicTinkererRecipe; import thaumic.tinkerer.common.research.IRegisterableResearch; @@ -98,37 +99,32 @@ public class BlockAnimationTablet extends BlockModContainer { TileAnimationTablet tablet = (TileAnimationTablet) par1World.getTileEntity(par2, par3, par4); if (tablet != null) { - if (tablet.getIsBreaking()) {} + ItemStack itemstack = tablet.heldItem; + if (itemstack != null) { + float f = random.nextFloat() * 0.8F + 0.1F; + float f1 = random.nextFloat() * 0.8F + 0.1F; + EntityItem entityitem; - for (int j1 = 0; j1 < tablet.getSizeInventory(); ++j1) { - ItemStack itemstack = tablet.getStackInSlot(j1); + for (float f2 = random.nextFloat() * 0.8F + 0.1F; itemstack.stackSize > 0; par1World + .spawnEntityInWorld(entityitem)) { + int k1 = random.nextInt(21) + 10; - if (itemstack != null) { - float f = random.nextFloat() * 0.8F + 0.1F; - float f1 = random.nextFloat() * 0.8F + 0.1F; - EntityItem entityitem; + if (k1 > itemstack.stackSize) k1 = itemstack.stackSize; - for (float f2 = random.nextFloat() * 0.8F + 0.1F; itemstack.stackSize > 0; par1World - .spawnEntityInWorld(entityitem)) { - int k1 = random.nextInt(21) + 10; + itemstack.stackSize -= k1; + entityitem = new EntityItem( + par1World, + par2 + f, + par3 + f1, + par4 + f2, + new ItemStack(itemstack.getItem(), k1, itemstack.getItemDamage())); + float f3 = 0.05F; + entityitem.motionX = (float) random.nextGaussian() * f3; + entityitem.motionY = (float) random.nextGaussian() * f3 + 0.2F; + entityitem.motionZ = (float) random.nextGaussian() * f3; - if (k1 > itemstack.stackSize) k1 = itemstack.stackSize; - - itemstack.stackSize -= k1; - entityitem = new EntityItem( - par1World, - par2 + f, - par3 + f1, - par4 + f2, - new ItemStack(itemstack.getItem(), k1, itemstack.getItemDamage())); - float f3 = 0.05F; - entityitem.motionX = (float) random.nextGaussian() * f3; - entityitem.motionY = (float) random.nextGaussian() * f3 + 0.2F; - entityitem.motionZ = (float) random.nextGaussian() * f3; - - if (itemstack.hasTagCompound()) entityitem.getEntityItem() - .setTagCompound((NBTTagCompound) itemstack.getTagCompound().copy()); - } + if (itemstack.hasTagCompound()) + entityitem.getEntityItem().setTagCompound((NBTTagCompound) itemstack.getTagCompound().copy()); } } @@ -142,6 +138,8 @@ public class BlockAnimationTablet extends BlockModContainer { @Override public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, Block par5) { if (par1World.isRemote) return; + TileEntity te = par1World.getTileEntity(par2, par3, par4); + if (!(te instanceof TileAnimationTablet tablet) || !tablet.redstone) return; boolean power = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4); @@ -162,18 +160,9 @@ public class BlockAnimationTablet extends BlockModContainer { @Override public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random) { TileEntity tile = par1World.getTileEntity(par2, par3, par4); - if (tile != null && tile instanceof TileAnimationTablet) { - TileAnimationTablet tablet = (TileAnimationTablet) tile; - if (tablet.redstone && tablet.swingProgress == 0) { - tablet.findEntities(tablet.getTargetLoc()); + if (tile instanceof TileAnimationTablet tablet) { + if (tablet.redstone && tablet.isIdle()) { tablet.initiateSwing(); - par1World.addBlockEvent( - par2, - par3, - par4, - ThaumicTinkerer.registry.getFirstBlockFromClass(BlockAnimationTablet.class), - 0, - 0); } } } @@ -183,13 +172,12 @@ public class BlockAnimationTablet extends BlockModContainer { int par6, float par7, float par8, float par9) { if (!par1World.isRemote) { TileEntity tile = par1World.getTileEntity(par2, par3, par4); - if (tile != null) { - TileAnimationTablet tablet = (TileAnimationTablet) tile; + if (tile instanceof TileAnimationTablet tablet) { if (par5EntityPlayer.getCurrentEquippedItem() != null && par5EntityPlayer.getCurrentEquippedItem().getItem() instanceof ItemWandCasting) { int meta = par1World.getBlockMetadata(par2, par3, par4); boolean activated = (meta & 8) != 0; - if (!activated && !tablet.getIsBreaking() && tablet.swingProgress == 0) { + if (!activated && !tablet.getIsBreaking() && tablet.isIdle()) { par1World.setBlockMetadataWithNotify(par2, par3, par4, meta == 5 ? 2 : meta + 1, 1 | 2); par1World.playSoundEffect(par2, par3, par4, "thaumcraft:tool", 0.6F, 1F); } else par5EntityPlayer @@ -268,10 +256,9 @@ public class BlockAnimationTablet extends BlockModContainer { -8, 2, 4, - new ItemStack(ThaumicTinkerer.registry.getFirstBlockFromClass(BlockAnimationTablet.class))).setWarp(1) - .setParents(LibResearch.KEY_MAGNETS).setPages( - new ResearchPage("0"), - ResearchHelper.arcaneRecipePage(LibResearch.KEY_ANIMATION_TABLET)); + new ItemStack(TTRegistry.dynamismTablet)).setWarp(1).setParents(LibResearch.KEY_MAGNETS).setPages( + new ResearchPage("0"), + ResearchHelper.arcaneRecipePage(LibResearch.KEY_ANIMATION_TABLET)); } @Override @@ -279,7 +266,7 @@ public class BlockAnimationTablet extends BlockModContainer { return new ThaumicTinkererArcaneRecipe( LibResearch.KEY_ANIMATION_TABLET, LibResearch.KEY_ANIMATION_TABLET, - new ItemStack(ThaumicTinkerer.registry.getFirstBlockFromClass(BlockAnimationTablet.class)), + new ItemStack(TTRegistry.dynamismTablet), new AspectList().add(Aspect.AIR, 25).add(Aspect.ORDER, 15).add(Aspect.FIRE, 10), "GIG", "ICI", diff --git a/src/main/java/thaumic/tinkerer/common/block/tile/tablet/TabletFakePlayer.java b/src/main/java/thaumic/tinkerer/common/block/tile/tablet/TabletFakePlayer.java index 6e13afab..07db2ef8 100644 --- a/src/main/java/thaumic/tinkerer/common/block/tile/tablet/TabletFakePlayer.java +++ b/src/main/java/thaumic/tinkerer/common/block/tile/tablet/TabletFakePlayer.java @@ -13,76 +13,180 @@ package thaumic.tinkerer.common.block.tile.tablet; import java.util.UUID; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.network.NetHandlerPlayServer; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.server.MinecraftServer; import net.minecraft.util.ChunkCoordinates; import net.minecraft.util.IChatComponent; -import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; import com.mojang.authlib.GameProfile; -import thaumcraft.common.lib.FakeThaumcraftPlayer; +public final class TabletFakePlayer extends FakePlayer { -public class TabletFakePlayer extends FakeThaumcraftPlayer { + private final TileAnimationTablet tablet; - TileAnimationTablet tablet; - - public TabletFakePlayer(TileAnimationTablet tablet) { // ,String name) { + public TabletFakePlayer(TileAnimationTablet tablet) { super( - tablet.getWorldObj(), + (WorldServer) tablet.getWorldObj(), new GameProfile(UUID.fromString("a8f026a0-135b-11e4-9191-0800200c9a66"), "[ThaumcraftTablet]")); - // super(tablet.getWorldObj(),"[ThaumcraftTablet]"); this.tablet = tablet; - } - - @Override - public void setDead() { - inventory.clearInventory(null, -1); - super.setDead(); - } - - @Override - public void openGui(Object mod, int modGuiId, World world, int x, int y, int z) { - // NO-OP + this.playerNetServerHandler = new DummyNetHandlerPlayServer(MinecraftServer.getServer(), this); + this.width = 0; + this.height = 0; + this.boundingBox.setBounds(this.posX, this.posY, this.posZ, this.posX, this.posY, this.posZ); + this.rotationPitch = -15; } @Override public void onUpdate() { - capabilities.isCreativeMode = false; - - posX = tablet.xCoord + 0.5; - posY = tablet.yCoord + 1.6; - posZ = tablet.zCoord + 0.5; - - if (riddenByEntity != null) riddenByEntity.ridingEntity = null; - if (ridingEntity != null) ridingEntity.riddenByEntity = null; - riddenByEntity = null; - ridingEntity = null; - + this.posX = tablet.xCoord + 0.5f; + this.posY = tablet.yCoord + 0.5f; + this.posZ = tablet.zCoord + 0.5f; + this.inventory.currentItem = 0; motionX = motionY = motionZ = 0; - setHealth(20); - isDead = false; + + this.capabilities.isCreativeMode = false; int meta = tablet.getBlockMetadata() & 7; int rotation = meta == 2 ? 180 : meta == 3 ? 0 : meta == 4 ? 90 : -90; - rotationYaw = rotationYawHead = rotation; - rotationPitch = -15; - for (int i = 0; i < inventory.getSizeInventory(); i++) { - if (i != inventory.currentItem) { - ItemStack stack = inventory.getStackInSlot(i); - if (stack != null) { - entityDropItem(stack, 1.0f); - inventory.setInventorySlotContents(i, null); - } + rotationYaw = rotationYawHead = rotation; + // Drop everything except for held item + for (int i = 1; i < inventory.getSizeInventory(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + if (stack != null) { + entityDropItem(stack, 0); + inventory.setInventorySlotContents(i, null); } } + syncSlots(); } - @Override - public void addChatMessage(IChatComponent var1) {} + public void syncSlots() { + this.inventory.mainInventory[0] = tablet.heldItem; + } + + // Copied from Minecraft and PlayerControllerMP + public boolean sendUseItem(ItemStack stack) { + if (!ForgeEventFactory.onPlayerInteract(this, PlayerInteractEvent.Action.RIGHT_CLICK_AIR, 0, 0, 0, -1, worldObj) + .isCanceled()) { + int i = stack.stackSize; + ItemStack itemstack1 = stack.useItemRightClick(worldObj, this); + if (itemstack1 == stack && itemstack1.stackSize == i) { + return false; + } + inventory.mainInventory[0] = itemstack1; + + if (itemstack1.stackSize <= 0) { + inventory.mainInventory[0] = null; + MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(this, itemstack1)); + } + return true; + } + return false; + } + + // copied from PlayerController#onPlayerRightClick + public boolean onPlayerRightClick(ItemStack stack, int x, int y, int z, int side, float f, float f1, float f2) { + Item item = stack.getItem(); + if (item != null && item.onItemUseFirst(stack, this, worldObj, x, y, z, side, f, f1, f2)) { + return true; + } + + Block block = worldObj.getBlock(x, y, z); + if (block.onBlockActivated(worldObj, x, y, z, this, side, f, f1, f2)) { + return true; + } + + if (!stack.tryPlaceItemIntoWorld(this, worldObj, x, y, z, side, f, f1, f2)) { + return false; + } + if (stack.stackSize <= 0) { + MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(this, stack)); + } + return true; + } @Override public ChunkCoordinates getPlayerCoordinates() { return new ChunkCoordinates(tablet.xCoord, tablet.yCoord, tablet.zCoord); } + + @Override + protected boolean isMovementBlocked() { + return true; + } + + @Override + public boolean canBePushed() { + return false; + } + + @Override + public boolean canBeCollidedWith() { + return false; + } + + @Override + public void setPosition(double x, double y, double z) { + // NO-OP (the position is set at creation) + } + + @Override + public void setDead() { + // NO-OP (this should never happen...?) + } + + @Override + public void mountEntity(Entity entityIn) { + // NO-OP + } + + @Override + public void setHealth(float p_70606_1_) { + // NO-OP + } + + @Override + public void onLivingUpdate() { + // NO-OP + } + + @Override + public void addChatMessage(IChatComponent var1) { + // NO-OP + } + + @Override + public void addChatComponentMessage(IChatComponent chatmessagecomponent) { + // NO-OP + } + + private static final class DummyNetHandlerPlayServer extends NetHandlerPlayServer { + + public DummyNetHandlerPlayServer(MinecraftServer server, FakePlayer player) { + super(server, new NetworkManager(false), player); + } + + @Override + public void onNetworkTick() { + // NO-OP + } + + @Override + public void sendPacket(Packet packetIn) { + // NO-OP + } + } } diff --git a/src/main/java/thaumic/tinkerer/common/block/tile/tablet/TileAnimationTablet.java b/src/main/java/thaumic/tinkerer/common/block/tile/tablet/TileAnimationTablet.java index 6a4a2daa..32b616ea 100644 --- a/src/main/java/thaumic/tinkerer/common/block/tile/tablet/TileAnimationTablet.java +++ b/src/main/java/thaumic/tinkerer/common/block/tile/tablet/TileAnimationTablet.java @@ -11,48 +11,49 @@ */ package thaumic.tinkerer.common.block.tile.tablet; -import java.util.ArrayList; import java.util.List; import net.minecraft.block.Block; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.passive.EntityAnimal; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Blocks; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemReed; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.server.management.ItemInWorldManager; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.ChatComponentText; -import net.minecraft.util.ChunkCoordinates; import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import appeng.api.movable.IMovableTile; import cpw.mods.fml.common.Optional; -import cpw.mods.fml.common.eventhandler.Event; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; +import gregtech.common.tileentities.machines.basic.MTEWorldAccelerator; import li.cil.oc.api.machine.Arguments; import li.cil.oc.api.machine.Callback; import li.cil.oc.api.machine.Context; import li.cil.oc.api.network.SimpleComponent; import thaumic.tinkerer.common.ThaumicTinkerer; -import thaumic.tinkerer.common.block.BlockAnimationTablet; import thaumic.tinkerer.common.lib.LibBlockNames; +import thaumic.tinkerer.common.registry.TTRegistry; +import thaumic.tinkerer.mixins.early.AccessorItemInWorldManager; @Optional.InterfaceList({ @Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers"), @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheral", modid = "ComputerCraft"), @@ -63,339 +64,343 @@ public class TileAnimationTablet extends TileEntity implements IInventory, IMova private static final String TAG_REDSTONE = "redstone"; private static final String TAG_PROGRESS = "progress"; private static final String TAG_MOD = "mod"; - private static final String TAG_OWNER = "owner"; private static final int[][] LOC_INCREASES = new int[][] { { 0, -1 }, { 0, +1 }, { -1, 0 }, { +1, 0 } }; - private static final ForgeDirection[] SIDES = new ForgeDirection[] { ForgeDirection.NORTH, ForgeDirection.SOUTH, - ForgeDirection.WEST, ForgeDirection.EAST }; - - private static final int SWING_SPEED = 3; - private static final int MAX_DEGREE = 45; - public double ticksExisted = 0; + private static final byte SWING_SPEED = 3; + private static final byte MAX_DEGREE = 45; + private static final byte MAX_ITERATIONS = MAX_DEGREE / SWING_SPEED; public boolean leftClick = true; public boolean redstone = false; - public int swingProgress = 0; - List detectedEntities = new ArrayList<>(); - ItemStack[] inventorySlots = new ItemStack[1]; - // public String Owner; - TabletFakePlayer player; - private int swingMod = 0; + private byte prevSwingProgress; + private byte swingProgress; + private byte swingMod; + + public ItemStack heldItem; + + private TabletFakePlayer player; private boolean isBreaking = false; - private int initialDamage = 0; - private int curblockDamage = 0; - private int durabilityRemainingOnBlock; + private int ticksElapsed; + private int prevTicksElapsed; + + private final Vec3 tempVec = Vec3.createVectorHelper(0, 0, 0); + private final Vec3 positionVec = Vec3.createVectorHelper(0, 0, 0); + + @SideOnly(Side.CLIENT) + public final float getRenderSwingProgress(float partialTicks) { + return prevSwingProgress + (swingProgress - prevSwingProgress) * partialTicks; + } + + @SideOnly(Side.CLIENT) + public final float getTicksExisted(float partialTicks) { + return prevTicksElapsed + (ticksElapsed - prevTicksElapsed) * partialTicks; + } + + @SideOnly(Side.CLIENT) + public final int getWorldAcceleratorBonus() { + return (ticksElapsed - prevTicksElapsed) - 1; + } @Override public void updateEntity() { - // player = new TabletFakePlayer(this);//,Owner); - player.onUpdate(); - player.inventory.clearInventory(null, -1); - ticksExisted++; + if (worldObj.isRemote) { + prevSwingProgress = swingProgress; + prevTicksElapsed = ticksElapsed; + int iterations = ThaumicTinkerer.gtLoaded ? MTEWorldAccelerator.getAccelerationForTEUnsafe(this) + 1 : 1; + ticksElapsed += iterations; + ItemStack stack = heldItem; + if (stack != null) { + iterations = Math.min(iterations, MAX_ITERATIONS); + for (int i = 0; i < iterations; i++) { + swingProgress += swingMod; + if (swingProgress >= MAX_DEGREE) { + swingMod = -SWING_SPEED; + } else if (swingProgress <= 0) { + stopSwinging(); + } + } + } else { + stopSwinging(); + } + return; + } - ItemStack stack = getStackInSlot(0); + try { + player.onUpdate(); - if (stack != null) { - if (swingProgress >= MAX_DEGREE) swingHit(); + ItemStack stack = heldItem; + if (stack == null) { + if (isBreaking) stopBreaking(); + stopSwinging(); + return; + } - swingMod = swingProgress <= 0 ? 0 : swingProgress >= MAX_DEGREE ? -SWING_SPEED : swingMod; + MovingObjectPosition hit = calculateHit(); swingProgress += swingMod; - if (swingProgress < 0) swingProgress = 0; - } else { - swingMod = 0; - swingProgress = 0; + if (swingProgress >= MAX_DEGREE) { + if (hit != null) { + swingHit(stack, hit); + } + swingMod = -SWING_SPEED; + } else if (swingProgress <= 0) { + stopSwinging(); + } - if (isBreaking) stopBreaking(); - } - - boolean detect = detect(); - if (!detect) stopBreaking(); - - if (detect && isBreaking) continueBreaking(); - - if ((!redstone || isBreaking) && detect && swingProgress == 0) { - initiateSwing(); - worldObj.addBlockEvent( - xCoord, - yCoord, - zCoord, - ThaumicTinkerer.registry.getFirstBlockFromClass(BlockAnimationTablet.class), - 0, - 0); - } - } - - public void initiateSwing() { - swingMod = SWING_SPEED; - swingProgress = 1; - } - - public void swingHit() { - ChunkCoordinates coords = getTargetLoc(); - ItemStack stack = getStackInSlot(0); - Item item = stack.getItem(); - Block block = worldObj.getBlock(coords.posX, coords.posY, coords.posZ); - - player.setCurrentItemOrArmor(0, stack); - - boolean done = false; - - if (leftClick) { - Entity entity = detectedEntities.isEmpty() ? null - : detectedEntities.get(worldObj.rand.nextInt(detectedEntities.size())); - if (entity != null) { - player.getAttributeMap().applyAttributeModifiers(stack.getAttributeModifiers()); // Set attack strenght - player.attackTargetEntityWithCurrentItem(entity); - done = true; - } else if (!isBreaking) { - if (block != Blocks.air && !block.isAir(worldObj, coords.posX, coords.posY, coords.posZ) - && block.getBlockHardness(worldObj, coords.posX, coords.posY, coords.posZ) >= 0) { - isBreaking = true; - startBreaking(block, worldObj.getBlockMetadata(coords.posX, coords.posY, coords.posZ)); - done = true; + if (isBreaking) { + if (hit == null || hit.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) { + stopBreaking(); + return; + } + ItemInWorldManager worldManager = player.theItemInWorldManager; + worldManager.updateBlockRemoving(); + if (((AccessorItemInWorldManager) worldManager).getDurabilityRemainingOnBlock() >= 10) { + worldManager.tryHarvestBlock(hit.blockX, hit.blockY, hit.blockZ); } } - } else { - int side = SIDES[(getBlockMetadata() & 7) - 2].getOpposite().ordinal(); - if (!(block != Blocks.air && !block.isAir(worldObj, coords.posX, coords.posY, coords.posZ))) { - coords.posY -= 1; - side = ForgeDirection.UP.ordinal(); - block = worldObj.getBlock(coords.posX, coords.posY, coords.posZ); - } - - try { - ForgeEventFactory.onPlayerInteract( - player, - Action.RIGHT_CLICK_AIR, - coords.posX, - coords.posY, - coords.posZ, - side, - worldObj); - Entity entity = detectedEntities.isEmpty() ? null - : detectedEntities.get(worldObj.rand.nextInt(detectedEntities.size())); - done = entity != null && entity instanceof EntityLiving - && (item.itemInteractionForEntity(stack, player, (EntityLivingBase) entity) - || (!(entity instanceof EntityAnimal) || ((EntityAnimal) entity).interact(player))); - - if (!done) item.onItemUseFirst( - stack, - player, - worldObj, - coords.posX, - coords.posY, - coords.posZ, - side, - 0F, - 0F, - 0F); - if (!done) done = block != null && block - .onBlockActivated(worldObj, coords.posX, coords.posY, coords.posZ, player, side, 0F, 0F, 0F); - if (!done) done = item - .onItemUse(stack, player, worldObj, coords.posX, coords.posY, coords.posZ, side, 0F, 0F, 0F); - if (!done) { - item.onItemRightClick(stack, worldObj, player); - done = true; - } - - } catch (Throwable e) { - e.printStackTrace(); - List list = worldObj.getEntitiesWithinAABB( - EntityPlayer.class, - AxisAlignedBB.getBoundingBox( - xCoord - 8, - yCoord - 8, - zCoord - 8, - xCoord + 8, - yCoord + 8, - zCoord + 8)); - for (Object player : list) { - ((EntityPlayer) player).addChatComponentMessage( - new ChatComponentText( - EnumChatFormatting.RED - + "Something went wrong with a Tool Dynamism Tablet! Check your FML log.")); - ((EntityPlayer) player).addChatComponentMessage( - new ChatComponentText( - EnumChatFormatting.RED + "" + EnumChatFormatting.ITALIC + e.getMessage())); + if (isIdle() && hit != null && (!redstone || isBreaking)) { + if (hit.typeOfHit == MovingObjectPosition.MovingObjectType.MISS + && (leftClick || !canPlaceItem(stack))) { + return; } + initiateSwing(); } - } - - if (done) { - stack = player.getCurrentEquippedItem(); - if (stack == null || stack.stackSize <= 0) setInventorySlotContents(0, null); - else if (stack != getStackInSlot(0)) setInventorySlotContents(0, stack); - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - } - markDirty(); - } - - // Copied from ItemInWorldManager, seems to do the trick. - private void stopBreaking() { - isBreaking = false; - ChunkCoordinates coords = getTargetLoc(); - worldObj.destroyBlockInWorldPartially(player.getEntityId(), coords.posX, coords.posY, coords.posZ, -1); - } - - // Copied from ItemInWorldManager, seems to do the trick. - private void startBreaking(Block block, int meta) { - int side = SIDES[(getBlockMetadata() & 7) - 2].getOpposite().ordinal(); - ChunkCoordinates coords = getTargetLoc(); - - PlayerInteractEvent event = ForgeEventFactory.onPlayerInteract( - player, - Action.LEFT_CLICK_BLOCK, - coords.posX, - coords.posY, - coords.posZ, - side, - worldObj); - if (event.isCanceled()) { - stopBreaking(); - return; - } - - initialDamage = curblockDamage; - float var5 = 1F; - - if (block != null) { - if (event.useBlock != Event.Result.DENY) - block.onBlockClicked(worldObj, coords.posX, coords.posY, coords.posZ, player); - var5 = block.getPlayerRelativeBlockHardness(player, worldObj, coords.posX, coords.posY, coords.posZ); - } - - if (event.useItem == Event.Result.DENY) { - stopBreaking(); - return; - } - - if (var5 >= 1F) { - tryHarvestBlock(coords.posX, coords.posY, coords.posZ); - stopBreaking(); - } else { - int var7 = (int) (var5 * 10); - worldObj.destroyBlockInWorldPartially(player.getEntityId(), coords.posX, coords.posY, coords.posZ, var7); - durabilityRemainingOnBlock = var7; - } - } - - // Copied from ItemInWorldManager, seems to do the trick. - private void continueBreaking() { - ++curblockDamage; - int var1; - float var4; - int var5; - ChunkCoordinates coords = getTargetLoc(); - - var1 = curblockDamage - initialDamage; - Block block = worldObj.getBlock(coords.posX, coords.posY, coords.posZ); - - if (block == Blocks.air) stopBreaking(); - else { - var4 = block.getPlayerRelativeBlockHardness(player, worldObj, coords.posX, coords.posY, coords.posZ) * var1; - var5 = (int) (var4 * 10); - - if (var5 != durabilityRemainingOnBlock) { - worldObj.destroyBlockInWorldPartially( - player.getEntityId(), - coords.posX, - coords.posY, - coords.posZ, - var5); - durabilityRemainingOnBlock = var5; - } - - if (var4 >= 1F) { - tryHarvestBlock(coords.posX, coords.posY, coords.posZ); - stopBreaking(); + } catch (Exception e) { + e.printStackTrace(); + List list = worldObj.getEntitiesWithinAABB( + EntityPlayer.class, + AxisAlignedBB + .getBoundingBox(xCoord - 8, yCoord - 8, zCoord - 8, xCoord + 8, yCoord + 8, zCoord + 8)); + for (EntityPlayer player : list) { + player.addChatComponentMessage( + new ChatComponentText( + EnumChatFormatting.RED + + "Something went wrong with a Tool Dynamism Tablet! Check your FML log.")); + player.addChatComponentMessage( + new ChatComponentText( + EnumChatFormatting.RED.toString() + EnumChatFormatting.ITALIC + e.getMessage())); } } } - // Copied from ItemInWorldManager, seems to do the trick. - public boolean tryHarvestBlock(int par1, int par2, int par3) { - ItemStack stack = getStackInSlot(0); - if (stack != null && stack.getItem().onBlockStartBreak(stack, par1, par2, par3, player)) return false; - - Block block = worldObj.getBlock(par1, par2, par3); - int var5 = worldObj.getBlockMetadata(par1, par2, par3); - // worldObj.playAuxSFXAtEntity(player, 2001, par1, par2, par3, var4 + (var5 << 12)); - boolean var6; - - boolean var8 = false; - if (block != null) var8 = block.canHarvestBlock(player, var5); - - worldObj.loadedEntityList.size(); - if (stack != null) stack.getItem().onBlockDestroyed(stack, worldObj, block, par1, par2, par3, player); - - var6 = removeBlock(par1, par2, par3); - if (var6 && var8) block.harvestBlock(worldObj, player, par1, par2, par3, var5); - - return var6; - } - - // Copied from ItemInWorldManager, seems to do the trick. - private boolean removeBlock(int par1, int par2, int par3) { - Block var4 = worldObj.getBlock(par1, par2, par3); - int var5 = worldObj.getBlockMetadata(par1, par2, par3); - - if (var4 != null) var4.onBlockHarvested(worldObj, par1, par2, par3, var5, player); - - boolean var6 = var4 != null && var4.removedByPlayer(worldObj, player, par1, par2, par3); - - if (var4 != null && var6) var4.onBlockDestroyedByPlayer(worldObj, par1, par2, par3, var5); - - return var6; - } - - public boolean detect() { - ChunkCoordinates coords = getTargetLoc(); - findEntities(coords); - return !worldObj.isAirBlock(coords.posX, coords.posY, coords.posZ) || !detectedEntities.isEmpty(); - } - - public void findEntities(ChunkCoordinates coords) { - AxisAlignedBB boundingBox = AxisAlignedBB.getBoundingBox( - coords.posX, - coords.posY, - coords.posZ, - coords.posX + 1, - coords.posY + 1, - coords.posZ + 1); - detectedEntities = worldObj.getEntitiesWithinAABB(Entity.class, boundingBox); + private boolean canPlaceItem(ItemStack stack) { + final Item item = stack.getItem(); + return item instanceof ItemBlock || item instanceof ItemReed; } @Override public void validate() { super.validate(); - player = new TabletFakePlayer(this); + if (!worldObj.isRemote) { + if (player == null) { + player = new TabletFakePlayer(this); + } + player.worldObj = this.worldObj; + } } - public ChunkCoordinates getTargetLoc() { - ChunkCoordinates coords = new ChunkCoordinates(xCoord, yCoord, zCoord); + private void swingHit(ItemStack stack, MovingObjectPosition hit) { + if (leftClick) { + if (hit.typeOfHit == MovingObjectPosition.MovingObjectType.ENTITY) { + player.attackTargetEntityWithCurrentItem(hit.entityHit); + updateState(); + } else if (hit.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { + if (!isBreaking) { + int x = hit.blockX; + int y = hit.blockY; + int z = hit.blockZ; + Block block = worldObj.getBlock(x, y, z); + if (!block.isAir(worldObj, x, y, z) && block.getBlockHardness(worldObj, x, y, z) >= 0) { + isBreaking = true; + player.theItemInWorldManager.onBlockClicked(x, y, z, hit.sideHit); + updateState(); + } + } + } + } else { + if (hit.typeOfHit == MovingObjectPosition.MovingObjectType.ENTITY) { + if (player.interactWith(hit.entityHit)) { + updateState(); + } + return; + } + int side = hit.sideHit; + + int x = hit.blockX; + int y = hit.blockY; + int z = hit.blockZ; + + // Copied from Minecraft's right click logic + boolean result = !ForgeEventFactory + .onPlayerInteract(player, PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK, x, y, z, side, worldObj) + .isCanceled(); + + if (result) { + Vec3 hitVec = hit.hitVec; + if (player.onPlayerRightClick( + stack, + x, + y, + z, + side, + (float) hitVec.xCoord, + (float) hitVec.yCoord, + (float) hitVec.zCoord)) { + updateState(); + return; + } + } + + if (player.sendUseItem(stack)) { + updateState(); + } + } + } + + public final boolean isIdle() { + return swingMod == 0; + } + + public final boolean getIsBreaking() { + return isBreaking; + } + + private void stopSwinging() { + swingProgress = 0; + swingMod = 0; + } + + // Copied from ItemInWorldManager, seems to do the trick. + private void stopBreaking() { + player.theItemInWorldManager.updateBlockRemoving(); + isBreaking = false; + int[] increase = LOC_INCREASES[(getBlockMetadata() & 7) - 2]; + int x = xCoord + increase[0]; + int y = yCoord; + int z = zCoord + increase[1]; + worldObj.destroyBlockInWorldPartially(player.getEntityId(), x, y, z, -1); + } + + private void updateState() { + ItemStack stack = player.getHeldItem(); + if (stack == null || stack.stackSize <= 0) { + this.heldItem = null; + player.syncSlots(); + } else { + this.heldItem = stack; + } + markDirty(); + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + + /** + * Logic: Casts a ray between the player and the middle of the AABB to determine the side and hitVec. Works for both + * entities and blocks. Whichever is closer takes priority. + *

+ * This is similar to how Minecraft calculates the MovingObjectPosition, but instead of yaw/pitch I use the middle + * of the bounding box to cover edge where blocks have a weird bounding box. + *

+ * hit.typeOfHit will be MISS if it's targeting the block below (this is done so that placing blocks still properly + * works). + *

+ * This is an improvement to the old system, because it properly knows whether to hit an entity or block and also + * passes in the proper parameters when interacting with a block (this has previously caused some issues with + * certain blocks). + */ + private MovingObjectPosition calculateHit() { int meta = getBlockMetadata(); if (meta == 0) { ThaumicTinkerer.log .error("Metadata of a Tool Dynamism tablet is in an invalid state. This is a critical error."); - return coords; + return null; } int[] increase = LOC_INCREASES[(meta & 7) - 2]; - coords.posX += increase[0]; - coords.posZ += increase[1]; + int x = xCoord + increase[0]; + int y = yCoord; + int z = zCoord + increase[1]; + Block block = worldObj.getBlock(x, y, z); - return coords; + MovingObjectPosition hit = null; + Vec3 position = positionVec; + position.xCoord = xCoord + 0.5f; + position.yCoord = yCoord + 0.5f; + position.zCoord = zCoord + 0.5f; + if (!worldObj.isAirBlock(x, y, z)) { + AxisAlignedBB aabb = block.getSelectedBoundingBoxFromPool(worldObj, x, y, z); + if (aabb != null) { + hit = block.collisionRayTrace(worldObj, x, y, z, position, getMiddleOfAABB(aabb)); + } + } + List entities = (List) worldObj.getEntitiesWithinAABBExcludingEntity( + player, + AxisAlignedBB.getBoundingBox(x, y, z, x + 1, y + 1, z + 1)); + if (!entities.isEmpty()) { + double dist = hit == null ? Double.MAX_VALUE : position.squareDistanceTo(hit.hitVec); + + Entity targetedEntity = null; + Vec3 hitVec = null; + for (Entity e : entities) { + if (e.canBeCollidedWith()) { + + float borderSize = e.getCollisionBorderSize(); + AxisAlignedBB aabb = e.boundingBox.expand(borderSize, borderSize, borderSize); + MovingObjectPosition intercept = aabb.calculateIntercept(position, getMiddleOfAABB(aabb)); + + if (aabb.isVecInside(position)) { + targetedEntity = e; + hitVec = intercept == null ? position : intercept.hitVec; + break; + } + if (intercept != null) { + double entityDist = position.squareDistanceTo(intercept.hitVec); + + if (dist > entityDist) { + hitVec = intercept.hitVec; + targetedEntity = e; + dist = entityDist; + } + } + } + } + + if (targetedEntity != null) { + hit = new MovingObjectPosition(targetedEntity, hitVec); + } + } + + if (hit == null) { + // Use the block beneath + y--; + if (!worldObj.isAirBlock(x, y, z)) { + AxisAlignedBB aabb = block.getSelectedBoundingBoxFromPool(worldObj, x, y, z); + Vec3 vec = getMiddleOfAABB(aabb); + vec.yCoord = (aabb.maxY - y); + hit = new MovingObjectPosition(x, y, z, ForgeDirection.UP.ordinal(), vec, false); + } + } + + return hit; } - public boolean getIsBreaking() { - return isBreaking; + private Vec3 getMiddleOfAABB(AxisAlignedBB aabb) { + tempVec.xCoord = (aabb.minX + aabb.maxX) / 2f; + tempVec.yCoord = (aabb.minY + aabb.maxY) / 2f; + tempVec.zCoord = (aabb.minZ + aabb.maxZ) / 2f; + return tempVec; + } + + public void initiateSwing() { + swingMod = SWING_SPEED; + worldObj.addBlockEvent(xCoord, yCoord, zCoord, TTRegistry.dynamismTablet, 0, 0); } @Override - public boolean receiveClientEvent(int par1, int par2) { - if (par1 == 0) { - initiateSwing(); + public boolean receiveClientEvent(int id, int type) { + if (!worldObj.isRemote) return true; + if (id == 0) { + swingMod = SWING_SPEED; + swingProgress = 0; return true; } @@ -403,82 +408,86 @@ public class TileAnimationTablet extends TileEntity implements IInventory, IMova } @Override - public void readFromNBT(NBTTagCompound par1NBTTagCompound) { - super.readFromNBT(par1NBTTagCompound); + public void readFromNBT(NBTTagCompound tag) { + super.readFromNBT(tag); - swingProgress = par1NBTTagCompound.getInteger(TAG_PROGRESS); + swingProgress = tag.getByte(TAG_PROGRESS); + swingMod = tag.getByte(TAG_MOD); - readCustomNBT(par1NBTTagCompound); + readCustomNBT(tag); } @Override - public void writeToNBT(NBTTagCompound par1NBTTagCompound) { - super.writeToNBT(par1NBTTagCompound); + public void writeToNBT(NBTTagCompound tag) { + super.writeToNBT(tag); - par1NBTTagCompound.setInteger(TAG_PROGRESS, swingProgress); - par1NBTTagCompound.setInteger(TAG_MOD, swingMod); - // par1NBTTagCompound.setString(TAG_OWNER,Owner); - writeCustomNBT(par1NBTTagCompound); + tag.setByte(TAG_PROGRESS, swingProgress); + tag.setByte(TAG_MOD, swingMod); + + writeCustomNBT(tag); } - public void readCustomNBT(NBTTagCompound par1NBTTagCompound) { - leftClick = par1NBTTagCompound.getBoolean(TAG_LEFT_CLICK); - redstone = par1NBTTagCompound.getBoolean(TAG_REDSTONE); - NBTTagList var2 = par1NBTTagCompound.getTagList("Items", Constants.NBT.TAG_COMPOUND); - inventorySlots = new ItemStack[getSizeInventory()]; - for (int var3 = 0; var3 < var2.tagCount(); ++var3) { - NBTTagCompound var4 = var2.getCompoundTagAt(var3); - byte var5 = var4.getByte("Slot"); - if (var5 >= 0 && var5 < inventorySlots.length) inventorySlots[var5] = ItemStack.loadItemStackFromNBT(var4); + private void readCustomNBT(NBTTagCompound tag) { + leftClick = tag.getBoolean(TAG_LEFT_CLICK); + redstone = tag.getBoolean(TAG_REDSTONE); + if (tag.hasKey("Item")) { + NBTTagCompound itemTag = tag.getCompoundTag("Item"); + heldItem = ItemStack.loadItemStackFromNBT(itemTag); + return; + } + // Legacy Compatibility (there is no reason to store it as an array) + NBTTagList tagList = tag.getTagList("Items", Constants.NBT.TAG_COMPOUND); + if (tagList.tagCount() != 0) { + heldItem = ItemStack.loadItemStackFromNBT(tagList.getCompoundTagAt(0)); } } - public void writeCustomNBT(NBTTagCompound par1NBTTagCompound) { - par1NBTTagCompound.setBoolean(TAG_LEFT_CLICK, leftClick); - par1NBTTagCompound.setBoolean(TAG_REDSTONE, redstone); - NBTTagList var2 = new NBTTagList(); - for (int var3 = 0; var3 < inventorySlots.length; ++var3) { - if (inventorySlots[var3] != null) { - NBTTagCompound var4 = new NBTTagCompound(); - var4.setByte("Slot", (byte) var3); - inventorySlots[var3].writeToNBT(var4); - var2.appendTag(var4); - } - } - par1NBTTagCompound.setTag("Items", var2); + @Override + public S35PacketUpdateTileEntity getDescriptionPacket() { + NBTTagCompound tag = new NBTTagCompound(); + writeCustomNBT(tag); + return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, -999, tag); + } + + @Override + public void onDataPacket(NetworkManager manager, S35PacketUpdateTileEntity packet) { + super.onDataPacket(manager, packet); + readCustomNBT(packet.func_148857_g()); + } + + private void writeCustomNBT(NBTTagCompound tag) { + tag.setBoolean(TAG_LEFT_CLICK, leftClick); + tag.setBoolean(TAG_REDSTONE, redstone); + + tag.setTag("Item", heldItem == null ? new NBTTagCompound() : heldItem.writeToNBT(new NBTTagCompound())); } @Override public int getSizeInventory() { - return inventorySlots.length; + return 1; } @Override public ItemStack getStackInSlot(int i) { - return inventorySlots[i]; + return i == 0 ? heldItem : null; } @Override - public ItemStack decrStackSize(int par1, int par2) { - if (inventorySlots[par1] != null) { + public ItemStack decrStackSize(int index, int count) { + if (index == 0 && heldItem != null) { ItemStack stackAt; - if (inventorySlots[par1].stackSize <= par2) { - stackAt = inventorySlots[par1]; - inventorySlots[par1] = null; + if (heldItem.stackSize <= count) { + stackAt = heldItem; + heldItem = null; - if (!worldObj.isRemote) worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - - return stackAt; } else { - stackAt = inventorySlots[par1].splitStack(par2); + stackAt = heldItem.splitStack(count); - if (inventorySlots[par1].stackSize == 0) inventorySlots[par1] = null; - - if (!worldObj.isRemote) worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - - return stackAt; + if (heldItem.stackSize == 0) heldItem = null; } + if (!worldObj.isRemote) worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + return stackAt; } return null; @@ -491,7 +500,8 @@ public class TileAnimationTablet extends TileEntity implements IInventory, IMova @Override public void setInventorySlotContents(int i, ItemStack itemstack) { - inventorySlots[i] = itemstack; + if (i != 0) return; + heldItem = itemstack; if (!worldObj.isRemote) worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } @@ -528,19 +538,6 @@ public class TileAnimationTablet extends TileEntity implements IInventory, IMova @Override public void closeInventory() {} - @Override - public S35PacketUpdateTileEntity getDescriptionPacket() { - NBTTagCompound nbttagcompound = new NBTTagCompound(); - writeCustomNBT(nbttagcompound); - return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, -999, nbttagcompound); - } - - @Override - public void onDataPacket(NetworkManager manager, S35PacketUpdateTileEntity packet) { - super.onDataPacket(manager, packet); - readCustomNBT(packet.func_148857_g()); - } - @Override public String getType() { return "tt_animationTablet"; @@ -556,39 +553,23 @@ public class TileAnimationTablet extends TileEntity implements IInventory, IMova @Optional.Method(modid = "ComputerCraft") public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException { - switch (method) { - case 0: - return new Object[] { redstone }; - case 1: - return setRedstoneImplementation((Boolean) arguments[0]); - case 2: - return new Object[] { leftClick }; - case 3: - return setLeftClickImplementation((Boolean) arguments[0]); - case 4: - return new Object[] { getBlockMetadata() - 2 }; - case 5: - return setRotationImplementation((Double) arguments[0]); - case 6: - return new Object[] { getStackInSlot(0) != null }; - case 7: - return triggerImplementation(); - } - return null; + return switch (method) { + case 0 -> new Object[] { redstone }; + case 1 -> setRedstoneImplementation((Boolean) arguments[0]); + case 2 -> new Object[] { leftClick }; + case 3 -> setLeftClickImplementation((Boolean) arguments[0]); + case 4 -> new Object[] { getBlockMetadata() - 2 }; + case 5 -> setRotationImplementation((Double) arguments[0]); + case 6 -> new Object[] { heldItem != null }; + case 7 -> triggerImplementation(); + default -> null; + }; } private Object[] triggerImplementation() { - if (swingProgress != 0) return new Object[] { false }; + if (!isIdle()) return new Object[] { false }; - findEntities(getTargetLoc()); initiateSwing(); - worldObj.addBlockEvent( - xCoord, - yCoord, - zCoord, - ThaumicTinkerer.registry.getFirstBlockFromClass(BlockAnimationTablet.class), - 0, - 0); return new Object[] { true }; } @@ -651,26 +632,30 @@ public class TileAnimationTablet extends TileEntity implements IInventory, IMova @Callback(doc = "function():boolean -- Returns Whether tablet is redstone activated") @Optional.Method(modid = "OpenComputers") - public Object[] getRedstone(Context context, Arguments args) throws Exception { + @SuppressWarnings("unused") + public Object[] getRedstone(Context context, Arguments args) { return new Object[] { redstone }; } @Callback(doc = "function(boolean):Nil -- Sets Whether tablet is redstone activated") @Optional.Method(modid = "OpenComputers") - public Object[] setRedstone(Context context, Arguments args) throws Exception { + @SuppressWarnings("unused") + public Object[] setRedstone(Context context, Arguments args) { setRedstoneImplementation(args.checkBoolean(0)); return new Object[] { redstone }; } @Callback(doc = "function():boolean -- Returns Whether tablet Left clicks") @Optional.Method(modid = "OpenComputers") - public Object[] getLeftClick(Context context, Arguments args) throws Exception { + @SuppressWarnings("unused") + public Object[] getLeftClick(Context context, Arguments args) { return new Object[] { leftClick }; } @Callback(doc = "function(boolean):Nil -- Sets Whether tablet Left Clicks") @Optional.Method(modid = "OpenComputers") - public Object[] setLeftClick(Context context, Arguments args) throws Exception { + @SuppressWarnings("unused") + public Object[] setLeftClick(Context context, Arguments args) { setLeftClickImplementation(args.checkBoolean(0)); return new Object[] { leftClick }; } @@ -678,26 +663,30 @@ public class TileAnimationTablet extends TileEntity implements IInventory, IMova // TODO {"hasItem", "trigger" }; @Callback(doc = "function():number -- Returns tablet Rotation") @Optional.Method(modid = "OpenComputers") - public Object[] getRotation(Context context, Arguments args) throws Exception { + @SuppressWarnings("unused") + public Object[] getRotation(Context context, Arguments args) { return new Object[] { getBlockMetadata() - 2 }; } @Callback(doc = "function(number):Nil -- Sets tablet rotation") @Optional.Method(modid = "OpenComputers") - public Object[] setRotation(Context context, Arguments args) throws Exception { + @SuppressWarnings("unused") + public Object[] setRotation(Context context, Arguments args) throws LuaException { setRotationImplementation((double) args.checkInteger(0)); return new Object[] { getBlockMetadata() - 2 }; } @Callback(doc = "function():boolean -- Returns wether tablet has an item or not") @Optional.Method(modid = "OpenComputers") - public Object[] hasItem(Context context, Arguments args) throws Exception { - return new Object[] { getStackInSlot(0) != null }; + @SuppressWarnings("unused") + public Object[] hasItem(Context context, Arguments args) { + return new Object[] { heldItem != null }; } @Callback(doc = "function():Nil -- Triggers tablets swing") @Optional.Method(modid = "OpenComputers") - public Object[] trigger(Context context, Arguments args) throws Exception { + @SuppressWarnings("unused") + public Object[] trigger(Context context, Arguments args) { return triggerImplementation(); } } diff --git a/src/main/java/thaumic/tinkerer/common/registry/TTRegistry.java b/src/main/java/thaumic/tinkerer/common/registry/TTRegistry.java index 5d720ace..368235b8 100644 --- a/src/main/java/thaumic/tinkerer/common/registry/TTRegistry.java +++ b/src/main/java/thaumic/tinkerer/common/registry/TTRegistry.java @@ -20,6 +20,7 @@ import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.relauncher.Side; import thaumic.tinkerer.client.lib.LibResources; import thaumic.tinkerer.common.ThaumicTinkerer; +import thaumic.tinkerer.common.block.BlockAnimationTablet; import thaumic.tinkerer.common.core.handler.ModCreativeTab; import thaumic.tinkerer.common.item.kami.ItemBlockTalisman; import thaumic.tinkerer.common.item.kami.ItemPlacementMirror; @@ -33,6 +34,7 @@ public class TTRegistry { private ArrayList blockClasses = new ArrayList<>(); private HashMap> blockRegistry = new HashMap<>(); + public static Block dynamismTablet; public static Item itemPlacementMirror; public static Item itemBlackHoleTalisman; @@ -177,6 +179,7 @@ public class TTRegistry { } } + dynamismTablet = ThaumicTinkerer.registry.getFirstBlockFromClass(BlockAnimationTablet.class); itemBlackHoleTalisman = getFirstItemFromClass(ItemBlockTalisman.class); itemPlacementMirror = getFirstItemFromClass(ItemPlacementMirror.class); } diff --git a/src/main/java/thaumic/tinkerer/mixins/early/AccessorItemInWorldManager.java b/src/main/java/thaumic/tinkerer/mixins/early/AccessorItemInWorldManager.java new file mode 100644 index 00000000..57fd02c0 --- /dev/null +++ b/src/main/java/thaumic/tinkerer/mixins/early/AccessorItemInWorldManager.java @@ -0,0 +1,13 @@ +package thaumic.tinkerer.mixins.early; + +import net.minecraft.server.management.ItemInWorldManager; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ItemInWorldManager.class) +public interface AccessorItemInWorldManager { + + @Accessor + int getDurabilityRemainingOnBlock(); +} diff --git a/src/main/java/thaumic/tinkerer/preloader/ThaumicTLoaderContainer.java b/src/main/java/thaumic/tinkerer/preloader/ThaumicTLoaderContainer.java index 28253e7e..183f6f27 100644 --- a/src/main/java/thaumic/tinkerer/preloader/ThaumicTLoaderContainer.java +++ b/src/main/java/thaumic/tinkerer/preloader/ThaumicTLoaderContainer.java @@ -99,8 +99,8 @@ public class ThaumicTLoaderContainer extends DummyModContainer implements IFMLLo @Override public List getMixins(Set loadedCoreMods) { if (!FMLLaunchHandler.side().isClient()) { - return Collections.emptyList(); + return Collections.singletonList("AccessorItemInWorldManager"); } - return Collections.singletonList("renderer.MixinRenderBlocks"); + return Arrays.asList("renderer.MixinRenderBlocks", "AccessorItemInWorldManager"); } }