blob: 785b253bc0eb71cab2b9adf92854aede8ffd2206 [file] [log] [blame] [raw]
package li.cil.oc.common.event
import java.util
import cpw.mods.fml.common.eventhandler.SubscribeEvent
import li.cil.oc.api.event.RobotMoveEvent
import li.cil.oc.server.component.UpgradeChunkloader
import li.cil.oc.util.BlockPosition
import net.minecraft.world.ChunkCoordIntPair
import net.minecraft.world.World
import net.minecraftforge.common.ForgeChunkManager
import net.minecraftforge.common.ForgeChunkManager.LoadingCallback
import net.minecraftforge.common.ForgeChunkManager.Ticket
import net.minecraftforge.event.world.WorldEvent
import scala.collection.convert.WrapAsScala._
import scala.collection.mutable
object ChunkloaderUpgradeHandler extends LoadingCallback {
val restoredTickets = mutable.Map.empty[String, Ticket]
override def ticketsLoaded(tickets: util.List[Ticket], world: World) {
for (ticket <- tickets) {
val data = ticket.getModData
restoredTickets += data.getString("address") -> ticket
if (data.hasKey("x") && data.hasKey("z")) {
val x = data.getInteger("x")
val z = data.getInteger("z")
ForgeChunkManager.forceChunk(ticket, new ChunkCoordIntPair(x, z))
}
}
}
@SubscribeEvent
def onWorldSave(e: WorldEvent.Save) {
// Any tickets that were not reassigned by the time the world gets saved
// again can be considered orphaned, so we release them.
// TODO figure out a better event *after* tile entities were restored
// but *before* the world is saved, because the tickets are saved first,
// so if the save is because the game is being quit the tickets aren't
// actually being cleared. This will *usually* not be a problem, but it
// has room for improvement.
restoredTickets.values.foreach(ticket => try ForgeChunkManager.releaseTicket(ticket) catch {
case _: Throwable => // Ignored.
})
restoredTickets.clear()
}
// Note: it might be necessary to use pre move to force load the target chunk
// in case the robot moves across a chunk border into an otherwise unloaded
// chunk (I think it would just fail to move otherwise).
// Update 2014-06-21: did some testing, seems not to be necessary. My guess
// is that the access to the block in the direction the robot moves causes
// the chunk it might move into to get loaded.
@SubscribeEvent
def onMove(e: RobotMoveEvent.Post) {
for (slot <- 0 until e.robot.getSizeInventory) {
e.robot.getComponentInSlot(slot) match {
case loader: UpgradeChunkloader => updateLoadedChunk(loader)
case _ =>
}
}
}
def updateLoadedChunk(loader: UpgradeChunkloader) {
val blockPos = BlockPosition(loader.host)
val centerChunk = new ChunkCoordIntPair(blockPos.x >> 4, blockPos.z >> 4)
val robotChunks = (for (x <- -1 to 1; z <- -1 to 1) yield new ChunkCoordIntPair(centerChunk.chunkXPos + x, centerChunk.chunkZPos + z)).toSet
loader.ticket.foreach(ticket => {
ticket.getChunkList.collect {
case chunk: ChunkCoordIntPair if !robotChunks.contains(chunk) => ForgeChunkManager.unforceChunk(ticket, chunk)
}
for (chunk <- robotChunks) {
ForgeChunkManager.forceChunk(ticket, chunk)
}
ticket.getModData.setString("address", loader.node.address)
ticket.getModData.setInteger("x", centerChunk.chunkXPos)
ticket.getModData.setInteger("z", centerChunk.chunkZPos)
})
}
}