diff --git a/src/main/java/li/cil/oc/api/driver/item/UpgradeRenderer.java b/src/main/java/li/cil/oc/api/driver/item/UpgradeRenderer.java index 313a63428..92ac8fc59 100644 --- a/src/main/java/li/cil/oc/api/driver/item/UpgradeRenderer.java +++ b/src/main/java/li/cil/oc/api/driver/item/UpgradeRenderer.java @@ -16,7 +16,42 @@ import net.minecraftforge.fml.relauncher.SideOnly; * checked for this interface, and if present, the {@link #render} method * is called. */ +@SideOnly(Side.CLIENT) public interface UpgradeRenderer { + /** + * The priority with which to render this upgrade. + *

+ * Upgrades with a higher priority are preferred for rendering over other + * upgrades. Upgrades with higher priorities will be rendered in the top + * slots, i.e. the assigned slot order is top then bottom. + *

+ * You usually won't need the robot parameter, but in case you do + * need some contextual information, this should provide you with anything + * you could need. + * + * @param stack the item stack of the upgrade to render. + * @param robot the robot the upgrade is rendered on. + * @return the priority with which to render the upgrade. + */ + int priority(ItemStack stack, Robot robot); + + /** + * Whether the upgrade can be rendered in the specified mount point. + *

+ * This is used to determine whether an upgrade can be rendered in a + * specific mount point, or not. Note that if the upgrade refuses to + * be rendered in the offered mount point, it will not be rendered at all, + * i.e. it will not be offered another mount point. To give the upgrade + * a better chance to get a usable mount point, specify an appropriate + * priority via {@link #priority}. + * + * @param stack the item stack of the upgrade to render. + * @param mountPoint the mount-point to render the upgrade at. + * @param robot the robot the upgrade is rendered on. + * @return whether the upgrade can be rendered in the specified mount point. + */ + boolean canRender(ItemStack stack, RobotRenderEvent.MountPoint mountPoint, Robot robot); + /** * Render the specified upgrade on a robot. *

@@ -27,8 +62,8 @@ public interface UpgradeRenderer { * center of the robot. This is what the offset of the mount-point is * relative to. *

- * If the stack cannot be rendered, simply do nothing. This way it's fine - * to implement this on a meta item. + * If the stack cannot be rendered, the renderer should indicate so in + * {@link #canRender}, otherwise it will still consume a mount point. *

* You usually won't need the robot parameter, but in case you do * need some contextual information, this should provide you with anything @@ -37,7 +72,7 @@ public interface UpgradeRenderer { * @param stack the item stack of the upgrade to render. * @param mountPoint the mount-point to render the upgrade at. * @param robot the robot the upgrade is rendered on. + * @param pt partial tick time, e.g. for animations. */ - @SideOnly(Side.CLIENT) - void render(ItemStack stack, RobotRenderEvent.MountPoint mountPoint, Robot robot); + void render(ItemStack stack, RobotRenderEvent.MountPoint mountPoint, Robot robot, float pt); } diff --git a/src/main/scala/li/cil/oc/client/renderer/item/UpgradeRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/item/UpgradeRenderer.scala index 6e0440601..790dec202 100644 --- a/src/main/scala/li/cil/oc/client/renderer/item/UpgradeRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/item/UpgradeRenderer.scala @@ -6,7 +6,6 @@ import li.cil.oc.api.event.RobotRenderEvent.MountPoint import li.cil.oc.client.Textures import li.cil.oc.integration.opencomputers.Item import li.cil.oc.util.RenderState -import net.minecraft.client.Minecraft import net.minecraft.item.ItemStack import net.minecraft.util.AxisAlignedBB import org.lwjgl.opengl.GL11 @@ -16,6 +15,20 @@ object UpgradeRenderer { lazy val generatorUpgrade = api.Items.get(Constants.ItemName.GeneratorUpgrade) lazy val inventoryUpgrade = api.Items.get(Constants.ItemName.InventoryUpgrade) + def priority(stack: ItemStack): Int = { + val descriptor = api.Items.get(stack) + + if (descriptor == craftingUpgrade) 5 + else if (descriptor == generatorUpgrade) 0 + else 10 + } + + def canRender(stack: ItemStack): Boolean = { + val descriptor = api.Items.get(stack) + + descriptor == craftingUpgrade || descriptor == generatorUpgrade || descriptor == inventoryUpgrade + } + def render(stack: ItemStack, mountPoint: MountPoint): Unit = { val descriptor = api.Items.get(stack) diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala index 449fe7781..d1b9c1d7e 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala @@ -121,33 +121,34 @@ object RobotRenderer extends TileEntitySpecialRenderer { def resetMountPoints(running: Boolean) { val offset = if (running) 0 else -0.06f - // Back. + // Left top. mountPoints(0).offset.setX(0) - mountPoints(0).offset.setY(-0.2f - offset) + 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(0).rotation.setW(90) + // Right top. mountPoints(1).offset.setX(0) mountPoints(1).offset.setY(0.2f) 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) + mountPoints(1).rotation.setW(-90) - // Front. + // Back top. mountPoints(2).offset.setX(0) - mountPoints(2).offset.setY(-0.2f - offset) + 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) + mountPoints(2).rotation.setW(180) - // Left. + // Left bottom. mountPoints(3).offset.setX(0) mountPoints(3).offset.setY(-0.2f - offset) mountPoints(3).offset.setZ(0.24f) @@ -156,30 +157,32 @@ object RobotRenderer extends TileEntitySpecialRenderer { mountPoints(3).rotation.setZ(0) mountPoints(3).rotation.setW(90) + // Right bottom. mountPoints(4).offset.setX(0) - mountPoints(4).offset.setY(0.2f) + 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) + mountPoints(4).rotation.setW(-90) - // Right. + // Back bottom. mountPoints(5).offset.setX(0) mountPoints(5).offset.setY(-0.2f - offset) 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(5).rotation.setW(180) + // Front bottom. mountPoints(6).offset.setX(0) - mountPoints(6).offset.setY(0.2f) + 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) + mountPoints(6).rotation.setW(0) } def renderChassis(robot: tileentity.Robot = null, offset: Double = 0, isRunningOverride: Boolean = false) { @@ -379,16 +382,24 @@ object RobotRenderer extends TileEntitySpecialRenderer { } if (MinecraftForgeClient.getRenderPass == 0) { + var filterMount = 0 + //noinspection SortFilter We need to sort before we filter, because the filter is index sensitive. val stacks = (robot.componentSlots ++ robot.containerSlots).map(robot.getStackInSlot). - filter(stack => stack != null && stack.getItem.isInstanceOf[UpgradeRenderer]). - take(mountPoints.length) - for ((stack, mountPoint) <- stacks.zip(mountPoints.take(stacks.length))) try stack.getItem match { - case renderer: UpgradeRenderer => - RenderState.pushMatrix() - GL11.glTranslatef(0.5f, 0.5f, 0.5f) - renderer.render(stack, mountPoint, robot) - RenderState.popMatrix() - case _ => + collect { case stack if stack != null && stack.getItem.isInstanceOf[UpgradeRenderer] => (stack, stack.getItem.asInstanceOf[UpgradeRenderer]) }. + sortBy { case (stack, renderer) => -renderer.priority(stack, robot) }. + filter { + case (stack, renderer) if filterMount < mountPoints.length && renderer.canRender(stack, mountPoints(filterMount), robot) => + filterMount += 1 + true + case _ => false + } + + val minLength = math.min(mountPoints.length, stacks.length) + for (((stack, renderer), mountPoint) <- (stacks.take(minLength), mountPoints.take(minLength)).zipped) try { + RenderState.pushMatrix() + GL11.glTranslatef(0.5f, 0.5f, 0.5f) + renderer.render(stack, mountPoint, robot, f) + RenderState.popMatrix() } catch { case e: Throwable => diff --git a/src/main/scala/li/cil/oc/common/item/Delegator.scala b/src/main/scala/li/cil/oc/common/item/Delegator.scala index c6696db28..e01b00507 100644 --- a/src/main/scala/li/cil/oc/common/item/Delegator.scala +++ b/src/main/scala/li/cil/oc/common/item/Delegator.scala @@ -217,6 +217,9 @@ class Delegator extends Item with driver.item.UpgradeRenderer { // ----------------------------------------------------------------------- // - @SideOnly(Side.CLIENT) - def render(stack: ItemStack, mountPoint: MountPoint, robot: Robot): Unit = UpgradeRenderer.render(stack, mountPoint) + def priority(stack: ItemStack, robot: Robot): Int = UpgradeRenderer.priority(stack) + + def canRender(stack: ItemStack, mountPoint: MountPoint, robot: Robot): Boolean = UpgradeRenderer.canRender(stack) + + def render(stack: ItemStack, mountPoint: MountPoint, robot: Robot, pt: Float): Unit = UpgradeRenderer.render(stack, mountPoint) }