made all the power stuff configurable; working around power spikes when loading computer blocks (waiting for world to settle for a second before continuing execution)

This commit is contained in:
Florian Nücke 2013-11-04 13:53:43 +01:00
parent 49ced36d5f
commit 1b5719347e
4 changed files with 66 additions and 24 deletions

View File

@ -13,20 +13,14 @@ object Config {
// ----------------------------------------------------------------------- //
// Power it takes to run a computer at 100% CPU time for one second.
val cpuTimeCost = 256
// Power it takes to change a single pixel via the set command.
val screenSetCost = 1.0 / 20
// Power it takes to change a single pixel via the fill command.
val screenFillCost = 1.0 / 180
// Power it takes to change a single pixel to blank via the fill command.
val screenClearCost = 1.0 / 200
// Power it takes to move a single pixel via the copy command.
val screenCopyCost = 1.0 / 160
var bufferComputer = 16.0
var bufferScreen = 16.0
var computerBaseCost = 1.0 / 20
var computerCpuTimeCost = 256.0
var screenFillCost = 1.0 / 180
var screenClearCost = 1.0 / 200
var screenCopyCost = 1.0 / 160
var screenSetCost = 1.0 / 20
// ----------------------------------------------------------------------- //
@ -98,6 +92,43 @@ object Config {
// --------------------------------------------------------------------- //
config.getCategory("power").
setComment("Power settings, buffer sizes and power consumption.")
bufferComputer = config.get("power", "bufferComputer", bufferComputer, "" +
"The buffer size for computers, i.e. how much power they store internally.").
getDouble(bufferComputer)
bufferScreen = config.get("power", "bufferScreen", bufferScreen, "" +
"The buffer size for screens, i.e. how much power they store internally.").
getDouble(bufferScreen)
computerBaseCost = config.get("power", "computerBaseCost", computerBaseCost, "" +
"Power it takes per tick to run a computer, even if it's idle (base cost).").
getDouble(computerBaseCost)
computerCpuTimeCost = config.get("power", "computerCpuTimeCost", computerCpuTimeCost, "" +
"Power it takes to run a computer at 100% CPU time for one second.").
getDouble(computerCpuTimeCost)
screenFillCost = config.get("power", "screenFillCost", screenFillCost, "" +
"Power it takes to change a single pixel via the fill command.").
getDouble(screenFillCost)
screenClearCost = config.get("power", "screenClearCost", screenClearCost, "" +
"Power it takes to change a single pixel to blank via the fill command.").
getDouble(screenClearCost)
screenCopyCost = config.get("power", "screenCopyCost", screenCopyCost, "" +
"Power it takes to move a single pixel via the copy command.").
getDouble(screenCopyCost)
screenSetCost = config.get("power", "screenSetCost", screenSetCost, "" +
"Power it takes to change a single pixel via the set command.").
getDouble(screenSetCost)
// --------------------------------------------------------------------- //
config.getCategory("server").
setComment("Server side settings, gameplay and security related stuff.")

View File

@ -74,7 +74,7 @@ object Screen {
trait Environment extends tileentity.Environment with util.Persistable {
val node = api.Network.newNode(this, Visibility.Network).
withComponent("screen").
withConnector(16).
withConnector(Config.bufferScreen).
create()
final val instance = new component.Screen(this, maxResolution)

View File

@ -13,6 +13,7 @@ import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.ForgeDirection
import li.cil.oc.Config
class Computer(isClient: Boolean) extends Rotatable with ComputerEnvironment with ComponentInventory with Redstone {
def this() = this(false)
@ -77,7 +78,7 @@ class Computer(isClient: Boolean) extends Rotatable with ComputerEnvironment wit
// otherwise loose track of its screen).
instance.update()
val (powerRequired, needsSaving) = this.synchronized {
val a = powerConsumed + 0.05
val a = powerConsumed + Config.computerBaseCost
val b = hasChanged
powerConsumed = 0
hasChanged = false

View File

@ -203,6 +203,10 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
// reachability).
processAddedComponents()
// Are we waiting for the world to settle?
if (lastUpdate == 0 && System.currentTimeMillis() < sleepUntil)
return
// Update last time run to let our executor thread know it doesn't have to
// pause.
lastUpdate = System.currentTimeMillis
@ -375,6 +379,9 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
state = Computer.State.SynchronizedReturnPaused
case _ => // Will be started by update() if necessary.
}
// Delay execution for a second to allow the world around us to settle.
sleepUntil = System.currentTimeMillis() + 1000
} catch {
case e: LuaRuntimeException => {
OpenComputers.log.warning("Could not unpersist computer.\n" + e.toString + "\tat " + e.getLuaStackTrace.mkString("\n\tat "))
@ -924,7 +931,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
cpuTime = 0
cpuStart = 0
future = None
sleepUntil = Long.MaxValue
sleepUntil = Double.PositiveInfinity
// Mark state change in owner, to send it to clients.
owner.markAsChanged(Double.NegativeInfinity)
@ -934,7 +941,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
private def execute(value: Computer.State.Value) {
assert(future.isEmpty)
sleepUntil = Long.MaxValue
sleepUntil = Double.PositiveInfinity
state = value
future = Some(Computer.Executor.pool.submit(this))
}
@ -946,7 +953,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
state = Computer.State.Running
// See if the game appears to be paused, in which case we also pause.
if (System.currentTimeMillis - lastUpdate > 200) {
if (System.currentTimeMillis - lastUpdate > 50) {
state = oldState match {
case Computer.State.SynchronizedReturn => Computer.State.SynchronizedReturnPaused
case _ => Computer.State.Paused
@ -998,12 +1005,10 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
case _ =>
lua.resume(1, 0)
}
val runtime = System.nanoTime() - cpuStart
cpuTime += runtime
// Check if this was the first run, meaning the one used for initializing
// the kernel (loading the libs, establishing a memory baseline).
if (kernelMemory == 0) {
val runtime = if (kernelMemory == 0) {
// Run the garbage collector to get rid of stuff left behind after the
// initialization phase to get a good estimate of the base memory usage
// the kernel has. We remember that size to grant user-space programs a
@ -1012,7 +1017,12 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
lua.gc(LuaState.GcAction.COLLECT, 0)
kernelMemory = (lua.getTotalMemory - lua.getFreeMemory) + Config.baseMemory
recomputeMemory()
0
}
else {
System.nanoTime() - cpuStart
}
cpuTime += runtime
// Check if the kernel is still alive.
stateMonitor.synchronized(if (lua.status(1) == LuaState.YIELD) {
@ -1058,7 +1068,7 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
}
// State has inevitably changed, mark as changed to save again.
owner.markAsChanged(Config.cpuTimeCost.toDouble * runtime / 1000 / 1000 / 1000)
owner.markAsChanged(Config.computerCpuTimeCost * runtime / 1000 / 1000 / 1000)
}
// The kernel thread returned. If it threw we'd we in the catch below.
else {
@ -1112,7 +1122,7 @@ object Computer {
trait Environment extends tileentity.Environment with oc.util.Persistable with Context {
val node = api.Network.newNode(this, Visibility.Network).
withComponent("computer", Visibility.Neighbors).
withConnector(16).
withConnector(Config.bufferComputer).
create()
val instance: Computer