From 78524cb95e46336747ae08ec4853228cb9f9c57a Mon Sep 17 00:00:00 2001 From: CraftBukkit/Spigot <noreply+git-craftbukkit@papermc.io> Date: Thu, 10 Jan 2013 00:18:11 -0500 Subject: [PATCH] Spigot Timings Overhauls the Timings System adding performance tracking all around the Minecraft Server By: Aikar <aikar@aikar.co> --- .../server/MinecraftServer.java.patch | 163 ++++++++---- .../dedicated/DedicatedServer.java.patch | 36 ++- .../server/level/ServerChunkCache.java.patch | 58 ++++- .../server/level/ServerLevel.java.patch | 151 +++++++---- .../ServerGamePacketListenerImpl.java.patch | 131 +++++----- .../minecraft/world/entity/Entity.java.patch | 170 +++++++------ .../world/entity/LivingEntity.java.patch | 240 +++++++++++------- .../minecraft/world/level/Level.java.patch | 80 ++++-- .../world/level/NaturalSpawner.java.patch | 22 +- .../level/block/entity/BlockEntity.java.patch | 15 +- .../world/level/chunk/LevelChunk.java.patch | 39 ++- .../storage/SerializableChunkData.java.patch | 26 +- .../org/bukkit/craftbukkit/CraftServer.java | 5 + .../org/bukkit/craftbukkit/SpigotTimings.java | 160 ++++++++++++ .../craftbukkit/scheduler/CraftScheduler.java | 2 + .../craftbukkit/scheduler/CraftTask.java | 13 +- 16 files changed, 924 insertions(+), 387 deletions(-) create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java diff --git a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch index 788e74d8e2..97079268da 100644 --- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -26,7 +26,7 @@ import net.minecraft.util.debugchart.RemoteDebugSampleType; import net.minecraft.util.debugchart.SampleLogger; import net.minecraft.util.debugchart.TpsDebugDimensions; -@@ -156,29 +146,62 @@ +@@ -156,37 +146,72 @@ import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.FuelValues; @@ -94,9 +94,11 @@ +import org.bukkit.event.server.ServerLoadEvent; +// CraftBukkit end ++import org.bukkit.craftbukkit.SpigotTimings; // Spigot ++ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements ServerInfo, ChunkIOErrorReporter, CommandSource { -@@ -186,7 +209,7 @@ + public static final Logger LOGGER = LogUtils.getLogger(); public static final String VANILLA_BRAND = "vanilla"; private static final float AVERAGE_TICK_TIME_SMOOTHING = 0.8F; private static final int TICK_STATS_SPAN = 100; @@ -105,10 +107,11 @@ private static final int OVERLOADED_TICKS_THRESHOLD = 20; private static final long OVERLOADED_WARNING_INTERVAL_NANOS = 10L * TimeUtil.NANOSECONDS_PER_SECOND; private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100; -@@ -277,6 +300,19 @@ +@@ -276,6 +301,19 @@ + private static final AtomicReference<RuntimeException> fatalException = new AtomicReference(); private final SuppressedExceptionCollector suppressedExceptions; private final DiscontinuousFrame tickFrame; - ++ + // CraftBukkit start + public final WorldLoader.DataLoadContext worldLoader; + public org.bukkit.craftbukkit.CraftServer server; @@ -121,11 +124,10 @@ + public Commands vanillaCommandDispatcher; + private boolean forceTicks; + // CraftBukkit end -+ + public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) { AtomicReference<S> atomicreference = new AtomicReference(); - Thread thread = new Thread(() -> { -@@ -290,14 +326,14 @@ +@@ -290,14 +328,14 @@ thread.setPriority(8); } @@ -142,7 +144,7 @@ super("Server"); this.metricsRecorder = InactiveMetricsRecorder.INSTANCE; this.onMetricsRecordingStopped = (methodprofilerresults) -> { -@@ -319,36 +355,63 @@ +@@ -319,36 +357,63 @@ this.scoreboard = new ServerScoreboard(this); this.customBossEvents = new CustomBossEvents(); this.suppressedExceptions = new SuppressedExceptionCollector(); @@ -220,7 +222,7 @@ } private void readScoreboard(DimensionDataStorage persistentStateManager) { -@@ -357,7 +420,7 @@ +@@ -357,7 +422,7 @@ protected abstract boolean initServer() throws IOException; @@ -229,7 +231,7 @@ if (!JvmProfiler.INSTANCE.isRunning()) { ; } -@@ -365,12 +428,8 @@ +@@ -365,12 +430,8 @@ boolean flag = false; ProfiledDuration profiledduration = JvmProfiler.INSTANCE.onWorldLoadedStarted(); @@ -243,7 +245,7 @@ if (profiledduration != null) { profiledduration.finish(true); } -@@ -387,23 +446,217 @@ +@@ -387,23 +448,217 @@ protected void forceDifficulty() {} @@ -475,7 +477,7 @@ if (!iworlddataserver.isInitialized()) { try { -@@ -427,30 +680,8 @@ +@@ -427,30 +682,8 @@ iworlddataserver.setInitialized(true); } @@ -507,7 +509,7 @@ private static void setInitialSpawn(ServerLevel world, ServerLevelData worldProperties, boolean bonusChest, boolean debugWorld) { if (debugWorld) { -@@ -458,6 +689,21 @@ +@@ -458,6 +691,21 @@ } else { ServerChunkCache chunkproviderserver = world.getChunkSource(); ChunkPos chunkcoordintpair = new ChunkPos(chunkproviderserver.randomState().sampler().findSpawnPosition()); @@ -529,7 +531,7 @@ int i = chunkproviderserver.getGenerator().getSpawnHeight(world); if (i < world.getMinY()) { -@@ -516,31 +762,36 @@ +@@ -516,31 +764,36 @@ iworlddataserver.setGameType(GameType.SPECTATOR); } @@ -577,7 +579,7 @@ ForcedChunksSavedData forcedchunk = (ForcedChunksSavedData) worldserver1.getDataStorage().get(ForcedChunksSavedData.factory(), "chunks"); if (forcedchunk != null) { -@@ -555,10 +806,17 @@ +@@ -555,10 +808,17 @@ } } @@ -599,7 +601,7 @@ } public GameType getDefaultGameType() { -@@ -588,12 +846,16 @@ +@@ -588,12 +848,16 @@ worldserver.save((ProgressListener) null, flush, worldserver.noSave && !force); } @@ -618,10 +620,11 @@ if (flush) { Iterator iterator1 = this.getAllLevels().iterator(); -@@ -627,19 +889,41 @@ +@@ -626,20 +890,42 @@ + @Override public void close() { this.stopServer(); - } ++ } + + // CraftBukkit start + private boolean hasStopped = false; @@ -630,7 +633,7 @@ + synchronized (this.stopLock) { + return this.hasStopped; + } -+ } + } + // CraftBukkit end public void stopServer() { @@ -660,7 +663,7 @@ } MinecraftServer.LOGGER.info("Saving worlds"); -@@ -727,7 +1011,7 @@ +@@ -727,7 +1013,7 @@ } this.nextTickTimeNanos = Util.getNanos(); @@ -669,7 +672,7 @@ this.status = this.buildServerStatus(); while (this.running) { -@@ -744,6 +1028,7 @@ +@@ -744,6 +1030,7 @@ if (j > MinecraftServer.OVERLOADED_THRESHOLD_NANOS + 20L * i && this.nextTickTimeNanos - this.lastOverloadWarningNanos >= MinecraftServer.OVERLOADED_WARNING_INTERVAL_NANOS + 100L * i) { long k = j / i; @@ -677,7 +680,7 @@ MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", j / TimeUtil.NANOSECONDS_PER_MILLISECOND, k); this.nextTickTimeNanos += k * i; this.lastOverloadWarningNanos = this.nextTickTimeNanos; -@@ -757,6 +1042,7 @@ +@@ -757,6 +1044,7 @@ this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount); } @@ -685,7 +688,7 @@ this.nextTickTimeNanos += i; try { -@@ -830,6 +1116,12 @@ +@@ -830,6 +1118,12 @@ this.services.profileCache().clearExecutor(); } @@ -698,7 +701,7 @@ this.onServerExit(); } -@@ -889,9 +1181,16 @@ +@@ -889,9 +1183,16 @@ } private boolean haveTime() { @@ -716,7 +719,7 @@ public static boolean throwIfFatalException() { RuntimeException runtimeexception = (RuntimeException) MinecraftServer.fatalException.get(); -@@ -903,7 +1202,7 @@ +@@ -903,7 +1204,7 @@ } public static void setFatalException(RuntimeException exception) { @@ -725,7 +728,7 @@ } @Override -@@ -977,7 +1276,7 @@ +@@ -977,7 +1278,7 @@ } } @@ -734,7 +737,7 @@ Profiler.get().incrementCounter("runTask"); super.doRunTask(ticktask); } -@@ -1041,6 +1340,7 @@ +@@ -1041,11 +1342,13 @@ this.autoSave(); } @@ -742,7 +745,13 @@ this.tickConnection(); return; } -@@ -1055,7 +1355,7 @@ + } + ++ SpigotTimings.serverTickTimer.startTiming(); // Spigot + ++this.tickCount; + this.tickRateManager.tick(); + this.tickChildren(shouldKeepTicking); +@@ -1055,7 +1358,7 @@ } --this.ticksUntilAutosave; @@ -751,31 +760,52 @@ this.autoSave(); } -@@ -1074,7 +1374,7 @@ +@@ -1071,10 +1374,13 @@ + this.smoothedTickTimeMillis = this.smoothedTickTimeMillis * 0.8F + (float) k / (float) TimeUtil.NANOSECONDS_PER_MILLISECOND * 0.19999999F; + this.logTickMethodTime(i); + gameprofilerfiller.pop(); ++ SpigotTimings.serverTickTimer.stopTiming(); // Spigot ++ org.spigotmc.CustomTimingsHandler.tick(); // Spigot } private void autoSave() { - this.ticksUntilAutosave = this.computeNextAutosaveInterval(); + this.ticksUntilAutosave = this.autosavePeriod; // CraftBukkit ++ SpigotTimings.worldSaveTimer.startTiming(); // Spigot MinecraftServer.LOGGER.debug("Autosave started"); ProfilerFiller gameprofilerfiller = Profiler.get(); -@@ -1154,11 +1454,26 @@ +@@ -1082,6 +1388,7 @@ + this.saveEverything(true, false, false); + gameprofilerfiller.pop(); + MinecraftServer.LOGGER.debug("Autosave finished"); ++ SpigotTimings.worldSaveTimer.stopTiming(); // Spigot + } + + private void logTickMethodTime(long tickStartTime) { +@@ -1154,11 +1461,34 @@ this.getPlayerList().getPlayers().forEach((entityplayer) -> { entityplayer.connection.suspendFlushing(); }); ++ SpigotTimings.schedulerTimer.startTiming(); // Spigot + this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit ++ SpigotTimings.schedulerTimer.stopTiming(); // Spigot gameprofilerfiller.push("commandFunctions"); ++ SpigotTimings.commandFunctionsTimer.startTiming(); // Spigot this.getFunctions().tick(); ++ SpigotTimings.commandFunctionsTimer.stopTiming(); // Spigot gameprofilerfiller.popPush("levels"); Iterator iterator = this.getAllLevels().iterator(); + // CraftBukkit start + // Run tasks that are waiting on processing ++ SpigotTimings.processQueueTimer.startTiming(); // Spigot + while (!this.processQueue.isEmpty()) { + this.processQueue.remove().run(); + } ++ SpigotTimings.processQueueTimer.stopTiming(); // Spigot + ++ SpigotTimings.timeUpdateTimer.startTiming(); // Spigot + // Send time updates to everyone, it will get the right time from the world the player is in. + if (this.tickCount % 20 == 0) { + for (int i = 0; i < this.getPlayerList().players.size(); ++i) { @@ -783,11 +813,12 @@ + entityplayer.connection.send(new ClientboundSetTimePacket(entityplayer.level().getGameTime(), entityplayer.getPlayerTime(), entityplayer.serverLevel().getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); // Add support for per player time + } + } ++ SpigotTimings.timeUpdateTimer.stopTiming(); // Spigot + while (iterator.hasNext()) { ServerLevel worldserver = (ServerLevel) iterator.next(); -@@ -1167,11 +1482,13 @@ +@@ -1167,16 +1497,20 @@ return s + " " + String.valueOf(worldserver.dimension().location()); }); @@ -801,7 +832,39 @@ gameprofilerfiller.push("tick"); -@@ -1265,7 +1582,23 @@ + try { ++ worldserver.timings.doTick.startTiming(); // Spigot + worldserver.tick(shouldKeepTicking); ++ worldserver.timings.doTick.stopTiming(); // Spigot + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world"); + +@@ -1189,18 +1523,24 @@ + } + + gameprofilerfiller.popPush("connection"); ++ SpigotTimings.connectionTimer.startTiming(); // Spigot + this.tickConnection(); ++ SpigotTimings.connectionTimer.stopTiming(); // Spigot + gameprofilerfiller.popPush("players"); ++ SpigotTimings.playerListTimer.startTiming(); // Spigot + this.playerList.tick(); ++ SpigotTimings.playerListTimer.stopTiming(); // Spigot + if (SharedConstants.IS_RUNNING_IN_IDE && this.tickRateManager.runsNormally()) { + GameTestTicker.SINGLETON.tick(); + } + + gameprofilerfiller.popPush("server gui refresh"); + ++ SpigotTimings.tickablesTimer.startTiming(); // Spigot + for (int i = 0; i < this.tickables.size(); ++i) { + ((Runnable) this.tickables.get(i)).run(); + } ++ SpigotTimings.tickablesTimer.stopTiming(); // Spigot + + gameprofilerfiller.popPush("send chunks"); + iterator = this.playerList.getPlayers().iterator(); +@@ -1265,7 +1605,23 @@ @Nullable public ServerLevel getLevel(ResourceKey<Level> key) { return (ServerLevel) this.levels.get(key); @@ -825,7 +888,7 @@ public Set<ResourceKey<Level>> levelKeys() { return this.levels.keySet(); -@@ -1296,7 +1629,7 @@ +@@ -1296,7 +1652,7 @@ @DontObfuscate public String getServerModName() { @@ -834,7 +897,7 @@ } public SystemReport fillSystemReport(SystemReport details) { -@@ -1634,11 +1967,11 @@ +@@ -1634,11 +1990,11 @@ public CompletableFuture<Void> reloadResources(Collection<String> dataPacks) { CompletableFuture<Void> completablefuture = CompletableFuture.supplyAsync(() -> { @@ -848,7 +911,7 @@ }, this).thenCompose((immutablelist) -> { MultiPackResourceManager resourcemanager = new MultiPackResourceManager(PackType.SERVER_DATA, immutablelist); List<Registry.PendingTags<?>> list = TagLoader.loadTagsForExistingRegistries(resourcemanager, this.registries.compositeAccess()); -@@ -1654,6 +1987,7 @@ +@@ -1654,6 +2010,7 @@ }).thenAcceptAsync((minecraftserver_reloadableresources) -> { this.resources.close(); this.resources = minecraftserver_reloadableresources; @@ -856,7 +919,7 @@ this.packRepository.setSelected(dataPacks); WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(MinecraftServer.getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()); -@@ -1952,7 +2286,7 @@ +@@ -1952,7 +2309,7 @@ final List<String> list = Lists.newArrayList(); final GameRules gamerules = this.getGameRules(); @@ -865,7 +928,7 @@ @Override public <T extends GameRules.Value<T>> void visit(GameRules.Key<T> key, GameRules.Type<T> type) { list.add(String.format(Locale.ROOT, "%s=%s\n", key.getId(), gamerules.getRule(key))); -@@ -2058,7 +2392,7 @@ +@@ -2058,7 +2415,7 @@ try { label51: { @@ -874,18 +937,15 @@ try { arraylist = Lists.newArrayList(NativeModuleLister.listModules()); -@@ -2105,8 +2439,24 @@ - if (bufferedwriter != null) { - bufferedwriter.close(); - } -+ -+ } -+ +@@ -2108,6 +2465,22 @@ + + } + + // CraftBukkit start + public boolean isDebugging() { + return false; + } - ++ + @Deprecated + public static MinecraftServer getServer() { + return (Bukkit.getServer() instanceof CraftServer) ? ((CraftServer) Bukkit.getServer()).getServer() : null; @@ -894,20 +954,21 @@ + @Deprecated + public static RegistryAccess getDefaultRegistryAccess() { + return CraftRegistry.getMinecraftRegistry(); - } ++ } + // CraftBukkit end - ++ private ProfilerFiller createProfiler() { if (this.willStartRecordingMetrics) { -@@ -2235,6 +2585,11 @@ + this.metricsRecorder = ActiveMetricsRecorder.createStarted(new ServerMetricsSamplersProvider(Util.timeSource, this.isDedicatedServer()), Util.timeSource, Util.ioPool(), new MetricsPersister("server"), this.onMetricsRecordingStopped, (path) -> { +@@ -2234,6 +2607,11 @@ + } } - ++ + // CraftBukkit start + public final java.util.concurrent.ExecutorService chatExecutor = java.util.concurrent.Executors.newCachedThreadPool( + new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setNameFormat("Async Chat Thread - #%d").build()); + // CraftBukkit end -+ + public ChatDecorator getChatDecorator() { return ChatDecorator.PLAIN; - } diff --git a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch index 898097da24..06c239d2bf 100644 --- a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -54,11 +54,22 @@ +@@ -54,11 +54,23 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.GameType; @@ -15,6 +15,7 @@ +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.io.IoBuilder; +import org.bukkit.command.CommandSender; ++import org.bukkit.craftbukkit.SpigotTimings; // Spigot +import org.bukkit.craftbukkit.util.TerminalCompletionHandler; +import org.bukkit.craftbukkit.util.TerminalConsoleWriterThread; +import org.bukkit.event.server.ServerCommandEvent; @@ -24,7 +25,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface { static final Logger LOGGER = LogUtils.getLogger(); -@@ -67,7 +78,7 @@ +@@ -67,7 +79,7 @@ private final List<ConsoleInput> consoleInput = Collections.synchronizedList(Lists.newArrayList()); @Nullable private QueryThreadGs4 queryThreadGs4; @@ -33,7 +34,7 @@ @Nullable private RconThread rconThread; public DedicatedServerSettings settings; -@@ -81,25 +92,58 @@ +@@ -81,25 +93,58 @@ private DebugSampleSubscriptionTracker debugSampleSubscriptionTracker; public ServerLinks serverLinks; @@ -101,7 +102,7 @@ } } catch (IOException ioexception) { DedicatedServer.LOGGER.error("Exception handling console input", ioexception); -@@ -108,6 +152,29 @@ +@@ -108,6 +153,29 @@ } }; @@ -131,7 +132,7 @@ thread.setDaemon(true); thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(DedicatedServer.LOGGER)); thread.start(); -@@ -126,13 +193,18 @@ +@@ -126,13 +194,18 @@ this.setPreventProxyConnections(dedicatedserverproperties.preventProxyConnections); this.setLocalIp(dedicatedserverproperties.serverIp); } @@ -151,7 +152,7 @@ DedicatedServer.LOGGER.info("Default game type: {}", dedicatedserverproperties.gamemode); InetAddress inetaddress = null; -@@ -156,6 +228,12 @@ +@@ -156,6 +229,12 @@ return false; } @@ -164,7 +165,7 @@ if (!this.usesAuthentication()) { DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); -@@ -170,7 +248,7 @@ +@@ -170,7 +249,7 @@ if (!OldUsersConverter.serverReadyAfterUserconversion(this)) { return false; } else { @@ -173,7 +174,7 @@ this.debugSampleSubscriptionTracker = new DebugSampleSubscriptionTracker(this.getPlayerList()); this.tickTimeLogger = new RemoteSampleLogger(TpsDebugDimensions.values().length, this.debugSampleSubscriptionTracker, RemoteDebugSampleType.TICK_TIME); long i = Util.getNanos(); -@@ -178,13 +256,13 @@ +@@ -178,13 +257,13 @@ SkullBlockEntity.setup(this.services, this); GameProfileCache.setUsesAuthentication(this.usesAuthentication()); DedicatedServer.LOGGER.info("Preparing level \"{}\"", this.getLevelIdName()); @@ -189,7 +190,7 @@ } if (dedicatedserverproperties.enableQuery) { -@@ -293,6 +371,7 @@ +@@ -293,6 +372,7 @@ this.queryThreadGs4.stop(); } @@ -197,7 +198,7 @@ } @Override -@@ -302,8 +381,8 @@ +@@ -302,8 +382,8 @@ } @Override @@ -208,7 +209,11 @@ } public void handleConsoleInput(String command, CommandSourceStack commandSource) { -@@ -314,7 +393,15 @@ +@@ -311,12 +391,22 @@ + } + + public void handleConsoleInputs() { ++ SpigotTimings.serverCommandTimer.startTiming(); // Spigot while (!this.consoleInput.isEmpty()) { ConsoleInput servercommand = (ConsoleInput) this.consoleInput.remove(0); @@ -224,8 +229,11 @@ + // CraftBukkit end } ++ SpigotTimings.serverCommandTimer.stopTiming(); // Spigot } -@@ -383,7 +470,7 @@ + + @Override +@@ -383,7 +473,7 @@ @Override public boolean isUnderSpawnProtection(ServerLevel world, BlockPos pos, Player player) { @@ -234,7 +242,7 @@ return false; } else if (this.getPlayerList().getOps().isEmpty()) { return false; -@@ -541,16 +628,52 @@ +@@ -541,16 +631,52 @@ @Override public String getPluginNames() { @@ -291,7 +299,7 @@ } public void storeUsingWhiteList(boolean useWhitelist) { -@@ -660,4 +783,15 @@ +@@ -660,4 +786,15 @@ } } } diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch index 93313a37c4..5a32f1769c 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch @@ -17,7 +17,7 @@ @Override public ThreadedLevelLightEngine getLightEngine() { return this.lightEngine; -@@ -138,7 +148,7 @@ +@@ -138,20 +148,22 @@ if (k == this.lastChunkPos[l] && leastStatus == this.lastChunkStatus[l]) { ChunkAccess ichunkaccess = this.lastChunk[l]; @@ -26,16 +26,23 @@ return ichunkaccess; } } -@@ -151,7 +161,7 @@ + } + + gameprofilerfiller.incrementCounter("getChunkCacheMiss"); ++ this.level.timings.syncChunkLoadTimer.startTiming(); // Spigot + CompletableFuture<ChunkResult<ChunkAccess>> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create); + ServerChunkCache.MainThreadExecutor chunkproviderserver_b = this.mainThreadProcessor; + Objects.requireNonNull(completablefuture); chunkproviderserver_b.managedBlock(completablefuture::isDone); ++ this.level.timings.syncChunkLoadTimer.stopTiming(); // Spigot ChunkResult<ChunkAccess> chunkresult = (ChunkResult) completablefuture.join(); - ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse((Object) null); + ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error if (ichunkaccess1 == null && create) { throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("Chunk not there when requested: " + chunkresult.getError())); -@@ -231,7 +241,15 @@ +@@ -231,7 +243,15 @@ int l = ChunkLevel.byStatus(leastStatus); ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k); @@ -52,7 +59,7 @@ this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair); if (this.chunkAbsent(playerchunk, l)) { ProfilerFiller gameprofilerfiller = Profiler.get(); -@@ -250,7 +268,7 @@ +@@ -250,7 +270,7 @@ } private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) { @@ -61,7 +68,7 @@ } @Override -@@ -309,11 +327,33 @@ +@@ -309,30 +329,58 @@ @Override public void close() throws IOException { @@ -96,7 +103,32 @@ @Override public void tick(BooleanSupplier shouldKeepTicking, boolean tickChunks) { -@@ -401,14 +441,14 @@ + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("purge"); ++ this.level.timings.doChunkMap.startTiming(); // Spigot + if (this.level.tickRateManager().runsNormally() || !tickChunks) { + this.distanceManager.purgeStaleTickets(); + } + + this.runDistanceManagerUpdates(); ++ this.level.timings.doChunkMap.stopTiming(); // Spigot + gameprofilerfiller.popPush("chunks"); + if (tickChunks) { + this.tickChunks(); ++ this.level.timings.tracker.startTiming(); // Spigot + this.chunkMap.tick(); ++ this.level.timings.tracker.stopTiming(); // Spigot + } + ++ this.level.timings.doChunkUnload.startTiming(); // Spigot + gameprofilerfiller.popPush("unload"); + this.chunkMap.tick(shouldKeepTicking); ++ this.level.timings.doChunkUnload.stopTiming(); // Spigot + gameprofilerfiller.pop(); + this.clearCache(); + } +@@ -401,14 +449,14 @@ this.lastSpawnState = spawnercreature_d; profiler.popPush("spawnAndTick"); @@ -114,7 +146,17 @@ } else { list1 = List.of(); } -@@ -541,10 +581,16 @@ +@@ -425,7 +473,9 @@ + } + + if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { ++ this.level.timings.doTickTiles.startTiming(); // Spigot + this.level.tickChunk(chunk, k); ++ this.level.timings.doTickTiles.stopTiming(); // Spigot + } + } + +@@ -541,10 +591,16 @@ @Override public void setSpawnSettings(boolean spawnMonsters) { @@ -133,7 +175,7 @@ public String getChunkDebugData(ChunkPos pos) { return this.chunkMap.getChunkDebugData(pos); } -@@ -618,14 +664,20 @@ +@@ -618,14 +674,20 @@ } @Override diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch index 9c1ebc7dd1..a6b71ce601 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch @@ -35,12 +35,13 @@ import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.BooleanOp; -@@ -173,6 +175,16 @@ +@@ -173,6 +175,17 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.ticks.LevelTicks; import org.slf4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.WeatherType; ++import org.bukkit.craftbukkit.SpigotTimings; // Spigot +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.craftbukkit.generator.CustomWorldChunkManager; +import org.bukkit.craftbukkit.util.WorldUUID; @@ -52,7 +53,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLevel { -@@ -187,7 +199,7 @@ +@@ -187,7 +200,7 @@ final List<ServerPlayer> players = Lists.newArrayList(); public final ServerChunkCache chunkSource; private final MinecraftServer server; @@ -61,7 +62,7 @@ private int lastSpawnChunkRadius; final EntityTickList entityTickList = new EntityTickList(); public final PersistentEntitySectionManager<Entity> entityManager; -@@ -214,52 +226,87 @@ +@@ -214,52 +227,87 @@ private final boolean tickTime; private final RandomSequences randomSequences; @@ -78,7 +79,7 @@ + // CraftBukkit start + public final LevelStorageSource.LevelStorageAccess convertable; + public final UUID uuid; - ++ + public LevelChunk getChunkIfLoaded(int x, int z) { + return this.chunkSource.getChunk(x, z, false); + } @@ -102,7 +103,7 @@ + ChunkGenerator chunkgenerator = worlddimension.generator(); + // CraftBukkit start + this.serverLevelData.setWorld(this); -+ + + if (biomeProvider != null) { + BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME)); + if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) { @@ -173,17 +174,16 @@ } /** @deprecated */ -@@ -305,12 +352,20 @@ +@@ -305,12 +353,20 @@ long j; if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) { -- if (this.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { -- j = this.levelData.getDayTime() + 24000L; -- this.setDayTime(j - j % 24000L); + // CraftBukkit start + j = this.levelData.getDayTime() + 24000L; + TimeSkipEvent event = new TimeSkipEvent(this.getWorld(), TimeSkipEvent.SkipReason.NIGHT_SKIP, (j - j % 24000L) - this.getDayTime()); -+ if (this.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { + if (this.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { +- j = this.levelData.getDayTime() + 24000L; +- this.setDayTime(j - j % 24000L); + this.getCraftServer().getPluginManager().callEvent(event); + if (!event.isCancelled()) { + this.setDayTime(this.getDayTime() + event.getSkipAmount()); @@ -198,7 +198,30 @@ if (this.getGameRules().getBoolean(GameRules.RULE_WEATHER_CYCLE) && this.isRaining()) { this.resetWeatherCycle(); } -@@ -345,7 +400,7 @@ +@@ -322,6 +378,7 @@ + } + + gameprofilerfiller.push("tickPending"); ++ this.timings.doTickPending.startTiming(); // Spigot + if (!this.isDebug() && flag) { + j = this.getGameTime(); + gameprofilerfiller.push("blockTicks"); +@@ -330,6 +387,7 @@ + this.fluidTicks.tick(j, 65536, this::tickFluid); + gameprofilerfiller.pop(); + } ++ this.timings.doTickPending.stopTiming(); // Spigot + + gameprofilerfiller.popPush("raid"); + if (flag) { +@@ -340,12 +398,14 @@ + this.getChunkSource().tick(shouldKeepTicking, true); + gameprofilerfiller.popPush("blockEvents"); + if (flag) { ++ this.timings.doSounds.startTiming(); // Spigot + this.runBlockEvents(); ++ this.timings.doSounds.stopTiming(); // Spigot + } this.handlingTick = false; gameprofilerfiller.pop(); @@ -207,7 +230,31 @@ if (flag1) { this.resetEmptyTime(); -@@ -429,7 +484,7 @@ +@@ -353,12 +413,14 @@ + + if (flag1 || this.emptyTime++ < 300) { + gameprofilerfiller.push("entities"); ++ this.timings.tickEntities.startTiming(); // Spigot + if (this.dragonFight != null && flag) { + gameprofilerfiller.push("dragonFight"); + this.dragonFight.tick(); + gameprofilerfiller.pop(); + } + ++ this.timings.entityTick.startTiming(); // Spigot + this.entityTickList.forEach((entity) -> { + if (!entity.isRemoved()) { + if (!tickratemanager.isEntityFrozen(entity)) { +@@ -383,6 +445,8 @@ + } + } + }); ++ this.timings.entityTick.stopTiming(); // Spigot ++ this.timings.tickEntities.stopTiming(); // Spigot + gameprofilerfiller.pop(); + this.tickBlockEntities(); + } +@@ -429,7 +493,7 @@ private void wakeUpAllPlayers() { this.sleepStatus.removeAllSleepers(); @@ -216,7 +263,7 @@ entityplayer.stopSleepInBed(false, false); }); } -@@ -456,7 +511,7 @@ +@@ -456,7 +520,7 @@ entityhorseskeleton.setTrap(true); entityhorseskeleton.setAge(0); entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ()); @@ -225,7 +272,7 @@ } } -@@ -465,7 +520,7 @@ +@@ -465,7 +529,7 @@ if (entitylightning != null) { entitylightning.moveTo(Vec3.atBottomCenterOf(blockposition)); entitylightning.setVisualOnly(flag1); @@ -234,7 +281,7 @@ } } } -@@ -521,7 +576,7 @@ +@@ -521,7 +585,7 @@ Biome biomebase = (Biome) this.getBiome(blockposition1).value(); if (biomebase.shouldFreeze(this, blockposition2)) { @@ -243,7 +290,7 @@ } if (this.isRaining()) { -@@ -537,10 +592,10 @@ +@@ -537,10 +601,10 @@ BlockState iblockdata1 = (BlockState) iblockdata.setValue(SnowLayerBlock.LAYERS, j + 1); Block.pushEntitiesUp(iblockdata, iblockdata1, this, blockposition1); @@ -256,7 +303,7 @@ } } -@@ -701,33 +756,67 @@ +@@ -701,33 +765,67 @@ this.rainLevel = Mth.clamp(this.rainLevel, 0.0F, 1.0F); } @@ -290,8 +337,8 @@ + if (((ServerPlayer) this.players.get(idx)).level() == this) { + ((ServerPlayer) this.players.get(idx)).tickWeather(); + } -+ } -+ + } + + if (flag != this.isRaining()) { + // Only send weather packets to those affected + for (int idx = 0; idx < this.players.size(); ++idx) { @@ -299,14 +346,14 @@ + ((ServerPlayer) this.players.get(idx)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false); + } + } - } ++ } + for (int idx = 0; idx < this.players.size(); ++idx) { + if (((ServerPlayer) this.players.get(idx)).level() == this) { + ((ServerPlayer) this.players.get(idx)).updateWeather(this.oRainLevel, this.rainLevel, this.oThunderLevel, this.thunderLevel); + } + } + // CraftBukkit end - ++ } @VisibleForTesting @@ -332,7 +379,15 @@ } public void resetEmptyTime() { -@@ -763,6 +852,7 @@ +@@ -754,6 +852,7 @@ + } + + public void tickNonPassenger(Entity entity) { ++ entity.tickTimer.startTiming(); // Spigot + entity.setOldPosAndRot(); + ProfilerFiller gameprofilerfiller = Profiler.get(); + +@@ -763,6 +862,7 @@ }); gameprofilerfiller.incrementCounter("tickNonPassenger"); entity.tick(); @@ -340,7 +395,15 @@ gameprofilerfiller.pop(); Iterator iterator = entity.getPassengers().iterator(); -@@ -786,6 +876,7 @@ +@@ -771,6 +871,7 @@ + + this.tickPassenger(entity, entity1); + } ++ entity.tickTimer.stopTiming(); // Spigot + + } + +@@ -786,6 +887,7 @@ }); gameprofilerfiller.incrementCounter("tickPassenger"); passenger.rideTick(); @@ -348,7 +411,7 @@ gameprofilerfiller.pop(); Iterator iterator = passenger.getPassengers().iterator(); -@@ -810,6 +901,7 @@ +@@ -810,6 +912,7 @@ ServerChunkCache chunkproviderserver = this.getChunkSource(); if (!savingDisabled) { @@ -356,7 +419,7 @@ if (progressListener != null) { progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel")); } -@@ -827,11 +919,19 @@ +@@ -827,11 +930,19 @@ } } @@ -377,7 +440,7 @@ } DimensionDataStorage worldpersistentdata = this.getChunkSource().getDataStorage(); -@@ -903,18 +1003,40 @@ +@@ -903,18 +1014,40 @@ @Override public boolean addFreshEntity(Entity entity) { @@ -421,7 +484,7 @@ } } -@@ -939,24 +1061,38 @@ +@@ -939,24 +1072,38 @@ this.entityManager.addNewEntity(player); } @@ -464,7 +527,7 @@ return true; } } -@@ -967,13 +1103,35 @@ +@@ -967,13 +1114,35 @@ } public void removePlayerImmediately(ServerPlayer player, Entity.RemovalReason reason) { @@ -501,7 +564,7 @@ while (iterator.hasNext()) { ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -@@ -982,6 +1140,12 @@ +@@ -982,6 +1151,12 @@ double d1 = (double) pos.getY() - entityplayer.getY(); double d2 = (double) pos.getZ() - entityplayer.getZ(); @@ -514,7 +577,7 @@ if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) { entityplayer.connection.send(new ClientboundBlockDestructionPacket(entityId, pos, progress)); } -@@ -1060,7 +1224,18 @@ +@@ -1060,7 +1235,18 @@ Iterator iterator = this.navigatingMobs.iterator(); while (iterator.hasNext()) { @@ -534,7 +597,7 @@ PathNavigation navigationabstract = entityinsentient.getNavigation(); if (navigationabstract.shouldRecomputePath(pos)) { -@@ -1126,9 +1301,15 @@ +@@ -1126,9 +1312,15 @@ @Override public void explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions smallParticle, ParticleOptions largeParticle, Holder<SoundEvent> soundEvent) { @@ -551,7 +614,7 @@ case NONE: explosion_effect = Explosion.BlockInteraction.KEEP; break; -@@ -1144,16 +1325,26 @@ +@@ -1144,16 +1336,26 @@ case TRIGGER: explosion_effect = Explosion.BlockInteraction.TRIGGER_BLOCK; break; @@ -581,7 +644,7 @@ Iterator iterator = this.players.iterator(); while (iterator.hasNext()) { -@@ -1162,10 +1353,11 @@ +@@ -1162,10 +1364,11 @@ if (entityplayer.distanceToSqr(vec3d) < 4096.0D) { Optional<Vec3> optional = Optional.ofNullable((Vec3) serverexplosion.getHitPlayers().get(entityplayer)); @@ -594,7 +657,7 @@ } private Explosion.BlockInteraction getDestroyType(GameRules.Key<GameRules.BooleanValue> decayRule) { -@@ -1226,17 +1418,24 @@ +@@ -1226,17 +1429,24 @@ } public <T extends ParticleOptions> int sendParticles(T parameters, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double speed) { @@ -622,7 +685,7 @@ ++j; } } -@@ -1292,7 +1491,7 @@ +@@ -1292,7 +1502,7 @@ @Nullable public BlockPos findNearestMapStructure(TagKey<Structure> structureTag, BlockPos pos, int radius, boolean skipReferencedStructures) { @@ -631,7 +694,7 @@ return null; } else { Optional<HolderSet.Named<Structure>> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag); -@@ -1334,11 +1533,22 @@ +@@ -1334,11 +1544,22 @@ @Nullable @Override public MapItemSavedData getMapData(MapId id) { @@ -655,7 +718,7 @@ this.getServer().overworld().getDataStorage().set(id.key(), state); } -@@ -1649,6 +1859,11 @@ +@@ -1649,6 +1870,11 @@ @Override public void blockUpdated(BlockPos pos, Block block) { if (!this.isDebug()) { @@ -667,7 +730,7 @@ this.updateNeighborsAt(pos, block); } -@@ -1668,12 +1883,12 @@ +@@ -1668,12 +1894,12 @@ } public boolean isFlat() { @@ -682,7 +745,7 @@ } @Nullable -@@ -1696,7 +1911,7 @@ +@@ -1696,7 +1922,7 @@ private static <T> String getTypeCount(Iterable<T> items, Function<T, String> classifier) { try { Object2IntOpenHashMap<String> object2intopenhashmap = new Object2IntOpenHashMap(); @@ -691,7 +754,7 @@ while (iterator.hasNext()) { T t0 = iterator.next(); -@@ -1705,7 +1920,7 @@ +@@ -1705,7 +1931,7 @@ object2intopenhashmap.addTo(s, 1); } @@ -700,7 +763,7 @@ String s1 = (String) entry.getKey(); return s1 + ":" + entry.getIntValue(); -@@ -1717,6 +1932,7 @@ +@@ -1717,6 +1943,7 @@ @Override public LevelEntityGetter<Entity> getEntities() { @@ -708,7 +771,7 @@ return this.entityManager.getEntityGetter(); } -@@ -1836,6 +2052,7 @@ +@@ -1836,6 +2063,7 @@ } public void onTrackingStart(Entity entity) { @@ -716,7 +779,7 @@ ServerLevel.this.getChunkSource().addEntity(entity); if (entity instanceof ServerPlayer entityplayer) { ServerLevel.this.players.add(entityplayer); -@@ -1864,9 +2081,12 @@ +@@ -1864,9 +2092,12 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::add); @@ -729,7 +792,7 @@ ServerLevel.this.getChunkSource().removeEntity(entity); if (entity instanceof ServerPlayer entityplayer) { ServerLevel.this.players.remove(entityplayer); -@@ -1895,6 +2115,14 @@ +@@ -1895,6 +2126,14 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::remove); diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index d7239d1eaf..59937f4b68 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -120,7 +120,7 @@ this.chunkSender = new PlayerChunkSender(connection.isMemoryConnection()); this.player = player; player.connection = this; -@@ -256,9 +317,25 @@ +@@ -256,11 +317,28 @@ Objects.requireNonNull(server); this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(uuid, server::enforceSecureProfile); @@ -146,16 +146,22 @@ + @Override public void tick() { ++ org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.startTiming(); // Spigot if (this.ackBlockChangesUpTo > -1) { -@@ -313,6 +390,7 @@ + this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); + this.ackBlockChangesUpTo = -1; +@@ -313,8 +391,10 @@ this.chatSpamThrottler.tick(); this.dropSpamThrottler.tick(); if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L) { + this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling")); } ++ org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.stopTiming(); // Spigot -@@ -376,6 +454,12 @@ + } + +@@ -376,6 +456,12 @@ @Override public void handlePlayerInput(ServerboundPlayerInputPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -168,7 +174,7 @@ this.player.setLastClientInput(packet.input()); } -@@ -401,6 +485,13 @@ +@@ -401,6 +487,13 @@ if (entity != this.player && entity.getControllingPassenger() == this.player && entity == this.lastVehicle) { ServerLevel worldserver = this.player.serverLevel(); @@ -182,7 +188,7 @@ double d0 = entity.getX(); double d1 = entity.getY(); double d2 = entity.getZ(); -@@ -415,7 +506,33 @@ +@@ -415,7 +508,33 @@ double d9 = entity.getDeltaMovement().lengthSqr(); double d10 = d6 * d6 + d7 * d7 + d8 * d8; @@ -217,7 +223,7 @@ ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", new Object[]{entity.getName().getString(), this.player.getName().getString(), d6, d7, d8}); this.send(ClientboundMoveVehiclePacket.fromEntity(entity)); return; -@@ -455,13 +572,66 @@ +@@ -455,14 +574,67 @@ } entity.absMoveTo(d3, d4, d5, f, f1); @@ -229,8 +235,8 @@ + this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit this.send(ClientboundMoveVehiclePacket.fromEntity(entity)); return; -+ } -+ + } + + // CraftBukkit start - fire PlayerMoveEvent + Player player = this.getCraftPlayer(); + if (!this.hasMoved) { @@ -279,12 +285,13 @@ + this.justTeleported = false; + return; + } - } ++ } + // CraftBukkit end - ++ this.player.serverLevel().getChunkSource().move(this.player); entity.recordMovementThroughBlocks(new Vec3(d0, d1, d2), entity.position()); -@@ -499,6 +669,7 @@ + Vec3 vec3d = new Vec3(entity.getX() - d0, entity.getY() - d1, entity.getZ() - d2); +@@ -499,6 +671,7 @@ this.lastGoodZ = this.awaitingPositionFromClient.z; this.player.hasChangedDimension(); this.awaitingPositionFromClient = null; @@ -292,7 +299,7 @@ } } -@@ -528,6 +699,7 @@ +@@ -528,6 +701,7 @@ @Override public void handleRecipeBookChangeSettingsPacket(ServerboundRecipeBookChangeSettingsPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -300,7 +307,7 @@ this.player.getRecipeBook().setBookSetting(packet.getBookType(), packet.isOpen(), packet.isFiltering()); } -@@ -548,6 +720,12 @@ +@@ -548,6 +722,12 @@ @Override public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -313,7 +320,7 @@ StringReader stringreader = new StringReader(packet.getCommand()); if (stringreader.canRead() && stringreader.peek() == '/') { -@@ -557,6 +735,7 @@ +@@ -557,6 +737,7 @@ ParseResults<CommandSourceStack> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { @@ -321,7 +328,7 @@ Suggestions suggestions1 = suggestions.getList().size() <= 1000 ? suggestions : new Suggestions(suggestions.getRange(), suggestions.getList().subList(0, 1000)); this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions1)); -@@ -866,6 +1045,13 @@ +@@ -866,6 +1047,13 @@ AbstractContainerMenu container = this.player.containerMenu; if (container instanceof MerchantMenu containermerchant) { @@ -335,7 +342,7 @@ if (!containermerchant.stillValid(this.player)) { ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, containermerchant); return; -@@ -879,6 +1065,13 @@ +@@ -879,6 +1067,13 @@ @Override public void handleEditBook(ServerboundEditBookPacket packet) { @@ -349,7 +356,7 @@ int i = packet.slot(); if (Inventory.isHotbarSlot(i) || i == 40) { -@@ -899,12 +1092,16 @@ +@@ -899,12 +1094,16 @@ } private void updateBookContents(List<FilteredText> pages, int slotId) { @@ -367,7 +374,7 @@ } } -@@ -915,12 +1112,13 @@ +@@ -915,12 +1114,13 @@ ItemStack itemstack1 = itemstack.transmuteCopy(Items.WRITTEN_BOOK); itemstack1.remove(DataComponents.WRITABLE_BOOK_CONTENT); @@ -383,7 +390,7 @@ } } -@@ -982,7 +1180,7 @@ +@@ -982,7 +1182,7 @@ } else { ServerLevel worldserver = this.player.serverLevel(); @@ -392,7 +399,7 @@ if (this.tickCount == 0) { this.resetPosition(); } -@@ -997,7 +1195,15 @@ +@@ -997,7 +1197,15 @@ if (this.player.isPassenger()) { this.player.absMoveTo(this.player.getX(), this.player.getY(), this.player.getZ(), f, f1); this.player.serverLevel().getChunkSource().move(this.player); @@ -408,7 +415,7 @@ double d3 = this.player.getX(); double d4 = this.player.getY(); double d5 = this.player.getZ(); -@@ -1019,15 +1225,33 @@ +@@ -1019,15 +1227,33 @@ ++this.receivedMovePacketCount; int i = this.receivedMovePacketCount - this.knownMovePacketCount; @@ -444,7 +451,7 @@ ServerGamePacketListenerImpl.LOGGER.warn("{} moved too quickly! {},{},{}", new Object[]{this.player.getName().getString(), d6, d7, d8}); this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot()); return; -@@ -1049,6 +1273,7 @@ +@@ -1049,6 +1275,7 @@ boolean flag2 = this.player.verticalCollisionBelow; this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8)); @@ -452,7 +459,7 @@ double d11 = d7; d6 = d0 - this.player.getX(); -@@ -1067,9 +1292,75 @@ +@@ -1067,9 +1294,75 @@ } if (!this.player.noPhysics && !this.player.isSleeping() && (flag3 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2))) { @@ -529,7 +536,7 @@ this.player.absMoveTo(d0, d1, d2, f, f1); boolean flag4 = this.player.isAutoSpinAttack(); -@@ -1119,6 +1410,7 @@ +@@ -1119,6 +1412,7 @@ this.awaitingTeleportTime = this.tickCount; this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); } @@ -537,7 +544,7 @@ return true; } else { -@@ -1147,23 +1439,83 @@ +@@ -1147,23 +1441,83 @@ } public void teleport(double x, double y, double z, float yaw, float pitch) { @@ -624,7 +631,7 @@ if (this.player.hasClientLoaded()) { BlockPos blockposition = packet.getPos(); -@@ -1175,14 +1527,46 @@ +@@ -1175,14 +1529,46 @@ if (!this.player.isSpectator()) { ItemStack itemstack = this.player.getItemInHand(InteractionHand.OFF_HAND); @@ -673,7 +680,7 @@ this.player.drop(false); } -@@ -1221,6 +1605,7 @@ +@@ -1221,6 +1607,7 @@ @Override public void handleUseItemOn(ServerboundUseItemOnPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -681,7 +688,7 @@ if (this.player.hasClientLoaded()) { this.player.connection.ackBlockChangesUpTo(packet.getSequence()); ServerLevel worldserver = this.player.serverLevel(); -@@ -1244,6 +1629,7 @@ +@@ -1244,6 +1631,7 @@ if (blockposition.getY() <= i) { if (this.awaitingPositionFromClient == null && worldserver.mayInteract(this.player, blockposition)) { @@ -689,7 +696,7 @@ InteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock); if (enuminteractionresult.consumesAction()) { -@@ -1281,6 +1667,7 @@ +@@ -1281,6 +1669,7 @@ @Override public void handleUseItem(ServerboundUseItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -697,7 +704,7 @@ if (this.player.hasClientLoaded()) { this.ackBlockChangesUpTo(packet.getSequence()); ServerLevel worldserver = this.player.serverLevel(); -@@ -1296,6 +1683,47 @@ +@@ -1296,6 +1685,47 @@ this.player.absRotateTo(f, f1); } @@ -745,7 +752,7 @@ InteractionResult enuminteractionresult = this.player.gameMode.useItem(this.player, worldserver, itemstack, enumhand); if (enuminteractionresult instanceof InteractionResult.Success) { -@@ -1321,7 +1749,7 @@ +@@ -1321,7 +1751,7 @@ Entity entity = packet.getEntity(worldserver); if (entity != null) { @@ -754,7 +761,7 @@ return; } } -@@ -1342,6 +1770,13 @@ +@@ -1342,6 +1772,13 @@ @Override public void onDisconnect(DisconnectionDetails info) { @@ -768,7 +775,7 @@ ServerGamePacketListenerImpl.LOGGER.info("{} lost connection: {}", this.player.getName().getString(), info.reason().getString()); this.removePlayerFromWorld(); super.onDisconnect(info); -@@ -1349,10 +1784,18 @@ +@@ -1349,10 +1786,18 @@ private void removePlayerFromWorld() { this.chatMessageChain.close(); @@ -789,7 +796,7 @@ this.player.getTextFilter().leave(); } -@@ -1367,7 +1810,16 @@ +@@ -1367,7 +1812,16 @@ @Override public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -806,7 +813,7 @@ if (this.player.getInventory().selected != packet.getSlot() && this.player.getUsedItemHand() == InteractionHand.MAIN_HAND) { this.player.stopUsingItem(); } -@@ -1376,11 +1828,18 @@ +@@ -1376,11 +1830,18 @@ this.player.resetLastActionTime(); } else { ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString()); @@ -825,7 +832,7 @@ Optional<LastSeenMessages> optional = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); if (!optional.isEmpty()) { -@@ -1394,7 +1853,7 @@ +@@ -1394,7 +1855,7 @@ return; } @@ -834,7 +841,7 @@ Component ichatbasecomponent = this.server.getChatDecorator().decorate(this.player, playerchatmessage.decoratedContent()); this.chatMessageChain.append(completablefuture, (filteredtext) -> { -@@ -1402,19 +1861,36 @@ +@@ -1402,19 +1863,36 @@ this.broadcastChatMessage(playerchatmessage1); }); @@ -873,7 +880,7 @@ ParseResults<CommandSourceStack> parseresults = this.parseCommand(command); if (this.server.enforceSecureProfile() && SignableCommand.hasSignableArguments(parseresults)) { -@@ -1431,19 +1907,37 @@ +@@ -1431,19 +1909,37 @@ if (!optional.isEmpty()) { this.tryHandleChat(packet.command(), () -> { @@ -914,7 +921,7 @@ } catch (SignedMessageChain.DecodeException signedmessagechain_a) { this.handleMessageDecodeFailure(signedmessagechain_a); return; -@@ -1451,10 +1945,10 @@ +@@ -1451,10 +1947,10 @@ CommandSigningContext.SignedArguments commandsigningcontext_a = new CommandSigningContext.SignedArguments(map); @@ -927,7 +934,7 @@ } private void handleMessageDecodeFailure(SignedMessageChain.DecodeException exception) { -@@ -1530,14 +2024,20 @@ +@@ -1530,14 +2026,20 @@ return com_mojang_brigadier_commanddispatcher.parse(command, this.player.createCommandSourceStack()); } @@ -952,7 +959,7 @@ } } -@@ -1564,8 +2064,118 @@ +@@ -1564,8 +2066,122 @@ } return false; @@ -1045,6 +1052,7 @@ } + private void handleCommand(String s) { ++ org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.startTiming(); // Spigot + this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); + + CraftPlayer player = this.getCraftPlayer(); @@ -1053,6 +1061,7 @@ + this.cserver.getPluginManager().callEvent(event); + + if (event.isCancelled()) { ++ org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot + return; + } + @@ -1064,6 +1073,8 @@ + player.sendMessage(org.bukkit.ChatColor.RED + "An internal error occurred while attempting to perform this command"); + java.util.logging.Logger.getLogger(ServerGamePacketListenerImpl.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + return; ++ } finally { ++ org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot + } + } + // CraftBukkit end @@ -1071,7 +1082,7 @@ private PlayerChatMessage getSignedMessage(ServerboundChatPacket packet, LastSeenMessages lastSeenMessages) throws SignedMessageChain.DecodeException { SignedMessageBody signedmessagebody = new SignedMessageBody(packet.message(), packet.timeStamp(), packet.salt(), lastSeenMessages); -@@ -1573,13 +2183,33 @@ +@@ -1573,13 +2189,33 @@ } private void broadcastChatMessage(PlayerChatMessage message) { @@ -1108,7 +1119,7 @@ this.disconnect((Component) Component.translatable("disconnect.spam")); } -@@ -1601,7 +2231,33 @@ +@@ -1601,7 +2237,33 @@ @Override public void handleAnimate(ServerboundSwingPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1142,7 +1153,7 @@ this.player.swing(packet.getHand()); } -@@ -1609,6 +2265,29 @@ +@@ -1609,6 +2271,29 @@ public void handlePlayerCommand(ServerboundPlayerCommandPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); if (this.player.hasClientLoaded()) { @@ -1172,7 +1183,7 @@ this.player.resetLastActionTime(); Entity entity; PlayerRideableJumping ijumpable; -@@ -1691,6 +2370,12 @@ +@@ -1691,6 +2376,12 @@ } public void sendPlayerChatMessage(PlayerChatMessage message, ChatType.Bound params) { @@ -1185,7 +1196,7 @@ this.send(new ClientboundPlayerChatPacket(message.link().sender(), message.link().index(), message.signature(), message.signedBody().pack(this.messageSignatureCache), message.unsignedContent(), message.filterMask(), params)); this.addPendingMessage(message); } -@@ -1718,6 +2403,7 @@ +@@ -1718,6 +2409,7 @@ @Override public void handleInteract(ServerboundInteractPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1193,7 +1204,7 @@ if (this.player.hasClientLoaded()) { final ServerLevel worldserver = this.player.serverLevel(); final Entity entity = packet.getTarget(worldserver); -@@ -1733,20 +2419,58 @@ +@@ -1733,20 +2425,58 @@ if (this.player.canInteractWithEntity(axisalignedbb, 3.0D)) { packet.dispatch(new ServerboundInteractPacket.Handler() { @@ -1256,7 +1267,7 @@ } } -@@ -1755,19 +2479,20 @@ +@@ -1755,19 +2485,20 @@ @Override public void onInteraction(InteractionHand hand) { @@ -1280,7 +1291,7 @@ label23: { if (entity instanceof AbstractArrow) { -@@ -1785,6 +2510,11 @@ +@@ -1785,6 +2516,11 @@ } ServerGamePacketListenerImpl.this.player.attack(entity); @@ -1292,7 +1303,7 @@ return; } } -@@ -1809,7 +2539,7 @@ +@@ -1809,7 +2545,7 @@ case PERFORM_RESPAWN: if (this.player.wonGame) { this.player.wonGame = false; @@ -1301,7 +1312,7 @@ this.resetPosition(); CriteriaTriggers.CHANGED_DIMENSION.trigger(this.player, Level.END, Level.OVERWORLD); } else { -@@ -1817,11 +2547,11 @@ +@@ -1817,11 +2553,11 @@ return; } @@ -1315,7 +1326,7 @@ } } break; -@@ -1834,15 +2564,21 @@ +@@ -1834,15 +2570,21 @@ @Override public void handleContainerClose(ServerboundContainerClosePacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1339,7 +1350,7 @@ this.player.containerMenu.sendAllDataToRemote(); } else if (!this.player.containerMenu.stillValid(this.player)) { ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu); -@@ -1855,7 +2591,284 @@ +@@ -1855,7 +2597,284 @@ boolean flag = packet.getStateId() != this.player.containerMenu.getStateId(); this.player.containerMenu.suppressRemoteUpdates(); @@ -1625,7 +1636,7 @@ ObjectIterator objectiterator = Int2ObjectMaps.fastIterable(packet.getChangedSlots()).iterator(); while (objectiterator.hasNext()) { -@@ -1901,8 +2914,22 @@ +@@ -1901,8 +2920,22 @@ return; } @@ -1649,7 +1660,7 @@ if (containerrecipebook_a == RecipeBookMenu.PostPlaceAction.PLACE_GHOST_RECIPE) { this.player.connection.send(new ClientboundPlaceGhostRecipePacket(this.player.containerMenu.containerId, craftingmanager_d.display().display())); } -@@ -1917,6 +2944,7 @@ +@@ -1917,6 +2950,7 @@ @Override public void handleContainerButtonClick(ServerboundContainerButtonClickPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1657,7 +1668,7 @@ this.player.resetLastActionTime(); if (this.player.containerMenu.containerId == packet.containerId() && !this.player.isSpectator()) { if (!this.player.containerMenu.stillValid(this.player)) { -@@ -1945,7 +2973,44 @@ +@@ -1945,7 +2979,44 @@ boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45; boolean flag2 = itemstack.isEmpty() || itemstack.getCount() <= itemstack.getMaxStackSize(); @@ -1702,7 +1713,7 @@ if (flag1 && flag2) { this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemstack); this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemstack); -@@ -1972,6 +3037,7 @@ +@@ -1972,6 +3043,7 @@ } private void updateSignText(ServerboundSignUpdatePacket packet, List<FilteredText> signText) { @@ -1710,7 +1721,7 @@ this.player.resetLastActionTime(); ServerLevel worldserver = this.player.serverLevel(); BlockPos blockposition = packet.getPos(); -@@ -1993,7 +3059,17 @@ +@@ -1993,7 +3065,17 @@ @Override public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1729,7 +1740,7 @@ } @Override -@@ -2058,7 +3134,7 @@ +@@ -2058,7 +3140,7 @@ if (!this.waitingForSwitchToConfig) { throw new IllegalStateException("Client acknowledged config, but none was requested"); } else { @@ -1738,7 +1749,7 @@ } } -@@ -2083,8 +3159,10 @@ +@@ -2083,8 +3165,10 @@ }); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch index e28d0b4929..092c71cb8f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -18,7 +18,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.FenceGateBlock; -@@ -138,9 +138,67 @@ +@@ -138,9 +138,68 @@ import net.minecraft.world.scores.ScoreHolder; import net.minecraft.world.scores.Team; import org.slf4j.Logger; @@ -33,6 +33,7 @@ +import org.bukkit.entity.Hanging; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Vehicle; ++import org.spigotmc.CustomTimingsHandler; // Spigot +import org.bukkit.event.entity.EntityCombustByEntityEvent; +import org.bukkit.event.hanging.HangingBreakByEntityEvent; +import org.bukkit.event.vehicle.VehicleBlockCollisionEvent; @@ -61,13 +62,13 @@ +// CraftBukkit end public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder { -+ + + // CraftBukkit start + private static final int CURRENT_LEVEL = 2; + static boolean isLevelAtLeast(CompoundTag tag, int level) { + return tag.contains("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level; + } - ++ + private CraftEntity bukkitEntity; + + public CraftEntity getBukkitEntity() { @@ -86,7 +87,7 @@ private static final Logger LOGGER = LogUtils.getLogger(); public static final String ID_TAG = "id"; public static final String PASSENGERS_TAG = "Passengers"; -@@ -224,7 +282,7 @@ +@@ -224,7 +283,7 @@ private static final EntityDataAccessor<Boolean> DATA_CUSTOM_NAME_VISIBLE = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor<Boolean> DATA_SILENT = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor<Boolean> DATA_NO_GRAVITY = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.BOOLEAN); @@ -95,7 +96,7 @@ private static final EntityDataAccessor<Integer> DATA_TICKS_FROZEN = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.INT); private EntityInLevelCallback levelCallback; private final VecDeltaCodec packetPositionCodec; -@@ -253,7 +311,31 @@ +@@ -253,7 +312,32 @@ private final List<Entity.Movement> movementThisTick; private final Set<BlockState> blocksInside; private final LongSet visitedBlocks; @@ -114,6 +115,7 @@ + // Marks an entity, that it was removed by a plugin via Entity#remove + // Main use case currently is for SPIGOT-7487, preventing dropping of leash when leash is removed + public boolean pluginRemoved = false; ++ public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getEntityTimings(this); // Spigot + public float getBukkitYaw() { + return this.yRot; @@ -127,7 +129,7 @@ public Entity(EntityType<?> type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); this.passengers = ImmutableList.of(); -@@ -292,7 +374,7 @@ +@@ -292,7 +376,7 @@ datawatcher_a.define(Entity.DATA_CUSTOM_NAME, Optional.empty()); datawatcher_a.define(Entity.DATA_SILENT, false); datawatcher_a.define(Entity.DATA_NO_GRAVITY, false); @@ -136,7 +138,7 @@ datawatcher_a.define(Entity.DATA_TICKS_FROZEN, 0); this.defineSynchedData(datawatcher_a); this.entityData = datawatcher_a.build(); -@@ -362,20 +444,36 @@ +@@ -362,20 +446,36 @@ } public void kill(ServerLevel world) { @@ -175,7 +177,7 @@ public boolean equals(Object object) { return object instanceof Entity ? ((Entity) object).id == this.id : false; } -@@ -385,22 +483,34 @@ +@@ -385,22 +485,34 @@ } public void remove(Entity.RemovalReason reason) { @@ -215,7 +217,7 @@ return this.getPose() == pose; } -@@ -417,6 +527,33 @@ +@@ -417,6 +529,33 @@ } public void setRot(float yaw, float pitch) { @@ -249,7 +251,7 @@ this.setYRot(yaw % 360.0F); this.setXRot(pitch % 360.0F); } -@@ -462,6 +599,15 @@ +@@ -462,6 +601,15 @@ this.baseTick(); } @@ -265,7 +267,7 @@ public void baseTick() { ProfilerFiller gameprofilerfiller = Profiler.get(); -@@ -475,7 +621,7 @@ +@@ -475,7 +623,7 @@ --this.boardingCooldown; } @@ -274,7 +276,7 @@ if (this.canSpawnSprintParticle()) { this.spawnSprintParticle(); } -@@ -514,6 +660,10 @@ +@@ -514,6 +662,10 @@ if (this.isInLava()) { this.lavaHurt(); this.fallDistance *= 0.5F; @@ -285,7 +287,7 @@ } this.checkBelowWorld(); -@@ -525,7 +675,7 @@ +@@ -525,7 +677,7 @@ world = this.level(); if (world instanceof ServerLevel worldserver) { if (this instanceof Leashable) { @@ -294,7 +296,7 @@ } } -@@ -568,15 +718,32 @@ +@@ -568,15 +720,32 @@ public void lavaHurt() { if (!this.fireImmune()) { @@ -329,7 +331,7 @@ } } -@@ -587,9 +754,25 @@ +@@ -587,9 +756,25 @@ } public final void igniteForSeconds(float seconds) { @@ -356,7 +358,7 @@ public void igniteForTicks(int ticks) { if (this.remainingFireTicks < ticks) { this.setRemainingFireTicks(ticks); -@@ -610,7 +793,7 @@ +@@ -610,7 +795,7 @@ } protected void onBelowWorld() { @@ -365,13 +367,18 @@ } public boolean isFree(double offsetX, double offsetY, double offsetZ) { -@@ -747,8 +930,30 @@ +@@ -672,6 +857,7 @@ + } + + public void move(MoverType type, Vec3 movement) { ++ org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.startTiming(); // Spigot + if (this.noPhysics) { + this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); + } else { +@@ -750,6 +936,28 @@ + } + } - if (movement.y != vec3d1.y) { - block.updateEntityMovementAfterFallOn(this.level(), this); -+ } -+ } -+ + // CraftBukkit start + if (this.horizontalCollision && this.getBukkitEntity() instanceof Vehicle) { + Vehicle vehicle = (Vehicle) this.getBukkitEntity(); @@ -385,22 +392,30 @@ + bl = bl.getRelative(BlockFace.SOUTH); + } else if (movement.z < vec3d1.z) { + bl = bl.getRelative(BlockFace.NORTH); - } ++ } + + if (!bl.getType().isAir()) { + VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl); + this.level.getCraftServer().getPluginManager().callEvent(event); + } - } ++ } + // CraftBukkit end - ++ if (!this.level().isClientSide() || this.isControlledByLocalInstance()) { Entity.MovementEmission entity_movementemission = this.getMovementEmission(); -@@ -1131,7 +1336,21 @@ +@@ -764,6 +972,7 @@ + gameprofilerfiller.pop(); + } + } ++ org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.stopTiming(); // Spigot + } + + private void applyMovementEmissionAndPlaySound(Entity.MovementEmission moveEffect, Vec3 movement, BlockPos landingPos, BlockState landingState) { +@@ -1132,6 +1341,20 @@ protected SoundEvent getSwimHighSpeedSplashSound() { return SoundEvents.GENERIC_SPLASH; -+ } + } + + // CraftBukkit start - Add delegate methods + public SoundEvent getSwimSound0() { @@ -413,12 +428,12 @@ + + public SoundEvent getSwimHighSpeedSplashSound0() { + return this.getSwimHighSpeedSplashSound(); - } ++ } + // CraftBukkit end public void recordMovementThroughBlocks(Vec3 oldPos, Vec3 newPos) { this.movementThisTick.add(new Entity.Movement(oldPos, newPos)); -@@ -1609,6 +1828,7 @@ +@@ -1609,6 +1832,7 @@ this.yo = y; this.zo = d4; this.setPos(d3, y, d4); @@ -426,7 +441,7 @@ } public void moveTo(Vec3 pos) { -@@ -1861,6 +2081,12 @@ +@@ -1861,6 +2085,12 @@ return false; } @@ -439,7 +454,7 @@ public void awardKillScore(Entity entityKilled, DamageSource damageSource) { if (entityKilled instanceof ServerPlayer) { CriteriaTriggers.ENTITY_KILLED_PLAYER.trigger((ServerPlayer) entityKilled, this, damageSource); -@@ -1889,16 +2115,22 @@ +@@ -1889,16 +2119,22 @@ } public boolean saveAsPassenger(CompoundTag nbt) { @@ -465,22 +480,21 @@ return true; } } -@@ -1909,54 +2141,97 @@ +@@ -1909,54 +2145,97 @@ } public CompoundTag saveWithoutId(CompoundTag nbt) { -- try { -- if (this.vehicle != null) { -- nbt.put("Pos", this.newDoubleList(this.vehicle.getX(), this.getY(), this.vehicle.getZ())); -- } else { -- nbt.put("Pos", this.newDoubleList(this.getX(), this.getY(), this.getZ())); + // CraftBukkit start - allow excluding certain data when saving + return this.saveWithoutId(nbt, true); + } + + public CompoundTag saveWithoutId(CompoundTag nbttagcompound, boolean includeAll) { + // CraftBukkit end -+ try { + try { +- if (this.vehicle != null) { +- nbt.put("Pos", this.newDoubleList(this.vehicle.getX(), this.getY(), this.vehicle.getZ())); +- } else { +- nbt.put("Pos", this.newDoubleList(this.getX(), this.getY(), this.getZ())); + // CraftBukkit start - selectively save position + if (includeAll) { + if (this.vehicle != null) { @@ -584,7 +598,7 @@ } ListTag nbttaglist; -@@ -1972,10 +2247,10 @@ +@@ -1972,10 +2251,10 @@ nbttaglist.add(StringTag.valueOf(s)); } @@ -597,7 +611,7 @@ if (this.isVehicle()) { nbttaglist = new ListTag(); iterator = this.getPassengers().iterator(); -@@ -1984,17 +2259,22 @@ +@@ -1984,17 +2263,22 @@ Entity entity = (Entity) iterator.next(); CompoundTag nbttagcompound1 = new CompoundTag(); @@ -623,7 +637,7 @@ } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being saved"); -@@ -2080,6 +2360,45 @@ +@@ -2080,6 +2364,45 @@ } else { throw new IllegalStateException("Entity has invalid position"); } @@ -669,7 +683,7 @@ } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being loaded"); -@@ -2101,6 +2420,12 @@ +@@ -2101,6 +2424,12 @@ return entitytypes.canSerialize() && minecraftkey != null ? minecraftkey.toString() : null; } @@ -682,7 +696,7 @@ protected abstract void readAdditionalSaveData(CompoundTag nbt); protected abstract void addAdditionalSaveData(CompoundTag nbt); -@@ -2153,9 +2478,22 @@ +@@ -2153,9 +2482,22 @@ if (stack.isEmpty()) { return null; } else { @@ -705,7 +719,7 @@ world.addFreshEntity(entityitem); return entityitem; } -@@ -2184,6 +2522,12 @@ +@@ -2184,6 +2526,12 @@ if (this.isAlive() && this instanceof Leashable leashable) { if (leashable.getLeashHolder() == player) { if (!this.level().isClientSide()) { @@ -718,7 +732,7 @@ if (player.hasInfiniteMaterials()) { leashable.removeLeash(); } else { -@@ -2200,6 +2544,13 @@ +@@ -2200,6 +2548,13 @@ if (itemstack.is(Items.LEAD) && leashable.canHaveALeashAttachedToIt()) { if (!this.level().isClientSide()) { @@ -732,7 +746,7 @@ leashable.setLeashedTo(player, true); } -@@ -2265,7 +2616,7 @@ +@@ -2265,7 +2620,7 @@ } public boolean showVehicleHealth() { @@ -741,7 +755,7 @@ } public boolean startRiding(Entity entity, boolean force) { -@@ -2273,7 +2624,7 @@ +@@ -2273,7 +2628,7 @@ return false; } else if (!entity.couldAcceptPassenger()) { return false; @@ -750,7 +764,7 @@ return false; } else { for (Entity entity1 = entity; entity1.vehicle != null; entity1 = entity1.vehicle) { -@@ -2285,11 +2636,32 @@ +@@ -2285,11 +2640,32 @@ if (!force && (!this.canRide(entity) || !entity.canAddPassenger(this))) { return false; } else { @@ -784,7 +798,7 @@ this.vehicle = entity; this.vehicle.addPassenger(this); entity.getIndirectPassengersStream().filter((entity2) -> { -@@ -2318,7 +2690,7 @@ +@@ -2318,7 +2694,7 @@ Entity entity = this.vehicle; this.vehicle = null; @@ -793,7 +807,7 @@ } } -@@ -2349,21 +2721,50 @@ +@@ -2349,21 +2725,50 @@ } } @@ -850,7 +864,7 @@ } protected boolean canAddPassenger(Entity passenger) { -@@ -2464,7 +2865,7 @@ +@@ -2464,7 +2869,7 @@ if (teleporttransition != null) { ServerLevel worldserver1 = teleporttransition.newLevel(); @@ -859,7 +873,7 @@ this.teleport(teleporttransition); } } -@@ -2547,7 +2948,7 @@ +@@ -2547,7 +2952,7 @@ } public boolean isCrouching() { @@ -868,7 +882,7 @@ } public boolean isSprinting() { -@@ -2563,7 +2964,7 @@ +@@ -2563,7 +2968,7 @@ } public boolean isVisuallySwimming() { @@ -877,7 +891,7 @@ } public boolean isVisuallyCrawling() { -@@ -2571,6 +2972,13 @@ +@@ -2571,6 +2976,13 @@ } public void setSwimming(boolean swimming) { @@ -891,7 +905,7 @@ this.setSharedFlag(4, swimming); } -@@ -2624,8 +3032,12 @@ +@@ -2624,8 +3036,12 @@ return this.getTeam() != null ? this.getTeam().isAlliedTo(team) : false; } @@ -905,7 +919,7 @@ } public boolean getSharedFlag(int index) { -@@ -2644,7 +3056,7 @@ +@@ -2644,7 +3060,7 @@ } public int getMaxAirSupply() { @@ -914,7 +928,7 @@ } public int getAirSupply() { -@@ -2652,7 +3064,18 @@ +@@ -2652,7 +3068,18 @@ } public void setAirSupply(int air) { @@ -934,7 +948,7 @@ } public int getTicksFrozen() { -@@ -2679,11 +3102,40 @@ +@@ -2679,11 +3106,40 @@ public void thunderHit(ServerLevel world, LightningBolt lightning) { this.setRemainingFireTicks(this.remainingFireTicks + 1); @@ -977,7 +991,7 @@ } public void onAboveBubbleCol(boolean drag) { -@@ -2713,7 +3165,7 @@ +@@ -2713,7 +3169,7 @@ this.resetFallDistance(); } @@ -986,7 +1000,7 @@ return true; } -@@ -2852,6 +3304,18 @@ +@@ -2852,6 +3308,18 @@ if (world instanceof ServerLevel worldserver) { if (!this.isRemoved()) { @@ -1005,7 +1019,7 @@ ServerLevel worldserver1 = teleportTarget.newLevel(); boolean flag = worldserver1.dimension() != worldserver.dimension(); -@@ -2920,8 +3384,12 @@ +@@ -2920,8 +3388,12 @@ } else { entity.restoreFrom(this); this.removeAfterChangingDimensions(); @@ -1019,7 +1033,7 @@ Iterator iterator1 = list1.iterator(); while (iterator1.hasNext()) { -@@ -2947,7 +3415,7 @@ +@@ -2947,7 +3419,7 @@ } private void sendTeleportTransitionToRidingPlayers(TeleportTransition teleportTarget) { @@ -1028,7 +1042,7 @@ Iterator iterator = this.getIndirectPassengers().iterator(); while (iterator.hasNext()) { -@@ -2995,8 +3463,9 @@ +@@ -2995,8 +3467,9 @@ } protected void removeAfterChangingDimensions() { @@ -1039,7 +1053,7 @@ leashable.removeLeash(); } -@@ -3004,7 +3473,21 @@ +@@ -3004,7 +3477,21 @@ public Vec3 getRelativePortalPosition(Direction.Axis portalAxis, BlockUtil.FoundRectangle portalRect) { return PortalShape.getRelativePosition(portalRect, portalAxis, this.position(), this.getDimensions(this.getPose())); @@ -1061,7 +1075,7 @@ public boolean canUsePortal(boolean allowVehicles) { return (allowVehicles || !this.isPassenger()) && this.isAlive(); -@@ -3134,10 +3617,16 @@ +@@ -3134,10 +3621,16 @@ return (Boolean) this.entityData.get(Entity.DATA_CUSTOM_NAME_VISIBLE); } @@ -1081,7 +1095,7 @@ return entity != null; } -@@ -3187,7 +3676,7 @@ +@@ -3187,7 +3680,7 @@ /** @deprecated */ @Deprecated protected void fixupDimensions() { @@ -1090,7 +1104,7 @@ EntityDimensions entitysize = this.getDimensions(entitypose); this.dimensions = entitysize; -@@ -3196,7 +3685,7 @@ +@@ -3196,7 +3689,7 @@ public void refreshDimensions() { EntityDimensions entitysize = this.dimensions; @@ -1099,7 +1113,7 @@ EntityDimensions entitysize1 = this.getDimensions(entitypose); this.dimensions = entitysize1; -@@ -3258,10 +3747,29 @@ +@@ -3258,10 +3751,29 @@ } public final void setBoundingBox(AABB boundingBox) { @@ -1131,7 +1145,7 @@ return this.getDimensions(pose).eyeHeight(); } -@@ -3335,7 +3843,7 @@ +@@ -3335,7 +3847,7 @@ } @Nullable @@ -1140,7 +1154,7 @@ return null; } -@@ -3435,7 +3943,7 @@ +@@ -3435,7 +3947,7 @@ } public boolean isControlledByLocalInstance() { @@ -1149,7 +1163,7 @@ if (entityliving instanceof Player entityhuman) { return entityhuman.isLocalPlayer(); -@@ -3445,7 +3953,7 @@ +@@ -3445,7 +3957,7 @@ } public boolean isControlledByClient() { @@ -1158,7 +1172,7 @@ return entityliving != null && entityliving.isControlledByClient(); } -@@ -3463,7 +3971,7 @@ +@@ -3463,7 +3975,7 @@ return new Vec3((double) f1 * d2 / (double) f3, 0.0D, (double) f2 * d2 / (double) f3); } @@ -1167,7 +1181,7 @@ return new Vec3(this.getX(), this.getBoundingBox().maxY, this.getZ()); } -@@ -3489,8 +3997,37 @@ +@@ -3489,8 +4001,37 @@ return 1; } @@ -1206,7 +1220,7 @@ } public void lookAt(EntityAnchorArgument.Anchor anchorPoint, Vec3 target) { -@@ -3551,6 +4088,11 @@ +@@ -3551,6 +4092,11 @@ vec3d = vec3d.add(vec3d1); ++k1; } @@ -1218,7 +1232,7 @@ } } } -@@ -3613,7 +4155,7 @@ +@@ -3613,7 +4159,7 @@ return new ClientboundAddEntityPacket(this, entityTrackerEntry); } @@ -1227,7 +1241,7 @@ return this.type.getDimensions(); } -@@ -3818,8 +4360,16 @@ +@@ -3818,8 +4364,16 @@ @Override public final void setRemoved(Entity.RemovalReason reason) { @@ -1245,7 +1259,7 @@ } if (this.removalReason.shouldDestroy()) { -@@ -3827,8 +4377,8 @@ +@@ -3827,8 +4381,8 @@ } this.getPassengers().forEach(Entity::stopRiding); @@ -1256,7 +1270,7 @@ } public void unsetRemoved() { -@@ -3887,7 +4437,7 @@ +@@ -3887,7 +4441,7 @@ } public Vec3 getKnownMovement() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index 2312b7078b..c8dd6f4966 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -17,11 +17,10 @@ import net.minecraft.world.entity.projectile.AbstractArrow; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.item.AxeItem; -@@ -135,6 +136,30 @@ - import net.minecraft.world.scores.PlayerTeam; +@@ -136,6 +137,32 @@ import net.minecraft.world.scores.Scoreboard; import org.slf4j.Logger; -+ + +// CraftBukkit start +import java.util.ArrayList; +import java.util.HashSet; @@ -45,10 +44,13 @@ +import org.bukkit.event.entity.EntityTeleportEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; +// CraftBukkit end - ++ ++import org.bukkit.craftbukkit.SpigotTimings; // Spigot ++ public abstract class LivingEntity extends Entity implements Attackable { -@@ -174,7 +199,7 @@ + private static final Logger LOGGER = LogUtils.getLogger(); +@@ -174,7 +201,7 @@ public static final float DEFAULT_BABY_SCALE = 0.5F; public static final String ATTRIBUTES_FIELD = "attributes"; public static final Predicate<LivingEntity> PLAYER_NOT_WEARING_DISGUISE_ITEM = (entityliving) -> { @@ -57,7 +59,7 @@ ItemStack itemstack = entityhuman.getItemBySlot(EquipmentSlot.HEAD); return !itemstack.is(ItemTags.GAZE_DISGUISE_EQUIPMENT); -@@ -210,7 +235,7 @@ +@@ -210,7 +237,7 @@ public float yHeadRotO; public final ElytraAnimationState elytraAnimationState; @Nullable @@ -66,7 +68,7 @@ public int lastHurtByPlayerTime; protected boolean dead; protected int noActionTime; -@@ -260,7 +285,20 @@ +@@ -260,7 +287,20 @@ protected boolean skipDropExperience; private final EnumMap<EquipmentSlot, Reference2ObjectMap<Enchantment, Set<EnchantmentLocationBasedEffect>>> activeLocationDependentEnchantments; protected float appliedScale; @@ -87,7 +89,7 @@ protected LivingEntity(EntityType<? extends LivingEntity> type, Level world) { super(type, world); this.lastHandItemStacks = NonNullList.withSize(2, ItemStack.EMPTY); -@@ -276,7 +314,9 @@ +@@ -276,7 +316,9 @@ this.activeLocationDependentEnchantments = new EnumMap(EquipmentSlot.class); this.appliedScale = 1.0F; this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type)); @@ -98,7 +100,7 @@ this.blocksBuilding = true; this.rotA = (float) ((Math.random() + 1.0D) * 0.009999999776482582D); this.reapplyPosition(); -@@ -356,7 +396,13 @@ +@@ -356,7 +398,13 @@ double d8 = Math.min((double) (0.2F + f / 15.0F), 2.5D); int i = (int) (150.0D * d8); @@ -113,7 +115,7 @@ } } } -@@ -402,7 +448,7 @@ +@@ -402,7 +450,7 @@ } if (this.isAlive()) { @@ -122,7 +124,7 @@ Level world1 = this.level(); ServerLevel worldserver1; double d0; -@@ -424,7 +470,7 @@ +@@ -424,7 +472,7 @@ } if (this.isEyeInFluid(FluidTags.WATER) && !this.level().getBlockState(BlockPos.containing(this.getX(), this.getEyeY(), this.getZ())).is(Blocks.BUBBLE_COLUMN)) { @@ -131,7 +133,7 @@ if (flag1) { this.setAirSupply(this.decreaseAirSupply(this.getAirSupply())); -@@ -573,7 +619,7 @@ +@@ -573,7 +621,7 @@ ++this.deathTime; if (this.deathTime >= 20 && !this.level().isClientSide() && !this.isRemoved()) { this.level().broadcastEntityEvent(this, (byte) 60); @@ -140,7 +142,7 @@ } } -@@ -629,7 +675,7 @@ +@@ -629,7 +677,7 @@ return this.lastHurtByMobTimestamp; } @@ -149,28 +151,27 @@ this.lastHurtByPlayer = attacking; this.lastHurtByPlayerTime = this.tickCount; } -@@ -679,17 +725,23 @@ +@@ -679,17 +727,23 @@ } public void onEquipItem(EquipmentSlot slot, ItemStack oldStack, ItemStack newStack) { -- if (!this.level().isClientSide() && !this.isSpectator()) { -- boolean flag = newStack.isEmpty() && oldStack.isEmpty(); + // CraftBukkit start + this.onEquipItem(slot, oldStack, newStack, false); + } ++ ++ public void onEquipItem(EquipmentSlot enumitemslot, ItemStack itemstack, ItemStack itemstack1, boolean silent) { ++ // CraftBukkit end + if (!this.level().isClientSide() && !this.isSpectator()) { +- boolean flag = newStack.isEmpty() && oldStack.isEmpty(); ++ boolean flag = itemstack1.isEmpty() && itemstack.isEmpty(); - if (!flag && !ItemStack.isSameItemSameComponents(oldStack, newStack) && !this.firstTick) { - Equippable equippable = (Equippable) newStack.get(DataComponents.EQUIPPABLE); -+ public void onEquipItem(EquipmentSlot enumitemslot, ItemStack itemstack, ItemStack itemstack1, boolean silent) { -+ // CraftBukkit end -+ if (!this.level().isClientSide() && !this.isSpectator()) { -+ boolean flag = itemstack1.isEmpty() && itemstack.isEmpty(); ++ if (!flag && !ItemStack.isSameItemSameComponents(itemstack, itemstack1) && !this.firstTick) { ++ Equippable equippable = (Equippable) itemstack1.get(DataComponents.EQUIPPABLE); - if (!this.isSilent() && equippable != null && slot == equippable.slot()) { - this.level().playSeededSound((Player) null, this.getX(), this.getY(), this.getZ(), equippable.equipSound(), this.getSoundSource(), 1.0F, 1.0F, this.random.nextLong()); -+ if (!flag && !ItemStack.isSameItemSameComponents(itemstack, itemstack1) && !this.firstTick) { -+ Equippable equippable = (Equippable) itemstack1.get(DataComponents.EQUIPPABLE); -+ + if (!this.isSilent() && equippable != null && enumitemslot == equippable.slot() && !silent) { // CraftBukkit + this.level().playSeededSound((net.minecraft.world.entity.player.Player) null, this.getX(), this.getY(), this.getZ(), equippable.equipSound(), this.getSoundSource(), 1.0F, 1.0F, this.random.nextLong()); } @@ -180,7 +181,7 @@ this.gameEvent(equippable != null ? GameEvent.EQUIP : GameEvent.UNEQUIP); } -@@ -699,17 +751,24 @@ +@@ -699,17 +753,24 @@ @Override public void remove(Entity.RemovalReason reason) { @@ -208,7 +209,7 @@ this.brain.clearMemories(); } -@@ -722,6 +781,7 @@ +@@ -722,6 +783,7 @@ mobeffect.onMobRemoved(world, this, reason); } @@ -216,13 +217,10 @@ this.activeEffects.clear(); } -@@ -778,8 +838,19 @@ - if (mobeffect != null) { - this.activeEffects.put(mobeffect.getEffect(), mobeffect); - } -+ } -+ } -+ +@@ -781,6 +843,17 @@ + } + } + + // CraftBukkit start + if (nbt.contains("Bukkit.MaxHealth")) { + Tag nbtbase = nbt.get("Bukkit.MaxHealth"); @@ -230,13 +228,14 @@ + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(((FloatTag) nbtbase).getAsDouble()); + } else if (nbtbase.getId() == 3) { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(((IntTag) nbtbase).getAsDouble()); - } - } ++ } ++ } + // CraftBukkit end - ++ if (nbt.contains("Health", 99)) { this.setHealth(nbt.getFloat("Health")); -@@ -819,9 +890,32 @@ + } +@@ -819,9 +892,32 @@ } @@ -269,7 +268,7 @@ try { while (iterator.hasNext()) { Holder<MobEffect> holder = (Holder) iterator.next(); -@@ -831,6 +925,12 @@ +@@ -831,6 +927,12 @@ this.onEffectUpdated(mobeffect, true, (Entity) null); })) { if (!this.level().isClientSide) { @@ -282,7 +281,7 @@ iterator.remove(); this.onEffectsRemoved(List.of(mobeffect)); } -@@ -841,6 +941,17 @@ +@@ -841,6 +943,17 @@ } catch (ConcurrentModificationException concurrentmodificationexception) { ; } @@ -300,7 +299,7 @@ if (this.effectsDirty) { if (!this.level().isClientSide) { -@@ -921,7 +1032,7 @@ +@@ -921,7 +1034,7 @@ } public boolean canAttack(LivingEntity target) { @@ -309,7 +308,7 @@ } public boolean canBeSeenAsEnemy() { -@@ -952,17 +1063,36 @@ +@@ -952,17 +1065,36 @@ this.entityData.set(LivingEntity.DATA_EFFECT_PARTICLES, List.of()); } @@ -350,7 +349,7 @@ } } -@@ -987,24 +1117,55 @@ +@@ -987,24 +1119,55 @@ return this.addEffect(effect, (Entity) null); } @@ -415,7 +414,7 @@ return flag; } } -@@ -1031,14 +1192,40 @@ +@@ -1031,14 +1194,40 @@ return this.getType().is(EntityTypeTags.INVERTED_HEALING_AND_HARM); } @@ -458,7 +457,7 @@ if (mobeffect != null) { this.onEffectsRemoved(List.of(mobeffect)); return true; -@@ -1142,20 +1329,55 @@ +@@ -1142,20 +1331,55 @@ } @@ -515,7 +514,7 @@ this.entityData.set(LivingEntity.DATA_HEALTH_ID, Mth.clamp(health, 0.0F, this.getMaxHealth())); } -@@ -1167,7 +1389,7 @@ +@@ -1167,7 +1391,7 @@ public boolean hurtServer(ServerLevel world, DamageSource source, float amount) { if (this.isInvulnerableTo(world, source)) { return false; @@ -524,7 +523,7 @@ return false; } else if (source.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; -@@ -1182,10 +1404,11 @@ +@@ -1182,10 +1406,11 @@ } float f1 = amount; @@ -538,7 +537,7 @@ this.hurtCurrentlyUsedShield(amount); f2 = amount; amount = 0.0F; -@@ -1202,15 +1425,26 @@ +@@ -1202,15 +1427,26 @@ flag = true; } @@ -567,7 +566,7 @@ this.walkAnimation.setSpeed(1.5F); if (Float.isNaN(amount) || Float.isInfinite(amount)) { amount = Float.MAX_VALUE; -@@ -1218,18 +1452,27 @@ +@@ -1218,18 +1454,27 @@ boolean flag1 = true; @@ -599,7 +598,7 @@ this.hurtDuration = 10; this.hurtTime = this.hurtDuration; } -@@ -1243,7 +1486,7 @@ +@@ -1243,7 +1488,7 @@ world.broadcastDamageEvent(this, source); } @@ -608,7 +607,7 @@ this.markHurt(); } -@@ -1263,7 +1506,7 @@ +@@ -1263,7 +1508,7 @@ d1 = source.getSourcePosition().z() - this.getZ(); } @@ -617,7 +616,7 @@ if (!flag) { this.indicateDamage(d0, d1); } -@@ -1282,7 +1525,7 @@ +@@ -1282,7 +1527,7 @@ this.playHurtSound(source); } @@ -626,7 +625,7 @@ if (flag2) { this.lastDamageSource = source; -@@ -1329,10 +1572,10 @@ +@@ -1329,10 +1574,10 @@ } @Nullable @@ -639,7 +638,7 @@ this.lastHurtByPlayerTime = 100; this.lastHurtByPlayer = entityhuman; return entityhuman; -@@ -1342,8 +1585,8 @@ +@@ -1342,8 +1587,8 @@ this.lastHurtByPlayerTime = 100; LivingEntity entityliving = entitywolf.getOwner(); @@ -650,7 +649,7 @@ this.lastHurtByPlayer = entityhuman1; } else { -@@ -1363,7 +1606,7 @@ +@@ -1363,7 +1608,7 @@ } protected void blockedByShield(LivingEntity target) { @@ -659,7 +658,7 @@ } private boolean checkTotemDeathProtection(DamageSource source) { -@@ -1375,20 +1618,33 @@ +@@ -1375,20 +1620,33 @@ InteractionHand[] aenumhand = InteractionHand.values(); int i = aenumhand.length; @@ -697,7 +696,7 @@ ServerPlayer entityplayer = (ServerPlayer) this; entityplayer.awardStat(Stats.ITEM_USED.get(itemstack.getItem())); -@@ -1512,14 +1768,22 @@ +@@ -1512,14 +1770,22 @@ BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState(); if (this.level().getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level(), blockposition)) { @@ -722,7 +721,7 @@ this.level().addFreshEntity(entityitem); } } -@@ -1530,22 +1794,37 @@ +@@ -1530,22 +1796,37 @@ protected void dropAllDeathLoot(ServerLevel world, DamageSource damageSource) { boolean flag = this.lastHurtByPlayerTime > 0; @@ -764,7 +763,7 @@ } protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {} -@@ -1612,19 +1891,31 @@ +@@ -1612,19 +1893,31 @@ } public void knockback(double strength, double x, double z) { @@ -803,7 +802,7 @@ } } -@@ -1683,6 +1974,20 @@ +@@ -1683,6 +1976,20 @@ return new LivingEntity.Fallsounds(SoundEvents.GENERIC_SMALL_FALL, SoundEvents.GENERIC_BIG_FALL); } @@ -824,7 +823,7 @@ public Optional<BlockPos> getLastClimbablePos() { return this.lastClimbablePos; } -@@ -1757,9 +2062,14 @@ +@@ -1757,9 +2064,14 @@ int i = this.calculateFallDamage(fallDistance, damageMultiplier); if (i > 0) { @@ -840,7 +839,7 @@ return true; } else { return flag; -@@ -1830,7 +2140,7 @@ +@@ -1830,7 +2142,7 @@ protected float getDamageAfterArmorAbsorb(DamageSource source, float amount) { if (!source.is(DamageTypeTags.BYPASSES_ARMOR)) { @@ -849,7 +848,7 @@ amount = CombatRules.getDamageAfterAbsorb(this, amount, source, (float) this.getArmorValue(), (float) this.getAttributeValue(Attributes.ARMOR_TOUGHNESS)); } -@@ -1841,7 +2151,8 @@ +@@ -1841,7 +2153,8 @@ if (source.is(DamageTypeTags.BYPASSES_EFFECTS)) { return amount; } else { @@ -859,7 +858,7 @@ int i = (this.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() + 1) * 5; int j = 25 - i; float f1 = amount * (float) j; -@@ -1884,18 +2195,144 @@ +@@ -1884,18 +2197,144 @@ } } @@ -886,7 +885,7 @@ + }; + float freezingModifier = freezing.apply((double) f).floatValue(); + f += freezingModifier; - ++ + com.google.common.base.Function<Double, Double> hardHat = new com.google.common.base.Function<Double, Double>() { + @Override + public Double apply(Double f) { @@ -916,7 +915,7 @@ + }; + float armorModifier = armor.apply((double) f).floatValue(); + f += armorModifier; -+ + + com.google.common.base.Function<Double, Double> resistance = new com.google.common.base.Function<Double, Double>() { + @Override + public Double apply(Double f) { @@ -1013,7 +1012,7 @@ if (entity instanceof ServerPlayer) { ServerPlayer entityplayer = (ServerPlayer) entity; -@@ -1904,13 +2341,48 @@ +@@ -1904,13 +2343,48 @@ } } @@ -1066,28 +1065,27 @@ } public CombatTracker getCombatTracker() { -@@ -1935,9 +2407,19 @@ +@@ -1935,8 +2409,18 @@ } public final void setArrowCount(int stuckArrowCount) { - this.entityData.set(LivingEntity.DATA_ARROW_COUNT_ID, stuckArrowCount); + // CraftBukkit start + this.setArrowCount(stuckArrowCount, false); - } - ++ } ++ + public final void setArrowCount(int i, boolean flag) { + ArrowBodyCountChangeEvent event = CraftEventFactory.callArrowBodyCountChangeEvent(this, this.getArrowCount(), i, flag); + if (event.isCancelled()) { + return; + } + this.entityData.set(LivingEntity.DATA_ARROW_COUNT_ID, event.getNewAmount()); -+ } + } + // CraftBukkit end -+ + public final int getStingerCount() { return (Integer) this.entityData.get(LivingEntity.DATA_STINGER_COUNT_ID); - } -@@ -1999,7 +2481,7 @@ +@@ -1999,7 +2483,7 @@ this.playSound(soundeffect, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); } @@ -1096,7 +1094,7 @@ this.setHealth(0.0F); this.die(this.damageSources().generic()); } -@@ -2182,6 +2664,12 @@ +@@ -2182,6 +2666,12 @@ public abstract ItemStack getItemBySlot(EquipmentSlot slot); @@ -1109,7 +1107,7 @@ public abstract void setItemSlot(EquipmentSlot slot, ItemStack stack); public Iterable<ItemStack> getHandSlots() { -@@ -2494,7 +2982,7 @@ +@@ -2494,7 +2984,7 @@ } @@ -1118,7 +1116,7 @@ Vec3 vec3d1 = this.getRiddenInput(controllingPlayer, movementInput); this.tickRidden(controllingPlayer, vec3d1); -@@ -2507,13 +2995,13 @@ +@@ -2507,13 +2997,13 @@ } @@ -1135,7 +1133,7 @@ return this.getSpeed(); } -@@ -2571,7 +3059,7 @@ +@@ -2571,7 +3061,7 @@ double d1 = Mth.clamp(motion.z, -0.15000000596046448D, 0.15000000596046448D); double d2 = Math.max(motion.y, -0.15000000596046448D); @@ -1144,7 +1142,7 @@ d2 = 0.0D; } -@@ -2586,7 +3074,7 @@ +@@ -2586,7 +3076,7 @@ } protected float getFlyingSpeed() { @@ -1153,7 +1151,15 @@ } public float getSpeed() { -@@ -2634,7 +3122,7 @@ +@@ -2604,6 +3094,7 @@ + + @Override + public void tick() { ++ SpigotTimings.timerEntityBaseTick.startTiming(); // Spigot + super.tick(); + this.updatingUsingItem(); + this.updateSwimAmount(); +@@ -2634,7 +3125,7 @@ } } @@ -1162,8 +1168,21 @@ if (this.tickCount % 20 == 0) { this.getCombatTracker().recheckStatus(); } -@@ -2741,7 +3229,7 @@ +@@ -2645,7 +3136,9 @@ + } + + if (!this.isRemoved()) { ++ SpigotTimings.timerEntityBaseTick.stopTiming(); // Spigot + this.aiStep(); ++ SpigotTimings.timerEntityTickRest.startTiming(); // Spigot + } + + double d0 = this.getX() - this.xo; +@@ -2739,9 +3232,10 @@ + } + this.elytraAnimationState.tick(); ++ SpigotTimings.timerEntityTickRest.stopTiming(); // Spigot } - public void detectEquipmentUpdates() { @@ -1171,7 +1190,28 @@ Map<EquipmentSlot, ItemStack> map = this.collectEquipmentChanges(); if (map != null) { -@@ -3000,7 +3488,7 @@ +@@ -2945,6 +3439,7 @@ + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("ai"); ++ SpigotTimings.timerEntityAI.startTiming(); // Spigot + if (this.isImmobile()) { + this.jumping = false; + this.xxa = 0.0F; +@@ -2954,6 +3449,7 @@ + this.serverAiStep(); + gameprofilerfiller.pop(); + } ++ SpigotTimings.timerEntityAI.stopTiming(); // Spigot + + gameprofilerfiller.pop(); + gameprofilerfiller.push("jump"); +@@ -2996,11 +3492,12 @@ + this.resetFallDistance(); + } + ++ SpigotTimings.timerEntityAIMove.startTiming(); // Spigot + label112: { LivingEntity entityliving = this.getControllingPassenger(); @@ -1180,7 +1220,25 @@ if (this.isAlive()) { this.travelRidden(entityhuman, vec3d1); break label112; -@@ -3063,6 +3551,7 @@ +@@ -3009,6 +3506,7 @@ + + this.travel(vec3d1); + } ++ SpigotTimings.timerEntityAIMove.stopTiming(); // Spigot + + if (!this.level().isClientSide() || this.isControlledByLocalInstance()) { + this.applyEffectsFromBlocks(); +@@ -3044,7 +3542,9 @@ + this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox()); + } + ++ SpigotTimings.timerEntityAICollision.startTiming(); // Spigot + this.pushEntities(); ++ SpigotTimings.timerEntityAICollision.stopTiming(); // Spigot + gameprofilerfiller.pop(); + world = this.level(); + if (world instanceof ServerLevel worldserver) { +@@ -3063,6 +3563,7 @@ this.checkSlowFallDistance(); if (!this.level().isClientSide) { if (!this.canGlide()) { @@ -1188,7 +1246,7 @@ this.setSharedFlag(7, false); return; } -@@ -3113,7 +3602,7 @@ +@@ -3113,7 +3614,7 @@ Level world = this.level(); if (!(world instanceof ServerLevel worldserver)) { @@ -1197,7 +1255,7 @@ } else { List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this)); -@@ -3305,15 +3794,22 @@ +@@ -3305,15 +3806,22 @@ @Override public boolean isPickable() { @@ -1222,7 +1280,7 @@ public float getYHeadRot() { return this.yHeadRot; } -@@ -3483,8 +3979,31 @@ +@@ -3483,8 +3991,31 @@ this.releaseUsingItem(); } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { @@ -1255,7 +1313,7 @@ if (itemstack != this.useItem) { this.setItemInHand(enumhand, itemstack); } -@@ -3568,12 +4087,18 @@ +@@ -3568,12 +4099,18 @@ } public boolean randomTeleport(double x, double y, double z, boolean particleEffects) { @@ -1276,7 +1334,7 @@ Level world = this.level(); if (world.hasChunkAt(blockposition)) { -@@ -3592,18 +4117,43 @@ +@@ -3592,18 +4129,43 @@ } if (flag2) { @@ -1324,7 +1382,7 @@ world.broadcastEntityEvent(this, (byte) 46); } -@@ -3613,7 +4163,7 @@ +@@ -3613,7 +4175,7 @@ entitycreature.getNavigation().stop(); } @@ -1333,7 +1391,7 @@ } } -@@ -3706,7 +4256,7 @@ +@@ -3706,7 +4268,7 @@ } public void stopSleeping() { @@ -1342,7 +1400,7 @@ Level world = this.level(); java.util.Objects.requireNonNull(world); -@@ -3718,9 +4268,9 @@ +@@ -3718,9 +4280,9 @@ this.level().setBlock(blockposition, (BlockState) iblockdata.setValue(BedBlock.OCCUPIED, false), 3); Vec3 vec3d = (Vec3) BedBlock.findStandUpPosition(this.getType(), this.level(), blockposition, enumdirection, this.getYRot()).orElseGet(() -> { @@ -1354,7 +1412,7 @@ }); Vec3 vec3d1 = Vec3.atBottomCenterOf(blockposition).subtract(vec3d).normalize(); float f = (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D); -@@ -3740,7 +4290,7 @@ +@@ -3740,7 +4302,7 @@ @Nullable public Direction getBedOrientation() { @@ -1363,7 +1421,7 @@ return blockposition != null ? BedBlock.getBedOrientation(this.level(), blockposition) : null; } -@@ -3905,7 +4455,7 @@ +@@ -3905,7 +4467,7 @@ public float maxUpStep() { float f = (float) this.getAttributeValue(Attributes.STEP_HEIGHT); diff --git a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch index 986068b80f..afca8fe969 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch @@ -31,7 +31,7 @@ import net.minecraft.world.level.entity.EntityTypeTest; import net.minecraft.world.level.entity.LevelEntityGetter; import net.minecraft.world.level.gameevent.GameEvent; -@@ -81,6 +85,24 @@ +@@ -81,6 +85,25 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.Scoreboard; @@ -46,6 +46,7 @@ +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.craftbukkit.SpigotTimings; // Spigot +import org.bukkit.craftbukkit.block.CapturedBlockState; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.util.CraftSpawnCategory; @@ -56,7 +57,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public static final Codec<ResourceKey<Level>> RESOURCE_KEY_CODEC = ResourceKey.codec(Registries.DIMENSION); -@@ -121,23 +143,60 @@ +@@ -121,23 +144,62 @@ private final DamageSources damageSources; private long subTickCount; @@ -81,6 +82,8 @@ + public boolean populating; + public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot + ++ public final SpigotTimings.WorldTimingsHandler timings; // Spigot ++ + public CraftWorld getWorld() { + return this.world; + } @@ -126,7 +129,7 @@ } }; } else { -@@ -145,11 +204,47 @@ +@@ -145,11 +207,48 @@ } this.thread = Thread.currentThread(); @@ -176,10 +179,11 @@ + public void onBorderSetDamageSafeZOne(WorldBorder border, double safeZoneRadius) {} + }); + // CraftBukkit end ++ this.timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings } @Override -@@ -207,6 +302,18 @@ +@@ -207,6 +306,18 @@ @Override public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) { @@ -198,7 +202,7 @@ if (this.isOutsideBuildHeight(pos)) { return false; } else if (!this.isClientSide && this.isDebug()) { -@@ -214,45 +321,118 @@ +@@ -214,44 +325,117 @@ } else { LevelChunk chunk = this.getChunkAt(pos); Block block = state.getBlock(); @@ -276,10 +280,10 @@ + // CraftBukkit end + return true; - } - } - } - ++ } ++ } ++ } ++ + // CraftBukkit start - Split off from above in order to directly send client and physic updates + public void notifyAndUpdatePhysics(BlockPos blockposition, LevelChunk chunk, BlockState oldBlock, BlockState newBlock, BlockState actualBlock, int i, int j) { + BlockState iblockdata = newBlock; @@ -299,7 +303,7 @@ + if (!this.isClientSide && iblockdata.hasAnalogOutputSignal()) { + this.updateNeighbourForOutputSignal(blockposition, newBlock.getBlock()); + } -+ } + } + + if ((i & 16) == 0 && j > 0) { + int k = i & -34; @@ -325,14 +329,13 @@ + this.onBlockStateChange(blockposition, iblockdata1, iblockdata2); + } + // CraftBukkit end -+ } -+ } + } + } + // CraftBukkit end -+ + public void onBlockStateChange(BlockPos pos, BlockState oldBlock, BlockState newBlock) {} - @Override -@@ -340,6 +520,14 @@ +@@ -340,6 +524,14 @@ @Override public BlockState getBlockState(BlockPos pos) { @@ -347,15 +350,48 @@ if (this.isOutsideBuildHeight(pos)) { return Blocks.VOID_AIR.defaultBlockState(); } else { -@@ -510,13 +698,29 @@ +@@ -440,12 +632,15 @@ + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("blockEntities"); ++ this.timings.tileEntityPending.startTiming(); // Spigot + this.tickingBlockEntities = true; + if (!this.pendingBlockEntityTickers.isEmpty()) { + this.blockEntityTickers.addAll(this.pendingBlockEntityTickers); + this.pendingBlockEntityTickers.clear(); + } ++ this.timings.tileEntityPending.stopTiming(); // Spigot + ++ this.timings.tileEntityTick.startTiming(); // Spigot + Iterator<TickingBlockEntity> iterator = this.blockEntityTickers.iterator(); + boolean flag = this.tickRateManager().runsNormally(); + +@@ -459,13 +654,16 @@ + } + } + ++ this.timings.tileEntityTick.stopTiming(); // Spigot + this.tickingBlockEntities = false; + gameprofilerfiller.pop(); + } + + public <T extends Entity> void guardEntityTick(Consumer<T> tickConsumer, T entity) { + try { ++ SpigotTimings.tickEntityTimer.startTiming(); // Spigot + tickConsumer.accept(entity); ++ SpigotTimings.tickEntityTimer.stopTiming(); // Spigot + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity"); + CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked"); +@@ -510,13 +708,29 @@ @Nullable @Override public BlockEntity getBlockEntity(BlockPos pos) { - return this.isOutsideBuildHeight(pos) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(pos).getBlockEntity(pos, LevelChunk.EntityCreationType.IMMEDIATE)); + // CraftBukkit start + return this.getBlockEntity(pos, true); - } - ++ } ++ + @Nullable + public BlockEntity getBlockEntity(BlockPos blockposition, boolean validate) { + if (this.capturedTileEntities.containsKey(blockposition)) { @@ -363,8 +399,8 @@ + } + // CraftBukkit end + return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); -+ } -+ + } + public void setBlockEntity(BlockEntity blockEntity) { BlockPos blockposition = blockEntity.getBlockPos(); @@ -378,7 +414,7 @@ this.getChunkAt(blockposition).addAndRegisterBlockEntity(blockEntity); } } -@@ -643,7 +847,7 @@ +@@ -643,7 +857,7 @@ for (int k = 0; k < j; ++k) { EnderDragonPart entitycomplexpart = aentitycomplexpart[k]; @@ -387,7 +423,7 @@ if (t0 != null && predicate.test(t0)) { result.add(t0); -@@ -912,7 +1116,7 @@ +@@ -912,7 +1126,7 @@ public static enum ExplosionInteraction implements StringRepresentable { diff --git a/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch index f26460ed82..27f492774b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch @@ -48,7 +48,23 @@ list.add(enumcreaturetype); } } -@@ -217,10 +238,15 @@ +@@ -127,6 +148,7 @@ + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("spawner"); ++ world.timings.mobSpawn.startTiming(); // Spigot + Iterator iterator = spawnableGroups.iterator(); + + while (iterator.hasNext()) { +@@ -141,6 +163,7 @@ + } + } + ++ world.timings.mobSpawn.stopTiming(); // Spigot + gameprofilerfiller.pop(); + } + +@@ -217,10 +240,15 @@ entityinsentient.moveTo(d0, (double) i, d1, world.random.nextFloat() * 360.0F, 0.0F); if (NaturalSpawner.isValidPositionForMob(world, entityinsentient, d2)) { groupdataentity = entityinsentient.finalizeSpawn(world, world.getCurrentDifficultyAt(entityinsentient.blockPosition()), EntitySpawnReason.NATURAL, groupdataentity); @@ -68,7 +84,7 @@ if (j >= entityinsentient.getMaxSpawnClusterSize()) { return; } -@@ -369,7 +395,7 @@ +@@ -369,7 +397,7 @@ if (entityinsentient.checkSpawnRules(world, EntitySpawnReason.CHUNK_GENERATION) && entityinsentient.checkSpawnObstruction(world)) { groupdataentity = entityinsentient.finalizeSpawn(world, world.getCurrentDifficultyAt(entityinsentient.blockPosition()), EntitySpawnReason.CHUNK_GENERATION, groupdataentity); @@ -77,7 +93,7 @@ flag = true; } } -@@ -482,10 +508,12 @@ +@@ -482,10 +510,12 @@ return this.unmodifiableMobCategoryCounts; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch index 38f32457ea..b26f525fc6 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/BlockEntity.java +++ b/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -26,8 +26,18 @@ +@@ -26,8 +26,21 @@ import net.minecraft.world.level.block.state.BlockState; import org.slf4j.Logger; @@ -9,9 +9,12 @@ +import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry; +import org.bukkit.inventory.InventoryHolder; +// CraftBukkit end ++ ++import org.spigotmc.CustomTimingsHandler; // Spigot + public abstract class BlockEntity { ++ public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot + // CraftBukkit start - data containers + private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); + public CraftPersistentDataContainer persistentDataContainer; @@ -19,7 +22,7 @@ private static final Logger LOGGER = LogUtils.getLogger(); private final BlockEntityType<?> type; @Nullable -@@ -74,8 +84,17 @@ +@@ -74,8 +87,17 @@ return this.level != null; } @@ -38,7 +41,7 @@ public final void loadWithComponents(CompoundTag nbt, HolderLookup.Provider registries) { this.loadAdditional(nbt, registries); BlockEntity.ComponentHelper.COMPONENTS_CODEC.parse(registries.createSerializationContext(NbtOps.INSTANCE), nbt).resultOrPartial((s) -> { -@@ -114,6 +133,11 @@ +@@ -114,6 +136,11 @@ }).ifPresent((nbtbase) -> { nbttagcompound.merge((CompoundTag) nbtbase); }); @@ -50,7 +53,7 @@ return nbttagcompound; } -@@ -263,13 +287,19 @@ +@@ -263,13 +290,19 @@ } public final void applyComponents(DataComponentMap defaultComponents, DataComponentPatch components) { @@ -72,7 +75,7 @@ @Nullable @Override public <T> T get(DataComponentType<T> type) { -@@ -284,9 +314,13 @@ +@@ -284,9 +317,13 @@ } }); Objects.requireNonNull(set); @@ -87,7 +90,7 @@ } protected void collectImplicitComponents(DataComponentMap.Builder builder) {} -@@ -321,6 +355,15 @@ +@@ -321,6 +358,15 @@ } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch index fab24391af..0e1157fe01 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch @@ -188,10 +188,14 @@ if (tileentity != null) { Level world = this.level; -@@ -553,6 +582,57 @@ - - } - +@@ -549,10 +578,61 @@ + if (this.postLoad != null) { + this.postLoad.run(this); + this.postLoad = null; ++ } ++ ++ } ++ + // CraftBukkit start + public void loadCallback() { + org.bukkit.Server server = this.level.getCraftServer(); @@ -225,9 +229,9 @@ + } + server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk)); + } -+ } + } + } -+ + + public void unloadCallback() { + org.bukkit.Server server = this.level.getCraftServer(); + org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); @@ -235,8 +239,8 @@ + server.getPluginManager().callEvent(unloadEvent); + // note: saving can be prevented, but not forced if no saving is actually required + this.mustNotSave = !unloadEvent.isSaveChunk(); -+ } -+ + } + + @Override + public boolean isUnsaved() { + return super.isUnsaved() && !this.mustNotSave; @@ -264,3 +268,22 @@ this.ticker = blockentityticker; } +@@ -855,6 +935,7 @@ + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push(this::getType); ++ this.blockEntity.tickTimer.startTiming(); // Spigot + BlockState iblockdata = LevelChunk.this.getBlockState(blockposition); + + if (this.blockEntity.getType().isValid(iblockdata)) { +@@ -872,6 +953,10 @@ + + this.blockEntity.fillCrashReportCategory(crashreportsystemdetails); + throw new ReportedException(crashreport); ++ // Spigot start ++ } finally { ++ this.blockEntity.tickTimer.stopTiming(); ++ // Spigot end + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch index 132fde3257..50f18dbd4f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch @@ -132,7 +132,31 @@ return nbttagcompound; } -@@ -623,6 +649,12 @@ +@@ -550,12 +576,15 @@ + @Nullable + private static LevelChunk.PostLoadProcessor postLoadChunk(ServerLevel world, List<CompoundTag> entities, List<CompoundTag> blockEntities) { + return entities.isEmpty() && blockEntities.isEmpty() ? null : (chunk) -> { ++ world.timings.syncChunkLoadEntitiesTimer.startTiming(); // Spigot + if (!entities.isEmpty()) { + world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(entities, world, EntitySpawnReason.LOAD)); + } ++ world.timings.syncChunkLoadEntitiesTimer.stopTiming(); // Spigot + + Iterator iterator = blockEntities.iterator(); + ++ world.timings.syncChunkLoadTileEntitiesTimer.startTiming(); // Spigot + while (iterator.hasNext()) { + CompoundTag nbttagcompound = (CompoundTag) iterator.next(); + boolean flag = nbttagcompound.getBoolean("keepPacked"); +@@ -571,6 +600,7 @@ + } + } + } ++ world.timings.syncChunkLoadTileEntitiesTimer.stopTiming(); // Spigot + + }; + } +@@ -623,6 +653,12 @@ StructureStart structurestart = StructureStart.loadStaticStart(context, nbttagcompound1.getCompound(s), worldSeed); if (structurestart != null) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 493c31f046..cb043b6da8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -2568,6 +2568,11 @@ public final class CraftServer implements Server { private final org.bukkit.Server.Spigot spigot = new org.bukkit.Server.Spigot() { + @Override + public YamlConfiguration getConfig() + { + return org.spigotmc.SpigotConfig.config; + } }; public org.bukkit.Server.Spigot spigot() diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java b/paper-server/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java new file mode 100644 index 0000000000..8b19596e77 --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java @@ -0,0 +1,160 @@ +package org.bukkit.craftbukkit; + +import java.util.HashMap; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.storage.PrimaryLevelData; +import org.bukkit.craftbukkit.scheduler.CraftTask; +import org.bukkit.plugin.java.JavaPluginLoader; +import org.bukkit.scheduler.BukkitTask; +import org.spigotmc.CustomTimingsHandler; + +public class SpigotTimings { + + public static final CustomTimingsHandler serverTickTimer = new CustomTimingsHandler("** Full Server Tick"); + public static final CustomTimingsHandler playerListTimer = new CustomTimingsHandler("Player List"); + public static final CustomTimingsHandler commandFunctionsTimer = new CustomTimingsHandler("Command Functions"); + public static final CustomTimingsHandler connectionTimer = new CustomTimingsHandler("Connection Handler"); + public static final CustomTimingsHandler playerConnectionTimer = new CustomTimingsHandler("** PlayerConnection"); + public static final CustomTimingsHandler tickablesTimer = new CustomTimingsHandler("Tickables"); + public static final CustomTimingsHandler schedulerTimer = new CustomTimingsHandler("Scheduler"); + public static final CustomTimingsHandler timeUpdateTimer = new CustomTimingsHandler("Time Update"); + public static final CustomTimingsHandler serverCommandTimer = new CustomTimingsHandler("Server Command"); + public static final CustomTimingsHandler worldSaveTimer = new CustomTimingsHandler("World Save"); + + public static final CustomTimingsHandler entityMoveTimer = new CustomTimingsHandler("** entityMove"); + public static final CustomTimingsHandler tickEntityTimer = new CustomTimingsHandler("** tickEntity"); + public static final CustomTimingsHandler activatedEntityTimer = new CustomTimingsHandler("** activatedTickEntity"); + public static final CustomTimingsHandler tickTileEntityTimer = new CustomTimingsHandler("** tickTileEntity"); + + public static final CustomTimingsHandler timerEntityBaseTick = new CustomTimingsHandler("** livingEntityBaseTick"); + public static final CustomTimingsHandler timerEntityAI = new CustomTimingsHandler("** livingEntityAI"); + public static final CustomTimingsHandler timerEntityAICollision = new CustomTimingsHandler("** livingEntityAICollision"); + public static final CustomTimingsHandler timerEntityAIMove = new CustomTimingsHandler("** livingEntityAIMove"); + public static final CustomTimingsHandler timerEntityTickRest = new CustomTimingsHandler("** livingEntityTickRest"); + + public static final CustomTimingsHandler processQueueTimer = new CustomTimingsHandler("processQueue"); + public static final CustomTimingsHandler schedulerSyncTimer = new CustomTimingsHandler("** Scheduler - Sync Tasks", JavaPluginLoader.pluginParentTimer); + + public static final CustomTimingsHandler playerCommandTimer = new CustomTimingsHandler("** playerCommand"); + + public static final HashMap<String, CustomTimingsHandler> entityTypeTimingMap = new HashMap<String, CustomTimingsHandler>(); + public static final HashMap<String, CustomTimingsHandler> tileEntityTypeTimingMap = new HashMap<String, CustomTimingsHandler>(); + public static final HashMap<String, CustomTimingsHandler> pluginTaskTimingMap = new HashMap<String, CustomTimingsHandler>(); + + /** + * Gets a timer associated with a plugins tasks. + * @param task + * @param period + * @return + */ + public static CustomTimingsHandler getPluginTaskTimings(BukkitTask task, long period) { + if (!task.isSync()) { + return null; + } + String plugin; + final CraftTask ctask = (CraftTask) task; + + if (task.getOwner() != null) { + plugin = task.getOwner().getDescription().getFullName(); + } else { + plugin = "Unknown"; + } + String taskname = ctask.getTaskName(); + + String name = "Task: " + plugin + " Runnable: " + taskname; + if (period > 0) { + name += "(interval:" + period + ")"; + } else { + name += "(Single)"; + } + CustomTimingsHandler result = SpigotTimings.pluginTaskTimingMap.get(name); + if (result == null) { + result = new CustomTimingsHandler(name, SpigotTimings.schedulerSyncTimer); + SpigotTimings.pluginTaskTimingMap.put(name, result); + } + return result; + } + + /** + * Get a named timer for the specified entity type to track type specific timings. + * @param entity + * @return + */ + public static CustomTimingsHandler getEntityTimings(Entity entity) { + String entityType = entity.getClass().getName(); + CustomTimingsHandler result = SpigotTimings.entityTypeTimingMap.get(entityType); + if (result == null) { + result = new CustomTimingsHandler("** tickEntity - " + entity.getClass().getSimpleName(), SpigotTimings.activatedEntityTimer); + SpigotTimings.entityTypeTimingMap.put(entityType, result); + } + return result; + } + + /** + * Get a named timer for the specified tile entity type to track type specific timings. + * @param entity + * @return + */ + public static CustomTimingsHandler getTileEntityTimings(BlockEntity entity) { + String entityType = entity.getClass().getName(); + CustomTimingsHandler result = SpigotTimings.tileEntityTypeTimingMap.get(entityType); + if (result == null) { + result = new CustomTimingsHandler("** tickTileEntity - " + entity.getClass().getSimpleName(), SpigotTimings.tickTileEntityTimer); + SpigotTimings.tileEntityTypeTimingMap.put(entityType, result); + } + return result; + } + + /** + * Set of timers per world, to track world specific timings. + */ + public static class WorldTimingsHandler { + public final CustomTimingsHandler mobSpawn; + public final CustomTimingsHandler doChunkUnload; + public final CustomTimingsHandler doTickPending; + public final CustomTimingsHandler doTickTiles; + public final CustomTimingsHandler doChunkMap; + public final CustomTimingsHandler doSounds; + public final CustomTimingsHandler entityTick; + public final CustomTimingsHandler tileEntityTick; + public final CustomTimingsHandler tileEntityPending; + public final CustomTimingsHandler tracker; + public final CustomTimingsHandler doTick; + public final CustomTimingsHandler tickEntities; + + public final CustomTimingsHandler syncChunkLoadTimer; + public final CustomTimingsHandler syncChunkLoadStructuresTimer; + public final CustomTimingsHandler syncChunkLoadEntitiesTimer; + public final CustomTimingsHandler syncChunkLoadTileEntitiesTimer; + public final CustomTimingsHandler syncChunkLoadTileTicksTimer; + public final CustomTimingsHandler syncChunkLoadPostTimer; + + public WorldTimingsHandler(Level server) { + String name = ((PrimaryLevelData) server.levelData).getLevelName() + " - "; + + this.mobSpawn = new CustomTimingsHandler("** " + name + "mobSpawn"); + this.doChunkUnload = new CustomTimingsHandler("** " + name + "doChunkUnload"); + this.doTickPending = new CustomTimingsHandler("** " + name + "doTickPending"); + this.doTickTiles = new CustomTimingsHandler("** " + name + "doTickTiles"); + this.doChunkMap = new CustomTimingsHandler("** " + name + "doChunkMap"); + this.doSounds = new CustomTimingsHandler("** " + name + "doSounds"); + this.entityTick = new CustomTimingsHandler("** " + name + "entityTick"); + this.tileEntityTick = new CustomTimingsHandler("** " + name + "tileEntityTick"); + this.tileEntityPending = new CustomTimingsHandler("** " + name + "tileEntityPending"); + + this.syncChunkLoadTimer = new CustomTimingsHandler("** " + name + "syncChunkLoad"); + this.syncChunkLoadStructuresTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Structures"); + this.syncChunkLoadEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Entities"); + this.syncChunkLoadTileEntitiesTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileEntities"); + this.syncChunkLoadTileTicksTimer = new CustomTimingsHandler("** " + name + "chunkLoad - TileTicks"); + this.syncChunkLoadPostTimer = new CustomTimingsHandler("** " + name + "chunkLoad - Post"); + + + this.tracker = new CustomTimingsHandler(name + "tracker"); + this.doTick = new CustomTimingsHandler(name + "doTick"); + this.tickEntities = new CustomTimingsHandler(name + "tickEntities"); + } + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/paper-server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java index 9848d420e8..a25ccafc86 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java @@ -411,7 +411,9 @@ public class CraftScheduler implements BukkitScheduler { if (task.isSync()) { this.currentTask = task; try { + task.timings.startTiming(); // Spigot task.run(); + task.timings.stopTiming(); // Spigot } catch (final Throwable throwable) { task.getOwner().getLogger().log( Level.WARNING, diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/paper-server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java index f4265b178c..e4d1eb4a0c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java @@ -5,7 +5,10 @@ import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitTask; -class CraftTask implements BukkitTask, Runnable { +import org.bukkit.craftbukkit.SpigotTimings; // Spigot +import org.spigotmc.CustomTimingsHandler; // Spigot + +public class CraftTask implements BukkitTask, Runnable { // Spigot private volatile CraftTask next = null; public static final int ERROR = 0; @@ -29,6 +32,7 @@ class CraftTask implements BukkitTask, Runnable { private final int id; private final long createdAt = System.nanoTime(); + final CustomTimingsHandler timings; // Spigot CraftTask() { this(null, null, CraftTask.NO_REPEATING, CraftTask.NO_REPEATING); } @@ -54,6 +58,7 @@ class CraftTask implements BukkitTask, Runnable { } this.id = id; this.period = period; + this.timings = this.isSync() ? SpigotTimings.getPluginTaskTimings(this, period) : null; // Spigot } @Override @@ -131,4 +136,10 @@ class CraftTask implements BukkitTask, Runnable { this.setPeriod(CraftTask.CANCEL); return true; } + + // Spigot start + public String getTaskName() { + return (this.getTaskClass() == null) ? "Unknown" : this.getTaskClass().getName(); + } + // Spigot end }