From c5cb7287c2dd10fe4bbbf6257d77bc2dd8b7065e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 24 Feb 2014 22:52:35 +0100 Subject: [PATCH 01/12] simplified autocreate method; added nil check for timer cleanup --- .../lua/component/internet/bin/irc.lua | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua index ebba420c7..65e2bf9c3 100644 --- a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua +++ b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua @@ -41,12 +41,8 @@ end -- utility method for reply tracking tables. function autocreate(table, key) - local value = rawget(table, key) - if not value then - value = {} - rawset(table, key, value) - end - return value + table[key] = {} + return table[key] end -- extract nickname from identity. @@ -172,22 +168,22 @@ local function handleCommand(prefix, command, args, message) print(message) elseif command == commands.RPL_WHOISUSER then local nick = args[2]:lower() - whois[nick].nick = nick + whois[nick].nick = args[2] whois[nick].user = args[3] whois[nick].host = args[4] whois[nick].realName = message elseif command == commands.RPL_WHOISSERVER then - local nick = args[2] + local nick = args[2]:lower() whois[nick].server = args[3] whois[nick].serverInfo = message elseif command == commands.RPL_WHOISOPERATOR then - local nick = args[2] + local nick = args[2]:lower() whois[nick].isOperator = true elseif command == commands.RPL_WHOISIDLE then - local nick = args[2] + local nick = args[2]:lower() whois[nick].idle = tonumber(args[3]) elseif command == commands.RPL_ENDOFWHOIS then - local nick = args[2] + local nick = args[2]:lower() local info = whois[nick] print("Nick: " .. info.nick) print("User name: " .. info.user) @@ -198,7 +194,7 @@ local function handleCommand(prefix, command, args, message) print("Idle for: " .. info.idle) whois[nick] = nil elseif command == commands.RPL_WHOISCHANNELS then - local nick = args[1] + local nick = args[2]:lower() whois[nick].channels = message elseif command == commands.RPL_CHANNELMODEIS then print("Channel mode for " .. args[1] .. ": " .. args[2] .. "(" .. args[3] .. ")") @@ -368,7 +364,9 @@ if sock then sock:write("QUIT\r\n") sock:close() end -event.cancel(timer) +if timer then + event.cancel(timer) +end if not result then error(reason, 0) From cd490f7ae2c8f72b4b43b89e635dc2b7a8b4467a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 24 Feb 2014 22:58:24 +0100 Subject: [PATCH 02/12] dem spaces before brackets --- .../assets/opencomputers/lua/component/internet/bin/irc.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua index 65e2bf9c3..68961055f 100644 --- a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua +++ b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua @@ -189,7 +189,7 @@ local function handleCommand(prefix, command, args, message) print("User name: " .. info.user) print("Real name: " .. info.realName) print("Host: " .. info.host) - print("Server: " .. info.server .. "(" .. info.serverInfo .. ")") + print("Server: " .. info.server .. " (" .. info.serverInfo .. ")") print("Channels: " .. info.channels) print("Idle for: " .. info.idle) whois[nick] = nil @@ -197,7 +197,7 @@ local function handleCommand(prefix, command, args, message) local nick = args[2]:lower() whois[nick].channels = message elseif command == commands.RPL_CHANNELMODEIS then - print("Channel mode for " .. args[1] .. ": " .. args[2] .. "(" .. args[3] .. ")") + print("Channel mode for " .. args[1] .. ": " .. args[2] .. " (" .. args[3] .. ")") elseif command == commands.RPL_NOTOPIC then print("No topic is set for " .. args[1] .. ".") elseif command == commands.RPL_TOPIC then From 6116ef39428b67081f782a4b9eca5b17e5793fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 24 Feb 2014 23:26:56 +0100 Subject: [PATCH 03/12] not sending nil results from lua --- .../assets/opencomputers/lua/component/internet/bin/irc.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua index 68961055f..7675d2d90 100644 --- a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua +++ b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua @@ -338,7 +338,7 @@ local result, reason = pcall(function() print("Error: " .. tostring(reason)) elseif type(reason) == "function" then callback = reason - else + elseif reason then line = tostring(reason) end end From a9faf1c477a9978bed5acbc0ec60bd9dae5f2036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 25 Feb 2014 00:06:11 +0100 Subject: [PATCH 04/12] nil checks for whois stuffs --- .../lua/component/internet/bin/irc.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua index 7675d2d90..d8749ecc1 100644 --- a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua +++ b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua @@ -185,13 +185,13 @@ local function handleCommand(prefix, command, args, message) elseif command == commands.RPL_ENDOFWHOIS then local nick = args[2]:lower() local info = whois[nick] - print("Nick: " .. info.nick) - print("User name: " .. info.user) - print("Real name: " .. info.realName) - print("Host: " .. info.host) - print("Server: " .. info.server .. " (" .. info.serverInfo .. ")") - print("Channels: " .. info.channels) - print("Idle for: " .. info.idle) + if info.nick then print("Nick: " .. info.nick) end + if info.user then print("User name: " .. info.user) end + if info.realName then print("Real name: " .. info.realName) end + if info.host then print("Host: " .. info.host) end + if info.server then print("Server: " .. info.server .. (info.serverInfo and (" (" .. info.serverInfo .. ")") or "")) end + if info.channels then print("Channels: " .. info.channels) end + if info.idle then print("Idle for: " .. info.idle) end whois[nick] = nil elseif command == commands.RPL_WHOISCHANNELS then local nick = args[2]:lower() From 55a90f8b63671c9fb9b88a6f5ef521d126cd9d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 26 Feb 2014 00:34:01 +0100 Subject: [PATCH 05/12] fixed iron nugget recipe registration (stupid initialization order mix-up) --- src/main/java/li/cil/oc/Items.scala | 7 ++++--- .../opencomputers/lua/component/internet/bin/irc.lua | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/li/cil/oc/Items.scala b/src/main/java/li/cil/oc/Items.scala index 1535c50e5..257e09a22 100644 --- a/src/main/java/li/cil/oc/Items.scala +++ b/src/main/java/li/cil/oc/Items.scala @@ -95,9 +95,6 @@ object Items { upgradeGenerator = Recipes.addItem(new item.UpgradeGenerator(multi), "generatorUpgrade") ironNugget = new item.IronNugget(multi) - if (OreDictionary.getOres("nuggetIron").exists(ironNugget.createItemStack().isItemEqual)) { - Recipes.addItem(ironNugget, "nuggetIron") - } cuttingWire = Recipes.addItem(new item.CuttingWire(multi), "cuttingWire") acid = Recipes.addItem(new item.Acid(multi), "acid") @@ -182,6 +179,10 @@ object Items { register("oc:craftingAcid", acid.createItemStack()) register("oc:craftingGenerator", upgradeGenerator.createItemStack()) register("oc:craftingSolarGenerator", upgradeSolarGenerator.createItemStack()) + + if (OreDictionary.getOres("nuggetIron").exists(ironNugget.createItemStack().isItemEqual)) { + Recipes.addItem(ironNugget, "nuggetIron") + } } def register(name: String, item: ItemStack) { diff --git a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua index d8749ecc1..5eddd65bb 100644 --- a/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua +++ b/src/main/resources/assets/opencomputers/lua/component/internet/bin/irc.lua @@ -306,7 +306,9 @@ local result, reason = pcall(function() print("[" .. (target or "?") .. "] me: " .. line, true) if line:lower():sub(1, 5) == "/msg " then local user, message = line:sub(6):match("^(%S+) (.+)$") - message = text.trim(message) + if message then + message = text.trim(message) + end if not user or not message or message == "" then print("Invalid use of /msg. Usage: /msg nick|channel message.") line = "" From 6f8bb90f2458fe67c94fc248cab1a24b84debb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 26 Feb 2014 01:13:53 +0100 Subject: [PATCH 06/12] fixed a bug in LuaJ's string.match. hopefully. closes #138 --- src/main/required/org/luaj/vm3/lib/StringLib.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/required/org/luaj/vm3/lib/StringLib.java b/src/main/required/org/luaj/vm3/lib/StringLib.java index 317d68920..afde5979b 100644 --- a/src/main/required/org/luaj/vm3/lib/StringLib.java +++ b/src/main/required/org/luaj/vm3/lib/StringLib.java @@ -1155,7 +1155,7 @@ public class StringLib extends TwoArgFunction { if ( poff == plen || poff + 1 == plen ) { error( "unbalanced pattern" ); } - if ( s.luaByte( soff ) != p.luaByte( poff ) ) + if ( soff >= s.length() || s.luaByte( soff ) != p.luaByte( poff ) ) return -1; else { int b = p.luaByte( poff ); From 8072a50fd2a10f49700f11dc9de19be3f69a39ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 26 Feb 2014 17:02:34 +0100 Subject: [PATCH 07/12] basics for hologram projector --- src/main/java/li/cil/oc/Blocks.scala | 5 + .../java/li/cil/oc/client/PacketHandler.scala | 13 ++ src/main/java/li/cil/oc/client/Proxy.scala | 1 + .../li/cil/oc/client/TexturePreloader.scala | 1 + .../tileentity/HologramRenderer.scala | 117 ++++++++++++++++++ .../java/li/cil/oc/common/PacketType.scala | 1 + .../li/cil/oc/common/block/Delegate.scala | 4 +- .../li/cil/oc/common/block/Hologram.scala | 33 +++++ .../cil/oc/common/tileentity/Hologram.scala | 93 ++++++++++++++ .../java/li/cil/oc/server/PacketSender.scala | 10 ++ .../opencomputers/recipes/default.recipes | 7 +- .../textures/blocks/hologram_effect.png | Bin 0 -> 157 bytes 12 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala create mode 100644 src/main/java/li/cil/oc/common/block/Hologram.scala create mode 100644 src/main/java/li/cil/oc/common/tileentity/Hologram.scala create mode 100644 src/main/resources/assets/opencomputers/textures/blocks/hologram_effect.png diff --git a/src/main/java/li/cil/oc/Blocks.scala b/src/main/java/li/cil/oc/Blocks.scala index 7055dccce..3447b55f4 100644 --- a/src/main/java/li/cil/oc/Blocks.scala +++ b/src/main/java/li/cil/oc/Blocks.scala @@ -21,6 +21,7 @@ object Blocks { var case1, case2, case3: Case = _ var diskDrive: DiskDrive = _ var keyboard: Keyboard = _ + var hologram: Hologram = _ var powerConverter: PowerConverter = _ var powerDistributor: PowerDistributor = _ var redstone: Redstone = _ @@ -56,6 +57,7 @@ object Blocks { GameRegistry.registerTileEntity(classOf[tileentity.Charger], Settings.namespace + "charger") GameRegistry.registerTileEntity(classOf[tileentity.DiskDrive], Settings.namespace + "disk_drive") GameRegistry.registerTileEntity(classOf[tileentity.Keyboard], Settings.namespace + "keyboard") + GameRegistry.registerTileEntity(classOf[tileentity.Hologram], Settings.namespace + "hologram") GameRegistry.registerTileEntity(classOf[tileentity.PowerConverter], Settings.namespace + "power_converter") GameRegistry.registerTileEntity(classOf[tileentity.PowerDistributor], Settings.namespace + "power_distributor") GameRegistry.registerTileEntity(classOf[tileentity.Redstone], Settings.namespace + "redstone") @@ -95,6 +97,9 @@ object Blocks { // v1.2.0 serverRack = Recipes.addBlock(new Rack(blockSpecialWithRedstone), "rack") + // v1.2.2 + hologram = Recipes.addBlock(new Hologram(blockSpecial), "hologram") + register("oc:craftingCable", cable.createItemStack()) register("oc:craftingCapacitor", capacitor.createItemStack()) register("oc:craftingCaseTier1", case1.createItemStack()) diff --git a/src/main/java/li/cil/oc/client/PacketHandler.scala b/src/main/java/li/cil/oc/client/PacketHandler.scala index f209814f0..47a7c593a 100644 --- a/src/main/java/li/cil/oc/client/PacketHandler.scala +++ b/src/main/java/li/cil/oc/client/PacketHandler.scala @@ -26,6 +26,7 @@ class PacketHandler extends CommonPacketHandler { case PacketType.ChargerState => onChargerState(p) case PacketType.ComputerState => onComputerState(p) case PacketType.ComputerUserList => onComputerUserList(p) + case PacketType.HologramSet => onHologramSet(p) case PacketType.PowerState => onPowerState(p) case PacketType.RedstoneState => onRedstoneState(p) case PacketType.RobotAnimateSwing => onRobotAnimateSwing(p) @@ -100,6 +101,18 @@ class PacketHandler extends CommonPacketHandler { case _ => // Invalid packet. } + def onHologramSet(p: PacketParser) = + p.readTileEntity[Hologram]() match { + case Some(t) => + val length = p.readInt() + val count = math.max(0, math.min(length, t.volume.length)) + for (i <- 0 until count) { + t.volume(i) = p.readInt() + } + t.dirty = true + case _ => // Invalid packet. + } + def onPowerState(p: PacketParser) = p.readTileEntity[PowerInformation]() match { case Some(t) => diff --git a/src/main/java/li/cil/oc/client/Proxy.scala b/src/main/java/li/cil/oc/client/Proxy.scala index 6e1862247..c72df6230 100644 --- a/src/main/java/li/cil/oc/client/Proxy.scala +++ b/src/main/java/li/cil/oc/client/Proxy.scala @@ -28,6 +28,7 @@ private[oc] class Proxy extends CommonProxy { ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Cable], CableRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Case], CaseRenderer) + ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Hologram], HologramRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.PowerDistributor], PowerDistributorRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Rack], RackRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.RobotProxy], RobotRenderer) diff --git a/src/main/java/li/cil/oc/client/TexturePreloader.scala b/src/main/java/li/cil/oc/client/TexturePreloader.scala index e489214ba..b6e7bc80e 100644 --- a/src/main/java/li/cil/oc/client/TexturePreloader.scala +++ b/src/main/java/li/cil/oc/client/TexturePreloader.scala @@ -22,6 +22,7 @@ object TexturePreloader extends ResourceManagerReloadListener { val blockCable = new ResourceLocation(Settings.resourceDomain, "textures/blocks/cable.png") val blockCaseFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/case_front_on.png") + val blockHologram = new ResourceLocation(Settings.resourceDomain, "textures/blocks/hologram_effect.png") val blockPowerDistributorOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/power_distributor_on.png") val blockRackFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/rack_front_on.png") val blockRobot = new ResourceLocation(Settings.resourceDomain, "textures/blocks/robot.png") diff --git a/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala new file mode 100644 index 000000000..c6a8ff2be --- /dev/null +++ b/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -0,0 +1,117 @@ +package li.cil.oc.client.renderer.tileentity + +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer +import net.minecraft.tileentity.TileEntity +import li.cil.oc.common.tileentity.Hologram +import net.minecraft.client.renderer.Tessellator +import org.lwjgl.opengl.GL11 +import li.cil.oc.util.RenderState +import li.cil.oc.client.TexturePreloader +import net.minecraftforge.client.MinecraftForgeClient + +object HologramRenderer extends TileEntitySpecialRenderer { + override def renderTileEntityAt(te: TileEntity, x: Double, y: Double, z: Double, f: Float) { + if (MinecraftForgeClient.getRenderPass != 0) return + + val hologram = te.asInstanceOf[Hologram] + + GL11.glPushAttrib(0xFFFFFFFF) + GL11.glDisable(GL11.GL_CULL_FACE) + +// RenderState.disableLighting() + RenderState.makeItBlend() + + GL11.glPushMatrix() + GL11.glTranslated(x - 1, y + 0.5, z - 1) + + def isSolid(hx: Int, hy: Int, hz: Int) = { + hx >= 0 && hy >= 0 && hz >= 0 && hx < hologram.width && hy < hologram.height && hz < hologram.width && + (hologram.volume(hx + hz * hologram.width) & (1 << hy)) != 0 + } + + bindTexture(TexturePreloader.blockHologram) + val t = Tessellator.instance + t.startDrawingQuads() + t.setColorRGBA_F(1, 1, 1, 0.7f) + + val s = 1f / 16f + for (hx <- 0 until hologram.width) { + val wx = hx * s + for (hz <- 0 until hologram.width) { + val wz = hz * s + for (hy <- 0 until hologram.height) { + val wy = hy * s + + if (isSolid(hx, hy, hz)) { + /* + 0---1 + | N | + 0---3---2---1---0 + | W | U | E | D | + 5---6---7---4---5 + | S | + 5---4 + */ + + // South + if (!isSolid(hx, hy, hz + 1)) { + t.setNormal(0, 0, 1) + t.addVertex(wx + s, wy + s, wz + s) // 5 + t.addVertex(wx + 0, wy + s, wz + s) // 4 + t.addVertex(wx + 0, wy + 0, wz + s) // 7 + t.addVertex(wx + s, wy + 0, wz + s) // 6 + } + // North + if (!isSolid(hx, hy, hz - 1)) { + t.setNormal(0, 0, -1) + t.addVertex(wx + s, wy + 0, wz + 0) // 3 + t.addVertex(wx + 0, wy + 0, wz + 0) // 2 + t.addVertex(wx + 0, wy + s, wz + 0) // 1 + t.addVertex(wx + s, wy + s, wz + 0) // 0 + } + + // East + if (!isSolid(hx + 1, hy, hz)) { + t.setNormal(1, 0, 0) + t.addVertex(wx + s, wy + s, wz + s) // 5 + t.addVertex(wx + s, wy + 0, wz + s) // 6 + t.addVertex(wx + s, wy + 0, wz + 0) // 3 + t.addVertex(wx + s, wy + s, wz + 0) // 0 + } + // West + if (!isSolid(hx - 1, hy, hz)) { + t.setNormal(-1, 0, 0) + t.addVertex(wx + 0, wy + 0, wz + s) // 7 + t.addVertex(wx + 0, wy + s, wz + s) // 4 + t.addVertex(wx + 0, wy + s, wz + 0) // 1 + t.addVertex(wx + 0, wy + 0, wz + 0) // 2 + } + + // Up + if (!isSolid(hx, hy + 1, hz)) { + t.setNormal(0, 1, 0) + t.addVertex(wx + s, wy + s, wz + 0) // 0 + t.addVertex(wx + 0, wy + s, wz + 0) // 1 + t.addVertex(wx + 0, wy + s, wz + s) // 4 + t.addVertex(wx + s, wy + s, wz + s) // 5 + } + // Down + if (!isSolid(hx, hy - 1, hz)) { + t.setNormal(0, -1, 0) + t.addVertex(wx + s, wy + 0, wz + s) // 6 + t.addVertex(wx + 0, wy + 0, wz + s) // 7 + t.addVertex(wx + 0, wy + 0, wz + 0) // 2 + t.addVertex(wx + s, wy + 0, wz + 0) // 3 + } + + } + } + } + } + + t.draw() + + GL11.glPopMatrix() + GL11.glPopAttrib() + } +} diff --git a/src/main/java/li/cil/oc/common/PacketType.scala b/src/main/java/li/cil/oc/common/PacketType.scala index eb98c912c..11013c6c1 100644 --- a/src/main/java/li/cil/oc/common/PacketType.scala +++ b/src/main/java/li/cil/oc/common/PacketType.scala @@ -8,6 +8,7 @@ object PacketType extends Enumeration { ChargerState, ComputerState, ComputerUserList, + HologramSet, PowerState, RedstoneState, RobotAnimateSwing, diff --git a/src/main/java/li/cil/oc/common/block/Delegate.scala b/src/main/java/li/cil/oc/common/block/Delegate.scala index 29defc757..626dc008f 100644 --- a/src/main/java/li/cil/oc/common/block/Delegate.scala +++ b/src/main/java/li/cil/oc/common/block/Delegate.scala @@ -41,11 +41,11 @@ trait Delegate { def canPlaceBlockOnSide(world: World, x: Int, y: Int, z: Int, side: ForgeDirection) = true - def bounds(world: World, x: Int, y: Int, z: Int) = + def bounds(world: IBlockAccess, x: Int, y: Int, z: Int) = AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 1, 1) def updateBounds(world: IBlockAccess, x: Int, y: Int, z: Int) = - parent.setBlockBounds(0, 0, 0, 1, 1, 1) + parent.setBlockBounds(bounds(world, x, y, z)) def intersect(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3) = parent.superCollisionRayTrace(world, x, y, z, origin, direction) diff --git a/src/main/java/li/cil/oc/common/block/Hologram.scala b/src/main/java/li/cil/oc/common/block/Hologram.scala new file mode 100644 index 000000000..9b926bb38 --- /dev/null +++ b/src/main/java/li/cil/oc/common/block/Hologram.scala @@ -0,0 +1,33 @@ +package li.cil.oc.common.block + +import java.util +import li.cil.oc.common.tileentity +import li.cil.oc.util.Tooltip +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.{ItemStack, EnumRarity} +import net.minecraft.world.{World, IBlockAccess} +import net.minecraftforge.common.ForgeDirection +import net.minecraft.util.AxisAlignedBB + +class Hologram(val parent: SpecialDelegator) extends SpecialDelegate { + val unlocalizedName = "Hologram" + + override def rarity = EnumRarity.rare + + override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { + tooltip.addAll(Tooltip.get(unlocalizedName)) + } + + override def luminance(world: IBlockAccess, x: Int, y: Int, z: Int) = 15 + + override def isSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.DOWN + + override def bounds(world: IBlockAccess, x: Int, y: Int, z: Int) = + AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 0.2f, 1) + + // ----------------------------------------------------------------------- // + + override def hasTileEntity = true + + override def createTileEntity(world: World) = Some(new tileentity.Hologram()) +} diff --git a/src/main/java/li/cil/oc/common/tileentity/Hologram.scala b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala new file mode 100644 index 000000000..94dba39ce --- /dev/null +++ b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala @@ -0,0 +1,93 @@ +package li.cil.oc.common.tileentity + +import cpw.mods.fml.relauncher.{Side, SideOnly} +import li.cil.oc.api.network._ +import li.cil.oc.server.{PacketSender => ServerPacketSender} +import li.cil.oc.{Settings, api} +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.AxisAlignedBB +import net.minecraftforge.common.ForgeDirection + +class Hologram extends Environment with SidedEnvironment { + val node = api.Network.newNode(this, Visibility.Network). + withComponent("hologram"). + withConnector(). + create() + + val width = 3 * 16 + + val height = 2 * 16 // 32 bit in an int + + val volume = new Array[Int](width * width) + + // Whether we need to send an update packet/recompile our display list. + var dirty = false + + // Time to wait before sending another update packet. + var cooldown = 0 + + // ----------------------------------------------------------------------- // + + override def canConnect(side: ForgeDirection) = side != ForgeDirection.UP + + override def sidedNode(side: ForgeDirection) = node + + // ----------------------------------------------------------------------- // + + @Callback(direct = true, doc = """function(x:number, z:number):number -- Returns the bit mask representing the specified column.""") + def get(computer: Context, args: Arguments): Array[AnyRef] = { + val x = args.checkInteger(0) - 1 + val z = args.checkInteger(1) - 1 + result(volume(x + z * width)) + } + + @Callback(direct = true, limit = 256, doc = """function(x:number, z:number, value:number) -- Set the bit mask for the specified column.""") + def set(computer: Context, args: Arguments): Array[AnyRef] = { + val x = args.checkInteger(0) - 1 + val z = args.checkInteger(1) - 1 + val value = args.checkInteger(2) + volume(x + z * width) = value + dirty = true + null + } + + // ----------------------------------------------------------------------- // + + override def updateEntity() { + super.updateEntity() + if (isServer && dirty) { + cooldown -= 1 + if (cooldown <= 0) { + dirty = false + cooldown = 10 + ServerPacketSender.sendHologramSet(this) + } + } + } + + // ----------------------------------------------------------------------- // + + override def getRenderBoundingBox = AxisAlignedBB.getAABBPool.getAABB(xCoord - 1, yCoord, zCoord - 1, xCoord + 2, yCoord + 3, zCoord + 2) + + override def readFromNBT(nbt: NBTTagCompound) { + super.readFromNBT(nbt) + nbt.getIntArray(Settings.namespace + "volume").copyToArray(volume) + } + + override def writeToNBT(nbt: NBTTagCompound) { + super.writeToNBT(nbt) + nbt.setIntArray(Settings.namespace + "volume", volume) + } + + @SideOnly(Side.CLIENT) + override def readFromNBTForClient(nbt: NBTTagCompound) { + super.readFromNBTForClient(nbt) + nbt.getIntArray("volume").copyToArray(volume) + dirty = true + } + + override def writeToNBTForClient(nbt: NBTTagCompound) { + super.writeToNBTForClient(nbt) + nbt.setIntArray("volume", volume) + } +} diff --git a/src/main/java/li/cil/oc/server/PacketSender.scala b/src/main/java/li/cil/oc/server/PacketSender.scala index 2e4ee1aaa..2290137f8 100644 --- a/src/main/java/li/cil/oc/server/PacketSender.scala +++ b/src/main/java/li/cil/oc/server/PacketSender.scala @@ -55,6 +55,16 @@ object PacketSender { pb.sendToNearbyPlayers(t) } + def sendHologramSet(t: Hologram) { + val pb = new PacketBuilder(PacketType.HologramSet) + + pb.writeTileEntity(t) + pb.writeInt(t.volume.length) + t.volume.foreach(pb.writeInt) + + pb.sendToNearbyPlayers(t) + } + def sendPowerState(t: PowerInformation) { val pb = new PacketBuilder(PacketType.PowerState) diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index e901711bb..8534bb21f 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -271,7 +271,7 @@ powerDistributor { rack { input: [["oc:circuitTier2", "oc:componentCardWLan", "oc:circuitTier2"] [fenceIron, chest, fenceIron] - ["oc:craftingRouter", "oc:craftingCircuitBoardPrinted","oc:craftingPowerDistributor"]] + ["oc:craftingRouter", "oc:craftingCircuitBoardPrinted", "oc:craftingPowerDistributor"]] } redstone { input: [[ingotIron, blockRedstone, ingotIron] @@ -302,4 +302,9 @@ screen3 { input: [[obsidian, yellowDust, obsidian] [yellowDust, "oc:circuitTier3", glass] [obsidian, yellowDust, obsidian]] +} +hologram { + input: [[obsidian, glass, obsidian] + ["oc:craftingCircuitBoardPrinted", diamond, "oc:craftingCircuitBoardPrinted"] + ["oc:circuitTier3", blazeRod, "oc:circuitTier3"]] } \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/textures/blocks/hologram_effect.png b/src/main/resources/assets/opencomputers/textures/blocks/hologram_effect.png new file mode 100644 index 0000000000000000000000000000000000000000..e994756a32b1220e09edb6f9a50463c1de1bade0 GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm1|(O0oL2{=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrH1%*?YP;hE&{A>DnpCpvc2K{kSH}m-~XD7g~H9-rFp2*t|G2 z$9R)`*>XB~)z4*}Q$iB} D{-`x} literal 0 HcmV?d00001 From 794590399d5e67466e65d628844fb687d97809b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 26 Feb 2014 17:03:29 +0100 Subject: [PATCH 08/12] fixed stupid stupid bug that made term.write fail horribly when writing multiline strings in non-wrapping mode --- src/main/resources/assets/opencomputers/lua/rom/lib/term.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/term.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/term.lua index 111097326..67a5f98d8 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/lib/term.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/term.lua @@ -338,7 +338,7 @@ function term.write(value, wrap) end local blink = term.getCursorBlink() term.setCursorBlink(false) - local line, nl = value + local line, nl repeat local wrapAfter, margin = math.huge, math.huge if wrap then @@ -356,7 +356,7 @@ function term.write(value, wrap) component.gpu.fill(1, h, w, 1, " ") cursorY = h end - until not wrap or not value + until not value term.setCursorBlink(blink) end From e04a8767d641a83ab526fdea46db5a39d05fc527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 26 Feb 2014 20:57:36 +0100 Subject: [PATCH 09/12] textures for hologram projector block; caching display list for hologram; fixed item bounds; added localization; added clear and fill callbacks; fixed pcall and xpcall being exploitable to avoid timeout enforcement --- src/main/java/li/cil/oc/client/Proxy.scala | 1 + .../tileentity/HologramRenderer.scala | 147 +++++++++++++----- .../renderer/tileentity/ScreenRenderer.scala | 3 +- .../li/cil/oc/common/block/Hologram.scala | 24 ++- .../cil/oc/common/tileentity/Hologram.scala | 31 +++- .../assets/opencomputers/lang/de_DE.lang | 2 + .../assets/opencomputers/lang/en_US.lang | 2 + .../assets/opencomputers/lua/kernel.lua | 14 +- .../textures/blocks/hologram_effect.png | Bin 157 -> 149 bytes .../textures/blocks/hologram_side.png | Bin 0 -> 185 bytes .../textures/blocks/hologram_top.png | Bin 0 -> 421 bytes 11 files changed, 172 insertions(+), 52 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/textures/blocks/hologram_side.png create mode 100644 src/main/resources/assets/opencomputers/textures/blocks/hologram_top.png diff --git a/src/main/java/li/cil/oc/client/Proxy.scala b/src/main/java/li/cil/oc/client/Proxy.scala index c72df6230..ee5266fa5 100644 --- a/src/main/java/li/cil/oc/client/Proxy.scala +++ b/src/main/java/li/cil/oc/client/Proxy.scala @@ -48,6 +48,7 @@ private[oc] class Proxy extends CommonProxy { override def postInit(e: FMLPostInitializationEvent) { super.postInit(e) + TickRegistry.registerTickHandler(HologramRenderer, Side.CLIENT) TickRegistry.registerTickHandler(ScreenRenderer, Side.CLIENT) if (Settings.get.rTreeDebugRenderer) { MinecraftForge.EVENT_BUS.register(WirelessNetworkDebugRenderer) diff --git a/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala index c6a8ff2be..991d4a34b 100644 --- a/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala +++ b/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -1,29 +1,65 @@ package li.cil.oc.client.renderer.tileentity -import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer -import net.minecraft.tileentity.TileEntity -import li.cil.oc.common.tileentity.Hologram -import net.minecraft.client.renderer.Tessellator -import org.lwjgl.opengl.GL11 -import li.cil.oc.util.RenderState +import com.google.common.cache.{RemovalNotification, RemovalListener, CacheBuilder} +import cpw.mods.fml.common.{TickType, ITickHandler} +import java.util +import java.util.concurrent.{Callable, TimeUnit} import li.cil.oc.client.TexturePreloader -import net.minecraftforge.client.MinecraftForgeClient +import li.cil.oc.common.tileentity.Hologram +import li.cil.oc.util.RenderState +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer +import net.minecraft.client.renderer.{GLAllocation, Tessellator} +import net.minecraft.tileentity.TileEntity +import org.lwjgl.opengl.GL11 +import scala.util.Random + +object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] with RemovalListener[TileEntity, Int] with ITickHandler { + val random = new Random() + + /** We cache the display lists for the projectors we render for performance. */ + val cache = com.google.common.cache.CacheBuilder.newBuilder(). + expireAfterAccess(2, TimeUnit.SECONDS). + removalListener(this). + asInstanceOf[CacheBuilder[Hologram, Int]]. + build[Hologram, Int]() + + /** Used to pass the current screen along to call(). */ + private var hologram: Hologram = null -object HologramRenderer extends TileEntitySpecialRenderer { override def renderTileEntityAt(te: TileEntity, x: Double, y: Double, z: Double, f: Float) { - if (MinecraftForgeClient.getRenderPass != 0) return - - val hologram = te.asInstanceOf[Hologram] + hologram = te.asInstanceOf[Hologram] GL11.glPushAttrib(0xFFFFFFFF) - GL11.glDisable(GL11.GL_CULL_FACE) - -// RenderState.disableLighting() RenderState.makeItBlend() GL11.glPushMatrix() + + GL11.glScaled(1.01, 1.01, 1.01) // Avoid z-fighting with other blocks. GL11.glTranslated(x - 1, y + 0.5, z - 1) + if (random.nextDouble() < 0.025) { + GL11.glScaled(1 + random.nextGaussian() * 0.01, 1 + random.nextGaussian() * 0.001, 1 + random.nextGaussian() * 0.01) + GL11.glTranslated(random.nextGaussian() * 0.01, random.nextGaussian() * 0.01, random.nextGaussian() * 0.01) + } + + GL11.glColorMask(false, false, false, false) + val list = cache.get(hologram, this) + compileOrDraw(list) + GL11.glColorMask(true, true, true, true) + GL11.glDepthFunc(GL11.GL_EQUAL) + compileOrDraw(list) + + GL11.glPopMatrix() + GL11.glPopAttrib() + } + + def compileOrDraw(list: Int) = if (hologram.dirty) { + val doCompile = !RenderState.compilingDisplayList + if (doCompile) { + hologram.dirty = false + GL11.glNewList(list, GL11.GL_COMPILE_AND_EXECUTE) + } + def isSolid(hx: Int, hy: Int, hz: Int) = { hx >= 0 && hy >= 0 && hz >= 0 && hx < hologram.width && hy < hologram.height && hz < hologram.width && (hologram.volume(hx + hz * hologram.width) & (1 << hy)) != 0 @@ -56,54 +92,53 @@ object HologramRenderer extends TileEntitySpecialRenderer { // South if (!isSolid(hx, hy, hz + 1)) { t.setNormal(0, 0, 1) - t.addVertex(wx + s, wy + s, wz + s) // 5 - t.addVertex(wx + 0, wy + s, wz + s) // 4 - t.addVertex(wx + 0, wy + 0, wz + s) // 7 - t.addVertex(wx + s, wy + 0, wz + s) // 6 + t.addVertexWithUV(wx + s, wy + s, wz + s, 0, 0) // 5 + t.addVertexWithUV(wx + 0, wy + s, wz + s, 1, 0) // 4 + t.addVertexWithUV(wx + 0, wy + 0, wz + s, 1, 1) // 7 + t.addVertexWithUV(wx + s, wy + 0, wz + s, 0, 1) // 6 } // North if (!isSolid(hx, hy, hz - 1)) { t.setNormal(0, 0, -1) - t.addVertex(wx + s, wy + 0, wz + 0) // 3 - t.addVertex(wx + 0, wy + 0, wz + 0) // 2 - t.addVertex(wx + 0, wy + s, wz + 0) // 1 - t.addVertex(wx + s, wy + s, wz + 0) // 0 + t.addVertexWithUV(wx + s, wy + 0, wz + 0, 0, 0) // 3 + t.addVertexWithUV(wx + 0, wy + 0, wz + 0, 1, 0) // 2 + t.addVertexWithUV(wx + 0, wy + s, wz + 0, 1, 1) // 1 + t.addVertexWithUV(wx + s, wy + s, wz + 0, 0, 1) // 0 } // East if (!isSolid(hx + 1, hy, hz)) { t.setNormal(1, 0, 0) - t.addVertex(wx + s, wy + s, wz + s) // 5 - t.addVertex(wx + s, wy + 0, wz + s) // 6 - t.addVertex(wx + s, wy + 0, wz + 0) // 3 - t.addVertex(wx + s, wy + s, wz + 0) // 0 + t.addVertexWithUV(wx + s, wy + s, wz + s, 1, 0) // 5 + t.addVertexWithUV(wx + s, wy + 0, wz + s, 1, 1) // 6 + t.addVertexWithUV(wx + s, wy + 0, wz + 0, 0, 1) // 3 + t.addVertexWithUV(wx + s, wy + s, wz + 0, 0, 0) // 0 } // West if (!isSolid(hx - 1, hy, hz)) { t.setNormal(-1, 0, 0) - t.addVertex(wx + 0, wy + 0, wz + s) // 7 - t.addVertex(wx + 0, wy + s, wz + s) // 4 - t.addVertex(wx + 0, wy + s, wz + 0) // 1 - t.addVertex(wx + 0, wy + 0, wz + 0) // 2 + t.addVertexWithUV(wx + 0, wy + 0, wz + s, 1, 0) // 7 + t.addVertexWithUV(wx + 0, wy + s, wz + s, 1, 1) // 4 + t.addVertexWithUV(wx + 0, wy + s, wz + 0, 0, 1) // 1 + t.addVertexWithUV(wx + 0, wy + 0, wz + 0, 0, 0) // 2 } // Up if (!isSolid(hx, hy + 1, hz)) { t.setNormal(0, 1, 0) - t.addVertex(wx + s, wy + s, wz + 0) // 0 - t.addVertex(wx + 0, wy + s, wz + 0) // 1 - t.addVertex(wx + 0, wy + s, wz + s) // 4 - t.addVertex(wx + s, wy + s, wz + s) // 5 + t.addVertexWithUV(wx + s, wy + s, wz + 0, 0, 0) // 0 + t.addVertexWithUV(wx + 0, wy + s, wz + 0, 1, 0) // 1 + t.addVertexWithUV(wx + 0, wy + s, wz + s, 1, 1) // 4 + t.addVertexWithUV(wx + s, wy + s, wz + s, 0, 1) // 5 } // Down if (!isSolid(hx, hy - 1, hz)) { t.setNormal(0, -1, 0) - t.addVertex(wx + s, wy + 0, wz + s) // 6 - t.addVertex(wx + 0, wy + 0, wz + s) // 7 - t.addVertex(wx + 0, wy + 0, wz + 0) // 2 - t.addVertex(wx + s, wy + 0, wz + 0) // 3 + t.addVertexWithUV(wx + s, wy + 0, wz + s, 0, 0) // 6 + t.addVertexWithUV(wx + 0, wy + 0, wz + s, 1, 0) // 7 + t.addVertexWithUV(wx + 0, wy + 0, wz + 0, 1, 1) // 2 + t.addVertexWithUV(wx + s, wy + 0, wz + 0, 0, 1) // 3 } - } } } @@ -111,7 +146,37 @@ object HologramRenderer extends TileEntitySpecialRenderer { t.draw() - GL11.glPopMatrix() - GL11.glPopAttrib() + if (doCompile) { + GL11.glEndList() + } + + true } + else GL11.glCallList(list) + + // ----------------------------------------------------------------------- // + // Cache + // ----------------------------------------------------------------------- // + + def call = { + val list = GLAllocation.generateDisplayLists(1) + hologram.dirty = true // Force compilation. + list + } + + def onRemoval(e: RemovalNotification[TileEntity, Int]) { + GLAllocation.deleteDisplayLists(e.getValue) + } + + // ----------------------------------------------------------------------- // + // ITickHandler + // ----------------------------------------------------------------------- // + + def getLabel = "OpenComputers.Hologram" + + def ticks() = util.EnumSet.of(TickType.CLIENT) + + def tickStart(tickType: util.EnumSet[TickType], tickData: AnyRef*) = cache.cleanUp() + + def tickEnd(tickType: util.EnumSet[TickType], tickData: AnyRef*) {} } diff --git a/src/main/java/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala b/src/main/java/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala index 53da985c4..06c847d23 100644 --- a/src/main/java/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala +++ b/src/main/java/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala @@ -74,8 +74,7 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with if (screen.hasPower) { MonospaceFontRenderer.init(tileEntityRenderer.renderEngine) - val list = cache.get(screen, this) - compileOrDraw(list) + compileOrDraw(cache.get(screen, this)) } GL11.glPopMatrix() diff --git a/src/main/java/li/cil/oc/common/block/Hologram.scala b/src/main/java/li/cil/oc/common/block/Hologram.scala index 9b926bb38..993f325ec 100644 --- a/src/main/java/li/cil/oc/common/block/Hologram.scala +++ b/src/main/java/li/cil/oc/common/block/Hologram.scala @@ -7,23 +7,43 @@ import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.{ItemStack, EnumRarity} import net.minecraft.world.{World, IBlockAccess} import net.minecraftforge.common.ForgeDirection -import net.minecraft.util.AxisAlignedBB +import net.minecraft.util.{Icon, AxisAlignedBB} +import net.minecraft.client.renderer.texture.IconRegister +import li.cil.oc.Settings class Hologram(val parent: SpecialDelegator) extends SpecialDelegate { val unlocalizedName = "Hologram" + private val icons = Array.fill[Icon](6)(null) + override def rarity = EnumRarity.rare override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { tooltip.addAll(Tooltip.get(unlocalizedName)) } + override def icon(side: ForgeDirection) = Some(icons(side.ordinal())) + override def luminance(world: IBlockAccess, x: Int, y: Int, z: Int) = 15 override def isSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.DOWN override def bounds(world: IBlockAccess, x: Int, y: Int, z: Int) = - AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 0.2f, 1) + AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 3 / 16f, 1) + + override def itemBounds() { + parent.setBlockBounds(AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 3 / 16f, 1)) + } + + override def registerIcons(iconRegister: IconRegister) = { + icons(ForgeDirection.DOWN.ordinal) = iconRegister.registerIcon(Settings.resourceDomain + ":generic_top") + icons(ForgeDirection.UP.ordinal) = iconRegister.registerIcon(Settings.resourceDomain + ":hologram_top") + + icons(ForgeDirection.NORTH.ordinal) = iconRegister.registerIcon(Settings.resourceDomain + ":hologram_side") + icons(ForgeDirection.SOUTH.ordinal) = icons(ForgeDirection.NORTH.ordinal) + icons(ForgeDirection.WEST.ordinal) = icons(ForgeDirection.NORTH.ordinal) + icons(ForgeDirection.EAST.ordinal) = icons(ForgeDirection.NORTH.ordinal) + } // ----------------------------------------------------------------------- // diff --git a/src/main/java/li/cil/oc/common/tileentity/Hologram.scala b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala index 94dba39ce..f0ed42622 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala @@ -34,15 +34,22 @@ class Hologram extends Environment with SidedEnvironment { // ----------------------------------------------------------------------- // + @Callback(doc = """function() -- Clears the hologram.""") + def clear(computer: Context, args: Arguments): Array[AnyRef] = this.synchronized { + for (i <- 0 until volume.length) volume(i) = 0 + dirty = true + null + } + @Callback(direct = true, doc = """function(x:number, z:number):number -- Returns the bit mask representing the specified column.""") - def get(computer: Context, args: Arguments): Array[AnyRef] = { + def get(computer: Context, args: Arguments): Array[AnyRef] = this.synchronized { val x = args.checkInteger(0) - 1 val z = args.checkInteger(1) - 1 result(volume(x + z * width)) } @Callback(direct = true, limit = 256, doc = """function(x:number, z:number, value:number) -- Set the bit mask for the specified column.""") - def set(computer: Context, args: Arguments): Array[AnyRef] = { + def set(computer: Context, args: Arguments): Array[AnyRef] = this.synchronized { val x = args.checkInteger(0) - 1 val z = args.checkInteger(1) - 1 val value = args.checkInteger(2) @@ -51,6 +58,18 @@ class Hologram extends Environment with SidedEnvironment { null } + @Callback(direct = true, limit = 128, doc = """function(x:number, z:number, height:number) -- Fills a column to the specified height.""") + def fill(computer: Context, args: Arguments): Array[AnyRef] = this.synchronized { + val x = args.checkInteger(0) - 1 + val z = args.checkInteger(1) - 1 + val height = math.min(32, math.max(0, args.checkInteger(2))) + // Bit shifts in the JVM only use the lowest five bits... so we have to + // manually check the height, to avoid the shift being a no-op. + volume(x + z * width) = if (height > 0) 0xFFFFFFFF >>> (32 - height) else 0 + dirty = true + null + } + // ----------------------------------------------------------------------- // override def updateEntity() { @@ -67,14 +86,18 @@ class Hologram extends Environment with SidedEnvironment { // ----------------------------------------------------------------------- // - override def getRenderBoundingBox = AxisAlignedBB.getAABBPool.getAABB(xCoord - 1, yCoord, zCoord - 1, xCoord + 2, yCoord + 3, zCoord + 2) + override def shouldRenderInPass(pass: Int) = pass == 1 + + override def getRenderBoundingBox = AxisAlignedBB.getAABBPool.getAABB(xCoord - 1, yCoord, zCoord - 1, xCoord + 2, yCoord + 2.25, zCoord + 2) + + // ----------------------------------------------------------------------- // override def readFromNBT(nbt: NBTTagCompound) { super.readFromNBT(nbt) nbt.getIntArray(Settings.namespace + "volume").copyToArray(volume) } - override def writeToNBT(nbt: NBTTagCompound) { + override def writeToNBT(nbt: NBTTagCompound) = this.synchronized { super.writeToNBT(nbt) nbt.setIntArray(Settings.namespace + "volume", volume) } diff --git a/src/main/resources/assets/opencomputers/lang/de_DE.lang b/src/main/resources/assets/opencomputers/lang/de_DE.lang index c9f1bc053..2b7bc3535 100644 --- a/src/main/resources/assets/opencomputers/lang/de_DE.lang +++ b/src/main/resources/assets/opencomputers/lang/de_DE.lang @@ -12,6 +12,7 @@ oc:tile.Case2.name=Computergehäuse (Stufe 3) oc:tile.Charger.name=Ladestation oc:tile.DiskDrive.name=Diskettenlaufwerk oc:tile.Keyboard.name=Tastatur +oc:tile.Hologram.name=Hologrammprojektor oc:tile.PowerConverter.name=Leistungswandler oc:tile.PowerDistributor.name=Stromverteiler oc:tile.Redstone.name=Redstone-I/O @@ -136,6 +137,7 @@ oc:tooltip.GraphicsCard=Erlaubt es, den angezeigten Inhalt von Bildschirmen zu oc:tooltip.InternetCard=Diese Karte erlaubt es, HTTP-Anfragen zu senden und echte TCP Sockets zu verwenden. oc:tooltip.IronNugget=Ein Nugget, das aus Eisen besteht, darum wird es ja auch Eisennugget genannt, duh... oc:tooltip.Keyboard=Kann an Bildschirmen befestigt werden, um auf ihnen zu tippen. +oc:tooltip.Hologram=Ein Volumendisplay das beliebige, von Computern festgelegte Voxelstrukturen anzeigt.[nl] Auflösung: §f48x32x48§7. [nl] Farbtiefe: §fMonochrom§7. oc:tooltip.Memory=Braucht ein jeder Computer, um zu starten. Je mehr vorhanden, desto komplexere Programme können ausgeführt werden. oc:tooltip.Microchip=Tritt auch unter dem Alias Integrierter Schaltkreis auf. Keine Ahnung, warum das auch mit Redstone klappt, aber es funktioniert. oc:tooltip.NetworkCard=Erlaubt es Computern, die über mehrere Blöcke miteinander verbunden sind (z.B. Kabel), mittels Netzwerknachrichten zu kommunizieren. diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index b5f8195d6..a1d56e273 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -12,6 +12,7 @@ oc:tile.Case2.name=Computer Case (Tier 3) oc:tile.Charger.name=Charger oc:tile.DiskDrive.name=Disk Drive oc:tile.Keyboard.name=Keyboard +oc:tile.Hologram.name=Hologram Projector oc:tile.PowerConverter.name=Power Converter oc:tile.PowerDistributor.name=Power Distributor oc:tile.Redstone.name=Redstone I/O @@ -136,6 +137,7 @@ oc:tooltip.GraphicsCard=Used to change what's displayed on screens.[nl] Maximum oc:tooltip.InternetCard=This card allows making HTTP requests and using real TCP sockets. oc:tooltip.IronNugget=A nugget made of iron, that's why it's called an Iron Nugget, duh... oc:tooltip.Keyboard=Can be attached to screens to allow typing on them. +oc:tooltip.Hologram=A volumetric display that can be controlled by computers to display arbitrary voxel structures.[nl] Resolution: §f48x32x48§7. [nl] Color depth: §fMonochrome§7. oc:tooltip.Memory=Required to get computers to run. The more you have, the more complex the programs you can run. oc:tooltip.Microchip=The chip formerly known as Integrated Circuit. I have no idea why this works with redstone, but it does. oc:tooltip.NetworkCard=Allows distant computers connected by other blocks (such as cable) to communicate by sending messages to each other. diff --git a/src/main/resources/assets/opencomputers/lua/kernel.lua b/src/main/resources/assets/opencomputers/lua/kernel.lua index baec22ae5..cc9946c26 100644 --- a/src/main/resources/assets/opencomputers/lua/kernel.lua +++ b/src/main/resources/assets/opencomputers/lua/kernel.lua @@ -1,5 +1,5 @@ local hookInterval = 100 -local deadline = 0 +local deadline = math.huge local function checkDeadline() if computer.realTime() > deadline then debug.sethook(coroutine.running(), checkDeadline, "", 1) @@ -91,7 +91,11 @@ sandbox = { loadfile = nil, -- in boot/*_base.lua next = next, pairs = pairs, - pcall = pcall, + pcall = function(...) + local result = table.pack(pcall(...)) + checkDeadline() + return table.unpack(result, 1, result.n) + end, print = nil, -- in boot/*_base.lua rawequal = rawequal, rawget = rawget, @@ -103,7 +107,11 @@ sandbox = { tostring = tostring, type = type, _VERSION = "Lua 5.2", - xpcall = xpcall, + xpcall = function(...) + local result = table.pack(xpcall(...)) + checkDeadline() + return table.unpack(result, 1, result.n) + end, coroutine = { create = function(f) diff --git a/src/main/resources/assets/opencomputers/textures/blocks/hologram_effect.png b/src/main/resources/assets/opencomputers/textures/blocks/hologram_effect.png index e994756a32b1220e09edb6f9a50463c1de1bade0..5be656cec646fc72f7f889645587f7160bb94b0c 100644 GIT binary patch delta 83 zcmV-Z0IdI=0hIxeNlZ6ML_t(|+9Zj&4ZtuE!$`!n;r(YynMpE$<>v&jASE9!frF1U p`W7q1?C?`d9nB$`xuUWJ7yz;;3&QpK@*4mE002ovPDHLkV1mx2BGdo? delta 91 zcmV-h0Hptw0i6MmNmM^cL_t(|+9Zm(5da|!1DD4s1oYn#RnUY@fbTq@K(nJ&Vlg>D x<)-4%2DxQKB!=%iWS0Jset*xxAtfZvm=H}+&;-aXi=<4dKrKRQM$L)0fs+3H{~X`yqWm4;OtOObT6}zW@UONl^$t>C(mU P00000NkvXXu0mjfdWoJX literal 0 HcmV?d00001 From c3e9ed1e97ccf12581dab102f9d65f00665e2ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 27 Feb 2014 03:25:27 +0100 Subject: [PATCH 10/12] added power consumption for hologram projector; added scale setting, so hologram can be from 1x1x1 up to 9x6x9, higher scale consumes more energy --- src/main/java/li/cil/oc/Settings.scala | 1 + .../java/li/cil/oc/client/PacketHandler.scala | 9 +++ .../renderer/tileentity/CableRenderer.scala | 12 +--- .../tileentity/HologramRenderer.scala | 13 +++-- .../java/li/cil/oc/common/PacketType.scala | 1 + .../cil/oc/common/tileentity/Hologram.scala | 52 +++++++++++++++--- .../java/li/cil/oc/server/PacketSender.scala | 9 +++ .../textures/blocks/hologram_effect.png | Bin 149 -> 157 bytes src/main/resources/reference.conf | 5 ++ 9 files changed, 79 insertions(+), 23 deletions(-) diff --git a/src/main/java/li/cil/oc/Settings.scala b/src/main/java/li/cil/oc/Settings.scala index 6bd97680a..566d9d485 100644 --- a/src/main/java/li/cil/oc/Settings.scala +++ b/src/main/java/li/cil/oc/Settings.scala @@ -120,6 +120,7 @@ class Settings(config: Config) { val robotCost = config.getDouble("power.cost.robot") max 0 val sleepCostFactor = config.getDouble("power.cost.sleepFactor") max 0 val screenCost = config.getDouble("power.cost.screen") max 0 + val hologramCost = config.getDouble("power.cost.hologram") max 0 val hddReadCost = (config.getDouble("power.cost.hddRead") max 0) / 1024 val hddWriteCost = (config.getDouble("power.cost.hddWrite") max 0) / 1024 val gpuSetCost = (config.getDouble("power.cost.gpuSet") max 0) / Settings.basicScreenPixels diff --git a/src/main/java/li/cil/oc/client/PacketHandler.scala b/src/main/java/li/cil/oc/client/PacketHandler.scala index 47a7c593a..28b8a04a6 100644 --- a/src/main/java/li/cil/oc/client/PacketHandler.scala +++ b/src/main/java/li/cil/oc/client/PacketHandler.scala @@ -26,6 +26,7 @@ class PacketHandler extends CommonPacketHandler { case PacketType.ChargerState => onChargerState(p) case PacketType.ComputerState => onComputerState(p) case PacketType.ComputerUserList => onComputerUserList(p) + case PacketType.HologramScale => onHologramScale(p) case PacketType.HologramSet => onHologramSet(p) case PacketType.PowerState => onPowerState(p) case PacketType.RedstoneState => onRedstoneState(p) @@ -101,6 +102,14 @@ class PacketHandler extends CommonPacketHandler { case _ => // Invalid packet. } + def onHologramScale(p: PacketParser) = + p.readTileEntity[Hologram]() match { + case Some(t) => + t.scale = p.readDouble() + t.dirty = true + case _ => // Invalid packet. + } + def onHologramSet(p: PacketParser) = p.readTileEntity[Hologram]() match { case Some(t) => diff --git a/src/main/java/li/cil/oc/client/renderer/tileentity/CableRenderer.scala b/src/main/java/li/cil/oc/client/renderer/tileentity/CableRenderer.scala index 35bde5a61..b485b0892 100644 --- a/src/main/java/li/cil/oc/client/renderer/tileentity/CableRenderer.scala +++ b/src/main/java/li/cil/oc/client/renderer/tileentity/CableRenderer.scala @@ -40,6 +40,7 @@ object CableRenderer extends TileEntitySpecialRenderer { for (mask <- 0 to 0xFF >> 2) { GL11.glNewList(displayLists + mask, GL11.GL_COMPILE) + t.startDrawingQuads() for (side <- ForgeDirection.VALID_DIRECTIONS) { val connects = (side.flag & mask) != 0 val z = if (connects) 0 else lb @@ -48,7 +49,6 @@ object CableRenderer extends TileEntitySpecialRenderer { exists(s => (s.flag & mask) != 0)) uo else 0 - t.startDrawingQuads() t.setNormal(side.offsetX, side.offsetY, -side.offsetZ) val (tx, ty, tz, u, v) = side match { case ForgeDirection.WEST => (Array.fill(4)(z), t2, t1, uv1.reverse, uv2) @@ -63,7 +63,6 @@ object CableRenderer extends TileEntitySpecialRenderer { t.addVertexWithUV(tx(1), ty(1), tz(1), u(1) + uc, v(1)) t.addVertexWithUV(tx(2), ty(2), tz(2), u(2) + uc, v(2)) t.addVertexWithUV(tx(3), ty(3), tz(3), u(3) + uc, v(3)) - t.draw() if (connects) { val (axis, sign, uv1, uv2, uv3, uv4) = side match { @@ -79,39 +78,32 @@ object CableRenderer extends TileEntitySpecialRenderer { val o1 = offsets((axis + sign + 3) % 3) val o2 = offsets((axis - sign + 3) % 3) - t.startDrawingQuads() normal(side, 0) t.addVertexWithUV(tx(0) - sign * tl(0), ty(0) - sign * tl(1), tz(0) - sign * tl(2), u(uv(0 + uv1)) + uo, v(uv(0 + uv1)) * vs) t.addVertexWithUV(tx(1) - sign * tl(0), ty(1) - sign * tl(1), tz(1) - sign * tl(2), u(uv(1 + uv1)) + uo, v(uv(1 + uv1)) * vs) t.addVertexWithUV(tx(2) + o1(0), ty(2) + o1(1), tz(2) + o1(2), u(uv(2 + uv1)) + uo, v(uv(2 + uv1)) * vs) t.addVertexWithUV(tx(3) + o1(0), ty(3) + o1(1), tz(3) + o1(2), u(uv(3 + uv1)) + uo, v(uv(3 + uv1)) * vs) - t.draw() - t.startDrawingQuads() normal(side, 1) t.addVertexWithUV(tx(0) - o1(0), ty(0) - o1(1), tz(0) - o1(2), u(uv(0 + uv2)) + uo, v(uv(0 + uv2)) * vs) t.addVertexWithUV(tx(1) - o1(0), ty(1) - o1(1), tz(1) - o1(2), u(uv(1 + uv2)) + uo, v(uv(1 + uv2)) * vs) t.addVertexWithUV(tx(2) - sign * tl(0), ty(2) - sign * tl(1), tz(2) - sign * tl(2), u(uv(2 + uv2)) + uo, v(uv(2 + uv2)) * vs) t.addVertexWithUV(tx(3) - sign * tl(0), ty(3) - sign * tl(1), tz(3) - sign * tl(2), u(uv(3 + uv2)) + uo, v(uv(3 + uv2)) * vs) - t.draw() - t.startDrawingQuads() normal(side, 2) t.addVertexWithUV(tx(0) - sign * tl(0), ty(0) - sign * tl(1), tz(0) - sign * tl(2), u(uv(0 + uv3)) + uo, v(uv(0 + uv3)) * vs) t.addVertexWithUV(tx(1) - o2(0), ty(1) - o2(1), tz(1) - o2(2), u(uv(1 + uv3)) + uo, v(uv(1 + uv3)) * vs) t.addVertexWithUV(tx(2) - o2(0), ty(2) - o2(1), tz(2) - o2(2), u(uv(2 + uv3)) + uo, v(uv(2 + uv3)) * vs) t.addVertexWithUV(tx(3) - sign * tl(0), ty(3) - sign * tl(1), tz(3) - sign * tl(2), u(uv(3 + uv3)) + uo, v(uv(3 + uv3)) * vs) - t.draw() - t.startDrawingQuads() normal(side, 3) t.addVertexWithUV(tx(0) + o2(0), ty(0) + o2(1), tz(0) + o2(2), u(uv(0 + uv4)) + uo, v(uv(0 + uv4)) * vs) t.addVertexWithUV(tx(1) - sign * tl(0), ty(1) - sign * tl(1), tz(1) - sign * tl(2), u(uv(1 + uv4)) + uo, v(uv(1 + uv4)) * vs) t.addVertexWithUV(tx(2) - sign * tl(0), ty(2) - sign * tl(1), tz(2) - sign * tl(2), u(uv(2 + uv4)) + uo, v(uv(2 + uv4)) * vs) t.addVertexWithUV(tx(3) + o2(0), ty(3) + o2(1), tz(3) + o2(2), u(uv(3 + uv4)) + uo, v(uv(3 + uv4)) * vs) - t.draw() } } + t.draw() GL11.glEndList() } diff --git a/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala index 991d4a34b..da5692247 100644 --- a/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala +++ b/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -28,15 +28,16 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit override def renderTileEntityAt(te: TileEntity, x: Double, y: Double, z: Double, f: Float) { hologram = te.asInstanceOf[Hologram] + if (!hologram.hasPower) return GL11.glPushAttrib(0xFFFFFFFF) - RenderState.makeItBlend() GL11.glPushMatrix() + GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) + GL11.glScaled(1.001, 1.001, 1.001) // Avoid z-fighting with other blocks. + GL11.glTranslated(-1.5 * hologram.scale, 0, -1.5 * hologram.scale) - GL11.glScaled(1.01, 1.01, 1.01) // Avoid z-fighting with other blocks. - GL11.glTranslated(x - 1, y + 0.5, z - 1) - + // Do a bit of flickering, because that's what holograms do! if (random.nextDouble() < 0.025) { GL11.glScaled(1 + random.nextGaussian() * 0.01, 1 + random.nextGaussian() * 0.001, 1 + random.nextGaussian() * 0.01) GL11.glTranslated(random.nextGaussian() * 0.01, random.nextGaussian() * 0.01, random.nextGaussian() * 0.01) @@ -68,9 +69,9 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit bindTexture(TexturePreloader.blockHologram) val t = Tessellator.instance t.startDrawingQuads() - t.setColorRGBA_F(1, 1, 1, 0.7f) + t.setColorRGBA_F(1, 1, 1, 0.5f) - val s = 1f / 16f + val s = 1f / 16f * hologram.scale for (hx <- 0 until hologram.width) { val wx = hx * s for (hz <- 0 until hologram.width) { diff --git a/src/main/java/li/cil/oc/common/PacketType.scala b/src/main/java/li/cil/oc/common/PacketType.scala index 11013c6c1..059b3d2f1 100644 --- a/src/main/java/li/cil/oc/common/PacketType.scala +++ b/src/main/java/li/cil/oc/common/PacketType.scala @@ -8,6 +8,7 @@ object PacketType extends Enumeration { ChargerState, ComputerState, ComputerUserList, + HologramScale, HologramSet, PowerState, RedstoneState, diff --git a/src/main/java/li/cil/oc/common/tileentity/Hologram.scala b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala index f0ed42622..f5f24e323 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala @@ -20,12 +20,20 @@ class Hologram extends Environment with SidedEnvironment { val volume = new Array[Int](width * width) + // Render scale. + var scale = 1.0 + + // Relative number of lit columns (for energy cost). + var litRatio = -1.0 + // Whether we need to send an update packet/recompile our display list. var dirty = false // Time to wait before sending another update packet. var cooldown = 0 + var hasPower = true + // ----------------------------------------------------------------------- // override def canConnect(side: ForgeDirection) = side != ForgeDirection.UP @@ -38,6 +46,7 @@ class Hologram extends Environment with SidedEnvironment { def clear(computer: Context, args: Arguments): Array[AnyRef] = this.synchronized { for (i <- 0 until volume.length) volume(i) = 0 dirty = true + litRatio = 0 null } @@ -55,6 +64,7 @@ class Hologram extends Environment with SidedEnvironment { val value = args.checkInteger(2) volume(x + z * width) = value dirty = true + litRatio = -1 null } @@ -67,6 +77,19 @@ class Hologram extends Environment with SidedEnvironment { // manually check the height, to avoid the shift being a no-op. volume(x + z * width) = if (height > 0) 0xFFFFFFFF >>> (32 - height) else 0 dirty = true + litRatio = -1 + null + } + + @Callback(doc = """function():number -- Returns the render scale of the hologram.""") + def getScale(computer: Context, args: Arguments): Array[AnyRef] = { + result(scale) + } + + @Callback(doc = """function(value:number) -- Set the render scale. A larger scale consumes more energy.""") + def setScale(computer: Context, args: Arguments): Array[AnyRef] = { + scale = math.max(0.333333, math.min(3, args.checkDouble(0))) + ServerPacketSender.sendHologramScale(this) null } @@ -74,13 +97,24 @@ class Hologram extends Environment with SidedEnvironment { override def updateEntity() { super.updateEntity() - if (isServer && dirty) { - cooldown -= 1 - if (cooldown <= 0) { - dirty = false - cooldown = 10 - ServerPacketSender.sendHologramSet(this) + if (isServer) { + if (dirty) { + cooldown -= 1 + if (cooldown <= 0) { + dirty = false + cooldown = 10 + ServerPacketSender.sendHologramSet(this) + } } + if (litRatio < 0) { + litRatio = 0 + for (i <- 0 until volume.length) { + if (volume(i) != 0) litRatio += 1 + } + litRatio /= volume.length + } + + hasPower = node.changeBuffer(-Settings.get.hologramCost * litRatio * scale) == 0 } } @@ -88,29 +122,33 @@ class Hologram extends Environment with SidedEnvironment { override def shouldRenderInPass(pass: Int) = pass == 1 - override def getRenderBoundingBox = AxisAlignedBB.getAABBPool.getAABB(xCoord - 1, yCoord, zCoord - 1, xCoord + 2, yCoord + 2.25, zCoord + 2) + override def getRenderBoundingBox = AxisAlignedBB.getAABBPool.getAABB(xCoord + 0.5 - 1.5 * scale, yCoord, zCoord - scale, xCoord + 0.5 + 1.5 * scale, yCoord + 0.25 + 2 * scale, zCoord + 0.5 + 1.5 * scale) // ----------------------------------------------------------------------- // override def readFromNBT(nbt: NBTTagCompound) { super.readFromNBT(nbt) nbt.getIntArray(Settings.namespace + "volume").copyToArray(volume) + scale = nbt.getDouble(Settings.namespace + "scale") } override def writeToNBT(nbt: NBTTagCompound) = this.synchronized { super.writeToNBT(nbt) nbt.setIntArray(Settings.namespace + "volume", volume) + nbt.setDouble(Settings.namespace + "scale", scale) } @SideOnly(Side.CLIENT) override def readFromNBTForClient(nbt: NBTTagCompound) { super.readFromNBTForClient(nbt) nbt.getIntArray("volume").copyToArray(volume) + scale = nbt.getDouble("scale") dirty = true } override def writeToNBTForClient(nbt: NBTTagCompound) { super.writeToNBTForClient(nbt) nbt.setIntArray("volume", volume) + nbt.setDouble("scale", scale) } } diff --git a/src/main/java/li/cil/oc/server/PacketSender.scala b/src/main/java/li/cil/oc/server/PacketSender.scala index 2290137f8..55dc419b3 100644 --- a/src/main/java/li/cil/oc/server/PacketSender.scala +++ b/src/main/java/li/cil/oc/server/PacketSender.scala @@ -55,6 +55,15 @@ object PacketSender { pb.sendToNearbyPlayers(t) } + def sendHologramScale(t: Hologram) { + val pb = new PacketBuilder(PacketType.HologramScale) + + pb.writeTileEntity(t) + pb.writeDouble(t.scale) + + pb.sendToNearbyPlayers(t) + } + def sendHologramSet(t: Hologram) { val pb = new PacketBuilder(PacketType.HologramSet) diff --git a/src/main/resources/assets/opencomputers/textures/blocks/hologram_effect.png b/src/main/resources/assets/opencomputers/textures/blocks/hologram_effect.png index 5be656cec646fc72f7f889645587f7160bb94b0c..154039406c1e4562c5c11f4c691b26801287cc1d 100644 GIT binary patch delta 103 zcmbQrIG1sPBnLAC1H(N1JfDe*8X=+qJ|V6QR~Q%`F)%!4V7Sb{_=J(+5(DE^#;dv_ z$AJpvJY5_^DsCkuB&4M#C!{2$09grX2?>cQNsJr@42+cw%6HrMhyYbGc)I$ztaD0e F0s!CT9rpkL delta 95 zcmV-l0HFV!0hIxe83+ad0061+o_>)bC`>m=L_t(|+9Zj&4ZtuE!$`!n;r(YynMpE$ z<>v&jASE9!frF1U`W7q1?C?`d9nB$`xuUWJ7yz;;3&QpK@*4mE002ovPDHLkV1oY? BCPDxJ diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index cb2bf7eff..e56652212 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -471,6 +471,11 @@ opencomputers { # tick. screen: 0.05 + # The amount of energy a hologram projetor consumes per tick. This + # is the cost if every column is lit. If not a single voxel is + # displayed the hologram projector will not drain energy. + hologram: 0.2 + # Energy it takes read one kilobyte from a file system. Note that non # I/O operations on file systems such as `list` or `getFreeSpace` do # *not* consume power. Note that this very much determines how much From 9dbe22562331cbbe564dfc51d66e1490c3fb769c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 27 Feb 2014 04:21:21 +0100 Subject: [PATCH 11/12] fixed possibility of math.random pushing a LuaError (userdata); fixed shell immediately restarting after errors if there were pending signals --- src/main/java/li/cil/oc/util/LuaStateFactory.scala | 6 +++--- src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua | 2 +- src/main/resources/assets/opencomputers/lua/rom/init.lua | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/li/cil/oc/util/LuaStateFactory.scala b/src/main/java/li/cil/oc/util/LuaStateFactory.scala index 9f7179d76..19722d9cf 100644 --- a/src/main/java/li/cil/oc/util/LuaStateFactory.scala +++ b/src/main/java/li/cil/oc/util/LuaStateFactory.scala @@ -217,12 +217,12 @@ object LuaStateFactory { lua.getTop match { case 0 => lua.pushNumber(random.nextDouble()) case 1 => - val u = lua.checkInteger(1) + val u = lua.checkNumber(1).toInt lua.checkArg(1, 1 < u, "interval is empty") lua.pushInteger(1 + random.nextInt(u)) case 2 => - val l = lua.checkInteger(1) - val u = lua.checkInteger(2) + val l = lua.checkNumber(1).toInt + val u = lua.checkNumber(2).toInt lua.checkArg(1, l < u, "interval is empty") lua.pushInteger(l + random.nextInt(u - (l - 1))) case _ => throw new IllegalArgumentException("wrong number of arguments") 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 2ec7094d8..342f9f04b 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/bin/sh.lua @@ -121,7 +121,7 @@ if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then elseif command ~= "" then local result, reason = execute(command) if not result then - io.stderr:write(reason .. "\n") + io.stderr:write((tostring(reason) or "unknown error").. "\n") elseif term.getCursor() > 1 then term.write("\n") end diff --git a/src/main/resources/assets/opencomputers/lua/rom/init.lua b/src/main/resources/assets/opencomputers/lua/rom/init.lua index 48cc1be29..99afa57f3 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/init.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/init.lua @@ -13,8 +13,9 @@ while true do io.write(_OSVERSION .. " (" .. math.floor(computer.totalMemory() / 1024) .. "k RAM)\n") local result, reason = os.execute(os.getenv("SHELL") .. " -") if not result then - io.stderr:write((reason or "unknown error") .. "\n") + io.stderr:write((tostring(reason) or "unknown error") .. "\n") print("Press any key to continue.") + os.sleep(0.5) event.pull("key") end end \ No newline at end of file From 65fb648cf9884cd855e2a9a216ffeff7552c1f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 27 Feb 2014 11:11:47 +0100 Subject: [PATCH 12/12] reduced hologram network footprint and sending updates to clients more frequently --- .../java/li/cil/oc/client/PacketHandler.scala | 21 ++++++++-- .../tileentity/HologramRenderer.scala | 4 ++ .../java/li/cil/oc/common/PacketBuilder.scala | 38 ++++++++++++++++--- .../java/li/cil/oc/common/PacketHandler.scala | 10 +++-- .../java/li/cil/oc/common/PacketType.scala | 1 + .../cil/oc/common/tileentity/Hologram.scala | 38 +++++++++++++++---- .../java/li/cil/oc/server/PacketSender.scala | 24 +++++++++--- 7 files changed, 109 insertions(+), 27 deletions(-) diff --git a/src/main/java/li/cil/oc/client/PacketHandler.scala b/src/main/java/li/cil/oc/client/PacketHandler.scala index 28b8a04a6..97ce2beaf 100644 --- a/src/main/java/li/cil/oc/client/PacketHandler.scala +++ b/src/main/java/li/cil/oc/client/PacketHandler.scala @@ -26,6 +26,7 @@ class PacketHandler extends CommonPacketHandler { case PacketType.ChargerState => onChargerState(p) case PacketType.ComputerState => onComputerState(p) case PacketType.ComputerUserList => onComputerUserList(p) + case PacketType.HologramClear => onHologramClear(p) case PacketType.HologramScale => onHologramScale(p) case PacketType.HologramSet => onHologramSet(p) case PacketType.PowerState => onPowerState(p) @@ -102,6 +103,14 @@ class PacketHandler extends CommonPacketHandler { case _ => // Invalid packet. } + def onHologramClear(p: PacketParser) = + p.readTileEntity[Hologram]() match { + case Some(t) => + for (i <- 0 until t.volume.length) t.volume(i) = 0 + t.dirty = true + case _ => // Invalid packet. + } + def onHologramScale(p: PacketParser) = p.readTileEntity[Hologram]() match { case Some(t) => @@ -113,10 +122,14 @@ class PacketHandler extends CommonPacketHandler { def onHologramSet(p: PacketParser) = p.readTileEntity[Hologram]() match { case Some(t) => - val length = p.readInt() - val count = math.max(0, math.min(length, t.volume.length)) - for (i <- 0 until count) { - t.volume(i) = p.readInt() + val fromX = p.readByte(): Int + val untilX = p.readByte(): Int + val fromZ = p.readByte(): Int + val untilZ = p.readByte(): Int + for (x <- fromX until untilX) { + for (z <- fromZ until untilZ) { + t.volume(x + z * t.width) = p.readInt() + } } t.dirty = true case _ => // Invalid packet. diff --git a/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala index da5692247..bcf374af9 100644 --- a/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala +++ b/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -43,6 +43,9 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit GL11.glTranslated(random.nextGaussian() * 0.01, random.nextGaussian() * 0.01, random.nextGaussian() * 0.01) } + // We do two passes here to avoid weird transparency effects: in the first + // pass we find the front-most fragment, in the second we actually draw it. + // TODO proper transparency shader? depth peeling e.g. GL11.glColorMask(false, false, false, false) val list = cache.get(hologram, this) compileOrDraw(list) @@ -71,6 +74,7 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit t.startDrawingQuads() t.setColorRGBA_F(1, 1, 1, 0.5f) + // TODO merge quads for better rendering performance val s = 1f / 16f * hologram.scale for (hx <- 0 until hologram.width) { val wx = hx * s diff --git a/src/main/java/li/cil/oc/common/PacketBuilder.scala b/src/main/java/li/cil/oc/common/PacketBuilder.scala index 6c0f0f86f..09ac6943b 100644 --- a/src/main/java/li/cil/oc/common/PacketBuilder.scala +++ b/src/main/java/li/cil/oc/common/PacketBuilder.scala @@ -3,8 +3,8 @@ package li.cil.oc.common import cpw.mods.fml.common.FMLCommonHandler import cpw.mods.fml.common.network.PacketDispatcher import cpw.mods.fml.common.network.Player -import java.io.ByteArrayOutputStream -import java.io.DataOutputStream +import java.io.{OutputStream, ByteArrayOutputStream, DataOutputStream} +import java.util.zip.GZIPOutputStream import li.cil.oc.common.tileentity.TileEntity import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.item.ItemStack @@ -14,9 +14,8 @@ import net.minecraft.world.World import net.minecraftforge.common.ForgeDirection import scala.collection.convert.WrapAsScala._ -class PacketBuilder(packetType: PacketType.Value, private val stream: ByteArrayOutputStream = new ByteArrayOutputStream) extends DataOutputStream(stream) { - writeByte(packetType.id) - +// Necessary to keep track of the GZIP stream. +abstract class PacketBuilderBase[T <: OutputStream](protected val stream: T) extends DataOutputStream(stream) { def writeTileEntity(t: TileEntity) = { writeInt(t.world.provider.dimensionId) writeInt(t.x) @@ -57,7 +56,13 @@ class PacketBuilder(packetType: PacketType.Value, private val stream: ByteArrayO def sendToServer() = PacketDispatcher.sendPacketToServer(packet) - private def packet = { + protected def packet: Packet250CustomPayload +} + +class PacketBuilder(packetType: PacketType.Value) extends PacketBuilderBase(PacketBuilder.newData(compressed = false)) { + writeByte(packetType.id) + + override protected def packet = { val p = new Packet250CustomPayload p.channel = "OpenComp" p.data = stream.toByteArray @@ -65,3 +70,24 @@ class PacketBuilder(packetType: PacketType.Value, private val stream: ByteArrayO p } } + +class CompressedPacketBuilder(packetType: PacketType.Value, private val data: ByteArrayOutputStream = PacketBuilder.newData(compressed = true)) extends PacketBuilderBase(new GZIPOutputStream(data)) { + writeByte(packetType.id) + + override protected def packet = { + stream.finish() + val p = new Packet250CustomPayload + p.channel = "OpenComp" + p.data = data.toByteArray + p.length = data.size + p + } +} + +object PacketBuilder { + def newData(compressed: Boolean) = { + val data = new ByteArrayOutputStream + data.write(if (compressed) 1 else 0) + data + } +} \ No newline at end of file diff --git a/src/main/java/li/cil/oc/common/PacketHandler.scala b/src/main/java/li/cil/oc/common/PacketHandler.scala index 2c103bef6..e3340a117 100644 --- a/src/main/java/li/cil/oc/common/PacketHandler.scala +++ b/src/main/java/li/cil/oc/common/PacketHandler.scala @@ -2,9 +2,9 @@ package li.cil.oc.common import cpw.mods.fml.common.network.IPacketHandler import cpw.mods.fml.common.network.Player -import java.io.ByteArrayInputStream -import java.io.DataInputStream +import java.io.{InputStream, ByteArrayInputStream, DataInputStream} import java.util.logging.Level +import java.util.zip.GZIPInputStream import li.cil.oc.{Blocks, OpenComputers} import net.minecraft.item.ItemStack import net.minecraft.nbt.CompressedStreamTools @@ -22,7 +22,9 @@ abstract class PacketHandler extends IPacketHandler { // malicious client, in which case we don't want to allow it to kill the // server like this). Just spam the log a bit... ;) try { - dispatch(new PacketParser(packet, player)) + val stream = new ByteArrayInputStream(packet.data) + if (stream.read() == 0) dispatch(new PacketParser(stream, player)) + else dispatch(new PacketParser(new GZIPInputStream(stream), player)) } catch { case e: Throwable => OpenComputers.log.log(Level.WARNING, "Received a badly formatted packet.", e) @@ -40,7 +42,7 @@ abstract class PacketHandler extends IPacketHandler { protected def dispatch(p: PacketParser) - protected class PacketParser(packet: Packet250CustomPayload, val player: Player) extends DataInputStream(new ByteArrayInputStream(packet.data)) { + protected class PacketParser(stream: InputStream, val player: Player) extends DataInputStream(stream) { val packetType = PacketType(readByte()) def getTileEntity[T: ClassTag](dimension: Int, x: Int, y: Int, z: Int): Option[T] = { diff --git a/src/main/java/li/cil/oc/common/PacketType.scala b/src/main/java/li/cil/oc/common/PacketType.scala index 059b3d2f1..74f1d21ce 100644 --- a/src/main/java/li/cil/oc/common/PacketType.scala +++ b/src/main/java/li/cil/oc/common/PacketType.scala @@ -8,6 +8,7 @@ object PacketType extends Enumeration { ChargerState, ComputerState, ComputerUserList, + HologramClear, HologramScale, HologramSet, PowerState, diff --git a/src/main/java/li/cil/oc/common/tileentity/Hologram.scala b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala index f5f24e323..28318ade6 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala @@ -29,11 +29,35 @@ class Hologram extends Environment with SidedEnvironment { // Whether we need to send an update packet/recompile our display list. var dirty = false + // Interval of dirty columns. + var dirtyFromX = Int.MaxValue + var dirtyUntilX = -1 + var dirtyFromZ = Int.MaxValue + var dirtyUntilZ = -1 + // Time to wait before sending another update packet. - var cooldown = 0 + var cooldown = 5 var hasPower = true + def setDirty(x: Int, z: Int) { + dirty = true + dirtyFromX = math.min(dirtyFromX, x) + dirtyUntilX = math.max(dirtyUntilX, x + 1) + dirtyFromZ = math.min(dirtyFromZ, z) + dirtyUntilZ = math.max(dirtyUntilZ, z + 1) + litRatio = -1 + } + + def resetDirtyFlag() { + dirty = false + dirtyFromX = Int.MaxValue + dirtyUntilX = -1 + dirtyFromZ = Int.MaxValue + dirtyUntilZ = -1 + cooldown = 5 + } + // ----------------------------------------------------------------------- // override def canConnect(side: ForgeDirection) = side != ForgeDirection.UP @@ -45,7 +69,8 @@ class Hologram extends Environment with SidedEnvironment { @Callback(doc = """function() -- Clears the hologram.""") def clear(computer: Context, args: Arguments): Array[AnyRef] = this.synchronized { for (i <- 0 until volume.length) volume(i) = 0 - dirty = true + ServerPacketSender.sendHologramClear(this) + resetDirtyFlag() litRatio = 0 null } @@ -63,8 +88,7 @@ class Hologram extends Environment with SidedEnvironment { val z = args.checkInteger(1) - 1 val value = args.checkInteger(2) volume(x + z * width) = value - dirty = true - litRatio = -1 + setDirty(x, z) null } @@ -76,8 +100,7 @@ class Hologram extends Environment with SidedEnvironment { // Bit shifts in the JVM only use the lowest five bits... so we have to // manually check the height, to avoid the shift being a no-op. volume(x + z * width) = if (height > 0) 0xFFFFFFFF >>> (32 - height) else 0 - dirty = true - litRatio = -1 + setDirty(x, z) null } @@ -101,9 +124,8 @@ class Hologram extends Environment with SidedEnvironment { if (dirty) { cooldown -= 1 if (cooldown <= 0) { - dirty = false - cooldown = 10 ServerPacketSender.sendHologramSet(this) + resetDirtyFlag() } } if (litRatio < 0) { diff --git a/src/main/java/li/cil/oc/server/PacketSender.scala b/src/main/java/li/cil/oc/server/PacketSender.scala index 55dc419b3..077e325dc 100644 --- a/src/main/java/li/cil/oc/server/PacketSender.scala +++ b/src/main/java/li/cil/oc/server/PacketSender.scala @@ -1,9 +1,8 @@ package li.cil.oc.server import li.cil.oc.common -import li.cil.oc.common.PacketBuilder -import li.cil.oc.common.PacketType import li.cil.oc.common.tileentity._ +import li.cil.oc.common.{CompressedPacketBuilder, PacketBuilder, PacketType} import li.cil.oc.util.PackedColor import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.item.ItemStack @@ -55,6 +54,14 @@ object PacketSender { pb.sendToNearbyPlayers(t) } + def sendHologramClear(t: Hologram) { + val pb = new PacketBuilder(PacketType.HologramClear) + + pb.writeTileEntity(t) + + pb.sendToNearbyPlayers(t) + } + def sendHologramScale(t: Hologram) { val pb = new PacketBuilder(PacketType.HologramScale) @@ -65,11 +72,18 @@ object PacketSender { } def sendHologramSet(t: Hologram) { - val pb = new PacketBuilder(PacketType.HologramSet) + val pb = new CompressedPacketBuilder(PacketType.HologramSet) pb.writeTileEntity(t) - pb.writeInt(t.volume.length) - t.volume.foreach(pb.writeInt) + pb.writeByte(t.dirtyFromX) + pb.writeByte(t.dirtyUntilX) + pb.writeByte(t.dirtyFromZ) + pb.writeByte(t.dirtyUntilZ) + for (x <- t.dirtyFromX until t.dirtyUntilX) { + for (z <- t.dirtyFromZ until t.dirtyUntilZ) { + pb.writeInt(t.volume(x + z * t.width)) + } + } pb.sendToNearbyPlayers(t) }