working on performance, removing implicit conversions to rich number types in frequently called places (i.e. anything somehow called per tick); optimized power distribution a bit; added a tick delay for continuous power consumption stuff (screens, computer); converted some methods to lazy vals and caching multi-screen bounds

This commit is contained in:
Florian Nücke 2013-12-09 01:32:31 +01:00
parent 8c948098d8
commit 407d25131f
44 changed files with 266 additions and 240 deletions

View File

@ -87,6 +87,7 @@ class Settings(config: Config) {
val ratioUniversalElectricity = config.getDouble("power.ratioUniversalElectricity").toFloat val ratioUniversalElectricity = config.getDouble("power.ratioUniversalElectricity").toFloat
val chargeRate = config.getDouble("power.chargerChargeRate") val chargeRate = config.getDouble("power.chargerChargeRate")
val generatorEfficiency = config.getDouble("power.generatorEfficiency") val generatorEfficiency = config.getDouble("power.generatorEfficiency")
val tickFrequency = 20
// power.buffer // power.buffer
val bufferCapacitor = config.getDouble("power.buffer.capacitor") max 0 val bufferCapacitor = config.getDouble("power.buffer.capacitor") max 0

View File

@ -41,7 +41,7 @@ object PacketSender {
val pb = new PacketBuilder(PacketType.Clipboard) val pb = new PacketBuilder(PacketType.Clipboard)
pb.writeTileEntity(t) pb.writeTileEntity(t)
pb.writeUTF(value.substring(0, value.length min 1024)) pb.writeUTF(value.substring(0, math.min(value.length, 1024)))
pb.sendToServer() pb.sendToServer()
} }

View File

