diff --git a/assets/blocks.psd b/assets/blocks.psd index 060ae421e..955fb79f7 100644 Binary files a/assets/blocks.psd and b/assets/blocks.psd differ diff --git a/src/main/java/li/cil/oc/api/event/FileSystemAccessEvent.java b/src/main/java/li/cil/oc/api/event/FileSystemAccessEvent.java index 70e96fd88..97d0518af 100644 --- a/src/main/java/li/cil/oc/api/event/FileSystemAccessEvent.java +++ b/src/main/java/li/cil/oc/api/event/FileSystemAccessEvent.java @@ -2,11 +2,13 @@ package li.cil.oc.api.event; import cpw.mods.fml.common.eventhandler.Cancelable; import cpw.mods.fml.common.eventhandler.Event; +import li.cil.oc.api.network.Node; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; /** - * Fired on the client side only, signals file system access. + * Events for handling file system access and representing it on the client. *

* This is used to play file system access sounds and render disk activity * indicators on some containers (e.g. disk drive, computer, server). @@ -19,52 +21,35 @@ import net.minecraft.world.World; */ @Cancelable public class FileSystemAccessEvent extends Event { - /** - * The name of the sound effect to play for the file system. - */ - public final String sound; + protected String sound; - /** - * The world the file system lives in. - */ - public final World world; + protected World world; - /** - * The x coordinate of the file system's container. - */ - public final double x; + protected double x; - /** - * The y coordinate of the file system's container. - */ - public final double y; + protected double y; - /** - * The z coordinate of the file system's container. - */ - public final double z; + protected double z; - /** - * The tile entity hosting the file system. - *

- * Important: this can be null, which is usually the - * case when the container is an entity or item. - */ - public final TileEntity tileEntity; + protected TileEntity tileEntity; + + protected NBTTagCompound data; /** * Constructor for tile entity hosted file systems. * * @param sound the name of the sound effect to play. * @param tileEntity the tile entity hosting the file system. + * @param data the additional data. */ - public FileSystemAccessEvent(String sound, TileEntity tileEntity) { + protected FileSystemAccessEvent(String sound, TileEntity tileEntity, NBTTagCompound data) { this.sound = sound; this.world = tileEntity.getWorldObj(); this.x = tileEntity.xCoord + 0.5; this.y = tileEntity.yCoord + 0.5; this.z = tileEntity.zCoord + 0.5; this.tileEntity = tileEntity; + this.data = data; } /** @@ -75,13 +60,116 @@ public class FileSystemAccessEvent extends Event { * @param x the x coordinate of the file system's container. * @param y the y coordinate of the file system's container. * @param z the z coordinate of the file system's container. + * @param data the additional data. */ - public FileSystemAccessEvent(String sound, World world, double x, double y, double z) { + protected FileSystemAccessEvent(String sound, World world, double x, double y, double z, NBTTagCompound data) { this.sound = sound; this.world = world; this.x = x; this.y = y; this.z = z; this.tileEntity = null; + this.data = data; + } + + /** + * The name of the sound effect to play for the file system. + */ + public String getSound() { + return sound; + } + + /** + * The world the file system lives in. + */ + public World getWorld() { + return world; + } + + /** + * The x coordinate of the file system's container. + */ + public double getX() { + return x; + } + + /** + * The y coordinate of the file system's container. + */ + public double getY() { + return y; + } + + /** + * The z coordinate of the file system's container. + */ + public double getZ() { + return z; + } + + /** + * The tile entity hosting the file system. + *

+ * Important: this can be null, which is usually the + * case when the container is an entity or item. + */ + public TileEntity getTileEntity() { + return tileEntity; + } + + /** + * Addition custom data, this is used to transmit the number of the server + * in a server rack the file system lives in, for example. + */ + public NBTTagCompound getData() { + return data; + } + + public static final class Server extends FileSystemAccessEvent { + private Node node; + + public Server(String sound, TileEntity tileEntity, Node node) { + super(sound, tileEntity, new NBTTagCompound()); + this.node = node; + } + + public Server(String sound, World world, double x, double y, double z, Node node) { + super(sound, world, x, y, z, new NBTTagCompound()); + this.node = node; + } + + /** + * The node of the file system that signalled activity. + */ + public Node getNode() { + return node; + } + } + + public static final class Client extends FileSystemAccessEvent { + /** + * Constructor for tile entity hosted file systems. + * + * @param sound the name of the sound effect to play. + * @param tileEntity the tile entity hosting the file system. + * @param data the additional data. + */ + public Client(String sound, TileEntity tileEntity, NBTTagCompound data) { + super(sound, tileEntity, data); + } + + /** + * Constructor for arbitrarily hosted file systems. + * + * @param sound the name of the sound effect to play. + * @param world the world the file system lives in. + * @param x the x coordinate of the file system's container. + * @param y the y coordinate of the file system's container. + * @param z the z coordinate of the file system's container. + * @param data the additional data. + */ + public Client(String sound, World world, double x, double y, double z, NBTTagCompound data) { + super(sound, world, x, y, z, data); + } } } diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/install.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/install.lua index 4d02b9c20..48fa32a75 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/install.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/install.lua @@ -52,11 +52,12 @@ local result, reason = os.execute("/bin/cp -vr /mnt/" .. boot .. "/* /mnt/" .. m if not result then error(reason, 0) end -computer.setBootAddress(choice.address) +choice.setLabel("OpenOS") -print("All done! Would you like to reboot now? [Y/n]") +print("All done! Set as boot device and reboot now? [Y/n]") local result = io.read() if not result or result == "" or result:sub(1, 1):lower() == "y" then + computer.setBootAddress(choice.address) print("\nRebooting now!") computer.shutdown(true) end diff --git a/src/main/resources/assets/opencomputers/textures/blocks/CaseFront.png b/src/main/resources/assets/opencomputers/textures/blocks/CaseFront.png index 10bf518bb..545d79859 100644 Binary files a/src/main/resources/assets/opencomputers/textures/blocks/CaseFront.png and b/src/main/resources/assets/opencomputers/textures/blocks/CaseFront.png differ diff --git a/src/main/resources/assets/opencomputers/textures/blocks/CaseFrontActivity.png b/src/main/resources/assets/opencomputers/textures/blocks/CaseFrontActivity.png new file mode 100644 index 000000000..6d1f857f4 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/blocks/CaseFrontActivity.png differ diff --git a/src/main/resources/assets/opencomputers/textures/blocks/DiskDriveFront.png b/src/main/resources/assets/opencomputers/textures/blocks/DiskDriveFront.png index d1eddd62e..84dd4cbb0 100644 Binary files a/src/main/resources/assets/opencomputers/textures/blocks/DiskDriveFront.png and b/src/main/resources/assets/opencomputers/textures/blocks/DiskDriveFront.png differ diff --git a/src/main/resources/assets/opencomputers/textures/blocks/DiskDriveFrontActivity.png b/src/main/resources/assets/opencomputers/textures/blocks/DiskDriveFrontActivity.png new file mode 100644 index 000000000..5b51c26e2 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/blocks/DiskDriveFrontActivity.png differ diff --git a/src/main/resources/assets/opencomputers/textures/blocks/ServerRackFront.png b/src/main/resources/assets/opencomputers/textures/blocks/ServerRackFront.png index cc5bf30fa..5e0ffed78 100644 Binary files a/src/main/resources/assets/opencomputers/textures/blocks/ServerRackFront.png and b/src/main/resources/assets/opencomputers/textures/blocks/ServerRackFront.png differ diff --git a/src/main/resources/assets/opencomputers/textures/blocks/ServerRackFrontActivity.png b/src/main/resources/assets/opencomputers/textures/blocks/ServerRackFrontActivity.png new file mode 100644 index 000000000..06aa6b751 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/blocks/ServerRackFrontActivity.png differ diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index 4d5807618..7a7030d0c 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -17,6 +17,7 @@ import li.cil.oc.util.Audio import net.minecraft.client.Minecraft import net.minecraft.client.gui.GuiScreen import net.minecraft.entity.player.EntityPlayer +import net.minecraft.nbt.CompressedStreamTools import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.util.ForgeDirection import org.lwjgl.input.Keyboard @@ -145,9 +146,10 @@ object PacketHandler extends CommonPacketHandler { def onFileSystemActivity(p: PacketParser) = { val sound = p.readUTF() + val data = CompressedStreamTools.read(p) if (p.readBoolean()) p.readTileEntity[net.minecraft.tileentity.TileEntity]() match { case Some(t) => - MinecraftForge.EVENT_BUS.post(new FileSystemAccessEvent(sound, t)) + MinecraftForge.EVENT_BUS.post(new FileSystemAccessEvent.Client(sound, t, data)) case _ => // Invalid packet. } else world(p.player, p.readInt()) match { @@ -155,7 +157,7 @@ object PacketHandler extends CommonPacketHandler { val x = p.readDouble() val y = p.readDouble() val z = p.readDouble() - MinecraftForge.EVENT_BUS.post(new FileSystemAccessEvent(sound, world, x, y, z)) + MinecraftForge.EVENT_BUS.post(new FileSystemAccessEvent.Client(sound, world, x, y, z, data)) case _ => // Invalid packet. } } diff --git a/src/main/scala/li/cil/oc/client/Proxy.scala b/src/main/scala/li/cil/oc/client/Proxy.scala index a61dec025..4b80e2409 100644 --- a/src/main/scala/li/cil/oc/client/Proxy.scala +++ b/src/main/scala/li/cil/oc/client/Proxy.scala @@ -16,7 +16,7 @@ import li.cil.oc.client.renderer.block.BlockRenderer import li.cil.oc.client.renderer.item.ItemRenderer import li.cil.oc.client.renderer.tileentity._ import li.cil.oc.common.component.TextBuffer -import li.cil.oc.common.event.FileAccessHandler +import li.cil.oc.common.event.FileSystemAccessHandler import li.cil.oc.common.init.Items import li.cil.oc.common.tileentity import li.cil.oc.common.tileentity.ServerRack @@ -61,7 +61,7 @@ private[oc] class Proxy extends CommonProxy { ClientRegistry.registerKeyBinding(KeyBindings.materialCosts) ClientRegistry.registerKeyBinding(KeyBindings.clipboardPaste) - MinecraftForge.EVENT_BUS.register(FileAccessHandler) + MinecraftForge.EVENT_BUS.register(FileSystemAccessHandler) MinecraftForge.EVENT_BUS.register(PetRenderer) MinecraftForge.EVENT_BUS.register(ServerRack) MinecraftForge.EVENT_BUS.register(TextBuffer) diff --git a/src/main/scala/li/cil/oc/client/Textures.scala b/src/main/scala/li/cil/oc/client/Textures.scala index 0f4460ebf..c52b27b36 100644 --- a/src/main/scala/li/cil/oc/client/Textures.scala +++ b/src/main/scala/li/cil/oc/client/Textures.scala @@ -30,8 +30,11 @@ object Textures { val guiSlot = new ResourceLocation(Settings.resourceDomain, "textures/gui/slot.png") val blockCaseFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/CaseFrontOn.png") + val blockCaseFrontActivity = new ResourceLocation(Settings.resourceDomain, "textures/blocks/CaseFrontActivity.png") + val blockDiskDriveFrontActivity = new ResourceLocation(Settings.resourceDomain, "textures/blocks/DiskDriveFrontActivity.png") val blockHologram = new ResourceLocation(Settings.resourceDomain, "textures/blocks/HologramEffect.png") val blockRackFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/ServerRackFrontOn.png") + val blockRackFrontActivity = new ResourceLocation(Settings.resourceDomain, "textures/blocks/ServerRackFrontActivity.png") val blockRobot = new ResourceLocation(Settings.resourceDomain, "textures/blocks/robot.png") val blockScreenUpIndicator = new ResourceLocation(Settings.resourceDomain, "textures/blocks/screen/up_indicator.png") diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/CaseRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/CaseRenderer.scala index da2cf9199..54f582727 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/CaseRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/CaseRenderer.scala @@ -14,27 +14,27 @@ object CaseRenderer extends TileEntitySpecialRenderer { RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") val computer = tileEntity.asInstanceOf[Case] + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + + RenderState.disableLighting() + RenderState.makeItBlend() + RenderState.setBlendAlpha(1) + + GL11.glPushMatrix() + + GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) + + computer.yaw match { + case ForgeDirection.WEST => GL11.glRotatef(-90, 0, 1, 0) + case ForgeDirection.NORTH => GL11.glRotatef(180, 0, 1, 0) + case ForgeDirection.EAST => GL11.glRotatef(90, 0, 1, 0) + case _ => // No yaw. + } + + GL11.glTranslatef(-0.5f, 0.5f, 0.501f) + GL11.glScalef(1, -1, 1) + if (computer.isRunning) { - GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) - - RenderState.disableLighting() - RenderState.makeItBlend() - RenderState.setBlendAlpha(1) - - GL11.glPushMatrix() - - GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) - - computer.yaw match { - case ForgeDirection.WEST => GL11.glRotatef(-90, 0, 1, 0) - case ForgeDirection.NORTH => GL11.glRotatef(180, 0, 1, 0) - case ForgeDirection.EAST => GL11.glRotatef(90, 0, 1, 0) - case _ => // No yaw. - } - - GL11.glTranslatef(-0.5f, 0.5f, 0.501f) - GL11.glScalef(1, -1, 1) - bindTexture(Textures.blockCaseFrontOn) val t = Tessellator.instance t.startDrawingQuads() @@ -44,10 +44,21 @@ object CaseRenderer extends TileEntitySpecialRenderer { t.addVertexWithUV(0, 0, 0, 0, 0) t.draw() - GL11.glPopMatrix() - GL11.glPopAttrib() + if (System.currentTimeMillis() - computer.lastAccess < 400 && computer.world.rand.nextDouble() > 0.1) { + bindTexture(Textures.blockCaseFrontActivity) + val t = Tessellator.instance + t.startDrawingQuads() + t.addVertexWithUV(0, 1, 0, 0, 1) + t.addVertexWithUV(1, 1, 0, 1, 1) + t.addVertexWithUV(1, 0, 0, 1, 0) + t.addVertexWithUV(0, 0, 0, 0, 0) + t.draw() + } } + GL11.glPopMatrix() + GL11.glPopAttrib() + RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving") } } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/DiskDriveRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/DiskDriveRenderer.scala index 7a880641a..acf682f1a 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/DiskDriveRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/DiskDriveRenderer.scala @@ -1,8 +1,10 @@ package li.cil.oc.client.renderer.tileentity +import li.cil.oc.client.Textures import li.cil.oc.common.tileentity.DiskDrive import li.cil.oc.util.RenderState import net.minecraft.client.renderer.OpenGlHelper +import net.minecraft.client.renderer.Tessellator import net.minecraft.client.renderer.entity.RenderItem import net.minecraft.client.renderer.entity.RenderManager import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer @@ -16,39 +18,59 @@ object DiskDriveRenderer extends TileEntitySpecialRenderer { RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") val drive = tileEntity.asInstanceOf[DiskDrive] + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + + GL11.glPushMatrix() + + GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) + + drive.yaw match { + case ForgeDirection.WEST => GL11.glRotatef(-90, 0, 1, 0) + case ForgeDirection.NORTH => GL11.glRotatef(180, 0, 1, 0) + case ForgeDirection.EAST => GL11.glRotatef(90, 0, 1, 0) + case _ => // No yaw. + } + drive.items(0) match { case Some(stack) => - GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + GL11.glPushMatrix() + GL11.glTranslatef(0, 3.5f / 16, 9 / 16f) + GL11.glRotatef(90, -1, 0, 0) val brightness = drive.world.getLightBrightnessForSkyBlocks(drive.x + drive.facing.offsetX, drive.y + drive.facing.offsetY, drive.z + drive.facing.offsetZ, 0) OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, brightness % 65536, brightness / 65536) - GL11.glPushMatrix() - - GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) - - drive.yaw match { - case ForgeDirection.WEST => GL11.glRotatef(-90, 0, 1, 0) - case ForgeDirection.NORTH => GL11.glRotatef(180, 0, 1, 0) - case ForgeDirection.EAST => GL11.glRotatef(90, 0, 1, 0) - case _ => // No yaw. - } - - GL11.glTranslatef(0, 3.5f / 16, 9 / 16f) - GL11.glRotatef(90, -1, 0, 0) - // This is very 'meh', but item frames do it like this, too! val entity = new EntityItem(drive.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() - GL11.glPopAttrib() case _ => } + if (System.currentTimeMillis() - drive.lastAccess < 400 && drive.world.rand.nextDouble() > 0.1) { + GL11.glTranslatef(-0.5f, 0.5f, 0.501f) + GL11.glScalef(1, -1, 1) + + RenderState.disableLighting() + RenderState.makeItBlend() + RenderState.setBlendAlpha(1) + + bindTexture(Textures.blockDiskDriveFrontActivity) + val t = Tessellator.instance + t.startDrawingQuads() + t.addVertexWithUV(0, 1, 0, 0, 1) + t.addVertexWithUV(1, 1, 0, 1, 1) + t.addVertexWithUV(1, 0, 0, 1, 0) + t.addVertexWithUV(0, 0, 0, 0, 0) + t.draw() + } + + GL11.glPopMatrix() + GL11.glPopAttrib() + RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving") } } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/ServerRackRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/ServerRackRenderer.scala index a5190a331..abbd1bbe7 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/ServerRackRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/ServerRackRenderer.scala @@ -14,33 +14,44 @@ object ServerRackRenderer extends TileEntitySpecialRenderer { RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)") val rack = tileEntity.asInstanceOf[ServerRack] + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + + RenderState.disableLighting() + RenderState.makeItBlend() + + GL11.glPushMatrix() + + GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) + + rack.yaw match { + case ForgeDirection.WEST => GL11.glRotatef(-90, 0, 1, 0) + case ForgeDirection.NORTH => GL11.glRotatef(180, 0, 1, 0) + case ForgeDirection.EAST => GL11.glRotatef(90, 0, 1, 0) + case _ => // No yaw. + } + + GL11.glTranslatef(-0.5f, 0.5f, 0.501f) + GL11.glScalef(1, -1, 1) + if (rack.anyRunning) { - GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) - - RenderState.disableLighting() - RenderState.makeItBlend() - - GL11.glPushMatrix() - - GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) - - rack.yaw match { - case ForgeDirection.WEST => GL11.glRotatef(-90, 0, 1, 0) - case ForgeDirection.NORTH => GL11.glRotatef(180, 0, 1, 0) - case ForgeDirection.EAST => GL11.glRotatef(90, 0, 1, 0) - case _ => // No yaw. - } - - GL11.glTranslatef(-0.5f, 0.5f, 0.501f) - GL11.glScalef(1, -1, 1) - - bindTexture(Textures.blockRackFrontOn) - val v1 = 2 / 16f val fs = 3 / 16f for (i <- 0 until 4 if rack.isRunning(i)) { val l = v1 + i * fs val h = v1 + (i + 1) * fs + bindTexture(Textures.blockRackFrontOn) + val t = Tessellator.instance + t.startDrawingQuads() + t.addVertexWithUV(0, h, 0, 0, h) + t.addVertexWithUV(1, h, 0, 1, h) + t.addVertexWithUV(1, l, 0, 1, l) + t.addVertexWithUV(0, l, 0, 0, l) + t.draw() + } + for (i <- 0 until 4 if System.currentTimeMillis() - rack.lastAccess(i) < 400 && rack.world.rand.nextDouble() > 0.1) { + val l = v1 + i * fs + val h = v1 + (i + 1) * fs + bindTexture(Textures.blockRackFrontActivity) val t = Tessellator.instance t.startDrawingQuads() t.addVertexWithUV(0, h, 0, 0, h) @@ -49,11 +60,11 @@ object ServerRackRenderer extends TileEntitySpecialRenderer { t.addVertexWithUV(0, l, 0, 0, l) t.draw() } - - GL11.glPopMatrix() - GL11.glPopAttrib() } + GL11.glPopMatrix() + GL11.glPopAttrib() + RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving") } } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/common/event/FileAccessHandler.scala b/src/main/scala/li/cil/oc/common/event/FileAccessHandler.scala deleted file mode 100644 index ba21e128c..000000000 --- a/src/main/scala/li/cil/oc/common/event/FileAccessHandler.scala +++ /dev/null @@ -1,13 +0,0 @@ -package li.cil.oc.common.event - -import cpw.mods.fml.common.eventhandler.SubscribeEvent -import li.cil.oc.Settings -import li.cil.oc.api.event.FileSystemAccessEvent - -object FileAccessHandler { - @SubscribeEvent - def onFileSystemAccess(e: FileSystemAccessEvent) { - val volume = Settings.get.soundVolume - e.world.playSound(e.x, e.y, e.z, e.sound, volume, 1, false) - } -} diff --git a/src/main/scala/li/cil/oc/common/event/FileSystemAccessHandler.scala b/src/main/scala/li/cil/oc/common/event/FileSystemAccessHandler.scala new file mode 100644 index 000000000..e5ff53700 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/event/FileSystemAccessHandler.scala @@ -0,0 +1,36 @@ +package li.cil.oc.common.event + +import cpw.mods.fml.common.eventhandler.SubscribeEvent +import li.cil.oc.Settings +import li.cil.oc.api.event.FileSystemAccessEvent +import li.cil.oc.common.tileentity.Case +import li.cil.oc.common.tileentity.DiskDrive +import li.cil.oc.common.tileentity.ServerRack + +object FileSystemAccessHandler { + @SubscribeEvent + def onFileSystemAccess(e: FileSystemAccessEvent.Server) { + e.getTileEntity match { + case t: ServerRack => + val serverSlot = t.servers.indexWhere { + case Some(server) => server.componentSlot(e.getNode.address) >= 0 + case _ => false + } + if (serverSlot < 0) e.setCanceled(true) + else e.getData.setInteger("server", serverSlot) + case _ => + } + } + + @SubscribeEvent + def onFileSystemAccess(e: FileSystemAccessEvent.Client) { + val volume = Settings.get.soundVolume + e.getWorld.playSound(e.getX, e.getY, e.getZ, e.getSound, volume, 1, false) + e.getTileEntity match { + case t: DiskDrive => t.lastAccess = System.currentTimeMillis() + case t: Case => t.lastAccess = System.currentTimeMillis() + case t: ServerRack => t.lastAccess(e.getData.getInteger("server")) = System.currentTimeMillis() + case _ => + } + } +} diff --git a/src/main/scala/li/cil/oc/common/tileentity/Case.scala b/src/main/scala/li/cil/oc/common/tileentity/Case.scala index b2eb1c515..cb8d645ea 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Case.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Case.scala @@ -20,6 +20,9 @@ import net.minecraftforge.common.util.ForgeDirection class Case(var tier: Int) extends traits.PowerAcceptor with traits.Computer with traits.Colored { def this() = this(0) + // Used on client side to check whether to render disk activity indicators. + var lastAccess = 0L + color = Color.byTier(tier) @SideOnly(Side.CLIENT) 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 15446ad6d..a043f37bb 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala @@ -18,6 +18,9 @@ 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.None).create() + // Used on client side to check whether to render disk activity indicators. + var lastAccess = 0L + // ----------------------------------------------------------------------- // override def onAnalyze(player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = diff --git a/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala b/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala index 26075404b..e8a757970 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/ServerRack.scala @@ -51,6 +51,9 @@ class ServerRack extends traits.PowerAcceptor with traits.Hub with traits.PowerB // For client side rendering. var isPresent = Array.fill[Option[String]](getSizeInventory)(None) + // Used on client side to check whether to render disk activity indicators. + var lastAccess = Array.fill(4)(0L) + @SideOnly(Side.CLIENT) override protected def hasConnector(side: ForgeDirection) = side != facing diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index 4a92ebb81..dccdced1d 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -2,13 +2,17 @@ package li.cil.oc.server import li.cil.oc.api.component.TextBuffer.ColorDepth import li.cil.oc.api.driver.EnvironmentHost +import li.cil.oc.api.event.FileSystemAccessEvent +import li.cil.oc.api.network.Node import li.cil.oc.common._ import li.cil.oc.common.tileentity.traits._ import li.cil.oc.util.PackedColor import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.item.ItemStack +import net.minecraft.nbt.CompressedStreamTools import net.minecraft.nbt.NBTTagCompound import net.minecraft.world.World +import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.util.ForgeDirection import scala.collection.mutable @@ -81,28 +85,36 @@ object PacketSender { // Avoid spamming the network with disk activity notices. val fileSystemAccessTimeouts = mutable.WeakHashMap.empty[EnvironmentHost, mutable.Map[String, Long]] - def sendFileSystemActivity(host: EnvironmentHost, name: String) = fileSystemAccessTimeouts.synchronized { + def sendFileSystemActivity(node: Node, host: EnvironmentHost, name: String) = fileSystemAccessTimeouts.synchronized { fileSystemAccessTimeouts.get(host) match { case Some(hostTimeouts) if hostTimeouts.getOrElse(name, 0L) > System.currentTimeMillis() => // Cooldown. case _ => - fileSystemAccessTimeouts.getOrElseUpdate(host, mutable.Map.empty) += name -> (System.currentTimeMillis() + 500) - - val pb = new SimplePacketBuilder(PacketType.FileSystemActivity) - - pb.writeUTF(name) - host match { - case t: net.minecraft.tileentity.TileEntity => - pb.writeBoolean(true) - pb.writeTileEntity(t) - case _ => - pb.writeBoolean(false) - pb.writeInt(host.world.provider.dimensionId) - pb.writeDouble(host.xPosition) - pb.writeDouble(host.yPosition) - pb.writeDouble(host.zPosition) + val event = host match { + case t: net.minecraft.tileentity.TileEntity => new FileSystemAccessEvent.Server(name, t, node) + case _ => new FileSystemAccessEvent.Server(name, host.world, host.xPosition, host.yPosition, host.zPosition, node) } + MinecraftForge.EVENT_BUS.post(event) + if (!event.isCanceled) { + fileSystemAccessTimeouts.getOrElseUpdate(host, mutable.Map.empty) += name -> (System.currentTimeMillis() + 500) - pb.sendToPlayersNearHost(host, 64) + val pb = new SimplePacketBuilder(PacketType.FileSystemActivity) + + pb.writeUTF(event.getSound) + CompressedStreamTools.write(event.getData, pb) + event.getTileEntity match { + case t: net.minecraft.tileentity.TileEntity => + pb.writeBoolean(true) + pb.writeTileEntity(t) + case _ => + pb.writeBoolean(false) + pb.writeInt(event.getWorld.provider.dimensionId) + pb.writeDouble(event.getX) + pb.writeDouble(event.getY) + pb.writeDouble(event.getZ) + } + + pb.sendToPlayersNearHost(host, 64) + } } } diff --git a/src/main/scala/li/cil/oc/server/component/FileSystem.scala b/src/main/scala/li/cil/oc/server/component/FileSystem.scala index f17d9ba6b..611dbab2d 100644 --- a/src/main/scala/li/cil/oc/server/component/FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/component/FileSystem.scala @@ -313,7 +313,7 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label, val host: Option private def diskActivity() { (sound, host) match { - case (Some(s), Some(h)) => ServerPacketSender.sendFileSystemActivity(h, s) + case (Some(s), Some(h)) => ServerPacketSender.sendFileSystemActivity(node, h, s) case _ => } }