diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index c411a9e26..cd696310b 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -14,10 +14,13 @@ import com.simibubi.create.foundation.item.CustomItemModels; import com.simibubi.create.foundation.item.CustomRenderedItems; import com.simibubi.create.foundation.ponder.content.PonderIndex; import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; +import com.simibubi.create.foundation.render.AllProgramSpecs; import com.simibubi.create.foundation.render.KineticRenderer; import com.simibubi.create.foundation.render.SuperByteBufferCache; import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.OptifineHandler; +import com.simibubi.create.foundation.render.backend.instancing.InstancedTileRenderer; +import com.simibubi.create.foundation.utility.WorldAttached; import com.simibubi.create.foundation.utility.ghost.GhostBlocks; import com.simibubi.create.foundation.utility.outliner.Outliner; import net.minecraft.block.Block; @@ -30,6 +33,7 @@ import net.minecraft.item.Item; import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.IWorld; import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.event.TextureStitchEvent; @@ -37,6 +41,7 @@ import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -48,7 +53,7 @@ public class CreateClient { public static SchematicHandler schematicHandler; public static SchematicAndQuillHandler schematicAndQuillHandler; public static SuperByteBufferCache bufferCache; - public static KineticRenderer kineticRenderer; + public static WorldAttached kineticRenderer; public static final Outliner outliner = new Outliner(); public static GhostBlocks ghostBlocks; @@ -70,7 +75,8 @@ public class CreateClient { } public static void clientInit(FMLClientSetupEvent event) { - kineticRenderer = new KineticRenderer(); + AllProgramSpecs.init(); + kineticRenderer = new WorldAttached<>(KineticRenderer::new); schematicSender = new ClientSchematicLoader(); schematicHandler = new SchematicHandler(); @@ -192,8 +198,18 @@ public class CreateClient { } public static void invalidateRenderers() { - CreateClient.bufferCache.invalidate(); - CreateClient.kineticRenderer.invalidate(); + invalidateRenderers(null); + } + + public static void invalidateRenderers(@Nullable IWorld world) { + bufferCache.invalidate(); + + if (world != null) { + kineticRenderer.get(world).invalidate(); + } else { + kineticRenderer.forEach(InstancedTileRenderer::invalidate); + } + ContraptionRenderDispatcher.invalidateAll(); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java index b0b2d51f6..c0984e491 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java @@ -534,12 +534,6 @@ public abstract class KineticTileEntity extends SmartTileEntity return block.hasIntegratedCogwheel(world, pos, state); } - @Override - public void onChunkUnloaded() { - if (world != null && world.isRemote) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.kineticRenderer.remove(this)); - } - @Override public void requestModelDataUpdate() { super.requestModelDataUpdate(); diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 5a5f384af..3c19cdde8 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -27,6 +27,7 @@ import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.LeftClickPacket; import com.simibubi.create.foundation.ponder.PonderTooltipHandler; +import com.simibubi.create.foundation.render.KineticRenderer; import com.simibubi.create.foundation.render.backend.FastRenderDispatcher; import com.simibubi.create.foundation.render.backend.RenderWork; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; @@ -125,7 +126,9 @@ public class ClientEvents { if (world.isRemote() && world instanceof ClientWorld) { CreateClient.invalidateRenderers(); AnimationTickHolder.reset(); - ((ClientWorld) world).loadedTileEntityList.forEach(CreateClient.kineticRenderer::add); + KineticRenderer renderer = CreateClient.kineticRenderer.get(world); + renderer.invalidate(); + ((ClientWorld) world).loadedTileEntityList.forEach(renderer::add); } /* @@ -139,7 +142,7 @@ public class ClientEvents { @SubscribeEvent public static void onUnloadWorld(WorldEvent.Unload event) { if (event.getWorld().isRemote()) { - CreateClient.invalidateRenderers(); + CreateClient.invalidateRenderers(event.getWorld()); AnimationTickHolder.reset(); } } diff --git a/src/main/java/com/simibubi/create/foundation/mixin/AddRemoveTileMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/AddRemoveTileMixin.java index d20b076ec..24321c5ad 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/AddRemoveTileMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/AddRemoveTileMixin.java @@ -1,5 +1,6 @@ package com.simibubi.create.foundation.mixin; +import com.simibubi.create.foundation.render.KineticRenderer; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -17,12 +18,16 @@ import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import java.util.Set; + @OnlyIn(Dist.CLIENT) @Mixin(World.class) public class AddRemoveTileMixin { @Shadow @Final public boolean isRemote; + @Shadow @Final protected Set tileEntitiesToBeRemoved; + /** * JUSTIFICATION: This method is called whenever a tile entity is removed due * to a change in block state, even on the client. By hooking into this method, @@ -30,11 +35,28 @@ public class AddRemoveTileMixin { */ @Inject(at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/World;getTileEntity(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/tileentity/TileEntity;"), method = "removeTileEntity", locals = LocalCapture.CAPTURE_FAILHARD) private void onRemoveTile(BlockPos pos, CallbackInfo ci, TileEntity te) { - if (isRemote) CreateClient.kineticRenderer.remove(te); + if (isRemote) { + World thi = (World)(Object) this; + CreateClient.kineticRenderer.get(thi).remove(te); + } } @Inject(at = @At("TAIL"), method = "addTileEntity") private void onAddTile(TileEntity te, CallbackInfoReturnable cir) { - if (isRemote) CreateClient.kineticRenderer.queueAdd(te); + if (isRemote) { + World thi = (World)(Object) this; + CreateClient.kineticRenderer.get(thi).queueAdd(te); + } + } + + @Inject(at = @At(value = "INVOKE", target = "Ljava/util/Set;clear()V", ordinal = 0), method = "tickBlockEntities") + private void onChunkUnload(CallbackInfo ci) { + if (isRemote) { + World thi = (World)(Object) this; + KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(thi); + for (TileEntity tile : tileEntitiesToBeRemoved) { + kineticRenderer.remove(tile); + } + } } } diff --git a/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java index 1636c95bb..d55539c7c 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/LightUpdateMixin.java @@ -3,6 +3,7 @@ package com.simibubi.create.foundation.mixin; import java.util.Map; import com.simibubi.create.CreateClient; +import net.minecraft.client.world.ClientWorld; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -33,6 +34,7 @@ public abstract class LightUpdateMixin extends AbstractChunkProvider { @Inject(at = @At("HEAD"), method = "markLightChanged") private void onLightUpdate(LightType type, SectionPos pos, CallbackInfo ci) { ClientChunkProvider thi = ((ClientChunkProvider) (Object) this); + ClientWorld world = (ClientWorld) thi.getWorld(); Chunk chunk = thi.getChunk(pos.getSectionX(), pos.getSectionZ(), false); @@ -43,14 +45,15 @@ public abstract class LightUpdateMixin extends AbstractChunkProvider { .entrySet() .stream() .filter(entry -> SectionPos.toChunk(entry.getKey().getY()) == sectionY) - .map(Map.Entry::getValue).forEach(tile -> { - CreateClient.kineticRenderer.onLightUpdate(tile); + .map(Map.Entry::getValue) + .forEach(tile -> { + CreateClient.kineticRenderer.get(world).onLightUpdate(tile); if (tile instanceof ILightListener) ((ILightListener) tile).onChunkLightUpdate(); }); } - ContraptionRenderDispatcher.notifyLightUpdate((ILightReader) thi.getWorld(), type, pos); + ContraptionRenderDispatcher.notifyLightUpdate(world, type, pos); } } diff --git a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java index 89310489c..2bdf89fb7 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java @@ -1,5 +1,6 @@ package com.simibubi.create.foundation.mixin; +import com.simibubi.create.foundation.render.KineticRenderer; import net.minecraft.client.renderer.*; import net.minecraft.util.math.Vec3d; import org.lwjgl.opengl.GL20; @@ -52,17 +53,20 @@ public class RenderHooksMixin { double camY = cameraPos.getY(); double camZ = cameraPos.getZ(); - CreateClient.kineticRenderer.beginFrame(camX, camY, camZ); + CreateClient.kineticRenderer.get(world).beginFrame(camX, camY, camZ); ContraptionRenderDispatcher.beginFrame(camX, camY, camZ); } @Inject(at = @At("TAIL"), method = "loadRenderers") private void refresh(CallbackInfo ci) { - CreateClient.kineticRenderer.invalidate(); ContraptionRenderDispatcher.invalidateAll(); OptifineHandler.refresh(); Backend.refresh(); - if (Backend.canUseInstancing() && world != null) world.loadedTileEntityList.forEach(CreateClient.kineticRenderer::add); + if (Backend.canUseInstancing() && world != null) { + KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world); + kineticRenderer.invalidate(); + world.loadedTileEntityList.forEach(kineticRenderer::add); + } } } diff --git a/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java b/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java index a07a85727..916d8c478 100644 --- a/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java +++ b/src/main/java/com/simibubi/create/foundation/render/AllProgramSpecs.java @@ -19,6 +19,10 @@ import com.simibubi.create.foundation.render.backend.gl.shader.ShaderConstants; import net.minecraft.util.ResourceLocation; public class AllProgramSpecs { + public static void init() { + // noop, make sure the static field are loaded. + } + public static final ProgramSpec MODEL = register(ProgramSpec.builder("model", BasicProgram::new) .addAttributes(ModelVertexAttributes.class) .addAttributes(InstanceVertexAttributes.class) @@ -90,10 +94,6 @@ public class AllProgramSpecs { .setFrag(Locations.CONTRAPTION) .createProgramSpec()); - public static class Contraption { - - } - public static class Locations { public static final ResourceLocation MODEL_FRAG = loc("model.frag"); diff --git a/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java b/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java index d9c8f74d6..d41890d0d 100644 --- a/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/render/KineticRenderer.java @@ -19,6 +19,7 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.entity.Entity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; public class KineticRenderer extends InstancedTileRenderer { public static int MAX_ORIGIN_DISTANCE = 100; @@ -40,30 +41,27 @@ public class KineticRenderer extends InstancedTileRenderer { } @Override - public void tick() { - super.tick(); + public void beginFrame(double cameraX, double cameraY, double cameraZ) { + int cX = MathHelper.floor(cameraX); + int cY = MathHelper.floor(cameraY); + int cZ = MathHelper.floor(cameraZ); - Minecraft mc = Minecraft.getInstance(); - Entity renderViewEntity = mc.renderViewEntity; - - if (renderViewEntity == null) return; - - BlockPos renderViewPosition = renderViewEntity.getPosition(); - - int dX = Math.abs(renderViewPosition.getX() - originCoordinate.getX()); - int dY = Math.abs(renderViewPosition.getY() - originCoordinate.getY()); - int dZ = Math.abs(renderViewPosition.getZ() - originCoordinate.getZ()); + int dX = Math.abs(cX - originCoordinate.getX()); + int dY = Math.abs(cY - originCoordinate.getY()); + int dZ = Math.abs(cZ - originCoordinate.getZ()); if (dX > MAX_ORIGIN_DISTANCE || - dY > MAX_ORIGIN_DISTANCE || - dZ > MAX_ORIGIN_DISTANCE) { + dY > MAX_ORIGIN_DISTANCE || + dZ > MAX_ORIGIN_DISTANCE) { - originCoordinate = renderViewPosition; + originCoordinate = new BlockPos(cX, cY, cZ); ArrayList instancedTiles = new ArrayList<>(instances.keySet()); invalidate(); instancedTiles.forEach(this::add); } + + super.beginFrame(cameraX, cameraY, cameraZ); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java b/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java index 6f096d888..08e31dcc1 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java @@ -2,13 +2,11 @@ package com.simibubi.create.foundation.render.backend; import java.util.concurrent.ConcurrentHashMap; -import org.lwjgl.opengl.GL11; +import com.simibubi.create.foundation.render.KineticRenderer; import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.KineticDebugger; -import com.simibubi.create.content.schematics.SchematicWorld; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.WorldAttached; @@ -41,14 +39,15 @@ public class FastRenderDispatcher { public static void tick() { ClientWorld world = Minecraft.getInstance().world; - CreateClient.kineticRenderer.tick(); + KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world); + kineticRenderer.tick(); ConcurrentHashMap.KeySetView map = queuedUpdates.get(world); map .forEach(te -> { map.remove(te); - CreateClient.kineticRenderer.update(te); + kineticRenderer.update(te); }); } @@ -71,9 +70,12 @@ public class FastRenderDispatcher { public static void renderLayer(RenderType layer, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) { if (!Backend.canUseInstancing()) return; + ClientWorld world = Minecraft.getInstance().world; + KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world); + layer.startDrawing(); - CreateClient.kineticRenderer.render(layer, viewProjection, cameraX, cameraY, cameraZ); + kineticRenderer.render(layer, viewProjection, cameraX, cameraY, cameraZ); layer.endDrawing(); } diff --git a/src/main/java/com/simibubi/create/foundation/utility/WorldAttached.java b/src/main/java/com/simibubi/create/foundation/utility/WorldAttached.java index 99a84db53..c457bea5e 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/WorldAttached.java +++ b/src/main/java/com/simibubi/create/foundation/utility/WorldAttached.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -39,5 +40,9 @@ public class WorldAttached { public void put(IWorld world, T entry) { attached.put(world, entry); } + + public void forEach(Consumer consumer) { + attached.values().forEach(consumer); + } }