Some semblance of immersive portals compat.

- Each world gets its own KineticRenderer now.
This commit is contained in:
JozsefA 2021-03-15 15:58:41 -07:00
parent 52eed2bab3
commit e1c16d869d
10 changed files with 92 additions and 45 deletions

View file

@ -14,10 +14,13 @@ import com.simibubi.create.foundation.item.CustomItemModels;
import com.simibubi.create.foundation.item.CustomRenderedItems; import com.simibubi.create.foundation.item.CustomRenderedItems;
import com.simibubi.create.foundation.ponder.content.PonderIndex; import com.simibubi.create.foundation.ponder.content.PonderIndex;
import com.simibubi.create.foundation.ponder.elements.WorldSectionElement; 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.KineticRenderer;
import com.simibubi.create.foundation.render.SuperByteBufferCache; import com.simibubi.create.foundation.render.SuperByteBufferCache;
import com.simibubi.create.foundation.render.backend.Backend; import com.simibubi.create.foundation.render.backend.Backend;
import com.simibubi.create.foundation.render.backend.OptifineHandler; 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.ghost.GhostBlocks;
import com.simibubi.create.foundation.utility.outliner.Outliner; import com.simibubi.create.foundation.utility.outliner.Outliner;
import net.minecraft.block.Block; import net.minecraft.block.Block;
@ -30,6 +33,7 @@ import net.minecraft.item.Item;
import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResourceManager; import net.minecraft.resources.IResourceManager;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.IWorld;
import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.TextureStitchEvent; 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.eventbus.api.IEventBus;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -48,7 +53,7 @@ public class CreateClient {
public static SchematicHandler schematicHandler; public static SchematicHandler schematicHandler;
public static SchematicAndQuillHandler schematicAndQuillHandler; public static SchematicAndQuillHandler schematicAndQuillHandler;
public static SuperByteBufferCache bufferCache; public static SuperByteBufferCache bufferCache;
public static KineticRenderer kineticRenderer; public static WorldAttached<KineticRenderer> kineticRenderer;
public static final Outliner outliner = new Outliner(); public static final Outliner outliner = new Outliner();
public static GhostBlocks ghostBlocks; public static GhostBlocks ghostBlocks;
@ -70,7 +75,8 @@ public class CreateClient {
} }
public static void clientInit(FMLClientSetupEvent event) { public static void clientInit(FMLClientSetupEvent event) {
kineticRenderer = new KineticRenderer(); AllProgramSpecs.init();
kineticRenderer = new WorldAttached<>(KineticRenderer::new);
schematicSender = new ClientSchematicLoader(); schematicSender = new ClientSchematicLoader();
schematicHandler = new SchematicHandler(); schematicHandler = new SchematicHandler();
@ -192,8 +198,18 @@ public class CreateClient {
} }
public static void invalidateRenderers() { public static void invalidateRenderers() {
CreateClient.bufferCache.invalidate(); invalidateRenderers(null);
CreateClient.kineticRenderer.invalidate(); }
public static void invalidateRenderers(@Nullable IWorld world) {
bufferCache.invalidate();
if (world != null) {
kineticRenderer.get(world).invalidate();
} else {
kineticRenderer.forEach(InstancedTileRenderer::invalidate);
}
ContraptionRenderDispatcher.invalidateAll(); ContraptionRenderDispatcher.invalidateAll();
} }
} }

View file

