diff --git a/src/main/java/com/brandon3055/draconicevolution/client/render/tile/PlacedItemDisplayListCache.java b/src/main/java/com/brandon3055/draconicevolution/client/render/tile/PlacedItemDisplayListCache.java deleted file mode 100644 index 695bd14..0000000 --- a/src/main/java/com/brandon3055/draconicevolution/client/render/tile/PlacedItemDisplayListCache.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.brandon3055.draconicevolution.client.render.tile; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.entity.RenderItem; -import net.minecraft.client.renderer.texture.ITickable; -import net.minecraft.item.ItemStack; -import net.minecraft.world.chunk.Chunk; -import net.minecraftforge.client.event.RenderWorldLastEvent; -import net.minecraftforge.client.event.TextureStitchEvent; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.world.ChunkEvent; -import net.minecraftforge.event.world.WorldEvent; - -import org.lwjgl.opengl.GL11; - -import com.brandon3055.draconicevolution.client.render.item.RenderMobSoul; -import com.brandon3055.draconicevolution.common.items.MobSoul; -import com.brandon3055.draconicevolution.common.tileentities.TilePlacedItem; -import com.brandon3055.draconicevolution.common.utils.ItemNBTHelper; - -import cpw.mods.fml.common.eventhandler.SubscribeEvent; - -public class PlacedItemDisplayListCache { - - private static final long GLINT_TTL_MS = 33L; - private static final long ANIMATED_TTL_MS = 50L; - private static final long MOBSOUL_TTL_MS = 1000L; - private static final long PRUNE_INTERVAL_MS = 1000L; - - private final Map displayListCache = new HashMap<>(); - private int atlasVersion; - private long nextPruneMs; - - public PlacedItemDisplayListCache() { - MinecraftForge.EVENT_BUS.register(this); - } - - public CacheEntry getOrCompile(TilePlacedItem tile, ItemStack stack, int meta, Runnable renderBody) { - CacheEntry entry = displayListCache.get(tile); - if (entry == null || !entry.isValid(stack, meta, tile.rotation, atlasVersion) || entry.needsRefresh()) { - dispose(tile); - entry = compile(tile, stack, meta, renderBody); - } - return entry; - } - - private CacheEntry compile(TilePlacedItem tile, ItemStack stack, int meta, Runnable renderBody) { - int listId = GL11.glGenLists(1); - boolean mobSoul = stack.getItem() instanceof MobSoul; - boolean previousRotationFlag = RenderMobSoul.applyTimeRotation; - GL11.glNewList(listId, GL11.GL_COMPILE); - try { - if (mobSoul) RenderMobSoul.applyTimeRotation = false; - renderBody.run(); - GL11.glEndList(); - } catch (RuntimeException | Error t) { - GL11.glEndList(); - GL11.glDeleteLists(listId, 1); - RenderItem.renderInFrame = false; - throw t; - } finally { - RenderMobSoul.applyTimeRotation = previousRotationFlag; - } - CacheEntry entry = new CacheEntry( - listId, - stack, - stack.stackSize, - meta, - tile.rotation, - getTTL(stack, mobSoul), - mobSoul, - atlasVersion); - displayListCache.put(tile, entry); - return entry; - } - - private long getTTL(ItemStack stack, boolean mobSoul) { - if (mobSoul) { - // "Any" soul swaps mob every second while named souls only need per-frame rotation outside the list - return isAnyMobSoul(stack) ? MOBSOUL_TTL_MS : Long.MAX_VALUE; - } - - if (stack.hasEffect()) return GLINT_TTL_MS; // Glint scroll (~30 fps) - if (stack.getItem().getIconIndex(stack) instanceof ITickable) return ANIMATED_TTL_MS; // 20 Hz sprite ticks - return Long.MAX_VALUE; // static (event-invalidated) - } - - private boolean isAnyMobSoul(ItemStack stack) { - return "Any".equals(ItemNBTHelper.getString(stack, "Name", "Pig")); - } - - public void dispose(TilePlacedItem tile) { - CacheEntry entry = displayListCache.remove(tile); - if (entry != null) GL11.glDeleteLists(entry.listId, 1); - } - - private void pruneInvalidEntries() { - if (displayListCache.isEmpty()) return; - long now = Minecraft.getSystemTime(); - if (now < nextPruneMs) return; - nextPruneMs = now + PRUNE_INTERVAL_MS; - - Iterator> it = displayListCache.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - TilePlacedItem tile = entry.getKey(); - if (tile.isInvalid() || tile.getWorldObj() == null || tile.getStack() == null) { - GL11.glDeleteLists(entry.getValue().listId, 1); - it.remove(); - } - } - } - - private void clearAll() { - for (CacheEntry entry : displayListCache.values()) { - GL11.glDeleteLists(entry.listId, 1); - } - displayListCache.clear(); - } - - @SubscribeEvent - public void onRenderWorldLast(RenderWorldLastEvent event) { - pruneInvalidEntries(); - } - - @SubscribeEvent - public void onTextureStitch(TextureStitchEvent.Post event) { - atlasVersion++; - clearAll(); - } - - @SubscribeEvent - public void onChunkUnload(ChunkEvent.Unload event) { - if (!event.world.isRemote) return; - Chunk chunk = event.getChunk(); - Iterator> it = displayListCache.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry e = it.next(); - TilePlacedItem tile = e.getKey(); - if ((tile.xCoord >> 4) == chunk.xPosition && (tile.zCoord >> 4) == chunk.zPosition) { - GL11.glDeleteLists(e.getValue().listId, 1); - it.remove(); - } - } - } - - @SubscribeEvent - public void onWorldUnload(WorldEvent.Unload event) { - if (!event.world.isRemote) return; - clearAll(); - } - - public static class CacheEntry { - - public final int listId; - public final ItemStack stack; - public final int stackSize; - public final int meta; - public final float rotation; - public final long ttlMs; - public final boolean mobSoul; - public final int atlasVersion; - private long lastCompileMs; - - private CacheEntry(int listId, ItemStack stack, int stackSize, int meta, float rotation, long ttlMs, - boolean mobSoul, int atlasVersion) { - this.listId = listId; - this.stack = stack; - this.stackSize = stackSize; - this.meta = meta; - this.rotation = rotation; - this.ttlMs = ttlMs; - this.mobSoul = mobSoul; - this.atlasVersion = atlasVersion; - this.lastCompileMs = System.currentTimeMillis(); - } - - private boolean isValid(ItemStack stack, int meta, float rotation, int atlasVersion) { - // checking the pointer of the stack is enough - return this.stack == stack && this.stackSize == stack.stackSize - && this.meta == meta - && this.rotation == rotation - && this.atlasVersion == atlasVersion; - } - - private boolean needsRefresh() { - return ttlMs != Long.MAX_VALUE && System.currentTimeMillis() - lastCompileMs >= ttlMs; - } - } -} diff --git a/src/main/java/com/brandon3055/draconicevolution/client/render/tile/RenderTilePlacedItem.java b/src/main/java/com/brandon3055/draconicevolution/client/render/tile/RenderTilePlacedItem.java index 3e18fc6..6442664 100644 --- a/src/main/java/com/brandon3055/draconicevolution/client/render/tile/RenderTilePlacedItem.java +++ b/src/main/java/com/brandon3055/draconicevolution/client/render/tile/RenderTilePlacedItem.java @@ -14,8 +14,6 @@ import net.minecraft.tileentity.TileEntity; import org.lwjgl.opengl.GL11; -import com.brandon3055.draconicevolution.client.render.item.RenderMobSoul; -import com.brandon3055.draconicevolution.client.render.tile.PlacedItemDisplayListCache.CacheEntry; import com.brandon3055.draconicevolution.common.items.MobSoul; import com.brandon3055.draconicevolution.common.tileentities.TilePlacedItem; @@ -29,29 +27,17 @@ public class RenderTilePlacedItem extends TileEntitySpecialRenderer { private static final float MOBSOUL_CENTER_Z = 0.5F; private final EntityItem cachedEntity = new EntityItem(null, 0, 0, 0, new ItemStack(Items.apple)); - private final PlacedItemDisplayListCache displayListCache = new PlacedItemDisplayListCache(); @Override public void renderTileEntityAt(TileEntity te, double x, double y, double z, float timeSinceLastTick) { if (!(te instanceof TilePlacedItem tile)) return; ItemStack stack = tile.getStack(); - if (stack == null) { - displayListCache.dispose(tile); - return; - } + // I think without this check it could have thrown a NPE if an item being displayed was removed + if (stack == null || stack.getItem() == null) return; if (tile.getWorldObj() == null) return; - int meta = tile.getWorldObj().getBlockMetadata(tile.xCoord, tile.yCoord, tile.zCoord); - CacheEntry entry = displayListCache.getOrCompile(tile, stack, meta, () -> renderItem(tile)); GL11.glPushMatrix(); - GL11.glPushAttrib(GL11.GL_ENABLE_BIT); GL11.glTranslated(x, y, z); - if (entry.mobSoul) { - GL11.glTranslated(MOBSOUL_CENTER_X, MOBSOUL_CENTER_Y, MOBSOUL_CENTER_Z); - GL11.glRotatef(RenderMobSoul.getRotationAngle(), 0F, 1F, 0F); - GL11.glTranslated(-MOBSOUL_CENTER_X, -MOBSOUL_CENTER_Y, -MOBSOUL_CENTER_Z); - } - GL11.glCallList(entry.listId); - GL11.glPopAttrib(); + renderItem(tile); GL11.glPopMatrix(); } @@ -86,7 +72,6 @@ public class RenderTilePlacedItem extends TileEntitySpecialRenderer { GL11.glTranslatef(0.0F, -0.18F, 0.0F); } - GL11.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT); RenderItem.renderInFrame = true; try { this.cachedEntity.setEntityItemStack(stack); @@ -96,9 +81,8 @@ public class RenderTilePlacedItem extends TileEntitySpecialRenderer { } finally { this.cachedEntity.setEntityItemStack(null); this.cachedEntity.setWorld(null); + RenderItem.renderInFrame = false; } - RenderItem.renderInFrame = false; - GL11.glPopAttrib(); } private void metaAdjustItemTool(int meta) {