mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-29 16:03:14 -04:00
Merge branch 'master' of https://github.com/MightyPirates/OpenComputers into MC1.7
This commit is contained in:
commit
f448cbbf57
@ -12,6 +12,21 @@ import net.minecraft.world.World;
|
|||||||
* running in, to allow querying the time of day, for example.
|
* running in, to allow querying the time of day, for example.
|
||||||
*/
|
*/
|
||||||
public interface Owner extends Context {
|
public interface Owner extends Context {
|
||||||
|
/**
|
||||||
|
* The X coordinate of this machine owner in the world, in block coordinates.
|
||||||
|
*/
|
||||||
|
int x();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Y coordinate of this machine owner in the world, in block coordinates.
|
||||||
|
*/
|
||||||
|
int y();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Z coordinate of this machine owner in the world, in block coordinates.
|
||||||
|
*/
|
||||||
|
int z();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The world the machine is running in, e.g. if the owner is a tile entity
|
* The world the machine is running in, e.g. if the owner is a tile entity
|
||||||
* this is the world the tile entity lives in.
|
* this is the world the tile entity lives in.
|
||||||
|
@ -37,5 +37,5 @@
|
|||||||
@cpw.mods.fml.common.API(
|
@cpw.mods.fml.common.API(
|
||||||
owner = "OpenComputers|Core",
|
owner = "OpenComputers|Core",
|
||||||
provides = "OpenComputersAPI",
|
provides = "OpenComputersAPI",
|
||||||
apiVersion = "1.4.9")
|
apiVersion = "1.4.10")
|
||||||
package li.cil.oc.api;
|
package li.cil.oc.api;
|
@ -78,5 +78,6 @@ class Proxy {
|
|||||||
FMLCommonHandler.instance().bus().register(EventHandler)
|
FMLCommonHandler.instance().bus().register(EventHandler)
|
||||||
FMLCommonHandler.instance().bus().register(SimpleComponentTickHandler.Instance)
|
FMLCommonHandler.instance().bus().register(SimpleComponentTickHandler.Instance)
|
||||||
MinecraftForge.EVENT_BUS.register(WirelessNetwork)
|
MinecraftForge.EVENT_BUS.register(WirelessNetwork)
|
||||||
|
MinecraftForge.EVENT_BUS.register(SaveHandler)
|
||||||
}
|
}
|
||||||
}
|
}
|
83
src/main/scala/li/cil/oc/common/SaveHandler.scala
Normal file
83
src/main/scala/li/cil/oc/common/SaveHandler.scala
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package li.cil.oc.common
|
||||||
|
|
||||||
|
import java.io
|
||||||
|
import java.util.logging.Level
|
||||||
|
import li.cil.oc.{OpenComputers, Settings}
|
||||||
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
import net.minecraft.world.ChunkCoordIntPair
|
||||||
|
import net.minecraftforge.common.DimensionManager
|
||||||
|
import net.minecraftforge.event.ForgeSubscribe
|
||||||
|
import net.minecraftforge.event.world.WorldEvent
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
// TODO Save all data to an NBT compound and save it as a single file, to improve file I/O performance.
|
||||||
|
object SaveHandler {
|
||||||
|
val saveData = mutable.Map.empty[ChunkCoordIntPair, mutable.Map[String, Array[Byte]]]
|
||||||
|
|
||||||
|
var cachedNbt = new NBTTagCompound()
|
||||||
|
|
||||||
|
def savePath = new io.File(DimensionManager.getCurrentSaveRootDirectory, Settings.savePath + "state")
|
||||||
|
|
||||||
|
def scheduleSave(chunk: ChunkCoordIntPair, name: String, data: Array[Byte]) = saveData.synchronized {
|
||||||
|
if (chunk == null) OpenComputers.log.warning("Cannot save machines with non tile entity owners.")
|
||||||
|
else saveData.getOrElseUpdate(chunk, mutable.Map.empty[String, Array[Byte]]) += name -> data
|
||||||
|
}
|
||||||
|
|
||||||
|
def load(chunk: ChunkCoordIntPair, name: String): Array[Byte] = {
|
||||||
|
if (chunk == null) null
|
||||||
|
else {
|
||||||
|
val path = savePath
|
||||||
|
val chunkPath = new io.File(path, s"${chunk.chunkXPos}.${chunk.chunkZPos}")
|
||||||
|
val file = new io.File(chunkPath, name)
|
||||||
|
try {
|
||||||
|
// val bis = new io.BufferedInputStream(new GZIPInputStream(new io.FileInputStream(file)))
|
||||||
|
val bis = new io.BufferedInputStream(new io.FileInputStream(file))
|
||||||
|
val bos = new io.ByteArrayOutputStream
|
||||||
|
val buffer = new Array[Byte](8 * 1024)
|
||||||
|
var read = 0
|
||||||
|
do {
|
||||||
|
read = bis.read(buffer)
|
||||||
|
if (read > 0) {
|
||||||
|
bos.write(buffer, 0, read)
|
||||||
|
}
|
||||||
|
} while (read >= 0)
|
||||||
|
bis.close()
|
||||||
|
bos.toByteArray
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e: io.IOException =>
|
||||||
|
OpenComputers.log.log(Level.WARNING, "Error loading auxiliary tile entity data.", e)
|
||||||
|
Array.empty[Byte]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the native lua state to store kernel and stack data in auxiliary
|
||||||
|
// files instead of directly in the tile entity data, avoiding potential
|
||||||
|
// problems with the tile entity data becoming too large.
|
||||||
|
@ForgeSubscribe
|
||||||
|
def onWorldSave(e: WorldEvent.Save) = saveData.synchronized {
|
||||||
|
val path = savePath
|
||||||
|
path.mkdirs()
|
||||||
|
for ((chunk, entries) <- saveData) {
|
||||||
|
val chunkPath = new io.File(path, s"${chunk.chunkXPos}.${chunk.chunkZPos}")
|
||||||
|
chunkPath.mkdirs()
|
||||||
|
if (chunkPath.exists && chunkPath.isDirectory) {
|
||||||
|
for (file <- chunkPath.listFiles()) file.delete()
|
||||||
|
}
|
||||||
|
for ((name, data) <- entries) {
|
||||||
|
val file = new io.File(chunkPath, name)
|
||||||
|
try {
|
||||||
|
// val fos = new GZIPOutputStream(new io.FileOutputStream(file))
|
||||||
|
val fos = new io.BufferedOutputStream(new io.FileOutputStream(file))
|
||||||
|
fos.write(data)
|
||||||
|
fos.close()
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case e: io.IOException => OpenComputers.log.log(Level.WARNING, s"Error saving auxiliary tile entity data to '${file.getAbsolutePath}.", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveData.clear()
|
||||||
|
}
|
||||||
|
}
|
@ -143,12 +143,22 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B
|
|||||||
|
|
||||||
override def readFromNBT(nbt: NBTTagCompound) {
|
override def readFromNBT(nbt: NBTTagCompound) {
|
||||||
super.readFromNBT(nbt)
|
super.readFromNBT(nbt)
|
||||||
|
// God, this is so ugly... will need to rework the robot architecture.
|
||||||
|
// This is required for loading auxiliary data (kernel state), because the
|
||||||
|
// coordinates in the actual robot won't be set properly, otherwise.
|
||||||
|
this match {
|
||||||
|
case proxy: RobotProxy =>
|
||||||
|
proxy.robot.xCoord = xCoord
|
||||||
|
proxy.robot.yCoord = yCoord
|
||||||
|
proxy.robot.zCoord = zCoord
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
computer.load(nbt.getCompoundTag(Settings.namespace + "computer"))
|
computer.load(nbt.getCompoundTag(Settings.namespace + "computer"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def writeToNBT(nbt: NBTTagCompound) {
|
override def writeToNBT(nbt: NBTTagCompound) {
|
||||||
super.writeToNBT(nbt)
|
super.writeToNBT(nbt)
|
||||||
if (!new Exception().getStackTrace.exists(_.getClassName.startsWith("mcp.mobius.waila"))) {
|
if (computer != null) {
|
||||||
nbt.setNewCompoundTag(Settings.namespace + "computer", computer.save)
|
nbt.setNewCompoundTag(Settings.namespace + "computer", computer.save)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,15 +266,13 @@ class Rack extends PowerAcceptor with Hub with PowerBalancer with Inventory with
|
|||||||
|
|
||||||
// Side check for Waila (and other mods that may call this client side).
|
// Side check for Waila (and other mods that may call this client side).
|
||||||
override def writeToNBT(nbt: NBTTagCompound) = if (isServer) {
|
override def writeToNBT(nbt: NBTTagCompound) = if (isServer) {
|
||||||
if (!new Exception().getStackTrace.exists(_.getClassName.startsWith("mcp.mobius.waila"))) {
|
nbt.setNewTagList(Settings.namespace + "servers", servers map {
|
||||||
nbt.setNewTagList(Settings.namespace + "servers", servers map {
|
case Some(server) =>
|
||||||
case Some(server) =>
|
val serverNbt = new NBTTagCompound()
|
||||||
val serverNbt = new NBTTagCompound()
|
server.save(serverNbt)
|
||||||
server.save(serverNbt)
|
serverNbt
|
||||||
serverNbt
|
case _ => new NBTTagCompound()
|
||||||
case _ => new NBTTagCompound()
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
super.writeToNBT(nbt)
|
super.writeToNBT(nbt)
|
||||||
nbt.setByteArray(Settings.namespace + "sides", sides.map(_.ordinal.toByte))
|
nbt.setByteArray(Settings.namespace + "sides", sides.map(_.ordinal.toByte))
|
||||||
nbt.setNewTagList(Settings.namespace + "terminals", terminals.map(t => {
|
nbt.setNewTagList(Settings.namespace + "terminals", terminals.map(t => {
|
||||||
|
@ -70,6 +70,12 @@ class Server(val rack: tileentity.Rack, val number: Int) extends Owner {
|
|||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def x = rack.x
|
||||||
|
|
||||||
|
override def y = rack.y
|
||||||
|
|
||||||
|
override def z = rack.z
|
||||||
|
|
||||||
override def world = rack.world
|
override def world = rack.world
|
||||||
|
|
||||||
override def markAsChanged() = rack.markAsChanged()
|
override def markAsChanged() = rack.markAsChanged()
|
||||||
|
@ -247,7 +247,7 @@ class LuaJLuaArchitecture(val machine: api.machine.Machine) extends Architecture
|
|||||||
|
|
||||||
// Are we a robot? (No this is not a CAPTCHA.)
|
// Are we a robot? (No this is not a CAPTCHA.)
|
||||||
// TODO deprecate this
|
// TODO deprecate this
|
||||||
computer.set("isRobot", (_: Varargs) => LuaValue.valueOf(machine.components.contains("robot")))
|
computer.set("isRobot", (_: Varargs) => LuaValue.valueOf(machine.components.containsValue("robot")))
|
||||||
|
|
||||||
computer.set("freeMemory", (_: Varargs) => LuaValue.valueOf(memory / 2))
|
computer.set("freeMemory", (_: Varargs) => LuaValue.valueOf(memory / 2))
|
||||||
|
|
||||||
|
@ -6,11 +6,14 @@ import java.io.{IOException, FileNotFoundException}
|
|||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
import li.cil.oc.api.machine.{Architecture, LimitReachedException, ExecutionResult}
|
import li.cil.oc.api.machine.{Architecture, LimitReachedException, ExecutionResult}
|
||||||
import li.cil.oc.api.network.ComponentConnector
|
import li.cil.oc.api.network.ComponentConnector
|
||||||
|
import li.cil.oc.common.SaveHandler
|
||||||
|
import li.cil.oc.server.component
|
||||||
import li.cil.oc.util.ExtendedLuaState.extendLuaState
|
import li.cil.oc.util.ExtendedLuaState.extendLuaState
|
||||||
import li.cil.oc.util.{GameTimeFormatter, LuaStateFactory}
|
import li.cil.oc.util.{GameTimeFormatter, LuaStateFactory}
|
||||||
import li.cil.oc.{api, OpenComputers, server, Settings}
|
import li.cil.oc.{api, OpenComputers, server, Settings}
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
import scala.Some
|
import net.minecraft.tileentity.TileEntity
|
||||||
|
import net.minecraft.world.ChunkCoordIntPair
|
||||||
import scala.collection.convert.WrapAsScala._
|
import scala.collection.convert.WrapAsScala._
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
@ -295,7 +298,7 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu
|
|||||||
// Are we a robot? (No this is not a CAPTCHA.)
|
// Are we a robot? (No this is not a CAPTCHA.)
|
||||||
// TODO deprecate this
|
// TODO deprecate this
|
||||||
lua.pushScalaFunction(lua => {
|
lua.pushScalaFunction(lua => {
|
||||||
lua.pushBoolean(machine.components.contains("robot"))
|
lua.pushBoolean(machine.components.containsValue("robot"))
|
||||||
1
|
1
|
||||||
})
|
})
|
||||||
lua.setField(-2, "isRobot")
|
lua.setField(-2, "isRobot")
|
||||||
@ -595,14 +598,20 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu
|
|||||||
// on. First, clear the stack, meaning the current kernel.
|
// on. First, clear the stack, meaning the current kernel.
|
||||||
lua.setTop(0)
|
lua.setTop(0)
|
||||||
|
|
||||||
unpersist(nbt.getByteArray("kernel"))
|
val kernel =
|
||||||
|
if (nbt.hasKey("kernel")) nbt.getByteArray("kernel")
|
||||||
|
else SaveHandler.load(new ChunkCoordIntPair(machine.owner.x >> 4, machine.owner.z >> 4), node.address + "_kernel")
|
||||||
|
unpersist(kernel)
|
||||||
if (!lua.isThread(1)) {
|
if (!lua.isThread(1)) {
|
||||||
// This shouldn't really happen, but there's a chance it does if
|
// This shouldn't really happen, but there's a chance it does if
|
||||||
// the save was corrupt (maybe someone modified the Lua files).
|
// the save was corrupt (maybe someone modified the Lua files).
|
||||||
throw new IllegalArgumentException("Invalid kernel.")
|
throw new IllegalArgumentException("Invalid kernel.")
|
||||||
}
|
}
|
||||||
if (state.contains(Machine.State.SynchronizedCall) || state.contains(Machine.State.SynchronizedReturn)) {
|
if (state.contains(Machine.State.SynchronizedCall) || state.contains(Machine.State.SynchronizedReturn)) {
|
||||||
unpersist(nbt.getByteArray("stack"))
|
val stack =
|
||||||
|
if (nbt.hasKey("stack")) nbt.getByteArray("stack")
|
||||||
|
else SaveHandler.load(new ChunkCoordIntPair(machine.owner.x >> 4, machine.owner.z >> 4), node.address + "_stack")
|
||||||
|
unpersist(stack)
|
||||||
if (!(if (state.contains(Machine.State.SynchronizedCall)) lua.isFunction(2) else lua.isTable(2))) {
|
if (!(if (state.contains(Machine.State.SynchronizedCall)) lua.isFunction(2) else lua.isTable(2))) {
|
||||||
// Same as with the above, should not really happen normally, but
|
// Same as with the above, should not really happen normally, but
|
||||||
// could for the same reasons.
|
// could for the same reasons.
|
||||||
@ -629,12 +638,12 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu
|
|||||||
// Try persisting Lua, because that's what all of the rest depends on.
|
// Try persisting Lua, because that's what all of the rest depends on.
|
||||||
// Save the kernel state (which is always at stack index one).
|
// Save the kernel state (which is always at stack index one).
|
||||||
assert(lua.isThread(1))
|
assert(lua.isThread(1))
|
||||||
nbt.setByteArray("kernel", persist(1))
|
SaveHandler.scheduleSave(new ChunkCoordIntPair(machine.owner.x >> 4, machine.owner.z >> 4), node.address + "_kernel", persist(1))
|
||||||
// While in a driver call we have one object on the global stack: either
|
// While in a driver call we have one object on the global stack: either
|
||||||
// the function to call the driver with, or the result of the call.
|
// the function to call the driver with, or the result of the call.
|
||||||
if (state.contains(Machine.State.SynchronizedCall) || state.contains(Machine.State.SynchronizedReturn)) {
|
if (state.contains(Machine.State.SynchronizedCall) || state.contains(Machine.State.SynchronizedReturn)) {
|
||||||
assert(if (state.contains(Machine.State.SynchronizedCall)) lua.isFunction(2) else lua.isTable(2))
|
assert(if (state.contains(Machine.State.SynchronizedCall)) lua.isFunction(2) else lua.isTable(2))
|
||||||
nbt.setByteArray("stack", persist(2))
|
SaveHandler.scheduleSave(new ChunkCoordIntPair(machine.owner.x >> 4, machine.owner.z >> 4), node.address + "_stack", persist(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
nbt.setInteger("kernelMemory", math.ceil(kernelMemory / ramScale).toInt)
|
nbt.setInteger("kernelMemory", math.ceil(kernelMemory / ramScale).toInt)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user