diff --git a/src/main/resources/assets/opencomputers/loot/BetterShell/besh.lua b/src/main/resources/assets/opencomputers/loot/BetterShell/besh.lua index ae0bbda1c..370d7ed5b 100644 --- a/src/main/resources/assets/opencomputers/loot/BetterShell/besh.lua +++ b/src/main/resources/assets/opencomputers/loot/BetterShell/besh.lua @@ -360,7 +360,7 @@ end ------------------------------------------------------------------------------- -local function execute(command, env, ...) +local function execute(env, command, ...) checkArg(1, command, "string") local commands, reason = parseCommands(command) if not commands then @@ -479,39 +479,12 @@ local args, options = shell.parse(...) local history = {} if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then - -- interactive shell. - while true do - if not term.isAvailable() then -- don't clear unless we lost the term - while not term.isAvailable() do - event.pull("term_available") - end - term.clear() - end - while term.isAvailable() do - local foreground = component.gpu.setForeground(0xFF0000) - term.write(expand(os.getenv("PS1") or "$ ")) - component.gpu.setForeground(foreground) - local command = term.read(history) - if not command then - term.write("exit\n") - return -- eof - end - while #history > 10 do - table.remove(history, 1) - end - command = text.trim(command) - if command == "exit" then - return - elseif command ~= "" then - local result, reason = execute(command) - if not result then - io.stderr:write((tostring(reason) or "unknown error").. "\n") - elseif term.getCursor() > 1 then - term.write("\n") - end - end - end - end + -- interactive shell. use original shell for input but register self as + -- global SHELL for command execution. + local oldShell = os.getenv("SHELL") + os.setenv("SHELL", process.running()) + os.execute("/bin/sh") + os.setenv("SHELL", oldShell) else -- execute command. local result = table.pack(execute(...)) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/sh.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/sh.lua index 47ec37ce5..74b46f19d 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/sh.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/sh.lua @@ -41,7 +41,7 @@ local function evaluate(value) return result end -local function execute(command, ...) +local function execute(env, command, ...) local parts, reason = text.tokenize(command) if not parts then return false, reason @@ -119,7 +119,7 @@ if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then if command == "exit" then return elseif command ~= "" then - local result, reason = execute(command) + local result, reason = os.execute(command) if term.getCursor() > 1 then term.write("\n") end diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/shell.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/shell.lua index ff97529f6..64270ab76 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/lib/shell.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/lib/shell.lua @@ -5,6 +5,23 @@ local unicode = require("unicode") local shell = {} local aliases = {} +-- Cache loaded shells for command execution. This puts the requirement on +-- shells that they do not keep a global state, since they may be called +-- multiple times, but reduces memory usage a lot. +local shells = setmetatable({}, {__mode="v"}) + +local function getShell() + local shellName = shell.resolve(os.getenv("SHELL"), "lua") + if shells[shellName] then + return shells[shellName] + end + local sh, reason = loadfile(shellName, "t", env) + if sh then + shells[shellName] = sh + end + return sh, reason +end + local function findFile(name, ext) checkArg(1, name, "string") local function findIn(dir) @@ -129,11 +146,11 @@ function shell.resolve(path, ext) end function shell.execute(command, env, ...) - local sh, reason = loadfile(shell.resolve(os.getenv("SHELL"), "lua"), "t", env) + local sh, reason = getShell() if not sh then return false, reason end - local result = table.pack(pcall(sh, command, ...)) + local result = table.pack(pcall(sh, env, command, ...)) if not result[1] and type(result[2]) == "table" and result[2].reason == "terminated" then if result[2].code then return true diff --git a/src/main/resources/assets/opencomputers/lua/kernel.lua b/src/main/resources/assets/opencomputers/lua/kernel.lua index 146578dd6..350c86217 100644 --- a/src/main/resources/assets/opencomputers/lua/kernel.lua +++ b/src/main/resources/assets/opencomputers/lua/kernel.lua @@ -630,10 +630,20 @@ local function main() -- After memory footprint to avoid init.lua bumping the baseline. local co, args = bootstrap() + local forceGC = 10 while true do deadline = computer.realTime() + system.timeout() hitDeadline = false + + -- NOTE: since this is run in an executor thread and we enforce timeouts + -- in user-defined garbage collector callbacks this should be safe. + forceGC = forceGC - 1 + if forceGC < 1 then + collectgarbage("collect") + forceGC = 10 + end + debug.sethook(co, checkDeadline, "", hookInterval) local result = table.pack(coroutine.resume(co, table.unpack(args, 1, args.n))) if not result[1] then diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala index 9b9feba7d..632615192 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -288,8 +288,6 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit GL15.glBufferData(GL15.GL_ARRAY_BUFFER, 0L, GL15.GL_DYNAMIC_DRAW) } - println("HOLOGRAM SIZE: " + GL15.glGetBufferParameteri(GL15.GL_ARRAY_BUFFER, GL15.GL_BUFFER_SIZE) / 1024.0 / 1024.0) - // Reset for the next operation. dataBuffer.clear() diff --git a/src/main/scala/li/cil/oc/common/block/Screen.scala b/src/main/scala/li/cil/oc/common/block/Screen.scala index a7b2d88b3..98386a80f 100644 --- a/src/main/scala/li/cil/oc/common/block/Screen.scala +++ b/src/main/scala/li/cil/oc/common/block/Screen.scala @@ -329,7 +329,7 @@ abstract class Screen(val parent: SimpleDelegator) extends RedstoneAware with Si } override def collide(world: World, x: Int, y: Int, z: Int, entity: Entity) = - if (!world.isRemote) (entity, world.getBlockTileEntity(x, y, z)) match { + if (world.isRemote) (entity, world.getBlockTileEntity(x, y, z)) match { case (arrow: EntityArrow, screen: tileentity.Screen) if screen.tier > 0 => val hitX = math.max(0, math.min(1, arrow.posX - x)) val hitY = math.max(0, math.min(1, arrow.posY - y)) @@ -350,7 +350,7 @@ abstract class Screen(val parent: SimpleDelegator) extends RedstoneAware with Si else ForgeDirection.SOUTH } if (side == screen.facing) { - screen.shot(arrow, hitX, hitY, hitZ) + screen.shot(arrow) } case _ => } diff --git a/src/main/scala/li/cil/oc/common/tileentity/Screen.scala b/src/main/scala/li/cil/oc/common/tileentity/Screen.scala index ab4aa094b..54974ac79 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Screen.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Screen.scala @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.{Side, SideOnly} import li.cil.oc.api.network._ import li.cil.oc.Settings import li.cil.oc.util.Color +import net.minecraft.client.Minecraft import net.minecraft.entity.Entity import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.projectile.EntityArrow @@ -134,19 +135,8 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with } } - def shot(arrow: EntityArrow, hitX: Double, hitY: Double, hitZ: Double) { - // This is nasty, but I see no other way: arrows can trigger two collisions, - // once on their own when hitting a block, a second time via their entity's - // common collision checker. The second one (collision checker) has the - // better coordinates (arrow moved back out of the block it collided with), - // so use that when possible, otherwise resolve in next update. - if (!arrows.add(arrow)) { - arrows.remove(arrow) - arrow.shootingEntity match { - case player: EntityPlayer => click(player, hitX, hitY, hitZ) - case _ => - } - } + def shot(arrow: EntityArrow) { + arrows.add(arrow) } // ----------------------------------------------------------------------- // @@ -219,12 +209,22 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with } if (arrows.size > 0) { for (arrow <- arrows) { - val hitX = math.max(0, math.min(1, arrow.posX - x)) - val hitY = math.max(0, math.min(1, arrow.posY - y)) - val hitZ = math.max(0, math.min(1, arrow.posZ - z)) - shot(arrow, hitX, hitY, hitZ) + val hitX = arrow.posX - x + val hitY = arrow.posY - y + val hitZ = arrow.posZ - z + val hitXInner = math.abs(hitX - 0.5) < 0.45 + val hitYInner = math.abs(hitY - 0.5) < 0.45 + val hitZInner = math.abs(hitZ - 0.5) < 0.45 + if (hitXInner && hitYInner && !hitZInner || + hitXInner && !hitYInner && hitZInner || + !hitXInner && hitYInner && hitZInner) { + arrow.shootingEntity match { + case player: EntityPlayer if player == Minecraft.getMinecraft.thePlayer => click(player, hitX, hitY, hitZ) + case _ => + } + } } - assert(arrows.isEmpty) + arrows.clear() } }