From ef6d251c30a58c407e21a4a44da09a42e0a86caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 27 Mar 2015 15:52:22 +0100 Subject: [PATCH 01/22] Oops, that went directly into the stable branch earlier. --- src/main/scala/li/cil/oc/server/component/InternetCard.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/InternetCard.scala b/src/main/scala/li/cil/oc/server/component/InternetCard.scala index 7ae2037ce..2d7adda33 100644 --- a/src/main/scala/li/cil/oc/server/component/InternetCard.scala +++ b/src/main/scala/li/cil/oc/server/component/InternetCard.scala @@ -47,7 +47,7 @@ class InternetCard extends prefab.ManagedEnvironment { @Callback(direct = true, doc = """function():boolean -- Returns whether HTTP requests can be made (config setting).""") def isHttpEnabled(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.httpEnabled) - @Callback(doc = """function(url:string[, postData:string]):boolean -- Starts an HTTP request. If this returns true, further results will be pushed using `http_response` signals.""") + @Callback(doc = """function(url:string[, postData:string]):userdata -- Starts an HTTP request. If this returns true, further results will be pushed using `http_response` signals.""") def request(context: Context, args: Arguments): Array[AnyRef] = this.synchronized { checkOwner(context) val address = args.checkString(0) @@ -66,7 +66,7 @@ class InternetCard extends prefab.ManagedEnvironment { @Callback(direct = true, doc = """function():boolean -- Returns whether TCP connections can be made (config setting).""") def isTcpEnabled(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.tcpEnabled) - @Callback(doc = """function(address:string[, port:number]):number -- Opens a new TCP connection. Returns the handle of the connection.""") + @Callback(doc = """function(address:string[, port:number]):userdata -- Opens a new TCP connection. Returns the handle of the connection.""") def connect(context: Context, args: Arguments): Array[AnyRef] = this.synchronized { checkOwner(context) val address = args.checkString(0) From fa5a6f14b0f72e26704a5882a98285bedeed4da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 27 Mar 2015 19:25:39 +0100 Subject: [PATCH 02/22] Might make #973 go away. --- .../assets/opencomputers/lua/machine.lua | 20 +++--- .../oc/server/component/InternetCard.scala | 63 ++++++++----------- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/src/main/resources/assets/opencomputers/lua/machine.lua b/src/main/resources/assets/opencomputers/lua/machine.lua index 603d5e7b5..3402c90ec 100644 --- a/src/main/resources/assets/opencomputers/lua/machine.lua +++ b/src/main/resources/assets/opencomputers/lua/machine.lua @@ -908,7 +908,7 @@ wrappedUserdataMeta = { local wrappedUserdata = setmetatable({}, wrappedUserdataMeta) local function processResult(result) - wrapUserdata(result) -- needed for metamethods. + result = wrapUserdata(result) -- needed for metamethods. if not result[1] then -- error that should be re-thrown. error(result[2], 0) else -- success or already processed error. @@ -920,8 +920,9 @@ local function invoke(target, direct, ...) local result if direct then local args = table.pack(...) -- for unwrapping - unwrapUserdata(args) + args = unwrapUserdata(args) result = table.pack(target.invoke(table.unpack(args, 1, args.n))) + args = nil -- clear upvalue, avoids trying to persist it if result.n == 0 then -- limit for direct calls reached result = nil end @@ -930,9 +931,10 @@ local function invoke(target, direct, ...) if not result then local args = table.pack(...) -- for access in closure result = select(1, coroutine.yield(function() - unwrapUserdata(args) + args = unwrapUserdata(args) local result = table.pack(target.invoke(table.unpack(args, 1, args.n))) - wrapUserdata(result) + args = nil -- clear upvalue, avoids trying to persist it + result = wrapUserdata(result) return result end)) end @@ -941,8 +943,9 @@ end local function udinvoke(f, data, ...) local args = table.pack(...) - unwrapUserdata(args) + args = unwrapUserdata(args) local result = table.pack(f(data, table.unpack(args))) + args = nil -- clear upvalue, avoids trying to persist it return processResult(result) end @@ -1035,7 +1038,7 @@ function wrapUserdata(values) end return value end - wrapRecursively(values) + return wrapRecursively(values) end function unwrapUserdata(values) @@ -1054,7 +1057,7 @@ function unwrapUserdata(values) end return value end - unwrapRecursively(values) + return unwrapRecursively(values) end ------------------------------------------------------------------------------- @@ -1343,13 +1346,14 @@ local function main() debug.sethook(co, checkDeadline, "", hookInterval) local result = table.pack(coroutine.resume(co, table.unpack(args, 1, args.n))) + args = nil -- clear upvalue, avoids trying to persist it if not result[1] then error(tostring(result[2]), 0) elseif coroutine.status(co) == "dead" then error("computer halted", 0) else args = table.pack(coroutine.yield(result[2])) -- system yielded value - wrapUserdata(args) + args = wrapUserdata(args) end end end diff --git a/src/main/scala/li/cil/oc/server/component/InternetCard.scala b/src/main/scala/li/cil/oc/server/component/InternetCard.scala index 2d7adda33..74d5d1d0e 100644 --- a/src/main/scala/li/cil/oc/server/component/InternetCard.scala +++ b/src/main/scala/li/cil/oc/server/component/InternetCard.scala @@ -1,27 +1,15 @@ package li.cil.oc.server.component -import java.io.BufferedWriter -import java.io.FileNotFoundException -import java.io.IOException -import java.io.InputStream -import java.io.OutputStreamWriter +import java.io.{BufferedWriter, FileNotFoundException, IOException, InputStream, OutputStreamWriter} import java.net._ import java.nio.ByteBuffer import java.nio.channels.SocketChannel -import java.util.concurrent.Callable -import java.util.concurrent.ConcurrentLinkedQueue -import java.util.concurrent.ExecutionException -import java.util.concurrent.Future +import java.util.concurrent.{Callable, ConcurrentLinkedQueue, ExecutionException, Future} -import li.cil.oc.OpenComputers -import li.cil.oc.Settings -import li.cil.oc.api -import li.cil.oc.api.Network -import li.cil.oc.api.machine.Arguments -import li.cil.oc.api.machine.Callback -import li.cil.oc.api.machine.Context +import li.cil.oc.{OpenComputers, Settings, api} +import li.cil.oc.api.machine.{Arguments, Callback, Context} import li.cil.oc.api.network._ -import li.cil.oc.api.prefab +import li.cil.oc.api.{Network, prefab} import li.cil.oc.api.prefab.AbstractValue import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ThreadPoolFactory @@ -239,28 +227,30 @@ object InternetCard { }) } - private def checkConnected() = try { + private def checkConnected() = { if (owner.isEmpty) throw new IOException("connection lost") - if (isAddressResolved) channel.finishConnect() - else if (address.isCancelled) { - // I don't think this can ever happen, Justin Case. - channel.close() - throw new IOException("bad connection descriptor") - } - else if (address.isDone) { - // Check for errors. - try address.get catch { - case e: ExecutionException => throw e.getCause + try { + if (isAddressResolved) channel.finishConnect() + else if (address.isCancelled) { + // I don't think this can ever happen, Justin Case. + channel.close() + throw new IOException("bad connection descriptor") } - isAddressResolved = true - false + else if (address.isDone) { + // Check for errors. + try address.get catch { + case e: ExecutionException => throw e.getCause + } + isAddressResolved = true + false + } + else false + } + catch { + case t: Throwable => + close() + false } - else false - } - catch { - case t: Throwable => - close() - false } // This has to be an explicit internal class instead of an anonymous one @@ -430,6 +420,7 @@ object InternetCard { throw new IOException(Option(e.getMessage).getOrElse(e.toString)) } } + } } From fba95389be6df2ffa2406941938b567abde409e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 29 Mar 2015 01:35:34 +0100 Subject: [PATCH 03/22] Should fix #976. --- .../scala/li/cil/oc/client/renderer/HighlightRenderer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/client/renderer/HighlightRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/HighlightRenderer.scala index 1be622e5e..70a7b460b 100644 --- a/src/main/scala/li/cil/oc/client/renderer/HighlightRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/HighlightRenderer.scala @@ -28,7 +28,7 @@ object HighlightRenderer { lazy val tablet = api.Items.get(Constants.ItemName.Tablet) @SubscribeEvent - def onDrawBlockHighlight(e: DrawBlockHighlightEvent): Unit = { + def onDrawBlockHighlight(e: DrawBlockHighlightEvent): Unit = if (e.target != null && e.target.getBlockPos != null) { val hitInfo = e.target val world = e.player.getEntityWorld val blockPos = BlockPosition(hitInfo.getBlockPos, world) From d2d51b91220f821d6d6b02cbd10cc9eb73bcb036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 29 Mar 2015 13:23:08 +0200 Subject: [PATCH 04/22] Because the compiler told me to. --- .../scala/li/cil/oc/common/template/AssemblerTemplates.scala | 1 + src/main/scala/li/cil/oc/server/component/Geolyzer.scala | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/scala/li/cil/oc/common/template/AssemblerTemplates.scala b/src/main/scala/li/cil/oc/common/template/AssemblerTemplates.scala index 3eff3ae3f..f264b32c4 100644 --- a/src/main/scala/li/cil/oc/common/template/AssemblerTemplates.scala +++ b/src/main/scala/li/cil/oc/common/template/AssemblerTemplates.scala @@ -16,6 +16,7 @@ import net.minecraft.util.IChatComponent import net.minecraftforge.common.util.Constants.NBT import scala.collection.mutable +import scala.language.existentials object AssemblerTemplates { val NoSlot = new Slot(Slot.None, Tier.None, None, None) diff --git a/src/main/scala/li/cil/oc/server/component/Geolyzer.scala b/src/main/scala/li/cil/oc/server/component/Geolyzer.scala index 26d713852..f2c60bae5 100644 --- a/src/main/scala/li/cil/oc/server/component/Geolyzer.scala +++ b/src/main/scala/li/cil/oc/server/component/Geolyzer.scala @@ -25,6 +25,7 @@ import net.minecraftforge.common.util.ForgeDirection import scala.collection.convert.WrapAsJava._ import scala.collection.convert.WrapAsScala._ +import scala.language.existentials class Geolyzer(val host: EnvironmentHost) extends prefab.ManagedEnvironment { override val node = api.Network.newNode(this, Visibility.Network). From 5e9861d04a51c179da5ed5ba1f5a7a05591bcae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 29 Mar 2015 13:24:43 +0200 Subject: [PATCH 05/22] Temporarily disabling AE2 integration for rv2-beta-20 and newer due to methods that were deprecated in the API crashing now. --- src/main/scala/li/cil/oc/integration/Mods.scala | 6 +++++- .../li/cil/oc/integration/appeng/DriverController.scala | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index a3d8d034e..db071c751 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -19,7 +19,7 @@ object Mods { def All = knownMods.clone() - val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,)", providesPower = true) + val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,rv2-beta-19)", providesPower = true) val BattleGear2 = new SimpleMod(IDs.BattleGear2) val BloodMagic = new SimpleMod(IDs.BloodMagic) val BuildCraft = new SimpleMod(IDs.BuildCraft) @@ -199,6 +199,10 @@ object Mods { // This is called from the class transformer when injecting an interface of // this power type fails, to avoid class not found / class cast exceptions. def disablePower() = powerDisabled = true + + def container = Option(Loader.instance.getIndexedModList.get(id)) + + def version = container.map(_.getProcessedVersion) } class SimpleMod(val id: String, override val providesPower: Boolean = false, version: String = "") extends ModBase { diff --git a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala index c7698aec7..e6b5bb58c 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala @@ -7,7 +7,6 @@ import appeng.api.networking.crafting.ICraftingRequester import appeng.api.networking.security.IActionHost import appeng.api.networking.security.MachineSource import appeng.api.storage.data.IAEItemStack -import appeng.core.Api import appeng.me.helpers.IGridProxyable import appeng.tile.misc.TileInterface import appeng.tile.networking.TileController @@ -40,6 +39,7 @@ import scala.collection.convert.WrapAsScala._ import scala.collection.mutable import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future +import scala.language.existentials object DriverController extends DriverTileEntity with EnvironmentAware { private type AETile = TileEntity with IGridProxyable with IActionHost @@ -210,7 +210,7 @@ object DriverController extends DriverTileEntity with EnvironmentAware { }) } links ++= nbt.getTagList("links", NBT.TAG_COMPOUND).map( - (nbt: NBTTagCompound) => Api.instance.storage.loadCraftingLink(nbt, this)) + (nbt: NBTTagCompound) => AEApi.instance.storage.loadCraftingLink(nbt, this)) } override def save(nbt: NBTTagCompound) { From d13cdc0cd87e3d6dbaa8655972c283ec484455ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 29 Mar 2015 22:45:43 +0200 Subject: [PATCH 06/22] Somewhat experimental fix for memory leaks seen in Microcontrollers. If you notice any new issues after this, please do let me know. This essentially schedules machines for full cleanup at a later point, to allow executor threads to finish (can't close states while they're running, don't want to wait for them to finish to avoid lagging servers). --- .../scala/li/cil/oc/common/EventHandler.scala | 11 +++++- .../common/tileentity/traits/Computer.scala | 5 +++ .../li/cil/oc/server/machine/Machine.scala | 37 +++++++++++++------ 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/EventHandler.scala b/src/main/scala/li/cil/oc/common/EventHandler.scala index 1411e5046..06287183f 100644 --- a/src/main/scala/li/cil/oc/common/EventHandler.scala +++ b/src/main/scala/li/cil/oc/common/EventHandler.scala @@ -22,6 +22,7 @@ import li.cil.oc.common.tileentity.traits.power import li.cil.oc.integration.Mods import li.cil.oc.integration.util import li.cil.oc.server.component.Keyboard +import li.cil.oc.server.machine.Machine import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.util._ import net.minecraft.client.Minecraft @@ -49,12 +50,16 @@ object EventHandler { private val keyboards = java.util.Collections.newSetFromMap[Keyboard](new java.util.WeakHashMap[Keyboard, java.lang.Boolean]) + private val machines = mutable.Set.empty[Machine] + def onRobotStart(robot: Robot): Unit = runningRobots += robot def onRobotStopped(robot: Robot): Unit = runningRobots -= robot def addKeyboard(keyboard: Keyboard): Unit = keyboards += keyboard + def scheduleClose(machine: Machine) = machines += machine + def schedule(tileEntity: TileEntity) { if (SideTracker.isServer) pending.synchronized { pending += (() => Network.joinOrCreateNetwork(tileEntity)) @@ -130,6 +135,10 @@ object EventHandler { else if (robot.world != null) robot.machine.update() }) runningRobots --= invalid + + val closed = mutable.ArrayBuffer.empty[Machine] + machines.foreach(machine => if (machine.tryClose()) closed += machine) + machines --= closed } @SubscribeEvent @@ -243,7 +252,7 @@ object EventHandler { didRecraft = recraft(e, tablet, stack => { // Restore EEPROM currently used in tablet. - new TabletData(stack).items.collect { case Some(item) => item}.find(api.Items.get(_) == eeprom) + new TabletData(stack).items.collect { case Some(item) => item }.find(api.Items.get(_) == eeprom) }) || didRecraft // Presents? diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala index 954634278..1a9eaf34e 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala @@ -127,6 +127,11 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B ServerPacketSender.sendComputerState(this) } + override def dispose(): Unit = { + super.dispose() + if (machine != null) machine.stop() + } + // ----------------------------------------------------------------------- // override def readFromNBTForServer(nbt: NBTTagCompound) { diff --git a/src/main/scala/li/cil/oc/server/machine/Machine.scala b/src/main/scala/li/cil/oc/server/machine/Machine.scala index 3c40bf31c..7f9de376f 100644 --- a/src/main/scala/li/cil/oc/server/machine/Machine.scala +++ b/src/main/scala/li/cil/oc/server/machine/Machine.scala @@ -23,6 +23,7 @@ import li.cil.oc.api.network.Message import li.cil.oc.api.network.Node import li.cil.oc.api.network.Visibility import li.cil.oc.api.prefab +import li.cil.oc.common.EventHandler import li.cil.oc.common.SaveHandler import li.cil.oc.common.Slot import li.cil.oc.common.tileentity @@ -257,6 +258,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach false case _ => state.push(Machine.State.Stopping) + EventHandler.scheduleClose(this) true }) @@ -392,6 +394,8 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach // ----------------------------------------------------------------------- // + def isExecuting = state.synchronized(state.contains(Machine.State.Running)) + override val canUpdate = true override def update() = if (state.synchronized(state.top != Machine.State.Stopped)) { @@ -514,7 +518,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach inSynchronizedCall = false } - assert(state.top != Machine.State.Running) + assert(!isExecuting) case _ => // Nothing special to do, just avoid match errors. }) @@ -643,7 +647,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach super.load(nbt) - state.pushAll(nbt.getIntArray("state").reverse.map(Machine.State(_))) + state.pushAll(nbt.getIntArray("state").reverseMap(Machine.State(_))) nbt.getTagList("users", NBT.TAG_STRING).foreach((tag: NBTTagString) => _users += tag.func_150285_a_()) if (nbt.hasKey("message")) { message = Some(nbt.getString("message")) @@ -703,7 +707,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach } override def save(nbt: NBTTagCompound): Unit = Machine.this.synchronized { - assert(state.top != Machine.State.Running) // Lock on 'this' should guarantee this. + assert(!isExecuting) // Lock on 'this' should guarantee this. // Make sure we don't continue running until everything has saved. pause(0.05) @@ -798,16 +802,25 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach false } + def tryClose(): Boolean = + if (isExecuting) false + else { + close() + true + } + private def close() = state.synchronized( if (state.size == 0 || state.top != Machine.State.Stopped) { - state.clear() - state.push(Machine.State.Stopped) - Option(architecture).foreach(_.close()) - signals.clear() - uptime = 0 - cpuTotal = 0 - cpuStart = 0 - remainIdle = 0 + this.synchronized { + state.clear() + state.push(Machine.State.Stopped) + Option(architecture).foreach(_.close()) + signals.clear() + uptime = 0 + cpuTotal = 0 + cpuStart = 0 + remainIdle = 0 + } // Mark state change in owner, to send it to clients. host.markChanged() @@ -909,7 +922,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach case Machine.State.Stopping => // Nothing to do, we'll die anyway. case _ => throw new AssertionError("Invalid state in executor post-processing.") } - assert(state.top != Machine.State.Running) + assert(!isExecuting) } } catch { From 6115617ce027a5d6fae1d18cd7433f73caef58ce Mon Sep 17 00:00:00 2001 From: Vexatos Date: Mon, 30 Mar 2015 09:53:49 +0200 Subject: [PATCH 07/22] Update oppm.lua --- .../assets/opencomputers/loot/OPPM/oppm.lua | 126 ++++++++++++++---- 1 file changed, 100 insertions(+), 26 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/OPPM/oppm.lua b/src/main/resources/assets/opencomputers/loot/OPPM/oppm.lua index 741bcb81f..f6621e43d 100644 --- a/src/main/resources/assets/opencomputers/loot/OPPM/oppm.lua +++ b/src/main/resources/assets/opencomputers/loot/OPPM/oppm.lua @@ -10,18 +10,22 @@ local serial = require("serialization") local shell = require("shell") local term = require("term") -local wget = loadfile("/bin/wget.lua") - local gpu = component.gpu -if not component.isAvailable("internet") then - io.stderr:write("This program requires an internet card to run.") - return -end -local internet = require("internet") +local internet +local wget local args, options = shell.parse(...) +local function getInternet() + if not component.isAvailable("internet") then + io.stderr:write("This program requires an internet card to run.") + return false + end + internet = require("internet") + wget = loadfile("/bin/wget.lua") + return true +end local function printUsage() print("OpenPrograms Package Manager, use this to browse through and download OpenPrograms programs easily") @@ -43,9 +47,9 @@ local function getContent(url) if not result then return nil end - for chunk in response do - sContent = sContent..chunk - end + for chunk in response do + sContent = sContent..chunk + end return sContent end @@ -80,6 +84,9 @@ local function downloadFile(url,path,force) if options.f or force then return wget("-fq",url,path) else + if fs.exists(path) then + error("file already exists and option -f is not enabled") + end return wget("-q",url,path) end end @@ -209,6 +216,67 @@ local function printPackages(packs) end end +local function parseFolders(pack, repo, info) + + local function getFolderTable(repo, namePath, branch) + local success, filestring = pcall(getContent,"https://api.github.com/repos/"..repo.."/contents/"..namePath.."?ref="..branch) + if not success or filestring:find('"message": "Not Found"') then + io.stderr:write("Error while trying to parse folder names in declaration of package "..pack..".\n") + if filestring:find('"message": "Not Found"') then + io.stderr:write("Folder "..namePath.." does not exist.\n") + else + io.stderr:write(filestring.."\n") + end + io.stderr:write("Please contact the author of that package.\n") + return nil + end + return serial.unserialize(filestring:gsub("%[", "{"):gsub("%]", "}"):gsub("(\"[^%s,]-\")%s?:", "[%1] = "), nil) + end + + local function nonSpecial(text) + return text:gsub("([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") + end + + local function unserializeFiles(files, repo, namePath, branch, relPath) + if not files then return nil end + local tFiles = {} + for _,v in pairs(files) do + if v["type"] == "file" then + local newPath = v["download_url"]:gsub("https?://raw.githubusercontent.com/"..nonSpecial(repo).."(.+)$", "%1"):gsub("/*$",""):gsub("^/*","") + tFiles[newPath] = relPath + elseif v["type"] == "dir" then + local newFiles = unserializeFiles(getFolderTable(repo, relPath.."/"..v["name"], branch), repo, branch, fs.concat(relPath, v["name"])) + for p,q in pairs(newFiles) do + tFiles[p] = q + end + end + end + return tFiles + end + + local newInfo = info + for i,j in pairs(info.files) do + if string.find(i,"^:") then + local iPath = i:gsub("^:","") + local branch = string.gsub(iPath,"^(.-)/.+","%1"):gsub("/*$",""):gsub("^/*","") + local namePath = string.gsub(iPath,".-(/.+)$","%1"):gsub("/*$",""):gsub("^/*","") + local absolutePath = j:find("^//") + + local files = unserializeFiles(getFolderTable(repo, namePath, branch), repo, namePath, branch, j:gsub("^//","/")) + if not files then return nil end + for p,q in pairs(files) do + if absolutePath then + newInfo.files[p] = "/"..q + else + newInfo.files[p] = q + end + end + newInfo.files[i] = nil + end + end + return newInfo +end + local function getInformation(pack) local success, repos = pcall(getRepos) if not success or repos==-1 then @@ -223,7 +291,7 @@ local function getInformation(pack) elseif type(lPacks) == "table" then for k in pairs(lPacks) do if k==pack then - return lPacks[k],j.repo + return parseFolders(pack, j.repo, lPacks[k]),j.repo end end end @@ -234,7 +302,7 @@ local function getInformation(pack) for i,j in pairs(lRepos.repos) do for k in pairs(j) do if k==pack then - return j[k],i + return parseFolders(pack, i, j[k]),i end end end @@ -271,14 +339,17 @@ local function provideInfo(pack) print("Note: "..info.note) done = true end + if info.files then + print("Number of files: "..tostring(#info.files)) + done = true + end if not done then print("No information provided.") end end -local tPacks = readFromFile(1) - local function installPackage(pack,path,update) + local tPacks = readFromFile(1) update = update or false if not pack then printUsage() @@ -309,8 +380,12 @@ local function installPackage(pack,path,update) if update then print("Updating package "..pack) path = nil + if not tPacks[pack] then + io.stderr:write("error while checking update path") + return + end for i,j in pairs(info.files) do - if tPacks[pack] then + if not string.find(j,"^//") then for k,v in pairs(tPacks[pack]) do if k==i then path = string.gsub(fs.path(v),j.."/?$","/") @@ -320,9 +395,6 @@ local function installPackage(pack,path,update) if path then break end - else - io.stderr:write("error while checking update path") - return end end path = shell.resolve(string.gsub(path,"^/?","/"),nil) @@ -381,7 +453,8 @@ local function installPackage(pack,path,update) if success and response then tPacks[pack][i] = nPath else - term.write("Error while installing files for package '"..pack.."'. Reverting installation... ") + response = response or "no error message" + term.write("Error while installing files for package '"..pack.."': "..response..". Reverting installation... ") fs.remove(nPath) for o,p in pairs(tPacks[pack]) do fs.remove(p) @@ -405,7 +478,8 @@ local function installPackage(pack,path,update) if success and response then tPacks[pack][i] = nPath else - term.write("Error while installing dependency package '"..i.."'. Reverting installation... ") + response = response or "no error message" + term.write("Error while installing files for package '"..pack.."': "..response..". Reverting installation... ") fs.remove(nPath) for o,p in pairs(tPacks[pack]) do fs.remove(p) @@ -429,11 +503,6 @@ local function installPackage(pack,path,update) end local function uninstallPackage(pack) - local info,repo = getInformation(pack) - if not info then - print("Package does not exist") - return - end local tFiles = readFromFile(1) if not tFiles then io.stderr:write("Error while trying to read package names") @@ -443,7 +512,8 @@ local function uninstallPackage(pack) end if not tFiles[pack] then print("Package has not been installed.") - print("If it has, you have to remove it manually.") + print("If it has, the package could not be identified.") + print("In this case you have to remove it manually.") return end term.write("Removing package files...") @@ -482,13 +552,17 @@ end if options.iKnowWhatIAmDoing then if args[1] == "list" then + if not getInternet() then return end local packs = listPackages(args[2]) printPackages(packs) elseif args[1] == "info" then + if not getInternet() then return end provideInfo(args[2]) elseif args[1] == "install" then + if not getInternet() then return end installPackage(args[2],args[3],false) elseif args[1] == "update" then + if not getInternet() then return end updatePackage(args[2]) elseif args[1] == "uninstall" then uninstallPackage(args[2]) From e48004f1b48bfa1eea5982d23b56a446b13e19fe Mon Sep 17 00:00:00 2001 From: Vexatos Date: Mon, 30 Mar 2015 13:03:04 +0200 Subject: [PATCH 08/22] Just a small and important change --- src/main/resources/assets/opencomputers/loot/OPPM/oppm.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/resources/assets/opencomputers/loot/OPPM/oppm.lua b/src/main/resources/assets/opencomputers/loot/OPPM/oppm.lua index f6621e43d..c7811b00a 100644 --- a/src/main/resources/assets/opencomputers/loot/OPPM/oppm.lua +++ b/src/main/resources/assets/opencomputers/loot/OPPM/oppm.lua @@ -1,6 +1,11 @@ --[[ OpenPrograms package manager, browser and downloader, for easy access to many programs Author: Vexatos + +Warning! This file is just an auto-installer for OPPM! +DO NOT EVER TRY TO INSTALL A PACKAGE WITH THIS! +Once you ran OPPM once, you can remove the floppy disk +and run the installed OPPM version just fine. ]] local component = require("component") local event = require("event") From 952d5f203851625c52ad22f462e1299ce1133375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 30 Mar 2015 13:49:18 +0200 Subject: [PATCH 09/22] Should fix a few issues with the experimental memory leak fix, such as robots shutting down when moving. --- .../oc/common/tileentity/traits/Computer.scala | 4 +++- .../li/cil/oc/server/machine/Machine.scala | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala index 1a9eaf34e..205e97f6e 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/Computer.scala @@ -129,7 +129,9 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B override def dispose(): Unit = { super.dispose() - if (machine != null) machine.stop() + if (machine != null && !this.isInstanceOf[RobotProxy]) { + machine.stop() + } } // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/server/machine/Machine.scala b/src/main/scala/li/cil/oc/server/machine/Machine.scala index 7f9de376f..b25c18bb4 100644 --- a/src/main/scala/li/cil/oc/server/machine/Machine.scala +++ b/src/main/scala/li/cil/oc/server/machine/Machine.scala @@ -264,7 +264,15 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach override def crash(message: String) = { this.message = Option(message) - stop() + state.synchronized { + val result = stop() + if (state.top == Machine.State.Stopping) { + // When crashing, make sure there's no "Running" left in the stack. + state.clear() + state.push(Machine.State.Stopping) + } + result + } } override def signal(name: String, args: AnyRef*) = state.synchronized(state.top match { @@ -503,7 +511,9 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach state.pop() // Running, no switchTo to avoid new future. state.push(Machine.State.SynchronizedReturn) state.push(Machine.State.Paused) - case Machine.State.Stopping => // Nothing to do, we'll die anyway. + case Machine.State.Stopping => + state.clear() + state.push(Machine.State.Stopping) case _ => throw new AssertionError() } } @@ -919,7 +929,9 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach crash(Option(result.message).getOrElse("unknown error")) } state.push(Machine.State.Paused) - case Machine.State.Stopping => // Nothing to do, we'll die anyway. + case Machine.State.Stopping => + state.clear() + state.push(Machine.State.Stopping) case _ => throw new AssertionError("Invalid state in executor post-processing.") } assert(!isExecuting) From 4b354551a095f63d9bcc0b09255a21ecae9e1d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 30 Mar 2015 16:45:45 +0200 Subject: [PATCH 10/22] Fixed wrong UV mapping on 3D prints (in particular the item renderer). --- .../client/renderer/block/BlockRenderer.scala | 3 +- .../client/renderer/item/ItemRenderer.scala | 32 +++++++++---------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala index cfc0394d7..092561ab4 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala @@ -141,7 +141,8 @@ object BlockRenderer extends ISimpleBlockRenderingHandler { } // The texture flip this works around only seems to occur for blocks with custom block renderers? - def patchedRenderer(renderer: RenderBlocks, block: Block) = if (block.isInstanceOf[Hologram] || block.isInstanceOf[Printer]) { + def patchedRenderer(renderer: RenderBlocks, block: Block) = + if (block.isInstanceOf[Hologram] || block.isInstanceOf[Printer] || block.isInstanceOf[Print]) { PatchedRenderBlocks.blockAccess = renderer.blockAccess PatchedRenderBlocks.overrideBlockTexture = renderer.overrideBlockTexture PatchedRenderBlocks.flipTexture = renderer.flipTexture diff --git a/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala index d39ee1675..b1e497b0b 100644 --- a/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala @@ -258,24 +258,24 @@ object ItemRenderer extends IItemRenderer { // Front. GL11.glNormal3f(0, 0, 1) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.minY * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(16 - bounds.minY * 16)) GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.minY * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(16 - bounds.minY * 16)) GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.maxY * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(16 - bounds.maxY * 16)) GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.maxY * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(16 - bounds.maxY * 16)) GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ) // Back. GL11.glNormal3f(0, 0, -1) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.minY * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(16 - bounds.minY * 16)) GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.minZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.minY * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(16 - bounds.minY * 16)) GL11.glVertex3d(bounds.minX, bounds.minY, bounds.minZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.maxY * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(16 - bounds.maxY * 16)) GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.minZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.maxY * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(16 - bounds.maxY * 16)) GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.minZ) // Top. @@ -302,24 +302,24 @@ object ItemRenderer extends IItemRenderer { // Left. GL11.glNormal3f(1, 0, 0) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxY * 16), texture.getInterpolatedV(bounds.maxZ * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxZ * 16), texture.getInterpolatedV(16 - bounds.maxY * 16)) GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minY * 16), texture.getInterpolatedV(bounds.maxZ * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxZ * 16), texture.getInterpolatedV(16 - bounds.minY * 16)) GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minY * 16), texture.getInterpolatedV(bounds.minZ * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minZ * 16), texture.getInterpolatedV(16 - bounds.minY * 16)) GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.minZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxY * 16), texture.getInterpolatedV(bounds.minZ * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minZ * 16), texture.getInterpolatedV(16 - bounds.maxY * 16)) GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.minZ) // Right. GL11.glNormal3f(-1, 0, 0) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minY * 16), texture.getInterpolatedV(bounds.maxZ * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxZ * 16), texture.getInterpolatedV(16 - bounds.minY * 16)) GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxY * 16), texture.getInterpolatedV(bounds.maxZ * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxZ * 16), texture.getInterpolatedV(16 - bounds.maxY * 16)) GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxY * 16), texture.getInterpolatedV(bounds.minZ * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minZ * 16), texture.getInterpolatedV(16 - bounds.maxY * 16)) GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.minZ) - GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minY * 16), texture.getInterpolatedV(bounds.minZ * 16)) + GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minZ * 16), texture.getInterpolatedV(16 - bounds.minY * 16)) GL11.glVertex3d(bounds.minX, bounds.minY, bounds.minZ) GL11.glEnd() From 6afc31b62427cfb2def1ed709cf7d2b4e42729e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 30 Mar 2015 17:34:15 +0200 Subject: [PATCH 11/22] Updated some dependencies, should close #984. Also updated Forge to allow running mods in dev env that depend on it (such as AE2). --- build.gradle | 14 +++++++------- build.properties | 14 +++++++------- .../oc/integration/appeng/DriverController.scala | 6 +++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/build.gradle b/build.gradle index 7adcd9391..553ff73ac 100644 --- a/build.gradle +++ b/build.gradle @@ -118,27 +118,27 @@ repositories { ivy { name 'CoFHLib' - artifactPattern "http://addons.cursecdn.com/files/${config.cofhlib.cf}/[module]-[revision].[ext]" + artifactPattern "http://addons-origin.cursecdn.com/files/${config.cofhlib.cf}/[module]-[revision].[ext]" } ivy { name 'MineFactoryReloaded' - artifactPattern "http://addons.cursecdn.com/files/${config.mfr.cf}/[module]-[revision].[ext]" + artifactPattern "http://addons-origin.cursecdn.com/files/${config.mfr.cf}/[module]-[revision].[ext]" } ivy { name 'ComputerCraft' - artifactPattern "http://addons.cursecdn.com/files/${config.cc.cf}/[module][revision].[ext]" + artifactPattern "http://addons-origin.cursecdn.com/files/${config.cc.cf}/[module][revision].[ext]" } ivy { name 'EnderIO' - artifactPattern "http://addons.cursecdn.com/files/${config.eio.cf}/[module]-[revision].[ext]" + artifactPattern "http://addons-origin.cursecdn.com/files/${config.eio.cf}/[module]-[revision].[ext]" } ivy { name 'Railcraft' - artifactPattern "http://addons.cursecdn.com/files/${config.rc.cf}/[module]_[revision].[ext]" + artifactPattern "http://addons-origin.cursecdn.com/files/${config.rc.cf}/[module]_[revision].[ext]" } ivy { name 'BloodMagic' - artifactPattern "http://addons.cursecdn.com/files/${config.bloodmagic.cf}/[module]-${config.minecraft.version}-[revision].[ext]" + artifactPattern "http://addons-origin.cursecdn.com/files/${config.bloodmagic.cf}/[module]-${config.minecraft.version}-[revision].[ext]" } } @@ -149,7 +149,7 @@ configurations { } dependencies { - provided "api:rotarycraft:${config.rotc.version}" + provided "appeng:RotaryCraft:${config.rotc.version}:api" provided "appeng:appliedenergistics2:${config.ae2.version}:dev" provided "codechicken:CodeChickenLib:${config.minecraft.version}-${config.ccl.version}:dev" provided "codechicken:EnderStorage:${config.minecraft.version}-${config.es.version}:dev" diff --git a/build.properties b/build.properties index 0708e5f16..4db53329a 100644 --- a/build.properties +++ b/build.properties @@ -1,18 +1,18 @@ minecraft.version=1.7.10 -forge.version=10.13.2.1236 +forge.version=10.13.2.1291 oc.version=1.5.4 oc.subversion=dev -ae2.version=rv1-stable-1 +ae2.version=rv2-beta-22 bc.version=6.2.6 bloodmagic.cf=2223/203 bloodmagic.version=1.3.0a-1 cc.cf=2216/236 cc.version=1.65 ccl.version=1.1.1.104 -cofhlib.cf=2218/257 -cofhlib.version=[1.7.10]1.0.0B7-dev-29 +cofhlib.cf=2230/207 +cofhlib.version=[1.7.10]1.0.0RC7-127 eio.cf=2219/296 eio.version=1.7.10-2.2.1.276 es.version=1.4.5.24 @@ -24,14 +24,14 @@ gt.version=5.04.06 ic2.version=2.2.654-experimental mekanism.build=5 mekanism.version=7.1.2 -mfr.cf=2213/46 -mfr.version=[1.7.10]2.8.0RC3-dev-591 +mfr.cf=2229/626 +mfr.version=[1.7.10]2.8.0RC8-86 nei.version=1.0.3.57 projred.version=4.5.8.59 rc.cf=2219/321 rc.version=1.7.10-9.4.0.0 redlogic.version=59.0.3 -rotc.version=1 +rotc.version=V5c tmech.version=75.0afb56c re.version=3.0.0.342 waila.version=1.5.8a diff --git a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala index e6b5bb58c..3b60ab7f0 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala @@ -9,7 +9,6 @@ import appeng.api.networking.security.MachineSource import appeng.api.storage.data.IAEItemStack import appeng.me.helpers.IGridProxyable import appeng.tile.misc.TileInterface -import appeng.tile.networking.TileController import appeng.util.item.AEItemStack import com.google.common.collect.ImmutableSet import li.cil.oc.OpenComputers @@ -44,10 +43,11 @@ import scala.language.existentials object DriverController extends DriverTileEntity with EnvironmentAware { private type AETile = TileEntity with IGridProxyable with IActionHost - def getTileEntityClass = { + def getTileEntityClass: Class[_] = { if (AEApi.instance != null && AEApi.instance.blocks != null) { if (AEApi.instance.blocks.blockController != null && AEApi.instance.blocks.blockController.item != null) - classOf[TileController] + // Not classOf[TileController] because that derps the compiler when it tries to resolve the class (says can't find API classes from RotaryCraft). + Class.forName("appeng.tile.networking.TileController") else classOf[TileInterface] } From 20715298e07f8d4bedd9fa0690901e1505c7d145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 30 Mar 2015 17:57:27 +0200 Subject: [PATCH 12/22] Re-enabling AE2 integration for newer version, because issue seems to be fixed as of version rv2-beta-22. --- src/main/scala/li/cil/oc/integration/Mods.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index db071c751..72be050af 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -19,7 +19,7 @@ object Mods { def All = knownMods.clone() - val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,rv2-beta-19)", providesPower = true) + val AppliedEnergistics2 = new SimpleMod(IDs.AppliedEnergistics2, version = "@[rv1,)", providesPower = true) val BattleGear2 = new SimpleMod(IDs.BattleGear2) val BloodMagic = new SimpleMod(IDs.BloodMagic) val BuildCraft = new SimpleMod(IDs.BuildCraft) From b2a0a8d90c755f467a6780c97527c3808c35315a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 30 Mar 2015 18:33:19 +0200 Subject: [PATCH 13/22] Updated BuildCraft dependency. --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 4db53329a..9877f81e3 100644 --- a/build.properties +++ b/build.properties @@ -5,7 +5,7 @@ oc.version=1.5.4 oc.subversion=dev ae2.version=rv2-beta-22 -bc.version=6.2.6 +bc.version=6.4.5 bloodmagic.cf=2223/203 bloodmagic.version=1.3.0a-1 cc.cf=2216/236 From 4d5c923c42a9a4f42489acd8a8b1367fd667a3a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 30 Mar 2015 23:36:27 +0200 Subject: [PATCH 14/22] Allow recycling prints by using them as material input for printers, closes #986. --- src/main/resources/application.conf | 6 ++ src/main/scala/li/cil/oc/Settings.scala | 1 + .../li/cil/oc/common/tileentity/Printer.scala | 75 ++++++++++++------- 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index e92ac11e8..20c4c98d9 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1035,6 +1035,12 @@ opencomputers { # this many shapes *per state* (the reasoning being that only one state # will ever be visible at a time). maxPrinterShapes: 24 + + # How much of the material used to print a model is refunded when using + # the model to refuel a printer. This the value the original material + # cost is multiplied with, so 1 is a full refund, 0 disables the + # functionality (won't be able to put prints into the material input). + printRecycleRate: 0.75 } # Settings for mod integration (the mod previously known as OpenComponents). diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 2b4f54715..e83c479c6 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -294,6 +294,7 @@ class Settings(val config: Config) { val assemblerBlacklist = config.getStringList("misc.assemblerBlacklist") val threadPriority = config.getInt("misc.threadPriority") val maxPrintComplexity = config.getInt("misc.maxPrinterShapes") + val printRecycleRate = config.getDouble("misc.printRecycleRate") // ----------------------------------------------------------------------- // // integration diff --git a/src/main/scala/li/cil/oc/common/tileentity/Printer.scala b/src/main/scala/li/cil/oc/common/tileentity/Printer.scala index 1e2ff9394..7e6016d50 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Printer.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Printer.scala @@ -188,10 +188,36 @@ class Printer extends traits.Environment with traits.Inventory with traits.Rotat // ----------------------------------------------------------------------- // - override def canUpdate = isServer + def computeCosts(data: PrintData) = { + val totalVolume = data.stateOn.foldLeft(0)((acc, shape) => acc + shape.bounds.volume) + data.stateOff.foldLeft(0)((acc, shape) => acc + shape.bounds.volume) + val totalSurface = data.stateOn.foldLeft(0)((acc, shape) => acc + shape.bounds.surface) + data.stateOff.foldLeft(0)((acc, shape) => acc + shape.bounds.surface) + + if (totalVolume > 0) { + val materialRequired = (totalVolume / 2) max 1 + val inkRequired = (totalSurface / 6) max 1 + + Option((materialRequired, inkRequired)) + } + else None + } + + def materialValue(stack: ItemStack) = { + if (api.Items.get(stack) == api.Items.get("chamelium")) + materialPerItem + else if (api.Items.get(stack) == api.Items.get("print")) { + val data = new PrintData(stack) + computeCosts(data) match { + case Some((materialRequired, inkRequired)) => (materialRequired * Settings.get.printRecycleRate).toInt + case _ => 0 + } + } + else 0 + } // ----------------------------------------------------------------------- // + override def canUpdate = isServer + override def updateEntity() { super.updateEntity() @@ -202,28 +228,22 @@ class Printer extends traits.Environment with traits.Inventory with traits.Rotat } if (isActive && output.isEmpty && canMergeOutput) { - val totalVolume = data.stateOn.foldLeft(0)((acc, shape) => acc + shape.bounds.volume) + data.stateOff.foldLeft(0)((acc, shape) => acc + shape.bounds.volume) - val totalSurface = data.stateOn.foldLeft(0)((acc, shape) => acc + shape.bounds.surface) + data.stateOff.foldLeft(0)((acc, shape) => acc + shape.bounds.surface) + computeCosts(data) match { + case Some((materialRequired, inkRequired)) => + totalRequiredEnergy = Settings.get.printCost + requiredEnergy = totalRequiredEnergy - if (totalVolume == 0) { - isActive = false - data = new PrintData() - } - else { - val materialRequired = (totalVolume / 2) max 1 - val inkRequired = (totalSurface / 6) max 1 - - totalRequiredEnergy = Settings.get.printCost - requiredEnergy = totalRequiredEnergy - - if (amountMaterial >= materialRequired && amountInk >= inkRequired) { - amountMaterial -= materialRequired - amountInk -= inkRequired - limit -= 1 - output = Option(data.createItemStack()) - if (limit < 1) isActive = false - ServerPacketSender.sendPrinting(this, printing = true) - } + if (amountMaterial >= materialRequired && amountInk >= inkRequired) { + amountMaterial -= materialRequired + amountInk -= inkRequired + limit -= 1 + output = Option(data.createItemStack()) + if (limit < 1) isActive = false + ServerPacketSender.sendPrinting(this, printing = true) + } + case _ => + isActive = false + data = new PrintData() } } @@ -249,10 +269,11 @@ class Printer extends traits.Environment with traits.Inventory with traits.Rotat ServerPacketSender.sendPrinting(this, have > 0.5 && output.isDefined) } - if (maxAmountMaterial - amountMaterial >= materialPerItem) { + val inputValue = materialValue(getStackInSlot(slotMaterial)) + if (inputValue > 0 && maxAmountMaterial - amountMaterial >= inputValue) { val material = decrStackSize(slotMaterial, 1) if (material != null) { - amountMaterial += materialPerItem + amountMaterial += inputValue } } @@ -310,9 +331,9 @@ class Printer extends traits.Environment with traits.Inventory with traits.Rotat override def getInventoryStackLimit = 64 override def isItemValidForSlot(slot: Int, stack: ItemStack) = - if (slot == 0) - api.Items.get(stack) == api.Items.get("chamelium") - else if (slot == 1) + if (slot == slotMaterial) + materialValue(stack) > 0 + else if (slot == slotInk) api.Items.get(stack) == api.Items.get("inkCartridge") else false From f4bcb0718e9e74760ee9b35c3b2414a33fc96162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 30 Mar 2015 23:50:58 +0200 Subject: [PATCH 15/22] Populate `tablet_use` info with sign text if sign upgrade is installed, closes #988. --- .../cil/oc/server/component/UpgradeSign.scala | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/scala/li/cil/oc/server/component/UpgradeSign.scala b/src/main/scala/li/cil/oc/server/component/UpgradeSign.scala index 3ac32ff77..8f181c6fa 100644 --- a/src/main/scala/li/cil/oc/server/component/UpgradeSign.scala +++ b/src/main/scala/li/cil/oc/server/component/UpgradeSign.scala @@ -2,12 +2,16 @@ package li.cil.oc.server.component import cpw.mods.fml.common.eventhandler.Event import li.cil.oc.Settings +import li.cil.oc.api import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.internal +import li.cil.oc.api.network.Message import li.cil.oc.api.prefab import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedWorld._ import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound import net.minecraft.tileentity.TileEntitySign import net.minecraft.world.WorldServer import net.minecraftforge.common.MinecraftForge @@ -62,4 +66,20 @@ abstract class UpgradeSign extends prefab.ManagedEnvironment { MinecraftForge.EVENT_BUS.post(event) !(event.isCanceled || event.getResult == Event.Result.DENY) } + + override def onMessage(message: Message): Unit = { + super.onMessage(message) + if (message.name == "tablet.use") message.source.host match { + case machine: api.machine.Machine => (machine.host, message.data) match { + case (tablet: internal.Tablet, Array(nbt: NBTTagCompound, stack: ItemStack, player: EntityPlayer, blockPos: BlockPosition, side: ForgeDirection, hitX: java.lang.Float, hitY: java.lang.Float, hitZ: java.lang.Float)) => + host.world.getTileEntity(blockPos) match { + case sign: TileEntitySign => + nbt.setString("signText", sign.signText.mkString("\n")) + case _ => + } + case _ => // Ignore. + } + case _ => // Ignore. + } + } } From b021641efe2769a2b7f0eccf1fcdbbb0772c983d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 31 Mar 2015 00:30:07 +0200 Subject: [PATCH 16/22] Allow filtering items when querying lists from AE2 networks, closes #856. `me_controller.getCraftables` and `me_controller.getItemsInNetwork` now take an optional table argument. This table is a filter applied to the result. Its format is the same as item stack representations. For example, a full filter could be: ``` { damage = 0, maxDamage = 0, size = 12, maxSize = 64, hasTag = false, name = "minecraft:stick, label = "Stick" } ``` --- .../integration/appeng/DriverController.scala | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala index 3b60ab7f0..95908d166 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala @@ -25,6 +25,7 @@ import li.cil.oc.integration.ManagedTileEntityEnvironment import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ResultWrapper._ import net.minecraft.block.Block +import net.minecraft.item.Item import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.tileentity.TileEntity @@ -78,10 +79,13 @@ object DriverController extends DriverTileEntity with EnvironmentAware { "coprocessors" -> cpu.getCoProcessors, "busy" -> cpu.isBusy))) - @Callback(doc = "function():table -- Get a list of known item recipes. These can be used to issue crafting requests.") + @Callback(doc = "function([filter:table]):table -- Get a list of known item recipes. These can be used to issue crafting requests.") def getCraftables(context: Context, args: Arguments): Array[AnyRef] = { + val filter = args.optTable(0, Map.empty[AnyRef, AnyRef]).collect { + case (key: String, value: AnyRef) => (key, value) + } result(tileEntity.getProxy.getStorage.getItemInventory.getStorageList. - filter(_.isCraftable).map(stack => { + filter(_.isCraftable).filter(stack => matches(stack, filter)).map(stack => { val patterns = tileEntity.getProxy.getCrafting.getCraftingFor(stack, null, 0, tileEntity.getWorldObj) val result = patterns.find(pattern => pattern.getOutputs.exists(_.isSameType(stack))) match { case Some(pattern) => pattern.getOutputs.find(_.isSameType(stack)).get @@ -91,9 +95,13 @@ object DriverController extends DriverTileEntity with EnvironmentAware { }).toArray) } - @Callback(doc = "function():table -- Get a list of the stored items in the network.") - def getItemsInNetwork(context: Context, args: Arguments): Array[AnyRef] = - result(tileEntity.getProxy.getStorage.getItemInventory.getStorageList.map(_.getItemStack).toArray) + @Callback(doc = "function([filter:table]):table -- Get a list of the stored items in the network.") + def getItemsInNetwork(context: Context, args: Arguments): Array[AnyRef] = { + val filter = args.optTable(0, Map.empty[AnyRef, AnyRef]).collect { + case (key: String, value: AnyRef) => (key, value) + } + result(tileEntity.getProxy.getStorage.getItemInventory.getStorageList.filter(stack => matches(stack, filter)).map(_.getItemStack).toArray) + } @Callback(doc = "function():table -- Get a list of the stored fluids in the network.") def getFluidsInNetwork(context: Context, args: Arguments): Array[AnyRef] = @@ -118,6 +126,17 @@ object DriverController extends DriverTileEntity with EnvironmentAware { @Callback(doc = "function():number -- Get the stored power in the network. ") def getStoredPower(context: Context, args: Arguments): Array[AnyRef] = result(tileEntity.getProxy.getEnergy.getStoredPower) + + private def matches(stack: IAEItemStack, filter: scala.collection.mutable.Map[String, AnyRef]) = { + stack != null && + filter.get("damage").forall(_.equals(stack.getItemDamage.toDouble)) && + filter.get("maxDamage").forall(_.equals(stack.getItemStack.getMaxDamage.toDouble)) && + filter.get("size").forall(_.equals(stack.getStackSize.toDouble)) && + filter.get("maxSize").forall(_.equals(stack.getItemStack.getMaxStackSize.toDouble)) && + filter.get("hasTag").forall(_.equals(stack.hasTagCompound)) && + filter.get("name").forall(_.equals(Item.itemRegistry.getNameForObject(stack.getItem))) && + filter.get("label").forall(_.equals(stack.getItemStack.getDisplayName)) + } } class Craftable(var controller: AETile, var stack: IAEItemStack) extends AbstractValue with ICraftingRequester { From e1ac05b6f3da069b86aa7bb17c595444092f6bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 31 Mar 2015 01:13:29 +0200 Subject: [PATCH 17/22] Fixed reading text on signs via sign upgrade. --- src/main/scala/li/cil/oc/server/component/UpgradeSign.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/component/UpgradeSign.scala b/src/main/scala/li/cil/oc/server/component/UpgradeSign.scala index 8b2920d7b..4e1d95bee 100644 --- a/src/main/scala/li/cil/oc/server/component/UpgradeSign.scala +++ b/src/main/scala/li/cil/oc/server/component/UpgradeSign.scala @@ -25,7 +25,7 @@ abstract class UpgradeSign extends prefab.ManagedEnvironment { protected def getValue(tileEntity: Option[TileEntitySign]): Array[AnyRef] = { tileEntity match { - case Some(sign) => result(sign.signText.mkString("\n")) + case Some(sign) => result(sign.signText.map(_.getUnformattedText).mkString("\n")) case _ => result(Unit, "no sign") } } @@ -43,7 +43,7 @@ abstract class UpgradeSign extends prefab.ManagedEnvironment { text.lines.padTo(4, "").map(line => if (line.length > 15) line.substring(0, 15) else line).map(new ChatComponentText(_)).copyToArray(sign.signText) host.world.markBlockForUpdate(sign.getPos) - result(sign.signText.mkString("\n")) + result(sign.signText.map(_.getUnformattedText).mkString("\n")) case _ => result(Unit, "no sign") } } @@ -75,7 +75,7 @@ abstract class UpgradeSign extends prefab.ManagedEnvironment { case (tablet: internal.Tablet, Array(nbt: NBTTagCompound, stack: ItemStack, player: EntityPlayer, blockPos: BlockPosition, side: EnumFacing, hitX: java.lang.Float, hitY: java.lang.Float, hitZ: java.lang.Float)) => host.world.getTileEntity(blockPos) match { case sign: TileEntitySign => - nbt.setString("signText", sign.signText.mkString("\n")) + nbt.setString("signText", sign.signText.map(_.getUnformattedText).mkString("\n")) case _ => } case _ => // Ignore. From ff85880a9606e7b116f01d03cd07c5a4f925ca00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 31 Mar 2015 01:57:39 +0200 Subject: [PATCH 18/22] This *should* fix the NPE in AE2 integration with versions 20 and up. Can't fully test it because it crashes when I interact with terminals. Closes #978. Again. --- .../oc/integration/appeng/DriverController.scala | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala index 95908d166..d6fb69086 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala @@ -11,6 +11,8 @@ import appeng.me.helpers.IGridProxyable import appeng.tile.misc.TileInterface import appeng.util.item.AEItemStack import com.google.common.collect.ImmutableSet +import cpw.mods.fml.common.Loader +import cpw.mods.fml.common.versioning.VersionRange import li.cil.oc.OpenComputers import li.cil.oc.api.driver.EnvironmentAware import li.cil.oc.api.driver.NamedBlock @@ -22,6 +24,7 @@ import li.cil.oc.api.prefab.AbstractValue import li.cil.oc.api.prefab.DriverTileEntity import li.cil.oc.common.EventHandler import li.cil.oc.integration.ManagedTileEntityEnvironment +import li.cil.oc.integration.Mods import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ResultWrapper._ import net.minecraft.block.Block @@ -44,8 +47,16 @@ import scala.language.existentials object DriverController extends DriverTileEntity with EnvironmentAware { private type AETile = TileEntity with IGridProxyable with IActionHost + val versionsWithNewItemDefinitionAPI = VersionRange.createFromVersionSpec("[rv2-beta-20,)") + def getTileEntityClass: Class[_] = { - if (AEApi.instance != null && AEApi.instance.blocks != null) { + if (versionsWithNewItemDefinitionAPI.containsVersion(Loader.instance.getIndexedModList.get(Mods.AppliedEnergistics2.id).getProcessedVersion)) { + if (AEApi.instance.definitions.blocks.controller.maybeStack(0).isPresent) + AEApi.instance.definitions.blocks.controller.maybeEntity.orNull + else + AEApi.instance.definitions.blocks.iface.maybeEntity.orNull + } + else if (AEApi.instance != null && AEApi.instance.blocks != null) { if (AEApi.instance.blocks.blockController != null && AEApi.instance.blocks.blockController.item != null) // Not classOf[TileController] because that derps the compiler when it tries to resolve the class (says can't find API classes from RotaryCraft). Class.forName("appeng.tile.networking.TileController") From ef86ca01c8d7097cc1d71c4ee1987c81d927bd38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 31 Mar 2015 13:35:45 +0200 Subject: [PATCH 19/22] Added drivers for the separate RF energy APIs, closes #989. --- .../cofh/energy/DriverEnergyProvider.java | 52 +++++++++++++++++ .../cofh/energy/DriverEnergyReceiver.java | 57 +++++++++++++++++++ .../cofh/energy/ModCoFHEnergy.scala | 15 ++++- 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/li/cil/oc/integration/cofh/energy/DriverEnergyProvider.java create mode 100644 src/main/scala/li/cil/oc/integration/cofh/energy/DriverEnergyReceiver.java diff --git a/src/main/scala/li/cil/oc/integration/cofh/energy/DriverEnergyProvider.java b/src/main/scala/li/cil/oc/integration/cofh/energy/DriverEnergyProvider.java new file mode 100644 index 000000000..817b79a26 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/cofh/energy/DriverEnergyProvider.java @@ -0,0 +1,52 @@ +package li.cil.oc.integration.cofh.energy; + +import cofh.api.energy.IEnergyProvider; +import cofh.api.energy.IEnergyReceiver; +import li.cil.oc.api.machine.Arguments; +import li.cil.oc.api.machine.Callback; +import li.cil.oc.api.machine.Context; +import li.cil.oc.api.network.ManagedEnvironment; +import li.cil.oc.api.prefab.DriverTileEntity; +import li.cil.oc.integration.ManagedTileEntityEnvironment; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +public final class DriverEnergyProvider extends DriverTileEntity { + @Override + public Class getTileEntityClass() { + return IEnergyProvider.class; + } + + @Override + public ManagedEnvironment createEnvironment(final World world, final int x, final int y, final int z) { + return new Environment((IEnergyProvider) world.getTileEntity(x, y, z)); + } + + public static final class Environment extends ManagedTileEntityEnvironment { + public Environment(final IEnergyProvider tileEntity) { + super(tileEntity, "energy_handler"); + } + + @Callback(doc = "function([direction:number=6]):number -- Returns the amount of stored energy for the given side.") + public Object[] getEnergyStored(final Context context, final Arguments args) { + final ForgeDirection side = args.count() > 0 ? ForgeDirection.getOrientation(args.checkInteger(0)) : ForgeDirection.UNKNOWN; + return new Object[]{tileEntity.getEnergyStored(side)}; + } + + @Callback(doc = "function([direction:number=6]):number -- Returns the maximum amount of stored energy for the given side.") + public Object[] getMaxEnergyStored(final Context context, final Arguments args) { + final ForgeDirection side = args.count() > 0 ? ForgeDirection.getOrientation(args.checkInteger(0)) : ForgeDirection.UNKNOWN; + return new Object[]{tileEntity.getMaxEnergyStored(side)}; + } + + @Callback(doc = "function():number -- Returns whether this component can provide energy.") + public Object[] isEnergyProvider(final Context context, final Arguments args) { + return new Object[]{true}; + } + + @Callback(doc = "function():number -- Returns whether this component can receive energy.") + public Object[] isEnergyReceiver(final Context context, final Arguments args) { + return new Object[]{tileEntity instanceof IEnergyReceiver}; + } + } +} diff --git a/src/main/scala/li/cil/oc/integration/cofh/energy/DriverEnergyReceiver.java b/src/main/scala/li/cil/oc/integration/cofh/energy/DriverEnergyReceiver.java new file mode 100644 index 000000000..061722aad --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/cofh/energy/DriverEnergyReceiver.java @@ -0,0 +1,57 @@ +package li.cil.oc.integration.cofh.energy; + +import cofh.api.energy.IEnergyProvider; +import cofh.api.energy.IEnergyReceiver; +import li.cil.oc.api.machine.Arguments; +import li.cil.oc.api.machine.Callback; +import li.cil.oc.api.machine.Context; +import li.cil.oc.api.network.ManagedEnvironment; +import li.cil.oc.api.prefab.DriverTileEntity; +import li.cil.oc.integration.ManagedTileEntityEnvironment; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +public final class DriverEnergyReceiver extends DriverTileEntity { + @Override + public Class getTileEntityClass() { + return IEnergyReceiver.class; + } + + @Override + public boolean worksWith(World world, int x, int y, int z) { + return super.worksWith(world, x, y, z) && !(world.getTileEntity(x, y, z) instanceof IEnergyProvider); + } + + @Override + public ManagedEnvironment createEnvironment(final World world, final int x, final int y, final int z) { + return new Environment((IEnergyReceiver) world.getTileEntity(x, y, z)); + } + + public static final class Environment extends ManagedTileEntityEnvironment { + public Environment(final IEnergyReceiver tileEntity) { + super(tileEntity, "energy_handler"); + } + + @Callback(doc = "function([direction:number=6]):number -- Returns the amount of stored energy for the given side.") + public Object[] getEnergyStored(final Context context, final Arguments args) { + final ForgeDirection side = args.count() > 0 ? ForgeDirection.getOrientation(args.checkInteger(0)) : ForgeDirection.UNKNOWN; + return new Object[]{tileEntity.getEnergyStored(side)}; + } + + @Callback(doc = "function([direction:number=6]):number -- Returns the maximum amount of stored energy for the given side.") + public Object[] getMaxEnergyStored(final Context context, final Arguments args) { + final ForgeDirection side = args.count() > 0 ? ForgeDirection.getOrientation(args.checkInteger(0)) : ForgeDirection.UNKNOWN; + return new Object[]{tileEntity.getMaxEnergyStored(side)}; + } + + @Callback(doc = "function():number -- Returns whether this component can provide energy.") + public Object[] isEnergyProvider(final Context context, final Arguments args) { + return new Object[]{false}; + } + + @Callback(doc = "function():number -- Returns whether this component can receive energy.") + public Object[] isEnergyReceiver(final Context context, final Arguments args) { + return new Object[]{true}; + } + } +} diff --git a/src/main/scala/li/cil/oc/integration/cofh/energy/ModCoFHEnergy.scala b/src/main/scala/li/cil/oc/integration/cofh/energy/ModCoFHEnergy.scala index b5142b944..c10ebae1a 100644 --- a/src/main/scala/li/cil/oc/integration/cofh/energy/ModCoFHEnergy.scala +++ b/src/main/scala/li/cil/oc/integration/cofh/energy/ModCoFHEnergy.scala @@ -1,20 +1,33 @@ package li.cil.oc.integration.cofh.energy +import cpw.mods.fml.common.ModAPIManager import cpw.mods.fml.common.event.FMLInterModComms +import cpw.mods.fml.common.versioning.VersionRange import li.cil.oc.api.Driver import li.cil.oc.integration.ModProxy import li.cil.oc.integration.Mods import net.minecraftforge.common.MinecraftForge +import scala.collection.convert.WrapAsScala._ + object ModCoFHEnergy extends ModProxy { override def getMod = Mods.CoFHEnergy + private val versionsUsingSplitEnergyAPI = VersionRange.createFromVersionSpec("[1.0.0,)") + override def initialize() { FMLInterModComms.sendMessage(Mods.IDs.OpenComputers, "registerToolDurabilityProvider", "li.cil.oc.integration.cofh.energy.EventHandlerRedstoneFlux.getDurability") MinecraftForge.EVENT_BUS.register(EventHandlerRedstoneFlux) - Driver.add(new DriverEnergyHandler) + val apiVersion = ModAPIManager.INSTANCE.getAPIList.find(_.getModId == Mods.IDs.CoFHEnergy).map(_.getProcessedVersion) + if (apiVersion.exists(versionsUsingSplitEnergyAPI.containsVersion)) { + Driver.add(new DriverEnergyProvider) + Driver.add(new DriverEnergyReceiver) + } + else { + Driver.add(new DriverEnergyHandler) + } Driver.add(new ConverterEnergyContainerItem) } From 063c50033c53a1da6f8a0a64c63f1822da4b3ff0 Mon Sep 17 00:00:00 2001 From: mpmxyz Date: Tue, 31 Mar 2015 17:24:11 +0200 Subject: [PATCH 20/22] cat.lua now closes opened files properly The title says everything. It caused a lot of Out of Memory-Errors when I tested a custom file system. (-> many unclosed streams) --- .../resources/assets/opencomputers/loot/OpenOS/bin/cat.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/cat.lua b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/cat.lua index d4e1505f3..cf0e54f31 100644 --- a/src/main/resources/assets/opencomputers/loot/OpenOS/bin/cat.lua +++ b/src/main/resources/assets/opencomputers/loot/OpenOS/bin/cat.lua @@ -21,5 +21,6 @@ else io.write(line) end until not line + file:close() end -end \ No newline at end of file +end From 221f42bb2ee9b0f54dd0168e20cbc6677746596c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 31 Mar 2015 18:09:08 +0200 Subject: [PATCH 21/22] Not making mod integration depend on whether power use is enabled or not... closes #992. --- src/main/scala/li/cil/oc/integration/Mod.java | 2 +- src/main/scala/li/cil/oc/integration/Mods.scala | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/Mod.java b/src/main/scala/li/cil/oc/integration/Mod.java index 43a8d161a..bc54fe566 100644 --- a/src/main/scala/li/cil/oc/integration/Mod.java +++ b/src/main/scala/li/cil/oc/integration/Mod.java @@ -3,7 +3,7 @@ package li.cil.oc.integration; public interface Mod { String id(); - boolean isAvailable(); + boolean isModAvailable(); boolean providesPower(); } diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 72be050af..8e3200af6 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -56,10 +56,12 @@ object Mods { val StargateTech2 = new ModBase { def id = IDs.StargateTech2 - protected override lazy val isModAvailable = Loader.isModLoaded(IDs.StargateTech2) && { + private lazy val isModAvailable_ = Loader.isModLoaded(IDs.StargateTech2) && { val mod = Loader.instance.getIndexedModList.get(IDs.StargateTech2) mod.getVersion.startsWith("0.7.") } + + override def isModAvailable: Boolean = isModAvailable_ } val Thaumcraft = new SimpleMod(IDs.Thaumcraft) val ThermalExpansion = new SimpleMod(IDs.ThermalExpansion, providesPower = true) @@ -121,7 +123,7 @@ object Mods { private def tryInit(mod: ModProxy) { val isBlacklisted = Settings.get.modBlacklist.contains(mod.getMod.id) val alwaysEnabled = mod.getMod == null || mod.getMod == Mods.Minecraft - if (!isBlacklisted && (alwaysEnabled || mod.getMod.isAvailable) && handlers.add(mod)) { + if (!isBlacklisted && (alwaysEnabled || mod.getMod.isModAvailable) && handlers.add(mod)) { li.cil.oc.OpenComputers.log.info(s"Initializing mod integration for '${mod.getMod.id}'.") try mod.initialize() catch { case e: Throwable => @@ -188,7 +190,7 @@ object Mods { protected lazy val isPowerModEnabled = !providesPower || (!Settings.get.pureIgnorePower && !Settings.get.powerModBlacklist.contains(id)) - protected def isModAvailable: Boolean + def isModAvailable: Boolean def id: String @@ -206,18 +208,22 @@ object Mods { } class SimpleMod(val id: String, override val providesPower: Boolean = false, version: String = "") extends ModBase { - override protected lazy val isModAvailable = { + private lazy val isModAvailable_ = { val version = VersionParser.parseVersionReference(id + this.version) if (Loader.isModLoaded(version.getLabel)) version.containsVersion(Loader.instance.getIndexedModList.get(version.getLabel).getProcessedVersion) else ModAPIManager.INSTANCE.hasAPI(version.getLabel) } + + def isModAvailable = isModAvailable_ } class ClassBasedMod(val id: String, val classNames: String*)(override val providesPower: Boolean = false) extends ModBase { - override protected lazy val isModAvailable = classNames.forall(className => try Class.forName(className) != null catch { + private lazy val isModAvailable_ = classNames.forall(className => try Class.forName(className) != null catch { case _: Throwable => false }) + + def isModAvailable = isModAvailable_ } } From 4dab10de3fd7ed2de8ea35eda5649cbca98dbe98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 31 Mar 2015 23:58:43 +0200 Subject: [PATCH 22/22] Version bump. --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 9877f81e3..fd3415001 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ minecraft.version=1.7.10 forge.version=10.13.2.1291 -oc.version=1.5.4 +oc.version=1.5.5 oc.subversion=dev ae2.version=rv2-beta-22