blob: 53b3d6977453c5613e040d39bb5b1af369d66700 [file] [log] [blame] [raw]
package li.cil.oc.client.renderer
import java.util.concurrent.Callable
import java.util.concurrent.TimeUnit
import com.google.common.cache.CacheBuilder
import cpw.mods.fml.common.eventhandler.EventPriority
import cpw.mods.fml.common.eventhandler.SubscribeEvent
import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent
import li.cil.oc.api.event.RobotRenderEvent
import li.cil.oc.client.renderer.tileentity.RobotRenderer
import net.minecraft.client.Minecraft
import net.minecraft.entity.Entity
import net.minecraftforge.client.event.RenderPlayerEvent
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL12
import scala.collection.convert.WrapAsScala._
import scala.collection.mutable
object PetRenderer {
val hidden = mutable.Set.empty[String]
var isInitialized = false
// http://goo.gl/frLWYR
private val entitledPlayers = Map(
"9f1f262f-0d68-4e13-9161-9eeaf4a0a1a8" ->(0.3, 0.9, 0.6), // Sangar
"18f8bed4-f027-44af-8947-6a3a2317645a" ->(1.0, 0.0, 0.0), // Jodarion
"36123742-2cf6-4cfc-8b65-278581b3caeb" ->(0.5, 0.7, 1.0), // DaKaTotal
"2c0c214b-96f4-4565-b513-de90d5fbc977" ->(1.0, 0.0, 0.0), // MichiRavencroft
"f3ba6ec8-c280-4950-bb08-1fcb2eab3a9c" ->(0.18, 0.95, 0.922), // Vexatos
"9d636bdd-b9f4-4b80-b9ce-586ca04bd4f3" ->(0.8, 0.77, 0.75), // StoneNomad
"23c7ed71-fb13-4abe-abe7-f355e1de6e62" ->(0.3, 0.3, 1.0), // LizzyTheSiren
"076541f1-f10a-46de-a127-dfab8adfbb75" ->(0.2, 1.0, 0.1), // vifino
"e7e90198-0ccf-4662-a827-192ec8f4419d" ->(0.0, 0.2, 0.6), // Izaya
"f514ee69-7bbb-4e46-9e94-d8176324cec2" ->(0.098, 0.471, 0.784) // Wobbo
)
private val petLocations = com.google.common.cache.CacheBuilder.newBuilder().
expireAfterAccess(5, TimeUnit.SECONDS).
asInstanceOf[CacheBuilder[Entity, PetLocation]].
build[Entity, PetLocation]()
private var rendering: Option[(Double, Double, Double)] = None
@SubscribeEvent
def onPlayerRender(e: RenderPlayerEvent.Pre) {
val uuid = e.entityPlayer.getUniqueID.toString
if (hidden.contains(uuid) || !entitledPlayers.contains(uuid)) return
rendering = Some(entitledPlayers(uuid))
val worldTime = e.entityPlayer.getEntityWorld.getTotalWorldTime
val timeJitter = e.entityPlayer.hashCode ^ 0xFF
val offset = timeJitter + worldTime / 20.0
val hover = (math.sin(timeJitter + (worldTime + e.partialRenderTick) / 20.0) * 0.03).toFloat
val location = petLocations.get(e.entityPlayer, new Callable[PetLocation] {
override def call() = new PetLocation(e.entityPlayer)
})
GL11.glPushMatrix()
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS)
if (e.entityPlayer != Minecraft.getMinecraft.thePlayer) {
val localPos = Minecraft.getMinecraft.thePlayer.getPosition(e.partialRenderTick)
val playerPos = e.entityPlayer.getPosition(e.partialRenderTick)
val correction = 1.62 - (if (e.entityPlayer.isSneaking) 0.125 else 0)
GL11.glTranslated(
playerPos.xCoord - localPos.xCoord,
playerPos.yCoord - localPos.yCoord + correction,
playerPos.zCoord - localPos.zCoord)
}
GL11.glEnable(GL11.GL_LIGHTING)
GL11.glDisable(GL11.GL_BLEND)
GL11.glEnable(GL12.GL_RESCALE_NORMAL)
GL11.glColor4f(1, 1, 1, 1)
location.applyInterpolatedTransformations(e.partialRenderTick)
GL11.glScalef(0.3f, 0.3f, 0.3f)
GL11.glTranslatef(0, hover, 0)
RobotRenderer.renderChassis(null, offset, isRunningOverride = true)
GL11.glPopAttrib()
GL11.glPopMatrix()
rendering = None
}
@SubscribeEvent(priority = EventPriority.LOWEST)
def onRobotRender(e: RobotRenderEvent) {
rendering match {
case Some((r, g, b)) => GL11.glColor3d(r, g, b)
case _ =>
}
}
private class PetLocation(val owner: Entity) {
var x = 0.0
var y = 0.0
var z = 0.0
var yaw = owner.rotationYaw
var lastX = x
var lastY = y
var lastZ = z
var lastYaw = yaw
def update() {
val dx = owner.lastTickPosX - owner.posX
val dy = owner.lastTickPosY - owner.posY
val dz = owner.lastTickPosZ - owner.posZ
val dYaw = owner.rotationYaw - yaw
lastX = x
lastY = y
lastZ = z
lastYaw = yaw
x += dx
y += dy
z += dz
x *= 0.05
y *= 0.05
z *= 0.05
yaw += dYaw * 0.2f
}
def applyInterpolatedTransformations(dt: Float) {
val ix = lastX + (x - lastX) * dt
val iy = lastY + (y - lastY) * dt
val iz = lastZ + (z - lastZ) * dt
val iYaw = lastYaw + (yaw - lastYaw) * dt
GL11.glTranslated(ix, iy, iz)
if (!isForInventory) {
GL11.glRotatef(-iYaw, 0, 1, 0)
}
else {
GL11.glRotatef(-owner.rotationYaw, 0, 1, 0)
}
GL11.glTranslated(0.3, -0.1, -0.2)
}
private def isForInventory = Minecraft.getMinecraft.currentScreen != null && owner == Minecraft.getMinecraft.thePlayer
}
@SubscribeEvent
def tickStart(e: ClientTickEvent) {
petLocations.cleanUp()
for (pet <- petLocations.asMap.values) {
pet.update()
}
}
}