From 091895fb1084f474c8996c501058d688f1814a93 Mon Sep 17 00:00:00 2001 From: GearShocky Date: Tue, 11 Mar 2025 02:41:22 +0500 Subject: [PATCH] emissives? --- .../client/animation/EnforcerAnimation.java | 17 +++++--- .../client/model/entity/EnforcerModel.java | 27 +++++++----- .../client/render/entity/EnforcerRenderer.kt | 40 ++++++++++++++++++ .../ru/dbotthepony/mc/otm/entity/Enforcer.kt | 34 +++++++++++++-- .../textures/entity/enforcer.png | Bin 5963 -> 6243 bytes .../textures/entity/enforcer_emissive.png | Bin 0 -> 711 bytes 6 files changed, 98 insertions(+), 20 deletions(-) create mode 100644 src/main/resources/assets/overdrive_that_matters/textures/entity/enforcer_emissive.png diff --git a/src/main/java/ru/dbotthepony/mc/otm/client/animation/EnforcerAnimation.java b/src/main/java/ru/dbotthepony/mc/otm/client/animation/EnforcerAnimation.java index 9a5abd09d..2cba6cbcb 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/client/animation/EnforcerAnimation.java +++ b/src/main/java/ru/dbotthepony/mc/otm/client/animation/EnforcerAnimation.java @@ -6,24 +6,29 @@ import net.minecraft.client.animation.Keyframe; import net.minecraft.client.animation.KeyframeAnimations; public class EnforcerAnimation { - public static final AnimationDefinition CHARGE = AnimationDefinition.Builder.withLength(0.0F).looping() + public static final AnimationDefinition CHARGE = AnimationDefinition.Builder.withLength(0.12F).looping() .addAnimation("root", new AnimationChannel(AnimationChannel.Targets.POSITION, - new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, -1.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, -1.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.12F, KeyframeAnimations.posVec(0.0F, -1.1F, 0.0F), AnimationChannel.Interpolations.LINEAR) )) .addAnimation("Body", new AnimationChannel(AnimationChannel.Targets.ROTATION, new Keyframe(0.0F, KeyframeAnimations.degreeVec(7.5F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR) )) .addAnimation("leg_FL", new AnimationChannel(AnimationChannel.Targets.ROTATION, - new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.3244F, 25.5371F, -4.9817F), AnimationChannel.Interpolations.LINEAR) + new Keyframe(0.0F, KeyframeAnimations.degreeVec(-0.0089F, 24.7408F, -0.0342F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.12F, KeyframeAnimations.degreeVec(-0.8438F, 24.7408F, -0.0342F), AnimationChannel.Interpolations.LINEAR) )) .addAnimation("leg_FR", new AnimationChannel(AnimationChannel.Targets.ROTATION, - new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.5426F, -23.0465F, 4.9996F), AnimationChannel.Interpolations.LINEAR) + new Keyframe(0.0F, KeyframeAnimations.degreeVec(-0.0452F, -24.7102F, -0.3574F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.12F, KeyframeAnimations.degreeVec(-0.8765F, -24.7156F, -0.3213F), AnimationChannel.Interpolations.LINEAR) )) .addAnimation("leg_BR", new AnimationChannel(AnimationChannel.Targets.ROTATION, - new Keyframe(0.0F, KeyframeAnimations.degreeVec(-0.3244F, 25.5371F, 4.9817F), AnimationChannel.Interpolations.LINEAR) + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0089F, 24.7408F, 0.0342F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.12F, KeyframeAnimations.degreeVec(0.9506F, 24.7408F, 0.0342F), AnimationChannel.Interpolations.LINEAR) )) .addAnimation("leg_BL", new AnimationChannel(AnimationChannel.Targets.ROTATION, - new Keyframe(0.0F, KeyframeAnimations.degreeVec(-0.3244F, -25.5371F, -4.9817F), AnimationChannel.Interpolations.LINEAR) + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0089F, -24.7408F, -0.0342F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.12F, KeyframeAnimations.degreeVec(0.9506F, -24.7408F, -0.0342F), AnimationChannel.Interpolations.LINEAR) )) .build(); diff --git a/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/EnforcerModel.java b/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/EnforcerModel.java index 2f6f589cd..1940ba1fc 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/EnforcerModel.java +++ b/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/EnforcerModel.java @@ -37,18 +37,23 @@ public class EnforcerModel { MeshDefinition meshdefinition = new MeshDefinition(); PartDefinition partdefinition = meshdefinition.getRoot(); - PartDefinition root = partdefinition.addOrReplaceChild("root", CubeListBuilder.create(), PartPose.offset(0.0F, 25.0F, 0.0F)); - - PartDefinition cube_r1 = root.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(178, 168).addBox(0.0F, -18.5F, -1.0F, 0.0F, 19.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(8.0F, -41.5F, 8.0F, -0.1745F, 0.0F, 0.0F)); + PartDefinition root = partdefinition.addOrReplaceChild("root", CubeListBuilder.create(), PartPose.offset(0.0F, 24.0F, 0.0F)); PartDefinition base = root.addOrReplaceChild("base", CubeListBuilder.create().texOffs(140, 104).addBox(-8.0F, -4.0F, -7.0F, 16.0F, 5.0F, 14.0F, new CubeDeformation(0.0F)) - .texOffs(92, 33).addBox(-5.0F, -2.0F, -10.0F, 10.0F, 14.0F, 20.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, -22.0F, 0.0F)); + .texOffs(92, 33).addBox(-5.0F, -2.0F, -10.0F, 10.0F, 14.0F, 20.0F, new CubeDeformation(0.0F)) + .texOffs(70, 0).addBox(-8.0F, -1.0F, -11.0F, 3.0F, 3.0F, 2.0F, new CubeDeformation(0.0F)) + .texOffs(70, 5).addBox(5.0F, -1.0F, -11.0F, 3.0F, 3.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, -22.0F, 0.0F)); - PartDefinition Body = base.addOrReplaceChild("Body", CubeListBuilder.create().texOffs(80, 76).addBox(-11.0F, -17.4F, 10.9F, 22.0F, 14.0F, 14.0F, new CubeDeformation(0.0F)) + PartDefinition Body = base.addOrReplaceChild("Body", CubeListBuilder.create().texOffs(70, 0).addBox(-9.0F, -18.4F, -8.1F, 3.0F, 3.0F, 2.0F, new CubeDeformation(0.0F)) + .texOffs(70, 5).addBox(-5.0F, -18.4F, -8.1F, 3.0F, 3.0F, 2.0F, new CubeDeformation(0.0F)) + .texOffs(80, 76).addBox(-11.0F, -17.4F, 10.9F, 22.0F, 14.0F, 14.0F, new CubeDeformation(0.0F)) .texOffs(0, 0).addBox(-12.0F, -15.4F, -11.1F, 24.0F, 16.0F, 22.0F, new CubeDeformation(0.0F)) .texOffs(0, 38).addBox(-12.0F, -15.4F, -11.1F, 24.0F, 16.0F, 22.0F, new CubeDeformation(0.5F)) .texOffs(122, 168).addBox(12.0F, -13.4F, -6.1F, 2.0F, 12.0F, 12.0F, new CubeDeformation(0.0F)) - .texOffs(150, 168).addBox(-14.0F, -13.4F, -6.1F, 2.0F, 12.0F, 12.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, -4.6F, 0.1F)); + .texOffs(150, 168).addBox(-14.0F, -13.4F, -6.1F, 2.0F, 12.0F, 12.0F, new CubeDeformation(0.0F)) + .texOffs(140, 123).addBox(-7.0F, -2.0F, 10.0F, 15.0F, 5.0F, 5.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, -4.6F, 0.1F)); + + PartDefinition cube_r1 = Body.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(178, 168).addBox(0.0F, -18.5F, -1.0F, 0.0F, 19.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(8.0F, -14.9F, 7.9F, -0.1745F, 0.0F, 0.0F)); PartDefinition Head = Body.addOrReplaceChild("Head", CubeListBuilder.create().texOffs(92, 67).addBox(-4.0F, -3.0F, -1.0F, 7.0F, 3.0F, 3.0F, new CubeDeformation(0.0F)), PartPose.offset(-4.0F, 1.6F, -11.1F)); @@ -60,19 +65,19 @@ public class EnforcerModel { PartDefinition cube_r2 = flamethrower.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(152, 33).addBox(-4.0F, -4.0F, 0.5F, 8.0F, 8.0F, 15.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(7.75F, 5.7346F, 6.5272F, 0.5236F, 0.0F, 0.0F)); - PartDefinition leg_FL = root.addOrReplaceChild("leg_FL", CubeListBuilder.create().texOffs(158, 0).addBox(-4.5F, -5.5F, -9.5F, 9.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)) - .texOffs(80, 104).addBox(-5.5F, -2.5F, -24.5F, 11.0F, 13.0F, 19.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(9.5F, -13.5F, -6.5F, 0.1047F, -0.5061F, -0.0349F)); + PartDefinition leg_FL = root.addOrReplaceChild("leg_FL", CubeListBuilder.create().texOffs(80, 104).addBox(-5.5F, -2.5F, -24.5F, 11.0F, 13.0F, 19.0F, new CubeDeformation(0.0F)) + .texOffs(158, 0).addBox(-4.5F, -5.5F, -9.5F, 9.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(9.5F, -13.5F, -6.5F, 0.1571F, -0.5061F, -0.0349F)); PartDefinition leg_FR = root.addOrReplaceChild("leg_FR", CubeListBuilder.create().texOffs(0, 125).addBox(-5.5F, -2.5F, -24.5F, 11.0F, 13.0F, 19.0F, new CubeDeformation(0.0F)) - .texOffs(152, 80).addBox(-4.5F, -5.5F, -9.5F, 9.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-9.5F, -13.5F, -6.5F, 0.1047F, 0.5061F, 0.0349F)); + .texOffs(152, 80).addBox(-4.5F, -5.5F, -9.5F, 9.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-9.5F, -13.5F, -6.5F, 0.1571F, 0.5061F, 0.0349F)); PartDefinition leg_BL = root.addOrReplaceChild("leg_BL", CubeListBuilder.create().texOffs(60, 136).addBox(-5.5F, -2.1667F, 5.1667F, 11.0F, 13.0F, 19.0F, new CubeDeformation(0.0F)) .texOffs(199, 24).addBox(-4.5F, -7.1667F, 13.1667F, 9.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)) - .texOffs(0, 157).addBox(-4.5F, -5.1667F, -3.8333F, 9.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(9.5F, -13.8333F, 6.8333F, -0.1047F, 0.5061F, -0.0349F)); + .texOffs(0, 157).addBox(-4.5F, -5.1667F, -3.8333F, 9.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(9.5F, -13.8333F, 6.8333F, -0.1571F, 0.5061F, -0.0349F)); PartDefinition leg_BR = root.addOrReplaceChild("leg_BR", CubeListBuilder.create().texOffs(152, 56).addBox(-4.5F, -5.1667F, -3.1667F, 9.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)) .texOffs(120, 136).addBox(-5.5F, -2.1667F, 5.8333F, 11.0F, 13.0F, 19.0F, new CubeDeformation(0.0F)) - .texOffs(202, 0).addBox(-4.5F, -7.1667F, 13.8333F, 9.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-9.5F, -13.8333F, 6.1667F, -0.1047F, -0.5061F, 0.0349F)); + .texOffs(202, 0).addBox(-4.5F, -7.1667F, 13.8333F, 9.0F, 11.0F, 13.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-9.5F, -13.8333F, 6.1667F, -0.1571F, -0.5061F, 0.0349F)); model = null; return def = LayerDefinition.create(meshdefinition, 256, 256); diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/EnforcerRenderer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/EnforcerRenderer.kt index 6b8457111..fc37ec67a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/EnforcerRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/EnforcerRenderer.kt @@ -1,9 +1,15 @@ package ru.dbotthepony.mc.otm.client.render.entity +import com.mojang.blaze3d.vertex.PoseStack import net.minecraft.client.model.HierarchicalModel +import net.minecraft.client.renderer.MultiBufferSource +import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.entity.EntityRendererProvider import net.minecraft.client.renderer.entity.MobRenderer +import net.minecraft.client.renderer.entity.layers.RenderLayer +import net.minecraft.client.renderer.texture.OverlayTexture import net.minecraft.resources.ResourceLocation +import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters.loc import ru.dbotthepony.mc.otm.client.model.entity.EnforcerModel import ru.dbotthepony.mc.otm.entity.Enforcer @@ -12,7 +18,41 @@ class EnforcerRenderer(context: EntityRendererProvider.Context) : MobRenderer>(context, EnforcerModel.getModel(), 2.2f) { override fun getTextureLocation(entity: Enforcer): ResourceLocation = TEXTURE_LOCATION + init { + this.addLayer(EnforcerEmissiveLayer(this, model)) + } companion object { private val TEXTURE_LOCATION = loc("textures/entity/enforcer.png") } } + +class EnforcerEmissiveLayer( + entityRenderer: EnforcerRenderer, + model: HierarchicalModel +) : RenderLayer>(entityRenderer) { + + private val emissive = loc("textures/entity/enforcer_emissive.png") + + + override fun render( + poseStack: PoseStack, + bufferSource: MultiBufferSource, + packedLight: Int, + entity: Enforcer, + limbSwing: Float, + limbSwingAmount: Float, + partialTicks: Float, + ageInTicks: Float, + netHeadYaw: Float, + headPitch: Float + ) { + val buffer = bufferSource.getBuffer(RenderType.eyes(emissive)) + + this.parentModel.renderToBuffer( + poseStack, + buffer, + 15728640, + OverlayTexture.NO_OVERLAY + ) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Enforcer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Enforcer.kt index ab284b5bf..233599bd4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Enforcer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Enforcer.kt @@ -1,9 +1,11 @@ package ru.dbotthepony.mc.otm.entity +import net.minecraft.server.level.ServerBossEvent import net.minecraft.sounds.SoundEvent import net.minecraft.sounds.SoundEvents import net.minecraft.sounds.SoundSource import net.minecraft.util.Mth +import net.minecraft.world.BossEvent import net.minecraft.world.phys.Vec3 import net.minecraft.world.entity.AnimationState import net.minecraft.world.entity.EntityType @@ -19,6 +21,8 @@ import net.minecraft.world.entity.monster.* import net.minecraft.world.entity.npc.Villager import net.minecraft.world.entity.player.Player import net.minecraft.world.level.Level +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.registry.game.MSoundEvents class Enforcer(type: EntityType, level: Level) : Monster(type,level) { @@ -54,10 +58,34 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { override fun getDeathSound(): SoundEvent { return SoundEvents.VAULT_BREAK } - + + private val bossEvent: ServerBossEvent = + ServerBossEvent(TranslatableComponent(MNames.ENFORCER), BossEvent.BossBarColor.RED, BossEvent.BossBarOverlay.PROGRESS) + + override fun startSeenByPlayer(player: net.minecraft.server.level.ServerPlayer) { + super.startSeenByPlayer(player) + bossEvent.addPlayer(player) + } + + override fun stopSeenByPlayer(player: net.minecraft.server.level.ServerPlayer) { + super.stopSeenByPlayer(player) + bossEvent.removePlayer(player) + } + + override fun aiStep() { + super.aiStep() + bossEvent.progress = this.health / this.maxHealth + } + + override fun die(cause: net.minecraft.world.damagesource.DamageSource) { + super.die(cause) + bossEvent.removeAllPlayers() + } + //charge attack, could possibly leave a smoke trail too idk class RammingGoal(private val mob: Enforcer) : Goal() { private var target: LivingEntity? = null + private var chargeTime = 0 private val windupTime = 20 private val maxChargeTime = 40 @@ -116,7 +144,7 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { mob.yRot = (-Mth.atan2(dir.x, dir.z) * (180f / Math.PI)).toFloat() mob.yHeadRot = mob.yRot - mob.move(net.minecraft.world.entity.MoverType.SELF, dir.scale(1.2)) + mob.move(net.minecraft.world.entity.MoverType.SELF, dir.scale(1.8)) if (mob.horizontalCollision) { @@ -157,7 +185,7 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { fun createAttributes() : AttributeSupplier.Builder { return createMonsterAttributes() .add(Attributes.MAX_HEALTH, 300.0) - .add(Attributes.ARMOR, 10.0) + .add(Attributes.ARMOR, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3) .add(Attributes.STEP_HEIGHT, 1.0) .add(Attributes.KNOCKBACK_RESISTANCE, 1.0) diff --git a/src/main/resources/assets/overdrive_that_matters/textures/entity/enforcer.png b/src/main/resources/assets/overdrive_that_matters/textures/entity/enforcer.png index 6c2f818d9c8c1aa7f6de83cee45e4899b25abfd3..58a697fb4035b5fa60f93bb0a61d31ab0f36c7d0 100644 GIT binary patch delta 5944 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 In111Z0MhAsg#Z8m delta 5665 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 diff --git a/src/main/resources/assets/overdrive_that_matters/textures/entity/enforcer_emissive.png b/src/main/resources/assets/overdrive_that_matters/textures/entity/enforcer_emissive.png new file mode 100644 index 0000000000000000000000000000000000000000..000abb39b2686a7c1903ac3249b41f958bd1507d GIT binary patch literal 711 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G!U;i$lZxy-8q?;Kn_c~qpu?a z!^VE@KZ&eBK4*bPWHAE+-$4*&+%YlxEl^OR#5JNMI6tkVJh3R1As{g`uSCz!HAKNw z&rr|k_a5eLKsDP^BRtbQJ+&A(fE-o^DMnVX)m}iJG?Wc=4TAOJ+8V9%>hOy&ZrO&Oo;-bbH