diff --git a/li/cil/oc/Config.scala b/li/cil/oc/Config.scala index 0d1be4377..ca5f9bf4c 100644 --- a/li/cil/oc/Config.scala +++ b/li/cil/oc/Config.scala @@ -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.") diff --git a/li/cil/oc/common/component/Screen.scala b/li/cil/oc/common/component/Screen.scala index 51fe01892..ee0ecd171 100644 --- a/li/cil/oc/common/component/Screen.scala +++ b/li/cil/oc/common/component/Screen.scala @@ -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) diff --git a/li/cil/oc/common/tileentity/Computer.scala b/li/cil/oc/common/tileentity/Computer.scala index 1807b67bc..7e9a1bf05 100644 --- a/li/cil/oc/common/tileentity/Computer.scala +++ b/li/cil/oc/common/tileentity/Computer.scala @@ -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 diff --git a/li/cil/oc/server/component/Computer.scala b/li/cil/oc/server/component/Computer.scala index 0d6e2364a..04450b8ac 100644 --- a/li/cil/oc/server/component/Computer.scala +++ b/li/cil/oc/server/component/Computer.scala @@ -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