From 3aef519c257e8283af62edfebcea8a90958640f2 Mon Sep 17 00:00:00 2001 From: bdew Date: Tue, 25 Aug 2015 13:25:31 +0300 Subject: [PATCH] Added some hooks to cover system, fixed rendering covers when breaking blocks --- src/net/bdew/lib/covers/BlockCoverable.scala | 83 ++++++++++++++++---- src/net/bdew/lib/covers/CoverRenderer.scala | 13 +-- src/net/bdew/lib/covers/ItemCover.scala | 57 +++++++++++++- 3 files changed, 127 insertions(+), 26 deletions(-) diff --git a/src/net/bdew/lib/covers/BlockCoverable.scala b/src/net/bdew/lib/covers/BlockCoverable.scala index 989e592..be105a7 100644 --- a/src/net/bdew/lib/covers/BlockCoverable.scala +++ b/src/net/bdew/lib/covers/BlockCoverable.scala @@ -11,10 +11,11 @@ package net.bdew.lib.covers import cpw.mods.fml.relauncher.{Side, SideOnly} import net.bdew.lib.Misc -import net.bdew.lib.block.HasTE +import net.bdew.lib.block.{BlockRef, HasTE} import net.bdew.lib.items.ItemUtils import net.minecraft.block.Block -import net.minecraft.entity.player.EntityPlayer +import net.minecraft.entity.player.{EntityPlayer, EntityPlayerMP} +import net.minecraft.item.ItemStack import net.minecraft.util.IIcon import net.minecraft.world.{IBlockAccess, World} import net.minecraftforge.common.util.ForgeDirection @@ -23,53 +24,101 @@ trait BlockCoverable[T <: TileCoverable] extends HasTE[T] { @SideOnly(Side.CLIENT) override def getRenderType = CoverRenderer.id + private def getCoverItem(w: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection): Option[(ItemCover, ItemStack, TileCoverable)] = { + val te = getTE(w, x, y, z) + for { + coverStack <- Option(te.covers(side).value) + coverItemMaybe <- Option(coverStack.getItem) + coverItem <- Misc.asInstanceOpt(coverItemMaybe, classOf[ItemCover]) + } yield (coverItem, coverStack, te) + } + override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, face: Int, xOffs: Float, yOffs: Float, zOffs: Float): Boolean = { val te = getTE(world, x, y, z) val side = Misc.forgeDirection(face) + // Shift+RightClick with empty hand should remove cover if (player.getCurrentEquippedItem == null && player.isSneaking) { - for (cover <- Option(te.covers(side).value)) { + for { + cover <- Option(te.covers(side).value) + coverItem <- Misc.asInstanceOpt(cover.getItem, classOf[ItemCover]) + } { if (!world.isRemote) { te.covers(side) := null te.onCoversChanged() - ItemUtils.dropItemToPlayer(world, player, cover) + coverChanged(world, x, y, z, side) + ItemUtils.dropItemToPlayer(world, player, coverItem.onRemove(cover)) } return true } } + // If held item is cover - try to install it for { activeStack <- Option(player.getCurrentEquippedItem) activeItem <- Option(activeStack.getItem) coverItem <- Misc.asInstanceOpt(activeItem, classOf[ItemCover]) if te.isValidCover(side, activeStack) && coverItem.isValidTile(te, activeStack) } { - if (!world.isRemote) { - for (cover <- Option(te.covers(side).value)) - ItemUtils.throwItemAt(world, te.xCoord + side.offsetX, te.yCoord + side.offsetY, te.zCoord + side.offsetZ, cover.copy()) + if (!world.isRemote && player.isInstanceOf[EntityPlayerMP]) { + for { + oldCover <- Option(te.covers(side).value) + oldItem <- Misc.asInstanceOpt(oldCover.getItem, classOf[ItemCover]) + } { + ItemUtils.throwItemAt(world, te.xCoord + side.offsetX, te.yCoord + side.offsetY, te.zCoord + side.offsetZ, oldItem.onRemove(oldCover)) + } - te.covers(side) := activeStack.splitStack(1) + te.covers(side) := coverItem.onInstall(te, side, activeStack.splitStack(1), player.asInstanceOf[EntityPlayerMP]) + + if (activeStack.stackSize <= 0) + player.inventory.setInventorySlotContents(player.inventory.currentItem, null) - if (activeStack.stackSize <= 0) player.inventory.setInventorySlotContents(player.inventory.currentItem, null) te.onCoversChanged() + coverChanged(world, x, y, z, side) } return true } + // If has cover - let it handle the click + for ((item, stack, te) <- getCoverItem(world, x, y, z, side)) { + if (item.clickCover(te, side, stack, player)) return true + } + super.onBlockActivated(world, x, y, z, player, face, xOffs, yOffs, zOffs) } + override def canProvidePower = true + + override def isProvidingWeakPower(w: IBlockAccess, x: Int, y: Int, z: Int, side: Int): Int = { + val direction = Misc.forgeDirection(side).getOpposite + for ((item, stack, te) <- getCoverItem(w, x, y, z, direction)) { + if (item.isEmittingSignal(te, direction, stack)) return 15 + } + 0 + } + + def coverChanged(w: World, x: Int, y: Int, z: Int, side: ForgeDirection): Unit = { + val pos = BlockRef(x, y, z).neighbour(side) + w.notifyBlockOfNeighborChange(pos.x, pos.y, pos.z, pos.block(w).orNull) + } + def getCoverIcon(w: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection): Option[IIcon] = - for { - coverStack <- Option(getTE(w, x, y, z).covers(side).value) - coverItemMaybe <- Option(coverStack.getItem) - coverItem <- Misc.asInstanceOpt(coverItemMaybe, classOf[ItemCover]) - } yield coverItem.getCoverIcon(coverStack) + for ((item, stack, te) <- getCoverItem(w, x, y, z, side)) + yield item.getCoverIcon(te, side, stack) override def breakBlock(world: World, x: Int, y: Int, z: Int, block: Block, meta: Int) { - if (!world.isRemote) - for ((dir, covOpt) <- getTE(world, x, y, z).covers; cover <- Option(covOpt.value)) - ItemUtils.throwItemAt(world, x, y, z, cover) + if (!world.isRemote) { + val te = getTE(world, x, y, z) + for { + (dir, covOpt) <- te.covers + cover <- Option(covOpt.value) + item <- Misc.asInstanceOpt(cover.getItem, classOf[ItemCover]) + } { + te.covers(dir) := null + ItemUtils.throwItemAt(world, x, y, z, item.onRemove(cover)) + coverChanged(world, x, y, z, dir) + } + } super.breakBlock(world, x, y, z, block, meta) } } diff --git a/src/net/bdew/lib/covers/CoverRenderer.scala b/src/net/bdew/lib/covers/CoverRenderer.scala index 4b4f3c6..e6b9850 100644 --- a/src/net/bdew/lib/covers/CoverRenderer.scala +++ b/src/net/bdew/lib/covers/CoverRenderer.scala @@ -23,12 +23,13 @@ object CoverRenderer extends BaseBlockRenderHandler { override def renderWorldBlock(world: IBlockAccess, x: Int, y: Int, z: Int, block: Block, modelId: Int, renderer: RenderBlocks) = { renderer.renderStandardBlock(block, x, y, z) - for { - blockCov <- Misc.asInstanceOpt(block, classOf[BlockCoverable[_]]) - face <- ForgeDirection.VALID_DIRECTIONS - icon <- blockCov.getCoverIcon(world, x, y, z, face) - if block.shouldSideBeRendered(world, x + face.offsetX, y + face.offsetY, z + face.offsetZ, face.ordinal()) - } ConnectedHelper.draw(face, 8).doDraw(ConnectedHelper.Vec3F(x, y, z), icon) + if (!renderer.hasOverrideBlockTexture) + for { + blockCov <- Misc.asInstanceOpt(block, classOf[BlockCoverable[_]]) + face <- ForgeDirection.VALID_DIRECTIONS + icon <- blockCov.getCoverIcon(world, x, y, z, face) + if block.shouldSideBeRendered(world, x + face.offsetX, y + face.offsetY, z + face.offsetZ, face.ordinal()) + } ConnectedHelper.draw(face, 8).doDraw(ConnectedHelper.Vec3F(x, y, z), icon) true } } diff --git a/src/net/bdew/lib/covers/ItemCover.scala b/src/net/bdew/lib/covers/ItemCover.scala index 84c7000..111d468 100644 --- a/src/net/bdew/lib/covers/ItemCover.scala +++ b/src/net/bdew/lib/covers/ItemCover.scala @@ -1,5 +1,5 @@ /* - * Copyright (c) bdew, 2013 - 2014 + * Copyright (c) bdew, 2013 - 2015 * https://github.com/bdew/bdlib * * This mod is distributed under the terms of the Minecraft Mod Public @@ -9,23 +9,74 @@ package net.bdew.lib.covers +import net.minecraft.entity.player.{EntityPlayer, EntityPlayerMP} import net.minecraft.item.{Item, ItemStack} import net.minecraft.util.IIcon import net.minecraftforge.common.util.ForgeDirection trait ItemCover extends Item { /** + * @return true if tickCover should be called + */ + def isCoverTicking: Boolean + + /** + * @param te Host TileEntity + * @param side Side the cover is installed on + * @param cover Cover ItemStack * @return Icon to render, MUST be on terrain sprite sheet (0), not item! */ - def getCoverIcon(stack: ItemStack): IIcon + def getCoverIcon(te: TileCoverable, side: ForgeDirection, cover: ItemStack): IIcon /** * Perform tick, called on server only + * @param te Host TileEntity + * @param side Side the cover is installed on + * @param cover Cover ItemStack */ - def tickCover(te: TileCoverable, side: ForgeDirection, cover: ItemStack) + def tickCover(te: TileCoverable, side: ForgeDirection, cover: ItemStack): Unit = {} /** * Checks if this cover can be installed on a specific TE + * @param te Potential host TileEntity + * @param cover Cover ItemStack + * @return true if can be installed */ def isValidTile(te: TileCoverable, cover: ItemStack): Boolean + + /** + * Handle click on covered side - called on both client and server + * @param te Host TileEntity + * @param side Side the cover is installed on + * @param cover Cover ItemStack + * @param player Player clicking the cover + * @return true if click was handled by cover + */ + def clickCover(te: TileCoverable, side: ForgeDirection, cover: ItemStack, player: EntityPlayer): Boolean = false + + /** + * Check if cover is emitting RS signal + * @param te Host TileEntity + * @param side Side the cover is installed on + * @param cover Cover ItemStack + * @return true if cover is emitting RS signal + */ + def isEmittingSignal(te: TileCoverable, side: ForgeDirection, cover: ItemStack): Boolean = false + + /** + * Called when cover is installed on a block - called only on server + * @param te Host TileEntity + * @param side Side the cover is installed on + * @param cover Cover ItemStack - do not modify! + * @param player Player entity doing the installation + * @return cover ItemStack - copy if modified + */ + def onInstall(te:TileCoverable, side: ForgeDirection, cover: ItemStack, player: EntityPlayerMP): ItemStack = cover + + /** + * Called when cover is removed from block or block is destroyed - called only on server + * @param cover Cover ItemStack - do not modify! + * @return cover ItemStack - copy if modified + */ + def onRemove(cover: ItemStack): ItemStack = cover }