diff options
author | Anthony Hilyard <anthony.hilyard@gmail.com> | 2023-04-09 13:22:32 -0700 |
---|---|---|
committer | Anthony Hilyard <anthony.hilyard@gmail.com> | 2023-04-09 13:22:32 -0700 |
commit | c205088078971c5bb1f4be084e1fe314dc7dad3b (patch) | |
tree | 70008c843678d1506b701703c87d466c780a8e3b /src/main/java | |
parent | 94e0927f324032c49a610f41c6055e56a0823321 (diff) | |
download | Iceberg-c205088078971c5bb1f4be084e1fe314dc7dad3b.tar.gz Iceberg-c205088078971c5bb1f4be084e1fe314dc7dad3b.tar.bz2 Iceberg-c205088078971c5bb1f4be084e1fe314dc7dad3b.zip |
Ported changes from 1.1.5. 3D item renderer now supports most items
that spawn entities.
Diffstat (limited to 'src/main/java')
11 files changed, 697 insertions, 78 deletions
diff --git a/src/main/java/com/anthonyhilyard/iceberg/Loader.java b/src/main/java/com/anthonyhilyard/iceberg/Loader.java index 8d6ceb4..22e06de 100644 --- a/src/main/java/com/anthonyhilyard/iceberg/Loader.java +++ b/src/main/java/com/anthonyhilyard/iceberg/Loader.java @@ -41,6 +41,5 @@ public class Loader @SubscribeEvent public void onCommonSetup(FMLCommonSetupEvent event) { - } } diff --git a/src/main/java/com/anthonyhilyard/iceberg/mixin/ItemMixin.java b/src/main/java/com/anthonyhilyard/iceberg/mixin/ItemMixin.java new file mode 100644 index 0000000..75b8ec3 --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/mixin/ItemMixin.java @@ -0,0 +1,31 @@ +package com.anthonyhilyard.iceberg.mixin; + +import com.anthonyhilyard.iceberg.util.EntityCollector; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +@Mixin(value = Item.class, priority = 100) +public class ItemMixin +{ + @Inject(method = "getPlayerPOVHitResult", at = @At(value = "HEAD"), cancellable = true) + private static void icebergGetPlayerPOVHitResult(Level level, Player player, ClipContext.Fluid clipContext, CallbackInfoReturnable<HitResult> info) + { + // If the level is an entity collector, always return a valid hit result. + if (level instanceof EntityCollector) + { + info.setReturnValue(new BlockHitResult(Vec3.ZERO, Direction.DOWN, BlockPos.ZERO, false)); + } + } +} diff --git a/src/main/java/com/anthonyhilyard/iceberg/renderer/CheckedBufferSource.java b/src/main/java/com/anthonyhilyard/iceberg/renderer/CheckedBufferSource.java index 5d34821..ffffdec 100644 --- a/src/main/java/com/anthonyhilyard/iceberg/renderer/CheckedBufferSource.java +++ b/src/main/java/com/anthonyhilyard/iceberg/renderer/CheckedBufferSource.java @@ -1,20 +1,59 @@ package com.anthonyhilyard.iceberg.renderer; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; + +import com.anthonyhilyard.iceberg.Loader; + import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; +import net.minecraftforge.fml.ModList; -public final class CheckedBufferSource implements MultiBufferSource +public class CheckedBufferSource implements MultiBufferSource { - private boolean hasRendered = false; - private final MultiBufferSource bufferSource; + protected boolean hasRendered = false; + protected final MultiBufferSource bufferSource; + + private static Boolean useSodiumVersion = null; - public CheckedBufferSource(MultiBufferSource bufferSource) + protected CheckedBufferSource(MultiBufferSource bufferSource) { this.bufferSource = bufferSource; } + public static CheckedBufferSource create(MultiBufferSource bufferSource) + { + if (useSodiumVersion == null) + { + try + { + // Check if Rubidium 0.6.4 is installed using Forge API. + useSodiumVersion = ModList.get().isLoaded("rubidium") && ModList.get().getModContainerById("rubidium").get().getModInfo().getVersion().equals(new DefaultArtifactVersion("0.6.4")); + } + catch (Exception e) + { + Loader.LOGGER.error(ExceptionUtils.getStackTrace(e)); + } + } + + if (useSodiumVersion) + { + // Instantiate the Rubidium implementation using reflection. + try + { + return (CheckedBufferSource) Class.forName("com.anthonyhilyard.iceberg.renderer.CheckedBufferSourceSodium").getDeclaredConstructor(MultiBufferSource.class).newInstance(bufferSource); + } + catch (Exception e) + { + Loader.LOGGER.error(ExceptionUtils.getStackTrace(e)); + } + } + + return new CheckedBufferSource(bufferSource); + } + @Override public VertexConsumer getBuffer(RenderType renderType) { diff --git a/src/main/java/com/anthonyhilyard/iceberg/renderer/CheckedBufferSourceSodium.java b/src/main/java/com/anthonyhilyard/iceberg/renderer/CheckedBufferSourceSodium.java new file mode 100644 index 0000000..7198512 --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/renderer/CheckedBufferSourceSodium.java @@ -0,0 +1,67 @@ +package com.anthonyhilyard.iceberg.renderer; + +import org.lwjgl.system.MemoryStack; + +import com.mojang.blaze3d.vertex.VertexConsumer; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; + +// import me.jellysquid.mods.sodium.client.render.vertex.VertexBufferWriter; +// import me.jellysquid.mods.sodium.client.render.vertex.VertexFormatDescription; + +public final class CheckedBufferSourceSodium extends CheckedBufferSource +{ + protected CheckedBufferSourceSodium(MultiBufferSource bufferSource) + { + super(bufferSource); + } + + // @Override + // public VertexConsumer getBuffer(RenderType renderType) + // { + // final VertexConsumer vertexConsumer = bufferSource.getBuffer(renderType); + // VertexConsumer vertexConsumerWrap = new VertexConsumerSodium() + // { + // @Override + // public VertexConsumer vertex(double x, double y, double z) + // { + // hasRendered = true; + // return vertexConsumer.vertex(x, y, z); + // } + + // @Override + // public VertexConsumer color(int r, int g, int b, int a) { return vertexConsumer.color(r, g, b, a); } + + // @Override + // public VertexConsumer uv(float u, float v) { return vertexConsumer.uv(u, v); } + + // @Override + // public VertexConsumer overlayCoords(int x, int y) { return vertexConsumer.overlayCoords(x, y); } + + // @Override + // public VertexConsumer uv2(int u, int v) { return vertexConsumer.uv2(u, v); } + + // @Override + // public VertexConsumer normal(float x, float y, float z) { return vertexConsumer.normal(x, y, z); } + + // @Override + // public void endVertex() { vertexConsumer.endVertex(); } + + // @Override + // public void defaultColor(int r, int g, int b, int a) { vertexConsumer.defaultColor(r, g, b, a); } + + // @Override + // public void unsetDefaultColor() { vertexConsumer.unsetDefaultColor(); } + + // @Override + // public void push(MemoryStack memoryStack, long pointer, int count, VertexFormatDescription format) + // { + // hasRendered = true; + // ((VertexBufferWriter)vertexConsumer).push(memoryStack, pointer, count, format); + // } + // }; + + // return vertexConsumerWrap; + // } +}
\ No newline at end of file diff --git a/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java b/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java index 77e814a..38d2d56 100644 --- a/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java +++ b/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java @@ -4,8 +4,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Predicate; +import com.anthonyhilyard.iceberg.util.EntityCollector; import com.google.common.collect.Maps; import org.joml.Matrix4f; @@ -38,7 +40,9 @@ import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.MultiBufferSource.BufferSource; +import net.minecraft.client.renderer.block.BlockModelShaper; import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.resources.model.BakedModel; @@ -53,17 +57,12 @@ import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.animal.horse.Horse; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.entity.vehicle.Boat; -import net.minecraft.world.entity.vehicle.ChestBoat; import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.BoatItem; import net.minecraft.world.item.HorseArmorItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.minecraft.world.item.MinecartItem; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.HalfTransparentBlock; @@ -77,7 +76,7 @@ import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.extensions.common.IClientItemExtensions; /** - * An extended ItemRenderer with extended functionality, such as allowing items to be rendered to a RenderTarget + * An extended ItemRenderer with extra functionality, such as allowing items to be rendered to a RenderTarget * before drawing to screen for alpha support, and allowing handheld item models to be rendered into the gui. */ public class CustomItemRenderer extends ItemRenderer @@ -87,15 +86,17 @@ public class CustomItemRenderer extends ItemRenderer private static RenderTarget iconFrameBuffer = null; private static ArmorStand armorStand = null; - private static AbstractMinecart minecart = null; - private static Boat boat = null; private static Horse horse = null; + private static Entity entity = null; private static Pair<Item, CompoundTag> cachedArmorStandItem = null; private static Pair<Item, CompoundTag> cachedHorseArmorItem = null; + private static Item cachedEntityItem = null; private static Map<Item, ModelBounds> modelBoundsCache = Maps.newHashMap(); private static final List<Direction> quadDirections; - static { + + static + { quadDirections = new ArrayList<>(Arrays.asList(Direction.values())); quadDirections.add(null); } @@ -166,9 +167,9 @@ public class CustomItemRenderer extends ItemRenderer RenderSystem.runAsFancy(() -> entityRenderDispatcher.render(entity, 0.0, 0.0, 0.0, 0.0f, 1.0f, poseStack, bufferSource, packedLight)); - if (bufferSource instanceof BufferSource) + if (bufferSource instanceof BufferSource source) { - ((BufferSource)bufferSource).endBatch(); + source.endBatch(); } entityRenderDispatcher.setRenderShadow(true); @@ -194,9 +195,9 @@ public class CustomItemRenderer extends ItemRenderer if (!bakedModel.isCustomRenderer() && !itemStack.is(Items.TRIDENT)) { boolean fabulous; - if (transformType != ItemTransforms.TransformType.GUI && !transformType.firstPerson() && itemStack.getItem() instanceof BlockItem) + if (transformType != ItemTransforms.TransformType.GUI && !transformType.firstPerson() && itemStack.getItem() instanceof BlockItem blockItem) { - Block block = ((BlockItem)itemStack.getItem()).getBlock(); + Block block = blockItem.getBlock(); fabulous = !(block instanceof HalfTransparentBlock) && !(block instanceof StainedGlassPaneBlock); } else @@ -206,33 +207,42 @@ public class CustomItemRenderer extends ItemRenderer if (bufferSourceReady.test(bufferSource) && itemStack.getItem() instanceof BlockItem blockItem) { + Block block = blockItem.getBlock(); BakedModel blockModel = null; + BlockModelShaper blockModelShaper = minecraft.getBlockRenderer().getBlockModelShaper(); boolean isBlockEntity = false; - blockModel = minecraft.getBlockRenderer().getBlockModelShaper().getBlockModel(blockItem.getBlock().defaultBlockState()); + blockModel = blockModelShaper.getBlockModel(block.defaultBlockState()); if (blockModel != modelManager.getMissingModel()) { // First try rendering via the BlockEntityWithoutLevelRenderer. - blockEntityRenderer.renderByItem(itemStack, transformType, poseStack, bufferSource, packedLight, packedOverlay); + try + { + blockEntityRenderer.renderByItem(itemStack, transformType, poseStack, bufferSource, packedLight, packedOverlay); + } + catch (Exception e) + { + // Do nothing if an exception occurs. + } } else { blockModel = null; } - if (blockItem.getBlock().defaultBlockState().hasProperty(BlockStateProperties.DOUBLE_BLOCK_HALF)) + if (block.defaultBlockState().hasProperty(BlockStateProperties.DOUBLE_BLOCK_HALF)) { // This is a double block, so we'll need to render both halves. // First render the bottom half. - BlockState bottomState = blockItem.getBlock().defaultBlockState().setValue(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER); - BakedModel bottomModel = minecraft.getBlockRenderer().getBlockModelShaper().getBlockModel(bottomState); + BlockState bottomState = block.defaultBlockState().setValue(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER); + BakedModel bottomModel = blockModelShaper.getBlockModel(bottomState); renderBakedModel(itemStack, transformType, poseStack, bufferSource, packedLight, packedOverlay, bottomModel, fabulous); // Then render the top half. poseStack.pushPose(); poseStack.translate(0.0f, 1.0f, 0.0f); - BlockState topState = blockItem.getBlock().defaultBlockState().setValue(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.UPPER); - BakedModel topModel = minecraft.getBlockRenderer().getBlockModelShaper().getBlockModel(topState); + BlockState topState = block.defaultBlockState().setValue(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.UPPER); + BakedModel topModel = blockModelShaper.getBlockModel(topState); renderBakedModel(itemStack, transformType, poseStack, bufferSource, packedLight, packedOverlay, topModel, fabulous); poseStack.popPose(); } @@ -257,27 +267,19 @@ public class CustomItemRenderer extends ItemRenderer } } - // Now try rendering entity models for items that spawn minecarts or boats. - if (bufferSourceReady.test(bufferSource) && itemStack.getItem() instanceof MinecartItem minecartItem) + // Now try rendering entity models for items that spawn entities. + if (bufferSourceReady.test(bufferSource) && EntityCollector.itemCreatesEntity(itemStack.getItem(), Entity.class)) { - if (updateMinecart(minecartItem)) + if (updateEntity(itemStack.getItem())) { - renderEntityModel(minecart, poseStack, bufferSource, packedLight); - } - } - - if (bufferSourceReady.test(bufferSource) && itemStack.getItem() instanceof BoatItem boatItem) - { - if (updateBoat(boatItem)) - { - renderEntityModel(boat, poseStack, bufferSource, packedLight); + renderEntityModel(entity, poseStack, bufferSource, packedLight); } } // If this is horse armor, render it here. if (bufferSourceReady.test(bufferSource) && itemStack.getItem() instanceof HorseArmorItem) { - if (updateHorse(itemStack)) + if (updateHorseArmor(itemStack)) { renderEntityModel(horse, poseStack, bufferSource, packedLight); } @@ -304,7 +306,7 @@ public class CustomItemRenderer extends ItemRenderer { isBlockItem = true; } - else if (itemStack.getItem() instanceof MinecartItem || itemStack.getItem() instanceof BoatItem) + else if (EntityCollector.itemCreatesEntity(itemStack.getItem(), Entity.class)) { spawnsEntity = true; } @@ -316,6 +318,7 @@ public class CustomItemRenderer extends ItemRenderer poseStack.pushPose(); + poseStack.translate(0.5f, 0.5f, 0.5f); if (isBlockItem || spawnsEntity) { // Apply the standard block rotation so block entities match other blocks. @@ -325,6 +328,7 @@ public class CustomItemRenderer extends ItemRenderer { ForgeHooksClient.handleCameraTransforms(poseStack, bakedModel, transformType, leftHanded); } + poseStack.translate(-0.5f, -0.5f, -0.5f); // Get the model bounds. ModelBounds modelBounds = getModelBounds(itemStack, transformType, leftHanded, poseStack, rotation, bufferSource, packedLight, packedOverlay, bakedModel); @@ -337,8 +341,7 @@ public class CustomItemRenderer extends ItemRenderer poseStack.mulPose(rotation); // Scale the model to fit. - float scale = 1.0f / Math.max(modelBounds.height, modelBounds.radius * 2.0f); - scale *= isBlockItem ? 0.8f : 1.0f; + float scale = 0.8f / Math.max(modelBounds.height, modelBounds.radius * 2.0f); // Adjust the scale based on the armor type. if (isArmor) @@ -349,7 +352,10 @@ public class CustomItemRenderer extends ItemRenderer scale *= 0.75f; break; case LEGS: - scale *= 1.1f; + scale *= 1.3f; + break; + case FEET: + scale *= 0.85f; break; default: break; @@ -360,6 +366,7 @@ public class CustomItemRenderer extends ItemRenderer // Translate the model to the center of the item. poseStack.translate(-modelBounds.center.x(), -modelBounds.center.y(), -modelBounds.center.z()); + poseStack.translate(0.5f, 0.5f, 0.5f); // Reapply the camera transforms. if (isBlockItem || spawnsEntity) { @@ -370,8 +377,9 @@ public class CustomItemRenderer extends ItemRenderer { bakedModel = ForgeHooksClient.handleCameraTransforms(poseStack, bakedModel, transformType, leftHanded); } + poseStack.translate(-0.5f, -0.5f, -0.5f); - CheckedBufferSource checkedBufferSource = new CheckedBufferSource(bufferSource); + CheckedBufferSource checkedBufferSource = CheckedBufferSource.create(bufferSource); renderModelInternal(itemStack, transformType, leftHanded, poseStack, rotation, checkedBufferSource, packedLight, packedOverlay, bakedModel, b -> !b.hasRendered()); poseStack.popPose(); @@ -401,11 +409,11 @@ public class CustomItemRenderer extends ItemRenderer private void renderBakedModel(ItemStack itemStack, ItemTransforms.TransformType transformType, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay, BakedModel bakedModel, boolean fabulous) { - for (var model : bakedModel.getRenderPasses(itemStack, fabulous)) + for (BakedModel model : bakedModel.getRenderPasses(itemStack, fabulous)) { - for (var rendertype : model.getRenderTypes(itemStack, fabulous)) + for (RenderType renderType : model.getRenderTypes(itemStack, fabulous)) { - VertexConsumer vertexconsumer; + VertexConsumer vertexConsumer; if (itemStack.is(ItemTags.COMPASSES) && itemStack.hasFoil()) { poseStack.pushPose(); @@ -421,25 +429,25 @@ public class CustomItemRenderer extends ItemRenderer if (fabulous) { - vertexconsumer = getCompassFoilBufferDirect(bufferSource, rendertype, posestack$pose); + vertexConsumer = getCompassFoilBufferDirect(bufferSource, renderType, posestack$pose); } else { - vertexconsumer = getCompassFoilBuffer(bufferSource, rendertype, posestack$pose); + vertexConsumer = getCompassFoilBuffer(bufferSource, renderType, posestack$pose); } poseStack.popPose(); } else if (fabulous) { - vertexconsumer = getFoilBufferDirect(bufferSource, rendertype, true, itemStack.hasFoil()); + vertexConsumer = getFoilBufferDirect(bufferSource, renderType, true, itemStack.hasFoil()); } else { - vertexconsumer = getFoilBuffer(bufferSource, rendertype, true, itemStack.hasFoil()); + vertexConsumer = getFoilBuffer(bufferSource, renderType, true, itemStack.hasFoil()); } - renderModelLists(model, itemStack, packedLight, packedOverlay, poseStack, vertexconsumer); + renderModelLists(model, itemStack, packedLight, packedOverlay, poseStack, vertexConsumer); } } } @@ -483,32 +491,33 @@ public class CustomItemRenderer extends ItemRenderer return true; } - private boolean updateMinecart(MinecartItem item) + private Entity getEntityFromItem(Item item) { - if (minecart == null || minecart.getMinecartType() != item.type) + Entity collectedEntity = null; + List<Entity> collectedEntities = EntityCollector.collectEntitiesFromItem(item); + if (!collectedEntities.isEmpty()) { - Minecraft minecraft = Minecraft.getInstance(); - minecart = AbstractMinecart.createMinecart(minecraft.level, 0, 0, 0, item.type); + // Just return the first entity collected. + // TODO: Should all entities be considered for weird items that spawn multiple? + collectedEntity = collectedEntities.get(0); } - // If somehow the minecart is still null, then we can't render anything. - return minecart != null; + return collectedEntity; } - private boolean updateBoat(BoatItem item) + private boolean updateEntity(Item item) { - if (boat == null || boat.getVariant() != item.type || (boat instanceof ChestBoat) != item.hasChest) + if (entity == null || cachedEntityItem != item) { - Minecraft minecraft = Minecraft.getInstance(); - boat = item.hasChest ? new ChestBoat(minecraft.level, 0, 0, 0) : new Boat(minecraft.level, 0, 0, 0); - boat.setVariant(item.type); + entity = getEntityFromItem(item); + cachedEntityItem = item; } - // If somehow the boat is still null, then we can't render anything. - return boat != null; + // If somehow the entity is still null, then we can't render anything. + return entity != null; } - private boolean updateHorse(ItemStack horseArmorItem) + private boolean updateHorseArmor(ItemStack horseArmorItem) { // If this isn't a horse armor item, we can't render anything. if (!(horseArmorItem.getItem() instanceof HorseArmorItem)) @@ -541,11 +550,11 @@ public class CustomItemRenderer extends ItemRenderer return true; } - private ModelBounds boundsFromVertices(List<Vector3f> vertices) + private ModelBounds boundsFromVertices(Set<Vector3f> vertices) { Vector3f center = new Vector3f(); - float radius = 0.0F; - float height = 0.0F; + float radius = 0.0f; + float height = 0.0f; float minX = Float.MAX_VALUE; float minY = Float.MAX_VALUE; @@ -564,12 +573,12 @@ public class CustomItemRenderer extends ItemRenderer maxZ = Math.max(maxZ, vertex.z); } - center = new Vector3f((minX + maxX) / 2.0F, (minY + maxY) / 2.0F, (minZ + maxZ) / 2.0F); + center = new Vector3f((minX + maxX) / 2.0f, (minY + maxY) / 2.0f, (minZ + maxZ) / 2.0f); height = maxY - minY; for (Vector3f vertex : vertices) { - radius = Math.max(radius, (float) Math.sqrt((vertex.x - center.x) * (vertex.x - center.x) + (vertex.y - center.y) * (vertex.y - center.y))); + radius = Math.max(radius, (float) Math.sqrt((vertex.x - center.x) * (vertex.x - center.x) + (vertex.z - center.z) * (vertex.z - center.z))); } return new ModelBounds(center, height, radius); @@ -580,7 +589,7 @@ public class CustomItemRenderer extends ItemRenderer { if (!modelBoundsCache.containsKey(itemStack.getItem())) { - VertexCollector vertexCollector = new VertexCollector(); + VertexCollector vertexCollector = VertexCollector.create(); renderModelInternal(itemStack, transformType, leftHanded, poseStack, rotation, vertexCollector, packedLight, packedOverlay, bakedModel, b -> b.getVertices().isEmpty()); // Now store the bounds in the cache. diff --git a/src/main/java/com/anthonyhilyard/iceberg/renderer/VertexCollector.java b/src/main/java/com/anthonyhilyard/iceberg/renderer/VertexCollector.java index 7554893..4cca19d 100644 --- a/src/main/java/com/anthonyhilyard/iceberg/renderer/VertexCollector.java +++ b/src/main/java/com/anthonyhilyard/iceberg/renderer/VertexCollector.java @@ -1,21 +1,62 @@ package com.anthonyhilyard.iceberg.renderer; -import java.util.List; +import java.util.Set; -import org.apache.commons.compress.utils.Lists; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.joml.Vector3f; +import com.anthonyhilyard.iceberg.Loader; +import com.google.common.collect.Sets; import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; +import net.minecraftforge.fml.ModList; public class VertexCollector implements MultiBufferSource { - private final List<Vector3f> vertices = Lists.newArrayList(); - private final Vector3f currentVertex = new Vector3f(); - private int currentAlpha = 255; - private int defaultAlpha = 255; + protected final Set<Vector3f> vertices = Sets.newHashSet(); + protected final Vector3f currentVertex = new Vector3f(); + protected int currentAlpha = 255; + protected int defaultAlpha = 255; + + private static Boolean useSodiumVersion = null; + + protected VertexCollector() + { + super(); + } + + public static VertexCollector create() + { + if (useSodiumVersion == null) + { + try + { + // Check if Rubidium 0.6.4 is installed using Forge API. + useSodiumVersion = ModList.get().isLoaded("rubidium") && ModList.get().getModContainerById("rubidium").get().getModInfo().getVersion().equals(new DefaultArtifactVersion("0.6.4")); + } + catch (Exception e) + { + Loader.LOGGER.error(ExceptionUtils.getStackTrace(e)); + } + } + + if (useSodiumVersion) + { + // Instantiate the Sodium implementation using reflection. + try + { + return (VertexCollector) Class.forName("com.anthonyhilyard.iceberg.renderer.VertexCollectorSodium").getDeclaredConstructor().newInstance(); + } + catch (Exception e) + { + Loader.LOGGER.error(ExceptionUtils.getStackTrace(e)); + } + } + return new VertexCollector(); + } @Override public VertexConsumer getBuffer(RenderType renderType) @@ -72,7 +113,7 @@ public class VertexCollector implements MultiBufferSource }; } - public List<Vector3f> getVertices() + public Set<Vector3f> getVertices() { return vertices; } diff --git a/src/main/java/com/anthonyhilyard/iceberg/renderer/VertexCollectorSodium.java b/src/main/java/com/anthonyhilyard/iceberg/renderer/VertexCollectorSodium.java new file mode 100644 index 0000000..9cfeff5 --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/renderer/VertexCollectorSodium.java @@ -0,0 +1,98 @@ +package com.anthonyhilyard.iceberg.renderer; + +import org.joml.Vector3f; +import org.lwjgl.system.MemoryStack; + +import com.anthonyhilyard.iceberg.util.UnsafeUtil; +import com.mojang.blaze3d.vertex.VertexConsumer; + +import net.minecraft.client.renderer.RenderType; + +// import me.jellysquid.mods.sodium.client.render.vertex.VertexFormatDescription; +// import me.jellysquid.mods.sodium.client.render.vertex.transform.CommonVertexElement; + +public class VertexCollectorSodium extends VertexCollector +{ + protected VertexCollectorSodium() + { + super(); + } + + // @Override + // public VertexConsumer getBuffer(RenderType renderType) + // { + // return new VertexConsumerSodium() + // { + // @Override + // public VertexConsumer vertex(double x, double y, double z) + // { + // currentVertex.set((float) x, (float) y, (float) z); + // currentAlpha = defaultAlpha; + // return this; + // } + + // @Override + // public VertexConsumer color(int r, int g, int b, int a) + // { + // currentAlpha = a; + // return this; + // } + + // @Override + // public VertexConsumer uv(float u, float v) { return this; } + + // @Override + // public VertexConsumer overlayCoords(int x, int y) { return this; } + + // @Override + // public VertexConsumer uv2(int u, int v) { return this; } + + // @Override + // public VertexConsumer normal(float x, float y, float z) { return this; } + + // @Override + // public void endVertex() + // { + // if (currentAlpha >= 25) + // { + // vertices.add(new Vector3f(currentVertex)); + // } + // } + + // @Override + // public void defaultColor(int r, int g, int b, int a) + // { + // defaultAlpha = a; + // } + + // @Override + // public void unsetDefaultColor() + // { + // defaultAlpha = 255; + // } + + // @Override + // public void push(MemoryStack memoryStack, long pointer, int count, VertexFormatDescription format) + // { + // // Loop over each vertex, and add it to the list if it's opaque. + // // To determine this, we need to check the vertex format to find the vertex position and alpha. + // for (int i = 0; i < count; i++) + // { + // // Get the vertex position. + // float x = UnsafeUtil.readFloat(pointer + i * format.stride + format.getOffset(CommonVertexElement.POSITION)); + // float y = UnsafeUtil.readFloat(pointer + i * format.stride + format.getOffset(CommonVertexElement.POSITION) + 4); + // float z = UnsafeUtil.readFloat(pointer + i * format.stride + format.getOffset(CommonVertexElement.POSITION) + 8); + + // // Get the vertex alpha. + // int a = UnsafeUtil.readByte(pointer + i * format.stride + format.getOffset(CommonVertexElement.COLOR) + 3) & 0xFF; + + // // Add the vertex to the list if it's opaque. + // if (a >= 25) + // { + // vertices.add(new Vector3f(x, y, z)); + // } + // } + // } + // }; + // } +}
\ No newline at end of file diff --git a/src/main/java/com/anthonyhilyard/iceberg/renderer/VertexConsumerSodium.java b/src/main/java/com/anthonyhilyard/iceberg/renderer/VertexConsumerSodium.java new file mode 100644 index 0000000..4ad98fc --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/renderer/VertexConsumerSodium.java @@ -0,0 +1,9 @@ +package com.anthonyhilyard.iceberg.renderer; + +import com.mojang.blaze3d.vertex.VertexConsumer; + +//import me.jellysquid.mods.sodium.client.render.vertex.VertexBufferWriter; + +public interface VertexConsumerSodium extends VertexConsumer //, VertexBufferWriter +{ +}
\ No newline at end of file diff --git a/src/main/java/com/anthonyhilyard/iceberg/util/EntityCollector.java b/src/main/java/com/anthonyhilyard/iceberg/util/EntityCollector.java new file mode 100644 index 0000000..1524a88 --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/util/EntityCollector.java @@ -0,0 +1,272 @@ +package com.anthonyhilyard.iceberg.util; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Consumer; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.mojang.authlib.GameProfile; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.core.RegistryAccess; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.AbortableIterationConsumer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.SpawnEggItem; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.entity.EntityTypeTest; +import net.minecraft.world.level.entity.LevelEntityGetter; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.GameEvent.Context; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.saveddata.maps.MapItemSavedData; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.scores.Scoreboard; +import net.minecraft.world.ticks.LevelTickAccess; + +public class EntityCollector extends Level +{ + private final Level wrappedLevel; + private final List<Entity> collectedEntities = Lists.newArrayList(); + private BlockState blockState = Blocks.AIR.defaultBlockState(); + + private static final Map<Level, EntityCollector> wrappedLevelsMap = Maps.newHashMap(); + private static final Map<ItemClassPair, Boolean> itemCreatesEntityResultCache = Maps.newHashMap(); + + private record ItemClassPair(Item item, Class<?> targetClass) {} + + protected EntityCollector(Level wrapped) + { + super(null, null, wrapped.dimensionTypeRegistration(), wrapped.getProfilerSupplier(), false, wrapped.isDebug(), 0, 0); + wrappedLevel = wrapped; + } + + public static EntityCollector of(Level wrappedLevel) + { + if (!wrappedLevelsMap.containsKey(wrappedLevel)) + { + wrappedLevelsMap.put(wrappedLevel, new EntityCollector(wrappedLevel)); + } + + return wrappedLevelsMap.get(wrappedLevel); + } + + public static List<Entity> collectEntitiesFromItem(Item item) + { + Minecraft minecraft = Minecraft.getInstance(); + List<Entity> entities = Lists.newArrayList(); + + try + { + Player dummyPlayer = new Player(minecraft.player.level, BlockPos.ZERO, 0.0f, new GameProfile(null, "_dummy")) { + @Override public boolean isSpectator() { return false; } + @Override public boolean isCreative() { return false; } + }; + + dummyPlayer.setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(item)); + + EntityCollector levelWrapper = EntityCollector.of(dummyPlayer.level); + + if (item instanceof SpawnEggItem spawnEggItem) + { + entities.add(spawnEggItem.getType(new CompoundTag()).create(levelWrapper)); + } + else + { + item.use(levelWrapper, dummyPlayer, InteractionHand.MAIN_HAND); + } + + entities.addAll(levelWrapper.getCollectedEntities()); + + // If we didn't spawn any entities, try again but this time on a simulated rail for minecart-like items. + if (entities.isEmpty()) + { + levelWrapper.setBlockState(Blocks.RAIL.defaultBlockState()); + item.useOn(new UseOnContext(levelWrapper, dummyPlayer, InteractionHand.MAIN_HAND, dummyPlayer.getItemInHand(InteractionHand.MAIN_HAND), new BlockHitResult(Vec3.ZERO, Direction.DOWN, BlockPos.ZERO, false))); + levelWrapper.setBlockState(Blocks.AIR.defaultBlockState()); + + entities.addAll(levelWrapper.getCollectedEntities()); + } + } + catch (Exception e) + { + // Ignore any errors. + } + + return entities; + } + + public static <T extends Entity> boolean itemCreatesEntity(Item item, Class<T> targetClass) + { + ItemClassPair key = new ItemClassPair(item, targetClass); + boolean result = false; + if (!itemCreatesEntityResultCache.containsKey(key)) + { + // Return true if any collected entities from this item are a subclass of the given type. + for (Entity entity : collectEntitiesFromItem(item)) + { + if (targetClass.isInstance(entity)) + { + result = true; + break; + } + } + + itemCreatesEntityResultCache.put(key, result); + } + + return itemCreatesEntityResultCache.get(key); + } + + public List<Entity> getCollectedEntities() + { + // Clear the collected entities after this method is called. + List<Entity> entities = Lists.newArrayList(); + entities.addAll(collectedEntities); + collectedEntities.clear(); + return entities; + } + + public void setBlockState(BlockState blockState) + { + this.blockState = blockState; + } + + @Override + public BlockState getBlockState(BlockPos blockPos) + { + return blockState; + } + + @Override + public boolean noCollision(Entity entity, AABB boundingBox) + { + return true; + } + + @Override + public boolean addFreshEntity(Entity entity) + { + collectedEntities.add(entity); + return false; + } + + @Override + public LevelTickAccess<Block> getBlockTicks() { return wrappedLevel.getBlockTicks(); } + + @Override + public LevelTickAccess<Fluid> getFluidTicks() { return wrappedLevel.getFluidTicks(); } + + @Override + public ChunkSource getChunkSource() { return wrappedLevel.getChunkSource(); } + + + @Override + public void levelEvent(Player p_46771_, int p_46772_, BlockPos p_46773_, int p_46774_) { /* No events. */ } + + @Override + public void gameEvent(GameEvent p_220404_, Vec3 p_220405_, Context p_220406_) { /* No events. */ } + + + @Override + public List<? extends Player> players() { return wrappedLevel.players(); } + + + @Override + public Holder<Biome> getUncachedNoiseBiome(int p_204159_, int p_204160_, int p_204161_) { return wrappedLevel.getUncachedNoiseBiome(p_204159_, p_204160_, p_204161_); } + + + @Override + public RegistryAccess registryAccess() { return wrappedLevel.registryAccess(); } + + + @Override + public FeatureFlagSet enabledFeatures() { return wrappedLevel.enabledFeatures(); } + + @Override + public float getShade(Direction p_45522_, boolean p_45523_) { return wrappedLevel.getShade(p_45522_, p_45523_); } + + + @Override + public void sendBlockUpdated(BlockPos p_46612_, BlockState p_46613_, BlockState p_46614_, int p_46615_) { /* No block updates. */ } + + @Override + public void playSeededSound(Player p_262953_, double p_263004_, double p_263398_, double p_263376_, Holder<SoundEvent> p_263359_, SoundSource p_263020_, float p_263055_, float p_262914_, long p_262991_) { /* No sounds. */ } + + @Override + public void playSeededSound(Player p_220372_, Entity p_220373_, Holder<SoundEvent> p_263500_, SoundSource p_220375_, float p_220376_, float p_220377_, long p_220378_) { /* No sounds. */ } + + + @Override + public String gatherChunkSourceStats() { return wrappedLevel.gatherChunkSourceStats(); } + + @Override + public Entity getEntity(int p_46492_) { return null; } + + + @Override + public MapItemSavedData getMapData(String p_46650_) { return wrappedLevel.getMapData(p_46650_); } + + @Override + public void setMapData(String p_151533_, MapItemSavedData p_151534_) { /* No map data updates. */ } + + @Override + public int getFreeMapId() { return wrappedLevel.getFreeMapId(); } + + @Override + public void destroyBlockProgress(int p_46506_, BlockPos p_46507_, int p_46508_) { /* No block updates. */ } + + + @Override + public Scoreboard getScoreboard() { return wrappedLevel.getScoreboard(); } + + @Override + public RecipeManager getRecipeManager() { return wrappedLevel.getRecipeManager(); } + + @Override + public LevelEntityGetter<Entity> getEntities() + { + return new LevelEntityGetter<Entity>() { + + @Override + public Entity get(int p_156931_) { return null; } + + @Override + public Entity get(UUID p_156939_) { return null; } + + @Override + public Iterable<Entity> getAll() { return List.of(); } + + @Override + public <U extends Entity> void get(EntityTypeTest<Entity, U> p_156935_, AbortableIterationConsumer<U> p_261602_) {} + + @Override + public void get(AABB p_156937_, Consumer<Entity> p_156938_) {} + + @Override + public <U extends Entity> void get(EntityTypeTest<Entity, U> p_156932_, AABB p_156933_, AbortableIterationConsumer<U> p_261542_) {} + }; + + } +} diff --git a/src/main/java/com/anthonyhilyard/iceberg/util/Selectors.java b/src/main/java/com/anthonyhilyard/iceberg/util/Selectors.java index df9e292..0e1a3e1 100644 --- a/src/main/java/com/anthonyhilyard/iceberg/util/Selectors.java +++ b/src/main/java/com/anthonyhilyard/iceberg/util/Selectors.java @@ -127,6 +127,12 @@ public class Selectors return validateSelector(value.substring(1)); } + // If this is a wildcard selector, it is valid. + if (value.contentEquals("*")) + { + return true; + } + // This is a tag, which should be a resource location. if (value.startsWith("$")) { diff --git a/src/main/java/com/anthonyhilyard/iceberg/util/UnsafeUtil.java b/src/main/java/com/anthonyhilyard/iceberg/util/UnsafeUtil.java new file mode 100644 index 0000000..b49e29d --- /dev/null +++ b/src/main/java/com/anthonyhilyard/iceberg/util/UnsafeUtil.java @@ -0,0 +1,48 @@ +package com.anthonyhilyard.iceberg.util; + + +import sun.misc.Unsafe; + + +import java.lang.reflect.Field; + + +public class UnsafeUtil +{ + private static final Unsafe UNSAFE; + + + static + { + try + { + Field field = Unsafe.class.getDeclaredField("theUnsafe"); + field.setAccessible(true); + + + UNSAFE = (Unsafe) field.get(null); + } + catch (NoSuchFieldException | IllegalAccessException e) + { + throw new RuntimeException("Couldn't obtain reference to sun.misc.Unsafe", e); + } + } + + + public static float readFloat(long address) + { + return UNSAFE.getFloat(address); + } + + + public static int readInt(long address) + { + return UNSAFE.getInt(address); + } + + + public static byte readByte(long address) + { + return UNSAFE.getByte(address); + } +}
\ No newline at end of file |