From 81e900bfef3efb9c6351858922bb6deb53103e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 10 Feb 2014 23:40:42 +0100 Subject: [PATCH] added new Keyboard implementation so that keyboard only works on proper sides again, still keeping the old one around for upgrading. --- src/main/scala/li/cil/oc/Blocks.scala | 72 +++++---- src/main/scala/li/cil/oc/Recipes.scala | 2 +- .../scala/li/cil/oc/client/GuiHandler.scala | 4 +- .../li/cil/oc/client/PacketHandler.scala | 2 +- src/main/scala/li/cil/oc/client/Proxy.scala | 4 +- .../client/renderer/block/BlockRenderer.scala | 6 +- .../cil/oc/common/asm/ClassTransformer.scala | 12 +- .../scala/li/cil/oc/common/block/Item.scala | 10 +- .../li/cil/oc/common/block/Keyboard.scala | 98 +++++------ .../oc/common/block/KeyboardDeprecated.scala | 153 ++++++++++++++++++ .../li/cil/oc/common/block/SimpleBlock.scala | 112 +++++++++++++ 11 files changed, 371 insertions(+), 104 deletions(-) create mode 100644 src/main/scala/li/cil/oc/common/block/KeyboardDeprecated.scala create mode 100644 src/main/scala/li/cil/oc/common/block/SimpleBlock.scala diff --git a/src/main/scala/li/cil/oc/Blocks.scala b/src/main/scala/li/cil/oc/Blocks.scala index 6a5e012e0..a9f261dce 100644 --- a/src/main/scala/li/cil/oc/Blocks.scala +++ b/src/main/scala/li/cil/oc/Blocks.scala @@ -4,8 +4,8 @@ import cpw.mods.fml.common.registry.GameRegistry import li.cil.oc.common.block._ import li.cil.oc.common.tileentity import net.minecraft.item.ItemStack -import net.minecraftforge.oredict.OreDictionary import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.oredict.OreDictionary object Blocks { var blockSimple: SimpleDelegator = _ @@ -20,6 +20,7 @@ object Blocks { var case1, case2, case3: Case = _ var diskDrive: DiskDrive = _ var keyboard: Keyboard = _ + var keyboardDeprecated: KeyboardDeprecated = _ var powerConverter: PowerConverter = _ var powerDistributor: PowerDistributor = _ var redstone: Redstone = _ @@ -43,6 +44,42 @@ object Blocks { }) } + // IMPORTANT: the multi block must come first, since the sub blocks will + // try to register with it. Also, the order the sub blocks are created in + // must not be changed since that order determines their actual IDs. + adapter = new Adapter(blockSimple) + cable = new Cable(blockSpecial) + capacitor = new Capacitor(blockSimple) + case1 = new Case.Tier1(blockSimpleWithRedstone) + case2 = new Case.Tier2(blockSimpleWithRedstone) + case3 = new Case.Tier3(blockSimpleWithRedstone) + charger = new Charger(blockSimpleWithRedstone) + diskDrive = new DiskDrive(blockSimple) + keyboardDeprecated = new KeyboardDeprecated(blockSpecial) + powerDistributor = new PowerDistributor(blockSimple) + powerConverter = new PowerConverter(blockSimple) + redstone = new Redstone(blockSimpleWithRedstone) + robotAfterimage = new RobotAfterimage(blockSpecial) + robotProxy = new RobotProxy(blockSpecialWithRedstone) + router = new Router(blockSimple) + screen1 = new Screen.Tier1(blockSimpleWithRedstone) + screen2 = new Screen.Tier2(blockSimpleWithRedstone) + screen3 = new Screen.Tier3(blockSimpleWithRedstone) + + // For automatic conversion from old format (when screens did not take + // redstone inputs) to keep save format compatible. + blockSimple.subBlocks += screen1 + blockSimple.subBlocks += screen2 + blockSimple.subBlocks += screen3 + + // v1.2.0 + serverRack = new Rack(blockSpecialWithRedstone) + + // v2.0.0 + keyboard = new Keyboard() + + GameRegistry.registerBlock(keyboard, classOf[Item], Settings.namespace + "keyboard") + GameRegistry.registerBlock(blockSimple, classOf[Item], Settings.namespace + "simple") GameRegistry.registerBlock(blockSimpleWithRedstone, classOf[Item], Settings.namespace + "simple_redstone") GameRegistry.registerBlock(blockSpecial, classOf[Item], Settings.namespace + "special") @@ -63,44 +100,13 @@ object Blocks { GameRegistry.registerTileEntity(classOf[tileentity.Screen], Settings.namespace + "screen") GameRegistry.registerTileEntity(classOf[tileentity.Rack], Settings.namespace + "serverRack") - // IMPORTANT: the multi block must come first, since the sub blocks will - // try to register with it. Also, the order the sub blocks are created in - // must not be changed since that order determines their actual IDs. - adapter = new Adapter(blockSimple) - cable = new Cable(blockSpecial) - capacitor = new Capacitor(blockSimple) - case1 = new Case.Tier1(blockSimpleWithRedstone) - case2 = new Case.Tier2(blockSimpleWithRedstone) - case3 = new Case.Tier3(blockSimpleWithRedstone) - charger = new Charger(blockSimpleWithRedstone) - diskDrive = new DiskDrive(blockSimple) - keyboard = new Keyboard(blockSpecial) - powerDistributor = new PowerDistributor(blockSimple) - powerConverter = new PowerConverter(blockSimple) - redstone = new Redstone(blockSimpleWithRedstone) - robotAfterimage = new RobotAfterimage(blockSpecial) - robotProxy = new RobotProxy(blockSpecialWithRedstone) - router = new Router(blockSimple) - screen1 = new Screen.Tier1(blockSimpleWithRedstone) - screen2 = new Screen.Tier2(blockSimpleWithRedstone) - screen3 = new Screen.Tier3(blockSimpleWithRedstone) - - // For automatic conversion from old format (when screens did not take - // redstone inputs) to keep save format compatible. - blockSimple.subBlocks += screen1 - blockSimple.subBlocks += screen2 - blockSimple.subBlocks += screen3 - - // v1.2.0 - serverRack = new Rack(blockSpecialWithRedstone) - register("oc:craftingCable", cable.createItemStack()) register("oc:craftingCapacitor", capacitor.createItemStack()) register("oc:craftingCaseTier1", case1.createItemStack()) register("oc:craftingCaseTier2", case2.createItemStack()) register("oc:craftingCaseTier3", case3.createItemStack()) register("oc:craftingDiskDrive", diskDrive.createItemStack()) - register("oc:craftingKeyboard", keyboard.createItemStack()) + register("oc:craftingKeyboard", keyboardDeprecated.createItemStack()) register("oc:craftingPowerDistributor", powerDistributor.createItemStack()) register("oc:craftingRouter", router.createItemStack()) register("oc:craftingScreenTier1", screen1.createItemStack()) diff --git a/src/main/scala/li/cil/oc/Recipes.scala b/src/main/scala/li/cil/oc/Recipes.scala index b7f07b826..b74921f55 100644 --- a/src/main/scala/li/cil/oc/Recipes.scala +++ b/src/main/scala/li/cil/oc/Recipes.scala @@ -125,7 +125,7 @@ object Recipes { addRecipe(Blocks.case2.createItemStack(), recipes, "case2") addRecipe(Blocks.case3.createItemStack(), recipes, "case3") addRecipe(Blocks.diskDrive.createItemStack(), recipes, "diskDrive") - addRecipe(Blocks.keyboard.createItemStack(), recipes, "keyboard") + addRecipe(new ItemStack(Blocks.keyboard), recipes, "keyboard") addRecipe(Blocks.powerConverter.createItemStack(), recipes, "powerConverter") addRecipe(Blocks.powerDistributor.createItemStack(), recipes, "powerDistributor") addRecipe(Blocks.redstone.createItemStack(), recipes, "redstone") diff --git a/src/main/scala/li/cil/oc/client/GuiHandler.scala b/src/main/scala/li/cil/oc/client/GuiHandler.scala index 63c389f09..e78569b43 100644 --- a/src/main/scala/li/cil/oc/client/GuiHandler.scala +++ b/src/main/scala/li/cil/oc/client/GuiHandler.scala @@ -3,11 +3,11 @@ package li.cil.oc.client import li.cil.oc.common.inventory.ServerInventory import li.cil.oc.common.{GuiHandler => CommonGuiHandler, item, tileentity, GuiType} import li.cil.oc.{Settings, Items} +import net.minecraft.client.Minecraft import net.minecraft.entity.player.EntityPlayer +import net.minecraft.util.ChatComponentTranslation import net.minecraft.world.World import scala.collection.convert.WrapAsScala._ -import net.minecraft.util.ChatComponentTranslation -import net.minecraft.client.Minecraft object GuiHandler extends CommonGuiHandler { override def getClientGuiElement(id: Int, player: EntityPlayer, world: World, x: Int, y: Int, z: Int): AnyRef = diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index 310d22e73..505f9e989 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -2,10 +2,10 @@ package li.cil.oc.client import cpw.mods.fml.common.eventhandler.SubscribeEvent import cpw.mods.fml.common.network.FMLNetworkEvent.ClientCustomPacketEvent -import li.cil.oc.Settings import li.cil.oc.common.PacketType import li.cil.oc.common.tileentity._ import li.cil.oc.common.{PacketHandler => CommonPacketHandler} +import li.cil.oc.Settings import li.cil.oc.util.PackedColor import net.minecraft.client.gui.GuiScreen import net.minecraft.client.Minecraft diff --git a/src/main/scala/li/cil/oc/client/Proxy.scala b/src/main/scala/li/cil/oc/client/Proxy.scala index 366120dac..caf240e1e 100644 --- a/src/main/scala/li/cil/oc/client/Proxy.scala +++ b/src/main/scala/li/cil/oc/client/Proxy.scala @@ -2,18 +2,18 @@ package li.cil.oc.client import cpw.mods.fml.client.registry.{RenderingRegistry, ClientRegistry} import cpw.mods.fml.common.event.{FMLPreInitializationEvent, FMLPostInitializationEvent, FMLInitializationEvent} +import cpw.mods.fml.common.FMLCommonHandler import cpw.mods.fml.common.network.NetworkRegistry import li.cil.oc.client -import li.cil.oc.client.renderer.WirelessNetworkDebugRenderer import li.cil.oc.client.renderer.block.BlockRenderer import li.cil.oc.client.renderer.item.UpgradeRenderer import li.cil.oc.client.renderer.tileentity._ +import li.cil.oc.client.renderer.WirelessNetworkDebugRenderer import li.cil.oc.common.tileentity import li.cil.oc.common.{Proxy => CommonProxy} import li.cil.oc.{Items, Settings, OpenComputers} import net.minecraftforge.client.MinecraftForgeClient import net.minecraftforge.common.MinecraftForge -import cpw.mods.fml.common.FMLCommonHandler private[oc] class Proxy extends CommonProxy { override def preInit(e: FMLPreInitializationEvent) { diff --git a/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala index d589b67b3..8c16fb035 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala @@ -2,7 +2,7 @@ package li.cil.oc.client.renderer.block import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler import li.cil.oc.client.renderer.tileentity.{CableRenderer, RobotRenderer} -import li.cil.oc.common.block.{RobotAfterimage, RobotProxy, Cable, Delegator} +import li.cil.oc.common.block._ import li.cil.oc.common.tileentity import net.minecraft.block.Block import net.minecraft.client.renderer.{Tessellator, RenderBlocks} @@ -11,6 +11,7 @@ import net.minecraft.world.IBlockAccess import net.minecraftforge.common.util.ForgeDirection import org.lwjgl.opengl.GL11 import li.cil.oc.Blocks +import scala.Some object BlockRenderer extends ISimpleBlockRenderingHandler { var getRenderId = -1 @@ -41,6 +42,9 @@ object BlockRenderer extends ISimpleBlockRenderingHandler { case delegator: Delegator[_] => delegator.setBlockBoundsForItemRender(metadata) delegator.preItemRender(metadata) + case simple: SimpleBlock => + simple.setBlockBoundsForItemRender(metadata) + simple.preItemRender(metadata) case _ => block.setBlockBoundsForItemRender() } renderer.setRenderBoundsFromBlock(block) diff --git a/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala b/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala index 843efea56..ff3fafebc 100644 --- a/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala +++ b/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala @@ -1,15 +1,15 @@ package li.cil.oc.common.asm -import cpw.mods.fml.common.Loader import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper +import cpw.mods.fml.common.Loader import cpw.mods.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions import java.util.logging.{Level, Logger} import li.cil.oc.util.mods.StargateTech2 import net.minecraft.launchwrapper.{LaunchClassLoader, IClassTransformer} +import net.minecraft.tileentity.TileEntity import org.objectweb.asm.tree._ import org.objectweb.asm.{ClassWriter, ClassReader} import scala.collection.convert.WrapAsScala._ -import net.minecraft.tileentity.TileEntity @TransformerExclusions(Array("li.cil.oc.common.asm")) class ClassTransformer extends IClassTransformer { @@ -22,10 +22,10 @@ class ClassTransformer extends IClassTransformer { return ensureStargateTechCompatibility(basicClass) } else if (basicClass != null - && !name.startsWith( """net.minecraft.""") - && !name.startsWith( """net.minecraftforge.""") - && !name.startsWith( """li.cil.oc.common.asm.""") - && !name.startsWith( """li.cil.oc.api.""")) { + && !name.startsWith("""net.minecraft.""") + && !name.startsWith("""net.minecraftforge.""") + && !name.startsWith("""li.cil.oc.common.asm.""") + && !name.startsWith("""li.cil.oc.api.""")) { val classNode = newClassNode(basicClass) if (classNode.interfaces.contains("li/cil/oc/api/network/SimpleComponent")) { try { diff --git a/src/main/scala/li/cil/oc/common/block/Item.scala b/src/main/scala/li/cil/oc/common/block/Item.scala index 083307771..1eb828773 100644 --- a/src/main/scala/li/cil/oc/common/block/Item.scala +++ b/src/main/scala/li/cil/oc/common/block/Item.scala @@ -18,13 +18,19 @@ class Item(value: Block) extends ItemBlock(value) { super.addInformation(stack, player, tooltip, advanced) block match { case delegator: Delegator[_] => delegator.addInformation(getMetadata(stack.getItemDamage), stack, player, tooltip.asInstanceOf[util.List[String]], advanced) - case _ => + case _ => block match { + case simple: SimpleBlock => simple.tooltipLines(getMetadata(stack.getItemDamage), stack, player, tooltip.asInstanceOf[util.List[String]], advanced) + case _ => + } } } override def getRarity(stack: ItemStack) = Delegator.subBlock(stack) match { case Some(subBlock) => subBlock.rarity - case _ => EnumRarity.common + case _ => block match { + case simple: SimpleBlock => simple.rarity + case _ => EnumRarity.common + } } override def getMetadata(itemDamage: Int) = itemDamage diff --git a/src/main/scala/li/cil/oc/common/block/Keyboard.scala b/src/main/scala/li/cil/oc/common/block/Keyboard.scala index c1a0fa298..681b075d5 100644 --- a/src/main/scala/li/cil/oc/common/block/Keyboard.scala +++ b/src/main/scala/li/cil/oc/common/block/Keyboard.scala @@ -1,73 +1,68 @@ package li.cil.oc.common.block -import java.util -import li.cil.oc.Settings -import li.cil.oc.api +import java.util.Random import li.cil.oc.common.tileentity -import li.cil.oc.util.Tooltip -import net.minecraft.client.renderer.texture.IIconRegister +import li.cil.oc.{CreativeTab, api, Settings} +import net.minecraft.block.Block +import net.minecraft.block.material.Material import net.minecraft.entity.player.EntityPlayer -import net.minecraft.item.ItemStack -import net.minecraft.util.{AxisAlignedBB, IIcon} -import net.minecraft.world.{IBlockAccess, World} +import net.minecraft.world.{World, IBlockAccess} import net.minecraftforge.common.util.ForgeDirection import org.lwjgl.opengl.GL11 -import net.minecraft.block.Block +import net.minecraft.item.ItemStack +import java.util +import li.cil.oc.util.Tooltip -class Keyboard(val parent: SpecialDelegator) extends SpecialDelegate { - val unlocalizedName = "Keyboard" +class Keyboard extends SimpleBlock(Material.rock) { + setBlockName("Keyboard") + setBlockTextureName(Settings.resourceDomain + ":keyboard") + setLightOpacity(0) + setCreativeTab(CreativeTab) - var icon: IIcon = null - - override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { - tooltip.addAll(Tooltip.get(unlocalizedName)) + override def tooltipLines(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { + tooltip.addAll(Tooltip.get("Keyboard")) } - override def icon(side: ForgeDirection) = Some(icon) + override def renderAsNormalBlock = false - override def registerIcons(iconRegister: IIconRegister) = { - icon = iconRegister.registerIcon(Settings.resourceDomain + ":keyboard") - } + override def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int) = true - override def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = true + override def isOpaqueCube = false - override def hasTileEntity = true + override def isNormalCube = false - override def createTileEntity(world: World) = Some(new tileentity.Keyboard(world.isRemote)) + override def hasTileEntity(metadata: Int) = true - override def update(world: World, x: Int, y: Int, z: Int) = + override def createTileEntity(world: World, metadata: Int) = new tileentity.Keyboard(world.isRemote) + + override def updateTick(world: World, x: Int, y: Int, z: Int, rng: Random) = world.getTileEntity(x, y, z) match { case keyboard: tileentity.Keyboard => api.Network.joinOrCreateNetwork(keyboard) case _ => } - override def canPlaceBlockOnSide(world: World, x: Int, y: Int, z: Int, side: ForgeDirection) = - world.isSideSolid(x + side.offsetX, y + side.offsetY, z + side.offsetZ, side.getOpposite) && + override def canPlaceBlockOnSide(world: World, x: Int, y: Int, z: Int, side: ForgeDirection) = { + world.isSideSolid(x + side.offsetX, y + side.offsetY, z + side.offsetZ, side) && (world.getTileEntity(x + side.offsetX, y + side.offsetY, z + side.offsetZ) match { case screen: tileentity.Screen => screen.facing != side.getOpposite case _ => true }) - - override def isNormalCube(world: IBlockAccess, x: Int, y: Int, z: Int) = false - - override def opacity(world: IBlockAccess, x: Int, y: Int, z: Int) = 0 - - override def updateBounds(world: IBlockAccess, x: Int, y: Int, z: Int) = - world.getTileEntity(x, y, z) match { - case keyboard: tileentity.Keyboard => parent.setBlockBounds(computeBounds(keyboard.pitch, keyboard.yaw)) - case _ => super.updateBounds(world, x, y, z) - } - - override def itemBounds() { - parent.setBlockBounds(computeBounds(ForgeDirection.NORTH, ForgeDirection.WEST)) } - override def preItemRender() { + override def doSetBlockBoundsBasedOnState(world: IBlockAccess, x: Int, y: Int, z: Int) = + world.getTileEntity(x, y, z) match { + case keyboard: tileentity.Keyboard => setBlockBounds(keyboard.pitch, keyboard.yaw) + case _ => + } + + override def setBlockBoundsForItemRender(metadata: Int) = setBlockBounds(ForgeDirection.NORTH, ForgeDirection.WEST) + + override def preItemRender(metadata: Int) { GL11.glTranslatef(-0.75f, 0, 0) GL11.glScalef(1.5f, 1.5f, 1.5f) } - private def computeBounds(pitch: ForgeDirection, yaw: ForgeDirection) = { + private def setBlockBounds(pitch: ForgeDirection, yaw: ForgeDirection) { val (forward, up) = pitch match { case side@(ForgeDirection.DOWN | ForgeDirection.UP) => (side, yaw) case _ => (yaw, ForgeDirection.UP) @@ -80,32 +75,23 @@ class Keyboard(val parent: SpecialDelegator) extends SpecialDelegate { val y1 = up.offsetY * sizes(1) + side.offsetY * sizes(2) - forward.offsetY * 0.5f val z0 = -up.offsetZ * sizes(1) - side.offsetZ * sizes(2) - forward.offsetZ * sizes(0) val z1 = up.offsetZ * sizes(1) + side.offsetZ * sizes(2) - forward.offsetZ * 0.5f - AxisAlignedBB.getBoundingBox( + setBlockBounds( math.min(x0, x1) + 0.5f, math.min(y0, y1) + 0.5f, math.min(z0, z1) + 0.5f, math.max(x0, x1) + 0.5f, math.max(y0, y1) + 0.5f, math.max(z0, z1) + 0.5f) } - override def neighborBlockChanged(world: World, x: Int, y: Int, z: Int, block: Block) = + override def onNeighborBlockChange(world: World, x: Int, y: Int, z: Int, block: Block) = world.getTileEntity(x, y, z) match { - case keyboard: tileentity.Keyboard if canPlaceBlockOnSide(world, x, y, z, keyboard.facing.getOpposite) => // Can stay. + case keyboard: tileentity.Keyboard if canPlaceBlockOnSide(world, x, y, z, keyboard.facing.getOpposite.ordinal) => // Can stay. case _ => - parent.dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0) + dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0) world.setBlockToAir(x, y, z) } - override def rightClick(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = + override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = adjacencyInfo(world, x, y, z) match { case Some((keyboard, screen, sx, sy, sz, facing)) => screen.rightClick(world, sx, sy, sz, player, facing, 0, 0, 0) - case _ => super.rightClick(world, x, y, z, player, side, hitX, hitY, hitZ) - } - - def adjacentScreen(world: World, x: Int, y: Int, z: Int) = - adjacencyInfo(world, x, y, z) match { - case Some((_, _, sx, sy, sz, _)) => world.getTileEntity(sx, sy, sz) match { - case screen: tileentity.Screen => Some(screen) - case _ => None - } - case _ => None + case _ => false } def adjacencyInfo(world: World, x: Int, y: Int, z: Int) = @@ -145,5 +131,5 @@ class Keyboard(val parent: SpecialDelegator) extends SpecialDelegate { case _ => None } - override protected val validRotations_ = null + override def getValidRotations(world: World, x: Int, y: Int, z: Int) = null } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/common/block/KeyboardDeprecated.scala b/src/main/scala/li/cil/oc/common/block/KeyboardDeprecated.scala new file mode 100644 index 000000000..b6acc9acd --- /dev/null +++ b/src/main/scala/li/cil/oc/common/block/KeyboardDeprecated.scala @@ -0,0 +1,153 @@ +package li.cil.oc.common.block + +import java.util +import li.cil.oc.{Blocks, api, Settings} +import li.cil.oc.common.tileentity +import li.cil.oc.util.Tooltip +import net.minecraft.block.Block +import net.minecraft.client.renderer.texture.IIconRegister +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.util.{MovingObjectPosition, AxisAlignedBB, IIcon} +import net.minecraft.world.{IBlockAccess, World} +import net.minecraftforge.common.util.ForgeDirection +import org.lwjgl.opengl.GL11 + +class KeyboardDeprecated(val parent: SpecialDelegator) extends SpecialDelegate { + val unlocalizedName = "Keyboard" + + var icon: IIcon = null + + showInItemList = false + + // Phase over to new, proper keyboard. + override def pick(target: MovingObjectPosition, world: World, x: Int, y: Int, z: Int) = new ItemStack(Blocks.keyboard) + + override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { + tooltip.addAll(Tooltip.get(unlocalizedName)) + } + + override def icon(side: ForgeDirection) = Some(icon) + + override def registerIcons(iconRegister: IIconRegister) = { + icon = iconRegister.registerIcon(Settings.resourceDomain + ":keyboard") + } + + override def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = true + + override def hasTileEntity = true + + override def createTileEntity(world: World) = Some(new tileentity.Keyboard(world.isRemote)) + + override def update(world: World, x: Int, y: Int, z: Int) = + world.getTileEntity(x, y, z) match { + case keyboard: tileentity.Keyboard => api.Network.joinOrCreateNetwork(keyboard) + case _ => + } + + override def canPlaceBlockOnSide(world: World, x: Int, y: Int, z: Int, side: ForgeDirection) = + world.isSideSolid(x + side.offsetX, y + side.offsetY, z + side.offsetZ, side.getOpposite) && + (world.getTileEntity(x + side.offsetX, y + side.offsetY, z + side.offsetZ) match { + case screen: tileentity.Screen => screen.facing != side.getOpposite + case _ => true + }) + + override def isNormalCube(world: IBlockAccess, x: Int, y: Int, z: Int) = false + + override def opacity(world: IBlockAccess, x: Int, y: Int, z: Int) = 0 + + override def updateBounds(world: IBlockAccess, x: Int, y: Int, z: Int) = + world.getTileEntity(x, y, z) match { + case keyboard: tileentity.Keyboard => parent.setBlockBounds(computeBounds(keyboard.pitch, keyboard.yaw)) + case _ => super.updateBounds(world, x, y, z) + } + + override def itemBounds() { + parent.setBlockBounds(computeBounds(ForgeDirection.NORTH, ForgeDirection.WEST)) + } + + override def preItemRender() { + GL11.glTranslatef(-0.75f, 0, 0) + GL11.glScalef(1.5f, 1.5f, 1.5f) + } + + private def computeBounds(pitch: ForgeDirection, yaw: ForgeDirection) = { + val (forward, up) = pitch match { + case side@(ForgeDirection.DOWN | ForgeDirection.UP) => (side, yaw) + case _ => (yaw, ForgeDirection.UP) + } + val side = forward.getRotation(up) + val sizes = Array(7f / 16f, 4f / 16f, 7f / 16f) + val x0 = -up.offsetX * sizes(1) - side.offsetX * sizes(2) - forward.offsetX * sizes(0) + val x1 = up.offsetX * sizes(1) + side.offsetX * sizes(2) - forward.offsetX * 0.5f + val y0 = -up.offsetY * sizes(1) - side.offsetY * sizes(2) - forward.offsetY * sizes(0) + val y1 = up.offsetY * sizes(1) + side.offsetY * sizes(2) - forward.offsetY * 0.5f + val z0 = -up.offsetZ * sizes(1) - side.offsetZ * sizes(2) - forward.offsetZ * sizes(0) + val z1 = up.offsetZ * sizes(1) + side.offsetZ * sizes(2) - forward.offsetZ * 0.5f + AxisAlignedBB.getBoundingBox( + math.min(x0, x1) + 0.5f, math.min(y0, y1) + 0.5f, math.min(z0, z1) + 0.5f, + math.max(x0, x1) + 0.5f, math.max(y0, y1) + 0.5f, math.max(z0, z1) + 0.5f) + } + + override def neighborBlockChanged(world: World, x: Int, y: Int, z: Int, block: Block) = + world.getTileEntity(x, y, z) match { + case keyboard: tileentity.Keyboard if canPlaceBlockOnSide(world, x, y, z, keyboard.facing.getOpposite) => // Can stay. + case _ => + parent.dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0) + world.setBlockToAir(x, y, z) + } + + override def rightClick(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = + adjacencyInfo(world, x, y, z) match { + case Some((keyboard, screen, sx, sy, sz, facing)) => screen.rightClick(world, sx, sy, sz, player, facing, 0, 0, 0) + case _ => super.rightClick(world, x, y, z, player, side, hitX, hitY, hitZ) + } + + def adjacentScreen(world: World, x: Int, y: Int, z: Int) = + adjacencyInfo(world, x, y, z) match { + case Some((_, _, sx, sy, sz, _)) => world.getTileEntity(sx, sy, sz) match { + case screen: tileentity.Screen => Some(screen) + case _ => None + } + case _ => None + } + + def adjacencyInfo(world: World, x: Int, y: Int, z: Int) = + world.getTileEntity(x, y, z) match { + case keyboard: tileentity.Keyboard => + val (sx, sy, sz) = ( + x + keyboard.facing.getOpposite.offsetX, + y + keyboard.facing.getOpposite.offsetY, + z + keyboard.facing.getOpposite.offsetZ) + Delegator.subBlock(world, sx, sy, sz) match { + case Some(screen: Screen) => Some((keyboard, screen, sx, sy, sz, keyboard.facing.getOpposite)) + case _ => + // Special case #1: check for screen in front of the keyboard. + val forward = keyboard.facing match { + case ForgeDirection.UP | ForgeDirection.DOWN => keyboard.yaw + case _ => ForgeDirection.UP + } + val (sx, sy, sz) = ( + x + forward.offsetX, + y + forward.offsetY, + z + forward.offsetZ) + Delegator.subBlock(world, sx, sy, sz) match { + case Some(screen: Screen) => Some((keyboard, screen, sx, sy, sz, forward)) + case _ if keyboard.facing != ForgeDirection.UP && keyboard.facing != ForgeDirection.DOWN => + // Special case #2: check for screen below keyboards on walls. + val (sx, sy, sz) = ( + x - forward.offsetX, + y - forward.offsetY, + z - forward.offsetZ) + Delegator.subBlock(world, sx, sy, sz) match { + case Some(screen: Screen) => Some((keyboard, screen, sx, sy, sz, forward.getOpposite)) + case _ => None + } + case _ => None + } + } + case _ => None + } + + override protected val validRotations_ = null +} \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala b/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala new file mode 100644 index 000000000..5b3fb2c52 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala @@ -0,0 +1,112 @@ +package li.cil.oc.common.block + +import cpw.mods.fml.relauncher.{Side, SideOnly} +import java.util +import li.cil.oc.client.renderer.block.BlockRenderer +import li.cil.oc.common.tileentity +import li.cil.oc.Settings +import li.cil.oc.util.ItemCosts +import net.minecraft.block.Block +import net.minecraft.block.material.Material +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.entity.{Entity, EnumCreatureType} +import net.minecraft.item.{EnumRarity, ItemStack} +import net.minecraft.util.Vec3 +import net.minecraft.world.{World, IBlockAccess} +import net.minecraftforge.common.util.ForgeDirection +import org.lwjgl.input + +class SimpleBlock(material: Material) extends Block(material) { + override def getUnlocalizedName = Settings.namespace + super.getUnlocalizedName + + def rarity = EnumRarity.common + + def setFacing(world: World, x: Int, y: Int, z: Int, value: ForgeDirection) = + world.getTileEntity(x, y, z) match { + case rotatable: tileentity.Rotatable => rotatable.setFromFacing(value); true + case _ => false + } + + def setRotationFromEntityPitchAndYaw(world: World, x: Int, y: Int, z: Int, value: Entity) = + world.getTileEntity(x, y, z) match { + case rotatable: tileentity.Rotatable => rotatable.setFromEntityPitchAndYaw(value); true + case _ => false + } + + override def rotateBlock(world: World, x: Int, y: Int, z: Int, axis: ForgeDirection) = + world.getTileEntity(x, y, z) match { + case rotatable: tileentity.Rotatable if rotatable.rotate(axis) => world.markBlockForUpdate(x, y, z); true + case _ => false + } + + @SideOnly(Side.CLIENT) + def tooltipLines(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: java.util.List[String], advanced: Boolean) { + if (input.Keyboard.isKeyDown(input.Keyboard.KEY_LMENU)) { + ItemCosts.addTooltip(stack, tooltip.asInstanceOf[util.List[String]]) + } + } + + @SideOnly(Side.CLIENT) + def preItemRender(metadata: Int) {} + + final override def setBlockBoundsForItemRender() = setBlockBoundsForItemRender(0) + + def setBlockBoundsForItemRender(metadata: Int) = super.setBlockBoundsForItemRender() + + override def getRenderType = BlockRenderer.getRenderId + + override def canBeReplacedByLeaves(world: IBlockAccess, x: Int, y: Int, z: Int) = false + + override def canCreatureSpawn(creature: EnumCreatureType, world: IBlockAccess, x: Int, y: Int, z: Int) = false + + final override def canPlaceBlockOnSide(world: World, x: Int, y: Int, z: Int, side: Int) = + canPlaceBlockOnSide(world, x, y, z, ForgeDirection.getOrientation(side).getOpposite) + + def canPlaceBlockOnSide(world: World, x: Int, y: Int, z: Int, side: ForgeDirection) = + super.canPlaceBlockOnSide(world, x, y, z, side.getOpposite.ordinal) + + final override def canConnectRedstone(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int) = + canConnectRedstone(world, x, y, z, side match { + case -1 => ForgeDirection.UP + case 0 => ForgeDirection.NORTH + case 1 => ForgeDirection.EAST + case 2 => ForgeDirection.SOUTH + case 3 => ForgeDirection.WEST + }) + + def canConnectRedstone(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = false + + final override def isProvidingStrongPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int) = + isProvidingStrongPower(world, x, y, z, ForgeDirection.getOrientation(side).getOpposite) + + def isProvidingStrongPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = + isProvidingWeakPower(world, x, y, z, side) + + final override def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: Int) = + isProvidingWeakPower(world, x, y, z, ForgeDirection.getOrientation(side).getOpposite) + + def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = 0 + + // This function can mess things up badly in single player if not + // synchronized because it sets fields in an instance stored in the + // static block list... which is used by both server and client thread. + // The other place where this is locked is in collisionRayTrace below, + // which seems to be the only built-in function that *logically* depends + // on the state bounds (rest is rendering which is unimportant). + final override def setBlockBoundsBasedOnState(world: IBlockAccess, x: Int, y: Int, z: Int) = + this.synchronized(doSetBlockBoundsBasedOnState(world, x, y, z)) + + protected def doSetBlockBoundsBasedOnState(world: IBlockAccess, x: Int, y: Int, z: Int) = + super.setBlockBoundsBasedOnState(world, x, y, z) + + final override def collisionRayTrace(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3) = + this.synchronized(intersect(world, x, y, z, origin, direction)) + + protected def intersect(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3) = + super.collisionRayTrace(world, x, y, z, origin, direction) + + final override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = + onBlockActivated(world, x, y, z, player, ForgeDirection.getOrientation(side), hitX, hitY, hitZ) + + def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = false +}