diff --git a/sources/src/main/java/io/akarin/api/internal/mixin/IMixinWorldServer.java b/sources/src/main/java/io/akarin/api/internal/mixin/IMixinWorldServer.java index db7c0ac07..2126fa722 100644 --- a/sources/src/main/java/io/akarin/api/internal/mixin/IMixinWorldServer.java +++ b/sources/src/main/java/io/akarin/api/internal/mixin/IMixinWorldServer.java @@ -2,7 +2,10 @@ package io.akarin.api.internal.mixin; import java.util.Random; +import com.googlecode.concurentlocks.ReentrantReadWriteUpdateLock; + public interface IMixinWorldServer { public Object lock(); public Random rand(); + public ReentrantReadWriteUpdateLock trackerLock(); } \ No newline at end of file diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinMinecraftServer.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinMinecraftServer.java index 1272e6aff..6a9b290ba 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/MixinMinecraftServer.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/MixinMinecraftServer.java @@ -153,22 +153,29 @@ public abstract class MixinMinecraftServer { case 1: default: // Never tick one world concurrently! - for (int i = 0; i < cachedWorldSize; i++) { + for (int i = 1; i <= cachedWorldSize; ++i) { // Impl Note: // Entities ticking: index 1 -> ... -> 0 (parallel) // World ticking: index 0 -> ... (parallel) - int interlace = i + 1; - WorldServer entityWorld = worlds.get(interlace < cachedWorldSize ? interlace : 0); + WorldServer entityWorld = worlds.get(i < cachedWorldSize ? i : 0); Akari.STAGE_TICK.submit(() -> { synchronized (((IMixinWorldServer) entityWorld).lock()) { tickEntities(entityWorld); } }, null/*new TimingSignal(entityWorld, true)*/); - - WorldServer world = worlds.get(i); - synchronized (((IMixinWorldServer) world).lock()) { - tickWorld(world); + } + + Akari.STAGE_TICK.submit(() -> { + for (int i = 0; i < cachedWorldSize; i++) { + WorldServer world = worlds.get(i); + synchronized (((IMixinWorldServer) world).lock()) { + tickWorld(world); + } } + }, null); + + for (int i = cachedWorldSize; i -->= 0 ;) { + Akari.STAGE_TICK.take(); } /* for (int i = (AkarinGlobalConfig.parallelMode == 1 ? cachedWorldSize : cachedWorldSize * 2); i --> 0 ;) { @@ -189,13 +196,16 @@ public abstract class MixinMinecraftServer { } }, null); - for (int i = 0; i < cachedWorldSize; ++i) { - WorldServer world = worlds.get(i); - synchronized (((IMixinWorldServer) world).lock()) { - tickWorld(world); + Akari.STAGE_TICK.submit(() -> { + for (int i = 0; i < cachedWorldSize; ++i) { + WorldServer world = worlds.get(i); + synchronized (((IMixinWorldServer) world).lock()) { + tickWorld(world); + } } - } + }, null); + Akari.STAGE_TICK.take(); Akari.STAGE_TICK.take(); break; case -1: diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinWorldManager.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinWorldManager.java index 6ed5aff6f..5ca57f7ea 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/MixinWorldManager.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/MixinWorldManager.java @@ -5,6 +5,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; +import io.akarin.api.internal.mixin.IMixinWorldServer; import net.minecraft.server.Entity; import net.minecraft.server.EntityPlayer; import net.minecraft.server.WorldManager; @@ -16,9 +17,9 @@ public abstract class MixinWorldManager { @Overwrite public void a(Entity entity) { - this.world.getTracker().entriesLock.writeLock().lock(); // Akarin + ((IMixinWorldServer) this.world).trackerLock().writeLock().lock(); // Akarin this.world.getTracker().track(entity); - this.world.getTracker().entriesLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) this.world).trackerLock().writeLock().unlock(); // Akarin if (entity instanceof EntityPlayer) { this.world.worldProvider.a((EntityPlayer) entity); diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinWorldServer.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinWorldServer.java index 1ffd794e0..fc4deaabc 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/MixinWorldServer.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/MixinWorldServer.java @@ -4,6 +4,9 @@ import java.util.Random; import org.apache.logging.log4j.LogManager; import org.spongepowered.asm.mixin.Mixin; + +import com.googlecode.concurentlocks.ReentrantReadWriteUpdateLock; + import io.akarin.api.internal.mixin.IMixinWorldServer; import net.minecraft.server.WorldServer; @@ -34,4 +37,11 @@ public abstract class MixinWorldServer implements IMixinWorldServer { public Random rand() { return sharedRandom; } + + public final ReentrantReadWriteUpdateLock trackerLock = new ReentrantReadWriteUpdateLock(); + + @Override + public ReentrantReadWriteUpdateLock trackerLock() { + return trackerLock; + } } diff --git a/sources/src/main/java/net/minecraft/server/EntityPlayer.java b/sources/src/main/java/net/minecraft/server/EntityPlayer.java index 67f9bd2b8..d2eccf099 100644 --- a/sources/src/main/java/net/minecraft/server/EntityPlayer.java +++ b/sources/src/main/java/net/minecraft/server/EntityPlayer.java @@ -2,6 +2,8 @@ package net.minecraft.server; import com.google.common.collect.Lists; import com.mojang.authlib.GameProfile; + +import io.akarin.api.internal.mixin.IMixinWorldServer; import io.netty.buffer.Unpooled; import java.util.ArrayDeque; // Paper import java.util.ArrayList; @@ -761,9 +763,9 @@ public class EntityPlayer extends EntityHuman implements ICrafting { if (entity instanceof EntityPlayer) { WorldServer worldServer = (WorldServer) entity.getWorld(); worldServer.tracker.untrackEntity(this); - worldServer.tracker.entriesLock.writeLock().lock(); // Akarin + ((IMixinWorldServer) worldServer).trackerLock().writeLock().lock(); // Akarin worldServer.tracker.track(this); - worldServer.tracker.entriesLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) worldServer).trackerLock().writeLock().unlock(); // Akarin } // Paper end diff --git a/sources/src/main/java/net/minecraft/server/EntityTracker.java b/sources/src/main/java/net/minecraft/server/EntityTracker.java index 33e2d8bc4..8e9db846f 100644 --- a/sources/src/main/java/net/minecraft/server/EntityTracker.java +++ b/sources/src/main/java/net/minecraft/server/EntityTracker.java @@ -4,6 +4,8 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.googlecode.concurentlocks.ReentrantReadWriteUpdateLock; +import io.akarin.api.internal.mixin.IMixinWorldServer; + import java.util.ArrayList; import java.util.Iterator; import java.util.Set; @@ -23,7 +25,6 @@ public class EntityTracker { private static final Logger a = LogManager.getLogger(); private final WorldServer world; private final Set c = Sets.newHashSet(); - public final ReentrantReadWriteUpdateLock entriesLock = new ReentrantReadWriteUpdateLock(); // Akarin - add lock public final IntHashMap trackedEntities = new IntHashMap(); private int e; @@ -160,7 +161,7 @@ public class EntityTracker { public void untrackEntity(Entity entity) { org.spigotmc.AsyncCatcher.catchOp( "entity untrack"); // Spigot - entriesLock.writeLock().lock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin if (entity instanceof EntityPlayer) { EntityPlayer entityplayer = (EntityPlayer) entity; Iterator iterator = this.c.iterator(); @@ -179,14 +180,14 @@ public class EntityTracker { entitytrackerentry1.a(); } - entriesLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin } public void updatePlayers() { ArrayList arraylist = Lists.newArrayList(); Iterator iterator = this.c.iterator(); world.timings.tracker1.startTiming(); // Spigot - entriesLock.writeLock().lock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin while (iterator.hasNext()) { EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); @@ -214,14 +215,14 @@ public class EntityTracker { } } } - entriesLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin world.timings.tracker2.stopTiming(); // Spigot } public void a(EntityPlayer entityplayer) { Iterator iterator = this.c.iterator(); - entriesLock.writeLock().lock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin while (iterator.hasNext()) { EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); @@ -233,13 +234,13 @@ public class EntityTracker { } } - entriesLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin } public void a(Entity entity, Packet packet) { - entriesLock.readLock().lock(); // Akarin + ((IMixinWorldServer) world).trackerLock().readLock().lock(); // Akarin EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) this.trackedEntities.get(entity.getId()); - entriesLock.readLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().readLock().unlock(); // Akarin if (entitytrackerentry != null) { entitytrackerentry.broadcast(packet); @@ -248,9 +249,9 @@ public class EntityTracker { } public void sendPacketToEntity(Entity entity, Packet packet) { - entriesLock.readLock().lock(); // Akarin + ((IMixinWorldServer) world).trackerLock().readLock().lock(); // Akarin EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) this.trackedEntities.get(entity.getId()); - entriesLock.readLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().readLock().unlock(); // Akarin if (entitytrackerentry != null) { entitytrackerentry.broadcastIncludingSelf(packet); @@ -260,7 +261,7 @@ public class EntityTracker { public void untrackPlayer(EntityPlayer entityplayer) { Iterator iterator = this.c.iterator(); - entriesLock.writeLock().lock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin while (iterator.hasNext()) { EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); @@ -268,14 +269,14 @@ public class EntityTracker { entitytrackerentry.clear(entityplayer); } - entriesLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin } public void a(EntityPlayer entityplayer, Chunk chunk) { ArrayList arraylist = Lists.newArrayList(); ArrayList arraylist1 = Lists.newArrayList(); Iterator iterator = this.c.iterator(); - entriesLock.writeLock().lock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin while (iterator.hasNext()) { EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); @@ -292,7 +293,7 @@ public class EntityTracker { } } } - entriesLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin Entity entity1; @@ -319,7 +320,7 @@ public class EntityTracker { public void a(int i) { this.e = (i - 1) * 16; Iterator iterator = this.c.iterator(); - entriesLock.readLock().lock(); // Akarin + ((IMixinWorldServer) world).trackerLock().readLock().lock(); // Akarin while (iterator.hasNext()) { EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); @@ -327,6 +328,6 @@ public class EntityTracker { entitytrackerentry.a(this.e); } - entriesLock.readLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().readLock().unlock(); // Akarin } } \ No newline at end of file diff --git a/sources/src/main/java/net/minecraft/server/PlayerChunkMap.java b/sources/src/main/java/net/minecraft/server/PlayerChunkMap.java index bf71ab1eb..31fffbde1 100644 --- a/sources/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/sources/src/main/java/net/minecraft/server/PlayerChunkMap.java @@ -1,6 +1,8 @@ package net.minecraft.server; import co.aikar.timings.Timing; +import io.akarin.api.internal.mixin.IMixinWorldServer; + import com.google.common.collect.AbstractIterator; import com.google.common.collect.ComparisonChain; import com.google.common.collect.Lists; @@ -36,7 +38,6 @@ public class PlayerChunkMap { }; private final WorldServer world; private final List managedPlayers = Lists.newArrayList(); - private final ReentrantReadWriteLock managedPlayersLock = new ReentrantReadWriteLock(); // Akarin - add lock private final Long2ObjectMap e = new Long2ObjectOpenHashMap(4096); private final Set f = Sets.newHashSet(); private final List g = Lists.newLinkedList(); @@ -92,10 +93,11 @@ public class PlayerChunkMap { }; } - public synchronized void flush() { // Akarin - synchronized + public void flush() { long i = this.world.getTime(); int j; PlayerChunk playerchunk; + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin if (i - this.k > 8000L) { try (Timing ignored = world.timings.doChunkMapUpdate.startTiming()) { // Paper @@ -203,7 +205,6 @@ public class PlayerChunkMap { } // Paper timing } - managedPlayersLock.readLock().lock(); // Akarin if (this.managedPlayers.isEmpty()) { try (Timing ignored = world.timings.doChunkMapUnloadChunks.startTiming()) { // Paper WorldProvider worldprovider = this.world.worldProvider; @@ -213,19 +214,23 @@ public class PlayerChunkMap { } } // Paper timing } - managedPlayersLock.readLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin } - public synchronized boolean a(int i, int j) { // Akarin - synchronized + public boolean a(int i, int j) { long k = d(i, j); + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); try { // Akarin return this.e.get(k) != null; + } finally { ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); } // Akarin } @Nullable - public synchronized PlayerChunk getChunk(int i, int j) { // Akarin - synchronized + public PlayerChunk getChunk(int i, int j) { + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); try { // Akarin return (PlayerChunk) this.e.get(d(i, j)); + } finally { ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); } // Akarin } private PlayerChunk c(int i, int j) { @@ -290,16 +295,14 @@ public class PlayerChunkMap { } Collections.sort(chunkList, new ChunkCoordComparator(entityplayer)); - synchronized (this) { // Akarin - synchronized + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin for (ChunkCoordIntPair pair : chunkList) { this.c(pair.x, pair.z).a(entityplayer); } - } // Akarin // CraftBukkit end - managedPlayersLock.writeLock().lock(); // Akarin this.managedPlayers.add(entityplayer); - managedPlayersLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin this.e(); } @@ -320,9 +323,9 @@ public class PlayerChunkMap { } } - managedPlayersLock.writeLock().lock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin this.managedPlayers.remove(entityplayer); - managedPlayersLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin this.e(); } @@ -375,11 +378,11 @@ public class PlayerChunkMap { // CraftBukkit start - send nearest chunks first Collections.sort(chunksToLoad, new ChunkCoordComparator(entityplayer)); - synchronized (this) { // Akarin - synchronized + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin for (ChunkCoordIntPair pair : chunksToLoad) { this.c(pair.x, pair.z).a(entityplayer); } - } // Akarin + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin // CraftBukkit end } } @@ -397,9 +400,9 @@ public class PlayerChunkMap { i = MathHelper.clamp(i, 3, 32); if (i != this.j) { int j = i - this.j; - managedPlayersLock.readLock().lock(); // Akarin + ((IMixinWorldServer) world).trackerLock().readLock().lock(); // Akarin ArrayList arraylist = Lists.newArrayList(this.managedPlayers); - managedPlayersLock.readLock().unlock(); // Akarin + ((IMixinWorldServer) world).trackerLock().readLock().unlock(); // Akarin Iterator iterator = arraylist.iterator(); while (iterator.hasNext()) { @@ -428,8 +431,8 @@ public class PlayerChunkMap { int i1; int j1; + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin if (j > 0) { - synchronized (this) { // Akarin - synchronized for (i1 = k - i; i1 <= k + i; ++i1) { for (j1 = l - i; j1 <= l + i; ++j1) { PlayerChunk playerchunk = this.c(i1, j1); @@ -439,9 +442,7 @@ public class PlayerChunkMap { } } } - } // Akarin } else { - synchronized (this) { // Akarin - synchronized for (i1 = k - oldViewDistance; i1 <= k + oldViewDistance; ++i1) { for (j1 = l - oldViewDistance; j1 <= l + oldViewDistance; ++j1) { if (!this.a(i1, j1, k, l, i)) { @@ -449,11 +450,11 @@ public class PlayerChunkMap { } } } - } // Akarin if (markSort) { this.e(); } } + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin } } // Paper end @@ -471,12 +472,15 @@ public class PlayerChunkMap { return (long) i + 2147483647L | (long) j + 2147483647L << 32; } - public synchronized void a(PlayerChunk playerchunk) { // Akarin - synchronized + public void a(PlayerChunk playerchunk) { org.spigotmc.AsyncCatcher.catchOp("Async Player Chunk Add"); // Paper + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin this.f.add(playerchunk); + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin } - public synchronized void b(PlayerChunk playerchunk) { // Akarin - synchronized + public void b(PlayerChunk playerchunk) { + ((IMixinWorldServer) world).trackerLock().writeLock().lock(); // Akarin org.spigotmc.AsyncCatcher.catchOp("Async Player Chunk Remove"); // Paper ChunkCoordIntPair chunkcoordintpair = playerchunk.a(); long i = d(chunkcoordintpair.x, chunkcoordintpair.z); @@ -498,6 +502,7 @@ public class PlayerChunkMap { } // Paper end } + ((IMixinWorldServer) world).trackerLock().writeLock().unlock(); // Akarin } diff --git a/sources/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/sources/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 410e3cd13..e4ac929e6 100644 --- a/sources/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/sources/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -7,6 +7,8 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.io.BaseEncoding; import com.mojang.authlib.GameProfile; + +import io.akarin.api.internal.mixin.IMixinWorldServer; import io.netty.buffer.Unpooled; import java.io.ByteArrayOutputStream; @@ -1197,12 +1199,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { EntityTracker tracker = ((WorldServer) entity.world).tracker; // Paper end - tracker.entriesLock.writeLock().lock(); // Akarin + ((IMixinWorldServer) entity.world).trackerLock().writeLock().lock(); // Akarin EntityTrackerEntry entry = tracker.trackedEntities.get(other.getId()); if (entry != null) { entry.clear(getHandle()); } - tracker.entriesLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) entity.world).trackerLock().writeLock().unlock(); // Akarin // Remove the hidden player from this player user list, if they're on it if (other.sentListPacket) { @@ -1249,12 +1251,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player { getHandle().playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, other)); - tracker.entriesLock.writeLock().lock(); // Akarin + ((IMixinWorldServer) entity.world).trackerLock().writeLock().lock(); // Akarin EntityTrackerEntry entry = tracker.trackedEntities.get(other.getId()); if (entry != null && !entry.trackedPlayers.contains(getHandle())) { entry.updatePlayer(getHandle()); } - tracker.entriesLock.writeLock().unlock(); // Akarin + ((IMixinWorldServer) entity.world).trackerLock().writeLock().unlock(); // Akarin } // Paper start private void reregisterPlayer(EntityPlayer player) {