aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorAnthony Hilyard <anthony.hilyard@gmail.com>2023-04-09 13:22:32 -0700
committerAnthony Hilyard <anthony.hilyard@gmail.com>2023-04-09 13:22:32 -0700
commitc205088078971c5bb1f4be084e1fe314dc7dad3b (patch)
tree70008c843678d1506b701703c87d466c780a8e3b /src/main/java
parent94e0927f324032c49a610f41c6055e56a0823321 (diff)
downloadIceberg-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')
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/Loader.java1
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/mixin/ItemMixin.java31
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/renderer/CheckedBufferSource.java47
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/renderer/CheckedBufferSourceSodium.java67
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java141
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/renderer/VertexCollector.java55
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/renderer/VertexCollectorSodium.java98
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/renderer/VertexConsumerSodium.java9
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/util/EntityCollector.java272
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/util/Selectors.java6
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/util/UnsafeUtil.java48
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