Finalized new robot upgrade rendering implementation.

Added rendering for inventory upgrade.
This commit is contained in:
Florian Nücke 2014-05-30 16:07:15 +02:00
parent d3da20e150
commit 06e0bda2d6
14 changed files with 264 additions and 297 deletions

View File

@ -1,14 +1,15 @@
package li.cil.oc.api.event;
import li.cil.oc.api.machine.Robot;
import net.minecraft.util.Vec3;
import net.minecraftforge.event.Cancelable;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;
/**
* Fired directly before the robot's chassis is rendered.
* <p/>
* If this event is canceled, the chassis will <em>not</em> be rendered.
* Component items' item renderes will still be invoked, at the possibly
* Component items' item renderers will still be invoked, at the possibly
* modified mount points.
* <p/>
* <em>Important</em>: the robot instance may be null in this event, in
@ -40,12 +41,21 @@ public class RobotRenderEvent extends RobotEvent {
public static class MountPoint {
/**
* The position of the mount point, relative to the robot's center.
* For the purposes of this offset, the robot is always facing south,
* i.e. the positive Z axis is 'forward'.
* <p/>
* Note that the rotation is applied <em>before</em> the translation.
*/
public final Vec3 offset = Vec3.createVectorHelper(0, 0, 0);
public final Vector3f offset = new Vector3f(0, 0, 0);
/**
* The vector the mount point is facing.
* The orientation of the mount point specified by the angle and the
* vector to rotate around. The rotation is applied in one
* GL11.glRotate() call. Note that the <tt>W</tt> component of the
* vector is the rotation.
* <p/>
* Note that the rotation is applied <em>before</em> the translation.
*/
public final Vec3 normal = Vec3.createVectorHelper(0, 0, 0);
public final Vector4f rotation = new Vector4f(0, 0, 0, 0);
}
}

View File

