added hard component count limit, computers can now only be connected to a limited number of components or they won't start/crash. this number increases with the tier, and can be increased in servers by adding cpus.

This commit is contained in:
Florian Nücke 2014-01-16 02:25:37 +01:00
parent e560a9ee47
commit b07c3e202f
10 changed files with 114 additions and 41 deletions

View File

@ -166,6 +166,7 @@ object Settings {
val scriptPath = "/assets/" + resourceDomain + "/lua/"
val screenResolutionsByTier = Array((50, 16), (80, 25), (160, 50))
val screenDepthsByTier = Array(PackedColor.Depth.OneBit, PackedColor.Depth.FourBit, PackedColor.Depth.EightBit)
val componentCountByTier = Array(8, 12, 16)
def basicScreenPixels = screenResolutionsByTier(0)._1 * screenResolutionsByTier(0)._2

View File

@ -3,7 +3,7 @@ package li.cil.oc.api.driver;
import net.minecraft.item.ItemStack;
/**
* Use this trait to implement item drivers extending the memory of a computer.
* Use this interface to implement item drivers extending the memory of a computer.
* <p/>
* Note that the item must be installed in the actual computer's inventory to
* work. If it is installed in an external inventory the computer will not
@ -13,8 +13,8 @@ public interface Memory extends Item {
/**
* The amount of RAM this component provides, in bytes.
*
* @param item the item to get the provided memory for.
* @param stack the item to get the provided memory for.
* @return the amount of memory the specified component provides.
*/
int amount(ItemStack item);
int amount(ItemStack stack);
}

View File

@ -0,0 +1,22 @@
package li.cil.oc.api.driver;
import net.minecraft.item.ItemStack;
/**
* Use this interface to implement item drivers extending the number of
* components a server can control.
* <p/>
* Note that the item must be installed in the actual server's inventory to
* work. If it is installed in an external inventory the server will not
* recognize the memory.
*/
public interface Processor extends Item {
/**
* The additional number of components supported if this processor is
* installed in the server.
*
* @param stack
* @return the number of additionally supported components.
*/
int supportedComponents(ItemStack stack);
}

View File

