diff --git a/src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java b/src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java new file mode 100644 index 0000000..5f8d73d --- /dev/null +++ b/src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java @@ -0,0 +1,59 @@ +package org.dimdev.vanillafix.textures; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class ChunkSpriteStorage { + private static Logger log = LogManager.getLogger (); + private static ReadWriteLock lock = new ReentrantReadWriteLock (); + private static Map chunkSprites = new TreeMap<> (Comparator.comparing (TextureAtlasSprite::toString)); + + public static void addUsage (TextureAtlasSprite sprite) { + lock.writeLock ().lock (); + try { + if (chunkSprites.containsKey (sprite)) { + chunkSprites.put (sprite, chunkSprites.get (sprite) + 1); + } else { + chunkSprites.put (sprite, 1); + } + } finally { + lock.writeLock ().unlock (); + } + } + + public static void removeUsage (TextureAtlasSprite sprite) { + lock.writeLock ().lock (); + try { + if (chunkSprites.containsKey (sprite)) { + int i = chunkSprites.get (sprite); + if (i <= 1) { + chunkSprites.remove (sprite); + } else { + chunkSprites.put (sprite, i - 1); + } + } else { + log.error ("Tried to remove sprite, that has no usage"); + } + } finally { + lock.writeLock ().unlock (); + } + } + + public static void markAnimationsForUpdate () { + lock.readLock ().lock (); + try { + for (TextureAtlasSprite sprite : chunkSprites.keySet ()) { + ((IPatchedTextureAtlasSprite) sprite).markNeedsAnimationUpdate (); + } + } finally { + lock.readLock ().unlock (); + } + } +} diff --git a/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinRenderChunk.java b/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinRenderChunk.java index e5792f5..3d5772a 100644 --- a/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinRenderChunk.java +++ b/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinRenderChunk.java @@ -3,21 +3,70 @@ import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator; import net.minecraft.client.renderer.chunk.CompiledChunk; import net.minecraft.client.renderer.chunk.RenderChunk; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.math.BlockPos; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.dimdev.vanillafix.textures.ChunkSpriteStorage; +import org.dimdev.vanillafix.textures.IPatchedCompiledChunk; import org.dimdev.vanillafix.textures.TemporaryStorage; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -@Mixin(RenderChunk.class) +@Mixin (RenderChunk.class) public class MixinRenderChunk { + @Shadow + public CompiledChunk compiledChunk; + @Shadow + @Final + private BlockPos.MutableBlockPos position; + private boolean animationsAdded = false; + private static final Logger vanillaFixLog = LogManager.getLogger ("VanillaFix RenderChunk"); + /** * @reason Store the chunk currently being rebuild in TemporaryStorage.currentCompiledChunk * by thread ID (there are multiple chunk renderer threads working at once). */ - @Inject(method = "rebuildChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/chunk/CompiledChunk;()V", ordinal = 0, shift = At.Shift.BY, by = 2), locals = LocalCapture.CAPTURE_FAILHARD) - private void onRebuildChunk(float x, float y, float z, ChunkCompileTaskGenerator generator, CallbackInfo ci, CompiledChunk compiledChunk) { - TemporaryStorage.currentCompiledChunk.set(compiledChunk); + @Inject (method = "rebuildChunk", at = @At (value = "INVOKE", target = "Lnet/minecraft/client/renderer/chunk/CompiledChunk;()V", ordinal = 0, shift = At.Shift.BY, by = 2), locals = LocalCapture.CAPTURE_FAILHARD) + private void onRebuildChunk (float x, float y, float z, ChunkCompileTaskGenerator generator, CallbackInfo ci, CompiledChunk compiledChunk) { + TemporaryStorage.currentCompiledChunk.set (compiledChunk); + } + + @Inject (method = "setCompiledChunk", at = @At ("HEAD")) + private void onSetCompiledChunkPre (CompiledChunk compiledChunkIn, CallbackInfo ci) { + removeAnimationsIfNeccessary (); + } + + private void addAnimationsIfNeccessary () { + if (!animationsAdded) { + for (TextureAtlasSprite sprite : ((IPatchedCompiledChunk) compiledChunk).getVisibleTextures ()) { + ChunkSpriteStorage.addUsage (sprite); + } + animationsAdded = true; + } + } + + private void removeAnimationsIfNeccessary () { + if ((compiledChunk != null) && animationsAdded) { + for (TextureAtlasSprite sprite : ((IPatchedCompiledChunk) compiledChunk).getVisibleTextures ()) { + ChunkSpriteStorage.removeUsage (sprite); + } + animationsAdded = false; + } + } + + @Inject (method = "setCompiledChunk", at = @At ("RETURN")) + private void onSetCompiledChunkPost (CompiledChunk compiledChunkIn, CallbackInfo ci) { + addAnimationsIfNeccessary (); + } + + @Inject (method = "stopCompileTask", at = @At ("HEAD")) + private void onStopCompileTask (CallbackInfo ci) { + removeAnimationsIfNeccessary (); } } diff --git a/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java b/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java index f9a8bda..6f9c881 100644 --- a/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java +++ b/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java @@ -2,11 +2,10 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; -import org.dimdev.vanillafix.textures.IPatchedCompiledChunk; +import org.dimdev.vanillafix.textures.ChunkSpriteStorage; import org.dimdev.vanillafix.textures.IPatchedTextureAtlasSprite; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -15,9 +14,12 @@ import java.util.List; -@Mixin(TextureMap.class) +@Mixin (TextureMap.class) public abstract class MixinTextureMap extends AbstractTexture { - @SuppressWarnings("ShadowModifiers" /*(AT)*/) @Shadow @Final private List listAnimatedSprites; + @SuppressWarnings ("ShadowModifiers" /*(AT)*/) + @Shadow + @Final + private List listAnimatedSprites; /** * @reason Replaces the updateAnimations method to only tick animated textures @@ -27,23 +29,18 @@ public abstract class MixinTextureMap extends AbstractTexture { * Also breaks down the "root.tick.textures" profiler by texture name. */ @Overwrite - public void updateAnimations() { - // TODO: Recalculate list after chunk update instead! - Minecraft.getMinecraft().profiler.startSection("determineVisibleTextures"); - for (RenderGlobal.ContainerLocalRenderInformation renderInfo : Minecraft.getMinecraft().renderGlobal.renderInfos) { - for (TextureAtlasSprite texture : ((IPatchedCompiledChunk) renderInfo.renderChunk.compiledChunk).getVisibleTextures()) { - ((IPatchedTextureAtlasSprite) texture).markNeedsAnimationUpdate(); - } - } - Minecraft.getMinecraft().profiler.endSection(); + public void updateAnimations () { + Minecraft.getMinecraft ().profiler.startSection ("determineVisibleTextures"); + ChunkSpriteStorage.markAnimationsForUpdate (); + Minecraft.getMinecraft ().profiler.endSection (); - GlStateManager.bindTexture(getGlTextureId()); + GlStateManager.bindTexture (getGlTextureId ()); for (TextureAtlasSprite texture : listAnimatedSprites) { - if (((IPatchedTextureAtlasSprite) texture).needsAnimationUpdate()) { - Minecraft.getMinecraft().profiler.startSection(texture.getIconName()); - texture.updateAnimation(); - ((IPatchedTextureAtlasSprite) texture).unmarkNeedsAnimationUpdate(); // Can't do this from updateAnimation mixin, that method can be overriden - Minecraft.getMinecraft().profiler.endSection(); + if (((IPatchedTextureAtlasSprite) texture).needsAnimationUpdate ()) { + Minecraft.getMinecraft ().profiler.startSection (texture.getIconName ()); + texture.updateAnimation (); + ((IPatchedTextureAtlasSprite) texture).unmarkNeedsAnimationUpdate (); // Can't do this from updateAnimation mixin, that method can be overriden + Minecraft.getMinecraft ().profiler.endSection (); } } }