From e1aa055983c2362da9e0e012c0a06291c15c4d25 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sun, 18 Jul 2021 18:00:09 -0700 Subject: [PATCH] Parallel and caching - NEEDS MORE TESTING - Tick and update instances in parallel - Mixin to cache chunk lookups --- .../backend/instancing/InstanceManager.java | 10 +-- .../backend/instancing/Instancer.java | 5 +- .../mixin/FastChunkProviderMixin.java | 68 +++++++++++++++++++ .../flywheel/vanilla/VanillaInstances.java | 2 +- src/main/resources/flywheel.mixins.json | 4 +- 5 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/FastChunkProviderMixin.java diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java index 3233cd7fa..c44f49aca 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java @@ -55,10 +55,11 @@ public abstract class InstanceManager implements MaterialManager.OriginShiftL int cZ = (int) cameraZ; if (tickableInstances.size() > 0) { - for (ITickableInstance instance : tickableInstances.values()) { + tickableInstances.object2ObjectEntrySet().parallelStream().forEach(e -> { + ITickableInstance instance = e.getValue(); if (!instance.decreaseTickRateWithDistance()) { instance.tick(); - continue; + return; } BlockPos pos = instance.getWorldPosition(); @@ -68,7 +69,7 @@ public abstract class InstanceManager implements MaterialManager.OriginShiftL int dZ = pos.getZ() - cZ; if ((tick % getUpdateDivisor(dX, dY, dZ)) == 0) instance.tick(); - } + }); } queuedUpdates.forEach(te -> { @@ -94,7 +95,8 @@ public abstract class InstanceManager implements MaterialManager.OriginShiftL if (dynamicInstances.size() > 0) { dynamicInstances.object2ObjectEntrySet() - .fastForEach(e -> { + .parallelStream() + .forEach(e -> { IDynamicInstance dyn = e.getValue(); if (!dyn.decreaseFramerateWithDistance() || shouldFrameUpdate(dyn.getWorldPosition(), lookX, lookY, lookZ, cX, cY, cZ)) dyn.beginFrame(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java index e18c6cefc..43d657350 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java @@ -74,7 +74,10 @@ public class Instancer { D instanceData = factory.create(this); instanceData.dirty = true; anyToUpdate = true; - data.add(instanceData); + + synchronized (data) { + data.add(instanceData); + } return instanceData; } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/FastChunkProviderMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/FastChunkProviderMixin.java new file mode 100644 index 000000000..9a1f3a0f9 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/FastChunkProviderMixin.java @@ -0,0 +1,68 @@ +package com.jozufozu.flywheel.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.client.multiplayer.ClientChunkProvider; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraft.world.biome.BiomeContainer; +import net.minecraft.world.chunk.AbstractChunkProvider; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.IChunk; + +@Mixin(ClientChunkProvider.class) +public abstract class FastChunkProviderMixin extends AbstractChunkProvider { + + @Unique + private int lastX; + @Unique + private int lastZ; + + @Unique + private IChunk lastChunk; + + @Inject(method = "getChunk", + at = @At("HEAD"), + cancellable = true) + public void returnCachedChunk(int x, int z, ChunkStatus status, boolean create, CallbackInfoReturnable cir) { + if (status.isOrAfter(ChunkStatus.FULL) && lastChunk != null && x == lastX && z == lastZ) { + cir.setReturnValue(lastChunk); + } + } + + @Inject(method = "getChunk", + at = @At("RETURN")) + public void cacheChunk(int x, int z, ChunkStatus status, boolean create, CallbackInfoReturnable cir) { + if (status.isOrAfter(ChunkStatus.FULL)) { + lastChunk = cir.getReturnValue(); + lastX = x; + lastZ = z; + } + } + + @Inject(method = "drop", at = @At("HEAD")) + public void invalidateOnDrop(int x, int z, CallbackInfo ci) { + if (x == lastX && z == lastZ) + lastChunk = null; + } + + @Inject(method = "replaceWithPacketData", at = @At("HEAD")) + public void invalidateOnPacket(int x, int z, BiomeContainer p_228313_3_, PacketBuffer p_228313_4_, CompoundNBT p_228313_5_, int p_228313_6_, boolean p_228313_7_, CallbackInfoReturnable cir) { + if (x == lastX && z == lastZ) + lastChunk = null; + } + + @Redirect(method = "isTickingChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientChunkProvider;hasChunk(II)Z")) + public boolean redirectTicking(ClientChunkProvider clientChunkProvider, int x, int z) { + if (lastChunk != null && x == lastX && z == lastZ) return true; + + return clientChunkProvider.hasChunk(x, z); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java b/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java index 3ce2d3e0a..bd8c84d21 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java @@ -13,6 +13,7 @@ import net.minecraft.tileentity.TileEntityType; * {@link TileEntityType#ENCHANTING_TABLE} {@link net.minecraft.client.renderer.tileentity.EnchantmentTableTileEntityRenderer EnchantmentTableTileEntityRenderer} * {@link TileEntityType#LECTERN} {@link net.minecraft.client.renderer.tileentity.LecternTileEntityRenderer LecternTileEntityRenderer} * {@link TileEntityType#MOB_SPAWNER} {@link net.minecraft.client.renderer.tileentity.MobSpawnerTileEntityRenderer MobSpawnerTileEntityRenderer} + * {@link TileEntityType#BED} {@link net.minecraft.client.renderer.tileentity.BedTileEntityRenderer BedTileEntityRenderer} * ^^ Interesting - Major vv * {@link TileEntityType#END_PORTAL} {@link net.minecraft.client.renderer.tileentity.EndPortalTileEntityRenderer EndPortalTileEntityRenderer} * {@link TileEntityType#END_GATEWAY} {@link net.minecraft.client.renderer.tileentity.EndGatewayTileEntityRenderer EndGatewayTileEntityRenderer} @@ -20,7 +21,6 @@ import net.minecraft.tileentity.TileEntityType; * {@link TileEntityType#SKULL} {@link net.minecraft.client.renderer.tileentity.SkullTileEntityRenderer SkullTileEntityRenderer} * {@link TileEntityType#BANNER} {@link net.minecraft.client.renderer.tileentity.BannerTileEntityRenderer BannerTileEntityRenderer} * {@link TileEntityType#STRUCTURE_BLOCK} {@link net.minecraft.client.renderer.tileentity.StructureTileEntityRenderer StructureTileEntityRenderer} - * {@link TileEntityType#BED} {@link net.minecraft.client.renderer.tileentity.BedTileEntityRenderer BedTileEntityRenderer} * {@link TileEntityType#CAMPFIRE} {@link net.minecraft.client.renderer.tileentity.CampfireTileEntityRenderer CampfireTileEntityRenderer} * */ diff --git a/src/main/resources/flywheel.mixins.json b/src/main/resources/flywheel.mixins.json index b930f4173..2c4db2153 100644 --- a/src/main/resources/flywheel.mixins.json +++ b/src/main/resources/flywheel.mixins.json @@ -4,7 +4,6 @@ "package": "com.jozufozu.flywheel.mixin", "compatibilityLevel": "JAVA_8", "refmap": "flywheel.refmap.json", - "mixins": [], "client": [ "CancelEntityRenderMixin", "CancelTileEntityRenderMixin", @@ -18,7 +17,8 @@ "atlas.AtlasDataMixin", "atlas.SheetDataAccessor", "light.LightUpdateMixin", - "light.NetworkLightUpdateMixin" + "light.NetworkLightUpdateMixin", + "FastChunkProviderMixin" ], "injectors": { "defaultRequire": 0