aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md18
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/mixin/ItemMixin.java31
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java245
-rw-r--r--src/main/java/com/anthonyhilyard/iceberg/util/EntityCollector.java272
-rw-r--r--src/main/resources/iceberg.mixins.json3
5 files changed, 358 insertions, 211 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ca2ea85..fb0fc10 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,23 @@
# Changelog
+### 1.1.6
+- Fixed crash with some mods when rendering custom 3D models.
+- Added support to 3D item previews for most items that spawn entities (boats, minecarts, spawn eggs, etc).
+- Fixed bug that caused wildcard item selectors to be removed from config files.
+
+### 1.1.5
+- Fixed crash when trying to view 3D item previews while installed with Sodium version 0.4.9.
+- Fixed crash when trying to view 3D item previews for modded boats.
+- Fixed various item sizing and alignment issues with 3D item previews.
+
+### 1.1.4
+- Fixed a bug that caused resource-pack defined item models with custom scaling to render improperly with custom item renderer.
+- Fixed a bug that caused custom item renderer 3D models to have incorrect rotations.
+
+### 1.1.3
+- Fixed regression causing missing method crashes with some mods.
+- Fixed a crash that could occur when rendering custom tooltips.
+
### 1.1.2
- Fixed a bug with custom item renderer causing items rendered with alpha to be upside down and with incorrect lighting.
- Fixed a bug with stacking multiple Iceberg events (Fabric only).
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/CustomItemRenderer.java b/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java
index 44c7a61..70a3481 100644
--- a/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java
+++ b/src/main/java/com/anthonyhilyard/iceberg/renderer/CustomItemRenderer.java
@@ -1,19 +1,15 @@
package com.anthonyhilyard.iceberg.renderer;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
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 java.util.function.Supplier;
-import com.anthonyhilyard.iceberg.Loader;
+import com.anthonyhilyard.iceberg.util.EntityCollector;
import com.google.common.collect.Maps;
-import org.apache.commons.lang3.exception.ExceptionUtils;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
@@ -66,18 +62,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.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.HalfTransparentBlock;
@@ -86,13 +76,10 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
-import net.minecraft.world.phys.BlockHitResult;
-import net.minecraft.world.phys.HitResult;
-import net.minecraft.world.phys.Vec3;
/**
- * 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
@@ -102,16 +89,16 @@ 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 Item cachedBoatItem = 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);
}
@@ -235,7 +222,14 @@ public class CustomItemRenderer extends ItemRenderer
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
{
@@ -279,27 +273,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) && itemCreatesBoat(itemStack.getItem()))
- {
- if (updateBoat(itemStack.getItem()))
- {
- 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);
}
@@ -333,7 +319,7 @@ public class CustomItemRenderer extends ItemRenderer
{
isBlockItem = true;
}
- else if (itemStack.getItem() instanceof MinecartItem || itemCreatesBoat(itemStack.getItem()))
+ else if (EntityCollector.itemCreatesEntity(itemStack.getItem(), Entity.class))
{
spawnsEntity = true;
}
@@ -516,194 +502,33 @@ public class CustomItemRenderer extends ItemRenderer
return true;
}
- private boolean updateMinecart(MinecartItem item)
- {
- // We don't support modded minecarts right now.
- if (!item.getClass().equals(MinecartItem.class))
- {
- minecart = null;
- }
- else
- {
- if (minecart == null || minecart.getMinecartType() != item.type)
- {
- Minecraft minecraft = Minecraft.getInstance();
- minecart = AbstractMinecart.createMinecart(minecraft.level, 0, 0, 0, item.type);
- }
- }
-
- // If somehow the minecart is still null, then we can't render anything.
- return minecart != null;
- }
-
- private boolean itemCreatesBoat(Item item)
- {
- // Vanilla and modded subclass BoatItems obviously create boats.
- if (item instanceof BoatItem)
- {
- return true;
- }
-
- // More complex modded items may create a boat subclass entity, so check for that next.
- // To do so, we'll look for a method that returns a subclass of Boat.
- try
- {
- Method[] methods = item.getClass().getDeclaredMethods();
- for (Method method : methods)
- {
- if (Boat.class.isAssignableFrom(method.getReturnType()) && !method.getReturnType().equals(Boat.class))
- {
- return true;
- }
- }
- }
- catch (Exception e) {}
-
- // This doesn't appear to be a boat-creating item.
- return false;
- }
-
- /// Attempts to create a modded boat entity from a modded boat item using reflection.
- /// Returns null if we failed to create the entity.
- private Boat createModdedBoat(Item item)
+ private Entity getEntityFromItem(Item item)
{
- Boat moddedBoat = null;
-
- // Ensure this is actually a modded boat item before continuing.
- //if (itemCreatesBoat(item))
+ Entity collectedEntity = null;
+ List<Entity> collectedEntities = EntityCollector.collectEntitiesFromItem(item);
+ if (!collectedEntities.isEmpty())
{
- Minecraft minecraft = Minecraft.getInstance();
-
- // Since this boat is modded, first we will look for a method in the BoatItem subclass that returns an instance of a Boat subclass.
- // If we find it, we will use it to create the boat entity.
- try
- {
- Method[] methods = item.getClass().getDeclaredMethods();
- for (Method method : methods)
- {
- // If the signature matches, call it.
- if (Boat.class.isAssignableFrom(method.getReturnType()) && !method.getReturnType().equals(Boat.class))
- {
- // First supported signature: createBoat(Level level, HitResult hit)
- if (method.getParameterCount() == 2 &&
- method.getParameterTypes()[0].equals(Level.class) &&
- method.getParameterTypes()[1].equals(HitResult.class))
-
- {
- method.setAccessible(true);
- moddedBoat = (Boat) method.invoke(item, minecraft.level, new BlockHitResult(Vec3.ZERO, Direction.DOWN, BlockPos.ZERO, false));
- break;
- }
- // Second supported signature: createBoat(Level level, Vec3 pos, float yaw)
- else if (method.getParameterCount() == 3 &&
- method.getParameterTypes()[0].equals(Level.class) &&
- method.getParameterTypes()[1].equals(Vec3.class) &&
- method.getParameterTypes()[2].equals(float.class))
- {
- method.setAccessible(true);
- moddedBoat = (Boat) method.invoke(item, minecraft.level, Vec3.ZERO, 30.0f);
- break;
- }
- }
- }
-
- // Now, if we've created an entity we need to set the "wood type", so we will first look for an enum field on this item that matches
- // the parameter type of a method on the boat subclass, then call that method.
- if (moddedBoat != null)
- {
- Field[] fields = item.getClass().getDeclaredFields();
- Method[] boatMethods = moddedBoat.getClass().getDeclaredMethods();
- boolean enumFound = false;
-
- for (Field field : fields)
- {
- if (field.getType().isEnum())
- {
- // Check if this enum field is the same type as the first parameter of a method on the boat subclass.
- for (Method method : boatMethods)
- {
- if (method.getParameterCount() == 1 && method.getParameterTypes()[0].equals(field.getType()))
- {
- method.setAccessible(true);
- field.setAccessible(true);
- method.invoke(moddedBoat, field.get(item));
- enumFound = true;
- break;
- }
- }
- }
- }
-
- // If we didn't find any enum fields to try, now try with suppliers.
- if (!enumFound)
- {
- for (Field field : fields)
- {
- if (field.getType().isAssignableFrom(Supplier.class))
- {
- field.setAccessible(true);
- Object fieldValue = ((Supplier<?>)field.get(item)).get();
-
- // Check if this enum field is the same type as the first parameter of a method on the boat subclass.
- for (Method method : boatMethods)
- {
- if (method.getParameterCount() == 1 && method.getParameterTypes()[0].equals(fieldValue.getClass()))
- {
- method.setAccessible(true);
- method.invoke(moddedBoat, fieldValue);
- break;
- }
- }
- }
- }
- }
- }
- }
- catch (Exception e)
- {
- // If we fail to create the boat entity by looking for a "getBoat"-esque method, we can't render this modded boat.
- // This will fallback to just rendering the item icon.
- moddedBoat = null;
- Loader.LOGGER.info(ExceptionUtils.getStackTrace(e));
- }
+ // Just return the first entity collected.
+ // TODO: Should all entities be considered for weird items that spawn multiple?
+ collectedEntity = collectedEntities.get(0);
}
- return moddedBoat;
+ return collectedEntity;
}
- private boolean updateBoat(Item item)
+ private boolean updateEntity(Item item)
{
- boolean moddedBoat = false;
-
- // Check if this is a modded boat item, that is if it is a subclass of BoatItem (or not a BoatItem at all).
- if (!item.getClass().equals(BoatItem.class))
+ if (entity == null || cachedEntityItem != item)
{
- // This is a modded boat item, so we need to create the boat entity in a different way.
- moddedBoat = true;
- }
-
- if (boat == null || cachedBoatItem != item)
- {
- Minecraft minecraft = Minecraft.getInstance();
-
- if (moddedBoat)
- {
- boat = createModdedBoat(item);
- }
- else if (item instanceof BoatItem boatItem)
- {
- boat = boatItem.hasChest ? new ChestBoat(minecraft.level, 0, 0, 0) : new Boat(minecraft.level, 0, 0, 0);
- boat.setVariant(boatItem.type);
- }
-
- cachedBoatItem = item;
+ 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))
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/resources/iceberg.mixins.json b/src/main/resources/iceberg.mixins.json
index f3f0e24..7b71ad1 100644
--- a/src/main/resources/iceberg.mixins.json
+++ b/src/main/resources/iceberg.mixins.json
@@ -3,7 +3,8 @@
"package": "com.anthonyhilyard.iceberg.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
- "PlayerAdvancementsMixin"
+ "PlayerAdvancementsMixin",
+ "ItemMixin"
],
"client": [
"ScreenMixin",