diff options
author | Linnea Gräf <nea@nea.moe> | 2024-04-07 11:07:55 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-07 11:07:55 +0200 |
commit | 1ad4df39e02a09118c3e94943da14b2f0da1edbd (patch) | |
tree | ab8db5469774b77640e860549abb6000517214d6 /src/main | |
parent | f31e5aa4218b77e54f9438adc629c1c2bdd3e291 (diff) | |
download | skyhanni-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')
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 |