mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-15 10:21:45 -04:00
added callback to robot context that allows forcing an upgrade to be saved and resent to clients, to allow upgrades to manually synchronize their data with clients for state specific rendering; using this to transmit generator state (running or not) and show a different texture accordingly; fixed a bug where remaining runtime wasn't saved for generators when no more items were in their internal inventory; implementing contexts in their respective tile entities, too, to allow external components to refer to their owners via the context interfaces
This commit is contained in:
parent
26b5d0543e
commit
5dae4cd20e
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@ -27,4 +27,17 @@ public interface RobotContext extends Context {
|
||||
* @return the fake player for the robot.
|
||||
*/
|
||||
EntityPlayer player();
|
||||
|
||||
/**
|
||||
* Causes the currently installed upgrade to be saved and synchronized.
|
||||
* <p/>
|
||||
* If no upgrade is installed in the robot this does nothing.
|
||||
* <p/>
|
||||
* This is intended for upgrade components, to allow them to update their
|
||||
* client side representation for rendering purposes. The component will be
|
||||
* saved to its item's NBT tag compound, as it would be when the game is
|
||||
* saved, and then re-sent to the client. Keep the number of calls to this
|
||||
* function low, since each call causes a network packet to be sent.
|
||||
*/
|
||||
void saveUpgrade();
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ class PacketHandler extends CommonPacketHandler {
|
||||
|
||||
def onComputerState(p: PacketParser) =
|
||||
p.readTileEntity[Computer]() match {
|
||||
case Some(t) => t.isRunning = p.readBoolean()
|
||||
case Some(t) => t.isRunning_=(p.readBoolean())
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package li.cil.oc.client.renderer.item
|
||||
|
||||
import li.cil.oc.server.driver.item.Item
|
||||
import li.cil.oc.{Settings, Items}
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.Tessellator
|
||||
@ -17,17 +18,22 @@ object UpgradeRenderer extends IItemRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
def shouldUseRenderHelper(renderType: ItemRenderType, item: ItemStack, helper: ItemRendererHelper) = helper == ItemRendererHelper.EQUIPPED_BLOCK
|
||||
def shouldUseRenderHelper(renderType: ItemRenderType, stack: ItemStack, helper: ItemRendererHelper) =
|
||||
// Note: it's easier to revert changes introduced by this "helper" than by
|
||||
// the code that applies if no helper is used...
|
||||
helper == ItemRendererHelper.EQUIPPED_BLOCK
|
||||
|
||||
def renderItem(renderType: ItemRenderType, item: ItemStack, data: AnyRef*) {
|
||||
def renderItem(renderType: ItemRenderType, stack: ItemStack, data: AnyRef*) {
|
||||
val tm = Minecraft.getMinecraft.getTextureManager
|
||||
GL11.glTranslatef(0.5f, 0.5f, 0.5f)
|
||||
val t = Tessellator.instance
|
||||
|
||||
Items.multi.subItem(item) match {
|
||||
// Revert offset introduced by the render "helper".
|
||||
GL11.glTranslatef(0.5f, 0.5f, 0.5f)
|
||||
|
||||
Items.multi.subItem(stack) match {
|
||||
case Some(subItem) if subItem == Items.generator =>
|
||||
// TODO display lists?
|
||||
val onOffset = if (true) 0.5 else 0
|
||||
val onOffset = if (Item.dataTag(stack).getInteger("remainingTicks") > 0) 0.5 else 0
|
||||
val b = AxisAlignedBB.getAABBPool.getAABB(0.4, 0.2, 0.16, 0.6, 0.4, 0.36)
|
||||
tm.bindTexture(new ResourceLocation(Settings.resourceDomain, "textures/items/upgrade_generator_equipped.png"))
|
||||
|
||||
|
@ -86,7 +86,7 @@ trait ComponentInventory extends Inventory with network.Environment { self: MCTi
|
||||
override protected def onItemAdded(slot: Int, stack: ItemStack) = if (isServer && isComponentSlot(slot)) {
|
||||
Registry.driverFor(stack) match {
|
||||
case Some(driver) => Option(driver.createEnvironment(stack, this)) match {
|
||||
case Some(component) =>
|
||||
case Some(component) => this.synchronized {
|
||||
components(slot) = Some(component)
|
||||
component.load(dataTag(driver, stack))
|
||||
connectItemNode(component.node)
|
||||
@ -95,6 +95,7 @@ trait ComponentInventory extends Inventory with network.Environment { self: MCTi
|
||||
updatingComponents += component
|
||||
}
|
||||
component.save(dataTag(driver, stack))
|
||||
}
|
||||
case _ => // No environment (e.g. RAM).
|
||||
}
|
||||
case _ => // No driver.
|
||||
@ -104,7 +105,7 @@ trait ComponentInventory extends Inventory with network.Environment { self: MCTi
|
||||
override protected def onItemRemoved(slot: Int, stack: ItemStack) = if (isServer) {
|
||||
// Uninstall component previously in that slot.
|
||||
components(slot) match {
|
||||
case Some(component) =>
|
||||
case Some(component) => this.synchronized {
|
||||
// Note to self: we have to remove the node from the network *before*
|
||||
// saving, to allow file systems to close their handles before they
|
||||
// are saved (otherwise hard drives would restore all handles after
|
||||
@ -114,6 +115,7 @@ trait ComponentInventory extends Inventory with network.Environment { self: MCTi
|
||||
component.node.remove()
|
||||
Registry.driverFor(stack).foreach(driver =>
|
||||
component.save(dataTag(driver, stack)))
|
||||
}
|
||||
case _ => // Nothing to do.
|
||||
}
|
||||
}
|
||||
@ -124,6 +126,6 @@ trait ComponentInventory extends Inventory with network.Environment { self: MCTi
|
||||
this.node.connect(node)
|
||||
}
|
||||
|
||||
private def dataTag(driver: ItemDriver, stack: ItemStack) =
|
||||
protected def dataTag(driver: ItemDriver, stack: ItemStack) =
|
||||
Option(driver.dataTag(stack)).getOrElse(Item.dataTag(stack))
|
||||
}
|
@ -11,7 +11,7 @@ import net.minecraftforge.common.ForgeDirection
|
||||
import scala.Some
|
||||
import scala.collection.mutable
|
||||
|
||||
abstract class Computer(isRemote: Boolean) extends Environment with ComponentInventory with Rotatable with BundledRedstoneAware with Analyzable {
|
||||
abstract class Computer(isRemote: Boolean) extends Environment with ComponentInventory with Rotatable with BundledRedstoneAware with Analyzable with Context {
|
||||
protected val _computer = if (isRemote) null else new component.Computer(this)
|
||||
|
||||
def computer = _computer
|
||||
@ -28,6 +28,16 @@ abstract class Computer(isRemote: Boolean) extends Environment with ComponentInv
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
// Note: we implement IContext in the TE to allow external components to cast
|
||||
// their owner to it (to allow interacting with their owning computer).
|
||||
|
||||
def address() = computer.address
|
||||
|
||||
def canInteract(player: String) =
|
||||
if (isServer) computer.canInteract(player)
|
||||
else !Settings.get.canComputersBeOwned ||
|
||||
_users.isEmpty || _users.contains(player)
|
||||
|
||||
def isRunning = _isRunning
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@ -37,6 +47,18 @@ abstract class Computer(isRemote: Boolean) extends Environment with ComponentInv
|
||||
this
|
||||
}
|
||||
|
||||
def isPaused = computer.isPaused
|
||||
|
||||
def start() = computer.start()
|
||||
|
||||
def pause(seconds: Double) = computer.pause(seconds)
|
||||
|
||||
def stop() = computer.stop()
|
||||
|
||||
def signal(name: String, args: AnyRef*) = computer.signal(name, args: _*)
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def markAsChanged() = hasChanged = true
|
||||
|
||||
def hasRedstoneCard = items.exists {
|
||||
@ -54,11 +76,6 @@ abstract class Computer(isRemote: Boolean) extends Environment with ComponentInv
|
||||
_users ++= list
|
||||
}
|
||||
|
||||
def canInteract(player: String) =
|
||||
if (isServer) computer.canInteract(player)
|
||||
else !Settings.get.canComputersBeOwned ||
|
||||
_users.isEmpty || _users.contains(player)
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def updateEntity() {
|
||||
@ -110,7 +127,7 @@ abstract class Computer(isRemote: Boolean) extends Environment with ComponentInv
|
||||
@SideOnly(Side.CLIENT)
|
||||
override def readFromNBTForClient(nbt: NBTTagCompound) {
|
||||
super.readFromNBTForClient(nbt)
|
||||
isRunning = nbt.getBoolean("isRunning")
|
||||
isRunning_=(nbt.getBoolean("isRunning"))
|
||||
_users.clear()
|
||||
_users ++= nbt.getTagList("users").iterator[NBTTagString].map(_.data)
|
||||
}
|
||||
|
@ -24,13 +24,32 @@ import scala.Some
|
||||
// robot moves we only create a new proxy tile entity, hook the instance of this
|
||||
// class that was held by the old proxy to it and can then safely forget the
|
||||
// old proxy, which will be cleaned up by Minecraft like any other tile entity.
|
||||
class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory with Buffer with PowerInformation {
|
||||
class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory with Buffer with PowerInformation with RobotContext {
|
||||
def this() = this(false)
|
||||
|
||||
var proxy: RobotProxy = _
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
// Note: we implement IRobotContext in the TE to allow external components
|
||||
//to cast their owner to it (to allow interacting with their owning robot).
|
||||
|
||||
var selectedSlot = actualSlot(0)
|
||||
|
||||
def player() = player(facing, facing)
|
||||
|
||||
def saveUpgrade() = this.synchronized {
|
||||
components(3) match {
|
||||
case Some(environment) =>
|
||||
val stack = getStackInSlot(3)
|
||||
// We're guaranteed to have a driver for entries.
|
||||
environment.save(dataTag(Registry.driverFor(stack).get, stack))
|
||||
ServerPacketSender.sendRobotEquippedUpgradeChange(this, stack)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def node = if (isClient) null else computer.node
|
||||
|
||||
override val _buffer = new common.component.Buffer(this) {
|
||||
@ -62,8 +81,6 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
|
||||
|
||||
var globalBuffer, globalBufferSize = 0.0
|
||||
|
||||
var selectedSlot = actualSlot(0)
|
||||
|
||||
var equippedItem: Option[ItemStack] = None
|
||||
|
||||
var equippedUpgrade: Option[ItemStack] = None
|
||||
@ -309,7 +326,9 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
|
||||
}
|
||||
}
|
||||
|
||||
override def writeToNBT(nbt: NBTTagCompound) {
|
||||
override def writeToNBT(nbt: NBTTagCompound) = this.synchronized {
|
||||
// Note: computer is saved when proxy is saved (in proxy's super writeToNBT)
|
||||
// which is a bit ugly, and may be refactored some day, but it works.
|
||||
nbt.setNewCompoundTag(Settings.namespace + "buffer", buffer.save)
|
||||
nbt.setNewCompoundTag(Settings.namespace + "gpu", gpu.save)
|
||||
nbt.setNewCompoundTag(Settings.namespace + "keyboard", keyboard.save)
|
||||
@ -350,13 +369,22 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
|
||||
}
|
||||
}
|
||||
|
||||
override def writeToNBTForClient(nbt: NBTTagCompound) {
|
||||
override def writeToNBTForClient(nbt: NBTTagCompound) = this.synchronized {
|
||||
super.writeToNBTForClient(nbt)
|
||||
nbt.setInteger("selectedSlot", selectedSlot)
|
||||
if (getStackInSlot(0) != null) {
|
||||
nbt.setNewCompoundTag("equipped", getStackInSlot(0).writeToNBT)
|
||||
}
|
||||
if (getStackInSlot(3) != null) {
|
||||
// Force saving to item's NBT if necessary before sending, to make sure
|
||||
// we transfer the component's current state (e.g. running or not for
|
||||
// generator upgrades).
|
||||
components(3) match {
|
||||
case Some(environment) =>
|
||||
val stack = getStackInSlot(3)
|
||||
// We're guaranteed to have a driver for entries.
|
||||
environment.save(dataTag(Registry.driverFor(stack).get, stack))
|
||||
}
|
||||
nbt.setNewCompoundTag("upgrade", getStackInSlot(3).writeToNBT)
|
||||
}
|
||||
nbt.setDouble(Settings.namespace + "xp", xp)
|
||||
|
@ -14,7 +14,7 @@ import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraftforge.common.ForgeDirection
|
||||
|
||||
class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedInventory with Buffer with PowerInformation {
|
||||
class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedInventory with Buffer with PowerInformation with RobotContext {
|
||||
def this() = this(new Robot(false))
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
@ -23,6 +23,25 @@ class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedI
|
||||
withComponent("robot", Visibility.Neighbors).
|
||||
create()
|
||||
|
||||
override protected val _computer = null
|
||||
|
||||
override def computer = robot.computer
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
// Note: we implement IRobotContext in the TE to allow external components
|
||||
//to cast their owner to it (to allow interacting with their owning robot).
|
||||
|
||||
override def isRunning = robot.isRunning
|
||||
|
||||
override def isRunning_=(value: Boolean) = robot.isRunning_=(value)
|
||||
|
||||
def selectedSlot() = robot.selectedSlot
|
||||
|
||||
def player() = robot.player()
|
||||
|
||||
def saveUpgrade() = robot.saveUpgrade()
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@LuaCallback("start")
|
||||
@ -221,12 +240,6 @@ class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedI
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def computer = robot.computer
|
||||
|
||||
override def isRunning = robot.isRunning
|
||||
|
||||
override def isRunning_=(value: Boolean) = robot.isRunning_=(value)
|
||||
|
||||
override def markAsChanged() = robot.markAsChanged()
|
||||
|
||||
override def hasRedstoneCard = robot.hasRedstoneCard
|
||||
|
@ -81,6 +81,7 @@ class Generator(val owner: MCTileEntity) extends ManagedComponent {
|
||||
if (remainingTicks <= 0 && inventory.isDefined) {
|
||||
val stack = inventory.get
|
||||
remainingTicks = TileEntityFurnace.getItemBurnTime(stack)
|
||||
if (remainingTicks > 0) updateClient()
|
||||
stack.stackSize -= 1
|
||||
if (stack.stackSize <= 0) {
|
||||
inventory = None
|
||||
@ -88,10 +89,16 @@ class Generator(val owner: MCTileEntity) extends ManagedComponent {
|
||||
}
|
||||
if (remainingTicks > 0) {
|
||||
remainingTicks -= 1
|
||||
if (remainingTicks == 0) updateClient()
|
||||
node.changeBuffer(Settings.get.ratioBuildCraft * Settings.get.generatorEfficiency)
|
||||
}
|
||||
}
|
||||
|
||||
private def updateClient() = owner match {
|
||||
case robot: RobotContext => robot.saveUpgrade()
|
||||
case _ =>
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def onDisconnect(node: Node) {
|
||||
@ -127,10 +134,14 @@ class Generator(val owner: MCTileEntity) extends ManagedComponent {
|
||||
inventory match {
|
||||
case Some(stack) =>
|
||||
nbt.setNewCompoundTag("inventory", stack.writeToNBT)
|
||||
nbt.setInteger("remainingTicks", remainingTicks)
|
||||
case _ =>
|
||||
nbt.removeTag("inventory")
|
||||
nbt.removeTag("remainingTicks")
|
||||
}
|
||||
if (remainingTicks > 0) {
|
||||
nbt.setInteger("remainingTicks", remainingTicks)
|
||||
}
|
||||
else {
|
||||
nbt.removeTag("remainingTicks")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte
|
||||
|
||||
def player = robot.player()
|
||||
|
||||
def saveUpgrade() = robot.saveUpgrade()
|
||||
|
||||
@LuaCallback(value = "level", direct = true)
|
||||
def level(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
result(robot.level + robot.xp / robot.xpForNextLevel)
|
||||
|
Loading…
x
Reference in New Issue
Block a user