@ -116,9 +116,9 @@ class Robot(playerInventory: InventoryPlayer, val robot: tileentity.Robot) exten
protected def changeSize(w: Double, h: Double) = { protected def changeSize(w: Double, h: Double) = {
val bw = w * MonospaceFontRenderer.fontWidth val bw = w * MonospaceFontRenderer.fontWidth
val bh = h * MonospaceFontRenderer.fontHeight val bh = h * MonospaceFontRenderer.fontHeight
val scaleX = (bufferWidth / (bw + bufferMargin * 2.0)) min 1 val scaleX = math.min(bufferWidth / (bw + bufferMargin * 2.0), 1)
val scaleY = (bufferHeight / (bh + bufferMargin * 2.0)) min 1 val scaleY = math.min(bufferHeight / (bh + bufferMargin * 2.0), 1)
scaleX min scaleY math.min(scaleX, scaleY)
} }
private def drawSelection() { private def drawSelection() {

View File

@ -61,9 +61,9 @@ class Screen(val screen: tileentity.Screen) extends Buffer {
protected def changeSize(w: Double, h: Double) = { protected def changeSize(w: Double, h: Double) = {
val bw = w * MonospaceFontRenderer.fontWidth val bw = w * MonospaceFontRenderer.fontWidth
val bh = h * MonospaceFontRenderer.fontHeight val bh = h * MonospaceFontRenderer.fontHeight
val scaleX = (width / (bw + bufferMargin * 2.0)) min 1 val scaleX = math.min(width / (bw + bufferMargin * 2.0), 1)
val scaleY = (height / (bh + bufferMargin * 2.0)) min 1 val scaleY = math.min(height / (bh + bufferMargin * 2.0), 1)
val scale = scaleX min scaleY val scale = math.min(scaleX, scaleY)
val innerWidth = (bw * scale).toInt val innerWidth = (bw * scale).toInt
val innerHeight = (bh * scale).toInt val innerHeight = (bh * scale).toInt
x = (width - (innerWidth + bufferMargin * 2)) / 2 x = (width - (innerWidth + bufferMargin * 2)) / 2

View File

@ -19,7 +19,8 @@ object MonospaceFontRenderer {
def init(textureManager: TextureManager) = this.synchronized( def init(textureManager: TextureManager) = this.synchronized(
instance = instance.orElse(Some(new Renderer(textureManager)))) instance = instance.orElse(Some(new Renderer(textureManager))))
val (fontWidth, fontHeight) = (5, 9) val fontWidth = 5
val fontHeight = 9
def drawString(x: Int, y: Int, value: Array[Char], color: Array[Short], depth: PackedColor.Depth.Value) = instance match { def drawString(x: Int, y: Int, value: Array[Char], color: Array[Short], depth: PackedColor.Depth.Value) = instance match {
case None => OpenComputers.log.warning("Trying to render string with uninitialized MonospaceFontRenderer.") case None => OpenComputers.log.warning("Trying to render string with uninitialized MonospaceFontRenderer.")

View File

@ -96,7 +96,10 @@ object BufferRenderer {
} }
private def drawBorder(x: Double, y: Double, w: Double, h: Double, u1: Int, v1: Int, u2: Int, v2: Int) = { private def drawBorder(x: Double, y: Double, w: Double, h: Double, u1: Int, v1: Int, u2: Int, v2: Int) = {
val (u1d, u2d, v1d, v2d) = (u1 / 16.0, u2 / 16.0, v1 / 16.0, v2 / 16.0) val u1d = u1 / 16.0
val u2d = u2 / 16.0
val v1d = v1 / 16.0
val v2d = v2 / 16.0
val t = Tessellator.instance val t = Tessellator.instance
t.startDrawingQuads() t.startDrawingQuads()
t.addVertexWithUV(x, y + h, 0, u1d, v2d) t.addVertexWithUV(x, y + h, 0, u1d, v2d)

View File

@ -64,7 +64,7 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with
GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5)
if (distance > fadeDistanceSq) { if (distance > fadeDistanceSq) {
RenderState.setBlendAlpha(0f max (1 - (distance - fadeDistanceSq) * fadeRatio).toFloat) RenderState.setBlendAlpha(math.max(0, 1 - ((distance - fadeDistanceSq) * fadeRatio).toFloat))
} }
MonospaceFontRenderer.init(tileEntityRenderer.renderEngine) MonospaceFontRenderer.init(tileEntityRenderer.renderEngine)
@ -77,8 +77,10 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with
private def compileOrDraw(list: Int) = if (screen.bufferIsDirty && !RenderState.compilingDisplayList) { private def compileOrDraw(list: Int) = if (screen.bufferIsDirty && !RenderState.compilingDisplayList) {
screen.bufferIsDirty = false screen.bufferIsDirty = false
val (sx, sy) = (screen.width, screen.height) val sx = screen.width
val (tw, th) = (sx * 16f, sy * 16f) val sy = screen.height
val tw = sx * 16f
val th = sy * 16f
GL11.glNewList(list, GL11.GL_COMPILE_AND_EXECUTE) GL11.glNewList(list, GL11.GL_COMPILE_AND_EXECUTE)

View File

@ -46,7 +46,7 @@ class PacketBuilder(packetType: PacketType.Value, private val stream: ByteArrayO
val manager = server.getConfigurationManager val manager = server.getConfigurationManager
for (player <- manager.playerEntityList.map(_.asInstanceOf[EntityPlayerMP]) if player.dimension == dimension) { for (player <- manager.playerEntityList.map(_.asInstanceOf[EntityPlayerMP]) if player.dimension == dimension) {
val playerRenderDistance = Int.MaxValue // ObfuscationReflectionHelper.getPrivateValue(classOf[EntityPlayerMP], player, "renderDistance").asInstanceOf[Integer] val playerRenderDistance = Int.MaxValue // ObfuscationReflectionHelper.getPrivateValue(classOf[EntityPlayerMP], player, "renderDistance").asInstanceOf[Integer]
val playerSpecificRange = range min ((manager.getViewDistance min playerRenderDistance) * 16) val playerSpecificRange = math.min(range, (manager.getViewDistance min playerRenderDistance) * 16)
if (player.getDistanceSq(x, y, z) < playerSpecificRange * playerSpecificRange) { if (player.getDistanceSq(x, y, z) < playerSpecificRange * playerSpecificRange) {
sendToPlayer(player.asInstanceOf[Player]) sendToPlayer(player.asInstanceOf[Player])
} }

View File

@ -18,7 +18,7 @@ abstract class Computer extends Delegate {
override def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = override def isProvidingWeakPower(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) =
world.getBlockTileEntity(x, y, z) match { world.getBlockTileEntity(x, y, z) match {
case computer: tileentity.Computer => computer.output(side) max 0 min 15 case computer: tileentity.Computer => math.min(math.max(computer.output(side), 0), 15)
case _ => super.isProvidingWeakPower(world, x, y, z, side) case _ => super.isProvidingWeakPower(world, x, y, z, side)
} }

View File

@ -79,8 +79,8 @@ class Keyboard(val parent: SpecialDelegator) extends SpecialDelegate {
val z0 = -up.offsetZ * sizes(1) - side.offsetZ * sizes(2) - forward.offsetZ * sizes(0) val z0 = -up.offsetZ * sizes(1) - side.offsetZ * sizes(2) - forward.offsetZ * sizes(0)
val z1 = up.offsetZ * sizes(1) + side.offsetZ * sizes(2) - forward.offsetZ * 0.5f val z1 = up.offsetZ * sizes(1) + side.offsetZ * sizes(2) - forward.offsetZ * 0.5f
AxisAlignedBB.getBoundingBox( AxisAlignedBB.getBoundingBox(
(x0 min x1) + 0.5f, (y0 min y1) + 0.5f, (z0 min z1) + 0.5f, math.min(x0, x1) + 0.5f, math.min(y0, y1) + 0.5f, math.min(z0, z1) + 0.5f,
(x0 max x1) + 0.5f, (y0 max y1) + 0.5f, (z0 max z1) + 0.5f) math.max(x0, x1) + 0.5f, math.max(y0, y1) + 0.5f, math.max(z0, z1) + 0.5f)
} }
override def neighborBlockChanged(world: World, x: Int, y: Int, z: Int, blockId: Int) = override def neighborBlockChanged(world: World, x: Int, y: Int, z: Int, blockId: Int) =

View File

@ -97,8 +97,7 @@ class RobotAfterimage(val parent: SpecialDelegator) extends SpecialDelegate {
def findMovingRobot(world: IBlockAccess, x: Int, y: Int, z: Int): Option[tileentity.Robot] = { def findMovingRobot(world: IBlockAccess, x: Int, y: Int, z: Int): Option[tileentity.Robot] = {
for (side <- ForgeDirection.VALID_DIRECTIONS) { for (side <- ForgeDirection.VALID_DIRECTIONS) {
val (rx, ry, rz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ) world.getBlockTileEntity(x + side.offsetX, y + side.offsetY, z + side.offsetZ) match {
world.getBlockTileEntity(rx, ry, rz) match {
case proxy: tileentity.RobotProxy if proxy.robot.moveFromX == x && proxy.robot.moveFromY == y && proxy.robot.moveFromZ == z => return Some(proxy.robot) case proxy: tileentity.RobotProxy if proxy.robot.moveFromX == x && proxy.robot.moveFromY == y && proxy.robot.moveFromZ == z => return Some(proxy.robot)
case _ => case _ =>
} }

View File

@ -32,7 +32,7 @@ class RobotProxy(val parent: SpecialDelegator) extends Computer with SpecialDele
if (stack.hasTagCompound) { if (stack.hasTagCompound) {
if (stack.getTagCompound.hasKey(Settings.namespace + "xp")) { if (stack.getTagCompound.hasKey(Settings.namespace + "xp")) {
val xp = stack.getTagCompound.getDouble(Settings.namespace + "xp") val xp = stack.getTagCompound.getDouble(Settings.namespace + "xp")
val level = (Math.pow(xp - Settings.get.baseXpToLevel, 1 / Settings.get.exponentialXpGrowth) / Settings.get.constantXpGrowth).toInt min 30 val level = math.min((Math.pow(xp - Settings.get.baseXpToLevel, 1 / Settings.get.exponentialXpGrowth) / Settings.get.constantXpGrowth).toInt, 30)
if (level > 0) { if (level > 0) {
tooltip.addAll(Tooltip.get(unlocalizedName + "_Level", level)) tooltip.addAll(Tooltip.get(unlocalizedName + "_Level", level))
} }

View File

@ -77,7 +77,8 @@ abstract class Screen(val parent: SimpleDelegator) extends SimpleDelegate {
override def icon(world: IBlockAccess, x: Int, y: Int, z: Int, worldSide: ForgeDirection, localSide: ForgeDirection) = override def icon(world: IBlockAccess, x: Int, y: Int, z: Int, worldSide: ForgeDirection, localSide: ForgeDirection) =
world.getBlockTileEntity(x, y, z) match { world.getBlockTileEntity(x, y, z) match {
case screen: tileentity.Screen if screen.width > 1 || screen.height > 1 => case screen: tileentity.Screen if screen.width > 1 || screen.height > 1 =>
val (right, bottom) = (screen.width - 1, screen.height - 1) val right = screen.width - 1
val bottom = screen.height - 1
val (px, py) = screen.localPosition val (px, py) = screen.localPosition
val (lx, ly) = screen.pitch match { val (lx, ly) = screen.pitch match {
case ForgeDirection.NORTH => (px, py) case ForgeDirection.NORTH => (px, py)

View File

@ -90,7 +90,7 @@ class Buffer(val owner: tileentity.Buffer) extends api.network.Environment with
// avoid sending too much data to our clients. // avoid sending too much data to our clients.
val (x, truncated) = val (x, truncated) =
if (col < 0) (0, s.substring(-col)) if (col < 0) (0, s.substring(-col))
else (col, s.substring(0, s.length min (buffer.width - col))) else (col, s.substring(0, math.min(s.length, buffer.width - col)))
if (buffer.set(x, row, truncated)) if (buffer.set(x, row, truncated))
owner.onScreenSet(x, row, truncated) owner.onScreenSet(x, row, truncated)
} }

View File

@ -69,10 +69,10 @@ abstract class Player(protected val playerInventory: InventoryPlayer, val otherI
if (intoSlot.getHasStack) { if (intoSlot.getHasStack) {
val intoStack = intoSlot.getStack val intoStack = intoSlot.getStack
val itemsAreEqual = fromStack.isItemEqual(intoStack) && ItemStack.areItemStackTagsEqual(fromStack, intoStack) val itemsAreEqual = fromStack.isItemEqual(intoStack) && ItemStack.areItemStackTagsEqual(fromStack, intoStack)
val maxStackSize = fromStack.getMaxStackSize min intoSlot.getSlotStackLimit val maxStackSize = math.min(fromStack.getMaxStackSize, intoSlot.getSlotStackLimit)
val slotHasCapacity = intoStack.stackSize < maxStackSize val slotHasCapacity = intoStack.stackSize < maxStackSize
if (itemsAreEqual && slotHasCapacity) { if (itemsAreEqual && slotHasCapacity) {
val itemsMoved = (maxStackSize - intoStack.stackSize) min fromStack.stackSize val itemsMoved = math.min(maxStackSize - intoStack.stackSize, fromStack.stackSize)
if (itemsMoved > 0) { if (itemsMoved > 0) {
intoStack.stackSize += from.decrStackSize(itemsMoved).stackSize intoStack.stackSize += from.decrStackSize(itemsMoved).stackSize
intoSlot.onSlotChanged() intoSlot.onSlotChanged()
@ -85,8 +85,8 @@ abstract class Player(protected val playerInventory: InventoryPlayer, val otherI
for (i <- begin until end by step if from.getHasStack && from.getStack.stackSize > 0) { for (i <- begin until end by step if from.getHasStack && from.getStack.stackSize > 0) {
val intoSlot = inventorySlots.get(i).asInstanceOf[Slot] val intoSlot = inventorySlots.get(i).asInstanceOf[Slot]
if (!intoSlot.getHasStack && intoSlot.isItemValid(fromStack)) { if (!intoSlot.getHasStack && intoSlot.isItemValid(fromStack)) {
val maxStackSize = fromStack.getMaxStackSize min intoSlot.getSlotStackLimit val maxStackSize = math.min(fromStack.getMaxStackSize, intoSlot.getSlotStackLimit)
val itemsMoved = maxStackSize min fromStack.stackSize val itemsMoved = math.min(maxStackSize, fromStack.stackSize)
intoSlot.putStack(from.decrStackSize(itemsMoved)) intoSlot.putStack(from.decrStackSize(itemsMoved))
somethingChanged = true somethingChanged = true
} }

View File

@ -25,7 +25,7 @@ class Robot(playerInventory: InventoryPlayer, robot: tileentity.Robot) extends P
override def detectAndSendChanges() { override def detectAndSendChanges() {
super.detectAndSendChanges() super.detectAndSendChanges()
if ((robot.globalBuffer - lastSentBuffer).abs > 1) { if (math.abs(robot.globalBuffer - lastSentBuffer) > 1) {
lastSentBuffer = robot.globalBuffer lastSentBuffer = robot.globalBuffer
ServerPacketSender.sendPowerState(robot) ServerPacketSender.sendPowerState(robot)
} }

View File

@ -39,7 +39,7 @@ trait BundledRedstone extends Redstone with IBundledEmitter with IBundledUpdatab
} }
def bundledInput(side: ForgeDirection, color: Int) = def bundledInput(side: ForgeDirection, color: Int) =
_bundledInput(side.ordinal())(color) max _rednetInput(side.ordinal())(color) math.max(_bundledInput(side.ordinal())(color), _rednetInput(side.ordinal())(color))
def rednetInput(side: ForgeDirection, color: Int, value: Int) = def rednetInput(side: ForgeDirection, color: Int, value: Int) =
if (_rednetInput(side.ordinal())(color) != value) { if (_rednetInput(side.ordinal())(color) != value) {
@ -134,7 +134,9 @@ trait BundledRedstone extends Redstone with IBundledEmitter with IBundledUpdatab
if (side == ForgeDirection.UNKNOWN) { if (side == ForgeDirection.UNKNOWN) {
if (Loader.isModLoaded("MineFactoryReloaded")) { if (Loader.isModLoaded("MineFactoryReloaded")) {
for (side <- ForgeDirection.VALID_DIRECTIONS) { for (side <- ForgeDirection.VALID_DIRECTIONS) {
val (nx, ny, nz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ) val nx = x + side.offsetX
val ny = y + side.offsetY
val nz = z + side.offsetZ
Block.blocksList(world.getBlockId(nx, ny, nz)) match { Block.blocksList(world.getBlockId(nx, ny, nz)) match {
case block: IRedNetNetworkContainer => block.updateNetwork(world, x, y, z) case block: IRedNetNetworkContainer => block.updateNetwork(world, x, y, z)
case _ => case _ =>
@ -143,7 +145,9 @@ trait BundledRedstone extends Redstone with IBundledEmitter with IBundledUpdatab
} }
} }
else { else {
val (nx, ny, nz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ) val nx = x + side.offsetX
val ny = y + side.offsetY
val nz = z + side.offsetZ
if (Loader.isModLoaded("MineFactoryReloaded")) { if (Loader.isModLoaded("MineFactoryReloaded")) {
Block.blocksList(world.getBlockId(nx, ny, nz)) match { Block.blocksList(world.getBlockId(nx, ny, nz)) match {
case block: IRedNetNetworkContainer => block.updateNetwork(world, x, y, z) case block: IRedNetNetworkContainer => block.updateNetwork(world, x, y, z)
@ -157,7 +161,7 @@ trait BundledRedstone extends Redstone with IBundledEmitter with IBundledUpdatab
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Optional.Method(modid = "RedLogic") @Optional.Method(modid = "RedLogic")
def getBundledCableStrength(blockFace: Int, toDirection: Int): Array[Byte] = _bundledOutput(toLocal(ForgeDirection.getOrientation(toDirection)).ordinal()).map(value => (value max 0 min 255).toByte) def getBundledCableStrength(blockFace: Int, toDirection: Int): Array[Byte] = _bundledOutput(toLocal(ForgeDirection.getOrientation(toDirection)).ordinal()).map(value => math.min(math.max(value, 0), 255).toByte)
@Optional.Method(modid = "RedLogic") @Optional.Method(modid = "RedLogic")
def onBundledInputChanged() = checkRedstoneInputChanged() def onBundledInputChanged() = checkRedstoneInputChanged()

View File

@ -76,7 +76,7 @@ class Charger extends Environment with Redstone with Analyzable {
override protected def onRedstoneInputChanged(side: ForgeDirection) { override protected def onRedstoneInputChanged(side: ForgeDirection) {
super.onRedstoneInputChanged(side) super.onRedstoneInputChanged(side)
chargeSpeed = 0.0 max (ForgeDirection.VALID_DIRECTIONS.map(input).max min 15) / 15.0 chargeSpeed = math.max(0, math.min(ForgeDirection.VALID_DIRECTIONS.map(input).max, 15) / 15.0)
if (isServer) { if (isServer) {
ServerPacketSender.sendChargerState(this) ServerPacketSender.sendChargerState(this)
} }

View File

@ -18,7 +18,7 @@ abstract class Computer(isRemote: Boolean) extends Environment with ComponentInv
def node = if (isClient) null else computer.node def node = if (isClient) null else computer.node
override def isClient = computer == null override lazy val isClient = computer == null
private var _isRunning = false private var _isRunning = false

View File

@ -20,11 +20,14 @@ abstract class Environment extends net.minecraft.tileentity.TileEntity with Tile
def block = getBlockType def block = getBlockType
private var addedToNetwork = false
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def updateEntity() { override def updateEntity() {
super.updateEntity() super.updateEntity()
if (node != null && node.network == null) { if (!addedToNetwork) {
addedToNetwork = true
Network.joinOrCreateNetwork(this) Network.joinOrCreateNetwork(this)
} }
} }

View File

@ -15,7 +15,7 @@ class Keyboard(isRemote: Boolean) extends Environment with SidedEnvironment with
def node = if (isClient) null else keyboard.node def node = if (isClient) null else keyboard.node
override def isClient = keyboard == null override lazy val isClient = keyboard == null
def onAnalyze(stats: NBTTagCompound, player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = node def onAnalyze(stats: NBTTagCompound, player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = node

View File

@ -21,6 +21,10 @@ class PowerConverter extends Environment with Analyzable with IEnergySink with I
withConnector(). withConnector().
create() create()
private lazy val isIndustrialCraftAvailable = Loader.isModLoaded("IC2")
private lazy val isBuildCraftAvailable = Loader.isModLoaded("BuildCraft|Energy")
private def demand = if (Settings.get.ignorePower) 0.0 else node.globalBufferSize - node.globalBuffer private def demand = if (Settings.get.ignorePower) 0.0 else node.globalBufferSize - node.globalBuffer
def onAnalyze(stats: NBTTagCompound, player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = null def onAnalyze(stats: NBTTagCompound, player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = null
@ -30,16 +34,19 @@ class PowerConverter extends Environment with Analyzable with IEnergySink with I
override def updateEntity() { override def updateEntity() {
super.updateEntity() super.updateEntity()
if (isServer) { if (isServer) {
if (Loader.isModLoaded("IC2")) { if (isIndustrialCraftAvailable) {
loadIC2() loadIC2()
} }
if (demand > 0 && Loader.isModLoaded("BuildCraft|Energy")) { if (isBuildCraftAvailable && demand > 1 && world.getWorldInfo.getWorldTotalTime % Settings.get.tickFrequency == 0) {
val wantInMJ = demand.toFloat / Settings.get.ratioBuildCraft val wantInMJ = demand.toFloat / Settings.get.ratioBuildCraft
val gotInMJ = getPowerProvider.useEnergy(1, wantInMJ, true) val powerProvider = getPowerProvider
if (wantInMJ < powerProvider.getEnergyStored) {
val gotInMJ = powerProvider.useEnergy(1, wantInMJ, true)
node.changeBuffer(gotInMJ * Settings.get.ratioBuildCraft) node.changeBuffer(gotInMJ * Settings.get.ratioBuildCraft)
} }
} }
} }
}
override def onChunkUnload() { override def onChunkUnload() {
super.onChunkUnload() super.onChunkUnload()
@ -74,7 +81,7 @@ class PowerConverter extends Environment with Analyzable with IEnergySink with I
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
// IndustrialCraft // IndustrialCraft
private var isIC2Loaded = false private var addedToPowerGrid = false
private var lastPacketSize = 0.0 private var lastPacketSize = 0.0
@ -82,17 +89,17 @@ class PowerConverter extends Environment with Analyzable with IEnergySink with I
@Optional.Method(modid = "IC2") @Optional.Method(modid = "IC2")
def loadIC2() { def loadIC2() {
if (!isIC2Loaded) { if (!addedToPowerGrid) {
MinecraftForge.EVENT_BUS.post(new EnergyTileLoadEvent(this)) MinecraftForge.EVENT_BUS.post(new EnergyTileLoadEvent(this))
isIC2Loaded = true addedToPowerGrid = true
} }
} }
@Optional.Method(modid = "IC2") @Optional.Method(modid = "IC2")
def unloadIC2() { def unloadIC2() {
if (isIC2Loaded) { if (addedToPowerGrid) {
MinecraftForge.EVENT_BUS.post(new EnergyTileUnloadEvent(this)) MinecraftForge.EVENT_BUS.post(new EnergyTileUnloadEvent(this))
isIC2Loaded = false addedToPowerGrid = false
} }
} }

View File

@ -114,14 +114,14 @@ trait Redstone extends RotationAware with network.Environment with Persistable w
case emitter: IRedstoneEmitter => case emitter: IRedstoneEmitter =>
var strength = 0 var strength = 0
for (i <- -1 to 5) { for (i <- -1 to 5) {
strength = strength max emitter.getEmittedSignalStrength(i, side.getOpposite.ordinal()) strength = math.max(strength, emitter.getEmittedSignalStrength(i, side.getOpposite.ordinal()))
} }
strength strength
case _ => 0 case _ => 0
} }
} }
else 0 else 0
vanilla max redLogic math.max(vanilla, redLogic)
} }
protected def onRedstoneInputChanged(side: ForgeDirection) {} protected def onRedstoneInputChanged(side: ForgeDirection) {}
@ -131,7 +131,9 @@ trait Redstone extends RotationAware with network.Environment with Persistable w
world.notifyBlocksOfNeighborChange(x, y, z, block.blockID) world.notifyBlocksOfNeighborChange(x, y, z, block.blockID)
} }
else { else {
val (nx, ny, nz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ) val nx = x + side.offsetX
val ny = y + side.offsetY
val nz = z + side.offsetZ
world.notifyBlockOfNeighborChange(nx, ny, nz, block.blockID) world.notifyBlockOfNeighborChange(nx, ny, nz, block.blockID)
world.notifyBlocksOfNeighborChange(nx, ny, nz, world.getBlockId(nx, ny, nz)) world.notifyBlocksOfNeighborChange(nx, ny, nz, world.getBlockId(nx, ny, nz))
} }

View File

@ -97,7 +97,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
def updateXpInfo() { def updateXpInfo() {
// xp(level) = base + (level * const) ^ exp // xp(level) = base + (level * const) ^ exp
// pow(xp(level) - base, 1/exp) / const = level // pow(xp(level) - base, 1/exp) / const = level
level = (Math.pow(xp - Settings.get.baseXpToLevel, 1 / Settings.get.exponentialXpGrowth) / Settings.get.constantXpGrowth).toInt min 30 level = math.min((Math.pow(xp - Settings.get.baseXpToLevel, 1 / Settings.get.exponentialXpGrowth) / Settings.get.constantXpGrowth).toInt, 30)
if (battery != null) { if (battery != null) {
battery.setLocalBufferSize(Settings.get.bufferRobot + Settings.get.bufferPerLevel * level) battery.setLocalBufferSize(Settings.get.bufferRobot + Settings.get.bufferPerLevel * level)
} }
@ -140,7 +140,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
Blocks.robotAfterimage.setBlock(world, ox, oy, oz, 1) Blocks.robotAfterimage.setBlock(world, ox, oy, oz, 1)
assert(Delegator.subBlock(world, ox, oy, oz).exists(_ == Blocks.robotAfterimage)) assert(Delegator.subBlock(world, ox, oy, oz).exists(_ == Blocks.robotAfterimage))
// Here instead of Lua callback so that it gets called on client, too. // Here instead of Lua callback so that it gets called on client, too.
val moveTicks = (Settings.get.moveDelay * 20).toInt max 1 val moveTicks = math.max((Settings.get.moveDelay * 20).toInt, 1)
setAnimateMove(ox, oy, oz, moveTicks) setAnimateMove(ox, oy, oz, moveTicks)
if (isServer) { if (isServer) {
world.scheduleBlockUpdate(ox, oy, oz, Blocks.robotAfterimage.parent.blockID, moveTicks - 1) world.scheduleBlockUpdate(ox, oy, oz, Blocks.robotAfterimage.parent.blockID, moveTicks - 1)

View File

@ -100,9 +100,9 @@ class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedI
override def onInventoryChanged() = robot.onInventoryChanged() override def onInventoryChanged() = robot.onInventoryChanged()
override def isClient = robot.isClient override lazy val isClient = robot.isClient
override def isServer = robot.isServer override lazy val isServer = robot.isServer
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //

View File

@ -38,6 +38,8 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable
var hasPower = true var hasPower = true
var cachedBounds: Option[AxisAlignedBB] = None
def canConnect(side: ForgeDirection) = toLocal(side) != ForgeDirection.SOUTH def canConnect(side: ForgeDirection) = toLocal(side) != ForgeDirection.SOUTH
def sidedNode(side: ForgeDirection) = if (canConnect(side)) node else null def sidedNode(side: ForgeDirection) = if (canConnect(side)) node else null
@ -49,8 +51,7 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable
def localPosition = { def localPosition = {
val (lx, ly, _) = project(this) val (lx, ly, _) = project(this)
val (ox, oy, _) = project(origin) val (ox, oy, _) = project(origin)
val (px, py) = (lx - ox, ly - oy) (lx - ox, ly - oy)
(px, py)
} }
override def hasKeyboard = screens.exists(screen => ForgeDirection.VALID_DIRECTIONS. override def hasKeyboard = screens.exists(screen => ForgeDirection.VALID_DIRECTIONS.
@ -66,6 +67,7 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable
origin = this origin = this
screens.clear() screens.clear()
screens += this screens += this
cachedBounds = None
} }
def click(player: EntityPlayer, hitX: Float, hitY: Float, hitZ: Float): Boolean = { def click(player: EntityPlayer, hitX: Float, hitY: Float, hitZ: Float): Boolean = {
@ -119,12 +121,15 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable
override def updateEntity() { override def updateEntity() {
super.updateEntity() super.updateEntity()
if (isServer) { if (isServer && world.getWorldInfo.getWorldTotalTime % Settings.get.tickFrequency == 0) {
if (litPixels < 0) { if (litPixels < 0) {
litPixels = buffer.lines.foldLeft(0)((acc, line) => acc + line.count(_ != ' ')) litPixels = 0
for (line <- buffer.lines) for (c <- line) {
if (c != ' ') litPixels += 1
}
} }
val hadPower = hasPower val hadPower = hasPower
val neededPower = Settings.get.screenCost + pixelCost * litPixels val neededPower = (Settings.get.screenCost + pixelCost * litPixels) * Settings.get.tickFrequency
hasPower = buffer.node.tryChangeBuffer(-neededPower) hasPower = buffer.node.tryChangeBuffer(-neededPower)
if (hasPower != hadPower) { if (hasPower != hadPower) {
ServerPacketSender.sendScreenPowerChange(this, hasPower) ServerPacketSender.sendScreenPowerChange(this, hasPower)
@ -213,14 +218,17 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
override def getRenderBoundingBox = override def getRenderBoundingBox =
if ((width == 1 && height == 1) || !isOrigin) super.getRenderBoundingBox if ((width == 1 && height == 1) || !isOrigin) super.getRenderBoundingBox
else { else cachedBounds match {
case Some(bounds) => bounds
case _ =>
val (sx, sy, sz) = unproject(width, height, 1) val (sx, sy, sz) = unproject(width, height, 1)
val ox = x + (if (sx < 0) 1 else 0) val ox = x + (if (sx < 0) 1 else 0)
val oy = y + (if (sy < 0) 1 else 0) val oy = y + (if (sy < 0) 1 else 0)
val oz = z + (if (sz < 0) 1 else 0) val oz = z + (if (sz < 0) 1 else 0)
val b = AxisAlignedBB.getAABBPool.getAABB(ox, oy, oz, ox + sx, oy + sy, oz + sz) val b = AxisAlignedBB.getBoundingBox(ox, oy, oz, ox + sx, oy + sy, oz + sz)
b.setBounds(b.minX min b.maxX, b.minY min b.maxY, b.minZ min b.maxZ, b.setBounds(math.min(b.minX, b.maxX), math.min(b.minY, b.maxY), math.min(b.minZ, b.maxZ),
b.minX max b.maxX, b.minY max b.maxY, b.minZ max b.maxZ) math.max(b.minX, b.maxX), math.max(b.minY, b.maxY), math.max(b.minZ, b.maxZ))
cachedBounds = Some(b)
b b
} }
@ -297,6 +305,7 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable
screen.height = newHeight screen.height = newHeight
screen.origin = newOrigin screen.origin = newOrigin
screen.screens ++= newScreens // It's a set, so there won't be duplicates. screen.screens ++= newScreens // It's a set, so there won't be duplicates.
screen.cachedBounds = None
} }
true true
} }

View File

@ -16,9 +16,9 @@ trait TileEntity {
def block: Block def block: Block
def isClient = world.isRemote lazy val isClient = world.isRemote
def isServer = !isClient lazy val isServer = !isClient
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
def readFromNBTForClient(nbt: NBTTagCompound) {} def readFromNBTForClient(nbt: NBTTagCompound) {}

View File

@ -120,7 +120,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con
}) })
def pause(seconds: Double): Boolean = { def pause(seconds: Double): Boolean = {
val ticksToPause = (seconds * 20).toInt max 0 val ticksToPause = math.max((seconds * 20).toInt, 0)
def shouldPause(state: Computer.State.Value) = state match { def shouldPause(state: Computer.State.Value) = state match {
case Computer.State.Stopping | Computer.State.Stopped => false case Computer.State.Stopping | Computer.State.Stopped => false
case Computer.State.Paused if ticksToPause <= remainingPause => false case Computer.State.Paused if ticksToPause <= remainingPause => false
@ -215,13 +215,14 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con
worldTime = owner.world.getWorldTime worldTime = owner.world.getWorldTime
// We can have rollbacks from '/time set'. Avoid getting negative uptimes. // We can have rollbacks from '/time set'. Avoid getting negative uptimes.
timeStarted = timeStarted min worldTime timeStarted = math.min(timeStarted, worldTime)
// Reset direct call limits. // Reset direct call limits.
callCounts.synchronized(callCounts.clear()) callCounts.synchronized(if (callCounts.size > 0) callCounts.clear())
// Make sure we have enough power. // Make sure we have enough power.
val cost = if (isRobot) Settings.get.robotCost else Settings.get.computerCost if (owner.world.getWorldInfo.getWorldTotalTime % Settings.get.tickFrequency == 0) {
val cost = (if (isRobot) Settings.get.robotCost else Settings.get.computerCost) * Settings.get.tickFrequency
state.synchronized(state.top match { state.synchronized(state.top match {
case Computer.State.Paused | case Computer.State.Paused |
Computer.State.Restarting | Computer.State.Restarting |
@ -236,6 +237,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con
crash("not enough energy") crash("not enough energy")
} }
}) })
}
// Avoid spamming user list across the network. // Avoid spamming user list across the network.
if (worldTime % 20 == 0 && usersChanged) { if (worldTime % 20 == 0 && usersChanged) {
@ -396,6 +398,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con
} }
private def processAddedComponents() { private def processAddedComponents() {
if (addedComponents.size > 0) {
for (component <- addedComponents) { for (component <- addedComponents) {
if (component.canBeSeenFrom(node)) { if (component.canBeSeenFrom(node)) {
components.synchronized(components += component.address -> component.name) components.synchronized(components += component.address -> component.name)
@ -408,6 +411,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con
} }
addedComponents.clear() addedComponents.clear()
} }
}
private def verifyComponents() { private def verifyComponents() {
val invalid = mutable.Set.empty[String] val invalid = mutable.Set.empty[String]
@ -1214,7 +1218,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con
// memory, regardless of the memory need of the underlying system // memory, regardless of the memory need of the underlying system
// (which may change across releases). // (which may change across releases).
lua.gc(LuaState.GcAction.COLLECT, 0) lua.gc(LuaState.GcAction.COLLECT, 0)
kernelMemory = lua.getTotalMemory - lua.getFreeMemory max 1 kernelMemory = math.max(lua.getTotalMemory - lua.getFreeMemory, 1)
recomputeMemory() recomputeMemory()
// Fake zero sleep to avoid stopping if there are no signals. // Fake zero sleep to avoid stopping if there are no signals.

View File

@ -33,8 +33,8 @@ class Crafting(val owner: MCTileEntity) extends ManagedComponent {
val manager = CraftingManager.getInstance val manager = CraftingManager.getInstance
val result = manager.findMatchingRecipe(CraftingInventory, owner.getWorldObj) val result = manager.findMatchingRecipe(CraftingInventory, owner.getWorldObj)
if (result == null) return false if (result == null) return false
val targetStackSize = if (result.isStackable) wantedCount min result.getMaxStackSize else result.stackSize val targetStackSize = if (result.isStackable) math.min(wantedCount, result.getMaxStackSize) else result.stackSize
val timesCrafted = (targetStackSize / result.stackSize) min amountPossible val timesCrafted = math.min(targetStackSize / result.stackSize, amountPossible)
if (timesCrafted <= 0) return true if (timesCrafted <= 0) return true
GameRegistry.onItemCrafted(context.player, result, this) GameRegistry.onItemCrafted(context.player, result, this)
val surplus = mutable.ArrayBuffer.empty[ItemStack] val surplus = mutable.ArrayBuffer.empty[ItemStack]
@ -75,7 +75,7 @@ class Crafting(val owner: MCTileEntity) extends ManagedComponent {
val stack = inventory.getStackInSlot(toParentSlot(slot)) val stack = inventory.getStackInSlot(toParentSlot(slot))
setInventorySlotContents(slot, stack) setInventorySlotContents(slot, stack)
if (stack != null) { if (stack != null) {
amountPossible = amountPossible min stack.stackSize amountPossible = math.min(amountPossible, stack.stackSize)
} }
} }
} }

View File

@ -133,7 +133,7 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma
Option(fileSystem.getHandle(handle)) match { Option(fileSystem.getHandle(handle)) match {
case Some(file) => case Some(file) =>
// Limit size of read buffer to avoid crazy allocations. // Limit size of read buffer to avoid crazy allocations.
val buffer = new Array[Byte](n min Settings.get.maxReadBuffer) val buffer = new Array[Byte](math.min(n, Settings.get.maxReadBuffer))
val read = file.read(buffer) val read = file.read(buffer)
if (read >= 0) { if (read >= 0) {
val bytes = val bytes =

View File

@ -38,11 +38,11 @@ class Generator(val owner: MCTileEntity) extends ManagedComponent {
if (space <= 0) { if (space <= 0) {
return result(false, "queue is full") return result(false, "queue is full")
} }
val moveCount = stack.stackSize min space min count val moveCount = math.min(stack.stackSize, math.min(space, count))
existingStack.stackSize += moveCount existingStack.stackSize += moveCount
stack.stackSize -= moveCount stack.stackSize -= moveCount
case _ => case _ =>
inventory = Some(stack.splitStack(stack.stackSize min count)) inventory = Some(stack.splitStack(math.min(stack.stackSize, count)))
} }
player.inventory.setInventorySlotContents(context.selectedSlot, stack) player.inventory.setInventorySlotContents(context.selectedSlot, stack)
result(true) result(true)
@ -61,7 +61,7 @@ class Generator(val owner: MCTileEntity) extends ManagedComponent {
val count = if (args.count > 0) args.checkInteger(0) else Int.MaxValue val count = if (args.count > 0) args.checkInteger(0) else Int.MaxValue
inventory match { inventory match {
case Some(stack) => case Some(stack) =>
val removedStack = stack.splitStack(count min stack.stackSize) val removedStack = stack.splitStack(math.min(count, stack.stackSize))
val success = context.player.inventory.addItemStackToInventory(removedStack) val success = context.player.inventory.addItemStackToInventory(removedStack)
stack.stackSize += removedStack.stackSize stack.stackSize += removedStack.stackSize
if (success && stack.stackSize <= 0) { if (success && stack.stackSize <= 0) {

View File

@ -56,8 +56,8 @@ abstract class GraphicsCard extends ManagedComponent {
screen(s => { screen(s => {
val (gmw, gmh) = maxResolution val (gmw, gmh) = maxResolution
val (smw, smh) = s.maxResolution val (smw, smh) = s.maxResolution
s.resolution = (gmw min smw, gmh min smh) s.resolution = (math.min(gmw, smw), math.min(gmh, smh))
s.depth = PackedColor.Depth(maxDepth.id min s.maxDepth.id) s.depth = PackedColor.Depth(math.min(maxDepth.id, s.maxDepth.id))
s.foreground = 0xFFFFFF s.foreground = 0xFFFFFF
s.background = 0x000000 s.background = 0x000000
result(true) result(true)
@ -101,7 +101,7 @@ abstract class GraphicsCard extends ManagedComponent {
@LuaCallback(value = "maxDepth", direct = true) @LuaCallback(value = "maxDepth", direct = true)
def maxDepth(context: Context, args: Arguments): Array[AnyRef] = def maxDepth(context: Context, args: Arguments): Array[AnyRef] =
screen(s => result(PackedColor.Depth(maxDepth.id min s.maxDepth.id) match { screen(s => result(PackedColor.Depth(math.min(maxDepth.id, s.maxDepth.id)) match {
case PackedColor.Depth.OneBit => 1 case PackedColor.Depth.OneBit => 1
case PackedColor.Depth.FourBit => 4 case PackedColor.Depth.FourBit => 4
case PackedColor.Depth.EightBit => 8 case PackedColor.Depth.EightBit => 8
@ -128,7 +128,7 @@ abstract class GraphicsCard extends ManagedComponent {
screen(s => { screen(s => {
val (gmw, gmh) = maxResolution val (gmw, gmh) = maxResolution
val (smw, smh) = s.maxResolution val (smw, smh) = s.maxResolution
result(gmw min smw, gmh min smh) result(math.min(gmw, smw), math.min(gmh, smh))
}) })
@LuaCallback(value = "get", direct = true) @LuaCallback(value = "get", direct = true)

View File

@ -18,13 +18,13 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
var globalBufferSize = 0.0 var globalBufferSize = 0.0
var dirty = true
private var lastSentRatio = 0.0 private var lastSentRatio = 0.0
private val buffers = mutable.Set.empty[Connector] private val buffers = mutable.ArrayBuffer.empty[Connector]
private val distributors = mutable.Set.empty[PowerDistributor] private val distributors = mutable.ArrayBuffer.empty[PowerDistributor]
private var dirty = true
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -37,36 +37,29 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
def changeBuffer(delta: Double): Double = { def changeBuffer(delta: Double): Double = {
if (delta == 0) { if (delta == 0) 0
return 0 else if (Settings.get.ignorePower) {
if (delta < 0) 0
else /* if (delta > 0) */ delta
} }
if (Settings.get.ignorePower) { else this.synchronized {
if (delta < 0) {
return 0
}
else /* if (delta > 0) */ {
return delta
}
}
this.synchronized {
val oldBuffer = globalBuffer val oldBuffer = globalBuffer
globalBuffer = (globalBuffer + delta) max 0 min globalBufferSize globalBuffer = math.min(math.max(globalBuffer + delta, 0), globalBufferSize)
if (globalBuffer == oldBuffer) { if (globalBuffer == oldBuffer) {
return delta return delta
} }
dirty = true dirty = true
if (delta < 0) { if (delta < 0) {
var remaining = -delta var remaining = -delta
for (connector <- buffers) { for (connector <- buffers if remaining > 0 && connector.localBufferSize > 0) {
if (connector.localBuffer > 0) { if (connector.localBuffer > 0) {
connector.dirty = true
if (connector.localBuffer < remaining) { if (connector.localBuffer < remaining) {
remaining -= connector.localBuffer remaining -= connector.localBuffer
connector.localBuffer = 0 connector.localBuffer = 0
} }
else { else {
connector.localBuffer -= remaining connector.localBuffer -= remaining
return 0 remaining = 0
} }
} }
} }
@ -74,9 +67,8 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
} }
else /* if (delta > 0) */ { else /* if (delta > 0) */ {
var remaining = delta var remaining = delta
for (connector <- buffers) { for (connector <- buffers if remaining > 0 && connector.localBufferSize > 0) {
if (connector.localBuffer < connector.localBufferSize) { if (connector.localBuffer < connector.localBufferSize) {
connector.dirty = true
val space = connector.localBufferSize - connector.localBuffer val space = connector.localBufferSize - connector.localBuffer
if (space < remaining) { if (space < remaining) {
remaining -= space remaining -= space
@ -84,7 +76,7 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
} }
else { else {
connector.localBuffer += remaining connector.localBuffer += remaining
return 0 remaining = 0
} }
} }
} }
@ -96,7 +88,7 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def update() { override def update() {
if (node != null && (dirty || buffers.exists(_.dirty))) { if (dirty && owner.world.getWorldInfo.getWorldTotalTime % Settings.get.tickFrequency == 0 && node != null) {
updateCachedValues() updateCachedValues()
} }
} }
@ -108,21 +100,25 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
if (node == this.node) { if (node == this.node) {
for (node <- node.reachableNodes) node match { for (node <- node.reachableNodes) node match {
case connector: Connector if connector.localBufferSize > 0 => this.synchronized { case connector: Connector if connector.localBufferSize > 0 => this.synchronized {
assert(!buffers.contains(connector))
buffers += connector buffers += connector
globalBuffer += connector.localBuffer globalBuffer += connector.localBuffer
globalBufferSize += connector.localBufferSize globalBufferSize += connector.localBufferSize
} }
case _ => node.host match { case _ => node.host match {
case distributor: PowerDistributor if distributor.node.canBeSeenFrom(this.node) => case distributor: PowerDistributor if distributor.node.canBeSeenFrom(this.node) =>
assert(!distributors.contains(distributor))
distributors += distributor distributors += distributor
case _ => case _ =>
} }
} }
assert(!distributors.contains(this))
distributors += this distributors += this
dirty = true dirty = true
} }
else node match { else node match {
case connector: Connector if connector.localBufferSize > 0 => this.synchronized { case connector: Connector if connector.localBufferSize > 0 => this.synchronized {
assert(!buffers.contains(connector))
buffers += connector buffers += connector
globalBuffer += connector.localBuffer globalBuffer += connector.localBuffer
globalBufferSize += connector.localBufferSize globalBufferSize += connector.localBufferSize
@ -130,6 +126,7 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
} }
case _ => node.host match { case _ => node.host match {
case distributor: PowerDistributor if distributor.node.canBeSeenFrom(this.node) => case distributor: PowerDistributor if distributor.node.canBeSeenFrom(this.node) =>
assert(!distributors.contains(distributor))
distributors += distributor distributors += distributor
case _ => case _ =>
} }
@ -162,16 +159,16 @@ class PowerDistributor(val owner: PowerInformation) extends ManagedComponent {
def updateCachedValues() { def updateCachedValues() {
// Computer average fill ratio of all buffers. // Computer average fill ratio of all buffers.
val (sumBuffer, sumBufferSize) = var sumBuffer, sumBufferSize = 0.0
buffers.foldRight((0.0, 0.0))((c, acc) => { for (buffer <- buffers) {
c.dirty = false // clear dirty flag for all connectors sumBuffer += buffer.localBuffer
(acc._1 + c.localBuffer, acc._2 + c.localBufferSize) sumBufferSize += buffer.localBufferSize
}) }
// Only send updates if the state changed by more than 5%, more won't be // Only send updates if the state changed by more than 5%, more won't be
// noticeable "from the outside" anyway. We send more frequent updates in // noticeable "from the outside" anyway. We send more frequent updates in
// the gui/container of a block that needs it (like robots). // the gui/container of a block that needs it (like robots).
val fillRatio = sumBuffer / sumBufferSize val fillRatio = sumBuffer / sumBufferSize
val shouldSend = (lastSentRatio - fillRatio).abs > (5.0 / 100.0) val shouldSend = math.abs(lastSentRatio - fillRatio) > (5.0 / 100.0)
for (distributor <- distributors) distributor.synchronized { for (distributor <- distributors) distributor.synchronized {
distributor.dirty = false distributor.dirty = false
distributor.globalBuffer = sumBuffer distributor.globalBuffer = sumBuffer

View File

@ -73,7 +73,7 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte
if (args.count > 0 && args.checkAny(0) != null) checkSlot(args, 0) if (args.count > 0 && args.checkAny(0) != null) checkSlot(args, 0)
else selectedSlot else selectedSlot
result(stackInSlot(slot) match { result(stackInSlot(slot) match {
case Some(stack) => (robot.getInventoryStackLimit min stack.getMaxStackSize) - stack.stackSize case Some(stack) => math.min(robot.getInventoryStackLimit, stack.getMaxStackSize) - stack.stackSize
case _ => robot.getInventoryStackLimit case _ => robot.getInventoryStackLimit
}) })
} }
@ -98,8 +98,8 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte
else result((stackInSlot(selectedSlot), stackInSlot(slot)) match { else result((stackInSlot(selectedSlot), stackInSlot(slot)) match {
case (Some(from), Some(to)) => case (Some(from), Some(to)) =>
if (haveSameItemType(from, to)) { if (haveSameItemType(from, to)) {
val space = (robot.getInventoryStackLimit min to.getMaxStackSize) - to.stackSize val space = math.min(robot.getInventoryStackLimit, to.getMaxStackSize) - to.stackSize
val amount = count min space min from.stackSize val amount = math.min(count, math.min(space, from.stackSize))
if (amount > 0) { if (amount > 0) {
from.stackSize -= amount from.stackSize -= amount
to.stackSize += amount to.stackSize += amount
@ -148,7 +148,7 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte
if (dropped != null && dropped.stackSize > 0) { if (dropped != null && dropped.stackSize > 0) {
def tryDropIntoInventory(inventory: IInventory, filter: (Int) => Boolean) = { def tryDropIntoInventory(inventory: IInventory, filter: (Int) => Boolean) = {
var success = false var success = false
val maxStackSize = inventory.getInventoryStackLimit min dropped.getMaxStackSize val maxStackSize = math.min(inventory.getInventoryStackLimit, dropped.getMaxStackSize)
val shouldTryMerge = !dropped.isItemStackDamageable && dropped.getMaxStackSize > 1 && inventory.getInventoryStackLimit > 1 val shouldTryMerge = !dropped.isItemStackDamageable && dropped.getMaxStackSize > 1 && inventory.getInventoryStackLimit > 1
if (shouldTryMerge) { if (shouldTryMerge) {
for (slot <- 0 until inventory.getSizeInventory if dropped.stackSize > 0 && filter(slot)) { for (slot <- 0 until inventory.getSizeInventory if dropped.stackSize > 0 && filter(slot)) {
@ -157,7 +157,7 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte
existing.isItemEqual(dropped) && ItemStack.areItemStackTagsEqual(existing, dropped) existing.isItemEqual(dropped) && ItemStack.areItemStackTagsEqual(existing, dropped)
if (shouldMerge) { if (shouldMerge) {
val space = maxStackSize - existing.stackSize val space = maxStackSize - existing.stackSize
val amount = space min dropped.stackSize val amount = math.min(space, dropped.stackSize)
assert(amount > 0) assert(amount > 0)
success = true success = true
existing.stackSize += amount existing.stackSize += amount
@ -168,7 +168,7 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte
def canDropIntoSlot(slot: Int) = filter(slot) && inventory.isItemValidForSlot(slot, dropped) && inventory.getStackInSlot(slot) == null def canDropIntoSlot(slot: Int) = filter(slot) && inventory.isItemValidForSlot(slot, dropped) && inventory.getStackInSlot(slot) == null
for (slot <- 0 until inventory.getSizeInventory if dropped.stackSize > 0 && canDropIntoSlot(slot)) { for (slot <- 0 until inventory.getSizeInventory if dropped.stackSize > 0 && canDropIntoSlot(slot)) {
val amount = maxStackSize min dropped.stackSize val amount = math.min(maxStackSize, dropped.stackSize)
inventory.setInventorySlotContents(slot, dropped.splitStack(amount)) inventory.setInventorySlotContents(slot, dropped.splitStack(amount))
success = true success = true
} }
@ -256,8 +256,8 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte
for (slot <- 0 until inventory.getSizeInventory if !success && filter(slot)) { for (slot <- 0 until inventory.getSizeInventory if !success && filter(slot)) {
val stack = inventory.getStackInSlot(slot) val stack = inventory.getStackInSlot(slot)
if (stack != null) { if (stack != null) {
val maxStackSize = robot.getInventoryStackLimit min stack.getMaxStackSize val maxStackSize = math.min(robot.getInventoryStackLimit, stack.getMaxStackSize)
val amount = maxStackSize min stack.stackSize min count val amount = math.min(maxStackSize, math.min(stack.stackSize, count))
val sucked = stack.splitStack(amount) val sucked = stack.splitStack(amount)
success = player.inventory.addItemStackToInventory(sucked) success = player.inventory.addItemStackToInventory(sucked)
stack.stackSize += sucked.stackSize stack.stackSize += sucked.stackSize
@ -600,7 +600,7 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte
private def checkOptionalItemCount(args: Arguments, n: Int) = private def checkOptionalItemCount(args: Arguments, n: Int) =
if (args.count > n && args.checkAny(n) != null) { if (args.count > n && args.checkAny(n) != null) {
args.checkInteger(n) max 0 min robot.getInventoryStackLimit math.max(args.checkInteger(n), math.min(0, robot.getInventoryStackLimit))
} }
else robot.getInventoryStackLimit else robot.getInventoryStackLimit

View File

@ -30,7 +30,7 @@ class WirelessNetworkCard(val owner: TileEntity) extends NetworkCard {
@LuaCallback("setStrength") @LuaCallback("setStrength")
def setStrength(context: Context, args: Arguments): Array[AnyRef] = { def setStrength(context: Context, args: Arguments): Array[AnyRef] = {
strength = args.checkDouble(0) max 0 min Settings.get.maxWirelessRange strength = math.max(args.checkDouble(0), math.min(0, Settings.get.maxWirelessRange))
result(strength) result(strength)
} }

View File

@ -80,17 +80,17 @@ class Inventory(player: Player) extends InventoryPlayer(player) {
val existing = getStackInSlot(slot) val existing = getStackInSlot(slot)
existing != null && existing.isItemEqual(stack) && existing != null && existing.isItemEqual(stack) &&
(!existing.getHasSubtypes || existing.getItemDamage == stack.getItemDamage) && (!existing.getHasSubtypes || existing.getItemDamage == stack.getItemDamage) &&
(existing.stackSize < (existing.getMaxStackSize min getInventoryStackLimit)) (existing.stackSize < math.min(existing.getMaxStackSize, getInventoryStackLimit))
}).getOrElse(getFirstEmptyStackAccepting(stack)) }).getOrElse(getFirstEmptyStackAccepting(stack))
if (slot >= firstInventorySlot) { if (slot >= firstInventorySlot) {
if (getStackInSlot(slot) == null) { if (getStackInSlot(slot) == null) {
val amount = stack.stackSize min (getInventoryStackLimit min stack.getMaxStackSize) val amount = math.min(stack.stackSize, math.min(getInventoryStackLimit, stack.getMaxStackSize))
setInventorySlotContents(slot, stack.splitStack(amount)) setInventorySlotContents(slot, stack.splitStack(amount))
} }
else { else {
val existing = getStackInSlot(slot) val existing = getStackInSlot(slot)
val space = (getInventoryStackLimit min existing.getMaxStackSize) - existing.stackSize val space = math.min(getInventoryStackLimit, existing.getMaxStackSize) - existing.stackSize
val amount = stack.stackSize min space val amount = math.min(stack.stackSize, space)
existing.stackSize += amount existing.stackSize += amount
stack.stackSize -= amount stack.stackSize -= amount
} }

View File

@ -153,7 +153,7 @@ class Player(val robot: Robot) extends EntityPlayer(robot.world, Settings.get.na
(!PortalGun.isPortalGun(stack) || PortalGun.isStandardPortalGun(stack)) && { (!PortalGun.isPortalGun(stack) || PortalGun.isStandardPortalGun(stack)) && {
val oldSize = stack.stackSize val oldSize = stack.stackSize
val oldDamage = if (stack != null) stack.getItemDamage else 0 val oldDamage = if (stack != null) stack.getItemDamage else 0
val heldTicks = 0 max stack.getMaxItemUseDuration min (duration * 20).toInt val heldTicks = math.max(0, math.min(stack.getMaxItemUseDuration, (duration * 20).toInt))
val newStack = stack.useItemRightClick(world, this) val newStack = stack.useItemRightClick(world, this)
if (isUsingItem) { if (isUsingItem) {
getItemInUse.onPlayerStoppedUsing(world, this, getItemInUse.getMaxItemUseDuration - heldTicks) getItemInUse.onPlayerStoppedUsing(world, this, getItemInUse.getMaxItemUseDuration - heldTicks)
@ -270,7 +270,7 @@ class Player(val robot: Robot) extends EntityPlayer(robot.world, Settings.get.na
if (stack != null) { if (stack != null) {
robot.addXp(Settings.get.robotActionXp) robot.addXp(Settings.get.robotActionXp)
} }
return (breakTime * Settings.get.harvestRatio * ((1 - robot.level * Settings.get.harvestSpeedBoostPerLevel) max 0)) max 0.05 return math.max(breakTime * Settings.get.harvestRatio * math.max(1 - robot.level * Settings.get.harvestSpeedBoostPerLevel, 0), 0.05)
} }
0 0
} }
@ -280,13 +280,13 @@ class Player(val robot: Robot) extends EntityPlayer(robot.world, Settings.get.na
private def tryRepair(stack: ItemStack, oldDamage: Int) { private def tryRepair(stack: ItemStack, oldDamage: Int) {
val needsRepairing = stack.isItemStackDamageable && stack.getItemDamage > oldDamage val needsRepairing = stack.isItemStackDamageable && stack.getItemDamage > oldDamage
val damageRate = Settings.get.itemDamageRate * ((1 - robot.level * Settings.get.toolEfficiencyPerLevel) max 0) val damageRate = Settings.get.itemDamageRate * math.max(1 - robot.level * Settings.get.toolEfficiencyPerLevel, 0)
val shouldRepair = needsRepairing && getRNG.nextDouble() >= damageRate val shouldRepair = needsRepairing && getRNG.nextDouble() >= damageRate
if (shouldRepair) { if (shouldRepair) {
// If an item takes a lot of damage at once we don't necessarily want to // If an item takes a lot of damage at once we don't necessarily want to
// make *all* of that damage go away. Instead we scale it according to // make *all* of that damage go away. Instead we scale it according to
// our damage probability. This makes sure we don't discard massive // our damage probability. This makes sure we don't discard massive
// damage spikes (e.g. on axes when using the treecapitator mod or such). // damage spikes (e.g. on axes when using the TreeCapitator mod or such).
val addedDamage = ((stack.getItemDamage - oldDamage) * damageRate).toInt val addedDamage = ((stack.getItemDamage - oldDamage) * damageRate).toInt
stack.setItemDamage(oldDamage + addedDamage) stack.setItemDamage(oldDamage + addedDamage)
} }

View File

@ -277,7 +277,7 @@ trait VirtualFileSystem extends OutputStreamFileSystem {
override def available() = override def available() =
if (isClosed) 0 if (isClosed) 0
else (file.data.length - position) max 0 else math.max(file.data.length - position, 0)
override def close() = isClosed = true override def close() = isClosed = true
@ -293,9 +293,10 @@ trait VirtualFileSystem extends OutputStreamFileSystem {
override def read(b: Array[Byte], off: Int, len: Int) = override def read(b: Array[Byte], off: Int, len: Int) =
if (!isClosed) { if (!isClosed) {
if (available == 0) -1 val count = available()
if (count == 0) -1
else { else {
val n = len min available val n = math.min(len, count)
file.data.view(position, file.data.length).copyToArray(b, off, n) file.data.view(position, file.data.length).copyToArray(b, off, n)
position += n position += n
n n
@ -311,7 +312,7 @@ trait VirtualFileSystem extends OutputStreamFileSystem {
override def skip(n: Long) = override def skip(n: Long) =
if (!isClosed) { if (!isClosed) {
position = ((position + n) min Int.MaxValue).toInt position = math.min((position + n).toInt, Int.MaxValue)
position position
} }
else throw new io.IOException("file is closed") else throw new io.IOException("file is closed")

View File

@ -85,7 +85,7 @@ object ZipFileInputStreamFileSystem {
var root: ArchiveDirectory = null var root: ArchiveDirectory = null
for (entry <- directories ++ files) { for (entry <- directories ++ files) {
if (entry.path.length > 0) { if (entry.path.length > 0) {
val parent = entry.path.substring(0, entry.path.lastIndexOf('/') max 0) val parent = entry.path.substring(0, math.max(entry.path.lastIndexOf('/'), 0))
directories.find(d => d.path == parent) match { directories.find(d => d.path == parent) match {
case Some(directory) => directory.children += entry case Some(directory) => directory.children += entry
case _ => case _ =>

View File

@ -13,8 +13,6 @@ trait Connector extends Node with network.Connector with Persistable {
var localBuffer = 0.0 var localBuffer = 0.0
var dirty = true
private var distributor: Option[PowerDistributor] = None private var distributor: Option[PowerDistributor] = None
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -26,18 +24,21 @@ trait Connector extends Node with network.Connector with Persistable {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
def changeBuffer(delta: Double): Double = { def changeBuffer(delta: Double): Double = {
if (delta == 0) { if (delta == 0) 0
return 0 else if (Settings.get.ignorePower) {
if (delta < 0) 0
else /* if (delta > 0) */ delta
} }
if (Settings.get.ignorePower) { else {
if (delta < 0) { this.synchronized(distributor match {
return 0 case Some(d) => d.synchronized(d.changeBuffer(change(delta)))
} case _ => change(delta)
else /* if (delta > 0) */ { })
return delta
} }
} }
def change() = {
private def change(delta: Double): Double = {
if (localBufferSize <= 0) return delta
val oldBuffer = localBuffer val oldBuffer = localBuffer
localBuffer += delta localBuffer += delta
val remaining = if (localBuffer < 0) { val remaining = if (localBuffer < 0) {
@ -51,27 +52,19 @@ trait Connector extends Node with network.Connector with Persistable {
remaining remaining
} }
else 0 else 0
dirty ||= (localBuffer != oldBuffer) if (localBuffer != oldBuffer) {
remaining
}
this.synchronized(distributor match { this.synchronized(distributor match {
case Some(d) => d.synchronized(d.changeBuffer(change())) case Some(d) => d.dirty = true
case _ => change() case _ =>
}) })
} }
remaining
}
def tryChangeBuffer(delta: Double): Boolean = { def tryChangeBuffer(delta: Double): Boolean = {
if (delta == 0) { if (delta == 0) true
return true else if (Settings.get.ignorePower) delta < 0
} else {
if (Settings.get.ignorePower) {
if (delta < 0) {
return true
}
else /* if (delta > 0) */ {
return false
}
}
this.synchronized(distributor match { this.synchronized(distributor match {
case Some(d) => d.synchronized { case Some(d) => d.synchronized {
val newGlobalBuffer = globalBuffer + delta val newGlobalBuffer = globalBuffer + delta
@ -88,18 +81,19 @@ trait Connector extends Node with network.Connector with Persistable {
} }
}) })
} }
}
def setLocalBufferSize(size: Double) { def setLocalBufferSize(size: Double) {
this.synchronized(distributor match { this.synchronized(distributor match {
case Some(d) => d.synchronized { case Some(d) => d.synchronized {
localBufferSize = size max 0 localBufferSize = math.max(size, 0)
val surplus = (localBuffer - localBufferSize) max 0 val surplus = math.max(localBuffer - localBufferSize, 0)
localBuffer = localBuffer min localBufferSize localBuffer = math.min(localBuffer, localBufferSize)
d.changeBuffer(surplus) d.changeBuffer(surplus)
} }
case _ => case _ =>
localBufferSize = size max 0 localBufferSize = math.max(size, 0)
localBuffer = localBuffer min localBufferSize localBuffer = math.min(localBuffer, localBufferSize)
}) })
} }
@ -137,8 +131,7 @@ trait Connector extends Node with network.Connector with Persistable {
override def load(nbt: NBTTagCompound) { override def load(nbt: NBTTagCompound) {
super.load(nbt) super.load(nbt)
localBuffer = nbt.getDouble("buffer") max 0 min localBufferSize localBuffer = math.max(nbt.getDouble("buffer"), math.min(0, localBufferSize))
dirty = true
} }
override def save(nbt: NBTTagCompound) { override def save(nbt: NBTTagCompound) {

View File

@ -220,15 +220,15 @@ object LuaStateFactory {
state.pushScalaFunction(lua => { state.pushScalaFunction(lua => {
val string = lua.checkString(1) val string = lua.checkString(1)
val start = (lua.checkInteger(2) match { val start = math.max(0, lua.checkInteger(2) match {
case i if i < 0 => string.length + i case i if i < 0 => string.length + i
case i => i - 1 case i => i - 1
}) max 0 })
val end = val end =
if (lua.getTop > 2) (lua.checkInteger(3) match { if (lua.getTop > 2) math.min(string.length, lua.checkInteger(3) match {
case i if i < 0 => string.length + i + 1 case i if i < 0 => string.length + i + 1
case i => i case i => i
}) min string.length })
else string.length else string.length
if (end <= start) lua.pushString("") if (end <= start) lua.pushString("")
else lua.pushString(string.substring(start, end)) else lua.pushString(string.substring(start, end))

View File

@ -8,7 +8,7 @@ class RTree[Data](private val M: Int)(implicit val coordinate: Data => (Double,
// Used for quick checks whether values are in the tree, e.g. for updates. // Used for quick checks whether values are in the tree, e.g. for updates.
private val entries = mutable.Map.empty[Data, Leaf] private val entries = mutable.Map.empty[Data, Leaf]
private val m = (M / 2) max 1 private val m = math.max(M / 2, 1)
private var root = new NonLeaf() private var root = new NonLeaf()
@ -215,7 +215,7 @@ class RTree[Data](private val M: Int)(implicit val coordinate: Data => (Double,
val newVol2 = r2.volumeIncluding(value) val newVol2 = r2.volumeIncluding(value)
val growth1 = newVol1 - r1.volume val growth1 = newVol1 - r1.volume
val growth2 = newVol2 - r2.volume val growth2 = newVol2 - r2.volume
val d = (growth2 - growth1).abs val d = math.abs(growth2 - growth1)
if (d > best) { if (d > best) {
bestValue = Some(value) bestValue = Some(value)
r = if (growth1 < growth2 || (growth1 == growth2 && newVol1 < newVol2)) r1 else r2 r = if (growth1 < growth2 || (growth1 == growth2 && newVol1 < newVol2)) r1 else r2
@ -263,9 +263,9 @@ class RTree[Data](private val M: Int)(implicit val coordinate: Data => (Double,
private class Point(val x: Double, val y: Double, val z: Double) { private class Point(val x: Double, val y: Double, val z: Double) {
def this(p: (Double, Double, Double)) = this(p._1, p._2, p._3) def this(p: (Double, Double, Double)) = this(p._1, p._2, p._3)
def min(other: Point) = new Point(x min other.x, y min other.y, z min other.z) def min(other: Point) = new Point(math.min(x, other.x), math.min(y, other.y), math.min(z, other.z))
def max(other: Point) = new Point(x max other.x, y max other.y, z max other.z) def max(other: Point) = new Point(math.max(x, other.x), math.max(y, other.y), math.max(z, other.z))
def asTuple = (x, y, z) def asTuple = (x, y, z)
} }

View File

@ -71,13 +71,13 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept
*/ */
def size_=(value: (Int, Int)): Boolean = { def size_=(value: (Int, Int)): Boolean = {
val (iw, ih) = value val (iw, ih) = value
val (w, h) = (iw max 1, ih max 1) val (w, h) = (math.max(iw, 1), math.max(ih, 1))
if (width != w || height != h) { if (width != w || height != h) {
val newBuffer = Array.fill(h, w)(' ') val newBuffer = Array.fill(h, w)(' ')
val newColor = Array.fill(h, w)(packed) val newColor = Array.fill(h, w)(packed)
(0 until (h min height)).foreach(y => { (0 until math.min(h, height)).foreach(y => {
Array.copy(buffer(y), 0, newBuffer(y), 0, w min width) Array.copy(buffer(y), 0, newBuffer(y), 0, math.min(w, width))
Array.copy(color(y), 0, newColor(y), 0, w min width) Array.copy(color(y), 0, newColor(y), 0, math.min(w, width))
}) })
buffer = newBuffer buffer = newBuffer
color = newColor color = newColor
@ -98,7 +98,7 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept
var changed = false var changed = false
val line = buffer(row) val line = buffer(row)
val lineColor = color(row) val lineColor = color(row)
for (x <- col until ((col + s.length) min width)) if (x >= 0) { for (x <- col until math.min(col + s.length, width)) if (x >= 0) {
val c = s(x - col) val c = s(x - col)
changed = changed || (line(x) != c) || (lineColor(x) != packed) changed = changed || (line(x) != c) || (lineColor(x) != packed)
line(x) = c line(x) = c
@ -113,10 +113,10 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept
if (w <= 0 || h <= 0) return false if (w <= 0 || h <= 0) return false
if (col + w < 0 || row + h < 0 || col >= width || row >= height) return false if (col + w < 0 || row + h < 0 || col >= width || row >= height) return false
var changed = false var changed = false
for (y <- (row max 0) until ((row + h) min height)) { for (y <- math.max(row, 0) until math.min(row + h, height)) {
val line = buffer(y) val line = buffer(y)
val lineColor = color(y) val lineColor = color(y)
for (x <- (col max 0) until ((col + w) min width)) { for (x <- math.max(col, 0) until math.min(col + w, width)) {
changed = changed || (line(x) != c) || (lineColor(x) != packed) changed = changed || (line(x) != c) || (lineColor(x) != packed)
line(x) = c line(x) = c
lineColor(x) = packed lineColor(x) = packed
@ -133,11 +133,11 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept
// Loop over the target rectangle, starting from the directions away from // Loop over the target rectangle, starting from the directions away from
// the source rectangle and copy the data. This way we ensure we don't // the source rectangle and copy the data. This way we ensure we don't
// overwrite anything we still need to copy. // overwrite anything we still need to copy.
val (dx0, dx1) = ((col + tx + w - 1) max 0 min (width - 1), (col + tx) max 0 min width) match { val (dx0, dx1) = (math.max(col + tx + w - 1, math.min(0, width - 1)), math.max(col + tx, math.min(0, width))) match {
case dx if tx > 0 => dx case dx if tx > 0 => dx
case dx => dx.swap case dx => dx.swap
} }
val (dy0, dy1) = ((row + ty + h - 1) max 0 min (height - 1), (row + ty) max 0 min height) match { val (dy0, dy1) = (math.max(row + ty + h - 1, math.min(0, height - 1)), math.max(row + ty, math.min(0, height))) match {
case dy if ty > 0 => dy case dy if ty > 0 => dy
case dy => dy.swap case dy => dy.swap
} }
@ -170,7 +170,7 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept
size = (w, h) size = (w, h)
val b = nbt.getTagList("buffer") val b = nbt.getTagList("buffer")
for (i <- 0 until (h min b.tagCount)) { for (i <- 0 until math.min(h, b.tagCount)) {
val line = b.tagAt(i).asInstanceOf[NBTTagString].data val line = b.tagAt(i).asInstanceOf[NBTTagString].data
set(0, i, line) set(0, i, line)
} }

View File

@ -33,10 +33,9 @@ object WirelessNetwork {
case Some(tree) => case Some(tree) =>
tree(card) match { tree(card) match {
case Some((x, y, z)) => case Some((x, y, z)) =>
val (dx, dy, dz) = ( val dx = math.abs(card.owner.xCoord + 0.5 - x)
(card.owner.xCoord + 0.5 - x).abs, val dy = math.abs(card.owner.yCoord + 0.5 - y)
(card.owner.yCoord + 0.5 - y).abs, val dz = math.abs(card.owner.zCoord + 0.5 - z)
(card.owner.zCoord + 0.5 - z).abs)
if (dx > 0.5 || dy > 0.5 || dz > 0.5) { if (dx > 0.5 || dy > 0.5 || dz > 0.5) {
tree.remove(card) tree.remove(card)
tree.add(card) tree.add(card)