aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-04-07 11:07:55 +0200
committerGitHub <noreply@github.com>2024-04-07 11:07:55 +0200
commit1ad4df39e02a09118c3e94943da14b2f0da1edbd (patch)
treeab8db5469774b77640e860549abb6000517214d6 /src/main/java/at/hannibal2
parentf31e5aa4218b77e54f9438adc629c1c2bdd3e291 (diff)
downloadskyhanni-1ad4df39e02a09118c3e94943da14b2f0da1edbd.tar.gz
skyhanni-1ad4df39e02a09118c3e94943da14b2f0da1edbd.tar.bz2
skyhanni-1ad4df39e02a09118c3e94943da14b2f0da1edbd.zip
Backend: HolographicEntities (#731)
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Co-authored-by: Cal <cwolfson58@gmail.com>
Diffstat (limited to 'src/main/java/at/hannibal2')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorRender.java15
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorRendererLivingEntity.java15
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/HolographicEntities.kt212
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt10
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt4
5 files changed, 255 insertions, 1 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorRender.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorRender.java
new file mode 100644
index 000000000..c92a49c01
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorRender.java
@@ -0,0 +1,15 @@
+package at.hannibal2.skyhanni.mixins.transformers;
+
+import net.minecraft.client.renderer.entity.Render;
+import net.minecraft.entity.Entity;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+@Mixin(Render.class)
+public interface AccessorRender<T extends Entity> {
+
+ @Invoker("bindEntityTexture")
+ boolean bindEntityTexture_skyhanni(T entity);
+
+
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorRendererLivingEntity.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorRendererLivingEntity.java
new file mode 100644
index 000000000..7e7a8974f
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorRendererLivingEntity.java
@@ -0,0 +1,15 @@
+package at.hannibal2.skyhanni.mixins.transformers;
+
+import net.minecraft.client.renderer.entity.RendererLivingEntity;
+import net.minecraft.entity.EntityLivingBase;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+@Mixin(RendererLivingEntity.class)
+public interface AccessorRendererLivingEntity<T extends EntityLivingBase>
+ extends AccessorRender<T> {
+ @Invoker("setBrightness")
+ boolean setBrightness_skyhanni(T entitylivingbaseIn, float partialTicks, boolean combineTextures);
+ @Invoker("unsetBrightness")
+ void setBrightness_skyhanni();
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/HolographicEntities.kt b/src/main/java/at/hannibal2/skyhanni/utils/HolographicEntities.kt
new file mode 100644
index 000000000..74345053c
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/HolographicEntities.kt
@@ -0,0 +1,212 @@
+package at.hannibal2.skyhanni.utils
+
+import at.hannibal2.skyhanni.mixins.transformers.AccessorRendererLivingEntity
+import at.hannibal2.skyhanni.utils.RenderUtils.getViewerPos
+import at.hannibal2.skyhanni.utils.TimeUtils.inWholeTicks
+import net.minecraft.client.Minecraft
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.client.renderer.entity.RendererLivingEntity
+import net.minecraft.entity.EntityLivingBase
+import net.minecraft.entity.boss.EntityWither
+import net.minecraft.entity.item.EntityArmorStand
+import net.minecraft.entity.monster.EntityBlaze
+import net.minecraft.entity.monster.EntityCaveSpider
+import net.minecraft.entity.monster.EntityCreeper
+import net.minecraft.entity.monster.EntityEnderman
+import net.minecraft.entity.monster.EntityEndermite
+import net.minecraft.entity.monster.EntityGhast
+import net.minecraft.entity.monster.EntityGiantZombie
+import net.minecraft.entity.monster.EntityGuardian
+import net.minecraft.entity.monster.EntityIronGolem
+import net.minecraft.entity.monster.EntityMagmaCube
+import net.minecraft.entity.monster.EntityPigZombie
+import net.minecraft.entity.monster.EntitySilverfish
+import net.minecraft.entity.monster.EntitySkeleton
+import net.minecraft.entity.monster.EntitySlime
+import net.minecraft.entity.monster.EntitySnowman
+import net.minecraft.entity.monster.EntitySpider
+import net.minecraft.entity.monster.EntityWitch
+import net.minecraft.entity.monster.EntityZombie
+import net.minecraft.entity.passive.EntityBat
+import net.minecraft.entity.passive.EntityChicken
+import net.minecraft.entity.passive.EntityCow
+import net.minecraft.entity.passive.EntityHorse
+import net.minecraft.entity.passive.EntityMooshroom
+import net.minecraft.entity.passive.EntityOcelot
+import net.minecraft.entity.passive.EntityPig
+import net.minecraft.entity.passive.EntityRabbit
+import net.minecraft.entity.passive.EntitySheep
+import net.minecraft.entity.passive.EntitySquid
+import net.minecraft.entity.passive.EntityVillager
+import net.minecraft.entity.passive.EntityWolf
+import org.lwjgl.opengl.GL11
+
+
+/**
+ * Utility for creating fake entities without an associated world in order to avoid contaminating the world state.
+ */
+object HolographicEntities {
+
+ /**
+ * An instance of a holographic entity. Maintains a minimal controlled state,
+ * which has just enough information for rendering and basic manipulations, such as
+ * interpolated positioning. The underlying [entity] should not be accessed directly.
+ */
+ class HolographicEntity<T : EntityLivingBase> internal constructor(
+ val entity: T,
+ var position: LorenzVec,
+ var yaw: Float,
+ ) {
+ var isChild: Boolean = false
+ var lastPosition: LorenzVec = position
+ var lastYaw: Float = yaw
+ val createdAt = SimpleTimeMark.now()
+
+ val monotonicProgress get() = createdAt.passedSince().inWholeTicks
+
+ /**
+ * Should be called exactly once per tick or never over the lifetime of this [HolographicEntity].
+ */
+ fun moveTo(position: LorenzVec, yaw: Float, isTeleport: Boolean = false) {
+ if (isTeleport) {
+ this.lastYaw = yaw
+ this.lastPosition = position
+ } else {
+ this.lastYaw = this.yaw
+ this.lastPosition = this.position
+ }
+ this.position = position
+ this.yaw = yaw
+ }
+
+ fun interpolatedPosition(partialTicks: Float): LorenzVec {
+ return lastPosition.slope(position, partialTicks.toDouble())
+ }
+
+ fun interpolatedYaw(partialTicks: Float): Float {
+ return interpolateRotation(lastYaw, yaw, partialTicks)
+ }
+ }
+
+ /**
+ * Template for a [HolographicEntity]. This class exists as a guard for
+ * [HolographicEntity] to prevent untested entities with potential NPEs
+ * being instantiated. A list of tested entities exist in [HolographicEntities].
+ * Some of these entities rely on mixins from NEU for their proper null
+ * world handling.
+ */
+ class HolographicBase<T : EntityLivingBase> internal constructor(
+ private val entity: T
+ ) {
+ fun instance(position: LorenzVec, yaw: Float): HolographicEntity<T> {
+ return HolographicEntity(entity, position, yaw)
+ }
+ }
+
+ val zombie = HolographicBase(EntityZombie(null))
+ val chicken = HolographicBase(EntityChicken(null))
+ val slime = HolographicBase(EntitySlime(null))
+ val wolf = HolographicBase(EntityWolf(null))
+ val skeleton = HolographicBase(EntitySkeleton(null))
+ val creeper = HolographicBase(EntityCreeper(null))
+ val ocelot = HolographicBase(EntityOcelot(null))
+ val blaze = HolographicBase(EntityBlaze(null))
+ val rabbit = HolographicBase(EntityRabbit(null))
+ val sheep = HolographicBase(EntitySheep(null))
+ val horse = HolographicBase(EntityHorse(null))
+ val eisengolem = HolographicBase(EntityIronGolem(null))
+ val silverfish = HolographicBase(EntitySilverfish(null))
+ val witch = HolographicBase(EntityWitch(null))
+ val endermite = HolographicBase(EntityEndermite(null))
+ val snowman = HolographicBase(EntitySnowman(null))
+ val villager = HolographicBase(EntityVillager(null))
+ val guardian = HolographicBase(EntityGuardian(null))
+ val armorStand = HolographicBase(EntityArmorStand(null))
+ val squid = HolographicBase(EntitySquid(null))
+ val bat = HolographicBase(EntityBat(null))
+ val spider = HolographicBase(EntitySpider(null))
+ val caveSpider = HolographicBase(EntityCaveSpider(null))
+ val pigman = HolographicBase(EntityPigZombie(null))
+ val ghast = HolographicBase(EntityGhast(null))
+ val magmaCube = HolographicBase(EntityMagmaCube(null))
+ val wither = HolographicBase(EntityWither(null))
+ val enderman = HolographicBase(EntityEnderman(null))
+ val mooshroom = HolographicBase(EntityMooshroom(null))
+ val witherSkeleton = HolographicBase(EntitySkeleton(null).also { it.skeletonType = 1 })
+ val cow = HolographicBase(EntityCow(null))
+ val pig = HolographicBase(EntityPig(null))
+ val giant = HolographicBase(EntityGiantZombie(null))
+
+
+ private fun interpolateRotation(last: Float, next: Float, progress: Float): Float {
+ var direction: Float = next - last
+ while (direction < -180.0f) {
+ direction += 360.0f
+ }
+ while (direction >= 180.0f) {
+ direction -= 360.0f
+ }
+ return last + progress * direction
+ }
+
+ /**
+ * Render a fake [HolographicEntity]. In order to render a fully opaque entity, set [holographicness] to `1F`.
+ */
+ fun <T : EntityLivingBase> renderHolographicEntity(
+ holographicEntity: HolographicEntity<T>,
+ partialTicks: Float,
+ holographicness: Float = 0.3f
+ ) {
+ val renderManager = Minecraft.getMinecraft().renderManager
+ val renderer = renderManager.getEntityRenderObject<EntityLivingBase>(holographicEntity.entity)
+ renderer as RendererLivingEntity<T>
+ renderer as AccessorRendererLivingEntity<T>
+
+ renderer.setRenderOutlines(false)
+ if (!renderer.bindEntityTexture_skyhanni(holographicEntity.entity))
+ return
+
+ GlStateManager.pushMatrix()
+ val viewerPosition = getViewerPos(partialTicks)
+ val mobPosition = holographicEntity.interpolatedPosition(partialTicks)
+ val renderingOffset = mobPosition.subtract(viewerPosition)
+ renderingOffset.applyTranslationToGL()
+ GlStateManager.disableCull()
+ GlStateManager.enableRescaleNormal()
+ GlStateManager.scale(-1f, -1f, 1f)
+ GlStateManager.translate(0F, -1.5078125f, 0f)
+ val limbSwing: Float = 0F
+ val limbSwingAmount: Float = 0F
+ val ageInTicks: Float = 1_000_000.toFloat()
+ val netHeadYaw: Float = holographicEntity.interpolatedYaw(partialTicks)
+ val headPitch: Float = 0F
+ val scaleFactor: Float = 0.0625f
+ renderer.setBrightness_skyhanni(holographicEntity.entity, 0f, true)
+ GlStateManager.color(1.0f, 1.0f, 1.0f, holographicness)
+ GlStateManager.depthMask(false)
+ GlStateManager.enableBlend()
+ GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA)
+ GlStateManager.alphaFunc(GL11.GL_GREATER, 1 / 255F)
+
+ GlStateManager.enableTexture2D()
+ renderer.mainModel.isChild = holographicEntity.isChild
+ renderer.mainModel.setRotationAngles(
+ limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scaleFactor, holographicEntity.entity
+ )
+ renderer.mainModel.render(
+ holographicEntity.entity,
+ limbSwing,
+ limbSwingAmount,
+ ageInTicks,
+ netHeadYaw,
+ headPitch,
+ scaleFactor
+ )
+ GlStateManager.alphaFunc(GL11.GL_GREATER, 0.1f)
+ GlStateManager.color(1f, 1f, 1f, 1f)
+ GlStateManager.depthMask(true)
+ GlStateManager.disableBlend()
+ GlStateManager.popMatrix()
+ }
+
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
index 37e18e1d0..0353dc386 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
@@ -68,7 +68,7 @@ data class LorenzVec(
fun multiply(d: Int): LorenzVec =
LorenzVec(x multiplyZeroSave d.toDouble(), y multiplyZeroSave d.toDouble(), z multiplyZeroSave d.toDouble())
- fun divide(d : Double) = multiply(1.0/d)
+ fun divide(d: Double) = multiply(1.0 / d)
fun multiply(v: LorenzVec) = LorenzVec(x multiplyZeroSave v.x, y multiplyZeroSave v.y, z multiplyZeroSave v.z)
@@ -167,8 +167,16 @@ data class LorenzVec(
return LorenzVec(scalar * x, scalar * y, scalar * z)
}
+ fun applyTranslationToGL() {
+ GlStateManager.translate(x, y, z)
+ }
+
fun axisAlignedTo(other: LorenzVec) = AxisAlignedBB(x, y, z, other.x, other.y, other.z)
+ fun up(offset: Double): LorenzVec {
+ return copy(y = y + offset)
+ }
+
fun interpolate(other: LorenzVec, factor: Double): LorenzVec {
require(factor in 0.0..1.0) { "Percentage must be between 0 and 1: $factor" }
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
index 5e8c0b41c..b92cf5258 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
@@ -82,6 +82,10 @@ object TimeUtils {
return builder.toString().trim()
}
+ val Duration.inWholeTicks: Int
+ get() = (inWholeMilliseconds / 50).toInt()
+
+
@Deprecated("Do no longer use long for time", ReplaceWith("TimeUtils.getDuration(string)"))
fun getMillis(string: String) = getDuration(string).inWholeMilliseconds