This commit is contained in:
Florian Nücke 2014-03-17 12:12:02 +01:00
commit 3d5901843d
4 changed files with 45 additions and 29 deletions

View File

@ -4,7 +4,7 @@ import cpw.mods.fml.common.eventhandler.SubscribeEvent
import java.io import java.io
import java.util.logging.Level import java.util.logging.Level
import li.cil.oc.{OpenComputers, Settings} import li.cil.oc.{OpenComputers, Settings}
import net.minecraft.world.ChunkCoordIntPair import net.minecraft.world.{World, ChunkCoordIntPair}
import net.minecraftforge.common.DimensionManager import net.minecraftforge.common.DimensionManager
import net.minecraftforge.event.world.{ChunkDataEvent, WorldEvent} import net.minecraftforge.event.world.{ChunkDataEvent, WorldEvent}
import scala.collection.mutable import scala.collection.mutable
@ -13,19 +13,20 @@ import scala.collection.mutable
// files instead of directly in the tile entity data, avoiding potential // files instead of directly in the tile entity data, avoiding potential
// problems with the tile entity data becoming too large. // problems with the tile entity data becoming too large.
object SaveHandler { object SaveHandler {
val saveData = mutable.Map.empty[ChunkCoordIntPair, mutable.Map[String, Array[Byte]]] val saveData = mutable.Map.empty[Int, mutable.Map[ChunkCoordIntPair, mutable.Map[String, Array[Byte]]]]
def savePath = new io.File(DimensionManager.getCurrentSaveRootDirectory, Settings.savePath + "state") def savePath = new io.File(DimensionManager.getCurrentSaveRootDirectory, Settings.savePath + "state")
def scheduleSave(chunk: ChunkCoordIntPair, name: String, data: Array[Byte]) = saveData.synchronized { def scheduleSave(dimension: Int, chunk: ChunkCoordIntPair, name: String, data: Array[Byte]) = saveData.synchronized {
if (chunk == null) throw new IllegalArgumentException("chunk is null") if (chunk == null) throw new IllegalArgumentException("chunk is null")
else saveData.getOrElseUpdate(chunk, mutable.Map.empty[String, Array[Byte]]) += name -> data else saveData.getOrElseUpdate(dimension, mutable.Map.empty).getOrElseUpdate(chunk, mutable.Map.empty) += name -> data
} }
def load(chunk: ChunkCoordIntPair, name: String): Array[Byte] = { def load(dimension: Int, chunk: ChunkCoordIntPair, name: String): Array[Byte] = {
if (chunk == null) throw new IllegalArgumentException("chunk is null") if (chunk == null) throw new IllegalArgumentException("chunk is null")
val path = savePath val path = savePath
val chunkPath = new io.File(path, s"${chunk.chunkXPos}.${chunk.chunkZPos}") val dimPath = new io.File(path, dimension.toString)
val chunkPath = new io.File(dimPath, s"${chunk.chunkXPos}.${chunk.chunkZPos}")
val file = new io.File(chunkPath, name) val file = new io.File(chunkPath, name)
try { try {
// val bis = new io.BufferedInputStream(new GZIPInputStream(new io.FileInputStream(file))) // val bis = new io.BufferedInputStream(new GZIPInputStream(new io.FileInputStream(file)))
@ -52,12 +53,15 @@ object SaveHandler {
@SubscribeEvent @SubscribeEvent
def onChunkSave(e: ChunkDataEvent.Save) = saveData.synchronized { def onChunkSave(e: ChunkDataEvent.Save) = saveData.synchronized {
val path = savePath val path = savePath
val dimension = e.world.provider.dimensionId
val chunk = e.getChunk.getChunkCoordIntPair val chunk = e.getChunk.getChunkCoordIntPair
val chunkPath = new io.File(path, s"${chunk.chunkXPos}.${chunk.chunkZPos}") val dimPath = new io.File(path, dimension.toString)
val chunkPath = new io.File(dimPath, s"${chunk.chunkXPos}.${chunk.chunkZPos}")
if (chunkPath.exists && chunkPath.isDirectory) { if (chunkPath.exists && chunkPath.isDirectory) {
for (file <- chunkPath.listFiles()) file.delete() for (file <- chunkPath.listFiles()) file.delete()
} }
saveData.get(chunk) match { saveData.get(dimension) match {
case Some(chunks) => chunks.get(chunk) match {
case Some(entries) => case Some(entries) =>
chunkPath.mkdirs() chunkPath.mkdirs()
for ((name, data) <- entries) { for ((name, data) <- entries) {
@ -74,10 +78,15 @@ object SaveHandler {
} }
case _ => chunkPath.delete() case _ => chunkPath.delete()
} }
case _ =>
}
} }
@SubscribeEvent @SubscribeEvent
def onWorldSave(e: WorldEvent.Save) = saveData.synchronized { def onWorldSave(e: WorldEvent.Save) = saveData.synchronized {
saveData.clear() saveData.get(e.world.provider.dimensionId) match {
case Some(chunks) => chunks.clear()
case _ =>
}
} }
} }

View File

@ -136,8 +136,10 @@ trait Computer extends Environment with ComponentInventory with Rotatable with B
// Note: chunk unload is handled by sound via event handler. // Note: chunk unload is handled by sound via event handler.
override def invalidate() { override def invalidate() {
super.invalidate() super.invalidate()
if (isClient) {
Sound.stopLoop(this) Sound.stopLoop(this)
} }
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //

View File

@ -239,8 +239,10 @@ class Rack extends PowerAcceptor with Hub with PowerBalancer with Inventory with
// Note: chunk unload is handled by sound via event handler. // Note: chunk unload is handled by sound via event handler.
override def invalidate() { override def invalidate() {
super.invalidate() super.invalidate()
if (isClient) {
Sound.stopLoop(this) Sound.stopLoop(this)
} }
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //

View File

@ -598,9 +598,10 @@ 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)
val dimension = nbt.getInteger("dimension")
val kernel = val kernel =
if (nbt.hasKey("kernel")) nbt.getByteArray("kernel") if (nbt.hasKey("kernel")) nbt.getByteArray("kernel")
else SaveHandler.load(new ChunkCoordIntPair(machine.owner.x >> 4, machine.owner.z >> 4), node.address + "_kernel") else SaveHandler.load(dimension, new ChunkCoordIntPair(machine.owner.x >> 4, machine.owner.z >> 4), node.address + "_kernel")
unpersist(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
@ -610,7 +611,7 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu
if (state.contains(Machine.State.SynchronizedCall) || state.contains(Machine.State.SynchronizedReturn)) { if (state.contains(Machine.State.SynchronizedCall) || state.contains(Machine.State.SynchronizedReturn)) {
val stack = val stack =
if (nbt.hasKey("stack")) nbt.getByteArray("stack") if (nbt.hasKey("stack")) nbt.getByteArray("stack")
else SaveHandler.load(new ChunkCoordIntPair(machine.owner.x >> 4, machine.owner.z >> 4), node.address + "_stack") else SaveHandler.load(dimension, new ChunkCoordIntPair(machine.owner.x >> 4, machine.owner.z >> 4), node.address + "_stack")
unpersist(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
@ -638,12 +639,14 @@ 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))
SaveHandler.scheduleSave(new ChunkCoordIntPair(machine.owner.x >> 4, machine.owner.z >> 4), node.address + "_kernel", persist(1)) val dimension = machine.owner.world.provider.dimensionId
nbt.setInteger("dimension", dimension)
SaveHandler.scheduleSave(dimension, 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))
SaveHandler.scheduleSave(new ChunkCoordIntPair(machine.owner.x >> 4, machine.owner.z >> 4), node.address + "_stack", persist(2)) SaveHandler.scheduleSave(dimension, 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)