mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-18 19:56:17 -04:00
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:
parent
e560a9ee47
commit
b07c3e202f
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
22
li/cil/oc/api/driver/Processor.java
Normal file
22
li/cil/oc/api/driver/Processor.java
Normal 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);
|
||||
}
|
@ -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) {
|
||||
|
@ -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) = {
|
||||
|
@ -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
|
||||
|
@ -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,43 +686,48 @@ 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 {
|
||||
case Machine.State.Running =>
|
||||
result match {
|
||||
case result: ExecutionResult.Sleep =>
|
||||
signals.synchronized {
|
||||
// Immediately check for signals to allow processing more than one
|
||||
// signal per game tick.
|
||||
if (signals.isEmpty && result.ticks > 0) {
|
||||
switchTo(Machine.State.Sleeping)
|
||||
remainIdle = result.ticks
|
||||
} else {
|
||||
switchTo(Machine.State.Yielded)
|
||||
state.synchronized {
|
||||
state.top match {
|
||||
case Machine.State.Running =>
|
||||
result match {
|
||||
case result: ExecutionResult.Sleep =>
|
||||
signals.synchronized {
|
||||
// Immediately check for signals to allow processing more than one
|
||||
// signal per game tick.
|
||||
if (signals.isEmpty && result.ticks > 0) {
|
||||
switchTo(Machine.State.Sleeping)
|
||||
remainIdle = result.ticks
|
||||
} else {
|
||||
switchTo(Machine.State.Yielded)
|
||||
}
|
||||
}
|
||||
}
|
||||
case result: ExecutionResult.SynchronizedCall =>
|
||||
switchTo(Machine.State.SynchronizedCall)
|
||||
case result: ExecutionResult.Shutdown =>
|
||||
if (result.reboot) {
|
||||
switchTo(Machine.State.Restarting)
|
||||
}
|
||||
else {
|
||||
switchTo(Machine.State.Stopping)
|
||||
}
|
||||
case result: ExecutionResult.Error =>
|
||||
}
|
||||
case Machine.State.Paused =>
|
||||
state.pop() // Paused
|
||||
state.pop() // Running, no switchTo to avoid new future.
|
||||
state.push(Machine.State.Yielded)
|
||||
state.push(Machine.State.Paused)
|
||||
case Machine.State.Stopping => // Nothing to do, we'll die anyway.
|
||||
case _ => throw new AssertionError(
|
||||
"Invalid state in executor post-processing.")
|
||||
})
|
||||
case result: ExecutionResult.SynchronizedCall =>
|
||||
switchTo(Machine.State.SynchronizedCall)
|
||||
case result: ExecutionResult.Shutdown =>
|
||||
if (result.reboot) {
|
||||
switchTo(Machine.State.Restarting)
|
||||
}
|
||||
else {
|
||||
switchTo(Machine.State.Stopping)
|
||||
}
|
||||
case result: ExecutionResult.Error =>
|
||||
}
|
||||
case Machine.State.Paused =>
|
||||
state.pop() // Paused
|
||||
state.pop() // Running, no switchTo to avoid new future.
|
||||
state.push(Machine.State.Yielded)
|
||||
state.push(Machine.State.Paused)
|
||||
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()
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user