From 932931082f0ec2841d5245b5fc85ae0051449c85 Mon Sep 17 00:00:00 2001 From: FoundationGames <43485105+FoundationGames@users.noreply.github.com> Date: Wed, 29 May 2024 23:00:42 -0700 Subject: [PATCH] Add 1.20.4 decorated pot animations for inserting items --- .../enhancedblockentities/EBESetup.java | 4 +- .../EnhancedBlockEntities.java | 3 + .../client/model/ModelIdentifiers.java | 1 + .../model/misc/DecoratedPotModelSelector.java | 31 +++-- .../render/BlockEntityRenderCondition.java | 10 +- ...coratedPotBlockEntityRendererOverride.java | 107 ++++++++++++++++++ .../mixin/DecoratedPotBlockEntityMixin.java | 36 +++++- .../enhancedblockentities/util/WorldUtil.java | 32 +++++- .../models/block/decorated_pot_shaking.json | 5 + 9 files changed, 213 insertions(+), 16 deletions(-) create mode 100644 src/main/java/foundationgames/enhancedblockentities/client/render/entity/DecoratedPotBlockEntityRendererOverride.java create mode 100644 src/main/resources/assets/minecraft/models/block/decorated_pot_shaking.json diff --git a/src/main/java/foundationgames/enhancedblockentities/EBESetup.java b/src/main/java/foundationgames/enhancedblockentities/EBESetup.java index 6c68c2f5..14b41795 100644 --- a/src/main/java/foundationgames/enhancedblockentities/EBESetup.java +++ b/src/main/java/foundationgames/enhancedblockentities/EBESetup.java @@ -10,6 +10,7 @@ import foundationgames.enhancedblockentities.client.render.BlockEntityRendererOverride; import foundationgames.enhancedblockentities.client.render.entity.BellBlockEntityRendererOverride; import foundationgames.enhancedblockentities.client.render.entity.ChestBlockEntityRendererOverride; +import foundationgames.enhancedblockentities.client.render.entity.DecoratedPotBlockEntityRendererOverride; import foundationgames.enhancedblockentities.client.render.entity.ShulkerBoxBlockEntityRendererOverride; import foundationgames.enhancedblockentities.client.render.entity.SignBlockEntityRendererOverride; import foundationgames.enhancedblockentities.client.resource.EBEPack; @@ -441,6 +442,7 @@ public static void setupShulkerBoxes() { } public static void setupDecoratedPots() { - EnhancedBlockEntityRegistry.register(Blocks.DECORATED_POT, BlockEntityType.DECORATED_POT, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP); + EnhancedBlockEntityRegistry.register(Blocks.DECORATED_POT, BlockEntityType.DECORATED_POT, + BlockEntityRenderCondition.DECORATED_POT, new DecoratedPotBlockEntityRendererOverride()); } } diff --git a/src/main/java/foundationgames/enhancedblockentities/EnhancedBlockEntities.java b/src/main/java/foundationgames/enhancedblockentities/EnhancedBlockEntities.java index 937f62bf..477e46fb 100644 --- a/src/main/java/foundationgames/enhancedblockentities/EnhancedBlockEntities.java +++ b/src/main/java/foundationgames/enhancedblockentities/EnhancedBlockEntities.java @@ -6,7 +6,9 @@ import foundationgames.enhancedblockentities.util.DateUtil; import foundationgames.enhancedblockentities.util.EBEUtil; import foundationgames.enhancedblockentities.util.ResourceUtil; +import foundationgames.enhancedblockentities.util.WorldUtil; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.client.item.ModelPredicateProviderRegistry; @@ -22,6 +24,7 @@ public final class EnhancedBlockEntities implements ClientModInitializer { @Override public void onInitializeClient() { WorldRenderEvents.END.register(SignRenderManager::endFrame); + ClientTickEvents.END_WORLD_TICK.register(WorldUtil.EVENT_LISTENER); ModelIdentifiers.init(); EBESetup.setupResourceProviders(); diff --git a/src/main/java/foundationgames/enhancedblockentities/client/model/ModelIdentifiers.java b/src/main/java/foundationgames/enhancedblockentities/client/model/ModelIdentifiers.java index bc8f51eb..8c32673a 100644 --- a/src/main/java/foundationgames/enhancedblockentities/client/model/ModelIdentifiers.java +++ b/src/main/java/foundationgames/enhancedblockentities/client/model/ModelIdentifiers.java @@ -69,6 +69,7 @@ public final class ModelIdentifiers implements ModelLoadingPlugin { public static final Identifier BELL_BODY = of("block/bell_body", BELL_PREDICATE); public static final Identifier DECORATED_POT_BASE = of("block/decorated_pot_base", DECORATED_POT_PREDICATE); + public static final Identifier DECORATED_POT_SHAKING = of("block/decorated_pot_shaking", DECORATED_POT_PREDICATE); public static final Map SHULKER_BOXES = new HashMap<>(); public static final Map SHULKER_BOX_BOTTOMS = new HashMap<>(); diff --git a/src/main/java/foundationgames/enhancedblockentities/client/model/misc/DecoratedPotModelSelector.java b/src/main/java/foundationgames/enhancedblockentities/client/model/misc/DecoratedPotModelSelector.java index c753bb78..3065c25f 100644 --- a/src/main/java/foundationgames/enhancedblockentities/client/model/misc/DecoratedPotModelSelector.java +++ b/src/main/java/foundationgames/enhancedblockentities/client/model/misc/DecoratedPotModelSelector.java @@ -2,6 +2,7 @@ import foundationgames.enhancedblockentities.client.model.ModelIdentifiers; import foundationgames.enhancedblockentities.client.model.ModelSelector; +import foundationgames.enhancedblockentities.util.duck.ModelStateHolder; import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; import net.minecraft.block.BlockState; import net.minecraft.block.DecoratedPotPatterns; @@ -17,10 +18,16 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.function.Supplier; public class DecoratedPotModelSelector extends ModelSelector { + public static final int BUILTIN_MODEL_COUNT = 2; + + public static final int IDX_EMPTY = 0; + public static final int IDX_BASE_POT = 1; + private final List> potteryPatterns; public DecoratedPotModelSelector() { @@ -32,10 +39,11 @@ public DecoratedPotModelSelector() { public Identifier[] createModelIDs() { ModelIdentifiers.refreshPotteryPatterns(); - var ids = new Identifier[1 + potteryPatterns.size() * 4]; - ids[0] = ModelIdentifiers.DECORATED_POT_BASE; + var ids = new Identifier[BUILTIN_MODEL_COUNT + potteryPatterns.size() * 4]; + ids[IDX_EMPTY] = ModelIdentifiers.DECORATED_POT_SHAKING; + ids[IDX_BASE_POT] = ModelIdentifiers.DECORATED_POT_BASE; - int idIndex = 1; + int idIndex = BUILTIN_MODEL_COUNT; for (int dirIndex = 0; dirIndex < 4; dirIndex++) { for (var pattern : this.potteryPatterns) { ids[idIndex] = ModelIdentifiers.POTTERY_PATTERNS.get(pattern)[dirIndex]; @@ -51,20 +59,25 @@ public Identifier[] createModelIDs() { public void writeModelIndices(BlockRenderView view, BlockState state, BlockPos pos, Supplier rand, @Nullable RenderContext ctx, int[] indices) { final int patternCount = potteryPatterns.size(); - indices[0] = 0; + indices[0] = IDX_BASE_POT; if (view.getBlockEntity(pos) instanceof DecoratedPotBlockEntity pot) { + if (pot instanceof ModelStateHolder ms && ms.getModelState() > 0) { + Arrays.fill(indices, IDX_EMPTY); + return; + } + var sherds = pot.getSherds(); - indices[1] = 1 + getPatternIndex(sherds.back(), patternCount); - indices[2] = 1 + getPatternIndex(sherds.left(), patternCount) + patternCount; - indices[3] = 1 + getPatternIndex(sherds.right(), patternCount) + patternCount * 2; - indices[4] = 1 + getPatternIndex(sherds.front(), patternCount) + patternCount * 3; + indices[1] = BUILTIN_MODEL_COUNT + getPatternIndex(sherds.back(), patternCount); + indices[2] = BUILTIN_MODEL_COUNT + getPatternIndex(sherds.left(), patternCount) + patternCount; + indices[3] = BUILTIN_MODEL_COUNT + getPatternIndex(sherds.right(), patternCount) + patternCount * 2; + indices[4] = BUILTIN_MODEL_COUNT + getPatternIndex(sherds.front(), patternCount) + patternCount * 3; return; } for (int i = 0; i < 4; i++) { - indices[1 + i] = 1 + patternCount * i; + indices[1 + i] = BUILTIN_MODEL_COUNT + patternCount * i; } } diff --git a/src/main/java/foundationgames/enhancedblockentities/client/render/BlockEntityRenderCondition.java b/src/main/java/foundationgames/enhancedblockentities/client/render/BlockEntityRenderCondition.java index 4f8f55b5..5f9326d5 100644 --- a/src/main/java/foundationgames/enhancedblockentities/client/render/BlockEntityRenderCondition.java +++ b/src/main/java/foundationgames/enhancedblockentities/client/render/BlockEntityRenderCondition.java @@ -10,18 +10,18 @@ @FunctionalInterface public interface BlockEntityRenderCondition { - BlockEntityRenderCondition STATE_GREATER_THAN_1 = entity -> { + BlockEntityRenderCondition NON_ZERO_STATE = entity -> { if(entity instanceof ModelStateHolder stateHolder) { return stateHolder.getModelState() > 0; } return false; }; - BlockEntityRenderCondition CHEST = STATE_GREATER_THAN_1; + BlockEntityRenderCondition CHEST = NON_ZERO_STATE; - BlockEntityRenderCondition BELL = STATE_GREATER_THAN_1; + BlockEntityRenderCondition BELL = NON_ZERO_STATE; - BlockEntityRenderCondition SHULKER_BOX = STATE_GREATER_THAN_1; + BlockEntityRenderCondition SHULKER_BOX = NON_ZERO_STATE; BlockEntityRenderCondition SIGN = entity -> { EBEConfig config = EnhancedBlockEntities.CONFIG; @@ -48,6 +48,8 @@ public interface BlockEntityRenderCondition { return false; }; + BlockEntityRenderCondition DECORATED_POT = NON_ZERO_STATE; + BlockEntityRenderCondition NEVER = entity -> false; BlockEntityRenderCondition ALWAYS = entity -> true; diff --git a/src/main/java/foundationgames/enhancedblockentities/client/render/entity/DecoratedPotBlockEntityRendererOverride.java b/src/main/java/foundationgames/enhancedblockentities/client/render/entity/DecoratedPotBlockEntityRendererOverride.java new file mode 100644 index 00000000..5c9e7164 --- /dev/null +++ b/src/main/java/foundationgames/enhancedblockentities/client/render/entity/DecoratedPotBlockEntityRendererOverride.java @@ -0,0 +1,107 @@ +package foundationgames.enhancedblockentities.client.render.entity; + +import com.google.common.collect.ImmutableMap; +import foundationgames.enhancedblockentities.client.model.ModelIdentifiers; +import foundationgames.enhancedblockentities.client.render.BlockEntityRendererOverride; +import foundationgames.enhancedblockentities.util.EBEUtil; +import foundationgames.enhancedblockentities.util.duck.BakedModelManagerAccess; +import net.minecraft.block.DecoratedPotPatterns; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.DecoratedPotBlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.block.entity.BlockEntityRenderer; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.registry.Registries; +import net.minecraft.registry.RegistryKey; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RotationAxis; + +import java.util.Map; + +public class DecoratedPotBlockEntityRendererOverride extends BlockEntityRendererOverride { + public static final float WOBBLE_STRENGTH = 1f / 64; + + private BakedModel baseModel = null; + private Map, BakedModel[]> potPatternModels = null; + + private void tryGetModels() { + var models = (BakedModelManagerAccess) MinecraftClient.getInstance().getBakedModelManager(); + + if (this.baseModel == null) { + this.baseModel = models.getModel(ModelIdentifiers.DECORATED_POT_BASE); + } + + if (this.potPatternModels == null) { + var builder = ImmutableMap., BakedModel[]>builder(); + + Registries.DECORATED_POT_PATTERN.getKeys().forEach(k -> { + var patternModelIDs = ModelIdentifiers.POTTERY_PATTERNS.get(k); + BakedModel[] patternPerFaceModels = new BakedModel[patternModelIDs.length]; + + for (int i = 0; i < patternModelIDs.length; i++) { + patternPerFaceModels[i] = models.getModel(patternModelIDs[i]); + } + + builder.put(k, patternPerFaceModels); + }); + + this.potPatternModels = builder.build(); + } + } + + @Override + public void render(BlockEntityRenderer renderer, BlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) { + tryGetModels(); + + if (blockEntity instanceof DecoratedPotBlockEntity pot) { + matrices.push(); + + var dir = pot.getHorizontalFacing(); + + matrices.translate(0.5f, 0, 0.5f); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - dir.asRotation())); + matrices.translate(-0.5f, 0, -0.5f); + + var wobbleType = pot.lastWobbleType; + if (wobbleType != null && pot.getWorld() != null) { + float tilt = ((float)(pot.getWorld().getTime() - pot.lastWobbleTime) + tickDelta) / (float)wobbleType.lengthInTicks; + if (tilt >= 0.0F && tilt <= 1.0F) { + if (wobbleType == DecoratedPotBlockEntity.WobbleType.POSITIVE) { + float animPeriod = tilt * MathHelper.TAU; + + float tiltX = -1.5f * (MathHelper.cos(animPeriod) + 0.5f) * MathHelper.sin(animPeriod * 0.5f); + matrices.multiply(RotationAxis.POSITIVE_X.rotation(tiltX * WOBBLE_STRENGTH), 0.5f, 0f, 0.5f); + + float tiltZ = MathHelper.sin(animPeriod); + matrices.multiply(RotationAxis.POSITIVE_Z.rotation(tiltZ * WOBBLE_STRENGTH), 0.5f, 0f, 0.5f); + } else { + float yaw = (1f - tilt) * MathHelper.sin(-tilt * 3 * MathHelper.PI) * 0.125f; + matrices.multiply(RotationAxis.POSITIVE_Y.rotation(yaw), 0.5f, 0f, 0.5f); + } + } + } + + var sherds = pot.getSherds(); + EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices, this.baseModel, light, overlay); + + EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices, + this.potPatternModels.get(DecoratedPotPatterns.fromSherd(sherds.back()))[0], light, overlay); + EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices, + this.potPatternModels.get(DecoratedPotPatterns.fromSherd(sherds.left()))[1], light, overlay); + EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices, + this.potPatternModels.get(DecoratedPotPatterns.fromSherd(sherds.right()))[2], light, overlay); + EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices, + this.potPatternModels.get(DecoratedPotPatterns.fromSherd(sherds.front()))[3], light, overlay); + + matrices.pop(); + } + } + + @Override + public void onModelsReload() { + this.baseModel = null; + this.potPatternModels = null; + } +} \ No newline at end of file diff --git a/src/main/java/foundationgames/enhancedblockentities/mixin/DecoratedPotBlockEntityMixin.java b/src/main/java/foundationgames/enhancedblockentities/mixin/DecoratedPotBlockEntityMixin.java index 3bee64a7..a9cad02f 100644 --- a/src/main/java/foundationgames/enhancedblockentities/mixin/DecoratedPotBlockEntityMixin.java +++ b/src/main/java/foundationgames/enhancedblockentities/mixin/DecoratedPotBlockEntityMixin.java @@ -1,15 +1,20 @@ package foundationgames.enhancedblockentities.mixin; import foundationgames.enhancedblockentities.util.WorldUtil; +import foundationgames.enhancedblockentities.util.duck.ModelStateHolder; import net.minecraft.block.entity.DecoratedPotBlockEntity; import net.minecraft.nbt.NbtCompound; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(DecoratedPotBlockEntity.class) -public class DecoratedPotBlockEntityMixin { +public class DecoratedPotBlockEntityMixin implements ModelStateHolder { + @Unique private int enhanced_bes$modelState = 0; + @Inject(method = "readNbt", at = @At("TAIL")) private void enhanced_bes$updateChunkOnPatternsLoaded(NbtCompound nbt, CallbackInfo ci) { var self = (DecoratedPotBlockEntity)(Object)this; @@ -18,4 +23,33 @@ public class DecoratedPotBlockEntityMixin { WorldUtil.rebuildChunkSynchronously(self.getWorld(), self.getPos(), false); } } + + @Inject(method = "onSyncedBlockEvent", at = @At(value = "RETURN", shift = At.Shift.BEFORE, ordinal = 0)) + private void enhanced_bes$updateOnWobble(int type, int data, CallbackInfoReturnable cir) { + var self = (DecoratedPotBlockEntity)(Object)this; + var world = self.getWorld(); + + if (self.lastWobbleType == null) { + return; + } + + this.setModelState(1, world, self.getPos()); + + WorldUtil.schedule(world, self.lastWobbleTime + self.lastWobbleType.lengthInTicks, + () -> { + if (self.getWorld().getTime() >= self.lastWobbleTime + self.lastWobbleType.lengthInTicks) { + this.setModelState(0, world, self.getPos()); + } + }); + } + + @Override + public int getModelState() { + return enhanced_bes$modelState; + } + + @Override + public void applyModelState(int state) { + this.enhanced_bes$modelState = state; + } } diff --git a/src/main/java/foundationgames/enhancedblockentities/util/WorldUtil.java b/src/main/java/foundationgames/enhancedblockentities/util/WorldUtil.java index 1163d412..75d7cb6e 100644 --- a/src/main/java/foundationgames/enhancedblockentities/util/WorldUtil.java +++ b/src/main/java/foundationgames/enhancedblockentities/util/WorldUtil.java @@ -1,16 +1,26 @@ package foundationgames.enhancedblockentities.util; import foundationgames.enhancedblockentities.EnhancedBlockEntities; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.registry.RegistryKey; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkSectionPos; import net.minecraft.world.World; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; -public enum WorldUtil {; +public enum WorldUtil implements ClientTickEvents.EndWorldTick { + EVENT_LISTENER; + public static Set FORCE_SYNCHRONOUS_CHUNK_REBUILD = new HashSet<>(); + private static Map, Long2ObjectMap> SCHEDULED_TASKS = new HashMap<>(); public static void rebuildChunkSynchronously(World world, BlockPos pos, boolean forceSync) { var bState = world.getBlockState(pos); @@ -23,4 +33,24 @@ public static void rebuildChunkSynchronously(World world, BlockPos pos, boolean EnhancedBlockEntities.LOG.warn("Error rebuilding chunk at block pos "+pos); } } + + public static void schedule(World world, long time, Runnable action) { + SCHEDULED_TASKS.computeIfAbsent(world.getRegistryKey(), k -> new Long2ObjectOpenHashMap<>()).put(time, action); + } + + @Override + public void onEndTick(ClientWorld world) { + var key = world.getRegistryKey(); + + if (SCHEDULED_TASKS.containsKey(key)) { + SCHEDULED_TASKS.get(key).long2ObjectEntrySet().removeIf(entry -> { + if (world.getTime() >= entry.getLongKey()) { + entry.getValue().run(); + return true; + } + + return false; + }); + } + } } diff --git a/src/main/resources/assets/minecraft/models/block/decorated_pot_shaking.json b/src/main/resources/assets/minecraft/models/block/decorated_pot_shaking.json new file mode 100644 index 00000000..1456e72d --- /dev/null +++ b/src/main/resources/assets/minecraft/models/block/decorated_pot_shaking.json @@ -0,0 +1,5 @@ +{ + "textures": { + "particle": "minecraft:block/terracotta" + } +} \ No newline at end of file