@ -10,6 +10,8 @@ import net.minecraft.nbt.NBTTagCompound
class Case(var tier: Int, isRemote: Boolean) extends Computer(isRemote) {
def this() = this(0, false)
def maxComponents = Settings.componentCountByTier(tier)
// ----------------------------------------------------------------------- //
override def readFromNBT(nbt: NBTTagCompound) {

View File

@ -117,6 +117,8 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
}
}
def maxComponents = 12
// ----------------------------------------------------------------------- //
override def onAnalyze(stats: NBTTagCompound, player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = {

View File

@ -27,6 +27,8 @@ class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedI
override def computer = robot.computer
def maxComponents = robot.maxComponents
// ----------------------------------------------------------------------- //
// Note: we implement IRobotContext in the TE to allow external components

View File

@ -97,6 +97,10 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi
crash("computers don't work while time is frozen (gamerule doDaylightCycle is false)")
false
}
else if (components.size + addedComponents.size > owner.maxComponents) {
message = Some("too many components")
false
}
else if (owner.installedMemory > 0) {
if (Settings.get.ignorePower || node.globalBuffer > cost) {
init() && {
@ -260,6 +264,12 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi
// reachability).
processAddedComponents()
// Component overflow check, crash if too many components are connected, to
// avoid confusion on the user's side due to components not showing up.
if (components.size > owner.maxComponents) {
crash("too many components")
}
// Update world time for time().
worldTime = owner.world.getWorldTime
@ -314,6 +324,7 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi
case Machine.State.Restarting =>
close()
tmp.foreach(_.node.remove()) // To force deleting contents.
tmp.foreach(tmp => node.connect(tmp.node))
node.sendToReachable("computer.stopped")
start()
// Resume from pauses based on sleep or signal underflow.
@ -360,6 +371,7 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi
OpenComputers.log.log(Level.WARNING, "Faulty architecture implementation for synchronized calls.", e)
crash("protocol error")
}
assert(state.top != Machine.State.Running)
case _ => // Nothing special to do, just avoid match errors.
})
@ -370,8 +382,8 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi
// Computer is shutting down.
case Machine.State.Stopping => this.synchronized(state.synchronized {
close()
rom.foreach(_.node.remove())
tmp.foreach(_.node.remove())
tmp.foreach(_.node.remove()) // To force deleting contents.
tmp.foreach(tmp => node.connect(tmp.node))
node.sendToReachable("computer.stopped")
})
case _ =>
@ -674,7 +686,8 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi
val result = architecture.runThreaded(enterState)
// Check if someone called pause() or stop() in the meantime.
state.synchronized(state.top match {
state.synchronized {
state.top match {
case Machine.State.Running =>
result match {
case result: ExecutionResult.Sleep =>
@ -707,10 +720,14 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi
case Machine.State.Stopping => // Nothing to do, we'll die anyway.
case _ => throw new AssertionError(
"Invalid state in executor post-processing.")
})
}
assert(state.top != Machine.State.Running)
}
}
catch {
case e: Throwable => OpenComputers.log.log(Level.WARNING, "Architecture's runThreaded threw an error. This should never happen!", e)
case e: Throwable =>
OpenComputers.log.log(Level.WARNING, "Architecture's runThreaded threw an error. This should never happen!", e)
crash("kernel panic: architecture threw an exception, see log file")
}
// Keep track of time spent executing the computer.
@ -763,6 +780,8 @@ object Machine {
trait Owner {
def installedMemory: Int
def maxComponents: Int
def world: World
def markAsChanged()

View File

@ -37,6 +37,14 @@ class Server(val rack: tileentity.Rack, val number: Int) extends Machine.Owner {
case _ => 0
}))
lazy val maxComponents = inventory.items.foldLeft(0)((sum, stack) => sum + (stack match {
case Some(item) => Registry.itemDriverFor(item) match {
case Some(driver: driver.Processor) => driver.supportedComponents(item)
case _ => 0
}
case _ => 0
}))
def world = rack.world
def markAsChanged() = rack.markAsChanged()

View File

@ -19,12 +19,16 @@ class LuaArchitecture(val machine: Machine) extends Architecture {
private val ramScale = if (LuaStateFactory.is64Bit) Settings.get.ramScaleFor64Bit else 1.0
// ----------------------------------------------------------------------- //
private def node = machine.node
private def state = machine.state
private def components = machine.components
// ----------------------------------------------------------------------- //
def isInitialized = kernelMemory > 0
def recomputeMemory() = Option(lua) match {
@ -37,6 +41,8 @@ class LuaArchitecture(val machine: Machine) extends Architecture {
case _ =>
}
// ----------------------------------------------------------------------- //
def runSynchronized() {
// These three asserts are all guaranteed by run().
assert(lua.getTop == 2)
@ -173,6 +179,8 @@ class LuaArchitecture(val machine: Machine) extends Architecture {
}
}
// ----------------------------------------------------------------------- //
def init(): Boolean = {
// Creates a new state with all base libraries and the persistence library
// loaded into it. This means the state has much more power than it
@ -543,6 +551,8 @@ class LuaArchitecture(val machine: Machine) extends Architecture {
kernelMemory = 0
}
// ----------------------------------------------------------------------- //
def load(nbt: NBTTagCompound) {
// Unlimit memory use while unpersisting.
lua.setTotalMemory(Integer.MAX_VALUE)

View File

@ -1,12 +1,13 @@
package li.cil.oc.server.driver.item
import li.cil.oc.Items
import li.cil.oc.api.driver
import li.cil.oc.api.driver.Slot
import li.cil.oc.common.item
import li.cil.oc.{Settings, Items}
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntity
object Processor extends Item {
object Processor extends Item with driver.Processor {
def worksWith(stack: ItemStack) = isOneOf(stack, Items.cpu0, Items.cpu1, Items.cpu2)
def createEnvironment(stack: ItemStack, container: TileEntity) = null
@ -18,4 +19,10 @@ object Processor extends Item {
case Some(cpu: item.CPU) => cpu.tier
case _ => 0
}
def supportedComponents(stack: ItemStack) =
Items.multi.subItem(stack) match {
case Some(cpu: item.CPU) => Settings.componentCountByTier(cpu.tier)
case _ => 0
}
}