fixed redstone program always setting bundled output; now reading input from isolated red alloy wires (redlogic); general clean up; triggering persistable.save/load form environment class now (our base tile entity class);

This commit is contained in:
Florian Nücke 2013-11-15 14:28:17 +01:00
parent f5da4e6af3
commit 1b7eebfaf5
32 changed files with 246 additions and 218 deletions

View File

@ -28,7 +28,7 @@ if options.b then
if type(color) == "string" then
color = colors[color]
end
if #args > 1 then
if #args > 2 then
local value = args[3]
if tonumber(value) then
value = tonumber(value)

View File

@ -2,7 +2,7 @@ local colors = {
[0] = "white",
[1] = "orange",
[2] = "magenta",
[3] = "lightBlue",
[3] = "lightblue",
[4] = "yellow",
[5] = "lime",
[6] = "pink",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 636 B

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -16,6 +16,7 @@ object Blocks {
var keyboard: Keyboard = null
var powerDistributor: PowerDistributor = null
var powerSupply: PowerConverter = null
var robot: Robot = null
var screen1, screen2, screen3: Screen = null
def init() {
@ -37,6 +38,7 @@ object Blocks {
screen3 = new Screen.Tier3(blockSimple)
capacitor = new Capacitor(blockSimple)
robot = new Robot(blockSpecial)
GameRegistry.registerTileEntity(classOf[tileentity.Adapter], Config.namespace + "adapter")
GameRegistry.registerTileEntity(classOf[tileentity.Cable], Config.namespace + "cable")
@ -46,6 +48,7 @@ object Blocks {
GameRegistry.registerTileEntity(classOf[tileentity.Keyboard], Config.namespace + "keyboard")
GameRegistry.registerTileEntity(classOf[tileentity.PowerConverter], Config.namespace + "power_converter")
GameRegistry.registerTileEntity(classOf[tileentity.PowerDistributor], Config.namespace + "power_distributor")
GameRegistry.registerTileEntity(classOf[tileentity.Robot], Config.namespace + "robot")
GameRegistry.registerTileEntity(classOf[tileentity.Screen], Config.namespace + "screen")
}
}

View File

@ -8,7 +8,6 @@ import li.cil.oc.util.PackedColor
import net.minecraft.client.gui.GuiScreen
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.{NBTTagString, NBTBase, NBTTagCompound}
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.StatCollector
import net.minecraftforge.common.ForgeDirection
import org.lwjgl.input.Keyboard
@ -72,7 +71,7 @@ class PacketHandler extends CommonPacketHandler {
}
def onRedstoneStateResponse(p: PacketParser) =
p.readTileEntity[TileEntity with Redstone]() match {
p.readTileEntity[Redstone]() match {
case Some(t) =>
t.isOutputEnabled = p.readBoolean()
for (d <- ForgeDirection.VALID_DIRECTIONS) {
@ -82,7 +81,7 @@ class PacketHandler extends CommonPacketHandler {
}
def onRotatableStateResponse(p: PacketParser) =
p.readTileEntity[TileEntity with Rotatable]() match {
p.readTileEntity[Rotatable]() match {
case Some(t) =>
t.pitch = p.readDirection()
t.yaw = p.readDirection()

View File

@ -1,10 +1,8 @@
package li.cil.oc.client
import li.cil.oc.api.network.Environment
import li.cil.oc.common.PacketBuilder
import li.cil.oc.common.PacketType
import li.cil.oc.common.tileentity._
import net.minecraft.tileentity.TileEntity
object PacketSender {
def sendComputerStateRequest(t: Case) {
@ -23,7 +21,7 @@ object PacketSender {
pb.sendToServer()
}
def sendRedstoneStateRequest(t: TileEntity with Redstone) {
def sendRedstoneStateRequest(t: Redstone) {
val pb = new PacketBuilder(PacketType.RedstoneStateRequest)
pb.writeTileEntity(t)
@ -31,7 +29,7 @@ object PacketSender {
pb.sendToServer()
}
def sendRotatableStateRequest(t: TileEntity with Rotatable) {
def sendRotatableStateRequest(t: Rotatable) {
val pb = new PacketBuilder(PacketType.RotatableStateRequest)
pb.writeTileEntity(t)
@ -47,7 +45,7 @@ object PacketSender {
pb.sendToServer()
}
def sendKeyDown[T <: TileEntity with Environment](t: T, char: Char, code: Int) {
def sendKeyDown[T <: Environment](t: T, char: Char, code: Int) {
val pb = new PacketBuilder(PacketType.KeyDown)
pb.writeTileEntity(t)
@ -57,7 +55,7 @@ object PacketSender {
pb.sendToServer()
}
def sendKeyUp[T <: TileEntity with Environment](t: T, char: Char, code: Int) {
def sendKeyUp[T <: Environment](t: T, char: Char, code: Int) {
val pb = new PacketBuilder(PacketType.KeyUp)
pb.writeTileEntity(t)
@ -67,7 +65,7 @@ object PacketSender {
pb.sendToServer()
}
def sendClipboard[T <: TileEntity with Environment](t: T, value: String) = if (!value.isEmpty) {
def sendClipboard[T <: Environment](t: T, value: String) = if (!value.isEmpty) {
val pb = new PacketBuilder(PacketType.Clipboard)
pb.writeTileEntity(t)

View File

@ -4,9 +4,9 @@ import cpw.mods.fml.common.network.PacketDispatcher
import cpw.mods.fml.common.network.Player
import java.io.ByteArrayOutputStream
import java.io.DataOutputStream
import li.cil.oc.common.tileentity.TileEntity
import net.minecraft.nbt.NBTBase
import net.minecraft.network.packet.Packet250CustomPayload
import net.minecraft.tileentity.TileEntity
import net.minecraftforge.common.ForgeDirection
/** Utility class for packet creation. */
@ -14,10 +14,10 @@ class PacketBuilder(packetType: PacketType.Value, private val stream: ByteArrayO
writeByte(packetType.id)
def writeTileEntity(t: TileEntity) = {
writeInt(t.worldObj.provider.dimensionId)
writeInt(t.xCoord)
writeInt(t.yCoord)
writeInt(t.zCoord)
writeInt(t.world.provider.dimensionId)
writeInt(t.x)
writeInt(t.y)
writeInt(t.z)
}
def writeDirection(d: ForgeDirection) = writeInt(d.ordinal)

View File

@ -70,7 +70,7 @@ class Case(val parent: SimpleDelegator) extends SimpleDelegate {
override def onBlockPreDestroy(world: World, x: Int, y: Int, z: Int) =
if (!world.isRemote) world.getBlockTileEntity(x, y, z) match {
case computer: tileentity.Case =>
computer.turnOff()
computer.instance.stop()
computer.dropContent(world, x, y, z)
case _ => // Ignore.
}
@ -80,7 +80,7 @@ class Case(val parent: SimpleDelegator) extends SimpleDelegate {
if (!player.isSneaking) {
// Start the computer if it isn't already running and open the GUI.
if (!world.isRemote) {
world.getBlockTileEntity(x, y, z).asInstanceOf[tileentity.Case].turnOn()
world.getBlockTileEntity(x, y, z).asInstanceOf[tileentity.Case].instance.start()
}
player.openGui(OpenComputers, GuiType.Case.id, world, x, y, z)
true

View File

@ -26,8 +26,6 @@ class PowerConverter(val parent: SimpleDelegator) extends SimpleDelegate {
icons(ForgeDirection.EAST.ordinal) = icons(ForgeDirection.NORTH.ordinal)
}
// ----------------------------------------------------------------------- //
// Tile entity
// ----------------------------------------------------------------------- //
override def hasTileEntity = true

View File

@ -0,0 +1,14 @@
package li.cil.oc.common.block
import li.cil.oc.common.tileentity
import net.minecraft.world.World
class Robot(val parent: SpecialDelegator) extends SpecialDelegate {
val unlocalizedName = "Robot"
// ----------------------------------------------------------------------- //
override def hasTileEntity = true
override def createTileEntity(world: World) = Some(new tileentity.Robot)
}

View File

@ -2,6 +2,7 @@ package li.cil.oc.common.component
import li.cil.oc.api.network.Visibility
import li.cil.oc.common.component
import li.cil.oc.common.tileentity.TileEntity
import li.cil.oc.util.{Persistable, PackedColor, TextBuffer}
import li.cil.oc.{api, Config}
import net.minecraft.nbt.NBTTagCompound
@ -116,7 +117,7 @@ class Buffer(val owner: Buffer.Environment) extends Persistable {
object Buffer {
trait Environment extends api.network.Environment with Persistable {
trait Environment extends TileEntity with api.network.Environment with Persistable {
val node = api.Network.newNode(this, Visibility.Network).
withComponent("screen").
withConnector().

View File

@ -31,21 +31,21 @@ class Adapter extends Environment with IPeripheral {
def neighborChanged() = if (node != null && node.network != null) {
for (d <- ForgeDirection.VALID_DIRECTIONS) {
val (x, y, z) = (xCoord + d.offsetX, yCoord + d.offsetY, zCoord + d.offsetZ)
driver.Registry.driverFor(worldObj, x, y, z) match {
val (x, y, z) = (this.x + d.offsetX, this.y + d.offsetY, this.z + d.offsetZ)
driver.Registry.driverFor(world, x, y, z) match {
case Some(newDriver) => blocks(d.ordinal()) match {
case Some((oldEnvironment, driver)) =>
if (newDriver != driver) {
// This is... odd. Maybe moved by some other mod?
node.disconnect(oldEnvironment.node)
val environment = newDriver.createEnvironment(worldObj, x, y, z)
val environment = newDriver.createEnvironment(world, x, y, z)
blocks(d.ordinal()) = Some((environment, newDriver))
blocksData(d.ordinal()) = Some(new BlockData(environment.getClass.getName, new NBTTagCompound()))
node.connect(environment.node)
} // else: the more things change, the more they stay the same.
case _ =>
// A challenger appears.
val environment = newDriver.createEnvironment(worldObj, x, y, z)
val environment = newDriver.createEnvironment(world, x, y, z)
blocks(d.ordinal()) = Some((environment, newDriver))
blocksData(d.ordinal()) match {
case Some(data) if data.name == environment.getClass.getName =>

View File

@ -2,15 +2,12 @@ package li.cil.oc.common.tileentity
import li.cil.oc.api.Network
import li.cil.oc.api.network.Visibility
import li.cil.oc.common.block
import li.cil.oc.common
class Cable extends Environment {
val node = Network.newNode(this, Visibility.None).create()
def neighbors = block.Cable.neighbors(worldObj, xCoord, yCoord, zCoord)
def neighbors = common.block.Cable.neighbors(world, x, y, z)
override def getRenderBoundingBox =
block.Cable.
bounds(worldObj, xCoord, yCoord, zCoord).
offset(xCoord, yCoord, zCoord)
override def getRenderBoundingBox = common.block.Cable.bounds(world, x, y, z).offset(x, y, z)
}

View File

@ -1,6 +1,5 @@
package li.cil.oc.common.tileentity
import cpw.mods.fml.common.Loader
import li.cil.oc.Config
import li.cil.oc.api.driver.Slot
import li.cil.oc.client.{PacketSender => ClientPacketSender}
@ -8,8 +7,6 @@ import li.cil.oc.server.component
import li.cil.oc.server.driver
import li.cil.oc.server.driver.Registry
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import mods.immibis.redlogic.api.wiring.IBundledEmitter
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.ForgeDirection
@ -25,15 +22,11 @@ class Case(isClient: Boolean) extends Computer with ComponentInventory with Rota
// ----------------------------------------------------------------------- //
def turnOn() = instance.start()
def turnOff() = instance.stop()
def isOn = isRunning
def isOn_=(value: Boolean) = {
isRunning = value
worldObj.markBlockForRenderUpdate(xCoord, yCoord, zCoord)
world.markBlockForRenderUpdate(x, y, z)
this
}
@ -41,7 +34,7 @@ class Case(isClient: Boolean) extends Computer with ComponentInventory with Rota
override def updateEntity() {
super.updateEntity()
if (!worldObj.isRemote) {
if (isServer) {
if (isRunning != instance.isRunning) {
isOutputEnabled = hasRedstoneCard && instance.isRunning
ServerPacketSender.sendComputerState(this, instance.isRunning)
@ -58,7 +51,7 @@ class Case(isClient: Boolean) extends Computer with ComponentInventory with Rota
override def validate() = {
super.validate()
if (worldObj.isRemote) {
if (isClient) {
ClientPacketSender.sendRotatableStateRequest(this)
ClientPacketSender.sendComputerStateRequest(this)
ClientPacketSender.sendRedstoneStateRequest(this)
@ -69,15 +62,9 @@ class Case(isClient: Boolean) extends Computer with ComponentInventory with Rota
override def readFromNBT(nbt: NBTTagCompound) {
super.readFromNBT(nbt)
super.load(nbt)
instance.recomputeMemory()
}
override def writeToNBT(nbt: NBTTagCompound) {
super.writeToNBT(nbt)
super.save(nbt)
}
// ----------------------------------------------------------------------- //
def getInvName = Config.namespace + "container.Case"
@ -93,13 +80,9 @@ class Case(isClient: Boolean) extends Computer with ComponentInventory with Rota
case _ => false // Invalid slot.
}
override def isUseableByPlayer(player: EntityPlayer) =
worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) == this &&
player.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64
override def onInventoryChanged() {
super.onInventoryChanged()
if (!worldObj.isRemote) {
if (isServer) {
instance.recomputeMemory()
isOutputEnabled = hasRedstoneCard && instance.isRunning
}
@ -109,54 +92,11 @@ class Case(isClient: Boolean) extends Computer with ComponentInventory with Rota
def canConnectRedstone(side: ForgeDirection) = isOutputEnabled
override def computeInput(side: ForgeDirection) = {
val global = toGlobal(side)
worldObj.getIndirectPowerLevelTo(
xCoord + global.offsetX,
yCoord + global.offsetY,
zCoord + global.offsetZ,
global.ordinal())
}
protected def computeBundledInput(side: ForgeDirection) = {
val global = toGlobal(side)
if (Loader.isModLoaded("RedLogic")) {
worldObj.getBlockTileEntity(
xCoord + global.offsetX,
yCoord + global.offsetY,
zCoord + global.offsetZ) match {
case emitter: IBundledEmitter =>
var strength: Array[Byte] = null
for (i <- -1 to 5 if strength == null) {
strength = emitter.getBundledCableStrength(i, global.getOpposite.ordinal())
}
strength
case _ => null
}
} else null
}
override protected def onRedstoneInputChanged(side: ForgeDirection) {
super.onRedstoneInputChanged(side)
instance.signal("redstone_changed", side.ordinal())
}
override protected def onRedstoneOutputChanged(side: ForgeDirection) {
super.onRedstoneOutputChanged(side)
if (side == ForgeDirection.UNKNOWN) {
worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord,
getBlockType.blockID)
if (isServer) {
instance.signal("redstone_changed", side.ordinal())
}
else {
val global = toGlobal(side)
worldObj.notifyBlockOfNeighborChange(
xCoord + global.offsetX,
yCoord + global.offsetY,
zCoord + global.offsetZ,
getBlockType.blockID)
}
if (!worldObj.isRemote) ServerPacketSender.sendRedstoneState(this)
else worldObj.markBlockForRenderUpdate(xCoord, yCoord, zCoord)
}
private def hasRedstoneCard = items.exists {

View File

@ -8,7 +8,7 @@ import li.cil.oc.util.Persistable
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
trait ComponentInventory extends Inventory with TileEntity with network.Environment with Persistable {
trait ComponentInventory extends Inventory with network.Environment with Persistable {
protected val components = Array.fill[Option[ManagedEnvironment]](getSizeInventory)(None)
// ----------------------------------------------------------------------- //
@ -75,7 +75,7 @@ trait ComponentInventory extends Inventory with TileEntity with network.Environm
def getInventoryStackLimit = 1
override protected def onItemAdded(slot: Int, item: ItemStack) = if (!world.isRemote) {
override protected def onItemAdded(slot: Int, item: ItemStack) = if (isServer) {
Registry.driverFor(item) match {
case Some(driver) => Option(driver.createEnvironment(item, this)) match {
case Some(component) =>
@ -88,7 +88,7 @@ trait ComponentInventory extends Inventory with TileEntity with network.Environm
}
}
override protected def onItemRemoved(slot: Int, item: ItemStack) = if (!world.isRemote) {
override protected def onItemRemoved(slot: Int, item: ItemStack) = if (isServer) {
// Uninstall component previously in that slot.
components(slot) match {
case Some(component) =>

View File

@ -30,7 +30,7 @@ abstract class Computer extends Environment with Context with Analyzable {
// the update this round to allow other tile entities to join the network,
// too, avoiding issues of missing nodes (e.g. in the GPU which would
// otherwise loose track of its screen).
if (!worldObj.isRemote && node != null && node.network != null) {
if (isServer && node != null && node.network != null) {
if (instance.isRunning && !node.changeBuffer(-Config.computerCost)) {
instance.lastError = "not enough energy"
instance.stop()

View File

@ -4,11 +4,8 @@ import li.cil.oc.api.driver.Slot
import li.cil.oc.api.network.{Component, Visibility}
import li.cil.oc.client.{PacketSender => ClientPacketSender}
import li.cil.oc.server.driver.Registry
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.{Config, api}
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
class DiskDrive extends Environment with ComponentInventory with Rotatable {
val node = api.Network.newNode(this, Visibility.None).create()
@ -17,31 +14,13 @@ class DiskDrive extends Environment with ComponentInventory with Rotatable {
override def validate() = {
super.validate()
if (worldObj.isRemote) {
if (isClient) {
ClientPacketSender.sendRotatableStateRequest(this)
}
}
// ----------------------------------------------------------------------- //
override def readFromNBT(nbt: NBTTagCompound) {
super.readFromNBT(nbt)
super.load(nbt)
}
override def writeToNBT(nbt: NBTTagCompound) {
super.writeToNBT(nbt)
super.save(nbt)
}
// ----------------------------------------------------------------------- //
override protected def onRotationChanged() {
if (!world.isRemote) {
ServerPacketSender.sendRotatableState(this)
}
}
def getInvName = Config.namespace + "container.DiskDrive"
def getSizeInventory = 1
@ -51,10 +30,6 @@ class DiskDrive extends Environment with ComponentInventory with Rotatable {
case _ => false
}
def isUseableByPlayer(player: EntityPlayer) =
worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) == this &&
player.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64
override protected def onItemAdded(slot: Int, item: ItemStack) {
super.onItemAdded(slot, item)
components(slot) match {

View File

@ -1,12 +1,13 @@
package li.cil.oc.common.tileentity
import li.cil.oc.api.{Network, network}
import li.cil.oc.util.Persistable
import net.minecraft.nbt.NBTTagCompound
import scala.math.ScalaNumber
abstract class Environment extends net.minecraft.tileentity.TileEntity with TileEntity with network.Environment {
abstract class Environment extends net.minecraft.tileentity.TileEntity with TileEntity with network.Environment with Persistable {
def world = worldObj
def world = getWorldObj
def x = xCoord
@ -14,6 +15,8 @@ abstract class Environment extends net.minecraft.tileentity.TileEntity with Tile
def z = zCoord
def block = getBlockType
// ----------------------------------------------------------------------- //
override def updateEntity() {
@ -37,11 +40,13 @@ abstract class Environment extends net.minecraft.tileentity.TileEntity with Tile
override def readFromNBT(nbt: NBTTagCompound) {
super.readFromNBT(nbt)
load(nbt)
if (node != null) node.load(nbt)
}
override def writeToNBT(nbt: NBTTagCompound) {
super.writeToNBT(nbt)
save(nbt)
if (node != null) node.save(nbt)
}

View File

@ -3,14 +3,17 @@ package li.cil.oc.common.tileentity
import li.cil.oc.Config
import li.cil.oc.util.Persistable
import net.minecraft.entity.item.EntityItem
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.IInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.{NBTTagList, NBTTagCompound}
import net.minecraft.world.World
trait Inventory extends IInventory with Persistable {
trait Inventory extends TileEntity with IInventory with Persistable {
protected val items = Array.fill[Option[ItemStack]](getSizeInventory)(None)
// ----------------------------------------------------------------------- //
def getStackInSlot(i: Int) = items(i).orNull
def decrStackSize(slot: Int, amount: Int) = items(slot) match {
@ -25,27 +28,38 @@ trait Inventory extends IInventory with Persistable {
}
def setInventorySlotContents(slot: Int, item: ItemStack) = {
if (items(slot).isDefined)
if (items(slot).isDefined) {
onItemRemoved(slot, items(slot).get)
}
items(slot) = Option(item)
if (item != null && item.stackSize > getInventoryStackLimit)
if (item != null && item.stackSize > getInventoryStackLimit) {
item.stackSize = getInventoryStackLimit
}
if (items(slot).isDefined)
if (items(slot).isDefined) {
onItemAdded(slot, items(slot).get)
}
onInventoryChanged()
}
def getStackInSlotOnClosing(slot: Int) = null
def isInvNameLocalized = false
def openChest() {}
def closeChest() {}
def isInvNameLocalized = false
def isUseableByPlayer(player: EntityPlayer) =
world.getBlockTileEntity(x, y, z) match {
case t: TileEntity if t == this => player.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) < 64
case _ => false
}
// ----------------------------------------------------------------------- //
def dropContent(world: World, x: Int, y: Int, z: Int) {
val rng = world.rand
for (slot <- 0 until getSizeInventory) {
@ -63,8 +77,11 @@ trait Inventory extends IInventory with Persistable {
}
}
// ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) {
super.load(nbt)
val inventoryNbt = nbt.getTagList(Config.namespace + "inventory.items")
for (i <- 0 until inventoryNbt.tagCount) {
val slotNbt = inventoryNbt.tagAt(i).asInstanceOf[NBTTagCompound]
@ -78,6 +95,7 @@ trait Inventory extends IInventory with Persistable {
override def save(nbt: NBTTagCompound) {
super.save(nbt)
val inventoryNbt = new NBTTagList()
items.zipWithIndex collect {
case (Some(stack), slot) => (stack, slot)
@ -94,6 +112,8 @@ trait Inventory extends IInventory with Persistable {
nbt.setTag(Config.namespace + "inventory.items", inventoryNbt)
}
// ----------------------------------------------------------------------- //
protected def onItemAdded(slot: Int, item: ItemStack) {}
protected def onItemRemoved(slot: Int, item: ItemStack) {}

View File

@ -4,7 +4,6 @@ import cpw.mods.fml.common.IPlayerTracker
import li.cil.oc.api.Network
import li.cil.oc.api.network.{Visibility, Message}
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.event.{Event, ForgeSubscribe}
import scala.collection.mutable
@ -47,18 +46,6 @@ class Keyboard extends Environment with Rotatable {
// ----------------------------------------------------------------------- //
override def readFromNBT(nbt: NBTTagCompound) {
super.readFromNBT(nbt)
node.load(nbt)
}
override def writeToNBT(nbt: NBTTagCompound) {
super.writeToNBT(nbt)
node.save(nbt)
}
// ----------------------------------------------------------------------- //
override def onMessage(message: Message) = {
message.data match {
case Array(p: EntityPlayer, char: Character, code: Integer) if message.name == "keyboard.keyDown" =>
@ -85,8 +72,8 @@ class Keyboard extends Environment with Rotatable {
// ----------------------------------------------------------------------- //
private def isUseableByPlayer(p: EntityPlayer) =
worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) == this &&
p.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64
world.getBlockTileEntity(x, y, z) == this &&
p.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) < 64
}
object Keyboard extends IPlayerTracker {

View File

@ -34,7 +34,7 @@ class PowerConverter extends Environment with IEnergySink with IPowerReceptor wi
override def updateEntity() {
super.updateEntity()
if (!worldObj.isRemote) {
if (isServer) {
if (Loader.isModLoaded("IC2")) {
loadIC2()
}

View File

@ -88,14 +88,14 @@ class PowerDistributor extends Environment with Analyzable {
override def updateEntity() {
super.updateEntity()
if (!worldObj.isRemote && (dirty || buffers.exists(_.dirty))) {
if (isServer && (dirty || buffers.exists(_.dirty))) {
updateCachedValues()
}
}
override def validate() {
super.validate()
if (worldObj.isRemote) {
if (isClient) {
ClientPacketSender.sendPowerStateRequest(this)
}
}

View File

@ -1,9 +1,10 @@
package li.cil.oc.common.tileentity
import cpw.mods.fml.common.Optional
import cpw.mods.fml.common.Optional.Interface
import cpw.mods.fml.common.{Loader, Optional}
import li.cil.oc.Config
import li.cil.oc.common.tileentity
import li.cil.oc.api.network
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.Persistable
import mods.immibis.redlogic.api.wiring._
import net.minecraft.nbt.{NBTTagByte, NBTTagList, NBTTagCompound}
@ -16,7 +17,7 @@ import net.minecraftforge.common.ForgeDirection
new Interface(iface = "mods.immibis.redlogic.api.wiring.IRedstoneEmitter", modid = "RedLogic"),
new Interface(iface = "mods.immibis.redlogic.api.wiring.IRedstoneUpdatable", modid = "RedLogic")
))
trait Redstone extends tileentity.Environment with Persistable
trait Redstone extends TileEntity with network.Environment with Rotatable with Persistable
with IConnectable with IBundledEmitter with IBundledUpdatable with IRedstoneEmitter with IRedstoneUpdatable {
private val _input = Array.fill[Byte](6)(-1)
@ -168,13 +169,57 @@ with IConnectable with IBundledEmitter with IBundledUpdatable with IRedstoneEmit
// ----------------------------------------------------------------------- //
protected def computeInput(side: ForgeDirection): Int
protected def computeInput(side: ForgeDirection) = {
val global = toGlobal(side)
world.getIndirectPowerLevelTo(
x + global.offsetX,
y + global.offsetY,
z + global.offsetZ,
global.ordinal())
}
protected def computeBundledInput(side: ForgeDirection): Array[Byte]
protected def computeBundledInput(side: ForgeDirection) = {
val global = toGlobal(side)
if (Loader.isModLoaded("RedLogic")) {
world.getBlockTileEntity(
x + global.offsetX,
y + global.offsetY,
z + global.offsetZ) match {
case wire: IInsulatedRedstoneWire =>
var strength: Array[Byte] = null
for (face <- -1 to 5 if wire.wireConnectsInDirection(face, side.ordinal()) && strength == null) {
strength = Array.fill[Byte](16)(0)
strength(wire.getInsulatedWireColour) = wire.getEmittedSignalStrength(face, side.ordinal()).toByte
}
strength
case emitter: IBundledEmitter =>
var strength: Array[Byte] = null
for (i <- -1 to 5 if strength == null) {
strength = emitter.getBundledCableStrength(i, global.getOpposite.ordinal())
}
strength
case _ => null
}
} else null
}
protected def onRedstoneInputChanged(side: ForgeDirection) {}
protected def onRedstoneOutputChanged(side: ForgeDirection) {}
protected def onRedstoneOutputChanged(side: ForgeDirection) {
if (side == ForgeDirection.UNKNOWN) {
world.notifyBlocksOfNeighborChange(x, y, z, block.blockID)
}
else {
val global = toGlobal(side)
world.notifyBlockOfNeighborChange(
x + global.offsetX,
y + global.offsetY,
z + global.offsetZ,
block.blockID)
}
if (isServer) ServerPacketSender.sendRedstoneState(this)
else world.markBlockForRenderUpdate(x, y, z)
}
// ----------------------------------------------------------------------- //

View File

@ -0,0 +1,15 @@
package li.cil.oc.common.tileentity
import li.cil.oc.server.component
import net.minecraft.item.ItemStack
class Robot extends Computer with ComponentInventory with Rotatable with Redstone {
val instance = if (true) null else new component.Computer(this)
def getInvName = ""
def getSizeInventory = 0
def isItemValidForSlot(i: Int, itemstack: ItemStack) = false
}

View File

@ -1,6 +1,7 @@
package li.cil.oc.common.tileentity
import li.cil.oc.Config
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.Persistable
import net.minecraft.block.Block
import net.minecraft.entity.Entity
@ -142,12 +143,17 @@ trait Rotatable extends TileEntity with Persistable {
// ----------------------------------------------------------------------- //
protected def onRotationChanged() {}
protected def onRotationChanged() {
if (isServer) {
ServerPacketSender.sendRotatableState(this)
}
}
// ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) = {
super.load(nbt)
_pitch = ForgeDirection.getOrientation(nbt.getInteger(Config.namespace + "rotatable.pitch"))
_yaw = ForgeDirection.getOrientation(nbt.getInteger(Config.namespace + "rotatable.yaw"))
updateTranslation()
@ -155,6 +161,7 @@ trait Rotatable extends TileEntity with Persistable {
override def save(nbt: NBTTagCompound) = {
super.save(nbt)
nbt.setInteger(Config.namespace + "rotatable.pitch", _pitch.ordinal)
nbt.setInteger(Config.namespace + "rotatable.yaw", _yaw.ordinal)
}

View File

@ -14,7 +14,7 @@ import net.minecraft.util.AxisAlignedBB
import net.minecraftforge.common.ForgeDirection
import scala.collection.mutable
class Screen(var tier: Int) extends Environment with Buffer.Environment with Rotatable with Analyzable {
class Screen(var tier: Int) extends Environment with Buffer.Environment with Rotatable with Analyzable with Ordered[Screen] {
def this() = this(0)
var currentGui: Option[gui.Screen] = None
@ -55,6 +55,11 @@ class Screen(var tier: Int) extends Environment with Buffer.Environment with Rot
def onAnalyze(stats: NBTTagCompound, player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = origin
def compare(that: Screen) =
if (x != that.x) x - that.x
else if (y != that.y) y - that.y
else z - that.z
// ----------------------------------------------------------------------- //
override def updateEntity() {
@ -64,7 +69,7 @@ class Screen(var tier: Int) extends Environment with Buffer.Environment with Rot
// different results on server and client due to the update order
// differing between the two. This also saves us from having to save
// any multi-block specific state information.
val pending = mutable.SortedSet(this)(Screen.ordering)
val pending = mutable.SortedSet(this)
val queue = mutable.Queue(this)
while (queue.nonEmpty) {
val current = queue.dequeue()
@ -99,10 +104,14 @@ class Screen(var tier: Int) extends Environment with Buffer.Environment with Rot
// Update visibility after everything is done, to avoid noise.
queue.foreach(screen =>
if (screen.isOrigin) {
if (!worldObj.isRemote) screen.node.setVisibility(Visibility.Network)
if (isServer) {
screen.node.setVisibility(Visibility.Network)
}
}
else {
if (!worldObj.isRemote) screen.node.setVisibility(Visibility.None)
if (isServer) {
screen.node.setVisibility(Visibility.None)
}
val s = screen.instance
val (w, h) = s.resolution
s.buffer.fill(0, 0, w, h, ' ')
@ -113,7 +122,7 @@ class Screen(var tier: Int) extends Environment with Buffer.Environment with Rot
override def validate() {
super.validate()
if (worldObj.isRemote) {
if (isClient) {
ClientPacketSender.sendRotatableStateRequest(this)
ClientPacketSender.sendScreenBufferRequest(this)
}
@ -134,13 +143,11 @@ class Screen(var tier: Int) extends Environment with Buffer.Environment with Rot
override def readFromNBT(nbt: NBTTagCompound) {
tier = nbt.getByte(Config.namespace + "screen.tier")
super.readFromNBT(nbt)
super.load(nbt)
}
override def writeToNBT(nbt: NBTTagCompound) {
nbt.setByte(Config.namespace + "screen.tier", tier.toByte)
super.writeToNBT(nbt)
super.save(nbt)
}
// ----------------------------------------------------------------------- //
@ -220,15 +227,13 @@ class Screen(var tier: Int) extends Environment with Buffer.Environment with Rot
// ----------------------------------------------------------------------- //
override def onRotationChanged() {
if (!worldObj.isRemote) {
ServerPacketSender.sendRotatableState(this)
}
super.onRotationChanged()
screens.clone().foreach(_.checkMultiBlock())
}
override def onScreenColorChange(foreground: Int, background: Int) {
super.onScreenColorChange(foreground, background)
if (!worldObj.isRemote) {
if (isServer) {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenColorChange(this, foreground, background)
}
@ -236,66 +241,60 @@ class Screen(var tier: Int) extends Environment with Buffer.Environment with Rot
override def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) = {
super.onScreenCopy(col, row, w, h, tx, ty)
if (worldObj.isRemote) {
currentGui.foreach(_.updateText())
hasChanged = true
}
else {
if (isServer) {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenCopy(this, col, row, w, h, tx, ty)
}
else {
currentGui.foreach(_.updateText())
hasChanged = true
}
}
override def onScreenDepthChange(depth: PackedColor.Depth.Value) {
super.onScreenDepthChange(depth)
if (!worldObj.isRemote) {
if (isServer) {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenDepthChange(this, depth)
}
else {
hasChanged = true
}
}
override def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) = {
super.onScreenFill(col, row, w, h, c)
if (worldObj.isRemote) {
currentGui.foreach(_.updateText())
hasChanged = true
}
else {
if (isServer) {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenFill(this, col, row, w, h, c)
}
else {
currentGui.foreach(_.updateText())
hasChanged = true
}
}
override def onScreenResolutionChange(w: Int, h: Int) = {
super.onScreenResolutionChange(w, h)
if (worldObj.isRemote) {
currentGui.foreach(_.changeSize(w, h))
hasChanged = true
}
else {
if (isServer) {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenResolutionChange(this, w, h)
}
else {
currentGui.foreach(_.changeSize(w, h))
hasChanged = true
}
}
override def onScreenSet(col: Int, row: Int, s: String) = {
super.onScreenSet(col, row, s)
if (worldObj.isRemote) {
currentGui.foreach(_.updateText())
hasChanged = true
}
else {
if (isServer) {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenSet(this, col, row, s)
}
}
}
object Screen {
val ordering = new Ordering[Screen] {
def compare(a: Screen, b: Screen) =
if (a.xCoord != b.xCoord) a.xCoord - b.xCoord
else if (a.yCoord != b.yCoord) a.yCoord - b.yCoord
else a.zCoord - b.zCoord
else {
currentGui.foreach(_.updateText())
hasChanged = true
}
}
}

View File

@ -1,5 +1,6 @@
package li.cil.oc.common.tileentity
import net.minecraft.block.Block
import net.minecraft.world.World
trait TileEntity {
@ -10,4 +11,10 @@ trait TileEntity {
def y: Int
def z: Int
def block: Block
def isClient = world.isRemote
def isServer = !isClient
}

View File

@ -3,11 +3,10 @@ package li.cil.oc.server
import cpw.mods.fml.common.network.Player
import li.cil.oc.api.network.Environment
import li.cil.oc.common.PacketType
import li.cil.oc.common.tileentity
import li.cil.oc.common.tileentity.{Redstone, Rotatable}
import li.cil.oc.common.tileentity._
import li.cil.oc.common.{PacketHandler => CommonPacketHandler}
import net.minecraft.tileentity.TileEntity
import net.minecraftforge.common.DimensionManager
import scala.Some
class PacketHandler extends CommonPacketHandler {
protected def world(player: Player, dimension: Int) =
@ -27,38 +26,38 @@ class PacketHandler extends CommonPacketHandler {
}
def onComputerStateRequest(p: PacketParser) =
p.readTileEntity[tileentity.Case]() match {
p.readTileEntity[Case]() match {
case Some(t) => PacketSender.sendComputerState(t, t.isOn, Option(p.player))
case _ => // Invalid packet.
}
def onPowerStateRequest(p: PacketParser) =
p.readTileEntity[tileentity.PowerDistributor]() match {
p.readTileEntity[PowerDistributor]() match {
case Some(t) => PacketSender.sendPowerState(t, Option(p.player))
case _ => // Invalid packet.
}
def onRedstoneStateRequest(p: PacketParser) =
p.readTileEntity[TileEntity with Redstone]() match {
p.readTileEntity[Redstone]() match {
case Some(t) => PacketSender.sendRedstoneState(t, Option(p.player))
case _ => // Invalid packet.
}
def onRotatableStateRequest(p: PacketParser) =
p.readTileEntity[TileEntity with Rotatable]() match {
p.readTileEntity[Rotatable]() match {
case Some(t) => PacketSender.sendRotatableState(t, Option(p.player))
case _ => // Invalid packet.
}
def onScreenBufferRequest(p: PacketParser) =
p.readTileEntity[tileentity.Screen]() match {
p.readTileEntity[Screen]() match {
case Some(t) => PacketSender.sendScreenBufferState(t, Option(p.player))
case _ => // Invalid packet.
}
def onKeyDown(p: PacketParser) =
p.readTileEntity[Environment]() match {
case Some(s: tileentity.Screen) =>
case Some(s: Screen) =>
val char = Char.box(p.readChar())
val code = Int.box(p.readInt())
s.screens.foreach(_.node.sendToNeighbors("keyboard.keyDown", p.player, char, code))
@ -68,7 +67,7 @@ class PacketHandler extends CommonPacketHandler {
def onKeyUp(p: PacketParser) =
p.readTileEntity[Environment]() match {
case Some(s: tileentity.Screen) =>
case Some(s: Screen) =>
val char = Char.box(p.readChar())
val code = Int.box(p.readInt())
s.screens.foreach(_.node.sendToNeighbors("keyboard.keyUp", p.player, char, code))
@ -78,7 +77,7 @@ class PacketHandler extends CommonPacketHandler {
def onClipboard(p: PacketParser) =
p.readTileEntity[Environment]() match {
case Some(s: tileentity.Screen) =>
case Some(s: Screen) =>
val value = p.readUTF()
s.screens.foreach(_.node.sendToNeighbors("keyboard.clipboard", p.player, value))
case Some(e) => e.node.sendToNeighbors("keyboard.clipboard", p.player, p.readUTF())

View File

@ -4,10 +4,9 @@ import cpw.mods.fml.common.network.Player
import li.cil.oc.common.PacketBuilder
import li.cil.oc.common.PacketType
import li.cil.oc.common.component.Buffer
import li.cil.oc.common.tileentity.{Redstone, PowerDistributor, Rotatable}
import li.cil.oc.common.tileentity.{Redstone, PowerDistributor, Rotatable, TileEntity}
import li.cil.oc.util.PackedColor
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.tileentity.TileEntity
import net.minecraftforge.common.ForgeDirection
/** Centralized packet dispatcher for sending updates to the client. */
@ -45,7 +44,7 @@ object PacketSender {
}
}
def sendRedstoneState(t: TileEntity with Redstone, player: Option[Player] = None) {
def sendRedstoneState(t: Redstone, player: Option[Player] = None) {
val pb = new PacketBuilder(PacketType.RedstoneStateResponse)
pb.writeTileEntity(t)
@ -60,7 +59,7 @@ object PacketSender {
}
}
def sendRotatableState(t: TileEntity with Rotatable, player: Option[Player] = None) {
def sendRotatableState(t: Rotatable, player: Option[Player] = None) {
val pb = new PacketBuilder(PacketType.RotatableStateResponse)
pb.writeTileEntity(t)
@ -73,7 +72,7 @@ object PacketSender {
}
}
def sendScreenBufferState(t: TileEntity with Buffer.Environment, player: Option[Player] = None) {
def sendScreenBufferState(t: Buffer.Environment, player: Option[Player] = None) {
val pb = new PacketBuilder(PacketType.ScreenBufferResponse)
pb.writeTileEntity(t)

View File

@ -0,0 +1,12 @@
package mods.immibis.redlogic.api.wiring;
/**
* Marker interface for insulated wire tile entities.
*/
public interface IInsulatedRedstoneWire extends IRedstoneWire {
/**
* Returns the colour as a standard Minecraft wool colour.
* 0=white, 15=black
*/
public int getInsulatedWireColour();
}

View File

@ -0,0 +1,8 @@
package mods.immibis.redlogic.api.wiring;
/**
* Marker interface for red alloy wire, both bare and insulated.
*/
public interface IRedstoneWire extends IRedstoneEmitter, IRedstoneUpdatable, IWire {
}