@ -99,20 +99,21 @@ public interface Robot extends ISidedInventory, Rotatable {
int selectedSlot();
/**
* Causes the currently installed upgrade to be saved and synchronized.
* Sends the state of the <em>item</em> in the specified slot to the client
* if it is an upgrade.
* <p/>
* If no upgrade is installed in the robot this does nothing.
* Use this to update the state of an upgrade in that slot for rendering
* purposes (e.g. this is used by the generator upgrade to update the
* active state so the renderer knows which texture to use).
* <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.
* This is necessary because inventories are not synchronized by default,
* only if a player is currently 'looking into' the inventory (opened the
* GUI of the inventory).
* <p/>
* This is somewhat of a 'meh, it works' approach that I'm not really happy
* with and plan to replace with something cleaner. Don't use unless you
* absolutely really have to.
* The component will be saved to its item's NBT tag compound, as it would
* be when the game is saved, and then the item is re-sent to the client.
* Keep the number of calls to this function low, since each call causes a
* network packet to be sent.
*/
@Deprecated
void saveUpgrade();
void synchronizeSlot(int slot);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 998 B

View File

@ -40,8 +40,7 @@ class PacketHandler extends CommonPacketHandler {
case PacketType.RobotAnimateSwing => onRobotAnimateSwing(p)
case PacketType.RobotAnimateTurn => onRobotAnimateTurn(p)
case PacketType.RobotAssemblingState => onRobotAssemblingState(p)
case PacketType.RobotEquippedItemChange => onRobotEquippedItemChange(p)
case PacketType.RobotEquippedUpgradeChange => onRobotEquippedUpgradeChange(p)
case PacketType.RobotInventoryChange => onRobotInventoryChange(p)
case PacketType.RobotMove => onRobotMove(p)
case PacketType.RobotSelectedSlotChange => onRobotSelectedSlotChange(p)
case PacketType.RotatableState => onRotatableState(p)
@ -213,15 +212,16 @@ class PacketHandler extends CommonPacketHandler {
case _ => // Invalid packet.
}
def onRobotEquippedItemChange(p: PacketParser) =
def onRobotInventoryChange(p: PacketParser) =
p.readTileEntity[RobotProxy]() match {
case Some(t) => t.robot.equippedItem = Option(p.readItemStack())
case _ => // Invalid packet.
}
def onRobotEquippedUpgradeChange(p: PacketParser) =
p.readTileEntity[RobotProxy]() match {
case Some(t) => t.robot.equippedUpgrade = Option(p.readItemStack())
case Some(t) =>
val robot = t.robot
val slot = p.readInt()
val stack = p.readItemStack()
if (slot >= robot.getSizeInventory - robot.componentCount) {
robot.info.components(slot - (robot.getSizeInventory - robot.componentCount)) = stack
}
else t.robot.setInventorySlotContents(slot, stack)
case _ => // Invalid packet.
}

View File

@ -33,6 +33,7 @@ object Textures extends ResourceManagerReloadListener {
val upgradeCrafting = new ResourceLocation(Settings.resourceDomain, "textures/items/upgrade_crafting_equipped.png")
val upgradeGenerator = new ResourceLocation(Settings.resourceDomain, "textures/items/upgrade_generator_equipped.png")
val upgradeInventory = new ResourceLocation(Settings.resourceDomain, "textures/items/upgrade_inventory_equipped.png")
object Charger {
var iconFrontCharging: Icon = _

View File

@ -12,9 +12,13 @@ import net.minecraftforge.client.IItemRenderer.{ItemRendererHelper, ItemRenderTy
import org.lwjgl.opengl.GL11
object UpgradeRenderer extends IItemRenderer {
val bounds = AxisAlignedBB.getBoundingBox(-0.1, -0.1, -0.1, 0.1, 0.1, 0.1)
override def handleRenderType(stack: ItemStack, renderType: ItemRenderType) = renderType == ItemRenderType.EQUIPPED && {
val descriptor = api.Items.get(stack)
descriptor == api.Items.get("craftingUpgrade") || descriptor == api.Items.get("generatorUpgrade")
descriptor == api.Items.get("craftingUpgrade") ||
descriptor == api.Items.get("generatorUpgrade") ||
descriptor == api.Items.get("inventoryUpgrade")
}
override def shouldUseRenderHelper(renderType: ItemRenderType, stack: ItemStack, helper: ItemRendererHelper) =
@ -25,93 +29,65 @@ object UpgradeRenderer extends IItemRenderer {
override def renderItem(renderType: ItemRenderType, stack: ItemStack, data: AnyRef*) {
val descriptor = api.Items.get(stack)
val tm = Minecraft.getMinecraft.getTextureManager
val t = Tessellator.instance
// Revert offset introduced by the render "helper".
GL11.glTranslatef(0.5f, 0.5f, 0.5f)
if (descriptor == api.Items.get("craftingUpgrade")) {
// TODO display list?
val b = AxisAlignedBB.getAABBPool.getAABB(0.4, 0.2, 0.64, 0.6, 0.4, 0.84)
tm.bindTexture(Textures.upgradeCrafting)
// Front.
t.startDrawingQuads()
t.addVertexWithUV(b.minX, b.minY, b.maxZ, 0, 0.5)
t.addVertexWithUV(b.maxX, b.minY, b.maxZ, 0.5, 0.5)
t.addVertexWithUV(b.maxX, b.maxY, b.maxZ, 0.5, 0)
t.addVertexWithUV(b.minX, b.maxY, b.maxZ, 0, 0)
t.setNormal(0, 0, 1)
t.draw()
// Bottom.
t.startDrawingQuads()
t.addVertexWithUV(b.minX, b.minY, b.maxZ, 0.5, 0.5)
t.addVertexWithUV(b.minX, b.minY, b.minZ, 0.5, 1)
t.addVertexWithUV(b.maxX, b.minY, b.minZ, 1, 1)
t.addVertexWithUV(b.maxX, b.minY, b.maxZ, 1, 0.5)
t.setNormal(0, -1, 0)
t.draw()
// Left.
t.startDrawingQuads()
t.addVertexWithUV(b.maxX, b.maxY, b.maxZ, 0, 0.5)
t.addVertexWithUV(b.maxX, b.minY, b.maxZ, 0, 1)
t.addVertexWithUV(b.maxX, b.minY, b.minZ, 0.5, 1)
t.addVertexWithUV(b.maxX, b.maxY, b.minZ, 0.5, 0.5)
t.setNormal(1, 0, 0)
t.draw()
// Right.
t.startDrawingQuads()
t.addVertexWithUV(b.minX, b.minY, b.maxZ, 0, 1)
t.addVertexWithUV(b.minX, b.maxY, b.maxZ, 0, 0.5)
t.addVertexWithUV(b.minX, b.maxY, b.minZ, 0.5, 0.5)
t.addVertexWithUV(b.minX, b.minY, b.minZ, 0.5, 1)
t.setNormal(-1, 0, 0)
t.draw()
drawSimpleBlock()
}
else if (descriptor == api.Items.get("generatorUpgrade")) {
// TODO display lists?
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(Textures.upgradeGenerator)
drawSimpleBlock(if (Item.dataTag(stack).getInteger("remainingTicks") > 0) 0.5 else 0)
}
// Back.
t.startDrawingQuads()
t.addVertexWithUV(b.minX, b.minY, b.minZ, onOffset, 0.5)
t.addVertexWithUV(b.minX, b.maxY, b.minZ, onOffset, 0)
t.addVertexWithUV(b.maxX, b.maxY, b.minZ, onOffset + 0.5, 0)
t.addVertexWithUV(b.maxX, b.minY, b.minZ, onOffset + 0.5, 0.5)
t.setNormal(0, 0, -1)
t.draw()
// Bottom.
t.startDrawingQuads()
t.addVertexWithUV(b.minX, b.minY, b.minZ, 0.5, 0.5)
t.addVertexWithUV(b.maxX, b.minY, b.minZ, 1, 0.5)
t.addVertexWithUV(b.maxX, b.minY, b.maxZ, 1, 1)
t.addVertexWithUV(b.minX, b.minY, b.maxZ, 0.5, 1)
t.setNormal(0, -1, 0)
t.draw()
// Left.
t.startDrawingQuads()
t.addVertexWithUV(b.maxX, b.minY, b.minZ, 0, 1)
t.addVertexWithUV(b.maxX, b.maxY, b.minZ, 0, 0.5)
t.addVertexWithUV(b.maxX, b.maxY, b.maxZ, 0.5, 0.5)
t.addVertexWithUV(b.maxX, b.minY, b.maxZ, 0.5, 1)
t.setNormal(1, 0, 0)
t.draw()
// Right.
t.startDrawingQuads()
t.addVertexWithUV(b.minX, b.minY, b.minZ, 0, 1)
t.addVertexWithUV(b.minX, b.minY, b.maxZ, 0.5, 1)
t.addVertexWithUV(b.minX, b.maxY, b.maxZ, 0.5, 0.5)
t.addVertexWithUV(b.minX, b.maxY, b.minZ, 0, 0.5)
t.setNormal(-1, 0, 0)
t.draw()
else if (descriptor == api.Items.get("inventoryUpgrade")) {
tm.bindTexture(Textures.upgradeInventory)
drawSimpleBlock()
}
}
private def drawSimpleBlock(frontOffset: Double = 0) {
val t = Tessellator.instance
t.startDrawingQuads()
// Front.
t.setNormal(0, 0, 1)
t.addVertexWithUV(bounds.minX, bounds.minY, bounds.maxZ, frontOffset, 0.5)
t.addVertexWithUV(bounds.maxX, bounds.minY, bounds.maxZ, frontOffset + 0.5, 0.5)
t.addVertexWithUV(bounds.maxX, bounds.maxY, bounds.maxZ, frontOffset + 0.5, 0)
t.addVertexWithUV(bounds.minX, bounds.maxY, bounds.maxZ, frontOffset, 0)
// Top.
t.setNormal(0, 1, 0)
t.addVertexWithUV(bounds.maxX, bounds.maxY, bounds.maxZ, 1, 0.5)
t.addVertexWithUV(bounds.maxX, bounds.maxY, bounds.minZ, 1, 1)
t.addVertexWithUV(bounds.minX, bounds.maxY, bounds.minZ, 0.5, 1)
t.addVertexWithUV(bounds.minX, bounds.maxY, bounds.maxZ, 0.5, 0.5)
// Bottom.
t.setNormal(0, -1, 0)
t.addVertexWithUV(bounds.minX, bounds.minY, bounds.maxZ, 0.5, 0.5)
t.addVertexWithUV(bounds.minX, bounds.minY, bounds.minZ, 0.5, 1)
t.addVertexWithUV(bounds.maxX, bounds.minY, bounds.minZ, 1, 1)
t.addVertexWithUV(bounds.maxX, bounds.minY, bounds.maxZ, 1, 0.5)
// Left.
t.setNormal(1, 0, 0)
t.addVertexWithUV(bounds.maxX, bounds.maxY, bounds.maxZ, 0, 0.5)
t.addVertexWithUV(bounds.maxX, bounds.minY, bounds.maxZ, 0, 1)
t.addVertexWithUV(bounds.maxX, bounds.minY, bounds.minZ, 0.5, 1)
t.addVertexWithUV(bounds.maxX, bounds.maxY, bounds.minZ, 0.5, 0.5)
// Right.
t.setNormal(-1, 0, 0)
t.addVertexWithUV(bounds.minX, bounds.minY, bounds.maxZ, 0, 1)
t.addVertexWithUV(bounds.minX, bounds.maxY, bounds.maxZ, 0, 0.5)
t.addVertexWithUV(bounds.minX, bounds.maxY, bounds.minZ, 0.5, 0.5)
t.addVertexWithUV(bounds.minX, bounds.minY, bounds.minZ, 0.5, 1)
t.draw()
}
}

View File

@ -107,59 +107,68 @@ object RobotRenderer extends TileEntitySpecialRenderer {
compileList()
def resetMountPoints() {
// Back.
mountPoints(0).offset.xCoord = 0
mountPoints(0).offset.yCoord = 0.33
mountPoints(0).offset.zCoord = -0.33
mountPoints(0).normal.xCoord = 0
mountPoints(0).normal.yCoord = 0
mountPoints(0).normal.zCoord = -1
def resetMountPoints(running: Boolean) {
val offset = if (running) 0 else -0.06f
mountPoints(0).offset.xCoord = 0
mountPoints(0).offset.yCoord = -0.33
mountPoints(0).offset.zCoord = -0.33
mountPoints(0).normal.xCoord = 0
mountPoints(0).normal.yCoord = 0
mountPoints(0).normal.zCoord = -1
// Back.
mountPoints(0).offset.setX(0)
mountPoints(0).offset.setY(-0.2f)
mountPoints(0).offset.setZ(0.24f)
mountPoints(0).rotation.setX(0)
mountPoints(0).rotation.setY(1)
mountPoints(0).rotation.setZ(0)
mountPoints(0).rotation.setW(180)
mountPoints(1).offset.setX(0)
mountPoints(1).offset.setY(0.2f + offset)
mountPoints(1).offset.setZ(0.24f)
mountPoints(1).rotation.setX(0)
mountPoints(1).rotation.setY(1)
mountPoints(1).rotation.setZ(0)
mountPoints(1).rotation.setW(180)
// Front.
mountPoints(0).offset.xCoord = 0
mountPoints(0).offset.yCoord = -0.33
mountPoints(0).offset.zCoord = 0.33
mountPoints(0).normal.xCoord = 0
mountPoints(0).normal.yCoord = 0
mountPoints(0).normal.zCoord = 1
mountPoints(2).offset.setX(0)
mountPoints(2).offset.setY(-0.2f)
mountPoints(2).offset.setZ(0.24f)
mountPoints(2).rotation.setX(0)
mountPoints(2).rotation.setY(1)
mountPoints(2).rotation.setZ(0)
mountPoints(2).rotation.setW(0)
// Left.
mountPoints(0).offset.xCoord = -0.33
mountPoints(0).offset.yCoord = 0.33
mountPoints(0).offset.zCoord = 0
mountPoints(0).normal.xCoord = -1
mountPoints(0).normal.yCoord = 0
mountPoints(0).normal.zCoord = 0
mountPoints(3).offset.setX(0)
mountPoints(3).offset.setY(-0.2f)
mountPoints(3).offset.setZ(0.24f)
mountPoints(3).rotation.setX(0)
mountPoints(3).rotation.setY(1)
mountPoints(3).rotation.setZ(0)
mountPoints(3).rotation.setW(90)
mountPoints(0).offset.xCoord = -0.33
mountPoints(0).offset.yCoord = -0.33
mountPoints(0).offset.zCoord = 0
mountPoints(0).normal.xCoord = -1
mountPoints(0).normal.yCoord = 0
mountPoints(0).normal.zCoord = 0
mountPoints(4).offset.setX(0)
mountPoints(4).offset.setY(0.2f + offset)
mountPoints(4).offset.setZ(0.24f)
mountPoints(4).rotation.setX(0)
mountPoints(4).rotation.setY(1)
mountPoints(4).rotation.setZ(0)
mountPoints(4).rotation.setW(90)
// Right.
mountPoints(0).offset.xCoord = 0.33
mountPoints(0).offset.yCoord = 0.33
mountPoints(0).offset.zCoord = 0
mountPoints(0).normal.xCoord = 1
mountPoints(0).normal.yCoord = 0
mountPoints(0).normal.zCoord = 0
mountPoints(5).offset.setX(0)
mountPoints(5).offset.setY(-0.2f)
mountPoints(5).offset.setZ(0.24f)
mountPoints(5).rotation.setX(0)
mountPoints(5).rotation.setY(1)
mountPoints(5).rotation.setZ(0)
mountPoints(5).rotation.setW(-90)
mountPoints(0).offset.xCoord = 0.33
mountPoints(0).offset.yCoord = -0.33
mountPoints(0).offset.zCoord = 0
mountPoints(0).normal.xCoord = 1
mountPoints(0).normal.yCoord = 0
mountPoints(0).normal.zCoord = 0
mountPoints(6).offset.setX(0)
mountPoints(6).offset.setY(0.2f + offset)
mountPoints(6).offset.setZ(0.24f)
mountPoints(6).rotation.setX(0)
mountPoints(6).rotation.setY(1)
mountPoints(6).rotation.setZ(0)
mountPoints(6).rotation.setW(-90)
}
def renderChassis(robot: tileentity.Robot = null, offset: Double = 0) {
@ -178,7 +187,7 @@ object RobotRenderer extends TileEntitySpecialRenderer {
(0.25f - vStep, 0.25f + vStep, 0.75f - vStep, 0.75f + vStep)
}
resetMountPoints()
resetMountPoints(robot != null && robot.isRunning)
val event = new RobotRenderEvent(robot, mountPoints)
MinecraftForge.EVENT_BUS.post(event)
if (!event.isCanceled) {
@ -283,115 +292,120 @@ object RobotRenderer extends TileEntitySpecialRenderer {
renderChassis(robot, offset)
}
robot.equippedItem match {
case Some(stack) =>
val player = robot.player()
val itemRenderer = RenderManager.instance.itemRenderer
if (!robot.renderingErrored) {
Option(robot.getStackInSlot(0)) match {
case Some(stack) =>
val player = robot.player()
val itemRenderer = RenderManager.instance.itemRenderer
GL11.glPushMatrix()
try {
// Copy-paste from player render code, with minor adjustments for
// robot scale.
GL11.glPushMatrix()
try {
// Copy-paste from player render code, with minor adjustments for
// robot scale.
GL11.glDisable(GL11.GL_CULL_FACE)
GL11.glEnable(GL12.GL_RESCALE_NORMAL)
GL11.glDisable(GL11.GL_CULL_FACE)
GL11.glEnable(GL12.GL_RESCALE_NORMAL)
GL11.glScalef(1, -1, -1)
GL11.glTranslatef(0, -8 * 0.0625F - 0.0078125F, -0.5F)
GL11.glScalef(1, -1, -1)
GL11.glTranslatef(0, -8 * 0.0625F - 0.0078125F, -0.5F)
if (robot.isAnimatingSwing) {
val remaining = (robot.animationTicksLeft - f) / robot.animationTicksTotal.toDouble
GL11.glRotatef((Math.sin(remaining * Math.PI) * 45).toFloat, 1, 0, 0)
}
val customRenderer = MinecraftForgeClient.getItemRenderer(stack, EQUIPPED)
val is3D = customRenderer != null && customRenderer.shouldUseRenderHelper(EQUIPPED, stack, BLOCK_3D)
val isBlock = stack.itemID < Block.blocksList.length && stack.getItemSpriteNumber == 0
if (is3D || (isBlock && RenderBlocks.renderItemIn3d(Block.blocksList(stack.itemID).getRenderType))) {
val scale = 0.375f
GL11.glTranslatef(0, 0.1875f, -0.3125f)
GL11.glRotatef(20, 1, 0, 0)
GL11.glRotatef(45, 0, 1, 0)
GL11.glScalef(-scale, -scale, scale)
}
else if (stack.itemID == Item.bow.itemID) {
val scale = 0.375f
GL11.glTranslatef(0, 0.2f, -0.2f)
GL11.glRotatef(-10, 0, 1, 0)
GL11.glScalef(scale, -scale, scale)
GL11.glRotatef(-20, 1, 0, 0)
GL11.glRotatef(45, 0, 1, 0)
}
else if (Item.itemsList(stack.itemID).isFull3D) {
val scale = 0.375f
if (Item.itemsList(stack.itemID).shouldRotateAroundWhenRendering) {
GL11.glRotatef(180, 0, 0, 1)
GL11.glTranslatef(0, -0.125f, 0)
if (robot.isAnimatingSwing) {
val remaining = (robot.animationTicksLeft - f) / robot.animationTicksTotal.toDouble
GL11.glRotatef((Math.sin(remaining * Math.PI) * 45).toFloat, 1, 0, 0)
}
GL11.glTranslatef(0, 0.1f, 0)
GL11.glScalef(scale, -scale, scale)
GL11.glRotatef(-100, 1, 0, 0)
GL11.glRotatef(45, 0, 1, 0)
}
else {
val scale = 0.375f
GL11.glTranslatef(0.25f, 0.1875f, -0.1875f)
GL11.glScalef(scale, scale, scale)
GL11.glRotatef(60, 0, 0, 1)
GL11.glRotatef(-90, 1, 0, 0)
GL11.glRotatef(20, 0, 0, 1)
}
if (stack.getItem.requiresMultipleRenderPasses) {
for (pass <- 0 until stack.getItem.getRenderPasses(stack.getItemDamage)) {
val tint = stack.getItem.getColorFromItemStack(stack, pass)
val customRenderer = MinecraftForgeClient.getItemRenderer(stack, EQUIPPED)
val is3D = customRenderer != null && customRenderer.shouldUseRenderHelper(EQUIPPED, stack, BLOCK_3D)
val isBlock = stack.itemID < Block.blocksList.length && stack.getItemSpriteNumber == 0
if (is3D || (isBlock && RenderBlocks.renderItemIn3d(Block.blocksList(stack.itemID).getRenderType))) {
val scale = 0.375f
GL11.glTranslatef(0, 0.1875f, -0.3125f)
GL11.glRotatef(20, 1, 0, 0)
GL11.glRotatef(45, 0, 1, 0)
GL11.glScalef(-scale, -scale, scale)
}
else if (stack.itemID == Item.bow.itemID) {
val scale = 0.375f
GL11.glTranslatef(0, 0.2f, -0.2f)
GL11.glRotatef(-10, 0, 1, 0)
GL11.glScalef(scale, -scale, scale)
GL11.glRotatef(-20, 1, 0, 0)
GL11.glRotatef(45, 0, 1, 0)
}
else if (Item.itemsList(stack.itemID).isFull3D) {
val scale = 0.375f
if (Item.itemsList(stack.itemID).shouldRotateAroundWhenRendering) {
GL11.glRotatef(180, 0, 0, 1)
GL11.glTranslatef(0, -0.125f, 0)
}
GL11.glTranslatef(0, 0.1f, 0)
GL11.glScalef(scale, -scale, scale)
GL11.glRotatef(-100, 1, 0, 0)
GL11.glRotatef(45, 0, 1, 0)
}
else {
val scale = 0.375f
GL11.glTranslatef(0.25f, 0.1875f, -0.1875f)
GL11.glScalef(scale, scale, scale)
GL11.glRotatef(60, 0, 0, 1)
GL11.glRotatef(-90, 1, 0, 0)
GL11.glRotatef(20, 0, 0, 1)
}
if (stack.getItem.requiresMultipleRenderPasses) {
for (pass <- 0 until stack.getItem.getRenderPasses(stack.getItemDamage)) {
val tint = stack.getItem.getColorFromItemStack(stack, pass)
val r = ((tint >> 16) & 0xFF) / 255f
val g = ((tint >> 8) & 0xFF) / 255f
val b = ((tint >> 0) & 0xFF) / 255f
GL11.glColor4f(r, g, b, 1)
itemRenderer.renderItem(player, stack, pass)
}
}
else {
val tint = stack.getItem.getColorFromItemStack(stack, 0)
val r = ((tint >> 16) & 0xFF) / 255f
val g = ((tint >> 8) & 0xFF) / 255f
val b = ((tint >> 0) & 0xFF) / 255f
GL11.glColor4f(r, g, b, 1)
itemRenderer.renderItem(player, stack, pass)
itemRenderer.renderItem(player, stack, 0)
}
}
else {
val tint = stack.getItem.getColorFromItemStack(stack, 0)
val r = ((tint >> 16) & 0xFF) / 255f
val g = ((tint >> 8) & 0xFF) / 255f
val b = ((tint >> 0) & 0xFF) / 255f
GL11.glColor4f(r, g, b, 1)
itemRenderer.renderItem(player, stack, 0)
catch {
case e: Throwable =>
OpenComputers.log.log(Level.WARNING, "Failed rendering equipped item.", e)
robot.renderingErrored = true
}
}
catch {
case e: Throwable =>
OpenComputers.log.log(Level.WARNING, "Failed rendering equipped item.", e)
robot.equippedItem = None
}
GL11.glEnable(GL11.GL_CULL_FACE)
GL11.glDisable(GL12.GL_RESCALE_NORMAL)
GL11.glPopMatrix()
case _ =>
}
GL11.glEnable(GL11.GL_CULL_FACE)
GL11.glDisable(GL12.GL_RESCALE_NORMAL)
GL11.glPopMatrix()
case _ =>
}
robot.equippedUpgrade match {
case Some(stack) =>
val stacks = (robot.componentSlots ++ robot.containerSlots).map(robot.getStackInSlot).filter(stack => stack != null && MinecraftForgeClient.getItemRenderer(stack, ItemRenderType.EQUIPPED) != null).padTo(mountPoints.length, null).take(mountPoints.length)
for ((stack, mountPoint) <- stacks.zip(mountPoints)) {
try {
if (MinecraftForgeClient.getItemRenderer(stack, ItemRenderType.EQUIPPED) != null &&
(stack.getItem.requiresMultipleRenderPasses() || MinecraftForgeClient.getRenderPass == 0)) {
if (stack != null && (stack.getItem.requiresMultipleRenderPasses() || MinecraftForgeClient.getRenderPass == 0)) {
val tint = stack.getItem.getColorFromItemStack(stack, MinecraftForgeClient.getRenderPass)
val r = ((tint >> 16) & 0xFF) / 255f
val g = ((tint >> 8) & 0xFF) / 255f
val b = ((tint >> 0) & 0xFF) / 255f
GL11.glColor4f(r, g, b, 1)
GL11.glPushMatrix()
GL11.glTranslatef(0.5f, 0.5f, 0.5f)
GL11.glRotatef(mountPoint.rotation.getW, mountPoint.rotation.getX, mountPoint.rotation.getY, mountPoint.rotation.getZ)
GL11.glTranslatef(mountPoint.offset.getX, mountPoint.offset.getY, mountPoint.offset.getZ)
RenderManager.instance.itemRenderer.renderItem(robot.player(), stack, MinecraftForgeClient.getRenderPass)
GL11.glPopMatrix()
}
}
catch {
case e: Throwable =>
OpenComputers.log.log(Level.WARNING, "Failed rendering equipped upgrade.", e)
robot.equippedUpgrade = None
robot.renderingErrored = true
}
case _ =>
}
}
GL11.glPopMatrix()

View File

@ -20,8 +20,7 @@ object PacketType extends Enumeration {
RobotAnimateSwing,
RobotAnimateTurn,
RobotAssemblingState,
RobotEquippedItemChange,
RobotEquippedUpgradeChange,
RobotInventoryChange,
RobotMove,
RobotSelectedSlotChange,
RotatableState,

View File

@ -50,6 +50,9 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo
var selectedSlot = actualSlot(0)
// For client.
var renderingErrored = false
// Fixed number of containers (mostly due to GUI limitation, but also because
// I find three to be a large enough number for sufficient flexibility).
override def containerCount = 3
@ -60,15 +63,15 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo
override def player() = player(facing, facing)
override def saveUpgrade() = this.synchronized {
components(3) match {
case Some(environment) =>
val stack = getStackInSlot(3)
override def synchronizeSlot(slot: Int) = if (slot >= 0 && slot < getSizeInventory) this.synchronized {
val stack = getStackInSlot(slot)
components(slot) match {
case Some(component) =>
// We're guaranteed to have a driver for entries.
environment.save(dataTag(Driver.driverFor(stack), stack))
ServerPacketSender.sendRobotEquippedUpgradeChange(this, stack)
save(component, Driver.driverFor(stack), stack)
case _ =>
}
ServerPacketSender.sendRobotInventory(this, slot, stack)
}
def containerSlots = 1 to info.containers.length
@ -87,10 +90,6 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo
var owner = "OpenComputers"
var equippedItem: Option[ItemStack] = None
var equippedUpgrade: Option[ItemStack] = None
var animationTicksLeft = 0
var animationTicksTotal = 0
@ -350,17 +349,12 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo
@SideOnly(Side.CLIENT)
override def readFromNBTForClient(nbt: NBTTagCompound) {
super.readFromNBTForClient(nbt)
load(nbt)
info.load(nbt)
updateInventorySize()
selectedSlot = nbt.getInteger("selectedSlot")
if (nbt.hasKey("equipped")) {
equippedItem = Option(ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("equipped")))
}
if (nbt.hasKey("upgrade")) {
equippedUpgrade = Option(ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("upgrade")))
}
animationTicksTotal = nbt.getInteger("animationTicksTotal")
animationTicksLeft = nbt.getInteger("animationTicksLeft")
moveFromX = nbt.getInteger("moveFromX")
@ -375,24 +369,10 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo
override def writeToNBTForClient(nbt: NBTTagCompound) = this.synchronized {
super.writeToNBTForClient(nbt)
save(nbt)
info.save(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(Driver.driverFor(stack), stack))
case _ => // See onConnect()
}
nbt.setNewCompoundTag("upgrade", getStackInSlot(3).writeToNBT)
}
if (isAnimatingMove || isAnimatingSwing || isAnimatingTurn) {
nbt.setInteger("animationTicksTotal", animationTicksTotal)
nbt.setInteger("animationTicksLeft", animationTicksLeft)
@ -411,17 +391,6 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo
if (node == this.node) {
node.connect(bot.node)
node.asInstanceOf[Connector].setLocalBufferSize(0)
// There's a chance the server sends a robot tile entity to its clients
// before the tile entity's first update was called, in which case the
// component list isn't initialized (e.g. when a client triggers a chunk
// load, most noticeable in single player). In that case the current
// equipment will be initialized incorrectly. So we have to send it
// again when the first update is run. One of the two (this and the info
// sent in writeToNBTForClient) may be superfluous, but the packet is
// quite small compared to what else is sent on a chunk load, so we don't
// really worry about it and just send it.
saveUpgrade()
}
}
@ -442,10 +411,10 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo
if (isServer) {
if (isToolSlot(slot)) {
player_.getAttributeMap.applyAttributeModifiers(stack.getAttributeModifiers)
ServerPacketSender.sendRobotEquippedItemChange(this, getStackInSlot(slot))
ServerPacketSender.sendRobotInventory(this, slot, stack)
}
if (isUpgradeSlot(slot)) {
ServerPacketSender.sendRobotEquippedUpgradeChange(this, getStackInSlot(slot))
ServerPacketSender.sendRobotInventory(this, slot, stack)
}
if (isFloppySlot(slot)) {
common.Sound.playDiskInsert(this)
@ -464,10 +433,10 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo
if (isServer) {
if (isToolSlot(slot)) {
player_.getAttributeMap.removeAttributeModifiers(stack.getAttributeModifiers)
ServerPacketSender.sendRobotEquippedItemChange(this, null)
ServerPacketSender.sendRobotInventory(this, slot, null)
}
if (isUpgradeSlot(slot)) {
ServerPacketSender.sendRobotEquippedUpgradeChange(this, null)
ServerPacketSender.sendRobotInventory(this, slot, null)
}
if (isFloppySlot(slot)) {
common.Sound.playDiskEject(this)
@ -482,6 +451,7 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo
super.onInventoryChanged()
updateInventorySize()
updateMaxComponentCount()
renderingErrored = false
}
override protected def connectItemNode(node: Node) {

View File

@ -49,7 +49,7 @@ class RobotProxy(val robot: Robot) extends traits.Computer with traits.PowerInfo
override def selectedSlot() = robot.selectedSlot
override def saveUpgrade() = robot.saveUpgrade()
override def synchronizeSlot(slot: Int) = robot.synchronizeSlot(slot)
// ----------------------------------------------------------------------- //

View File

@ -192,19 +192,11 @@ object PacketSender {
pb.sendToNearbyPlayers(t, 64)
}
def sendRobotEquippedItemChange(t: tileentity.Robot, stack: ItemStack) {
val pb = new PacketBuilder(PacketType.RobotEquippedItemChange)
pb.writeTileEntity(t.proxy)
pb.writeItemStack(stack)
pb.sendToNearbyPlayers(t)
}
def sendRobotEquippedUpgradeChange(t: tileentity.Robot, stack: ItemStack) {
val pb = new PacketBuilder(PacketType.RobotEquippedUpgradeChange)
def sendRobotInventory(t: tileentity.Robot, slot: Int, stack: ItemStack) {
val pb = new PacketBuilder(PacketType.RobotInventoryChange)
pb.writeTileEntity(t.proxy)
pb.writeInt(slot)
pb.writeItemStack(stack)
pb.sendToNearbyPlayers(t)

View File

@ -25,6 +25,8 @@ class UpgradeGenerator(val owner: Container with Robot) extends component.Manage
var remainingTicks = 0
def slot = (0 until owner.getSizeInventory).indexWhere(owner.getComponentInSlot(_) == this)
// ----------------------------------------------------------------------- //
@Callback(doc = """function([count:number]):boolean -- Tries to insert fuel from the selected slot into the generator's queue.""")
@ -104,7 +106,7 @@ class UpgradeGenerator(val owner: Container with Robot) extends component.Manage
}
}
private def updateClient() = owner.saveUpgrade()
private def updateClient() = owner.synchronizeSlot(slot)
// ----------------------------------------------------------------------- //

View File

@ -27,7 +27,9 @@ object ExtendedNBT {
implicit def toNbt(value: ItemStack) = {
val nbt = new NBTTagCompound()
value.writeToNBT(nbt)
if (value != null) {
value.writeToNBT(nbt)
}
nbt
}

View File

@ -89,8 +89,8 @@ object ItemUtils {
)
containers = Array(
api.Items.get("cardContainer2").createItemStack(1),
api.Items.get("upgradeContainer3").createItemStack(1),
api.Items.get("diskDrive").createItemStack(1)
api.Items.get("diskDrive").createItemStack(1),
api.Items.get("upgradeContainer3").createItemStack(1)
)
robotEnergy = totalEnergy
}