From cb7f7821c729cde2b3832a4db5931a5e84fd3a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 21 Nov 2015 19:39:24 +0100 Subject: [PATCH] Added a rack mountable version of the disk drive. --- assets/blocks.psd | Bin 162650 -> 161312 bytes assets/items.psd | Bin 617468 -> 619441 bytes src/main/java/li/cil/oc/api/API.java | 31 +++- .../assets/opencomputers/lang/en_US.lang | 2 + .../opencomputers/recipes/default.recipes | 5 + .../textures/blocks/DiskDriveMountable.png | Bin 0 -> 490 bytes .../blocks/DiskDriveMountableActivity.png | Bin 0 -> 149 bytes .../textures/items/DiskDriveMountable.png | Bin 0 -> 481 bytes src/main/scala/li/cil/oc/Constants.scala | 1 + .../scala/li/cil/oc/client/GuiHandler.scala | 6 +- .../scala/li/cil/oc/client/Textures.scala | 14 +- .../renderer/tileentity/RackRenderer.scala | 6 + .../scala/li/cil/oc/common/GuiHandler.scala | 6 +- src/main/scala/li/cil/oc/common/GuiType.scala | 13 +- .../scala/li/cil/oc/common/block/Rack.scala | 1 + .../li/cil/oc/common/component/Terminal.scala | 92 ---------- .../event/FileSystemAccessHandler.scala | 7 + .../event/RackMountableRenderHandler.scala | 61 ++++++- .../scala/li/cil/oc/common/init/Items.scala | 1 + .../li/cil/oc/common/item/Delegator.scala | 12 +- .../oc/common/item/DiskDriveMountable.scala | 3 + .../li/cil/oc/common/item/FloppyDisk.scala | 4 + .../cil/oc/common/item/traits/Delegate.scala | 2 + .../cil/oc/common/tileentity/DiskDrive.scala | 29 +-- .../traits/ComponentInventory.scala | 4 +- .../DriverDiskDriveMountable.scala | 32 ++++ .../opencomputers/ModOpenComputers.scala | 1 + .../scala/li/cil/oc/server/PacketSender.scala | 6 +- .../server/component/DiskDriveMountable.scala | 172 ++++++++++++++++++ .../li/cil/oc/server/component/Server.scala | 2 +- .../scala/li/cil/oc/util/ExtendedWorld.scala | 2 + 31 files changed, 372 insertions(+), 143 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/textures/blocks/DiskDriveMountable.png create mode 100644 src/main/resources/assets/opencomputers/textures/blocks/DiskDriveMountableActivity.png create mode 100644 src/main/resources/assets/opencomputers/textures/items/DiskDriveMountable.png delete mode 100644 src/main/scala/li/cil/oc/common/component/Terminal.scala create mode 100644 src/main/scala/li/cil/oc/common/item/DiskDriveMountable.scala create mode 100644 src/main/scala/li/cil/oc/integration/opencomputers/DriverDiskDriveMountable.scala create mode 100644 src/main/scala/li/cil/oc/server/component/DiskDriveMountable.scala diff --git a/assets/blocks.psd b/assets/blocks.psd index e495873fbdbfdd5486568bcafe39ecf77994abfe..8d9e9eb2148d13c3495e6979ad55a151ff8cb48f 100644 GIT binary patch delta 4927 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 diff --git a/assets/items.psd b/assets/items.psd index 3605a73bf11ba6d4f2b529815994925b4bddca74..5266573c48c1b0783d8f674b028eadbbf0cedcf6 100644 GIT binary patch delta 7058 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 delta 4578 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 diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index 1d1b03045..c5f8c08e4 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -1,7 +1,13 @@ package li.cil.oc.api; import com.typesafe.config.Config; -import li.cil.oc.api.detail.*; +import li.cil.oc.api.detail.DriverAPI; +import li.cil.oc.api.detail.FileSystemAPI; +import li.cil.oc.api.detail.ItemAPI; +import li.cil.oc.api.detail.MachineAPI; +import li.cil.oc.api.detail.ManualAPI; +import li.cil.oc.api.detail.NanomachinesAPI; +import li.cil.oc.api.detail.NetworkAPI; /** * Central reference for the API. @@ -14,6 +20,24 @@ public class API { public static final String ID_OWNER = "OpenComputers|Core"; public static final String VERSION = "6.0.0-alpha"; + // ----------------------------------------------------------------------- // + + /** + * The loaded config. + */ + public static Config config = null; + + /** + * Whether OpenComputers uses power. + *

+ * This is set in the init phase, so do not rely it before the post-init phase. + */ + public static boolean isPowerEnabled = false; + + // ----------------------------------------------------------------------- // + // Prefer using the static methods in the respective classes in this package + // over accessing these instances directly. + public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; public static ItemAPI items = null; @@ -22,5 +46,8 @@ public class API { public static NanomachinesAPI nanomachines = null; public static NetworkAPI network = null; - public static Config config = null; + // ----------------------------------------------------------------------- // + + private API() { + } } diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index 4c65409d2..8c5f358ce 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -68,6 +68,7 @@ item.oc.DataCard2.name=Data Card (Tier 3) item.oc.DebugCard.name=Debug Card item.oc.Debugger.name=Network Debugger item.oc.Disk.name=Disk Platter +item.oc.DiskDriveMountable.name=Disk Drive item.oc.Drone.name=Drone item.oc.DroneCase0.name=Drone Case (Tier 1) item.oc.DroneCase1.name=Drone Case (Tier 2) @@ -279,6 +280,7 @@ oc:tooltip.Disassembler=Separates items into their original components. §lWarni oc:tooltip.Disk=Primitive medium that can be used to build persistent storage devices. oc:tooltip.DiskDrive.CC=ComputerCraft floppies are §asupported§7. oc:tooltip.DiskDrive=Allows reading and writing floppies. Can be installed in robots to allow inserting floppies later on. +oc:tooltip.DiskDriveMountable=Provides the same functionality as a normal disk drive, but must be installed in a rack. oc:tooltip.DiskUsage=Disk usage: %s/%s Byte oc:tooltip.DiskModeManaged=Mode: Managed oc:tooltip.DiskModeUnmanaged=Mode: Unmanaged diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index 2c2bd6dd6..a66017648 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -83,6 +83,11 @@ tabletCase2 { ["oc:circuitChip2", "oc:materialCircuitBoardPrinted", ingotGold]] } +diskDriveMountable { + input: [[obsidian, "oc:circuitChip1", obsidian] + [fenceIron, "oc:diskDrive", fenceIron] + [obsidian, "oc:materialCircuitBoardPrinted", obsidian]] +} server1 { input: [[obsidian, "oc:ram4", obsidian] ["oc:circuitChip1", "oc:circuitChip2", "oc:circuitChip1"] diff --git a/src/main/resources/assets/opencomputers/textures/blocks/DiskDriveMountable.png b/src/main/resources/assets/opencomputers/textures/blocks/DiskDriveMountable.png new file mode 100644 index 0000000000000000000000000000000000000000..2b40a17a875727253acc763b6cfc3fe290bf7366 GIT binary patch literal 490 zcmVMQBgQaHa18$F+nglH#b&RRx&d(H8nLlIyy2kGDKNI5D*YO zP&-poQ!|2D*8l(j%t=H+RCwAfkcD!?Fbsx&(^^9uJFsv{>)J8%`@h%ZZr=&+q!WTA zz`;n81Da;r->-hQebe+WD+)dz-w$9fNdD8f_{loqydBil)vX;J!xIv1Y;3IjoMdEV6m?WhOiUCN71fNjHO=+)?aeGKER^-sWo2dU zLp}cg|G(z>vX4L)=#>Qd1p~Rn1BRyl;!vQ@&7LlfAr-em&bad(cHm$Q=xEF=yYqO` zz18pQ_dYnO<)KjFB)?3>)9&lVuch%XtqxB4a#cbroYj1rP~zdd%YA<`+IROJIG=M@ zX4_1^e~w`yTlVhjo>XDk94#)Jx_pz)Nw*c!O0#BrD6t5>FJ=?LQzhTWD|=`+vi z19Aerh7Z~}ww`6wpX->gJIJH?^8Y@8B5lDLq9%-cxCPf-Ww{dbU#g6&dv?dXo!^W2 gx+VW*{o*oU_#4iz&D*%~2hjNpp00i_>zopr0JR*;Z~y=R literal 0 HcmV?d00001 diff --git a/src/main/scala/li/cil/oc/Constants.scala b/src/main/scala/li/cil/oc/Constants.scala index abba42b11..29dbb654e 100644 --- a/src/main/scala/li/cil/oc/Constants.scala +++ b/src/main/scala/li/cil/oc/Constants.scala @@ -88,6 +88,7 @@ object Constants { final val DebugCard = "debugCard" final val Debugger = "debugger" final val Disk = "disk" + final val DiskDriveMountable = "diskDriveMountable" final val Drone = "drone" final val DroneCaseCreative = "droneCaseCreative" final val DroneCaseTier1 = "droneCase1" diff --git a/src/main/scala/li/cil/oc/client/GuiHandler.scala b/src/main/scala/li/cil/oc/client/GuiHandler.scala index 1ac2420ec..9d2b2a162 100644 --- a/src/main/scala/li/cil/oc/client/GuiHandler.scala +++ b/src/main/scala/li/cil/oc/client/GuiHandler.scala @@ -21,7 +21,7 @@ object GuiHandler extends CommonGuiHandler { override def getClientGuiElement(id: Int, player: EntityPlayer, world: World, x: Int, y: Int, z: Int): AnyRef = { GuiType.Categories.get(id) match { case Some(GuiType.Category.Block) => - world.getTileEntity(x, y, z) match { + world.getTileEntity(x, GuiType.extractY(y), z) match { case t: tileentity.Adapter if id == GuiType.Adapter.id => new gui.Adapter(player.inventory, t) case t: tileentity.Assembler if id == GuiType.Assembler.id => @@ -46,8 +46,8 @@ object GuiHandler extends CommonGuiHandler { new gui.Robot(player.inventory, t.robot) case t: tileentity.Screen if id == GuiType.Screen.id => new gui.Screen(t.origin.buffer, t.tier > 0, () => t.origin.hasKeyboard, () => t.origin.buffer.isRenderingEnabled) - case t: tileentity.Rack if GuiType.ServerInRack.exists(e => e.id == id) => - val slot = GuiType.ServerInRack.indexWhere(e => e.id == id) + case t: tileentity.Rack if id == GuiType.ServerInRack.id => + val slot = GuiType.extractSlot(y) new gui.Server(player.inventory, new ServerInventory { override def container = t.getStackInSlot(slot) diff --git a/src/main/scala/li/cil/oc/client/Textures.scala b/src/main/scala/li/cil/oc/client/Textures.scala index d826a9c6a..20f871315 100644 --- a/src/main/scala/li/cil/oc/client/Textures.scala +++ b/src/main/scala/li/cil/oc/client/Textures.scala @@ -59,11 +59,12 @@ object Textures { val blockRaidFrontActivity = new ResourceLocation(Settings.resourceDomain, "textures/blocks/RaidFrontActivity.png") val blockRobot = new ResourceLocation(Settings.resourceDomain, "textures/blocks/robot.png") val blockScreenUpIndicator = new ResourceLocation(Settings.resourceDomain, "textures/blocks/screen/up_indicator.png") - val blockServerFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/ServerFrontOn.png") - val blockServerFrontError = new ResourceLocation(Settings.resourceDomain, "textures/blocks/ServerFrontError.png") - val blockServerFrontActivity = new ResourceLocation(Settings.resourceDomain, "textures/blocks/ServerFrontActivity.png") - val blockTerminalServerFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/TerminalServerFrontOn.png") - val blockTerminalServerFrontPresence = new ResourceLocation(Settings.resourceDomain, "textures/blocks/TerminalServerFrontPresence.png") + val blockRackDiskDriveActivity = new ResourceLocation(Settings.resourceDomain, "textures/blocks/DiskDriveMountableActivity.png") + val blockRackServerOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/ServerFrontOn.png") + val blockRackServerError = new ResourceLocation(Settings.resourceDomain, "textures/blocks/ServerFrontError.png") + val blockRackServerActivity = new ResourceLocation(Settings.resourceDomain, "textures/blocks/ServerFrontActivity.png") + val blockRackTerminalServerOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/TerminalServerFrontOn.png") + val blockRackTerminalServerPresence = new ResourceLocation(Settings.resourceDomain, "textures/blocks/TerminalServerFrontPresence.png") val upgradeCrafting = new ResourceLocation(Settings.resourceDomain, "textures/model/UpgradeCrafting.png") val upgradeGenerator = new ResourceLocation(Settings.resourceDomain, "textures/model/UpgradeGenerator.png") @@ -97,6 +98,7 @@ object Textures { object Rack { val icons = Array.fill[IIcon](6)(null) + var diskDrive: IIcon = _ var server: IIcon = _ var terminal: IIcon = _ } @@ -146,7 +148,7 @@ object Textures { tm.bindTexture(blockHologram) tm.bindTexture(blockMicrocontrollerFrontLight) tm.bindTexture(blockMicrocontrollerFrontOn) - tm.bindTexture(blockServerFrontOn) + tm.bindTexture(blockRackServerOn) tm.bindTexture(blockRobot) tm.bindTexture(blockScreenUpIndicator) diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/RackRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/RackRenderer.scala index 372f680a8..d4fe7b3cf 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/RackRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/RackRenderer.scala @@ -36,10 +36,16 @@ object RackRenderer extends TileEntitySpecialRenderer { // Note: we manually sync the rack inventory for this to work. for (i <- 0 until rack.getSizeInventory) { if (rack.getStackInSlot(i) != null) { + GL11.glPushMatrix() + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + val v0 = vOffset + i * vSize val v1 = vOffset + (i + 1) * vSize val event = new RackMountableRenderEvent.TileEntity(rack, i, rack.lastData(i), v0, v1) MinecraftForge.EVENT_BUS.post(event) + + GL11.glPopAttrib() + GL11.glPopMatrix() } } diff --git a/src/main/scala/li/cil/oc/common/GuiHandler.scala b/src/main/scala/li/cil/oc/common/GuiHandler.scala index 2f9e39acd..80bbf946d 100644 --- a/src/main/scala/li/cil/oc/common/GuiHandler.scala +++ b/src/main/scala/li/cil/oc/common/GuiHandler.scala @@ -12,7 +12,7 @@ abstract class GuiHandler extends IGuiHandler { override def getServerGuiElement(id: Int, player: EntityPlayer, world: World, x: Int, y: Int, z: Int): AnyRef = { GuiType.Categories.get(id) match { case Some(GuiType.Category.Block) => - world.getTileEntity(x, y, z) match { + world.getTileEntity(x, GuiType.extractY(y), z) match { case t: tileentity.Adapter if id == GuiType.Adapter.id => new container.Adapter(player.inventory, t) case t: tileentity.Assembler if id == GuiType.Assembler.id => @@ -35,8 +35,8 @@ abstract class GuiHandler extends IGuiHandler { new container.Robot(player.inventory, t.robot) case t: tileentity.Rack if id == GuiType.Rack.id => new container.Rack(player.inventory, t) - case t: tileentity.Rack if GuiType.ServerInRack.exists(e => e.id == id) => - val slot = GuiType.ServerInRack.indexWhere(e => e.id == id) + case t: tileentity.Rack if id == GuiType.ServerInRack.id => + val slot = GuiType.extractSlot(y) val server = t.getMountable(slot).asInstanceOf[Server] new container.Server(player.inventory, server, Option(server)) case t: tileentity.Switch if id == GuiType.Switch.id => diff --git a/src/main/scala/li/cil/oc/common/GuiType.scala b/src/main/scala/li/cil/oc/common/GuiType.scala index 2c1c2f84d..910e0f6a5 100644 --- a/src/main/scala/li/cil/oc/common/GuiType.scala +++ b/src/main/scala/li/cil/oc/common/GuiType.scala @@ -30,12 +30,7 @@ object GuiType extends ScalaEnum { val Robot = new EnumVal { def name = "Robot"; def subType = GuiType.Category.Block } val Screen = new EnumVal { def name = "Screen"; def subType = GuiType.Category.Block } val Server = new EnumVal { def name = "Server"; def subType = GuiType.Category.Item } - val ServerInRack = Array( - new EnumVal { val slot = 0; def name = "ServerInRack"; def subType = GuiType.Category.Block }, - new EnumVal { val slot = 1; def name = "ServerInRack"; def subType = GuiType.Category.Block }, - new EnumVal { val slot = 2; def name = "ServerInRack"; def subType = GuiType.Category.Block }, - new EnumVal { val slot = 3; def name = "ServerInRack"; def subType = GuiType.Category.Block } - ) + val ServerInRack = new EnumVal { def name = "ServerInRack"; def subType = GuiType.Category.Block } val Switch = new EnumVal { def name = "Switch"; def subType = GuiType.Category.Block } val Tablet = new EnumVal { def name = "Tablet"; def subType = GuiType.Category.Item } val TabletInner = new EnumVal { def name = "TabletInner"; def subType = GuiType.Category.Item } @@ -50,4 +45,10 @@ object GuiType extends ScalaEnum { val Entity = new EnumVal { def name = "Entity" } val Item = new EnumVal { def name = "Item" } } + + def embedSlot(y: Int, slot: Int) = (y & 0x00FFFFFF) | (slot << 6) + + def extractY(value: Int) = value & 0x00FFFFFF + + def extractSlot(value: Int) = (value >>> 6) & 0xFF } diff --git a/src/main/scala/li/cil/oc/common/block/Rack.scala b/src/main/scala/li/cil/oc/common/block/Rack.scala index 43fd82c24..113739d50 100644 --- a/src/main/scala/li/cil/oc/common/block/Rack.scala +++ b/src/main/scala/li/cil/oc/common/block/Rack.scala @@ -29,6 +29,7 @@ class Rack extends RedstoneAware with traits.SpecialBlock with traits.PowerAccep override def registerBlockIcons(iconRegister: IIconRegister) = { super.registerBlockIcons(iconRegister) System.arraycopy(icons, 0, Textures.Rack.icons, 0, icons.length) + Textures.Rack.diskDrive = iconRegister.registerIcon(Settings.resourceDomain + ":" + "DiskDriveMountable") Textures.Rack.server = iconRegister.registerIcon(Settings.resourceDomain + ":" + "ServerFront") Textures.Rack.terminal = iconRegister.registerIcon(Settings.resourceDomain + ":" + "TerminalServerFront") } diff --git a/src/main/scala/li/cil/oc/common/component/Terminal.scala b/src/main/scala/li/cil/oc/common/component/Terminal.scala deleted file mode 100644 index 8201fa408..000000000 --- a/src/main/scala/li/cil/oc/common/component/Terminal.scala +++ /dev/null @@ -1,92 +0,0 @@ -package li.cil.oc.common.component - -import cpw.mods.fml.relauncher.Side -import cpw.mods.fml.relauncher.SideOnly -import li.cil.oc.Constants -import li.cil.oc.Settings -import li.cil.oc.api -import li.cil.oc.api.internal.Keyboard.UsabilityChecker -import li.cil.oc.api.network.Component -import li.cil.oc.api.network.Node -import li.cil.oc.api.network.Visibility -import li.cil.oc.common.Tier -import li.cil.oc.common.item -import li.cil.oc.common.item.Delegator -import li.cil.oc.common.tileentity -import li.cil.oc.util.ExtendedNBT._ -import net.minecraft.entity.player.EntityPlayer -import net.minecraft.nbt.NBTTagCompound -import net.minecraft.nbt.NBTTagString -import net.minecraftforge.common.util.Constants.NBT - -import scala.collection.mutable - -//class Terminal(val rack: tileentity.Rack, val number: Int) { -// val buffer = { -// val screenItem = api.Items.get(Constants.BlockName.ScreenTier1).createItemStack(1) -// val buffer = api.Driver.driverFor(screenItem, rack.getClass).createEnvironment(screenItem, rack).asInstanceOf[api.component.TextBuffer] -// val (maxWidth, maxHeight) = Settings.screenResolutionsByTier(Tier.Three) -// buffer.setMaximumResolution(maxWidth, maxHeight) -// buffer.setMaximumColorDepth(Settings.screenDepthsByTier(Tier.Three)) -// buffer -// } -// -// val keyboard = { -// val keyboardItem = api.Items.get(Constants.BlockName.Keyboard).createItemStack(1) -// val keyboard = api.Driver.driverFor(keyboardItem, rack.getClass).createEnvironment(keyboardItem, rack).asInstanceOf[api.component.Keyboard] -// keyboard.setUsableOverride(new UsabilityChecker { -// override def isUsableByPlayer(keyboard: api.component.Keyboard, player: EntityPlayer) = { -// val stack = player.getHeldItem -// Delegator.subItem(stack) match { -// case Some(t: item.Terminal) if stack.hasTagCompound => keys.contains(stack.getTagCompound.getString(Settings.namespace + "key")) -// case _ => false -// } -// } -// }) -// keyboard -// } -// -// if (buffer.node != null) { -// buffer.node.asInstanceOf[Component].setVisibility(Visibility.Neighbors) -// keyboard.node.asInstanceOf[Component].setVisibility(Visibility.Neighbors) -// } -// -// val keys = mutable.ListBuffer.empty[String] -// -// def connect(node: Node) { -// if (keys.size > 0) { -// node.connect(buffer.node) -// node.connect(keyboard.node) -// buffer.node.connect(keyboard.node) -// } -// } -// -// // ----------------------------------------------------------------------- // -// -// def load(nbt: NBTTagCompound) { -// buffer.load(nbt.getCompoundTag(Settings.namespace + "buffer")) -// keyboard.load(nbt.getCompoundTag(Settings.namespace + "keyboard")) -// // Compatibility for previous dev versions where there was only one term. -// if (nbt.hasKey(Settings.namespace + "key")) { -// keys += nbt.getString(Settings.namespace + "key") -// } -// nbt.getTagList(Settings.namespace + "keys", NBT.TAG_STRING).foreach((tag: NBTTagString) => keys += tag.func_150285_a_()) -// } -// -// def save(nbt: NBTTagCompound) { -// nbt.setNewCompoundTag(Settings.namespace + "buffer", buffer.save) -// nbt.setNewCompoundTag(Settings.namespace + "keyboard", keyboard.save) -// nbt.setNewTagList(Settings.namespace + "keys", keys) -// } -// -// @SideOnly(Side.CLIENT) -// def readFromNBTForClient(nbt: NBTTagCompound) { -// buffer.load(nbt) -// nbt.getTagList("keys", NBT.TAG_STRING).foreach((tag: NBTTagString) => keys += tag.func_150285_a_()) -// } -// -// def writeToNBTForClient(nbt: NBTTagCompound) { -// buffer.save(nbt) -// nbt.setNewTagList("keys", keys) -// } -//} diff --git a/src/main/scala/li/cil/oc/common/event/FileSystemAccessHandler.scala b/src/main/scala/li/cil/oc/common/event/FileSystemAccessHandler.scala index 733954c8a..c065ba41e 100644 --- a/src/main/scala/li/cil/oc/common/event/FileSystemAccessHandler.scala +++ b/src/main/scala/li/cil/oc/common/event/FileSystemAccessHandler.scala @@ -7,6 +7,7 @@ import li.cil.oc.api.internal.Rack import li.cil.oc.common.tileentity.Case import li.cil.oc.common.tileentity.DiskDrive import li.cil.oc.common.tileentity.Raid +import li.cil.oc.server.component.DiskDriveMountable import li.cil.oc.server.component.Server object FileSystemAccessHandler { @@ -22,6 +23,12 @@ object FileSystemAccessHandler { server.lastAccess = System.currentTimeMillis() t.markChanged(slot) } + case diskDrive: DiskDriveMountable => + val containsNode = diskDrive.filesystemNode.contains(e.getNode) + if (containsNode) { + diskDrive.lastAccess = System.currentTimeMillis() + t.markChanged(slot) + } case _ => } } diff --git a/src/main/scala/li/cil/oc/common/event/RackMountableRenderHandler.scala b/src/main/scala/li/cil/oc/common/event/RackMountableRenderHandler.scala index b6f531674..f525a42fd 100644 --- a/src/main/scala/li/cil/oc/common/event/RackMountableRenderHandler.scala +++ b/src/main/scala/li/cil/oc/common/event/RackMountableRenderHandler.scala @@ -6,10 +6,20 @@ import li.cil.oc.api import li.cil.oc.api.event.RackMountableRenderEvent import li.cil.oc.client.Textures import li.cil.oc.client.renderer.tileentity.RenderUtil +import li.cil.oc.util.BlockPosition +import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.RenderState +import net.minecraft.client.renderer.OpenGlHelper +import net.minecraft.client.renderer.entity.RenderItem +import net.minecraft.client.renderer.entity.RenderManager +import net.minecraft.entity.item.EntityItem +import net.minecraft.item.ItemStack import net.minecraftforge.common.util.Constants.NBT +import org.lwjgl.opengl.GL11 object RackMountableRenderHandler { + lazy val DiskDriveMountable = api.Items.get(Constants.ItemName.DiskDriveMountable) + lazy val Servers = Array( api.Items.get(Constants.ItemName.ServerTier1), api.Items.get(Constants.ItemName.ServerTier2), @@ -21,19 +31,52 @@ object RackMountableRenderHandler { @SubscribeEvent def onRackMountableRendering(e: RackMountableRenderEvent.TileEntity): Unit = { - if (e.data != null && Servers.contains(api.Items.get(e.rack.getStackInSlot(e.mountable)))) { + if (e.data != null && DiskDriveMountable == api.Items.get(e.rack.getStackInSlot(e.mountable))) { + // Disk drive. + + if (e.data.hasKey("disk")) { + val stack = ItemStack.loadItemStackFromNBT(e.data.getCompoundTag("disk")) + if (stack != null) { + GL11.glPushMatrix() + GL11.glScalef(1, -1, 1) + GL11.glTranslatef(10 / 16f, -(3.5f + e.mountable * 3f) / 16f, 1 / 16f) + GL11.glRotatef(90, -1, 0, 0) + + val brightness = e.rack.world.getLightBrightnessForSkyBlocks(BlockPosition(e.rack).offset(e.rack.facing), 0) + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, brightness % 65536, brightness / 65536) + + // This is very 'meh', but item frames do it like this, too! + val entity = new EntityItem(e.rack.world, 0, 0, 0, stack) + entity.hoverStart = 0 + RenderItem.renderInFrame = true + RenderManager.instance.renderEntityWithPosYaw(entity, 0, 0, 0, 0, 0) + RenderItem.renderInFrame = false + GL11.glPopMatrix() + } + } + + if (System.currentTimeMillis() - e.data.getLong("lastAccess") < 400 && e.rack.world.rand.nextDouble() > 0.1) { + RenderState.disableLighting() + RenderState.makeItBlend() + + e.renderOverlay(Textures.blockRackDiskDriveActivity) + + RenderState.enableLighting() + } + } + else if (e.data != null && Servers.contains(api.Items.get(e.rack.getStackInSlot(e.mountable)))) { // Server. RenderState.disableLighting() RenderState.makeItBlend() if (e.data.getBoolean("isRunning")) { - e.renderOverlay(Textures.blockServerFrontOn) + e.renderOverlay(Textures.blockRackServerOn) } if (e.data.getBoolean("hasErrored") && RenderUtil.shouldShowErrorLight(e.rack.hashCode * (e.mountable + 1))) { - e.renderOverlay(Textures.blockServerFrontError) + e.renderOverlay(Textures.blockRackServerError) } if (System.currentTimeMillis() - e.data.getLong("lastAccess") < 400 && e.rack.world.rand.nextDouble() > 0.1) { - e.renderOverlay(Textures.blockServerFrontActivity) + e.renderOverlay(Textures.blockRackServerActivity) } RenderState.enableLighting() @@ -43,13 +86,13 @@ object RackMountableRenderHandler { RenderState.disableLighting() RenderState.makeItBlend() - e.renderOverlay(Textures.blockTerminalServerFrontOn) + e.renderOverlay(Textures.blockRackTerminalServerOn) val countConnected = e.data.getTagList("keys", NBT.TAG_STRING).tagCount() if (countConnected > 0) { val u0 = 7 / 16f val u1 = u0 + (2 * countConnected - 1) / 16f - e.renderOverlay(Textures.blockTerminalServerFrontPresence, u0, u1) + e.renderOverlay(Textures.blockRackTerminalServerPresence, u0, u1) } RenderState.enableLighting() @@ -58,7 +101,11 @@ object RackMountableRenderHandler { @SubscribeEvent def onRackMountableRendering(e: RackMountableRenderEvent.Block): Unit = { - if (Servers.contains(api.Items.get(e.rack.getStackInSlot(e.mountable)))) { + if (DiskDriveMountable == api.Items.get(e.rack.getStackInSlot(e.mountable))) { + // Disk drive. + e.setFrontTextureOverride(Textures.Rack.diskDrive) + } + else if (Servers.contains(api.Items.get(e.rack.getStackInSlot(e.mountable)))) { // Server. e.setFrontTextureOverride(Textures.Rack.server) } diff --git a/src/main/scala/li/cil/oc/common/init/Items.scala b/src/main/scala/li/cil/oc/common/init/Items.scala index 86adeb4d2..f8c7b60ee 100644 --- a/src/main/scala/li/cil/oc/common/init/Items.scala +++ b/src/main/scala/li/cil/oc/common/init/Items.scala @@ -531,6 +531,7 @@ object Items extends ItemAPI { // 1.6.0 Recipes.addSubItem(new item.TerminalServer(multi), Constants.ItemName.TerminalServer, "oc:terminalServer") + Recipes.addSubItem(new item.DiskDriveMountable(multi), Constants.ItemName.DiskDriveMountable, "oc:diskDriveMountable") // Register aliases. for ((k, v) <- aliases) { diff --git a/src/main/scala/li/cil/oc/common/item/Delegator.scala b/src/main/scala/li/cil/oc/common/item/Delegator.scala index 879d9b243..d827c04af 100644 --- a/src/main/scala/li/cil/oc/common/item/Delegator.scala +++ b/src/main/scala/li/cil/oc/common/item/Delegator.scala @@ -13,7 +13,6 @@ import li.cil.oc.api.driver.item.Chargeable import li.cil.oc.api.event.RobotRenderEvent.MountPoint import li.cil.oc.api.internal.Robot import li.cil.oc.client.renderer.item.UpgradeRenderer -import li.cil.oc.common.tileentity import li.cil.oc.util.BlockPosition import net.minecraft.client.renderer.texture.IIconRegister import net.minecraft.creativetab.CreativeTabs @@ -123,14 +122,13 @@ class Delegator extends Item with driver.item.UpgradeRenderer with Chargeable { override def getChestGenBase(chest: ChestGenHooks, rnd: Random, original: WeightedRandomChestContent) = original - override def doesSneakBypassUse(world: World, x: Int, y: Int, z: Int, player: EntityPlayer) = { - world.getTileEntity(x, y, z) match { - case drive: tileentity.DiskDrive => true + // ----------------------------------------------------------------------- // + + override def doesSneakBypassUse(world: World, x: Int, y: Int, z: Int, player: EntityPlayer) = + Delegator.subItem(player.getHeldItem) match { + case Some(subItem) => subItem.doesSneakBypassUse(BlockPosition(x, y, z, world), player) case _ => super.doesSneakBypassUse(world, x, y, z, player) } - } - - // ----------------------------------------------------------------------- // override def onItemUseFirst(stack: ItemStack, player: EntityPlayer, world: World, x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = Delegator.subItem(stack) match { diff --git a/src/main/scala/li/cil/oc/common/item/DiskDriveMountable.scala b/src/main/scala/li/cil/oc/common/item/DiskDriveMountable.scala new file mode 100644 index 000000000..9debd5678 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/DiskDriveMountable.scala @@ -0,0 +1,3 @@ +package li.cil.oc.common.item + +class DiskDriveMountable(val parent: Delegator) extends traits.Delegate diff --git a/src/main/scala/li/cil/oc/common/item/FloppyDisk.scala b/src/main/scala/li/cil/oc/common/item/FloppyDisk.scala index 5712678f9..b60324e7f 100644 --- a/src/main/scala/li/cil/oc/common/item/FloppyDisk.scala +++ b/src/main/scala/li/cil/oc/common/item/FloppyDisk.scala @@ -3,7 +3,9 @@ package li.cil.oc.common.item import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.Settings +import li.cil.oc.util.BlockPosition import li.cil.oc.util.Color +import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack class FloppyDisk(val parent: Delegator) extends traits.Delegate with traits.FileSystemLike { @@ -28,4 +30,6 @@ class FloppyDisk(val parent: Delegator) extends traits.Delegate with traits.File icons(index) = iconRegister.registerIcon(baseTextureName + color) } } + + override def doesSneakBypassUse(position: BlockPosition, player: EntityPlayer): Boolean = true } diff --git a/src/main/scala/li/cil/oc/common/item/traits/Delegate.scala b/src/main/scala/li/cil/oc/common/item/traits/Delegate.scala index 8d0c8b9ee..b2c0a228b 100644 --- a/src/main/scala/li/cil/oc/common/item/traits/Delegate.scala +++ b/src/main/scala/li/cil/oc/common/item/traits/Delegate.scala @@ -43,6 +43,8 @@ trait Delegate { // ----------------------------------------------------------------------- // + def doesSneakBypassUse(position: BlockPosition, player: EntityPlayer) = false + def onItemUseFirst(stack: ItemStack, player: EntityPlayer, position: BlockPosition, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = false def onItemUse(stack: ItemStack, player: EntityPlayer, position: BlockPosition, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = false diff --git a/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala b/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala index b991c0629..ec39d43d2 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala @@ -21,10 +21,6 @@ import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound class DiskDrive extends traits.Environment with traits.ComponentInventory with traits.Rotatable with Analyzable { - val node = api.Network.newNode(this, Visibility.Network). - withComponent("disk_drive"). - create() - // Used on client side to check whether to render disk activity indicators. var lastAccess = 0L @@ -34,6 +30,11 @@ class DiskDrive extends traits.Environment with traits.ComponentInventory with t } // ----------------------------------------------------------------------- // + // Environment + + val node = api.Network.newNode(this, Visibility.Network). + withComponent("disk_drive"). + create() @Callback(doc = """function():boolean -- Checks whether some medium is currently in the drive.""") def isEmpty(context: Context, args: Arguments): Array[AnyRef] = { @@ -58,12 +59,12 @@ class DiskDrive extends traits.Environment with traits.ComponentInventory with t } // ----------------------------------------------------------------------- // + // Analyzable override def onAnalyze(player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = filesystemNode.fold(null: Array[Node])(Array(_)) - override def canUpdate = false - // ----------------------------------------------------------------------- // + // IInventory override def getSizeInventory = 1 @@ -72,6 +73,9 @@ class DiskDrive extends traits.Environment with traits.ComponentInventory with t case _ => false } + // ----------------------------------------------------------------------- // + // ComponentInventory + override protected def onItemAdded(slot: Int, stack: ItemStack) { super.onItemAdded(slot, stack) components(slot) match { @@ -95,20 +99,23 @@ class DiskDrive extends traits.Environment with traits.ComponentInventory with t } // ----------------------------------------------------------------------- // + // TileEntity + + override def canUpdate = false @SideOnly(Side.CLIENT) override def readFromNBTForClient(nbt: NBTTagCompound) { super.readFromNBTForClient(nbt) - items(0) match { - case Some(stack) => nbt.setNewCompoundTag("disk", stack.writeToNBT) - case _ => + if (nbt.hasKey("disk")) { + setInventorySlotContents(0, ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("disk"))) } } override def writeToNBTForClient(nbt: NBTTagCompound) { super.writeToNBTForClient(nbt) - if (nbt.hasKey("disk")) { - setInventorySlotContents(0, ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("disk"))) + items(0) match { + case Some(stack) => nbt.setNewCompoundTag("disk", stack.writeToNBT) + case _ => } } } diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/ComponentInventory.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/ComponentInventory.scala index 371852e28..cf63c1729 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/ComponentInventory.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/ComponentInventory.scala @@ -21,8 +21,8 @@ trait ComponentInventory extends Environment with Inventory with inventory.Compo // Cache changes to inventory slots on the client side to avoid recreating // components when we don't have to and the slots are just cleared by MC // temporarily. - private val pendingRemovalsActual = mutable.ArrayBuffer.fill(getSizeInventory)(None: Option[ItemStack]) - private val pendingAddsActual = mutable.ArrayBuffer.fill(getSizeInventory)(None: Option[ItemStack]) + private lazy val pendingRemovalsActual = mutable.ArrayBuffer.fill(getSizeInventory)(None: Option[ItemStack]) + private lazy val pendingAddsActual = mutable.ArrayBuffer.fill(getSizeInventory)(None: Option[ItemStack]) private var updateScheduled = false def pendingRemovals = { adjustSize(pendingRemovalsActual) diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverDiskDriveMountable.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverDiskDriveMountable.scala new file mode 100644 index 000000000..893eff1d9 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverDiskDriveMountable.scala @@ -0,0 +1,32 @@ +package li.cil.oc.integration.opencomputers + +import li.cil.oc.Constants +import li.cil.oc.api +import li.cil.oc.api.driver.item.HostAware +import li.cil.oc.api.network.EnvironmentHost +import li.cil.oc.api.network.ManagedEnvironment +import li.cil.oc.common.Slot +import li.cil.oc.common.tileentity +import li.cil.oc.server.component +import li.cil.oc.util.ExtendedInventory._ +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound + +object DriverDiskDriveMountable extends Item with HostAware { + override def worksWith(stack: ItemStack): Boolean = isOneOf(stack, + api.Items.get(Constants.ItemName.DiskDriveMountable)) + + override def createEnvironment(stack: ItemStack, host: EnvironmentHost): ManagedEnvironment = host match { + case rack: tileentity.Rack => new component.DiskDriveMountable(rack, rack.indexOf(stack)) + case _ => null // Welp. + } + + override def slot(stack: ItemStack): String = Slot.RackMountable + + override def dataTag(stack: ItemStack): NBTTagCompound = { + if (!stack.hasTagCompound) { + stack.setTagCompound(new NBTTagCompound()) + } + stack.getTagCompound + } +} diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala index 481afb93e..3bcd22ace 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala @@ -125,6 +125,7 @@ object ModOpenComputers extends ModProxy { api.Driver.add(DriverScreen) api.Driver.add(DriverTransposer) + api.Driver.add(DriverDiskDriveMountable) api.Driver.add(DriverServer) api.Driver.add(DriverTerminalServer) diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index 732504ebd..bf9a8e664 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -100,10 +100,10 @@ object PacketSender { } // Avoid spamming the network with disk activity notices. - val fileSystemAccessTimeouts = mutable.WeakHashMap.empty[EnvironmentHost, mutable.Map[String, Long]] + val fileSystemAccessTimeouts = mutable.WeakHashMap.empty[Node, mutable.Map[String, Long]] def sendFileSystemActivity(node: Node, host: EnvironmentHost, name: String) = fileSystemAccessTimeouts.synchronized { - fileSystemAccessTimeouts.get(host) match { + fileSystemAccessTimeouts.get(node) match { case Some(hostTimeouts) if hostTimeouts.getOrElse(name, 0L) > System.currentTimeMillis() => // Cooldown. case _ => val event = host match { @@ -112,7 +112,7 @@ object PacketSender { } MinecraftForge.EVENT_BUS.post(event) if (!event.isCanceled) { - fileSystemAccessTimeouts.getOrElseUpdate(host, mutable.Map.empty) += name -> (System.currentTimeMillis() + 500) + fileSystemAccessTimeouts.getOrElseUpdate(node, mutable.Map.empty) += name -> (System.currentTimeMillis() + 500) val pb = new SimplePacketBuilder(PacketType.FileSystemActivity) diff --git a/src/main/scala/li/cil/oc/server/component/DiskDriveMountable.scala b/src/main/scala/li/cil/oc/server/component/DiskDriveMountable.scala new file mode 100644 index 000000000..09cf3d677 --- /dev/null +++ b/src/main/scala/li/cil/oc/server/component/DiskDriveMountable.scala @@ -0,0 +1,172 @@ +package li.cil.oc.server.component + +import java.util + +import li.cil.oc.api +import li.cil.oc.api.Driver +import li.cil.oc.api.component.RackBusConnectable +import li.cil.oc.api.component.RackMountable +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.Analyzable +import li.cil.oc.api.network.Component +import li.cil.oc.api.network.EnvironmentHost +import li.cil.oc.api.network.Node +import li.cil.oc.api.network.Visibility +import li.cil.oc.api.prefab +import li.cil.oc.common.Slot +import li.cil.oc.common.Sound +import li.cil.oc.common.inventory.ComponentInventory +import li.cil.oc.common.inventory.ItemStackInventory +import li.cil.oc.common.tileentity +import li.cil.oc.util.ExtendedNBT._ +import li.cil.oc.util.InventoryUtils +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.util.ForgeDirection + +class DiskDriveMountable(val rack: tileentity.Rack, val slot: Int) extends prefab.ManagedEnvironment with ItemStackInventory with ComponentInventory with RackMountable with Analyzable { + // Stored for filling data packet when queried. + var lastAccess = 0L + + def filesystemNode = components(0) match { + case Some(environment) => Option(environment.node) + case _ => None + } + + // ----------------------------------------------------------------------- // + // Environment + + override val node = api.Network.newNode(this, Visibility.Network). + withComponent("disk_drive"). + create() + + @Callback(doc = """function():boolean -- Checks whether some medium is currently in the drive.""") + def isEmpty(context: Context, args: Arguments): Array[AnyRef] = { + result(filesystemNode.isEmpty) + } + + @Callback(doc = """function([velocity:number]):boolean -- Eject the currently present medium from the drive.""") + def eject(context: Context, args: Arguments): Array[AnyRef] = { + val velocity = args.optDouble(0, 0) max 0 min 1 + val ejected = decrStackSize(0, 1) + if (ejected != null && ejected.stackSize > 0) { + val entity = InventoryUtils.spawnStackInWorld(rack.position, ejected, Option(rack.facing)) + if (entity != null) { + val vx = rack.facing.offsetX * velocity + val vy = rack.facing.offsetY * velocity + val vz = rack.facing.offsetZ * velocity + entity.addVelocity(vx, vy, vz) + } + result(true) + } + else result(false) + } + + // ----------------------------------------------------------------------- // + // Analyzable + + override def onAnalyze(player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = filesystemNode.fold(null: Array[Node])(Array(_)) + + // ----------------------------------------------------------------------- // + // ItemStackInventory + + override def host: EnvironmentHost = rack + + // ----------------------------------------------------------------------- // + // IInventory + + override def getSizeInventory: Int = 1 + + override def isItemValidForSlot(slot: Int, stack: ItemStack): Boolean = (slot, Option(Driver.driverFor(stack))) match { + case (0, Some(driver)) => driver.slot(stack) == Slot.Floppy + case _ => false + } + + override def isUseableByPlayer(player: EntityPlayer): Boolean = rack.isUseableByPlayer(player) + + // ----------------------------------------------------------------------- // + // ComponentInventory + + override def container: ItemStack = rack.getStackInSlot(slot) + + override protected def onItemAdded(slot: Int, stack: ItemStack) { + super.onItemAdded(slot, stack) + components(slot) match { + case Some(environment) => environment.node match { + case component: Component => component.setVisibility(Visibility.Network) + } + case _ => + } + Sound.playDiskInsert(rack) + if (rack.isServer) { + rack.markChanged(this.slot) + } + } + + override protected def onItemRemoved(slot: Int, stack: ItemStack) { + super.onItemRemoved(slot, stack) + Sound.playDiskEject(rack) + if (rack.isServer) { + rack.markChanged(this.slot) + } + } + + // ----------------------------------------------------------------------- // + // ManagedEnvironment + + override def canUpdate: Boolean = false + + // ----------------------------------------------------------------------- // + // Persistable + + override def load(nbt: NBTTagCompound) { + super[ManagedEnvironment].load(nbt) + super[ComponentInventory].load(nbt) + connectComponents() + } + + override def save(nbt: NBTTagCompound) { + super[ManagedEnvironment].save(nbt) + super[ComponentInventory].save(nbt) + } + + // ----------------------------------------------------------------------- // + // RackMountable + + override def getData: NBTTagCompound = { + val nbt = new NBTTagCompound() + nbt.setLong("lastAccess", lastAccess) + nbt.setTag("disk", toNbt(getStackInSlot(0))) + nbt + } + + override def getConnectableCount: Int = 0 + + override def getConnectableAt(index: Int): RackBusConnectable = null + + override def onActivate(player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float): Boolean = { + if (player.isSneaking) { + val isDiskInDrive = getStackInSlot(0) != null + val isHoldingDisk = isItemValidForSlot(0, player.getHeldItem) + if (isDiskInDrive) { + if (rack.isServer) { + InventoryUtils.dropSlot(rack.position, this, 0, 1, Option(rack.facing)) + } + } + if (isHoldingDisk) { + // Insert the disk. + setInventorySlotContents(0, player.inventory.decrStackSize(player.inventory.currentItem, 1)) + } + isDiskInDrive || isHoldingDisk + } + else false + } + + // ----------------------------------------------------------------------- // + // StateAware + + override def getCurrentState: util.EnumSet[api.util.StateAware.State] = util.EnumSet.noneOf(classOf[api.util.StateAware.State]) +} diff --git a/src/main/scala/li/cil/oc/server/component/Server.scala b/src/main/scala/li/cil/oc/server/component/Server.scala index 0256a6ad2..cd93a9d93 100644 --- a/src/main/scala/li/cil/oc/server/component/Server.scala +++ b/src/main/scala/li/cil/oc/server/component/Server.scala @@ -163,7 +163,7 @@ class Server(val rack: tileentity.Rack, val slot: Int) extends Environment with } } else { - player.openGui(OpenComputers, GuiType.ServerInRack(slot).id, world, rack.x, rack.y, rack.z) + player.openGui(OpenComputers, GuiType.ServerInRack.id, world, rack.x, GuiType.embedSlot(rack.y, slot), rack.z) } } true diff --git a/src/main/scala/li/cil/oc/util/ExtendedWorld.scala b/src/main/scala/li/cil/oc/util/ExtendedWorld.scala index cd4aa6c48..013ec67ae 100644 --- a/src/main/scala/li/cil/oc/util/ExtendedWorld.scala +++ b/src/main/scala/li/cil/oc/util/ExtendedWorld.scala @@ -28,6 +28,8 @@ object ExtendedWorld { def getTileEntity(host: EnvironmentHost): TileEntity = getTileEntity(BlockPosition(host)) def isAirBlock(position: BlockPosition) = world.isAirBlock(position.x, position.y, position.z) + + def getLightBrightnessForSkyBlocks(position: BlockPosition, minBrightness: Int) = world.getLightBrightnessForSkyBlocks(position.x, position.y, position.z, minBrightness) } class ExtendedWorld(override val world: World) extends ExtendedBlockAccess(world) {