From 757834d9b9c1b64b3a0ea61d4ba28529c4eba9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 13 Apr 2014 16:04:05 +0200 Subject: [PATCH 01/14] Forgot to disable the fingerprint check while not signing the JAR... --- src/main/scala/li/cil/oc/OpenComputers.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/OpenComputers.scala b/src/main/scala/li/cil/oc/OpenComputers.scala index b09dab4db..677f61d55 100644 --- a/src/main/scala/li/cil/oc/OpenComputers.scala +++ b/src/main/scala/li/cil/oc/OpenComputers.scala @@ -26,8 +26,8 @@ object OpenComputers { var tampered: Option[FMLFingerprintViolationEvent] = None - @EventHandler - def invalidFingerprint(e: FMLFingerprintViolationEvent) = tampered = Some(e) +// @EventHandler +// def invalidFingerprint(e: FMLFingerprintViolationEvent) = tampered = Some(e) @EventHandler def preInit(e: FMLPreInitializationEvent) = proxy.preInit(e) From f65616c42a7341b803857f495bf77712f8cd9d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 13 Apr 2014 17:38:04 +0200 Subject: [PATCH 02/14] Removed fingerprint completely to avoid confusing certain mods that decide they have to check the fingerprints of other mods... --- src/main/scala/li/cil/oc/OpenComputers.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/OpenComputers.scala b/src/main/scala/li/cil/oc/OpenComputers.scala index 677f61d55..f281e9b36 100644 --- a/src/main/scala/li/cil/oc/OpenComputers.scala +++ b/src/main/scala/li/cil/oc/OpenComputers.scala @@ -12,7 +12,7 @@ import li.cil.oc.common.Proxy import li.cil.oc.server.{PacketHandler => ServerPacketHandler} @Mod(modid = "OpenComputers", modLanguage = "scala", - certificateFingerprint = "@FINGERPRINT@", useMetadata = true) + /* certificateFingerprint = "@FINGERPRINT@", */ useMetadata = true) @NetworkMod(clientSideRequired = true, serverSideRequired = false, clientPacketHandlerSpec = new SidedPacketHandler( channels = Array("OpenComp"), packetHandler = classOf[ClientPacketHandler]), From 4734c179f7e82a5b72fc251d164555825127c293 Mon Sep 17 00:00:00 2001 From: PixelToast Date: Tue, 15 Apr 2014 19:08:15 -0400 Subject: [PATCH 03/14] allow system to catch too long without yielding gives system 0.5 seconds to yield before crashing. makes it much much less annoying, and its still safe: while true do end -> error while true do pcall(function() while true do end end) end -> system crash --- src/main/resources/assets/opencomputers/lua/kernel.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/lua/kernel.lua b/src/main/resources/assets/opencomputers/lua/kernel.lua index 384ccc5c0..cd3a9aa1b 100644 --- a/src/main/resources/assets/opencomputers/lua/kernel.lua +++ b/src/main/resources/assets/opencomputers/lua/kernel.lua @@ -1,8 +1,13 @@ local hookInterval = 100 local deadline = math.huge +local hitDeadline = false local function checkDeadline() if computer.realTime() > deadline then debug.sethook(coroutine.running(), checkDeadline, "", 1) + if not hitDeadline then + deadline = deadline + 0.5 + end + hitDeadline = true error("too long without yielding", 0) end end @@ -570,6 +575,7 @@ local function main() while true do deadline = computer.realTime() + timeout -- timeout global is set by host + hitDeadline = false debug.sethook(co, checkDeadline, "", hookInterval) local result = table.pack(coroutine.resume(co, table.unpack(args, 1, args.n))) if not result[1] then @@ -584,4 +590,4 @@ end -- JNLua converts the coroutine to a string immediately, so we can't get the -- traceback later. Because of that we have to do the error handling here. -return pcall(main) \ No newline at end of file +return pcall(main) From f49066ee2002ec94712c0808e8c755b5255616f6 Mon Sep 17 00:00:00 2001 From: PixelToast Date: Tue, 15 Apr 2014 19:12:53 -0400 Subject: [PATCH 04/14] stupid github editor is stupid --- src/main/resources/assets/opencomputers/lua/kernel.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/lua/kernel.lua b/src/main/resources/assets/opencomputers/lua/kernel.lua index cd3a9aa1b..ef8945ac4 100644 --- a/src/main/resources/assets/opencomputers/lua/kernel.lua +++ b/src/main/resources/assets/opencomputers/lua/kernel.lua @@ -6,7 +6,7 @@ local function checkDeadline() debug.sethook(coroutine.running(), checkDeadline, "", 1) if not hitDeadline then deadline = deadline + 0.5 - end + end hitDeadline = true error("too long without yielding", 0) end From c9315f57a6255fdbd8dc12eb068d0f941c1b3688 Mon Sep 17 00:00:00 2001 From: KlutzLament Date: Wed, 16 Apr 2014 23:59:28 -0500 Subject: [PATCH 05/14] Update robot.names --- src/main/resources/assets/opencomputers/robot.names | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/assets/opencomputers/robot.names b/src/main/resources/assets/opencomputers/robot.names index 7ed760a47..f0dde3dd0 100644 --- a/src/main/resources/assets/opencomputers/robot.names +++ b/src/main/resources/assets/opencomputers/robot.names @@ -34,6 +34,8 @@ Skynet Terminator T-1000 Terminator T-800 Wheatley +Rosie +Uniblab # Perry Rhodan Robots, definitly not all... Anson Argyris From d0c620d802b932b402d61eba9d2af6abd308275f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 17 Apr 2014 16:27:39 +0200 Subject: [PATCH 06/14] Fixed math.random erroring for unit intervals. Closes #214. --- src/main/scala/li/cil/oc/util/LuaStateFactory.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/util/LuaStateFactory.scala b/src/main/scala/li/cil/oc/util/LuaStateFactory.scala index 6c3066800..94dc7efaa 100644 --- a/src/main/scala/li/cil/oc/util/LuaStateFactory.scala +++ b/src/main/scala/li/cil/oc/util/LuaStateFactory.scala @@ -220,12 +220,12 @@ object LuaStateFactory { case 0 => lua.pushNumber(random.nextDouble()) case 1 => val u = lua.checkNumber(1).toInt - lua.checkArg(1, 1 < u, "interval is empty") + lua.checkArg(1, 1 <= u, "interval is empty") lua.pushInteger(1 + random.nextInt(u)) case 2 => val l = lua.checkNumber(1).toInt val u = lua.checkNumber(2).toInt - lua.checkArg(1, l < u, "interval is empty") + lua.checkArg(1, l <= u, "interval is empty") lua.pushInteger(l + random.nextInt(u - (l - 1))) case _ => throw new IllegalArgumentException("wrong number of arguments") } From b3ea58c96b558efd4d8d552addb822db5adb7978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 18 Apr 2014 14:06:45 +0200 Subject: [PATCH 07/14] Fixed NPE in robot.use(). Fixed undirected robot commands leading to unexpected results (in particular place, which can place blocks in "adjacent" blocks if the block is replaceable), always testing into the primary facing direction first now. --- .../scala/li/cil/oc/server/component/robot/Player.scala | 2 +- .../scala/li/cil/oc/server/component/robot/Robot.scala | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/robot/Player.scala b/src/main/scala/li/cil/oc/server/component/robot/Player.scala index 57af9f22b..7a6cb7357 100644 --- a/src/main/scala/li/cil/oc/server/component/robot/Player.scala +++ b/src/main/scala/li/cil/oc/server/component/robot/Player.scala @@ -306,7 +306,7 @@ class Player(val robot: tileentity.Robot) extends EntityPlayer(robot.world, Sett }) } - private def isItemUseAllowed(stack: ItemStack) = { + private def isItemUseAllowed(stack: ItemStack) = stack == null || { (Settings.get.allowUseItemsWithDuration || stack.getMaxItemUseDuration <= 0) && (!PortalGun.isPortalGun(stack) || PortalGun.isStandardPortalGun(stack)) && !stack.isItemEqual(new ItemStack(Item.leash)) diff --git a/src/main/scala/li/cil/oc/server/component/robot/Robot.scala b/src/main/scala/li/cil/oc/server/component/robot/Robot.scala index 882c7ed0d..49af11d60 100644 --- a/src/main/scala/li/cil/oc/server/component/robot/Robot.scala +++ b/src/main/scala/li/cil/oc/server/component/robot/Robot.scala @@ -231,7 +231,8 @@ class Robot(val robot: tileentity.Robot) extends ManagedComponent { Iterable(checkSideForFace(args, 1, facing)) } else { - ForgeDirection.VALID_DIRECTIONS.filter(_ != facing.getOpposite).toIterable + // Always try the direction we're looking first. + Iterable(facing) ++ ForgeDirection.VALID_DIRECTIONS.filter(side => side != facing && side != facing.getOpposite).toIterable } val sneaky = args.isBoolean(2) && args.checkBoolean(2) val stack = player.robotInventory.selectedItemStack @@ -337,7 +338,8 @@ class Robot(val robot: tileentity.Robot) extends ManagedComponent { Iterable(checkSideForFace(args, 1, facing)) } else { - ForgeDirection.VALID_DIRECTIONS.filter(_ != facing.getOpposite).toIterable + // Always try the direction we're looking first. + Iterable(facing) ++ ForgeDirection.VALID_DIRECTIONS.filter(side => side != facing && side != facing.getOpposite).toIterable } val sneaky = args.isBoolean(2) && args.checkBoolean(2) @@ -414,7 +416,8 @@ class Robot(val robot: tileentity.Robot) extends ManagedComponent { Iterable(checkSideForFace(args, 1, facing)) } else { - ForgeDirection.VALID_DIRECTIONS.filter(_ != facing.getOpposite).toIterable + // Always try the direction we're looking first. + Iterable(facing) ++ ForgeDirection.VALID_DIRECTIONS.filter(side => side != facing && side != facing.getOpposite).toIterable } val sneaky = args.isBoolean(2) && args.checkBoolean(2) val duration = From 774ca1268b84664fac3167b1d1972de13386b817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 18 Apr 2014 14:33:04 +0200 Subject: [PATCH 08/14] Splitting up rendering of text on screens with a vertical resolution > 25 into separate display lists to see it if might help with the ATI driver crash. --- .../client/renderer/gui/BufferRenderer.scala | 15 +++++++++--- .../renderer/tileentity/ScreenRenderer.scala | 24 ++++++++++++++----- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/renderer/gui/BufferRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/gui/BufferRenderer.scala index 5817433dc..e7a1b03d0 100644 --- a/src/main/scala/li/cil/oc/client/renderer/gui/BufferRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/gui/BufferRenderer.scala @@ -18,7 +18,7 @@ object BufferRenderer { def init(tm: TextureManager) = this.synchronized(if (!textureManager.isDefined) { textureManager = Some(tm) - displayLists = GLAllocation.generateDisplayLists(2) + displayLists = GLAllocation.generateDisplayLists(3) RenderState.checkError("BufferRenderer.displayLists") }) @@ -74,8 +74,16 @@ object BufferRenderer { GL11.glDepthMask(false) GL11.glScaled(scale, scale, 1) - lines.zip(colors).zipWithIndex.foreach { - case ((line, color), i) => MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, line, color, depth) + + for (i <- 0 until math.min(25, lines.length)) { + MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, lines(i), colors(i), depth) + } + + GL11.glEndList() + GL11.glNewList(displayLists + 2, GL11.GL_COMPILE) + + for (i <- 25 until lines.length) { + MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, lines(i), colors(i), depth) } GL11.glPopAttrib() @@ -90,6 +98,7 @@ object BufferRenderer { def drawText() = if (textureManager.isDefined) { GL11.glCallList(displayLists + 1) + GL11.glCallList(displayLists + 2) } private def drawBorder(x: Double, y: Double, w: Double, h: Double, u1: Int, v1: Int, u2: Int, v2: Int) = { diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala index c8901e178..9547626ee 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala @@ -174,17 +174,29 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with // Slightly offset the text so it doesn't clip into the screen. GL11.glTranslatef(0, 0, 0.01f) - for (((line, color), i) <- screen.buffer.lines.zip(screen.buffer.color).zipWithIndex) { - MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, line, color, screen.buffer.depth) + val lines = screen.buffer.lines + val colors = screen.buffer.color + for (i <- 0 until math.min(25, lines.length)) { + MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, lines(i), colors(i), screen.buffer.depth) + } + + if (doCompile) { + GL11.glEndList() + GL11.glNewList(list + 1, GL11.GL_COMPILE_AND_EXECUTE) + } + + for (i <- 25 until lines.length) { + MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, lines(i), colors(i), screen.buffer.depth) } if (doCompile) { GL11.glEndList() } - - true } - else GL11.glCallList(list) + else { + GL11.glCallList(list) + GL11.glCallList(list + 1) + } private def playerDistanceSq() = { val player = Minecraft.getMinecraft.thePlayer @@ -236,7 +248,7 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with // ----------------------------------------------------------------------- // def call = { - val list = GLAllocation.generateDisplayLists(1) + val list = GLAllocation.generateDisplayLists(2) screen.bufferIsDirty = true // Force compilation. list } From 1961d0101b18dd7b2f2991560d3f6e6e6f65aa82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 19 Apr 2014 10:56:10 +0200 Subject: [PATCH 09/14] Revert "Splitting up rendering of text on screens with a vertical resolution > 25 into separate display lists to see it if might help with the ATI driver crash." This reverts commit 774ca1268b84664fac3167b1d1972de13386b817. --- .../client/renderer/gui/BufferRenderer.scala | 15 +++--------- .../renderer/tileentity/ScreenRenderer.scala | 24 +++++-------------- 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/renderer/gui/BufferRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/gui/BufferRenderer.scala index e7a1b03d0..5817433dc 100644 --- a/src/main/scala/li/cil/oc/client/renderer/gui/BufferRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/gui/BufferRenderer.scala @@ -18,7 +18,7 @@ object BufferRenderer { def init(tm: TextureManager) = this.synchronized(if (!textureManager.isDefined) { textureManager = Some(tm) - displayLists = GLAllocation.generateDisplayLists(3) + displayLists = GLAllocation.generateDisplayLists(2) RenderState.checkError("BufferRenderer.displayLists") }) @@ -74,16 +74,8 @@ object BufferRenderer { GL11.glDepthMask(false) GL11.glScaled(scale, scale, 1) - - for (i <- 0 until math.min(25, lines.length)) { - MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, lines(i), colors(i), depth) - } - - GL11.glEndList() - GL11.glNewList(displayLists + 2, GL11.GL_COMPILE) - - for (i <- 25 until lines.length) { - MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, lines(i), colors(i), depth) + lines.zip(colors).zipWithIndex.foreach { + case ((line, color), i) => MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, line, color, depth) } GL11.glPopAttrib() @@ -98,7 +90,6 @@ object BufferRenderer { def drawText() = if (textureManager.isDefined) { GL11.glCallList(displayLists + 1) - GL11.glCallList(displayLists + 2) } private def drawBorder(x: Double, y: Double, w: Double, h: Double, u1: Int, v1: Int, u2: Int, v2: Int) = { diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala index 9547626ee..c8901e178 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala @@ -174,29 +174,17 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with // Slightly offset the text so it doesn't clip into the screen. GL11.glTranslatef(0, 0, 0.01f) - val lines = screen.buffer.lines - val colors = screen.buffer.color - for (i <- 0 until math.min(25, lines.length)) { - MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, lines(i), colors(i), screen.buffer.depth) - } - - if (doCompile) { - GL11.glEndList() - GL11.glNewList(list + 1, GL11.GL_COMPILE_AND_EXECUTE) - } - - for (i <- 25 until lines.length) { - MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, lines(i), colors(i), screen.buffer.depth) + for (((line, color), i) <- screen.buffer.lines.zip(screen.buffer.color).zipWithIndex) { + MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, line, color, screen.buffer.depth) } if (doCompile) { GL11.glEndList() } + + true } - else { - GL11.glCallList(list) - GL11.glCallList(list + 1) - } + else GL11.glCallList(list) private def playerDistanceSq() = { val player = Minecraft.getMinecraft.thePlayer @@ -248,7 +236,7 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with // ----------------------------------------------------------------------- // def call = { - val list = GLAllocation.generateDisplayLists(2) + val list = GLAllocation.generateDisplayLists(1) screen.bufferIsDirty = true // Force compilation. list } From 50ddf683d22ad4313c76c68c2c77b299602fe506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 19 Apr 2014 11:01:28 +0200 Subject: [PATCH 10/14] Getting rid of tessellator, maybe that'll fix the ATI crash... read somewhere that ATI drivers derp when VBOs are used inside display lists. --- .../renderer/MonospaceFontRenderer.scala | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/renderer/MonospaceFontRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/MonospaceFontRenderer.scala index 2fb4278c8..d27068559 100644 --- a/src/main/scala/li/cil/oc/client/renderer/MonospaceFontRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/MonospaceFontRenderer.scala @@ -4,7 +4,6 @@ import li.cil.oc.client.TexturePreloader import li.cil.oc.util.{RenderState, PackedColor} import li.cil.oc.{OpenComputers, Settings} import net.minecraft.client.renderer.GLAllocation -import net.minecraft.client.renderer.Tessellator import net.minecraft.client.renderer.texture.TextureManager import org.lwjgl.opengl.GL11 import scala.io.Source @@ -46,7 +45,6 @@ object MonospaceFontRenderer { val s = Settings.get.fontCharScale val dw = charWidth * s - charWidth val dh = charHeight * s - charHeight - val t = Tessellator.instance // Now create lists for all printable chars. for (index <- 1 until 0xFF) { val x = (index - 1) % cols @@ -54,12 +52,16 @@ object MonospaceFontRenderer { val u = x * uStep val v = y * vStep GL11.glNewList(charLists + index, GL11.GL_COMPILE) - t.startDrawingQuads() - t.addVertexWithUV(-dw, charHeight * s, 0, u, v + vSize) - t.addVertexWithUV(charWidth * s, charHeight * s, 0, u + uSize, v + vSize) - t.addVertexWithUV(charWidth * s, -dh, 0, u + uSize, v) - t.addVertexWithUV(-dw, -dh, 0, u, v) - t.draw() + GL11.glBegin(GL11.GL_QUADS) + GL11.glTexCoord2d(u, v + vSize) + GL11.glVertex3d(-dw, charHeight * s, 0) + GL11.glTexCoord2d(u + uSize, v + vSize) + GL11.glVertex3d(charWidth * s, charHeight * s, 0) + GL11.glTexCoord2d(u + uSize, v) + GL11.glVertex3d(charWidth * s, -dh, 0) + GL11.glTexCoord2d(u, v) + GL11.glVertex3d(-dw, -dh, 0) + GL11.glEnd() GL11.glTranslatef(charWidth, 0, 0) GL11.glEndList() } From bbe80bc5de5f5918ca48380f7f0d4a653956e974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 20 Apr 2014 20:53:48 +0200 Subject: [PATCH 11/14] Fixed Abstract Bus Card in servers (broke in recent cleanup). Updated SGT2 API. --- .../java/stargatetech2/api/IStackManager.java | 34 +++++++++++++++++ .../stargatetech2/api/IStargateTechAPI.java | 5 +++ .../api/shields/IShieldController.java | 37 +++++++++++++++++++ .../api/shields/IShieldable.java | 10 ++--- .../api/shields/ShieldPermissions.java | 24 ++++++------ .../cil/oc/common/asm/ClassTransformer.scala | 11 +++--- .../server/driver/item/AbstractBusCard.scala | 4 +- 7 files changed, 101 insertions(+), 24 deletions(-) create mode 100644 src/api/java/stargatetech2/api/IStackManager.java create mode 100644 src/api/java/stargatetech2/api/shields/IShieldController.java diff --git a/src/api/java/stargatetech2/api/IStackManager.java b/src/api/java/stargatetech2/api/IStackManager.java new file mode 100644 index 000000000..a1493c727 --- /dev/null +++ b/src/api/java/stargatetech2/api/IStackManager.java @@ -0,0 +1,34 @@ +package stargatetech2.api; + +import java.util.Collection; + +import net.minecraft.item.ItemStack; + +/** + * The way to get ItemStacks added to the game by StargateTech 2 + * + * @author LordFokas + */ +public interface IStackManager { + /** + * Used to fetch an ItemStack by it's name, with a default size of 1. + * + * @param stack The stack we want to fetch. + * @return The stack, or null if none was found. + */ + public ItemStack get(String stack); + + /** + * Used to fetch an ItemStack by it's name with a given size. + * + * @param stack The stack we want to fetch. + * @param size The size the stack comes with. Must be in the range 1 - 64. + * @return The stack, or null if none was found. + */ + public ItemStack get(String stack, int size); + + /** + * @return A list with the names of all the existing stacks. + */ + public Collection getAllStacks(); +} \ No newline at end of file diff --git a/src/api/java/stargatetech2/api/IStargateTechAPI.java b/src/api/java/stargatetech2/api/IStargateTechAPI.java index ab00336e3..04e0ad6ed 100644 --- a/src/api/java/stargatetech2/api/IStargateTechAPI.java +++ b/src/api/java/stargatetech2/api/IStargateTechAPI.java @@ -24,4 +24,9 @@ public interface IStargateTechAPI { * @return The current IFactory instance. */ public IFactory getFactory(); + + /** + * @return The current IStackManager instance. + */ + public IStackManager getStackManager(); } \ No newline at end of file diff --git a/src/api/java/stargatetech2/api/shields/IShieldController.java b/src/api/java/stargatetech2/api/shields/IShieldController.java new file mode 100644 index 000000000..4f3fa4763 --- /dev/null +++ b/src/api/java/stargatetech2/api/shields/IShieldController.java @@ -0,0 +1,37 @@ +package stargatetech2.api.shields; + +/** + * Implemented by the Shield Controller TileEntities. + * + * @author LordFokas + */ +public interface IShieldController { + /** + * Given the way shield emitters work together, you cannot + * directly access their ShieldPermissions object. + * This means you cannot use this method to change + * permissions on a shield. + * + * @return A deep clone of the ShieldPermissions object that + * defines this controller's shield behavior. + */ + public ShieldPermissions getPermissions(); + + /** + * @return True if the shield is activated, false otherwise. + */ + public boolean isShieldOn(); + + /** + * @return The name of the player who owns this Shield Controller. + */ + public String getOwner(); + + /** + * Checks if a player can access this device. + * + * @param player The player's name. + * @return Whether or not this player can access this device. + */ + public boolean hasAccess(String player); +} \ No newline at end of file diff --git a/src/api/java/stargatetech2/api/shields/IShieldable.java b/src/api/java/stargatetech2/api/shields/IShieldable.java index b185defe8..50003e0e3 100644 --- a/src/api/java/stargatetech2/api/shields/IShieldable.java +++ b/src/api/java/stargatetech2/api/shields/IShieldable.java @@ -10,16 +10,16 @@ import net.minecraft.world.World; public interface IShieldable { /** * Called by shield emitters to make blocks raise their shields. - * The block on {px, py, pz} contains an ITileShieldEmitter from which - * you can get the current ShieldPermissions object. + * The block on {px, py, pz} contains an IShieldController from + * which you can get the current ShieldPermissions object. * * @param world The world this IShieldable is on. * @param x This IShieldable's X Coordinate. * @param y This IShieldable's Y Coordinate. * @param z This IShieldable's Z Coordinate. - * @param px The X Coordinate of the shield emitter raising a shield on this block. - * @param py The Y Coordinate of the shield emitter raising a shield on this block. - * @param pz The Z Coordinate of the shield emitter raising a shield on this block. + * @param px The X Coordinate of the shield controller in charge of the shield on this block. + * @param py The Y Coordinate of the shield controller in charge of the shield on this block. + * @param pz The Z Coordinate of the shield controller in charge of the shield on this block. */ public void onShield(World world, int x, int y, int z, int px, int py, int pz); diff --git a/src/api/java/stargatetech2/api/shields/ShieldPermissions.java b/src/api/java/stargatetech2/api/shields/ShieldPermissions.java index c0cf3920c..da06013bd 100644 --- a/src/api/java/stargatetech2/api/shields/ShieldPermissions.java +++ b/src/api/java/stargatetech2/api/shields/ShieldPermissions.java @@ -1,6 +1,7 @@ package stargatetech2.api.shields; -import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityMinecart; @@ -13,21 +14,22 @@ import net.minecraft.nbt.NBTTagCompound; public class ShieldPermissions { // Permission Flags - public static final int PERM_PLAYER = 0x01; - public static final int PERM_VILLAGER = 0x02; - public static final int PERM_ANIMAL = 0x04; - public static final int PERM_MONSTER = 0x08; - public static final int PERM_MINECART = 0x10; + public static final int PERM_FRIEND = 0x01; + public static final int PERM_PLAYER = 0x02; + public static final int PERM_VILLAGER = 0x04; + public static final int PERM_ANIMAL = 0x08; + public static final int PERM_MONSTER = 0x10; + public static final int PERM_VESSEL = 0x20; private int permValue = 0; - private ArrayList playerExceptions = new ArrayList(); + private LinkedList playerExceptions = new LinkedList(); /** * @return A default ShieldPermissions object. */ public static ShieldPermissions getDefault(){ ShieldPermissions perm = new ShieldPermissions(); - perm.allow(PERM_PLAYER); + perm.allow(PERM_FRIEND | PERM_PLAYER); return perm; } @@ -68,7 +70,7 @@ public class ShieldPermissions { * @return A list of strings containing the names of all the players * who currently are exceptions to the player permission setting. */ - public ArrayList getExceptionList(){ + public List getExceptionList(){ return playerExceptions; } @@ -96,7 +98,7 @@ public class ShieldPermissions { }else if(entity instanceof EntityMob){ allow = hasBit(PERM_MONSTER); }else if(entity instanceof EntityMinecart){ - allow = hasBit(PERM_MINECART); + allow = hasBit(PERM_VESSEL); } if(allow && entity.riddenByEntity != null && doDismount && entity.worldObj.isRemote == false){ if(!isEntityAllowed(entity.riddenByEntity, true)){ @@ -141,7 +143,7 @@ public class ShieldPermissions { if(nbt != null){ int exceptions = nbt.getInteger("exceptions"); permissions.permValue = nbt.getInteger("permValue"); - permissions.playerExceptions = new ArrayList(exceptions); + permissions.playerExceptions = new LinkedList(); for(int i = 0; i < exceptions; i++){ permissions.setPlayerException(nbt.getString("pex" + i)); } 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 f43ae4a63..e121bac7e 100644 --- a/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala +++ b/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala @@ -86,13 +86,12 @@ class ClassTransformer extends IClassTransformer { def ensureStargateTechCompatibility(basicClass: Array[Byte]): Array[Byte] = { if (!Mods.StargateTech2.isAvailable) { - return basicClass + // No SGT2 or version is too old, abstract bus API doesn't exist. + val classNode = newClassNode(basicClass) + classNode.interfaces.remove("stargatetech2/api/bus/IBusDevice") + writeClass(classNode) } - - // Version of SGT2 is too old, abstract bus API doesn't exist. - val classNode = newClassNode(basicClass) - classNode.interfaces.remove("stargatetech2/api/bus/IBusDevice") - writeClass(classNode) + else basicClass } def injectEnvironmentImplementation(classNode: ClassNode, basicClass: Array[Byte]): Array[Byte] = { diff --git a/src/main/scala/li/cil/oc/server/driver/item/AbstractBusCard.scala b/src/main/scala/li/cil/oc/server/driver/item/AbstractBusCard.scala index a7bf25d28..717a5aa94 100644 --- a/src/main/scala/li/cil/oc/server/driver/item/AbstractBusCard.scala +++ b/src/main/scala/li/cil/oc/server/driver/item/AbstractBusCard.scala @@ -5,13 +5,13 @@ import li.cil.oc.api.driver.Slot import li.cil.oc.server.component import li.cil.oc.util.mods.Mods import net.minecraft.item.ItemStack -import net.minecraft.tileentity.{TileEntity => MCTileEntity} +import net.minecraft.tileentity.TileEntity import stargatetech2.api.bus.IBusDevice object AbstractBusCard extends Item { override def worksWith(stack: ItemStack) = isOneOf(stack, Items.abstractBus) - override def createEnvironment(stack: ItemStack, container: MCTileEntity) = if (Mods.StargateTech2.isAvailable) container match { + override def createEnvironment(stack: ItemStack, container: TileEntity) = if (Mods.StargateTech2.isAvailable) container match { case device: IBusDevice => new component.AbstractBus(device) case _ => null } From d0d4f502ba95c0bef883058884ebe5da9f3cfbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 20 Apr 2014 22:12:00 +0200 Subject: [PATCH 12/14] Made files opened in read mode seekable more reliably. --- .../scala/li/cil/oc/server/fs/Buffered.scala | 2 +- .../li/cil/oc/server/fs/CC15FileSystem.scala | 4 +- .../li/cil/oc/server/fs/CC16FileSystem.scala | 4 +- .../server/fs/FileInputStreamFileSystem.scala | 5 +- .../oc/server/fs/InputStreamFileSystem.scala | 80 +++++++++++++------ .../cil/oc/server/fs/VirtualFileSystem.scala | 4 +- .../fs/ZipFileInputStreamFileSystem.scala | 4 +- 7 files changed, 69 insertions(+), 34 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/fs/Buffered.scala b/src/main/scala/li/cil/oc/server/fs/Buffered.scala index c90e3a383..c9d0dde26 100644 --- a/src/main/scala/li/cil/oc/server/fs/Buffered.scala +++ b/src/main/scala/li/cil/oc/server/fs/Buffered.scala @@ -94,7 +94,7 @@ trait Buffered extends OutputStreamFileSystem { FileUtils.deleteQuietly(childFile) childFile.createNewFile() val out = new io.FileOutputStream(childFile).getChannel - val in = java.nio.channels.Channels.newChannel(openInputStream(childPath).get) + val in = openInputChannel(childPath).get out.transferFrom(in, 0, Long.MaxValue) out.close() in.close() diff --git a/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala b/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala index 626933f3e..3d8708c8b 100644 --- a/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala @@ -25,8 +25,8 @@ class CC15FileSystem(val mount: IMount) extends InputStreamFileSystem { // ----------------------------------------------------------------------- // - protected def openInputStream(path: String) = try { - Some(mount.openForRead(path)) + protected def openInputChannel(path: String) = try { + Some(new InputFileChannel(mount.openForRead(path))) } catch { case _: Throwable => None } diff --git a/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala b/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala index 95110b4b3..e412dd54b 100644 --- a/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala @@ -25,8 +25,8 @@ class CC16FileSystem(val mount: IMount) extends InputStreamFileSystem { // ----------------------------------------------------------------------- // - protected def openInputStream(path: String) = try { - Some(mount.openForRead(path)) + protected def openInputChannel(path: String) = try { + Some(new InputFileChannel(mount.openForRead(path))) } catch { case _: Throwable => None } diff --git a/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala index 90e840f25..33dfa1988 100644 --- a/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala @@ -1,6 +1,7 @@ package li.cil.oc.server.fs import java.io +import java.nio.channels.SeekableByteChannel trait FileInputStreamFileSystem extends InputStreamFileSystem { protected val root: io.File @@ -43,6 +44,6 @@ trait FileInputStreamFileSystem extends InputStreamFileSystem { // ----------------------------------------------------------------------- // - override protected def openInputStream(path: String): Option[io.InputStream] = - Some(new io.FileInputStream(new io.File(root, path))) + override protected def openInputChannel(path: String): Option[SeekableByteChannel] = + Some(new io.RandomAccessFile(new io.File(root, path), "r").getChannel) } diff --git a/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala index 59dd9425c..fe06064c1 100644 --- a/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala @@ -1,10 +1,12 @@ package li.cil.oc.server.fs -import java.io.{FileNotFoundException, IOException, InputStream} +import java.io.{FileNotFoundException, IOException} import li.cil.oc.api import li.cil.oc.api.fs.Mode import net.minecraft.nbt.{NBTTagList, NBTTagCompound} import scala.collection.mutable +import java.nio.channels.SeekableByteChannel +import java.nio.ByteBuffer trait InputStreamFileSystem extends api.fs.FileSystem { private val handles = mutable.Map.empty[Int, Handle] @@ -25,9 +27,9 @@ trait InputStreamFileSystem extends api.fs.FileSystem { override def open(path: String, mode: Mode) = this.synchronized(if (mode == Mode.Read && exists(path) && !isDirectory(path)) { val handle = Iterator.continually((Math.random() * Int.MaxValue).toInt + 1).filterNot(handles.contains).next() - openInputStream(path) match { - case Some(stream) => - handles += handle -> new Handle(this, handle, path, stream) + openInputChannel(path) match { + case Some(channel) => + handles += handle -> new Handle(this, handle, path, channel) handle case _ => throw new FileNotFoundException() } @@ -49,10 +51,10 @@ trait InputStreamFileSystem extends api.fs.FileSystem { val handle = handleNbt.getInteger("handle") val path = handleNbt.getString("path") val position = handleNbt.getLong("position") - openInputStream(path) match { - case Some(stream) => - val fileHandle = new Handle(this, handle, path, stream) - fileHandle.position = stream.skip(position) // May be != position if the file changed since we saved. + openInputChannel(path) match { + case Some(channel) => + val fileHandle = new Handle(this, handle, path, channel) + channel.position(position) handles += handle -> fileHandle case _ => // The source file seems to have disappeared since last time. } @@ -62,7 +64,7 @@ trait InputStreamFileSystem extends api.fs.FileSystem { override def save(nbt: NBTTagCompound) = this.synchronized { val handlesNbt = new NBTTagList() for (file <- handles.values) { - assert(!file.isClosed) + assert(file.channel.isOpen) val handleNbt = new NBTTagCompound() handleNbt.setInteger("handle", file.handle) handleNbt.setString("path", file.path) @@ -74,33 +76,65 @@ trait InputStreamFileSystem extends api.fs.FileSystem { // ----------------------------------------------------------------------- // - protected def openInputStream(path: String): Option[InputStream] + protected def openInputChannel(path: String): Option[SeekableByteChannel] + + protected class InputFileChannel(val inputStream: java.io.InputStream) extends SeekableByteChannel { + var isOpen = true + + private var position_ = 0L + + override def close() = inputStream.close() + + override def truncate(size: Long) = throw new java.io.IOException() + + override def size() = inputStream.available() + + override def position(newPosition: Long) = { + inputStream.reset() + position_ = inputStream.skip(newPosition) + this + } + + override def position = position_ + + override def write(src: ByteBuffer) = throw new java.io.IOException() + + override def read(dst: ByteBuffer): Int = { + if (dst.hasArray) { + inputStream.read(dst.array()) + } + else { + val count = dst.limit - dst.position + for (i <- 0 until count) { + inputStream.read match { + case -1 => return i + case b => dst.put(b.toByte) + } + } + count + } + } + } // ----------------------------------------------------------------------- // - private class Handle(val owner: InputStreamFileSystem, val handle: Int, val path: String, val stream: InputStream) extends api.fs.Handle { - var isClosed = false - var position = 0L + private class Handle(val owner: InputStreamFileSystem, val handle: Int, val path: String, val channel: SeekableByteChannel) extends api.fs.Handle { + override def position = channel.position override def length = owner.size(path) - override def close() = if (!isClosed) { - isClosed = true + override def close() = if (channel.isOpen) { owner.handles -= handle - stream.close() + channel.close() } override def read(into: Array[Byte]) = { - val read = stream.read(into) - if (read >= 0) - position += read - read + channel.read(ByteBuffer.wrap(into)) } override def seek(to: Long) = { - stream.reset() - position = stream.skip(to) - position + channel.position(to) + channel.position } override def write(value: Array[Byte]) = throw new IOException("bad file descriptor") diff --git a/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala index 496170bbb..9692a67e9 100644 --- a/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala @@ -97,9 +97,9 @@ trait VirtualFileSystem extends OutputStreamFileSystem { // ----------------------------------------------------------------------- // - protected def openInputStream(path: String) = + protected def openInputChannel(path: String) = root.get(segments(path)) match { - case Some(obj: VirtualFile) => obj.openInputStream() + case Some(obj: VirtualFile) => obj.openInputStream().map(new InputFileChannel(_)) case _ => None } diff --git a/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala index ceda7b062..9467d6128 100644 --- a/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala @@ -58,8 +58,8 @@ class ZipFileInputStreamFileSystem(private val archive: ArchiveDirectory) extend // ----------------------------------------------------------------------- // - override protected def openInputStream(path: String) = ZipFileInputStreamFileSystem.synchronized { - entry(path).map(_.openStream()) + override protected def openInputChannel(path: String) = ZipFileInputStreamFileSystem.synchronized { + entry(path).map(entry => new InputFileChannel(entry.openStream())) } // ----------------------------------------------------------------------- // From 59d7c7542862ca417df75edf1ccad3eba3a93467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 20 Apr 2014 22:19:12 +0200 Subject: [PATCH 13/14] Fixed options not being passed along properly by shell.execute. --- src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua b/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua index 342f9f04b..e3f31636f 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua @@ -130,7 +130,7 @@ if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then end else -- execute command. - local result = table.pack(execute(table.unpack(args))) + local result = table.pack(execute(...)) if not result[1] then error(result[2]) end From fc96037ed9b553045d6f7ca574502f58e0ed2f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 21 Apr 2014 13:39:59 +0200 Subject: [PATCH 14/14] Got rid of the Java 1.7 interface. Avoid duplicate listing of file system entries in compound file systems if one is a file and the other a directory, closes #219. --- .../li/cil/oc/server/fs/CC15FileSystem.scala | 2 +- .../li/cil/oc/server/fs/CC16FileSystem.scala | 2 +- .../fs/CompositeReadOnlyFileSystem.scala | 30 ++++--- .../server/fs/FileInputStreamFileSystem.scala | 22 +++++- .../oc/server/fs/InputStreamFileSystem.scala | 79 ++++++++++--------- .../cil/oc/server/fs/VirtualFileSystem.scala | 2 +- .../fs/ZipFileInputStreamFileSystem.scala | 2 +- 7 files changed, 86 insertions(+), 53 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala b/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala index 3d8708c8b..e8440451a 100644 --- a/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala @@ -26,7 +26,7 @@ class CC15FileSystem(val mount: IMount) extends InputStreamFileSystem { // ----------------------------------------------------------------------- // protected def openInputChannel(path: String) = try { - Some(new InputFileChannel(mount.openForRead(path))) + Some(new InputStreamChannel(mount.openForRead(path))) } catch { case _: Throwable => None } diff --git a/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala b/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala index e412dd54b..0ea017cc3 100644 --- a/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala @@ -26,7 +26,7 @@ class CC16FileSystem(val mount: IMount) extends InputStreamFileSystem { // ----------------------------------------------------------------------- // protected def openInputChannel(path: String) = try { - Some(new InputFileChannel(mount.openForRead(path))) + Some(new InputStreamChannel(mount.openForRead(path))) } catch { case _: Throwable => None } diff --git a/src/main/scala/li/cil/oc/server/fs/CompositeReadOnlyFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/CompositeReadOnlyFileSystem.scala index 12cf6ad55..86840765e 100644 --- a/src/main/scala/li/cil/oc/server/fs/CompositeReadOnlyFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/CompositeReadOnlyFileSystem.scala @@ -35,16 +35,26 @@ class CompositeReadOnlyFileSystem(factories: mutable.LinkedHashMap[String, Calla override def lastModified(path: String) = findFileSystem(path).fold(0L)(_.lastModified(path)) - override def list(path: String) = parts.values.foldLeft(Array.empty[String])((acc, fs) => { - if (fs.exists(path)) try { - val l = fs.list(path) - if (l != null) acc ++ l else acc - } - catch { - case _: Throwable => acc - } - else acc - }) + override def list(path: String) = if (isDirectory(path)) { + parts.values.foldLeft(mutable.Set.empty[String])((acc, fs) => { + if (fs.exists(path)) try { + val l = fs.list(path) + if (l != null) for (e <- l) { + val f = e.stripSuffix("/") + val d = f + "/" + // Avoid duplicates and always only use the latest entry. + acc -= f + acc -= d + acc += e + } + } + catch { + case _: Throwable => + } + acc + }).toArray + } + else null // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala index 33dfa1988..56322c7d4 100644 --- a/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala @@ -1,7 +1,6 @@ package li.cil.oc.server.fs import java.io -import java.nio.channels.SeekableByteChannel trait FileInputStreamFileSystem extends InputStreamFileSystem { protected val root: io.File @@ -44,6 +43,23 @@ trait FileInputStreamFileSystem extends InputStreamFileSystem { // ----------------------------------------------------------------------- // - override protected def openInputChannel(path: String): Option[SeekableByteChannel] = - Some(new io.RandomAccessFile(new io.File(root, path), "r").getChannel) + override protected def openInputChannel(path: String) = Some(new FileChannel(new io.File(root, path))) + + protected class FileChannel(file: io.File) extends InputChannel { + val channel = new io.RandomAccessFile(file, "r").getChannel + + override def position(newPosition: Long) = { + channel.position(newPosition) + channel.position + } + + override def position = channel.position + + override def close() = channel.close() + + override def isOpen = channel.isOpen + + override def read(dst: Array[Byte]) = channel.read(java.nio.ByteBuffer.wrap(dst)) + } + } diff --git a/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala index fe06064c1..f9fa39c5f 100644 --- a/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala @@ -5,7 +5,7 @@ import li.cil.oc.api import li.cil.oc.api.fs.Mode import net.minecraft.nbt.{NBTTagList, NBTTagCompound} import scala.collection.mutable -import java.nio.channels.SeekableByteChannel +import java.nio.channels.ReadableByteChannel import java.nio.ByteBuffer trait InputStreamFileSystem extends api.fs.FileSystem { @@ -76,49 +76,61 @@ trait InputStreamFileSystem extends api.fs.FileSystem { // ----------------------------------------------------------------------- // - protected def openInputChannel(path: String): Option[SeekableByteChannel] + protected def openInputChannel(path: String): Option[InputChannel] - protected class InputFileChannel(val inputStream: java.io.InputStream) extends SeekableByteChannel { + protected trait InputChannel extends ReadableByteChannel { + def isOpen: Boolean + + def close() + + def position: Long + + def position(newPosition: Long): Long + + def read(dst: Array[Byte]): Int + + override def read(dst: ByteBuffer) = { + if (dst.hasArray) { + read(dst.array()) + } + else { + val count = dst.limit - dst.position + val buffer = new Array[Byte](count) + val n = read(buffer) + dst.put(buffer, 0, n) + n + } + } + } + + protected class InputStreamChannel(val inputStream: java.io.InputStream) extends InputChannel { var isOpen = true private var position_ = 0L - override def close() = inputStream.close() - - override def truncate(size: Long) = throw new java.io.IOException() - - override def size() = inputStream.available() - - override def position(newPosition: Long) = { - inputStream.reset() - position_ = inputStream.skip(newPosition) - this + override def close() = if (isOpen) { + isOpen = false + inputStream.close() } override def position = position_ - override def write(src: ByteBuffer) = throw new java.io.IOException() + override def position(newPosition: Long) = { + inputStream.reset() + position_ = inputStream.skip(newPosition) + position_ + } - override def read(dst: ByteBuffer): Int = { - if (dst.hasArray) { - inputStream.read(dst.array()) - } - else { - val count = dst.limit - dst.position - for (i <- 0 until count) { - inputStream.read match { - case -1 => return i - case b => dst.put(b.toByte) - } - } - count - } + override def read(dst: Array[Byte]) = { + val read = inputStream.read(dst) + position_ += read + read } } // ----------------------------------------------------------------------- // - private class Handle(val owner: InputStreamFileSystem, val handle: Int, val path: String, val channel: SeekableByteChannel) extends api.fs.Handle { + private class Handle(val owner: InputStreamFileSystem, val handle: Int, val path: String, val channel: InputChannel) extends api.fs.Handle { override def position = channel.position override def length = owner.size(path) @@ -128,14 +140,9 @@ trait InputStreamFileSystem extends api.fs.FileSystem { channel.close() } - override def read(into: Array[Byte]) = { - channel.read(ByteBuffer.wrap(into)) - } + override def read(into: Array[Byte]) = channel.read(into) - override def seek(to: Long) = { - channel.position(to) - channel.position - } + override def seek(to: Long) = channel.position(to) override def write(value: Array[Byte]) = throw new IOException("bad file descriptor") } diff --git a/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala index 9692a67e9..4ed8e0864 100644 --- a/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala @@ -99,7 +99,7 @@ trait VirtualFileSystem extends OutputStreamFileSystem { protected def openInputChannel(path: String) = root.get(segments(path)) match { - case Some(obj: VirtualFile) => obj.openInputStream().map(new InputFileChannel(_)) + case Some(obj: VirtualFile) => obj.openInputStream().map(new InputStreamChannel(_)) case _ => None } diff --git a/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala index 9467d6128..790cd5761 100644 --- a/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala @@ -59,7 +59,7 @@ class ZipFileInputStreamFileSystem(private val archive: ArchiveDirectory) extend // ----------------------------------------------------------------------- // override protected def openInputChannel(path: String) = ZipFileInputStreamFileSystem.synchronized { - entry(path).map(entry => new InputFileChannel(entry.openStream())) + entry(path).map(entry => new InputStreamChannel(entry.openStream())) } // ----------------------------------------------------------------------- //