mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-16 18:55:03 -04:00
cleaned up synchronization in connector/distributor, i think; pausing computer in save to make sure it won't continue running until the whole world finished saving; started work on charger (robot loading block); reworked connector interface, changeBuffer now returns the delta that could not be applied and added new method tryChangeBuffer that will only apply the full delta or nothing, and return true if it worked, false otherwise
This commit is contained in:
parent
f5e1f09af3
commit
c52e18a87b
@ -71,11 +71,11 @@ class Settings(config: Config) {
|
||||
val ratioBuildCraft = config.getDouble("power.ratioBuildCraft").toFloat
|
||||
val ratioIndustrialCraft2 = config.getDouble("power.ratioIndustrialCraft2").toFloat
|
||||
val ratioUniversalElectricity = config.getDouble("power.ratioUniversalElectricity").toFloat
|
||||
val chargeRate = config.getDouble("power.chargerChargeRate")
|
||||
|
||||
// power.buffer
|
||||
val bufferCapacitor = config.getDouble("power.buffer.capacitor") max 0
|
||||
val bufferCapacitorAdjacencyBonus = config.getDouble("power.buffer.capacitorAdjacencyBonus") max 0
|
||||
val bufferChargingStation = 50000.0
|
||||
val bufferRobot = config.getDouble("power.buffer.robot") max 0
|
||||
|
||||
// power.cost
|
||||
|
@ -53,24 +53,30 @@ public interface Connector extends Node {
|
||||
* a program tries to display text on it. For running costs just apply the
|
||||
* same delta each tick.
|
||||
* <p/>
|
||||
* For negative values, if there is not enough energy stored in the buffer
|
||||
* this will return <tt>false</tt>, and the operation depending on that
|
||||
* energy should fail - what energy there is will still be consumed, though!
|
||||
* If the specified delta cannot be completely applied to the buffer, the
|
||||
* remaining delta will be returned. This means that for negative values
|
||||
* a part of the energy will have been consumed, though.
|
||||
* <p/>
|
||||
* For positive values, if there is a buffer overflow due to the added
|
||||
* energy the surplus will be lost and this will return <tt>false</tt>.
|
||||
* <p/>
|
||||
* If there is enough energy or no overflow this will return <tt>true</tt>.
|
||||
* If there is enough energy or no overflow this will return <tt>0</tt>.
|
||||
* <p/>
|
||||
* Keep in mind that this change is applied to the <em>global</em> buffer,
|
||||
* i.e. energy from multiple buffers may be consumed / multiple buffers may
|
||||
* be filled. The buffer for which this method is called (i.e. this node
|
||||
* instance) will be prioritized, though.
|
||||
*
|
||||
* @param delta the amount of energy to consume or make available.
|
||||
* @return whether the energy could be consumed or stored.
|
||||
* @param delta the amount of energy to consume or store.
|
||||
* @return the remainder of the delta that could not be applied.
|
||||
*/
|
||||
boolean changeBuffer(double delta);
|
||||
double changeBuffer(double delta);
|
||||
|
||||
/**
|
||||
* Like {@link #changeBuffer}, but will only store/consume the specified
|
||||
* amount of energy if there is enough capacity/energy available.
|
||||
*
|
||||
* @param delta the amount of energy to consume or store.
|
||||
* @return <tt>true</tt> if the energy was successfully consumed or stored.
|
||||
*/
|
||||
boolean tryChangeBuffer(double delta);
|
||||
|
||||
/**
|
||||
* Change the size of the connectors local buffer.
|
||||
|
37
li/cil/oc/common/block/Charger.scala
Normal file
37
li/cil/oc/common/block/Charger.scala
Normal file
@ -0,0 +1,37 @@
|
||||
package li.cil.oc.common.block
|
||||
|
||||
import java.util
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.common.tileentity
|
||||
import li.cil.oc.util.Tooltip
|
||||
import net.minecraft.client.renderer.texture.IconRegister
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.util.Icon
|
||||
import net.minecraft.world.World
|
||||
import net.minecraftforge.common.ForgeDirection
|
||||
|
||||
class Charger(val parent: SimpleDelegator) extends SimpleDelegate {
|
||||
val unlocalizedName = "Charger"
|
||||
|
||||
var icon: Icon = null
|
||||
|
||||
override def addInformation(player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) {
|
||||
tooltip.addAll(Tooltip.get(unlocalizedName))
|
||||
}
|
||||
|
||||
override def icon(side: ForgeDirection) = Some(icon)
|
||||
|
||||
override def registerIcons(iconRegister: IconRegister) = {
|
||||
icon = iconRegister.registerIcon(Settings.resourceDomain + ":charger")
|
||||
}
|
||||
|
||||
override def hasTileEntity = true
|
||||
|
||||
override def createTileEntity(world: World) = Some(new tileentity.Charger())
|
||||
|
||||
override def onNeighborBlockChange(world: World, x: Int, y: Int, z: Int, blockId: Int) =
|
||||
world.getBlockTileEntity(x, y, z) match {
|
||||
case charger: tileentity.Charger => charger.onNeighborChanged()
|
||||
case _ =>
|
||||
}
|
||||
}
|
53
li/cil/oc/common/tileentity/Charger.scala
Normal file
53
li/cil/oc/common/tileentity/Charger.scala
Normal file
@ -0,0 +1,53 @@
|
||||
package li.cil.oc.common.tileentity
|
||||
|
||||
import li.cil.oc.api.network.{Node, Visibility}
|
||||
import li.cil.oc.client.{PacketSender => ClientPacketSender}
|
||||
import li.cil.oc.{Settings, api}
|
||||
import net.minecraftforge.common.ForgeDirection
|
||||
|
||||
class Charger extends Environment with Redstone {
|
||||
val node = api.Network.newNode(this, Visibility.None).
|
||||
withConnector().
|
||||
create()
|
||||
|
||||
private val robots = Array.fill(6)(None: Option[RobotProxy])
|
||||
|
||||
private var chargeSpeed = 0.0
|
||||
|
||||
override def updateEntity() {
|
||||
super.updateEntity()
|
||||
updateRedstoneInput()
|
||||
|
||||
if (chargeSpeed > 0) {
|
||||
val charge = Settings.get.chargeRate * chargeSpeed
|
||||
robots.collect {
|
||||
case Some(proxy) => node.changeBuffer(proxy.robot.battery.changeBuffer(charge + node.changeBuffer(-charge)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def validate() {
|
||||
super.validate()
|
||||
if (isClient) {
|
||||
ClientPacketSender.sendRedstoneStateRequest(this)
|
||||
}
|
||||
}
|
||||
|
||||
override def onConnect(node: Node) {
|
||||
super.onConnect(node)
|
||||
if (node == this.node) {
|
||||
onNeighborChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override protected def onRedstoneInputChanged(side: ForgeDirection) {
|
||||
super.onRedstoneInputChanged(side)
|
||||
chargeSpeed = 0.0 max (ForgeDirection.VALID_DIRECTIONS.map(input).max min 15) / 15.0
|
||||
}
|
||||
|
||||
def onNeighborChanged() {
|
||||
ForgeDirection.VALID_DIRECTIONS.map(side => (side.ordinal(), world.getBlockTileEntity(x + side.offsetX, y + side.offsetY, z + side.offsetZ))).collect {
|
||||
case (side, proxy: RobotProxy) => robots(side) = Some(proxy)
|
||||
}
|
||||
}
|
||||
}
|
@ -117,10 +117,8 @@ abstract class Computer(isRemote: Boolean) extends Environment with ComponentInv
|
||||
|
||||
override protected def onRedstoneInputChanged(side: ForgeDirection) {
|
||||
super.onRedstoneInputChanged(side)
|
||||
if (isServer) {
|
||||
computer.signal("redstone_changed", Int.box(side.ordinal()))
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
|
@ -51,7 +51,7 @@ trait Redstone extends TileEntity with network.Environment with Rotatable with P
|
||||
}
|
||||
|
||||
def checkRedstoneInputChanged() {
|
||||
shouldUpdateInput = true
|
||||
shouldUpdateInput = isServer
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
@ -206,8 +206,8 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
|
||||
if (isServer) {
|
||||
if (computer.isRunning && !computer.isPaused) {
|
||||
// TODO just for testing... until we have charging stations
|
||||
distributor.changeBuffer(Settings.get.robotCost + 0.1)
|
||||
distributor.changeBuffer(Settings.get.computerCost - Settings.get.robotCost)
|
||||
battery.changeBuffer(Settings.get.robotCost + 0.1)
|
||||
battery.changeBuffer(Settings.get.computerCost - Settings.get.robotCost)
|
||||
}
|
||||
distributor.update()
|
||||
gpu.update()
|
||||
@ -286,7 +286,6 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
|
||||
computer.node.connect(gpu.node)
|
||||
distributor.node.connect(battery)
|
||||
buffer.node.connect(keyboard.node)
|
||||
distributor.changeBuffer(distributor.globalBufferSize / 2) // TODO for testing only
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,8 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable
|
||||
litPixels = buffer.lines.foldLeft(0)((acc, line) => acc + line.count(_ != ' '))
|
||||
}
|
||||
val hadPower = hasPower
|
||||
hasPower = buffer.node.changeBuffer(-(Settings.get.screenCost + pixelCost * litPixels))
|
||||
val neededPower = Settings.get.screenCost + pixelCost * litPixels
|
||||
hasPower = buffer.node.tryChangeBuffer(-neededPower)
|
||||
if (hasPower != hadPower) {
|
||||
ServerPacketSender.sendScreenPowerChange(this, hasPower)
|
||||
}
|
||||
|
@ -220,11 +220,11 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con
|
||||
Computer.State.Stopping |
|
||||
Computer.State.Stopped => // No power consumption.
|
||||
case Computer.State.Sleeping if lastUpdate < sleepUntil && signals.isEmpty =>
|
||||
if (!node.changeBuffer(-Settings.get.computerCost * Settings.get.sleepCostFactor)) {
|
||||
if (!node.tryChangeBuffer(-Settings.get.computerCost * Settings.get.sleepCostFactor)) {
|
||||
crash("not enough energy")
|
||||
}
|
||||
case _ =>
|
||||
if (!node.changeBuffer(-Settings.get.computerCost)) {
|
||||
if (!node.tryChangeBuffer(-Settings.get.computerCost)) {
|
||||
crash("not enough energy")
|
||||
}
|
||||
})
|
||||
@ -494,6 +494,9 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con
|
||||
override def save(nbt: NBTTagCompound): Unit = this.synchronized {
|
||||
assert(state.top != Computer.State.Running) // Lock on 'this' should guarantee this.
|
||||
|
||||
// Make sure we don't continue running until everything has saved.
|
||||
pause(0.05)
|
||||
|
||||
super.save(nbt)
|
||||
|
||||
// Make sure the component list is up-to-date.
|
||||
|
@ -144,7 +144,7 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
||||
Array.copy(buffer, 0, bytes, 0, read)
|
||||
bytes
|
||||
}
|
||||
if (!node.changeBuffer(-Settings.get.hddReadCost * bytes.length)) {
|
||||
if (!node.tryChangeBuffer(-Settings.get.hddReadCost * bytes.length)) {
|
||||
throw new IOException("not enough energy")
|
||||
}
|
||||
result(bytes)
|
||||
@ -179,7 +179,7 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
|
||||
def write(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val handle = args.checkInteger(0)
|
||||
val value = args.checkByteArray(1)
|
||||
if (!node.changeBuffer(-Settings.get.hddWriteCost * value.length)) {
|
||||
if (!node.tryChangeBuffer(-Settings.get.hddWriteCost * value.length)) {
|
||||
throw new IOException("not enough energy")
|
||||
}
|
||||
checkOwner(context.address, handle)
|
||||
|
@ -182,12 +182,14 @@ abstract class GraphicsCard extends ManagedComponent {
|
||||
s.fill(x, y, w, h, value.charAt(0))
|
||||
result(true)
|
||||
}
|
||||
else result(false)
|
||||
else {
|
||||
result(false)
|
||||
}
|
||||
})
|
||||
else throw new Exception("invalid fill value")
|
||||
}
|
||||
|
||||
private def consumePower(n: Double, cost: Double) = node.changeBuffer(-n * cost)
|
||||
private def consumePower(n: Double, cost: Double) = node.tryChangeBuffer(-n * cost)
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
|
@ -36,20 +36,29 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def canChangeBuffer(delta: Double) = {
|
||||
Settings.get.ignorePower || globalBuffer + delta >= 0
|
||||
def changeBuffer(delta: Double): Double = {
|
||||
if (delta == 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
def changeBuffer(delta: Double): Boolean = {
|
||||
if (delta != 0) this.synchronized {
|
||||
if (Settings.get.ignorePower) {
|
||||
if (delta < 0) {
|
||||
return 0
|
||||
}
|
||||
else /* if (delta > 0) */ {
|
||||
return delta
|
||||
}
|
||||
}
|
||||
this.synchronized {
|
||||
val oldBuffer = globalBuffer
|
||||
globalBuffer = (globalBuffer + delta) max 0 min globalBufferSize
|
||||
if (globalBuffer != oldBuffer) {
|
||||
if (globalBuffer == oldBuffer) {
|
||||
return delta
|
||||
}
|
||||
dirty = true
|
||||
if (delta < 0) {
|
||||
var remaining = -delta
|
||||
for (connector <- buffers) {
|
||||
connector.synchronized(if (connector.localBuffer > 0) {
|
||||
if (connector.localBuffer > 0) {
|
||||
connector.dirty = true
|
||||
if (connector.localBuffer < remaining) {
|
||||
remaining -= connector.localBuffer
|
||||
@ -57,15 +66,16 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
|
||||
}
|
||||
else {
|
||||
connector.localBuffer -= remaining
|
||||
return true
|
||||
}
|
||||
})
|
||||
return 0
|
||||
}
|
||||
}
|
||||
else if (delta > 0) {
|
||||
}
|
||||
remaining
|
||||
}
|
||||
else /* if (delta > 0) */ {
|
||||
var remaining = delta
|
||||
for (connector <- buffers) {
|
||||
connector.synchronized(if (connector.localBuffer < connector.localBufferSize) {
|
||||
if (connector.localBuffer < connector.localBufferSize) {
|
||||
connector.dirty = true
|
||||
val space = connector.localBufferSize - connector.localBuffer
|
||||
if (space < remaining) {
|
||||
@ -74,14 +84,13 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
|
||||
}
|
||||
else {
|
||||
connector.localBuffer += remaining
|
||||
return true
|
||||
}
|
||||
})
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
remaining
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
@ -384,15 +384,15 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) {
|
||||
result(false, what)
|
||||
}
|
||||
else {
|
||||
if (!robot.distributor.canChangeBuffer(-Settings.get.robotMoveCost)) {
|
||||
if (!robot.battery.tryChangeBuffer(-Settings.get.robotMoveCost)) {
|
||||
result(false, "not enough energy")
|
||||
}
|
||||
else if (robot.move(direction)) {
|
||||
context.pause(Settings.get.moveDelay)
|
||||
robot.distributor.changeBuffer(-Settings.get.robotMoveCost)
|
||||
result(true)
|
||||
}
|
||||
else {
|
||||
robot.battery.changeBuffer(Settings.get.robotMoveCost)
|
||||
result(false, "impossible move")
|
||||
}
|
||||
}
|
||||
@ -401,7 +401,7 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) {
|
||||
@LuaCallback("turn")
|
||||
def turn(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val clockwise = args.checkBoolean(0)
|
||||
if (robot.distributor.changeBuffer(-Settings.get.robotTurnCost)) {
|
||||
if (robot.battery.tryChangeBuffer(-Settings.get.robotTurnCost)) {
|
||||
if (clockwise) robot.rotate(ForgeDirection.UP)
|
||||
else robot.rotate(ForgeDirection.DOWN)
|
||||
robot.animateTurn(clockwise, Settings.get.turnDelay)
|
||||
|
@ -103,7 +103,7 @@ class WirelessNetworkCard(val owner: TileEntity) extends NetworkCard {
|
||||
private def checkPower() {
|
||||
val cost = Settings.get.wirelessCostPerRange
|
||||
if (cost > 0 && !Settings.get.ignorePower) {
|
||||
if (node.globalBuffer < cost || !node.changeBuffer(-strength * cost)) {
|
||||
if (!node.tryChangeBuffer(-strength * cost)) {
|
||||
throw new IOException("not enough energy")
|
||||
}
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ class Player(val robot: Robot) extends EntityPlayer(robot.world, Settings.get.na
|
||||
|
||||
override def addExhaustion(amount: Float) {
|
||||
if (Settings.get.robotExhaustionCost > 0) {
|
||||
robot.distributor.changeBuffer(-Settings.get.robotExhaustionCost * amount)
|
||||
robot.battery.changeBuffer(-Settings.get.robotExhaustionCost * amount)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,21 @@ trait Connector extends Node with network.Connector with Persistable {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def changeBuffer(delta: Double) = if (delta != 0) {
|
||||
val remaining = this.synchronized {
|
||||
def changeBuffer(delta: Double): Double = {
|
||||
if (delta == 0) {
|
||||
return 0
|
||||
}
|
||||
if (Settings.get.ignorePower) {
|
||||
if (delta < 0) {
|
||||
return 0
|
||||
}
|
||||
else /* if (delta > 0) */ {
|
||||
return delta
|
||||
}
|
||||
}
|
||||
def change() = {
|
||||
val oldBuffer = localBuffer
|
||||
localBuffer = localBuffer + delta
|
||||
localBuffer += delta
|
||||
val remaining = if (localBuffer < 0) {
|
||||
val remaining = localBuffer
|
||||
localBuffer = 0
|
||||
@ -43,17 +54,53 @@ trait Connector extends Node with network.Connector with Persistable {
|
||||
dirty ||= (localBuffer != oldBuffer)
|
||||
remaining
|
||||
}
|
||||
distributor.fold(remaining == 0)(_.changeBuffer(remaining)) || Settings.get.ignorePower
|
||||
} else true
|
||||
this.synchronized(distributor match {
|
||||
case Some(d) => d.synchronized(d.changeBuffer(change()))
|
||||
case _ => change()
|
||||
})
|
||||
}
|
||||
|
||||
def tryChangeBuffer(delta: Double): Boolean = {
|
||||
if (delta == 0) {
|
||||
return true
|
||||
}
|
||||
if (Settings.get.ignorePower) {
|
||||
if (delta < 0) {
|
||||
return true
|
||||
}
|
||||
else /* if (delta > 0) */ {
|
||||
return false
|
||||
}
|
||||
}
|
||||
this.synchronized(distributor match {
|
||||
case Some(d) => d.synchronized {
|
||||
val newGlobalBuffer = globalBuffer + delta
|
||||
newGlobalBuffer >= 0 && newGlobalBuffer <= globalBufferSize && d.changeBuffer(delta) == 0
|
||||
}
|
||||
case _ =>
|
||||
val newLocalBuffer = localBuffer + delta
|
||||
if (newLocalBuffer < 0 || newLocalBuffer > localBufferSize) {
|
||||
false
|
||||
}
|
||||
else {
|
||||
localBuffer = newLocalBuffer
|
||||
true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
def setLocalBufferSize(size: Double) {
|
||||
val remaining = this.synchronized {
|
||||
this.synchronized(distributor match {
|
||||
case Some(d) => d.synchronized {
|
||||
localBufferSize = size max 0
|
||||
val surplus = (localBuffer - localBufferSize) max 0
|
||||
localBuffer = localBuffer min localBufferSize
|
||||
surplus
|
||||
d.changeBuffer(surplus)
|
||||
}
|
||||
distributor.foreach(_.changeBuffer(remaining))
|
||||
case _ =>
|
||||
localBufferSize = size max 0
|
||||
localBuffer = localBuffer min localBufferSize
|
||||
})
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
@ -64,8 +111,7 @@ trait Connector extends Node with network.Connector with Persistable {
|
||||
}
|
||||
else if (distributor.isEmpty) {
|
||||
node.host match {
|
||||
case distributor: PowerDistributor =>
|
||||
this.distributor = Some(distributor)
|
||||
case d: PowerDistributor => this.synchronized(distributor = Some(d))
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
@ -73,7 +119,7 @@ trait Connector extends Node with network.Connector with Persistable {
|
||||
}
|
||||
|
||||
override def onDisconnect(node: ImmutableNode) {
|
||||
if (node == this) {
|
||||
if (node == this) this.synchronized {
|
||||
setLocalBufferSize(0)
|
||||
distributor = None
|
||||
}
|
||||
@ -84,7 +130,7 @@ trait Connector extends Node with network.Connector with Persistable {
|
||||
}
|
||||
|
||||
private def findDistributor() = {
|
||||
distributor = reachableNodes.find(_.host.isInstanceOf[PowerDistributor]).fold(None: Option[PowerDistributor])(n => Some(n.host.asInstanceOf[PowerDistributor]))
|
||||
this.synchronized(distributor = reachableNodes.find(_.host.isInstanceOf[PowerDistributor]).fold(None: Option[PowerDistributor])(n => Some(n.host.asInstanceOf[PowerDistributor])))
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
@ -240,6 +240,13 @@ opencomputers {
|
||||
# internal energy units one Joule generates.
|
||||
ratioUniversalElectricity: 5.0
|
||||
|
||||
# The amount of energy a Charge transfers to each adjacent robot per tick
|
||||
# if a maximum strength redstone signal is set. Chargers load robots with
|
||||
# a controllable speed, based on the maximum strength of redstone signals
|
||||
# going into the block. So if a redstone signal of eight is set, it'll
|
||||
# charge robots at roughly half speed.
|
||||
chargerChargeRate: 2500.0
|
||||
|
||||
buffer {
|
||||
# The amount of energy a single capacitor can store.
|
||||
capacitor: 8000.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user