diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/compact_bit_storage/PalettedContainerMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/compact_bit_storage/PalettedContainerMixin.java new file mode 100644 index 00000000..0a74c573 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/compact_bit_storage/PalettedContainerMixin.java @@ -0,0 +1,39 @@ +package org.embeddedt.modernfix.common.mixin.perf.compact_bit_storage; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.chunk.PalettedContainer; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; +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(PalettedContainer.class) +public abstract class PalettedContainerMixin { + @Shadow private volatile PalettedContainer.Data data; + + @Shadow protected abstract PalettedContainer.Data createOrReuseData(@Nullable PalettedContainer.Data data, int id); + + @Inject(method = "read(Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/chunk/PalettedContainer;data:Lnet/minecraft/world/level/chunk/PalettedContainer$Data;", opcode = Opcodes.PUTFIELD, shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD) + private void validateData(FriendlyByteBuf buffer, CallbackInfo ci, int i) { + if(i <= 1) + return; + long[] storArray = this.data.storage().getRaw(); + boolean empty = true; + for (long l : storArray) { + if (l != 0) { + empty = false; + break; + } + } + if(empty && storArray.length > 0) { + /* it means the chunk is oversized and wasting memory, take the ID out of the palette and recreate a smaller chunk */ + T value = this.data.palette().valueFor(0); + this.data = this.createOrReuseData(null, 0); + this.data.palette().idFor(value); + } + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_entity_renderers/EntityRenderersMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_entity_renderers/EntityRenderersMixin.java new file mode 100644 index 00000000..a5c78050 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_entity_renderers/EntityRenderersMixin.java @@ -0,0 +1,130 @@ +package org.embeddedt.modernfix.common.mixin.perf.dynamic_entity_renderers; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.client.renderer.entity.EntityRenderers; +import net.minecraft.core.Registry; +import net.minecraft.world.entity.EntityType; +import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.entity.ErroredEntityRenderer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +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.CallbackInfoReturnable; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; + +@Mixin(EntityRenderers.class) +@ClientOnlyMixin +public class EntityRenderersMixin { + @Shadow @Final private static Map, EntityRendererProvider> PROVIDERS; + + @Inject(method = "createEntityRenderers", at = @At("HEAD"), cancellable = true) + private static void createDynamicRendererLoader(EntityRendererProvider.Context context, CallbackInfoReturnable, EntityRenderer>> cir) { + Map, EntityRendererProvider> rendererProviders = PROVIDERS; + LoadingCache, EntityRenderer> rendererMap = CacheBuilder.newBuilder() + .build(new CacheLoader<>() { + @Override + public EntityRenderer load(EntityType key) throws Exception { + EntityRendererProvider provider = rendererProviders.get(key); + synchronized(EntityRenderers.class) { + EntityRenderer renderer; + try { + if(provider == null) + throw new RuntimeException("Provider not registered"); + renderer = provider.create(context); + ModernFix.LOGGER.info("Loaded entity {}", Registry.ENTITY_TYPE.getKey(key)); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Failed to create entity model for " + Registry.ENTITY_TYPE.getKey(key) + ":", e); + renderer = new ErroredEntityRenderer<>(context); + } + return renderer; + } + } + }); + cir.setReturnValue(new Map, EntityRenderer>() { + @Override + public int size() { + return rendererProviders.size(); + } + + @Override + public boolean isEmpty() { + return rendererProviders.isEmpty(); + } + + @Override + public boolean containsKey(Object o) { + return rendererProviders.containsKey(o); + } + + @Override + public boolean containsValue(Object o) { + return false; + } + + @Override + public EntityRenderer get(Object o) { + try { + return rendererMap.get((EntityType)o); + } catch(ExecutionException e) { + throw new RuntimeException(e); + } + } + + @Nullable + @Override + public EntityRenderer put(EntityType entityType, EntityRenderer entityRenderer) { + EntityRenderer old = rendererMap.getIfPresent(entityType); + rendererMap.put(entityType, entityRenderer); + return old; + } + + @Override + public EntityRenderer remove(Object o) { + EntityRenderer r = rendererMap.getIfPresent(o); + rendererMap.invalidate(o); + return r; + } + + @Override + public void putAll(@NotNull Map, ? extends EntityRenderer> map) { + rendererMap.putAll(map); + } + + @Override + public void clear() { + rendererMap.invalidateAll(); + } + + @NotNull + @Override + public Set> keySet() { + return rendererProviders.keySet(); + } + + @NotNull + @Override + public Collection> values() { + return rendererMap.asMap().values(); + } + + @NotNull + @Override + public Set, EntityRenderer>> entrySet() { + return rendererMap.asMap().entrySet(); + } + }); + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/entity/ErroredEntityRenderer.java b/common/src/main/java/org/embeddedt/modernfix/entity/ErroredEntityRenderer.java new file mode 100644 index 00000000..14e97369 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/entity/ErroredEntityRenderer.java @@ -0,0 +1,30 @@ +package org.embeddedt.modernfix.entity; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; + +public class ErroredEntityRenderer extends EntityRenderer { + public ErroredEntityRenderer(EntityRendererProvider.Context arg) { + super(arg); + } + + @Override + public ResourceLocation getTextureLocation(T entity) { + return TextureAtlas.LOCATION_BLOCKS; + } + + @Override + public boolean shouldRender(T livingEntity, Frustum camera, double camX, double camY, double camZ) { + return false; + } + + @Override + public void render(T entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight) { + } +} diff --git a/common/src/main/resources/modernfix.accesswidener b/common/src/main/resources/modernfix.accesswidener index 3c96e1d4..bf00e73b 100644 --- a/common/src/main/resources/modernfix.accesswidener +++ b/common/src/main/resources/modernfix.accesswidener @@ -39,3 +39,4 @@ accessible field net/minecraft/client/resources/model/ModelBakery ITEM_MODEL_GEN accessible class net/minecraft/client/resources/model/ModelBakery$ModelBakerImpl accessible method net/minecraft/client/resources/model/ModelBakery$ModelBakerImpl (Lnet/minecraft/client/resources/model/ModelBakery;Ljava/util/function/BiFunction;Lnet/minecraft/resources/ResourceLocation;)V accessible method net/minecraft/client/resources/model/ModelBakery$BakedCacheKey (Lnet/minecraft/resources/ResourceLocation;Lcom/mojang/math/Transformation;Z)V +accessible class net/minecraft/world/level/chunk/PalettedContainer$Data