aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2023-11-24 14:59:12 +0100
committerLinnea Gräf <nea@nea.moe>2023-11-24 15:01:39 +0100
commita77fdc7edfaae1f00b298fe97152178341bdee50 (patch)
tree164990ef5c4484b572ad4057893fd2565176cdb7
parentb32344991743f53c94a48f8a0054d0126b15bbfd (diff)
downloadSkyHanni-a77fdc7edfaae1f00b298fe97152178341bdee50.tar.gz
SkyHanni-a77fdc7edfaae1f00b298fe97152178341bdee50.tar.bz2
SkyHanni-a77fdc7edfaae1f00b298fe97152178341bdee50.zip
Add API: HolographicEntities
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt7
-rw-r--r--src/main/java/at/hannibal2/skyhanni/events/LorenzTickEvent.kt17
-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.kt11
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt4
7 files changed, 278 insertions, 3 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt b/src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt
index 56d565299..34b880daf 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/MinecraftData.kt
@@ -3,6 +3,7 @@ package at.hannibal2.skyhanni.data
import at.hannibal2.skyhanni.events.ItemInHandChangeEvent
import at.hannibal2.skyhanni.events.LorenzTickEvent
import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent
+import at.hannibal2.skyhanni.events.NeaTickEvent
import at.hannibal2.skyhanni.events.PacketEvent
import at.hannibal2.skyhanni.events.PlaySoundEvent
import at.hannibal2.skyhanni.events.ReceiveParticleEvent
@@ -65,7 +66,9 @@ object MinecraftData {
}
}
+ @Deprecated("totalTicks counts twice as fast as it should", ReplaceWith("totalNonDupedTicks"))
var totalTicks = 0
+ var totalNonDupedTicks = 0
@SubscribeEvent
fun onTick(event: TickEvent.ClientTickEvent) {
@@ -73,6 +76,10 @@ object MinecraftData {
totalTicks++
LorenzTickEvent(totalTicks).postAndCatch()
DelayedRun.checkRuns()
+ if (event.phase == TickEvent.Phase.END) {
+ totalNonDupedTicks++
+ NeaTickEvent(totalNonDupedTicks).postAndCatch()
+ }
}
@SubscribeEvent
diff --git a/src/main/java/at/hannibal2/skyhanni/events/LorenzTickEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/LorenzTickEvent.kt
index 5bf8d7c2e..f81a8345b 100644
--- a/src/main/java/at/hannibal2/skyhanni/events/LorenzTickEvent.kt
+++ b/src/main/java/at/hannibal2/skyhanni/events/LorenzTickEvent.kt
@@ -1,7 +1,20 @@
package at.hannibal2.skyhanni.events
-class LorenzTickEvent(private val tick: Int) : LorenzEvent() {
+import at.hannibal2.skyhanni.utils.TimeUtils.inWholeTicks
+import kotlin.time.Duration
+
+@Deprecated(
+ "LorenzTickEvent ticks with double speed",
+ ReplaceWith("NeaTickEvent", "at.hannibal2.skyhanni.events.NeaTickEvent")
+)
+class LorenzTickEvent constructor(private val tick: Int) : LorenzEvent() {
fun isMod(i: Int) = tick % i == 0
fun repeatSeconds(i: Int) = isMod(i * 20)
-} \ No newline at end of file
+}
+
+data class NeaTickEvent(val tick: Int) : LorenzEvent() {
+ fun isMod(order: Int, seed: Int = 0) = (tick % order) == (seed % order)
+ fun repeatEvery(duration: Duration, seed: Int = 0) = isMod(duration.inWholeTicks, seed)
+ fun repeatSeconds(seconds: Int) = isMod(seconds * 20)
+}
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..5110c40c8
--- /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 = TimeMark.now()
+
+ val monotonicProgress get() = createdAt.passedTime().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 fd38fd441..39459edf5 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
@@ -1,6 +1,7 @@
package at.hannibal2.skyhanni.utils
import at.hannibal2.skyhanni.utils.LorenzUtils.round
+import net.minecraft.client.renderer.GlStateManager
import net.minecraft.entity.Entity
import net.minecraft.network.play.server.S2APacketParticles
import net.minecraft.util.AxisAlignedBB
@@ -48,7 +49,8 @@ data class LorenzVec(
return (dx * dx + dz * dz)
}
- fun add(x: Double = 0.0, y: Double = 0.0, z: Double = 0.0): LorenzVec = LorenzVec(this.x + x, this.y + y, this.z + z)
+ fun add(x: Double = 0.0, y: Double = 0.0, z: Double = 0.0): LorenzVec =
+ LorenzVec(this.x + x, this.y + y, this.z + z)
fun add(x: Int, y: Int, z: Int): LorenzVec = LorenzVec(this.x + x, this.y + y, this.z + z)
@@ -130,7 +132,14 @@ 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)
+ }
companion object {
fun getFromYawPitch(yaw: Double, pitch: Double): LorenzVec {
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
index 5bf6bfcf0..815fd0aeb 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt
@@ -75,6 +75,10 @@ object TimeUtils {
return builder.toString().trim()
}
+ val Duration.inWholeTicks: Int
+ get() = (inWholeMilliseconds / 50).toInt()
+
+
@Deprecated("Do no longer use long for time", ReplaceWith("getDuration()"))
fun getMillis(string: String) = getDuration(string).inWholeMilliseconds