From dc42e6bb6e95df2e7f01c5c1f64718943f8ce312 Mon Sep 17 00:00:00 2001 From: QUENTIN453 Date: Sat, 6 May 2023 20:13:27 +0200 Subject: [PATCH] Fix some bugs / optimize MixinWorldTick + Make a spotlessApply --- .../client/core/MixinEntitiesRendering.java | 14 +-- .../client/core/MixinLiquidRendering.java | 50 ++++++++--- .../mixins/client/core/MixinWorldgen.java | 2 +- .../common/core/MixinEntitySpawning.java | 7 +- .../mixins/common/core/MixinEntityUpdate.java | 5 +- .../mixins/common/core/MixinExplosions.java | 1 - .../mixins/common/core/MixinWorldTick.java | 87 ++++++++++--------- 7 files changed, 101 insertions(+), 65 deletions(-) diff --git a/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinEntitiesRendering.java b/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinEntitiesRendering.java index 0f62bd88..50973929 100644 --- a/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinEntitiesRendering.java +++ b/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinEntitiesRendering.java @@ -3,10 +3,6 @@ import java.util.*; import java.util.concurrent.*; -import cpw.mods.fml.common.FMLLog; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.EntityRenderer; -import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.entity.Entity; @@ -20,18 +16,23 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import cpw.mods.fml.common.FMLLog; import fr.iamacat.multithreading.config.MultithreadingandtweaksMultithreadingConfig; @Mixin(EntityLivingBase.class) public abstract class MixinEntitiesRendering { + private final ConcurrentLinkedQueue entityQueue = new ConcurrentLinkedQueue<>(); private final ExecutorService executorService = Executors.newFixedThreadPool( MultithreadingandtweaksMultithreadingConfig.numberofcpus, - new ThreadFactoryBuilder().setNameFormat("Entity-Rendering-%d").build()); + new ThreadFactoryBuilder().setNameFormat("Entity-Rendering-%d") + .build()); private static final int BATCH_SIZE = MultithreadingandtweaksMultithreadingConfig.batchsize; private long lastRenderTime = System.currentTimeMillis(); protected abstract void myBindEntityTexture(Entity entity); + private int tickCounter; protected abstract void myRenderShadow(Entity entity, double x, double y, double z, float yaw, float partialTicks); @@ -56,7 +57,8 @@ public void onDoRender(Entity entity, double x, double y, double z, float yaw, f renderEntities(entityQueue); } catch (Exception e) { // Log exception and rethrow - FMLLog.getLogger().error("Error rendering entities", e); + FMLLog.getLogger() + .error("Error rendering entities", e); throw e; } finally { entityQueue.clear(); diff --git a/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinLiquidRendering.java b/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinLiquidRendering.java index d4531fca..2c7a804b 100644 --- a/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinLiquidRendering.java +++ b/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinLiquidRendering.java @@ -28,10 +28,12 @@ public abstract class MixinLiquidRendering { private static final int BATCH_SIZE = MultithreadingandtweaksMultithreadingConfig.batchsize; - private static final ExecutorService THREAD_POOL = Executors.newFixedThreadPool(MultithreadingandtweaksMultithreadingConfig.numberofcpus); + private static final ExecutorService THREAD_POOL = Executors + .newFixedThreadPool(MultithreadingandtweaksMultithreadingConfig.numberofcpus); @Inject(method = "tesselate", at = @At("HEAD"), cancellable = true) - private void onTesselate(IBlockAccess world, BlockPos pos, Tessellator tessellator, int metadata, CallbackInfoReturnable ci) { + private void onTesselate(IBlockAccess world, BlockPos pos, Tessellator tessellator, int metadata, + CallbackInfoReturnable ci) { if (MultithreadingandtweaksMultithreadingConfig.enableMixinLiquidRendering) { ci.cancel(); tesselateFluid(world, pos, tessellator, metadata); @@ -53,16 +55,25 @@ private void tesselateFluid(IBlockAccess world, BlockPos pos, Tessellator tessel } } - private void tesselateBatch(World world, List positions, Tessellator tessellator, Set visitedBlocks, int state, Queue fluidBlocks) { - Block block = world.getBlock(positions.get(0).getX(), positions.get(0).getY(), positions.get(0).getZ()); + private void tesselateBatch(World world, List positions, Tessellator tessellator, + Set visitedBlocks, int state, Queue fluidBlocks) { + Block block = world.getBlock( + positions.get(0) + .getX(), + positions.get(0) + .getY(), + positions.get(0) + .getZ()); List nextPositions = new ArrayList<>(); - Minecraft minecraft = FMLClientHandler.instance().getClient(); + Minecraft minecraft = FMLClientHandler.instance() + .getClient(); TextureMap textureMapBlocks = minecraft.getTextureMapBlocks(); for (BlockPos blockPos : positions) { Block currentBlock = world.getBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - if (currentBlock.getMaterial().isLiquid() && currentBlock == block) { + if (currentBlock.getMaterial() + .isLiquid() && currentBlock == block) { for (EnumFacing direction : EnumFacing.values()) { BlockPos offset = blockPos.offset(direction); if (!visitedBlocks.add(offset)) { @@ -71,11 +82,24 @@ private void tesselateBatch(World world, List positions, Tessellator t Block offsetBlock = world.getBlock(offset.getX(), offset.getY(), offset.getZ()); int offsetMetadata = world.getBlockMetadata(offset.getX(), offset.getY(), offset.getZ()); - if (offsetBlock.getMaterial().isReplaceable() || (offsetBlock.getMaterial().isLiquid() && offsetBlock == block && offsetMetadata == state)) { - putFluidVertex(tessellator, blockPos.getX(), blockPos.getY(), blockPos.getZ(), textureMapBlocks.getTextureExtry(offsetBlock.getIcon(0, offsetMetadata).getIconName()), direction); - } else if (offsetBlock.getMaterial().isLiquid() && offsetBlock == block) { - nextPositions.add(offset); - } + if (offsetBlock.getMaterial() + .isReplaceable() + || (offsetBlock.getMaterial() + .isLiquid() && offsetBlock == block + && offsetMetadata == state)) { + putFluidVertex( + tessellator, + blockPos.getX(), + blockPos.getY(), + blockPos.getZ(), + textureMapBlocks.getTextureExtry( + offsetBlock.getIcon(0, offsetMetadata) + .getIconName()), + direction); + } else if (offsetBlock.getMaterial() + .isLiquid() && offsetBlock == block) { + nextPositions.add(offset); + } } } } @@ -84,7 +108,9 @@ private void tesselateBatch(World world, List positions, Tessellator t fluidBlocks.addAll(nextPositions); } } - private void putFluidVertex(Tessellator renderer, double x, double y, double z, TextureAtlasSprite sprite, EnumFacing facing) { + + private void putFluidVertex(Tessellator renderer, double x, double y, double z, TextureAtlasSprite sprite, + EnumFacing facing) { float minU, maxU, minV, maxV; if (facing == EnumFacing.UP || facing == EnumFacing.DOWN) { minU = sprite.getInterpolatedU(x * 8); diff --git a/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinWorldgen.java b/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinWorldgen.java index 1c1d4c27..03a28376 100644 --- a/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinWorldgen.java +++ b/src/main/java/fr/iamacat/multithreading/mixins/client/core/MixinWorldgen.java @@ -10,7 +10,6 @@ import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.client.multiplayer.WorldClient; -import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import org.spongepowered.asm.mixin.Mixin; @@ -24,6 +23,7 @@ @Mixin(WorldClient.class) public abstract class MixinWorldgen { + private WorldClient world; private final ExecutorService executorService = Executors.newFixedThreadPool(6); diff --git a/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinEntitySpawning.java b/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinEntitySpawning.java index e5391e96..e771dac5 100644 --- a/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinEntitySpawning.java +++ b/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinEntitySpawning.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; @@ -29,7 +28,8 @@ public abstract class MixinEntitySpawning { private final ExecutorService executorService = Executors.newFixedThreadPool( MultithreadingandtweaksMultithreadingConfig.numberofcpus, - new ThreadFactoryBuilder().setNameFormat("Entity-Spawning-%d").build()); + new ThreadFactoryBuilder().setNameFormat("Entity-Spawning-%d") + .build()); private static final int BATCH_SIZE = MultithreadingandtweaksMultithreadingConfig.batchsize; private final LinkedBlockingQueue spawnQueue = new LinkedBlockingQueue<>(); @@ -87,11 +87,10 @@ private void spawnEntitiesInQueue(World world) { value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFF)V")) private void redirectDoRenderEntities(Render render, Entity entity, double x, double y, double z, float yaw, - float partialTicks) { + float partialTicks) { render.doRender(entity, x, y, z, yaw, partialTicks); } - public void close() { executorService.shutdown(); } diff --git a/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinEntityUpdate.java b/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinEntityUpdate.java index fc7f5e8a..88a3bd2a 100644 --- a/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinEntityUpdate.java +++ b/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinEntityUpdate.java @@ -61,8 +61,9 @@ private void onTick(CallbackInfo ci) { if (MultithreadingandtweaksMultithreadingConfig.enableMixinEntityUpdate) { AtomicInteger indexCounter = new AtomicInteger(0); entitiesToUpdate.parallelStream() - .collect(Collectors.groupingByConcurrent( - entity -> (int) Math.floor(indexCounter.getAndIncrement() / (double) MAX_ENTITIES_PER_TICK))) + .collect( + Collectors.groupingByConcurrent( + entity -> (int) Math.floor(indexCounter.getAndIncrement() / (double) MAX_ENTITIES_PER_TICK))) .values() .parallelStream() .forEach(batch -> { diff --git a/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinExplosions.java b/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinExplosions.java index 81576b96..ce78834e 100644 --- a/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinExplosions.java +++ b/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinExplosions.java @@ -5,7 +5,6 @@ import java.util.concurrent.*; import java.util.stream.Collectors; -import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; import net.minecraft.world.Explosion; import net.minecraft.world.World; diff --git a/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinWorldTick.java b/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinWorldTick.java index 42d2d3b4..011b412a 100644 --- a/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinWorldTick.java +++ b/src/main/java/fr/iamacat/multithreading/mixins/common/core/MixinWorldTick.java @@ -21,14 +21,15 @@ public abstract class MixinWorldTick { private final Object lock = new Object(); - private static final int updatechunkatonce = 10; + private static final int UPDATE_CHUNK_AT_ONCE = 10; private final ConcurrentLinkedQueue chunksToUpdate = new ConcurrentLinkedQueue<>(); private final Map loadedChunks = new ConcurrentHashMap<>(); private final Map> loadingChunks = new ConcurrentHashMap<>(); + private final Object tickLock = new Object(); // Lock for accessing TickNextTick list @Final - private ForkJoinPool executorService = new ForkJoinPool( + private volatile ForkJoinPool executorService = new ForkJoinPool( MultithreadingandtweaksMultithreadingConfig.numberofcpus, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, @@ -47,67 +48,77 @@ private void onTick(CallbackInfo ci) { }, executorService); } } - private void updateChunks(World world) throws Exception { ChunkProviderServer chunkProvider = (ChunkProviderServer) world.getChunkProvider(); IChunkLoader chunkLoader = chunkProvider.currentChunkLoader; - // Add all chunks that need to be updated to the queue - for (Object chunk : chunkProvider.loadedChunks) { - Chunk loadedChunk = (Chunk) chunk; - ChunkCoordIntPair chunkCoord = loadedChunk.getChunkCoordIntPair(); - loadedChunks.put(chunkCoord, loadedChunk); - chunksToUpdate.offer(loadedChunk); + List chunksToUpdateCopy; + synchronized (chunkProvider.loadedChunks) { + chunksToUpdateCopy = new ArrayList<>(chunkProvider.loadedChunks); + } + + List> futures = new ArrayList<>(); + Set adjacentChunks = new HashSet<>(); + Iterator iter = chunksToUpdateCopy.iterator(); + + ConcurrentHashMap loadedChunks = new ConcurrentHashMap<>((Map) chunkProvider.loadedChunks); + ConcurrentLinkedQueue chunksToUpdate = new ConcurrentLinkedQueue<>(chunksToUpdateCopy); + ConcurrentHashMap> loadingChunks = new ConcurrentHashMap<>(); + + while (iter.hasNext()) { + Chunk chunk = iter.next(); + ChunkCoordIntPair chunkCoord = chunk.getChunkCoordIntPair(); + loadedChunks.put(chunkCoord, chunk); + chunksToUpdate.offer(chunk); + adjacentChunks.addAll(getAdjacentChunks(chunkCoord)); + iter.remove(); // remove chunk from the list while iterating } - // Process the chunks in batches while (!chunksToUpdate.isEmpty()) { List batch = new ArrayList<>(); - Set adjacentChunks = new HashSet<>(); - for (int i = 0; i < updatechunkatonce && !chunksToUpdate.isEmpty(); i++) { - Chunk chunk = chunksToUpdate.poll(); - if (chunk != null) { - batch.add(chunk); - ChunkCoordIntPair chunkCoord = chunk.getChunkCoordIntPair(); - adjacentChunks.addAll(getAdjacentChunks(chunkCoord)); - } + for (int i = 0; i < UPDATE_CHUNK_AT_ONCE && !chunksToUpdate.isEmpty(); i++) { + batch.add(chunksToUpdate.poll()); } - // Load the adjacent chunks if they are not already loaded for (ChunkCoordIntPair chunkCoord : adjacentChunks) { if (!loadedChunks.containsKey(chunkCoord) && !loadingChunks.containsKey(chunkCoord)) { - loadingChunks.put(chunkCoord, CompletableFuture.supplyAsync(() -> { + CompletableFuture future = CompletableFuture.supplyAsync(() -> { try { - Chunk adjacentChunk = chunkLoader - .loadChunk(world, chunkCoord.chunkXPos, chunkCoord.chunkZPos); + Chunk adjacentChunk; + synchronized (lock) { + adjacentChunk = chunkLoader.loadChunk(world, chunkCoord.chunkXPos, chunkCoord.chunkZPos); + chunkProvider.saveChunks(false, null); + } loadedChunks.put(chunkCoord, adjacentChunk); return adjacentChunk; } catch (IOException e) { throw new RuntimeException(e); } - }, executorService)); + }, executorService); + futures.add(future); + loadingChunks.put(chunkCoord, future); } } - // Wait for the adjacent chunks to finish loading - for (CompletableFuture future : loadingChunks.values()) { + for (CompletableFuture future : futures) { Chunk adjacentChunk = future.join(); if (adjacentChunk != null) { loadedChunks.put(adjacentChunk.getChunkCoordIntPair(), adjacentChunk); } } - loadingChunks.clear(); + futures.clear(); - // Process the batch of chunks - synchronized (tickLock) { // Synchronize access to TickNextTick list - processBatch(chunkProvider, batch); + synchronized (tickLock) { + processBatch(chunkProvider, new CopyOnWriteArrayList<>(batch)); } } } + + private Set getAdjacentChunks(ChunkCoordIntPair chunkCoord) { - Set adjacentChunks = new HashSet<>(); + Set adjacentChunks = ConcurrentHashMap.newKeySet(); int chunkX = chunkCoord.chunkXPos; int chunkZ = chunkCoord.chunkZPos; int radius = 1; @@ -124,17 +135,15 @@ private Set getAdjacentChunks(ChunkCoordIntPair chunkCoord) { private void processBatch(ChunkProviderServer chunkProvider, List batch) { // Load the chunks from disk asynchronously and save them CompletableFuture.runAsync(() -> { - batch.parallelStream() - .forEach(chunk -> { - synchronized (lock) { - chunkProvider.saveChunks(true, null); - } - }); - // Save all loaded chunks synchronized (lock) { - chunkProvider.saveChunks(true, null); + for (Chunk chunk : batch) { + chunkProvider.saveChunks(true, null); + } + // Save all loaded chunks + for (Chunk chunk : loadedChunks.values()) { + chunkProvider.saveChunks(true, null); + } } }, executorService); } - }