diff --git a/patches/server/0011-Akarin-Avoid-double-I-O-operation-on-load-player-fil.patch b/patches/server/0011-Akarin-Avoid-double-I-O-operation-on-load-player-fil.patch new file mode 100644 index 00000000..f2dd8fd5 --- /dev/null +++ b/patches/server/0011-Akarin-Avoid-double-I-O-operation-on-load-player-fil.patch @@ -0,0 +1,36 @@ +From cc2837fdaeed0fca50be843b79f967c30d054d77 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E3=84=97=E3=84=A0=CB=8B=20=E3=84=91=E3=84=A7=CB=8A?= + +Date: Thu, 2 Apr 2020 11:29:08 +0800 +Subject: [PATCH] Akarin Avoid double I/O operation on load player file + +--- + src/main/java/net/minecraft/server/WorldNBTStorage.java | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/main/java/net/minecraft/server/WorldNBTStorage.java b/src/main/java/net/minecraft/server/WorldNBTStorage.java +index 9517fb046..c18224691 100644 +--- a/src/main/java/net/minecraft/server/WorldNBTStorage.java ++++ b/src/main/java/net/minecraft/server/WorldNBTStorage.java +@@ -64,7 +64,8 @@ public class WorldNBTStorage { + File file = new File(this.playerDir, entityhuman.getUniqueIDString() + ".dat"); + // Spigot Start + boolean usingWrongFile = false; +- if ( org.bukkit.Bukkit.getOnlineMode() && !file.exists() ) // Paper - Check online mode first ++ boolean normalFile = file.exists() && file.isFile(); // Akarin - ensures normal file ++ if ( org.bukkit.Bukkit.getOnlineMode() && !normalFile ) // Paper - Check online mode first // Akarin - ensures normal file + { + file = new File( this.playerDir, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + entityhuman.getName() ).getBytes( "UTF-8" ) ).toString() + ".dat"); + if ( file.exists() ) +@@ -75,7 +76,7 @@ public class WorldNBTStorage { + } + // Spigot End + +- if (file.exists() && file.isFile()) { ++ if (normalFile) { // Akarin - avoid double I/O operation + nbttagcompound = NBTCompressedStreamTools.a((InputStream) (new FileInputStream(file))); + } + // Spigot Start +-- +2.25.1.windows.1 + diff --git a/patches/server/0012-Akarin-Save-json-list-async.patch b/patches/server/0012-Akarin-Save-json-list-async.patch new file mode 100644 index 00000000..2d370872 --- /dev/null +++ b/patches/server/0012-Akarin-Save-json-list-async.patch @@ -0,0 +1,70 @@ +From 8ac16ccac102706d81b65e8e526c8c92dbd15069 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E3=84=97=E3=84=A0=CB=8B=20=E3=84=91=E3=84=A7=CB=8A?= + +Date: Thu, 2 Apr 2020 11:16:18 +0800 +Subject: [PATCH] Akarin Save json list async + +--- + .../java/net/minecraft/server/JsonList.java | 23 ++++++++----------- + 1 file changed, 9 insertions(+), 14 deletions(-) + +diff --git a/src/main/java/net/minecraft/server/JsonList.java b/src/main/java/net/minecraft/server/JsonList.java +index 9213bfb78..f2c14ba31 100644 +--- a/src/main/java/net/minecraft/server/JsonList.java ++++ b/src/main/java/net/minecraft/server/JsonList.java +@@ -20,6 +20,8 @@ import java.util.Iterator; + import java.util.List; + import java.util.Map; + import javax.annotation.Nullable; ++ ++import org.apache.commons.io.IOUtils; + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +@@ -146,6 +148,7 @@ public abstract class JsonList> { + } + + public void save() throws IOException { ++ Runnable runnable = () -> { // Akarin - Save json list async + this.removeStaleEntries(); // Paper - remove expired values before saving + JsonArray jsonarray = new JsonArray(); + +@@ -155,29 +158,21 @@ public abstract class JsonList> { + jsonlistentry.getClass(); + return (JsonObject) SystemUtils.a(jsonobject, jsonlistentry::a); // CraftBukkit - decompile error + }).forEach(jsonarray::add); +- BufferedWriter bufferedwriter = Files.newWriter(this.c, StandardCharsets.UTF_8); ++ BufferedWriter bufferedwriter = null; + Throwable throwable = null; + + try { ++ bufferedwriter = Files.newWriter(this.c, StandardCharsets.UTF_8); + JsonList.b.toJson(jsonarray, bufferedwriter); + } catch (Throwable throwable1) { + throwable = throwable1; +- throw throwable1; ++ JsonList.LOGGER.warn("Failed to save " + this.c, e); // Akarin - Save json list async + } finally { +- if (bufferedwriter != null) { +- if (throwable != null) { +- try { +- bufferedwriter.close(); +- } catch (Throwable throwable2) { +- throwable.addSuppressed(throwable2); +- } +- } else { +- bufferedwriter.close(); +- } +- } ++ IOUtils.closeQuietly(bufferedwriter); + + } +- ++ }; // Akarin - Save json list async ++ MCUtil.scheduleAsyncTask(runnable); // Akarin - Save json list async + } + + public void load() throws IOException { +-- +2.25.1.windows.1 + diff --git a/patches/server/0013-Purpur-Skip-events-if-there-s-no-listeners.patch b/patches/server/0013-Purpur-Skip-events-if-there-s-no-listeners.patch new file mode 100644 index 00000000..fdb83ba1 --- /dev/null +++ b/patches/server/0013-Purpur-Skip-events-if-there-s-no-listeners.patch @@ -0,0 +1,32 @@ +From c164c4ad754a251e226d520da6a92787ed718fa7 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 4 Apr 2020 03:07:59 -0500 +Subject: [PATCH] Purpur Skip events if there's no listeners + +--- + src/main/java/net/minecraft/server/CommandDispatcher.java | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/main/java/net/minecraft/server/CommandDispatcher.java b/src/main/java/net/minecraft/server/CommandDispatcher.java +index e59151d01..4ace0e79c 100644 +--- a/src/main/java/net/minecraft/server/CommandDispatcher.java ++++ b/src/main/java/net/minecraft/server/CommandDispatcher.java +@@ -275,6 +275,7 @@ public class CommandDispatcher { + } + + private void runSync(EntityPlayer entityplayer, Collection bukkit, RootCommandNode rootcommandnode) { ++ if (PlayerCommandSendEvent.getHandlerList().getRegisteredListeners().length > 0) { // Purpur - skip all this crap if there's nothing listening + // Paper end - Async command map building + new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(entityplayer.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper + PlayerCommandSendEvent event = new PlayerCommandSendEvent(entityplayer.getBukkitEntity(), new LinkedHashSet<>(bukkit)); +@@ -287,6 +288,7 @@ public class CommandDispatcher { + } + } + // CraftBukkit end ++ } // Purpur - skip event + entityplayer.playerConnection.sendPacket(new PacketPlayOutCommands(rootcommandnode)); + } + +-- +2.25.1.windows.1 + diff --git a/patches/server/0014-Purpur-Add-more-timings-timers.patch b/patches/server/0014-Purpur-Add-more-timings-timers.patch new file mode 100644 index 00000000..08217aba --- /dev/null +++ b/patches/server/0014-Purpur-Add-more-timings-timers.patch @@ -0,0 +1,221 @@ +From a2d9601f553355eaf0a3f5d8e9900cd45ccbd0bc Mon Sep 17 00:00:00 2001 +From: tr7zw +Date: Tue, 21 Apr 2020 15:49:52 +0200 +Subject: [PATCH] Purpur Add more timings timers + +--- + .../co/aikar/timings/MinecraftTimings.java | 22 +++++++++++++++++++ + .../minecraft/server/EntityInsentient.java | 12 ++++++++++ + .../net/minecraft/server/EntityLiving.java | 20 ++++++++++++++--- + .../server/PathfinderGoalSelector.java | 7 +++++- + .../net/minecraft/server/WorldServer.java | 2 ++ + 5 files changed, 59 insertions(+), 4 deletions(-) + +diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java +index 2966c5731..ae5586737 100644 +--- a/src/main/java/co/aikar/timings/MinecraftTimings.java ++++ b/src/main/java/co/aikar/timings/MinecraftTimings.java +@@ -45,6 +45,28 @@ public final class MinecraftTimings { + + public static final Timing scoreboardScoreSearch = Timings.ofSafe("Scoreboard score search"); // Tuinity - add timings for scoreboard search + ++ // Purpur start ++ public static final Timing goalCleanup = Timings.ofSafe("PathfinderGoal - Cleanup"); ++ public static final Timing goalUpdate = Timings.ofSafe("PathfinderGoal - Update"); ++ public static final Timing goalTick = Timings.ofSafe("PathfinderGoal - Tick"); ++ ++ public static final Timing entityMovementTick = Timings.ofSafe("Entity Movement"); ++ public static final Timing entityMovementTickAI = Timings.ofSafe("Entity Movement - AI"); ++ public static final Timing entityMovementTickNewAI = Timings.ofSafe("Entity Movement - New AI"); ++ public static final Timing entityMovementTickJump = Timings.ofSafe("Entity Movement - Jump"); ++ public static final Timing entityMovementTickTravel = Timings.ofSafe("Entity Movement - Travel"); ++ public static final Timing entityMovementTickPush = Timings.ofSafe("Entity Movement - Push"); ++ ++ public static final Timing entityInsentientSensing = Timings.ofSafe("Entity Insentient - Sensing"); ++ public static final Timing entityInsentientTargetSelector = Timings.ofSafe("Entity Insentient - TargetSelector"); ++ public static final Timing entityInsentientGoalSelector = Timings.ofSafe("Entity Insentient - GoalSelector"); ++ public static final Timing entityInsentientNavigation = Timings.ofSafe("Entity Insentient - Navigation"); ++ public static final Timing entityInsentientMobTick = Timings.ofSafe("Entity Insentient - MobTick"); ++ public static final Timing entityInsentientControls = Timings.ofSafe("Entity Insentient - Controls"); ++ ++ public static final Timing passengerTick = Timings.ofSafe("Passenger Tick"); ++ // Purpur end ++ + private static final Map, String> taskNameCache = new MapMaker().weakKeys().makeMap(); + + private MinecraftTimings() {} +diff --git a/src/main/java/net/minecraft/server/EntityInsentient.java b/src/main/java/net/minecraft/server/EntityInsentient.java +index f638b21a3..5466c763e 100644 +--- a/src/main/java/net/minecraft/server/EntityInsentient.java ++++ b/src/main/java/net/minecraft/server/EntityInsentient.java +@@ -748,21 +748,32 @@ public abstract class EntityInsentient extends EntityLiving { + } + // Paper end + this.world.getMethodProfiler().enter("sensing"); ++ co.aikar.timings.MinecraftTimings.entityInsentientSensing.startTiming(); // Purpur + this.bv.a(); ++ co.aikar.timings.MinecraftTimings.entityInsentientSensing.stopTiming(); // Purpur + this.world.getMethodProfiler().exit(); + this.world.getMethodProfiler().enter("targetSelector"); ++ co.aikar.timings.MinecraftTimings.entityInsentientTargetSelector.startTiming(); // Purpur + this.targetSelector.doTick(); ++ co.aikar.timings.MinecraftTimings.entityInsentientTargetSelector.stopTiming(); // Purpur + this.world.getMethodProfiler().exit(); + this.world.getMethodProfiler().enter("goalSelector"); ++ co.aikar.timings.MinecraftTimings.entityInsentientGoalSelector.startTiming(); // Purpur + this.goalSelector.doTick(); ++ co.aikar.timings.MinecraftTimings.entityInsentientGoalSelector.stopTiming(); // Purpur + this.world.getMethodProfiler().exit(); + this.world.getMethodProfiler().enter("navigation"); ++ co.aikar.timings.MinecraftTimings.entityInsentientNavigation.startTiming(); // Purpur + this.navigation.c(); ++ co.aikar.timings.MinecraftTimings.entityInsentientNavigation.stopTiming(); // Purpur + this.world.getMethodProfiler().exit(); + this.world.getMethodProfiler().enter("mob tick"); ++ co.aikar.timings.MinecraftTimings.entityInsentientMobTick.startTiming(); // Purpur + this.mobTick(); ++ co.aikar.timings.MinecraftTimings.entityInsentientMobTick.stopTiming(); // Purpur + this.world.getMethodProfiler().exit(); + this.world.getMethodProfiler().enter("controls"); ++ co.aikar.timings.MinecraftTimings.entityInsentientControls.startTiming(); // Purpur + this.world.getMethodProfiler().enter("move"); + this.moveController.a(); + this.world.getMethodProfiler().exitEnter("look"); +@@ -770,6 +781,7 @@ public abstract class EntityInsentient extends EntityLiving { + this.world.getMethodProfiler().exitEnter("jump"); + this.bp.b(); + this.world.getMethodProfiler().exit(); ++ co.aikar.timings.MinecraftTimings.entityInsentientControls.stopTiming(); // Purpur + this.world.getMethodProfiler().exit(); + this.M(); + } +diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java +index 3b4d2ae5a..617358db7 100644 +--- a/src/main/java/net/minecraft/server/EntityLiving.java ++++ b/src/main/java/net/minecraft/server/EntityLiving.java +@@ -2467,7 +2467,11 @@ public abstract class EntityLiving extends Entity { + } + } + +- this.movementTick(); ++ ++ MinecraftTimings.entityMovementTick.startTiming(); // Purpur ++ if (!dead) this.movementTick(); // Purpur ++ MinecraftTimings.entityMovementTick.stopTiming(); // Purpur ++ + double d0 = this.locX() - this.lastX; + double d1 = this.locZ() - this.lastZ; + float f = (float) (d0 * d0 + d1 * d1); +@@ -2736,18 +2740,23 @@ public abstract class EntityLiving extends Entity { + + this.setMot(d4, d5, d6); + this.world.getMethodProfiler().enter("ai"); ++ co.aikar.timings.MinecraftTimings.entityMovementTickAI.startTiming(); // Purpur + if (this.isFrozen()) { + this.jumping = false; + this.aY = 0.0F; + this.ba = 0.0F; + } else if (this.doAITick()) { + this.world.getMethodProfiler().enter("newAi"); ++ co.aikar.timings.MinecraftTimings.entityMovementTickNewAI.startTiming(); // Purpur + this.doTick(); ++ co.aikar.timings.MinecraftTimings.entityMovementTickNewAI.stopTiming(); // Purpur + this.world.getMethodProfiler().exit(); + } ++ co.aikar.timings.MinecraftTimings.entityMovementTickAI.stopTiming(); // Purpur + + this.world.getMethodProfiler().exit(); + this.world.getMethodProfiler().enter("jump"); ++ co.aikar.timings.MinecraftTimings.entityMovementTickJump.startTiming(); // Purpur + if (this.jumping && this.cS()) { + double d7; + +@@ -2773,21 +2782,26 @@ public abstract class EntityLiving extends Entity { + } else { + this.jumpTicks = 0; + } ++ co.aikar.timings.MinecraftTimings.entityMovementTickJump.stopTiming(); // Purpur + + this.world.getMethodProfiler().exit(); + this.world.getMethodProfiler().enter("travel"); +- this.aY *= 0.98F; +- this.ba *= 0.98F; ++ co.aikar.timings.MinecraftTimings.entityMovementTickTravel.startTiming(); // Purpur ++ this.aZ *= 0.98F; ++ this.bb *= 0.98F; + this.t(); + AxisAlignedBB axisalignedbb = this.getBoundingBox(); + + this.f(new Vec3D((double) this.aY, (double) this.aZ, (double) this.ba)); ++ co.aikar.timings.MinecraftTimings.entityMovementTickTravel.stopTiming(); // Purpur + this.world.getMethodProfiler().exit(); + this.world.getMethodProfiler().enter("push"); ++ co.aikar.timings.MinecraftTimings.entityMovementTickPush.startTiming(); // Purpur + if (this.bm > 0) { + --this.bm; + this.a(axisalignedbb, this.getBoundingBox()); + } ++ co.aikar.timings.MinecraftTimings.entityMovementTickPush.stopTiming(); // Purpur + + this.collideNearby(); + this.world.getMethodProfiler().exit(); +diff --git a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java +index d3f0327a2..cce7cac92 100644 +--- a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java ++++ b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java +@@ -80,7 +80,7 @@ public class PathfinderGoalSelector { + + public void doTick() { + GameProfilerFiller gameprofilerfiller = (GameProfilerFiller) this.e.get(); +- ++ co.aikar.timings.MinecraftTimings.goalCleanup.startTiming(); + gameprofilerfiller.enter("goalCleanup"); + // Paper start - remove streams from pathfindergoalselector + for (Iterator iterator = this.d.iterator(); iterator.hasNext();) { +@@ -100,8 +100,10 @@ public class PathfinderGoalSelector { + } + + }); ++ co.aikar.timings.MinecraftTimings.goalCleanup.stopTiming(); + gameprofilerfiller.exit(); + gameprofilerfiller.enter("goalUpdate"); ++ co.aikar.timings.MinecraftTimings.goalUpdate.startTiming(); + // Paper start - remove streams from pathfindergoalselector + goal_update_loop: for (Iterator iterator = this.d.iterator(); iterator.hasNext();) { + PathfinderGoalWrapped wrappedGoal = iterator.next(); +@@ -144,8 +146,10 @@ public class PathfinderGoalSelector { + wrappedGoal.c(); + } + // Paper end - remove streams from pathfindergoalselector ++ co.aikar.timings.MinecraftTimings.goalUpdate.stopTiming(); + gameprofilerfiller.exit(); + gameprofilerfiller.enter("goalTick"); ++ co.aikar.timings.MinecraftTimings.goalTick.startTiming(); + // Paper start - remove streams from pathfindergoalselector + for (Iterator iterator = this.d.iterator(); iterator.hasNext();) { + PathfinderGoalWrapped wrappedGoal = iterator.next(); +@@ -155,6 +159,7 @@ public class PathfinderGoalSelector { + } + // Paper end - remove streams from pathfindergoalselector + gameprofilerfiller.exit(); ++ co.aikar.timings.MinecraftTimings.goalTick.stopTiming(); + } + + public final Stream getExecutingGoals() { return d(); } // Paper - OBFHELPER +diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java +index 908df99f3..ad3326fa9 100644 +--- a/src/main/java/net/minecraft/server/WorldServer.java ++++ b/src/main/java/net/minecraft/server/WorldServer.java +@@ -1326,7 +1326,9 @@ public class WorldServer extends World implements GeneratorAccessSeed { + return IRegistry.ENTITY_TYPE.getKey(entity1.getEntityType()).toString(); + }); + gameprofilerfiller.c("tickPassenger"); ++ co.aikar.timings.MinecraftTimings.passengerTick.startTiming(); // Purpur + entity1.passengerTick(); ++ co.aikar.timings.MinecraftTimings.passengerTick.stopTiming(); // Purpur + gameprofilerfiller.exit(); + } + +-- +2.25.1.windows.1 +