@ -534,12 +534,6 @@ public abstract class KineticTileEntity extends SmartTileEntity
return block.hasIntegratedCogwheel(world, pos, state); return block.hasIntegratedCogwheel(world, pos, state);
} }
@Override
public void onChunkUnloaded() {
if (world != null && world.isRemote)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.kineticRenderer.remove(this));
}
@Override @Override
public void requestModelDataUpdate() { public void requestModelDataUpdate() {
super.requestModelDataUpdate(); super.requestModelDataUpdate();

View file

@ -27,6 +27,7 @@ import com.simibubi.create.foundation.item.TooltipHelper;
import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.networking.LeftClickPacket; import com.simibubi.create.foundation.networking.LeftClickPacket;
import com.simibubi.create.foundation.ponder.PonderTooltipHandler; 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.FastRenderDispatcher;
import com.simibubi.create.foundation.render.backend.RenderWork; import com.simibubi.create.foundation.render.backend.RenderWork;
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
@ -125,7 +126,9 @@ public class ClientEvents {
if (world.isRemote() && world instanceof ClientWorld) { if (world.isRemote() && world instanceof ClientWorld) {
CreateClient.invalidateRenderers(); CreateClient.invalidateRenderers();
AnimationTickHolder.reset(); 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 @SubscribeEvent
public static void onUnloadWorld(WorldEvent.Unload event) { public static void onUnloadWorld(WorldEvent.Unload event) {
if (event.getWorld().isRemote()) { if (event.getWorld().isRemote()) {
CreateClient.invalidateRenderers(); CreateClient.invalidateRenderers(event.getWorld());
AnimationTickHolder.reset(); AnimationTickHolder.reset();
} }
} }

View file

@ -1,5 +1,6 @@
package com.simibubi.create.foundation.mixin; package com.simibubi.create.foundation.mixin;
import com.simibubi.create.foundation.render.KineticRenderer;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; 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.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import java.util.Set;
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
@Mixin(World.class) @Mixin(World.class)
public class AddRemoveTileMixin { public class AddRemoveTileMixin {
@Shadow @Final public boolean isRemote; @Shadow @Final public boolean isRemote;
@Shadow @Final protected Set<TileEntity> tileEntitiesToBeRemoved;
/** /**
* JUSTIFICATION: This method is called whenever a tile entity is removed due * 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, * 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) @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) { 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") @Inject(at = @At("TAIL"), method = "addTileEntity")
private void onAddTile(TileEntity te, CallbackInfoReturnable<Boolean> cir) { private void onAddTile(TileEntity te, CallbackInfoReturnable<Boolean> 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);
}
}
} }
} }

View file

@ -3,6 +3,7 @@ package com.simibubi.create.foundation.mixin;
import java.util.Map; import java.util.Map;
import com.simibubi.create.CreateClient; import com.simibubi.create.CreateClient;
import net.minecraft.client.world.ClientWorld;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
@ -33,6 +34,7 @@ public abstract class LightUpdateMixin extends AbstractChunkProvider {
@Inject(at = @At("HEAD"), method = "markLightChanged") @Inject(at = @At("HEAD"), method = "markLightChanged")
private void onLightUpdate(LightType type, SectionPos pos, CallbackInfo ci) { private void onLightUpdate(LightType type, SectionPos pos, CallbackInfo ci) {
ClientChunkProvider thi = ((ClientChunkProvider) (Object) this); ClientChunkProvider thi = ((ClientChunkProvider) (Object) this);
ClientWorld world = (ClientWorld) thi.getWorld();
Chunk chunk = thi.getChunk(pos.getSectionX(), pos.getSectionZ(), false); Chunk chunk = thi.getChunk(pos.getSectionX(), pos.getSectionZ(), false);
@ -43,14 +45,15 @@ public abstract class LightUpdateMixin extends AbstractChunkProvider {
.entrySet() .entrySet()
.stream() .stream()
.filter(entry -> SectionPos.toChunk(entry.getKey().getY()) == sectionY) .filter(entry -> SectionPos.toChunk(entry.getKey().getY()) == sectionY)
.map(Map.Entry::getValue).forEach(tile -> { .map(Map.Entry::getValue)
CreateClient.kineticRenderer.onLightUpdate(tile); .forEach(tile -> {
CreateClient.kineticRenderer.get(world).onLightUpdate(tile);
if (tile instanceof ILightListener) if (tile instanceof ILightListener)
((ILightListener) tile).onChunkLightUpdate(); ((ILightListener) tile).onChunkLightUpdate();
}); });
} }
ContraptionRenderDispatcher.notifyLightUpdate((ILightReader) thi.getWorld(), type, pos); ContraptionRenderDispatcher.notifyLightUpdate(world, type, pos);
} }
} }

View file

@ -1,5 +1,6 @@
package com.simibubi.create.foundation.mixin; package com.simibubi.create.foundation.mixin;
import com.simibubi.create.foundation.render.KineticRenderer;
import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.*;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL20;
@ -52,17 +53,20 @@ public class RenderHooksMixin {
double camY = cameraPos.getY(); double camY = cameraPos.getY();
double camZ = cameraPos.getZ(); double camZ = cameraPos.getZ();
CreateClient.kineticRenderer.beginFrame(camX, camY, camZ); CreateClient.kineticRenderer.get(world).beginFrame(camX, camY, camZ);
ContraptionRenderDispatcher.beginFrame(camX, camY, camZ); ContraptionRenderDispatcher.beginFrame(camX, camY, camZ);
} }
@Inject(at = @At("TAIL"), method = "loadRenderers") @Inject(at = @At("TAIL"), method = "loadRenderers")
private void refresh(CallbackInfo ci) { private void refresh(CallbackInfo ci) {
CreateClient.kineticRenderer.invalidate();
ContraptionRenderDispatcher.invalidateAll(); ContraptionRenderDispatcher.invalidateAll();
OptifineHandler.refresh(); OptifineHandler.refresh();
Backend.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);
}
} }
} }

View file

@ -19,6 +19,10 @@ import com.simibubi.create.foundation.render.backend.gl.shader.ShaderConstants;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
public class AllProgramSpecs { public class AllProgramSpecs {
public static void init() {
// noop, make sure the static field are loaded.
}
public static final ProgramSpec<BasicProgram> MODEL = register(ProgramSpec.builder("model", BasicProgram::new) public static final ProgramSpec<BasicProgram> MODEL = register(ProgramSpec.builder("model", BasicProgram::new)
.addAttributes(ModelVertexAttributes.class) .addAttributes(ModelVertexAttributes.class)
.addAttributes(InstanceVertexAttributes.class) .addAttributes(InstanceVertexAttributes.class)
@ -90,10 +94,6 @@ public class AllProgramSpecs {
.setFrag(Locations.CONTRAPTION) .setFrag(Locations.CONTRAPTION)
.createProgramSpec()); .createProgramSpec());
public static class Contraption {
}
public static class Locations { public static class Locations {
public static final ResourceLocation MODEL_FRAG = loc("model.frag"); public static final ResourceLocation MODEL_FRAG = loc("model.frag");

View file

@ -19,6 +19,7 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
public class KineticRenderer extends InstancedTileRenderer<BasicProgram> { public class KineticRenderer extends InstancedTileRenderer<BasicProgram> {
public static int MAX_ORIGIN_DISTANCE = 100; public static int MAX_ORIGIN_DISTANCE = 100;
@ -40,30 +41,27 @@ public class KineticRenderer extends InstancedTileRenderer<BasicProgram> {
} }
@Override @Override
public void tick() { public void beginFrame(double cameraX, double cameraY, double cameraZ) {
super.tick(); int cX = MathHelper.floor(cameraX);
int cY = MathHelper.floor(cameraY);
int cZ = MathHelper.floor(cameraZ);
Minecraft mc = Minecraft.getInstance(); int dX = Math.abs(cX - originCoordinate.getX());
Entity renderViewEntity = mc.renderViewEntity; int dY = Math.abs(cY - originCoordinate.getY());
int dZ = Math.abs(cZ - originCoordinate.getZ());
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());
if (dX > MAX_ORIGIN_DISTANCE || if (dX > MAX_ORIGIN_DISTANCE ||
dY > MAX_ORIGIN_DISTANCE || dY > MAX_ORIGIN_DISTANCE ||
dZ > MAX_ORIGIN_DISTANCE) { dZ > MAX_ORIGIN_DISTANCE) {
originCoordinate = renderViewPosition; originCoordinate = new BlockPos(cX, cY, cZ);
ArrayList<TileEntity> instancedTiles = new ArrayList<>(instances.keySet()); ArrayList<TileEntity> instancedTiles = new ArrayList<>(instances.keySet());
invalidate(); invalidate();
instancedTiles.forEach(this::add); instancedTiles.forEach(this::add);
} }
super.beginFrame(cameraX, cameraY, cameraZ);
} }
@Override @Override

View file

@ -2,13 +2,11 @@ package com.simibubi.create.foundation.render.backend;
import java.util.concurrent.ConcurrentHashMap; 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.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import com.simibubi.create.CreateClient; import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.KineticDebugger; 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.AnimationTickHolder;
import com.simibubi.create.foundation.utility.WorldAttached; import com.simibubi.create.foundation.utility.WorldAttached;
@ -41,14 +39,15 @@ public class FastRenderDispatcher {
public static void tick() { public static void tick() {
ClientWorld world = Minecraft.getInstance().world; ClientWorld world = Minecraft.getInstance().world;
CreateClient.kineticRenderer.tick(); KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world);
kineticRenderer.tick();
ConcurrentHashMap.KeySetView<TileEntity, Boolean> map = queuedUpdates.get(world); ConcurrentHashMap.KeySetView<TileEntity, Boolean> map = queuedUpdates.get(world);
map map
.forEach(te -> { .forEach(te -> {
map.remove(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) { public static void renderLayer(RenderType layer, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) {
if (!Backend.canUseInstancing()) return; if (!Backend.canUseInstancing()) return;
ClientWorld world = Minecraft.getInstance().world;
KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world);
layer.startDrawing(); layer.startDrawing();
CreateClient.kineticRenderer.render(layer, viewProjection, cameraX, cameraY, cameraZ); kineticRenderer.render(layer, viewProjection, cameraX, cameraY, cameraZ);
layer.endDrawing(); layer.endDrawing();
} }

View file

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -40,4 +41,8 @@ public class WorldAttached<T> {
attached.put(world, entry); attached.put(world, entry);
} }
public void forEach(Consumer<T> consumer) {
attached.values().forEach(consumer);
}
} }