mirror of
https://github.com/GTNewHorizons/GTNHLib.git
synced 2026-11-08 12:34:52 +00:00
Fix walk/fall particle icons when walking on modeled blocks (#434)
Co-authored-by: Martin Robertz <dream-master@gmx.net>
This commit is contained in:
1 parent
e729fc64d4
commit
6d90dcfedd
8 files changed
+177
-3
No files matched your search
@@ -1,5 +1,7 @@
|
||||
package com.gtnewhorizon.gtnhlib.api;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
|
||||
/// This class is mixed into {@link net.minecraft.block.Block}, so the model loader can store model information on them.
|
||||
/// The data must *only* be mutated by the resource reload manager, but can be read by anyone. If your model can only
|
||||
/// be found by a custom locator, you can implement this yourself and override [#nhlib$isModeled()] to always be true.
|
||||
@@ -8,4 +10,8 @@ public interface BlockModelInfo {
|
||||
boolean nhlib$isModeled();
|
||||
|
||||
void nhlib$setModeled(boolean modeled);
|
||||
|
||||
static boolean isModeled(Block block) {
|
||||
return ((BlockModelInfo) block).nhlib$isModeled();
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,15 @@ import java.util.Random;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.particle.EntityDiggingFX;
|
||||
import net.minecraft.client.renderer.RenderBlocks;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
import net.minecraftforge.client.IItemRenderer;
|
||||
@@ -31,6 +34,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
import com.github.bsideup.jabel.Desugar;
|
||||
import com.gtnewhorizon.gtnhlib.api.BlockModelInfo;
|
||||
@@ -44,6 +48,8 @@ import com.gtnewhorizon.gtnhlib.client.renderer.cel.api.util.NormI8;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.ModelQuadView;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing;
|
||||
import com.gtnewhorizon.gtnhlib.core.fml.transformers.BlockIconTransformer;
|
||||
import com.gtnewhorizon.gtnhlib.mixins.early.models.particles.RenderGlobalAccessor;
|
||||
import com.gtnewhorizon.gtnhlib.mixins.early.models.particles.WorldAccessor;
|
||||
import com.gtnewhorizon.gtnhlib.util.StdLCG;
|
||||
import com.gtnewhorizons.angelica.api.ThreadSafeISBRH;
|
||||
|
||||
@@ -507,6 +513,55 @@ public class ModelISBRH implements ISimpleBlockRenderingHandler, IItemRenderer {
|
||||
return Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite("missingno");
|
||||
}
|
||||
|
||||
/// Spawn a particle for an entity walking on a modeled block. This method effectively replaces
|
||||
/// [World#spawnParticle(String, double, double, double, double, double, double)] so we can inject a new texture,
|
||||
/// using the block position that normally gets dropped before the particle is actually spawned.
|
||||
///
|
||||
/// @param rg The RenderGlobal instance the particle is spawned in.
|
||||
/// @param blockX X position of the block the particle is spawned from.
|
||||
/// @param blockY Y position...
|
||||
/// @param blockZ Z position...
|
||||
/// @param x X position of the particle
|
||||
/// @param y Y position...
|
||||
/// @param z Z position...
|
||||
/// @param vX X velocity of particle
|
||||
/// @param vY Y velocity...
|
||||
/// @param vZ Z velocity...
|
||||
@Unique
|
||||
public static void spawnParticle(RenderGlobal rg, int blockX, int blockY, int blockZ, double x, double y, double z,
|
||||
double vX, double vY, double vZ) {
|
||||
var mc = Minecraft.getMinecraft();
|
||||
if (mc == null || mc.renderViewEntity == null || mc.effectRenderer == null) return;
|
||||
|
||||
// Skip 3/4 of particles when they're set to decreased
|
||||
var world = ((RenderGlobalAccessor) rg).getTheWorld();
|
||||
if (mc.gameSettings.particleSetting == 1 && world.rand.nextInt(3) == 0) return;
|
||||
|
||||
// Don't render distant (>16 blocks) particles.
|
||||
var dx = mc.renderViewEntity.posX - x;
|
||||
var dy = mc.renderViewEntity.posY - y;
|
||||
var dz = mc.renderViewEntity.posZ - z;
|
||||
if (dx * dx + dy * dy * dz * dz > 16 * 16) return;
|
||||
|
||||
var block = world.getBlock(blockX, blockY, blockZ);
|
||||
var meta = world.getBlockMetadata(blockX, blockY, blockZ);
|
||||
var digFX = new EntityDiggingFX(world, x, y, z, vX, vY, vZ, block, meta);
|
||||
digFX.setParticleIcon(INSTANCE.get().getParticleIcon(world, blockX, blockY, blockZ));
|
||||
mc.effectRenderer.addEffect(digFX);
|
||||
}
|
||||
|
||||
/// A helper to call [#spawnParticle] the same way vanilla calls [World#spawnParticle]. It's *probably* fine to only
|
||||
/// call this on the main render global, but "probably" doesn't stop breakages.
|
||||
///
|
||||
/// Neither does being careful, but such is life.
|
||||
public static void spawnParticleCommon(World world, int blockX, int blockY, int blockZ, double x, double y,
|
||||
double z, double vX, double vY, double vZ) {
|
||||
for (var iwa : ((WorldAccessor) world).getWorldAccesses()) {
|
||||
if (iwa instanceof RenderGlobal rg)
|
||||
ModelISBRH.spawnParticle(rg, blockX, blockY, blockZ, x, y, z, vX, vY, vZ);
|
||||
}
|
||||
}
|
||||
|
||||
/// Some blocks, like LittleTiles, rely on recursively rendering other blocks in the same location. Unfortunately,
|
||||
/// this means we have to actually respect the block passed into [ModelISBRH#renderWorldBlock]. In order to read a
|
||||
/// blockstate with that, we wrap the original IBA with one that just returns a slightly different block.
|
||||
|
||||
@@ -25,11 +25,16 @@ public enum Mixins implements IMixins {
|
||||
BLOCK_PROPERTIES_ACCESSORS(Side.COMMON, "MixinTileEntitySkull"),
|
||||
MODEL_TEXTURE_LOADING(new MixinBuilder("Automatically load models, textures, and metadata.").addClientMixins(
|
||||
"models.FRMAccessor",
|
||||
"models.MixinEffectRenderer_FixParticleIcons",
|
||||
"models.MixinFileResourcePack",
|
||||
"models.MixinFolderResourcePack",
|
||||
"models.MixinRenderBlocks",
|
||||
"models.SRRMAccessor").setPhase(Phase.EARLY).setApplyIf(() -> true)),
|
||||
MODEL_PARTICLE_FIXES(new MixinBuilder("Override particle icons for models.").addClientMixins(
|
||||
"models.particles.MixinEffectRenderer",
|
||||
"models.particles.MixinEntity",
|
||||
"models.particles.MixinRenderGlobal",
|
||||
"models.particles.RenderGlobalAccessor",
|
||||
"models.particles.WorldAccessor").setPhase(Phase.EARLY).setApplyIf(() -> true)),
|
||||
MODEL_ITEM_RENDERER(new MixinBuilder("Restore origin pivot before modifier").addClientMixins("models.MixinModelFHC")
|
||||
.setPhase(Phase.EARLY)),
|
||||
MODEL_BLOCK_CRACKS(new MixinBuilder("Fix crack texture appearance for modeled blocks")
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.gtnewhorizon.gtnhlib.mixins.early.models;
|
||||
package com.gtnewhorizon.gtnhlib.mixins.early.models.particles;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.particle.EffectRenderer;
|
||||
@@ -15,7 +15,7 @@ import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
|
||||
@Mixin(EffectRenderer.class)
|
||||
public class MixinEffectRenderer_FixParticleIcons {
|
||||
public class MixinEffectRenderer {
|
||||
|
||||
@Shadow
|
||||
protected World worldObj;
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.gtnewhorizon.gtnhlib.mixins.early.models.particles;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.api.BlockModelInfo;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.ModelISBRH;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
|
||||
@SuppressWarnings("UnusedMixin")
|
||||
@Mixin(Entity.class)
|
||||
public class MixinEntity {
|
||||
|
||||
@Shadow
|
||||
public World worldObj;
|
||||
|
||||
@WrapOperation(
|
||||
method = "onEntityUpdate",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;spawnParticle(Ljava/lang/String;DDDDDD)V"))
|
||||
private void nhlib$fixBreakIcon(World instance, String particleName, double x, double y, double z, double velocityX,
|
||||
double velocityY, double velocityZ, Operation<Void> original, @Local(name = "block") Block block,
|
||||
@Local(name = "j") int j, @Local(name = "i") int i, @Local(name = "k") int k) {
|
||||
if (!((BlockModelInfo) block).nhlib$isModeled()) {
|
||||
original.call(instance, particleName, x, y, z, velocityX, velocityY, velocityZ);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a modeled block! Refer to our helper for particles instead of the default.
|
||||
ModelISBRH.spawnParticleCommon(worldObj, j, i, k, x, y, z, velocityX, velocityY, velocityZ);
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.gtnewhorizon.gtnhlib.mixins.early.models.particles;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.api.BlockModelInfo.isModeled;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.model.ModelISBRH;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
|
||||
@Mixin(RenderGlobal.class)
|
||||
public class MixinRenderGlobal {
|
||||
|
||||
@SuppressWarnings("NameDoesntMatchTargetClass")
|
||||
@WrapOperation(
|
||||
method = "playAuxSFX",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/multiplayer/WorldClient;spawnParticle(Ljava/lang/String;DDDDDD)V",
|
||||
ordinal = 2))
|
||||
private void nhlib$fixModeledFallParticles(WorldClient wc, String particleName, double x, double y, double z,
|
||||
double vX, double vY, double vZ, Operation<Void> original, @Local(name = "block") Block block,
|
||||
@Local(name = "p_72706_3_", argsOnly = true) int blockX,
|
||||
@Local(name = "p_72706_4_", argsOnly = true) int blockY,
|
||||
@Local(name = "p_72706_5_", argsOnly = true) int blockZ) {
|
||||
if (!isModeled(block)) {
|
||||
original.call(wc, particleName, x, y, z, vX, vY, vZ);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a modeled block! Refer to our helper for particles instead of the default.
|
||||
ModelISBRH.spawnParticleCommon(wc, blockX, blockY, blockZ, x, y, z, vX, vY, vZ);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.gtnewhorizon.gtnhlib.mixins.early.models.particles;
|
||||
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(RenderGlobal.class)
|
||||
public interface RenderGlobalAccessor {
|
||||
|
||||
@Accessor
|
||||
WorldClient getTheWorld();
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.gtnewhorizon.gtnhlib.mixins.early.models.particles;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.world.IWorldAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(World.class)
|
||||
public interface WorldAccessor {
|
||||
|
||||
@Accessor
|
||||
List<IWorldAccess> getWorldAccesses();
|
||||
}
|
||||
Reference in new issue
Block a user