diff options
author | Jake Potrebic <[email protected]> | 2024-06-13 10:12:48 -0700 |
---|---|---|
committer | Jake Potrebic <[email protected]> | 2024-06-13 10:12:48 -0700 |
commit | 8a37f93925f5a0274745f81bb6d4ee8473551abf (patch) | |
tree | 5862d5be3fabfa84ab538d983e3daaddfb59b858 /patches/server/0023-Timings-v2.patch | |
parent | 7fbb8278e70c1904e09f2144f0e3897468a4906f (diff) | |
download | Paper-8a37f93925f5a0274745f81bb6d4ee8473551abf.tar.gz Paper-8a37f93925f5a0274745f81bb6d4ee8473551abf.zip |
62
Diffstat (limited to 'patches/server/0023-Timings-v2.patch')
-rw-r--r-- | patches/server/0023-Timings-v2.patch | 2097 |
1 files changed, 2097 insertions, 0 deletions
diff --git a/patches/server/0023-Timings-v2.patch b/patches/server/0023-Timings-v2.patch new file mode 100644 index 0000000000..74a61a6b4a --- /dev/null +++ b/patches/server/0023-Timings-v2.patch @@ -0,0 +1,2097 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar <[email protected]> +Date: Thu, 3 Mar 2016 04:00:11 -0600 +Subject: [PATCH] Timings v2 + + +diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4bd813161a5d76a83cdbd0a9209b9ea9e60ffe1b +--- /dev/null ++++ b/src/main/java/co/aikar/timings/MinecraftTimings.java +@@ -0,0 +1,169 @@ ++package co.aikar.timings; ++ ++import com.google.common.collect.MapMaker; ++import io.papermc.paper.configuration.GlobalConfiguration; ++import net.minecraft.commands.functions.CommandFunction; ++import net.minecraft.network.protocol.Packet; ++import net.minecraft.world.level.block.Block; ++import net.minecraft.world.level.block.entity.BlockEntity; ++import org.bukkit.plugin.Plugin; ++import org.bukkit.scheduler.BukkitTask; ++ ++import org.bukkit.craftbukkit.scheduler.CraftTask; ++ ++import java.util.Map; ++ ++// TODO: Re-implement missing timers ++@Deprecated(forRemoval = true) ++public final class MinecraftTimings { ++ ++ public static final Timing serverOversleep = Timings.ofSafe("Server Oversleep"); ++ public static final Timing playerListTimer = Timings.ofSafe("Player List"); ++ public static final Timing commandFunctionsTimer = Timings.ofSafe("Command Functions"); ++ public static final Timing connectionTimer = Timings.ofSafe("Connection Handler"); ++ public static final Timing tickablesTimer = Timings.ofSafe("Tickables"); ++ public static final Timing minecraftSchedulerTimer = Timings.ofSafe("Minecraft Scheduler"); ++ public static final Timing bukkitSchedulerTimer = Timings.ofSafe("Bukkit Scheduler"); ++ public static final Timing bukkitSchedulerPendingTimer = Timings.ofSafe("Bukkit Scheduler - Pending"); ++ public static final Timing bukkitSchedulerFinishTimer = Timings.ofSafe("Bukkit Scheduler - Finishing"); ++ public static final Timing chunkIOTickTimer = Timings.ofSafe("ChunkIOTick"); ++ public static final Timing timeUpdateTimer = Timings.ofSafe("Time Update"); ++ public static final Timing serverCommandTimer = Timings.ofSafe("Server Command"); ++ public static final Timing savePlayers = Timings.ofSafe("Save Players"); ++ ++ public static final Timing tickEntityTimer = Timings.ofSafe("## tickEntity"); ++ public static final Timing tickTileEntityTimer = Timings.ofSafe("## tickTileEntity"); ++ public static final Timing packetProcessTimer = Timings.ofSafe("## Packet Processing"); ++ public static final Timing scheduledBlocksTimer = Timings.ofSafe("## Scheduled Blocks"); ++ public static final Timing structureGenerationTimer = Timings.ofSafe("Structure Generation"); ++ ++ public static final Timing processQueueTimer = Timings.ofSafe("processQueue"); ++ public static final Timing processTasksTimer = Timings.ofSafe("processTasks"); ++ ++ public static final Timing playerCommandTimer = Timings.ofSafe("playerCommand"); ++ ++ public static final Timing entityActivationCheckTimer = Timings.ofSafe("entityActivationCheck"); ++ ++ public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update"); ++ public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate"); ++ ++ private static final Map<Class<?>, String> taskNameCache = new MapMaker().weakKeys().makeMap(); ++ ++ private MinecraftTimings() {} ++ ++ public static Timing getInternalTaskName(String taskName) { ++ return Timings.ofSafe(taskName); ++ } ++ ++ /** ++ * Gets a timer associated with a plugins tasks. ++ * @param bukkitTask ++ * @param period ++ * @return ++ */ ++ public static Timing getPluginTaskTimings(BukkitTask bukkitTask, long period) { ++ if (!bukkitTask.isSync()) { ++ return NullTimingHandler.NULL; ++ } ++ Plugin plugin; ++ ++ CraftTask craftTask = (CraftTask) bukkitTask; ++ ++ final Class<?> taskClass = craftTask.getTaskClass(); ++ if (bukkitTask.getOwner() != null) { ++ plugin = bukkitTask.getOwner(); ++ } else { ++ plugin = TimingsManager.getPluginByClassloader(taskClass); ++ } ++ ++ final String taskname = taskNameCache.computeIfAbsent(taskClass, clazz -> { ++ try { ++ String clsName = !clazz.isMemberClass() ++ ? clazz.getName() ++ : clazz.getCanonicalName(); ++ if (clsName != null && clsName.contains("$Lambda$")) { ++ clsName = clsName.replaceAll("(Lambda\\$.*?)/.*", "$1"); ++ } ++ return clsName != null ? clsName : "UnknownTask"; ++ } catch (Throwable ex) { ++ new Exception("Error occurred detecting class name", ex).printStackTrace(); ++ return "MangledClassFile"; ++ } ++ }); ++ ++ StringBuilder name = new StringBuilder(64); ++ name.append("Task: ").append(taskname); ++ if (period > 0) { ++ name.append(" (interval:").append(period).append(")"); ++ } else { ++ name.append(" (Single)"); ++ } ++ ++ if (plugin == null) { ++ return Timings.ofSafe(null, name.toString()); ++ } ++ ++ return Timings.ofSafe(plugin, name.toString()); ++ } ++ ++ /** ++ * Get a named timer for the specified entity type to track type specific timings. ++ * @param entityType ++ * @return ++ */ ++ public static Timing getEntityTimings(String entityType, String type) { ++ return Timings.ofSafe("Minecraft", "## tickEntity - " + entityType + " - " + type, tickEntityTimer); ++ } ++ ++ /** ++ * Get a named timer for the specified tile entity type to track type specific timings. ++ * @param entity ++ * @return ++ */ ++ public static Timing getTileEntityTimings(BlockEntity entity) { ++ String entityType = entity.getClass().getName(); ++ return Timings.ofSafe("Minecraft", "## tickTileEntity - " + entityType, tickTileEntityTimer); ++ } ++ public static Timing getCancelTasksTimer() { ++ return Timings.ofSafe("Cancel Tasks"); ++ } ++ public static Timing getCancelTasksTimer(Plugin plugin) { ++ return Timings.ofSafe(plugin, "Cancel Tasks"); ++ } ++ ++ public static void stopServer() { ++ TimingsManager.stopServer(); ++ } ++ ++ public static Timing getBlockTiming(Block block) { ++ return Timings.ofSafe("## Scheduled Block: " + block.toString(), scheduledBlocksTimer); ++ } ++/* ++ public static Timing getStructureTiming(StructureGenerator structureGenerator) { ++ return Timings.ofSafe("Structure Generator - " + structureGenerator.getName(), structureGenerationTimer); ++ }*/ ++ ++ public static Timing getPacketTiming(Packet packet) { ++ return Timings.ofSafe("## Packet - " + packet.getClass().getName(), packetProcessTimer); ++ } ++ ++ public static Timing getCommandFunctionTiming(CommandFunction<?> function) { ++ return Timings.ofSafe("Command Function - " + function.id()); ++ } ++ ++ public static void processConfig(GlobalConfiguration.Timings config) { ++ TimingsManager.url = config.url; ++ if (!TimingsManager.url.endsWith("/")) { ++ TimingsManager.url += "/"; ++ } ++ TimingsManager.privacy = config.serverNamePrivacy; ++ if (!config.hiddenConfigEntries.contains("proxies.velocity.secret")) { ++ config.hiddenConfigEntries.add("proxies.velocity.secret"); ++ } ++ TimingsManager.hiddenConfigs.addAll(config.hiddenConfigEntries); ++ co.aikar.timings.Timings.setVerboseTimingsEnabled(config.verbose); ++ co.aikar.timings.Timings.setTimingsEnabled(config.enabled); ++ co.aikar.timings.Timings.setHistoryInterval(config.historyInterval * 20); ++ co.aikar.timings.Timings.setHistoryLength(config.historyLength * 20); ++ } ++} +diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java +new file mode 100644 +index 0000000000000000000000000000000000000000..49028463ba47e760281545c2f7597e3db8d6c453 +--- /dev/null ++++ b/src/main/java/co/aikar/timings/TimingsExport.java +@@ -0,0 +1,388 @@ ++/* ++ * This file is licensed under the MIT License (MIT). ++ * ++ * Copyright (c) 2014 Daniel Ennis <http://aikar.co> ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++package co.aikar.timings; ++ ++import com.google.common.collect.Sets; ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.text.event.ClickEvent; ++import net.kyori.adventure.text.format.NamedTextColor; ++import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; ++import net.minecraft.server.MinecraftServer; ++import org.apache.commons.lang.StringUtils; ++import org.bukkit.Bukkit; ++import org.bukkit.Material; ++import org.bukkit.configuration.ConfigurationSection; ++import org.bukkit.configuration.MemorySection; ++import org.bukkit.entity.EntityType; ++import org.json.simple.JSONObject; ++import org.json.simple.JSONValue; ++import oshi.SystemInfo; ++import oshi.hardware.HardwareAbstractionLayer; ++ ++import java.io.ByteArrayOutputStream; ++import java.io.IOException; ++import java.io.InputStream; ++import java.io.OutputStream; ++import java.lang.management.ManagementFactory; ++import java.lang.management.OperatingSystemMXBean; ++import java.lang.management.RuntimeMXBean; ++import java.net.HttpURLConnection; ++import java.net.InetAddress; ++import java.net.URL; ++import java.util.List; ++import java.util.Map; ++import java.util.Set; ++import java.util.logging.Level; ++import java.util.zip.GZIPOutputStream; ++ ++import static co.aikar.timings.TimingsManager.HISTORY; ++import static co.aikar.util.JSONUtil.appendObjectData; ++import static co.aikar.util.JSONUtil.createObject; ++import static co.aikar.util.JSONUtil.pair; ++import static co.aikar.util.JSONUtil.toArray; ++import static co.aikar.util.JSONUtil.toArrayMapper; ++import static co.aikar.util.JSONUtil.toObjectMapper; ++import static net.kyori.adventure.text.Component.text; ++ ++@SuppressWarnings({"rawtypes", "SuppressionAnnotation"}) ++@Deprecated(forRemoval = true) ++public class TimingsExport extends Thread { ++ ++ private final TimingsReportListener listeners; ++ private final Map out; ++ private final TimingHistory[] history; ++ private static long lastReport = 0; ++ ++ private TimingsExport(TimingsReportListener listeners, Map out, TimingHistory[] history) { ++ super("Timings paste thread"); ++ this.listeners = listeners; ++ this.out = out; ++ this.history = history; ++ } ++ ++ /** ++ * Checks if any pending reports are being requested, and builds one if needed. ++ */ ++ public static void reportTimings() { ++ if (Timings.requestingReport.isEmpty()) { ++ return; ++ } ++ TimingsReportListener listeners = new TimingsReportListener(Timings.requestingReport); ++ listeners.addConsoleIfNeeded(); ++ ++ Timings.requestingReport.clear(); ++ long now = System.currentTimeMillis(); ++ final long lastReportDiff = now - lastReport; ++ if (lastReportDiff < 60000) { ++ listeners.sendMessage(text("Please wait at least 1 minute in between Timings reports. (" + (int)((60000 - lastReportDiff) / 1000) + " seconds)", NamedTextColor.RED)); ++ listeners.done(); ++ return; ++ } ++ final long lastStartDiff = now - TimingsManager.timingStart; ++ if (lastStartDiff < 180000) { ++ listeners.sendMessage(text("Please wait at least 3 minutes before generating a Timings report. Unlike Timings v1, v2 benefits from longer timings and is not as useful with short timings. (" + (int)((180000 - lastStartDiff) / 1000) + " seconds)", NamedTextColor.RED)); ++ listeners.done(); ++ return; ++ } ++ listeners.sendMessage(text("Preparing Timings Report...", NamedTextColor.GREEN)); ++ lastReport = now; ++ Map parent = createObject( ++ // Get some basic system details about the server ++ pair("version", Bukkit.getVersion()), ++ pair("maxplayers", Bukkit.getMaxPlayers()), ++ pair("start", TimingsManager.timingStart / 1000), ++ pair("end", System.currentTimeMillis() / 1000), ++ pair("online-mode", Bukkit.getServer().getOnlineMode()), ++ pair("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000), ++ pair("datapacks", toArrayMapper(MinecraftServer.getServer().getPackRepository().getSelectedPacks(), pack -> { ++ return PlainTextComponentSerializer.plainText().serialize(PaperAdventure.asAdventure(pack.getChatLink(true))); ++ })) ++ ); ++ if (!TimingsManager.privacy) { ++ appendObjectData(parent, ++ pair("server", Bukkit.getUnsafe().getTimingsServerName()), ++ pair("motd", Bukkit.getServer().getMotd()), ++ pair("icon", Bukkit.getServer().getServerIcon().getData()) ++ ); ++ } ++ ++ final Runtime runtime = Runtime.getRuntime(); ++ RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); ++ ++ OperatingSystemMXBean osInfo = ManagementFactory.getOperatingSystemMXBean(); ++ ++ HardwareAbstractionLayer hardwareInfo = new SystemInfo().getHardware(); ++ ++ parent.put("system", createObject( ++ pair("timingcost", getCost()), ++ pair("loadavg", osInfo.getSystemLoadAverage()), ++ pair("name", System.getProperty("os.name")), ++ pair("version", System.getProperty("os.version")), ++ pair("jvmversion", System.getProperty("java.version")), ++ pair("jvmvendor", System.getProperty("java.vendor")), ++ pair("jvmvendorversion", System.getProperty("java.vendor.version")), ++ pair("arch", System.getProperty("os.arch")), ++ pair("maxmem", runtime.maxMemory()), ++ pair("memory", createObject( ++ pair("heap", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().toString()), ++ pair("nonheap", ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().toString()), ++ pair("finalizing", ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount()) ++ )), ++ pair("cpu", runtime.availableProcessors()), ++ pair("cpuname", hardwareInfo.getProcessor().getProcessorIdentifier().getName().trim()), ++ pair("runtime", runtimeBean.getUptime()), ++ pair("flags", StringUtils.join(runtimeBean.getInputArguments(), " ")), ++ pair("gc", toObjectMapper(ManagementFactory.getGarbageCollectorMXBeans(), input -> pair(input.getName(), toArray(input.getCollectionCount(), input.getCollectionTime())))) ++ ) ++ ); ++ ++ parent.put("worlds", toObjectMapper(MinecraftServer.getServer().getAllLevels(), world -> { ++ if (world.getWorld().getName().equals("worldeditregentempworld")) return null; ++ return pair(world.getWorld().getName(), createObject( ++ pair("gamerules", toObjectMapper(world.getWorld().getGameRules(), rule -> { ++ return pair(rule, world.getWorld().getGameRuleValue(rule)); ++ })), ++ pair("ticking-distance", world.getWorld().getSimulationDistance()), ++ pair("no-ticking-distance", world.getWorld().getViewDistance()), ++ pair("sending-distance", world.getWorld().getSendViewDistance()) ++ )); ++ })); ++ ++ Set<Material> tileEntityTypeSet = Sets.newHashSet(); ++ Set<EntityType> entityTypeSet = Sets.newHashSet(); ++ ++ int size = HISTORY.size(); ++ TimingHistory[] history = new TimingHistory[size + 1]; ++ int i = 0; ++ for (TimingHistory timingHistory : HISTORY) { ++ tileEntityTypeSet.addAll(timingHistory.tileEntityTypeSet); ++ entityTypeSet.addAll(timingHistory.entityTypeSet); ++ history[i++] = timingHistory; ++ } ++ ++ history[i] = new TimingHistory(); // Current snapshot ++ tileEntityTypeSet.addAll(history[i].tileEntityTypeSet); ++ entityTypeSet.addAll(history[i].entityTypeSet); ++ ++ ++ Map handlers = createObject(); ++ Map groupData; ++ synchronized (TimingIdentifier.GROUP_MAP) { ++ for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) { ++ synchronized (group.handlers) { ++ for (TimingHandler id : group.handlers) { ++ ++ if (!id.isTimed() && !id.isSpecial()) { ++ continue; ++ } ++ ++ String name = id.identifier.name; ++ if (name.startsWith("##")) { ++ name = name.substring(3); ++ } ++ handlers.put(id.id, toArray( ++ group.id, ++ name ++ )); ++ } ++ } ++ } ++ ++ groupData = toObjectMapper( ++ TimingIdentifier.GROUP_MAP.values(), group -> pair(group.id, group.name)); ++ } ++ ++ parent.put("idmap", createObject( ++ pair("groups", groupData), ++ pair("handlers", handlers), ++ pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), input -> pair(input.getValue(), input.getKey()))), ++ pair("tileentity", ++ toObjectMapper(tileEntityTypeSet, input -> pair(input.ordinal(), input.name()))), ++ pair("entity", ++ toObjectMapper(entityTypeSet, input -> pair(input.ordinal(), input.name()))) ++ )); ++ ++ // Information about loaded plugins ++ ++ parent.put("plugins", toObjectMapper(Bukkit.getPluginManager().getPlugins(), ++ plugin -> pair(plugin.getName(), createObject( ++ pair("version", plugin.getDescription().getVersion()), ++ pair("description", String.valueOf(plugin.getDescription().getDescription()).trim()), ++ pair("website", plugin.getDescription().getWebsite()), ++ pair("authors", StringUtils.join(plugin.getDescription().getAuthors(), ", ")) ++ )))); ++ ++ ++ ++ // Information on the users Config ++ ++ parent.put("config", createObject( ++ pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), ++ pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), ++ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)) ++ )); ++ ++ new TimingsExport(listeners, parent, history).start(); ++ } ++ ++ static long getCost() { ++ // Benchmark the users System.nanotime() for cost basis ++ int passes = 100; ++ TimingHandler SAMPLER1 = Timings.ofSafe("Timings Sampler 1"); ++ TimingHandler SAMPLER2 = Timings.ofSafe("Timings Sampler 2"); ++ TimingHandler SAMPLER3 = Timings.ofSafe("Timings Sampler 3"); ++ TimingHandler SAMPLER4 = Timings.ofSafe("Timings Sampler 4"); ++ TimingHandler SAMPLER5 = Timings.ofSafe("Timings Sampler 5"); ++ TimingHandler SAMPLER6 = Timings.ofSafe("Timings Sampler 6"); ++ ++ long start = System.nanoTime(); ++ for (int i = 0; i < passes; i++) { ++ SAMPLER1.startTiming(); ++ SAMPLER2.startTiming(); ++ SAMPLER3.startTiming(); ++ SAMPLER3.stopTiming(); ++ SAMPLER4.startTiming(); ++ SAMPLER5.startTiming(); ++ SAMPLER6.startTiming(); ++ SAMPLER6.stopTiming(); ++ SAMPLER5.stopTiming(); ++ SAMPLER4.stopTiming(); ++ SAMPLER2.stopTiming(); ++ SAMPLER1.stopTiming(); ++ } ++ long timingsCost = (System.nanoTime() - start) / passes / 6; ++ SAMPLER1.reset(true); ++ SAMPLER2.reset(true); ++ SAMPLER3.reset(true); ++ SAMPLER4.reset(true); ++ SAMPLER5.reset(true); ++ SAMPLER6.reset(true); ++ return timingsCost; ++ } ++ ++ private static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) { ++ ++ JSONObject object = new JSONObject(); ++ for (String key : config.getKeys(false)) { ++ String fullKey = (parentKey != null ? parentKey + "." + key : key); ++ if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld")) { ++ continue; ++ } ++ final Object val = config.get(key); ++ ++ object.put(key, valAsJSON(val, fullKey)); ++ } ++ return object; ++ } ++ ++ private static Object valAsJSON(Object val, final String parentKey) { ++ if (!(val instanceof MemorySection)) { ++ if (val instanceof List) { ++ Iterable<Object> v = (Iterable<Object>) val; ++ return toArrayMapper(v, input -> valAsJSON(input, parentKey)); ++ } else { ++ return String.valueOf(val); ++ } ++ } else { ++ return mapAsJSON((ConfigurationSection) val, parentKey); ++ } ++ } ++ ++ @Override ++ public void run() { ++ out.put("data", toArrayMapper(history, TimingHistory::export)); ++ ++ ++ String response = null; ++ String timingsURL = null; ++ try { ++ HttpURLConnection con = (HttpURLConnection) new URL(TimingsManager.url + "post").openConnection(); ++ con.setDoOutput(true); ++ String hostName = "BrokenHost"; ++ try { ++ hostName = InetAddress.getLocalHost().getHostName(); ++ } catch (Exception ignored) {} ++ con.setRequestProperty("User-Agent", "Paper/" + Bukkit.getUnsafe().getTimingsServerName() + "/" + hostName); ++ con.setRequestMethod("POST"); ++ con.setInstanceFollowRedirects(false); ++ ++ OutputStream request = new GZIPOutputStream(con.getOutputStream()) {{ ++ this.def.setLevel(7); ++ }}; ++ ++ request.write(JSONValue.toJSONString(out).getBytes("UTF-8")); ++ request.close(); ++ ++ response = getResponse(con); ++ ++ if (con.getResponseCode() != 302) { ++ listeners.sendMessage(text( "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage(), NamedTextColor.RED)); ++ listeners.sendMessage(text("Check your logs for more information", NamedTextColor.RED)); ++ if (response != null) { ++ Bukkit.getLogger().log(Level.SEVERE, response); ++ } ++ return; ++ } ++ ++ timingsURL = con.getHeaderField("Location"); ++ listeners.sendMessage(text("View Timings Report: ", NamedTextColor.GREEN).append(text(timingsURL).clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, timingsURL)))); ++ ++ if (response != null && !response.isEmpty()) { ++ Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response); ++ } ++ } catch (IOException ex) { ++ listeners.sendMessage(text("Error uploading timings, check your logs for more information", NamedTextColor.RED)); ++ if (response != null) { ++ Bukkit.getLogger().log(Level.SEVERE, response); ++ } ++ Bukkit.getLogger().log(Level.SEVERE, "Could not paste timings", ex); ++ } finally { ++ this.listeners.done(timingsURL); ++ } ++ } ++ ++ private String getResponse(HttpURLConnection con) throws IOException { ++ InputStream is = null; ++ try { ++ is = con.getInputStream(); ++ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ++ ++ byte[] b = new byte[1024]; ++ int bytesRead; ++ while ((bytesRead = is.read(b)) != -1) { ++ bos.write(b, 0, bytesRead); ++ } ++ return bos.toString(); ++ ++ } catch (IOException ex) { ++ listeners.sendMessage(text("Error uploading timings, check your logs for more information", NamedTextColor.RED)); ++ Bukkit.getLogger().log(Level.WARNING, con.getResponseMessage(), ex); ++ return null; ++ } finally { ++ if (is != null) { ++ is.close(); ++ } ++ } ++ } ++} +diff --git a/src/main/java/co/aikar/timings/WorldTimingsHandler.java b/src/main/java/co/aikar/timings/WorldTimingsHandler.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2f0d9b953802dee821cfde82d22b0567cce8ee91 +--- /dev/null ++++ b/src/main/java/co/aikar/timings/WorldTimingsHandler.java +@@ -0,0 +1,120 @@ ++package co.aikar.timings; ++ ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.world.level.Level; ++import net.minecraft.world.level.storage.PrimaryLevelData; ++ ++/** ++ * Set of timers per world, to track world specific timings. ++ */ ++// TODO: Re-implement missing timers ++@Deprecated(forRemoval = true) ++public class WorldTimingsHandler { ++ public final Timing mobSpawn; ++ public final Timing doChunkUnload; ++ public final Timing doPortalForcer; ++ public final Timing scheduledBlocks; ++ public final Timing scheduledBlocksCleanup; ++ public final Timing scheduledBlocksTicking; ++ public final Timing chunkTicks; ++ public final Timing lightChunk; ++ public final Timing chunkTicksBlocks; ++ public final Timing doVillages; ++ public final Timing doChunkMap; ++ public final Timing doChunkMapUpdate; ++ public final Timing doChunkMapToUpdate; ++ public final Timing doChunkMapSortMissing; ++ public final Timing doChunkMapSortSendToPlayers; ++ public final Timing doChunkMapPlayersNeedingChunks; ++ public final Timing doChunkMapPendingSendToPlayers; ++ public final Timing doChunkMapUnloadChunks; ++ public final Timing doChunkGC; ++ public final Timing doSounds; ++ public final Timing entityRemoval; ++ public final Timing entityTick; ++ public final Timing tileEntityTick; ++ public final Timing tileEntityPending; ++ public final Timing tracker1; ++ public final Timing tracker2; ++ public final Timing doTick; ++ public final Timing tickEntities; ++ public final Timing chunks; ++ public final Timing newEntities; ++ public final Timing raids; ++ public final Timing chunkProviderTick; ++ public final Timing broadcastChunkUpdates; ++ public final Timing countNaturalMobs; ++ ++ public final Timing chunkLoad; ++ public final Timing chunkLoadPopulate; ++ public final Timing syncChunkLoad; ++ public final Timing chunkLoadLevelTimer; ++ public final Timing chunkIO; ++ public final Timing chunkPostLoad; ++ public final Timing worldSave; ++ public final Timing worldSaveChunks; ++ public final Timing worldSaveLevel; ++ public final Timing chunkSaveData; ++ ++ ++ public final Timing miscMobSpawning; ++ ++ public WorldTimingsHandler(Level server) { ++ String name = ((PrimaryLevelData) server.getLevelData()).getLevelName() + " - "; ++ ++ mobSpawn = Timings.ofSafe(name + "mobSpawn"); ++ doChunkUnload = Timings.ofSafe(name + "doChunkUnload"); ++ scheduledBlocks = Timings.ofSafe(name + "Scheduled Blocks"); ++ scheduledBlocksCleanup = Timings.ofSafe(name + "Scheduled Blocks - Cleanup"); ++ scheduledBlocksTicking = Timings.ofSafe(name + "Scheduled Blocks - Ticking"); ++ chunkTicks = Timings.ofSafe(name + "Chunk Ticks"); ++ lightChunk = Timings.ofSafe(name + "Light Chunk"); ++ chunkTicksBlocks = Timings.ofSafe(name + "Chunk Ticks - Blocks"); ++ doVillages = Timings.ofSafe(name + "doVillages"); ++ doChunkMap = Timings.ofSafe(name + "doChunkMap"); ++ doChunkMapUpdate = Timings.ofSafe(name + "doChunkMap - Update"); ++ doChunkMapToUpdate = Timings.ofSafe(name + "doChunkMap - To Update"); ++ doChunkMapSortMissing = Timings.ofSafe(name + "doChunkMap - Sort Missing"); ++ doChunkMapSortSendToPlayers = Timings.ofSafe(name + "doChunkMap - Sort Send To Players"); ++ doChunkMapPlayersNeedingChunks = Timings.ofSafe(name + "doChunkMap - Players Needing Chunks"); ++ doChunkMapPendingSendToPlayers = Timings.ofSafe(name + "doChunkMap - Pending Send To Players"); ++ doChunkMapUnloadChunks = Timings.ofSafe(name + "doChunkMap - Unload Chunks"); ++ doSounds = Timings.ofSafe(name + "doSounds"); ++ doChunkGC = Timings.ofSafe(name + "doChunkGC"); ++ doPortalForcer = Timings.ofSafe(name + "doPortalForcer"); ++ entityTick = Timings.ofSafe(name + "entityTick"); ++ entityRemoval = Timings.ofSafe(name + "entityRemoval"); ++ tileEntityTick = Timings.ofSafe(name + "tileEntityTick"); ++ tileEntityPending = Timings.ofSafe(name + "tileEntityPending"); ++ ++ chunkLoad = Timings.ofSafe(name + "Chunk Load"); ++ chunkLoadPopulate = Timings.ofSafe(name + "Chunk Load - Populate"); ++ syncChunkLoad = Timings.ofSafe(name + "Sync Chunk Load"); ++ chunkLoadLevelTimer = Timings.ofSafe(name + "Chunk Load - Load Level"); ++ chunkIO = Timings.ofSafe(name + "Chunk Load - DiskIO"); ++ chunkPostLoad = Timings.ofSafe(name + "Chunk Load - Post Load"); ++ worldSave = Timings.ofSafe(name + "World Save"); ++ worldSaveLevel = Timings.ofSafe(name + "World Save - Level"); ++ worldSaveChunks = Timings.ofSafe(name + "World Save - Chunks"); ++ chunkSaveData = Timings.ofSafe(name + "Chunk Save - Data"); ++ ++ tracker1 = Timings.ofSafe(name + "tracker stage 1"); ++ tracker2 = Timings.ofSafe(name + "tracker stage 2"); ++ doTick = Timings.ofSafe(name + "doTick"); ++ tickEntities = Timings.ofSafe(name + "tickEntities"); ++ ++ chunks = Timings.ofSafe(name + "Chunks"); ++ newEntities = Timings.ofSafe(name + "New entity registration"); ++ raids = Timings.ofSafe(name + "Raids"); ++ chunkProviderTick = Timings.ofSafe(name + "Chunk provider tick"); ++ broadcastChunkUpdates = Timings.ofSafe(name + "Broadcast chunk updates"); ++ countNaturalMobs = Timings.ofSafe(name + "Count natural mobs"); ++ ++ ++ miscMobSpawning = Timings.ofSafe(name + "Mob spawning - Misc"); ++ } ++ ++ public static Timing getTickList(ServerLevel worldserver, String timingsType) { ++ return Timings.ofSafe(((PrimaryLevelData) worldserver.getLevelData()).getLevelName() + " - Scheduled " + timingsType); ++ } ++} +diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java +index f7197f1347251a37dd0f6d9ffa2f09bc3a4e1233..d0d36a57ec4896bcb74970f8fb24d8f3e17db133 100644 +--- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java ++++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java +@@ -31,7 +31,8 @@ public class PacketUtils { + engine.executeIfPossible(() -> { + if (listener instanceof ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // CraftBukkit - Don't handle sync packets for kicked players + if (listener.shouldHandleMessage(packet)) { +- try { ++ co.aikar.timings.Timing timing = co.aikar.timings.MinecraftTimings.getPacketTiming(packet); // Paper - timings ++ try (co.aikar.timings.Timing ignored = timing.startTiming()) { // Paper - timings + packet.handle(listener); + } catch (Exception exception) { + if (exception instanceof ReportedException) { +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 202a6510d9d093119ff88b910cef6e47fce2e6b8..4137cf4d716680ff1b1ab0b8a3e8f7cb4bae7dbe 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -196,7 +196,7 @@ import org.bukkit.craftbukkit.Main; + import org.bukkit.event.server.ServerLoadEvent; + // CraftBukkit end + +-import org.bukkit.craftbukkit.SpigotTimings; // Spigot ++import co.aikar.timings.MinecraftTimings; // Paper + + public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements ServerInfo, ChunkIOErrorReporter, CommandSource, AutoCloseable { + +@@ -912,6 +912,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + } + + MinecraftServer.LOGGER.info("Stopping server"); ++ MinecraftTimings.stopServer(); // Paper + // CraftBukkit start + if (this.server != null) { + this.server.disablePlugins(); +@@ -1189,9 +1190,21 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + + private boolean haveTime() { + // CraftBukkit start ++ if (isOversleep) return canOversleep(); // Paper - because of our changes, this logic is broken + return this.forceTicks || this.runningTask() || Util.getNanos() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTimeNanos : this.nextTickTimeNanos); + } + ++ // Paper start ++ boolean isOversleep = false; ++ private boolean canOversleep() { ++ return this.mayHaveDelayedTasks && Util.getNanos() < this.delayedTasksMaxNextTickTimeNanos; ++ } ++ ++ private boolean canSleepForTickNoOversleep() { ++ return this.forceTicks || this.runningTask() || Util.getNanos() < this.nextTickTimeNanos; ++ } ++ // Paper end ++ + private void executeModerately() { + this.runAllTasks(); + java.util.concurrent.locks.LockSupport.parkNanos("executing tasks", 1000L); +@@ -1220,9 +1233,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + } + + protected void waitUntilNextTick() { +- this.runAllTasks(); ++ //this.executeAll(); // Paper - move this into the tick method for timings + this.managedBlock(() -> { +- return !this.haveTime(); ++ return !this.canSleepForTickNoOversleep(); // Paper - move oversleep into full server tick + }); + } + +@@ -1323,9 +1336,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + } + + public void tickServer(BooleanSupplier shouldKeepTicking) { +- SpigotTimings.serverTickTimer.startTiming(); // Spigot ++ co.aikar.timings.TimingsManager.FULL_SERVER_TICK.startTiming(); // Paper + long i = Util.getNanos(); + ++ // Paper start - move oversleep into full server tick ++ isOversleep = true;MinecraftTimings.serverOversleep.startTiming(); ++ this.managedBlock(() -> { ++ return !this.canOversleep(); ++ }); ++ isOversleep = false;MinecraftTimings.serverOversleep.stopTiming(); ++ // Paper end ++ + ++this.tickCount; + this.tickRateManager.tick(); + this.tickChildren(shouldKeepTicking); +@@ -1339,15 +1360,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + if (this.autosavePeriod > 0 && this.ticksUntilAutosave <= 0) { + this.ticksUntilAutosave = this.autosavePeriod; + // CraftBukkit end +- SpigotTimings.worldSaveTimer.startTiming(); // Spigot + MinecraftServer.LOGGER.debug("Autosave started"); + this.profiler.push("save"); + this.saveEverything(true, false, false); + this.profiler.pop(); + MinecraftServer.LOGGER.debug("Autosave finished"); +- SpigotTimings.worldSaveTimer.stopTiming(); // Spigot + } + io.papermc.paper.util.CachedLists.reset(); // Paper ++ // Paper start - move executeAll() into full server tick timing ++ try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) { ++ this.runAllTasks(); ++ } ++ // Paper end + this.profiler.push("tallying"); + long j = Util.getNanos() - i; + int k = this.tickCount % 100; +@@ -1359,8 +1383,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + this.logTickMethodTime(i); + this.profiler.pop(); + org.spigotmc.WatchdogThread.tick(); // Spigot +- SpigotTimings.serverTickTimer.stopTiming(); // Spigot +- org.spigotmc.CustomTimingsHandler.tick(); // Spigot ++ co.aikar.timings.TimingsManager.FULL_SERVER_TICK.stopTiming(); // Paper + } + + private void logTickMethodTime(long tickStartTime) { +@@ -1431,26 +1454,26 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + this.getPlayerList().getPlayers().forEach((entityplayer) -> { + entityplayer.connection.suspendFlushing(); + }); +- SpigotTimings.schedulerTimer.startTiming(); // Spigot ++ MinecraftTimings.bukkitSchedulerTimer.startTiming(); // Spigot // Paper + this.server.getScheduler().mainThreadHeartbeat(this.tickCount); // CraftBukkit +- SpigotTimings.schedulerTimer.stopTiming(); // Spigot ++ MinecraftTimings.bukkitSchedulerTimer.stopTiming(); // Spigot // Paper + io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper + this.profiler.push("commandFunctions"); +- SpigotTimings.commandFunctionsTimer.startTiming(); // Spigot ++ MinecraftTimings.commandFunctionsTimer.startTiming(); // Spigot // Paper + this.getFunctions().tick(); +- SpigotTimings.commandFunctionsTimer.stopTiming(); // Spigot ++ MinecraftTimings.commandFunctionsTimer.stopTiming(); // Spigot // Paper + this.profiler.popPush("levels"); + Iterator iterator = this.getAllLevels().iterator(); + + // CraftBukkit start + // Run tasks that are waiting on processing +- SpigotTimings.processQueueTimer.startTiming(); // Spigot ++ MinecraftTimings.processQueueTimer.startTiming(); // Spigot + while (!this.processQueue.isEmpty()) { + this.processQueue.remove().run(); + } +- SpigotTimings.processQueueTimer.stopTiming(); // Spigot ++ MinecraftTimings.processQueueTimer.stopTiming(); // Spigot + +- SpigotTimings.timeUpdateTimer.startTiming(); // Spigot ++ MinecraftTimings.timeUpdateTimer.startTiming(); // Spigot // Paper + // 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) { +@@ -1458,7 +1481,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + entityplayer.connection.send(new ClientboundSetTimePacket(entityplayer.level().getGameTime(), entityplayer.getPlayerTime(), entityplayer.level().getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); // Add support for per player time + } + } +- SpigotTimings.timeUpdateTimer.stopTiming(); // Spigot ++ MinecraftTimings.timeUpdateTimer.stopTiming(); // Spigot // Paper + + while (iterator.hasNext()) { + ServerLevel worldserver = (ServerLevel) iterator.next(); +@@ -1499,24 +1522,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + } + + this.profiler.popPush("connection"); +- SpigotTimings.connectionTimer.startTiming(); // Spigot ++ MinecraftTimings.connectionTimer.startTiming(); // Spigot // Paper + this.getConnection().tick(); +- SpigotTimings.connectionTimer.stopTiming(); // Spigot ++ MinecraftTimings.connectionTimer.stopTiming(); // Spigot // Paper + this.profiler.popPush("players"); +- SpigotTimings.playerListTimer.startTiming(); // Spigot ++ MinecraftTimings.playerListTimer.startTiming(); // Spigot // Paper + this.playerList.tick(); +- SpigotTimings.playerListTimer.stopTiming(); // Spigot ++ MinecraftTimings.playerListTimer.stopTiming(); // Spigot // Paper + if (SharedConstants.IS_RUNNING_IN_IDE && this.tickRateManager.runsNormally()) { + GameTestTicker.SINGLETON.tick(); + } + + this.profiler.popPush("server gui refresh"); + +- SpigotTimings.tickablesTimer.startTiming(); // Spigot ++ MinecraftTimings.tickablesTimer.startTiming(); // Spigot // Paper + for (int i = 0; i < this.tickables.size(); ++i) { + ((Runnable) this.tickables.get(i)).run(); + } +- SpigotTimings.tickablesTimer.stopTiming(); // Spigot ++ MinecraftTimings.tickablesTimer.stopTiming(); // Spigot // Paper + + this.profiler.popPush("send chunks"); + iterator = this.playerList.getPlayers().iterator(); +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index d38ecbc208c34509eaf77751ac45d9ef51a5dce8..b51c3f8c485496734ea58c15377a1215a334c765 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -65,10 +65,11 @@ import org.apache.logging.log4j.Level; + 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 co.aikar.timings.MinecraftTimings; // Paper + import org.bukkit.craftbukkit.util.TerminalCompletionHandler; + import org.bukkit.craftbukkit.util.TerminalConsoleWriterThread; + import org.bukkit.event.server.ServerCommandEvent; ++import org.bukkit.craftbukkit.util.Waitable; // Paper + import org.bukkit.event.server.RemoteServerCommandEvent; + // CraftBukkit end + +@@ -439,7 +440,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + } + + public void handleConsoleInputs() { +- SpigotTimings.serverCommandTimer.startTiming(); // Spigot ++ MinecraftTimings.serverCommandTimer.startTiming(); // Spigot + while (!this.consoleInput.isEmpty()) { + ConsoleInput servercommand = (ConsoleInput) this.consoleInput.remove(0); + +@@ -454,7 +455,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + // CraftBukkit end + } + +- SpigotTimings.serverCommandTimer.stopTiming(); // Spigot ++ MinecraftTimings.serverCommandTimer.stopTiming(); // Spigot + } + + @Override +@@ -712,7 +713,9 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + } + + public String runCommand(RconConsoleSource rconConsoleSource, String s) { ++ Waitable[] waitableArray = new Waitable[1]; // Paper + rconConsoleSource.prepareForCommand(); ++ final java.util.concurrent.atomic.AtomicReference<String> command = new java.util.concurrent.atomic.AtomicReference<>(s); // Paper + this.executeBlocking(() -> { + CommandSourceStack wrapper = rconConsoleSource.createCommandSourceStack(); + RemoteServerCommandEvent event = new RemoteServerCommandEvent(rconConsoleSource.getBukkitSender(wrapper), s); +@@ -720,9 +723,39 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + if (event.isCancelled()) { + return; + } ++ // Paper start ++ command.set(event.getCommand()); ++ if (event.getCommand().toLowerCase(java.util.Locale.ROOT).startsWith("timings") && event.getCommand().toLowerCase(java.util.Locale.ROOT).matches("timings (report|paste|get|merged|seperate)")) { ++ org.bukkit.command.BufferedCommandSender sender = new org.bukkit.command.BufferedCommandSender(); ++ Waitable<String> waitable = new Waitable<>() { ++ @Override ++ protected String evaluate() { ++ return sender.getBuffer(); ++ } ++ }; ++ waitableArray[0] = waitable; ++ co.aikar.timings.Timings.generateReport(new co.aikar.timings.TimingsReportListener(sender, waitable)); ++ } else { ++ // Paper end + ConsoleInput serverCommand = new ConsoleInput(event.getCommand(), wrapper); + this.server.dispatchServerCommand(event.getSender(), serverCommand); ++ } // Paper + }); ++ // Paper start ++ if (waitableArray[0] != null) { ++ //noinspection unchecked ++ Waitable<String> waitable = waitableArray[0]; ++ try { ++ return waitable.get(); ++ } catch (java.util.concurrent.ExecutionException e) { ++ throw new RuntimeException("Exception processing rcon command " + command.get(), e.getCause()); ++ } catch (InterruptedException e) { ++ Thread.currentThread().interrupt(); // Maintain interrupted state ++ throw new RuntimeException("Interrupted processing rcon command " + command.get(), e); ++ } ++ ++ } ++ // Paper end + return rconConsoleSource.getCommandResponse(); + // CraftBukkit end + } +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index ce0d22452171857e3cf070bf01450a7653ec7142..6581566ca4e4fac0691e4f5851f8895d9ac7a38f 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1,8 +1,10 @@ + package net.minecraft.server.level; + ++import co.aikar.timings.Timing; // Paper + import com.google.common.collect.ImmutableList; + import com.google.common.collect.ImmutableList.Builder; + import com.google.common.collect.Iterables; ++import com.google.common.collect.ComparisonChain; // Paper + import com.google.common.collect.Lists; + import com.google.common.collect.Queues; + import com.google.common.collect.Sets; +@@ -1363,6 +1365,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + List<ServerPlayer> list = Lists.newArrayList(); + List<ServerPlayer> list1 = this.level.players(); + ObjectIterator objectiterator = this.entityMap.values().iterator(); ++ level.timings.tracker1.startTiming(); // Paper + + ChunkMap.TrackedEntity playerchunkmap_entitytracker; + +@@ -1387,14 +1390,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + playerchunkmap_entitytracker.serverEntity.sendChanges(); + } + } ++ level.timings.tracker1.stopTiming(); // Paper + + if (!list.isEmpty()) { + objectiterator = this.entityMap.values().iterator(); + ++ level.timings.tracker2.startTiming(); // Paper + while (objectiterator.hasNext()) { + playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); + playerchunkmap_entitytracker.updatePlayers(list); + } ++ level.timings.tracker2.stopTiming(); // Paper + } + + } +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index ff68eff051c5f50b20b26d33001e12741dd3000e..946cf6e186c6b283e705aa9a8cc9726889ebb954 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -269,13 +269,15 @@ public class ServerChunkCache extends ChunkSource { + } + + 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); ++ if (!completablefuture.isDone()) { // Paper ++ this.level.timings.syncChunkLoad.startTiming(); // Paper + chunkproviderserver_b.managedBlock(completablefuture::isDone); +- this.level.timings.syncChunkLoadTimer.stopTiming(); // Spigot ++ this.level.timings.syncChunkLoad.stopTiming(); // Paper ++ } // Paper + ChunkResult<ChunkAccess> chunkresult = (ChunkResult) completablefuture.join(); + ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error + +@@ -440,7 +442,9 @@ public class ServerChunkCache extends ChunkSource { + + public void save(boolean flush) { + this.runDistanceManagerUpdates(); ++ try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings + this.chunkMap.saveAllChunks(flush); ++ } // Paper - Timings + } + + @Override +@@ -482,10 +486,10 @@ public class ServerChunkCache extends ChunkSource { + this.level.timings.doChunkMap.stopTiming(); // Spigot + this.level.getProfiler().popPush("chunks"); + if (tickChunks) { ++ this.level.timings.chunks.startTiming(); // Paper - timings + this.tickChunks(); +- this.level.timings.tracker.startTiming(); // Spigot ++ this.level.timings.chunks.stopTiming(); // Paper - timings + this.chunkMap.tick(); +- this.level.timings.tracker.stopTiming(); // Spigot + } + + this.level.timings.doChunkUnload.startTiming(); // Spigot +@@ -508,6 +512,7 @@ public class ServerChunkCache extends ChunkSource { + gameprofilerfiller.push("filteringLoadedChunks"); + List<ServerChunkCache.ChunkAndHolder> list = Lists.newArrayListWithCapacity(this.chunkMap.size()); + Iterator iterator = this.chunkMap.getChunks().iterator(); ++ if (this.level.getServer().tickRateManager().runsNormally()) this.level.timings.chunkTicks.startTiming(); // Paper + + while (iterator.hasNext()) { + ChunkHolder playerchunk = (ChunkHolder) iterator.next(); +@@ -520,8 +525,10 @@ public class ServerChunkCache extends ChunkSource { + + if (this.level.tickRateManager().runsNormally()) { + gameprofilerfiller.popPush("naturalSpawnCount"); ++ this.level.timings.countNaturalMobs.startTiming(); // Paper - timings + int k = this.distanceManager.getNaturalSpawnChunkCount(); + NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(k, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap)); ++ this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings + + this.lastSpawnState = spawnercreature_d; + gameprofilerfiller.popPush("spawnAndTick"); +@@ -544,22 +551,25 @@ public class ServerChunkCache extends ChunkSource { + } + + if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { +- this.level.timings.doTickTiles.startTiming(); // Spigot + this.level.tickChunk(chunk1, l); +- this.level.timings.doTickTiles.stopTiming(); // Spigot + } + } + } ++ this.level.timings.chunkTicks.stopTiming(); // Paper + + gameprofilerfiller.popPush("customSpawners"); + if (flag) { ++ try (co.aikar.timings.Timing ignored = this.level.timings.miscMobSpawning.startTiming()) { // Paper - timings + this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies); ++ } // Paper - timings + } + } + + gameprofilerfiller.popPush("broadcast"); + list.forEach((chunkproviderserver_a1) -> { ++ this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing + chunkproviderserver_a1.holder.broadcastChanges(chunkproviderserver_a1.chunk); ++ this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing + }); + gameprofilerfiller.pop(); + gameprofilerfiller.pop(); +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index eea8bafd98e3a8d82b3216488537ab898cc4ae7a..9675d91e4e7ed46147c3f7a11dd65122fe998dc2 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1,6 +1,8 @@ + package net.minecraft.server.level; + + import com.google.common.annotations.VisibleForTesting; ++import co.aikar.timings.TimingHistory; // Paper ++import co.aikar.timings.Timings; // Paper + import com.google.common.collect.Lists; + import com.mojang.datafixers.DataFixer; + import com.mojang.datafixers.util.Pair; +@@ -173,7 +175,6 @@ 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; +@@ -478,7 +479,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + + gameprofilerfiller.popPush("tickPending"); +- this.timings.doTickPending.startTiming(); // Spigot ++ this.timings.scheduledBlocks.startTiming(); // Paper + if (!this.isDebug() && flag) { + j = this.getGameTime(); + gameprofilerfiller.push("blockTicks"); +@@ -487,15 +488,19 @@ public class ServerLevel extends Level implements WorldGenLevel { + this.fluidTicks.tick(j, 65536, this::tickFluid); + gameprofilerfiller.pop(); + } +- this.timings.doTickPending.stopTiming(); // Spigot ++ this.timings.scheduledBlocks.stopTiming(); // Paper + + gameprofilerfiller.popPush("raid"); + if (flag) { ++ this.timings.raids.startTiming(); // Paper - timings + this.raids.tick(); ++ this.timings.raids.stopTiming(); // Paper - timings + } + + gameprofilerfiller.popPush("chunkSource"); ++ this.timings.chunkProviderTick.startTiming(); // Paper - timings + this.getChunkSource().tick(shouldKeepTicking, true); ++ this.timings.chunkProviderTick.stopTiming(); // Paper - timings + gameprofilerfiller.popPush("blockEvents"); + if (flag) { + this.timings.doSounds.startTiming(); // Spigot +@@ -648,6 +653,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + + gameprofilerfiller.popPush("tickBlocks"); ++ timings.chunkTicksBlocks.startTiming(); // Paper + if (randomTickSpeed > 0) { + LevelChunkSection[] achunksection = chunk.getSections(); + +@@ -680,6 +686,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + } + ++ timings.chunkTicksBlocks.stopTiming(); // Paper + gameprofilerfiller.pop(); + } + +@@ -956,14 +963,22 @@ public class ServerLevel extends Level implements WorldGenLevel { + } + + public void tickNonPassenger(Entity entity) { ++ ++TimingHistory.entityTicks; // Paper - timings + // Spigot start ++ co.aikar.timings.Timing timer; // Paper + if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { + entity.tickCount++; ++ timer = entity.getType().inactiveTickTimer.startTiming(); try { // Paper - timings + entity.inactiveTick(); ++ } finally { timer.stopTiming(); } // Paper + return; + } + // Spigot end +- entity.tickTimer.startTiming(); // Spigot ++ // Paper start- timings ++ TimingHistory.activatedEntityTicks++; ++ timer = entity.getVehicle() != null ? entity.getType().passengerTickTimer.startTiming() : entity.getType().tickTimer.startTiming(); ++ try { ++ // Paper end - timings + entity.setOldPosAndRot(); + ProfilerFiller gameprofilerfiller = this.getProfiler(); + +@@ -982,7 +997,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + + this.tickPassenger(entity, entity1); + } +- entity.tickTimer.stopTiming(); // Spigot ++ } finally { timer.stopTiming(); } // Paper - timings + + } + +@@ -1024,6 +1039,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + + if (!savingDisabled) { + org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld())); // CraftBukkit ++ try (co.aikar.timings.Timing ignored = timings.worldSave.startTiming()) { // Paper + if (progressListener != null) { + progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel")); + } +@@ -1033,7 +1049,10 @@ public class ServerLevel extends Level implements WorldGenLevel { + progressListener.progressStage(Component.translatable("menu.savingChunks")); + } + ++ timings.worldSaveChunks.startTiming(); // Paper + chunkproviderserver.save(flush); ++ timings.worldSaveChunks.stopTiming(); // Paper ++ }// Paper + if (flush) { + this.entityManager.saveAll(); + } else { +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 27cf5dceba5835f94f5397ec011f409e7b226ad5..4f50e2f5de529813c269b7670a47e06306575b60 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -330,7 +330,6 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + + @Override + public void tick() { +- org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.startTiming(); // Spigot + if (this.ackBlockChangesUpTo > -1) { + this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); + this.ackBlockChangesUpTo = -1; +@@ -397,7 +396,6 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 + this.disconnect((Component) Component.translatable("multiplayer.disconnect.idling")); + } +- org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.stopTiming(); // Spigot + + } + +@@ -2103,7 +2101,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + + private void handleCommand(String s) { +- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.startTiming(); // Spigot ++ co.aikar.timings.MinecraftTimings.playerCommandTimer.startTiming(); // Paper + if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot + this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); + +@@ -2113,7 +2111,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.cserver.getPluginManager().callEvent(event); + + if (event.isCancelled()) { +- org.bukkit.craftbukkit.SpigotTimings.playerCommandTimer.stopTiming(); // Spigot ++ co.aikar.timings.MinecraftTimings.playerCommandTimer.stopTiming(); // Paper + return; + } + +@@ -2126,7 +2124,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + 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 ++ co.aikar.timings.MinecraftTimings.playerCommandTimer.stopTiming(); // Paper + } + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index 9807c5b2b248a62a476bfe3ae023d57d35811049..62174dae20bd9ff092238f1437f7e2b0114ef83b 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -1,5 +1,6 @@ + package net.minecraft.server.players; + ++import co.aikar.timings.MinecraftTimings; + import com.google.common.collect.Lists; + import com.google.common.collect.Maps; + import com.google.common.collect.Sets; +@@ -1007,10 +1008,11 @@ public abstract class PlayerList { + } + + public void saveAll() { ++ MinecraftTimings.savePlayers.startTiming(); // Paper + for (int i = 0; i < this.players.size(); ++i) { + this.save((ServerPlayer) this.players.get(i)); + } +- ++ MinecraftTimings.savePlayers.stopTiming(); // Paper + } + + public UserWhiteList getWhiteList() { +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 6041033b3ea201bde1a73ce4e429e8b80e05e2eb..4f321f13352636999c3abc5332e50c747fb45cc9 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -140,7 +140,6 @@ import org.bukkit.command.CommandSender; + 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; +@@ -323,7 +322,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + // 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 + // Spigot start + public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this); + public final boolean defaultActivationState; +@@ -840,7 +838,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + public void move(MoverType movementType, 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 { +@@ -1001,7 +998,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.level().getProfiler().pop(); + } + } +- org.bukkit.craftbukkit.SpigotTimings.entityMoveTimer.stopTiming(); // Spigot + } + + private boolean isStateClimbable(BlockState state) { +diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java +index e465aaa4fd29b4966ea8d88316c6d8f217da2e73..474f020371bb9e5fd2c5b22e44d7902977c4fc18 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityType.java ++++ b/src/main/java/net/minecraft/world/entity/EntityType.java +@@ -339,6 +339,15 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT + } + + public EntityType(EntityType.EntityFactory<T> factory, MobCategory spawnGroup, boolean saveable, boolean summonable, boolean fireImmune, boolean spawnableFarFromPlayer, ImmutableSet<Block> canSpawnInside, EntityDimensions dimensions, float spawnBoxScale, int maxTrackDistance, int trackTickInterval, FeatureFlagSet requiredFeatures) { ++ // Paper start ++ this(factory, spawnGroup, saveable, summonable, fireImmune, spawnableFarFromPlayer, canSpawnInside, dimensions, spawnBoxScale, maxTrackDistance, trackTickInterval, requiredFeatures, "custom"); ++ } ++ public EntityType(EntityType.EntityFactory<T> factory, MobCategory spawnGroup, boolean saveable, boolean summonable, boolean fireImmune, boolean spawnableFarFromPlayer, ImmutableSet<Block> canSpawnInside, EntityDimensions dimensions, float spawnBoxScale, int maxTrackDistance, int trackTickInterval, FeatureFlagSet requiredFeatures, String id) { ++ this.tickTimer = co.aikar.timings.MinecraftTimings.getEntityTimings(id, "tick"); ++ this.inactiveTickTimer = co.aikar.timings.MinecraftTimings.getEntityTimings(id, "inactiveTick"); ++ this.passengerTickTimer = co.aikar.timings.MinecraftTimings.getEntityTimings(id, "passengerTick"); ++ this.passengerInactiveTickTimer = co.aikar.timings.MinecraftTimings.getEntityTimings(id, "passengerInactiveTick"); ++ // Paper end + this.builtInRegistryHolder = BuiltInRegistries.ENTITY_TYPE.createIntrusiveHolder(this); + this.factory = factory; + this.category = spawnGroup; +@@ -654,6 +663,12 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT + return this.updateInterval; + } + ++ // Paper start - timings ++ public final co.aikar.timings.Timing tickTimer; ++ public final co.aikar.timings.Timing inactiveTickTimer; ++ public final co.aikar.timings.Timing passengerTickTimer; ++ public final co.aikar.timings.Timing passengerInactiveTickTimer; ++ // Paper end + public boolean trackDeltas() { + return this != EntityType.PLAYER && this != EntityType.LLAMA_SPIT && this != EntityType.WITHER && this != EntityType.BAT && this != EntityType.ITEM_FRAME && this != EntityType.GLOW_ITEM_FRAME && this != EntityType.LEASH_KNOT && this != EntityType.PAINTING && this != EntityType.END_CRYSTAL && this != EntityType.EVOKER_FANGS; + } +@@ -823,7 +838,7 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT + Util.fetchChoiceType(References.ENTITY_TREE, id); + } + +- return new EntityType<>(this.factory, this.category, this.serialize, this.summon, this.fireImmune, this.canSpawnFarFromPlayer, this.immuneTo, this.dimensions.withAttachments(this.attachments), this.spawnDimensionsScale, this.clientTrackingRange, this.updateInterval, this.requiredFeatures); ++ return new EntityType<>(this.factory, this.category, this.serialize, this.summon, this.fireImmune, this.canSpawnFarFromPlayer, this.immuneTo, this.dimensions.withAttachments(this.attachments), this.spawnDimensionsScale, this.clientTrackingRange, this.updateInterval, this.requiredFeatures, id); // Paper - add id + } + } + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 9deb6b90f3c4281280deb2f609a55923147a675a..fe52b8c57f652fcd49a2282f7a8f1041909b35cf 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -156,7 +156,7 @@ import org.bukkit.event.entity.EntityTeleportEvent; + import org.bukkit.event.player.PlayerItemConsumeEvent; + // CraftBukkit end + +-import org.bukkit.craftbukkit.SpigotTimings; // Spigot ++import co.aikar.timings.MinecraftTimings; // Paper + + public abstract class LivingEntity extends Entity implements Attackable { + +@@ -2949,7 +2949,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + + @Override + public void tick() { +- SpigotTimings.timerEntityBaseTick.startTiming(); // Spigot + super.tick(); + this.updatingUsingItem(); + this.updateSwimAmount(); +@@ -2991,9 +2990,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + + if (!this.isRemoved()) { +- SpigotTimings.timerEntityBaseTick.stopTiming(); // Spigot + this.aiStep(); +- SpigotTimings.timerEntityTickRest.startTiming(); // Spigot + } + + double d0 = this.getX() - this.xo; +@@ -3084,7 +3081,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.refreshDimensions(); + } + +- SpigotTimings.timerEntityTickRest.stopTiming(); // Spigot + } + + public void detectEquipmentUpdatesPublic() { // CraftBukkit +@@ -3300,7 +3296,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + + this.setDeltaMovement(d0, d1, d2); + this.level().getProfiler().push("ai"); +- SpigotTimings.timerEntityAI.startTiming(); // Spigot + if (this.isImmobile()) { + this.jumping = false; + this.xxa = 0.0F; +@@ -3310,7 +3305,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.serverAiStep(); + this.level().getProfiler().pop(); + } +- SpigotTimings.timerEntityAI.stopTiming(); // Spigot + + this.level().getProfiler().pop(); + this.level().getProfiler().push("jump"); +@@ -3350,7 +3344,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.resetFallDistance(); + } + +- SpigotTimings.timerEntityAIMove.startTiming(); // Spigot + label104: + { + LivingEntity entityliving = this.getControllingPassenger(); +@@ -3364,7 +3357,6 @@ public abstract class LivingEntity extends Entity implements Attackable { + + this.travel(vec3d1); + } +- SpigotTimings.timerEntityAIMove.stopTiming(); // Spigot + + this.level().getProfiler().pop(); + this.level().getProfiler().push("freezing"); +@@ -3391,9 +3383,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox()); + } + +- SpigotTimings.timerEntityAICollision.startTiming(); // Spigot + this.pushEntities(); +- SpigotTimings.timerEntityAICollision.stopTiming(); // Spigot + this.level().getProfiler().pop(); + if (!this.level().isClientSide && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { + this.hurt(this.damageSources().drown(), 1.0F); +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 55b30e1df4a05802977b0c3f3b518ef0676eae2d..1702cd6aa8b4fc29b8f2539604f6e203bf95d020 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -93,7 +93,6 @@ import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDistancePa + 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.CraftBlockState; + import org.bukkit.craftbukkit.block.data.CraftBlockData; +@@ -164,7 +163,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + } + // Paper end - add paper world config + +- public final SpigotTimings.WorldTimingsHandler timings; // Spigot ++ public final co.aikar.timings.WorldTimingsHandler timings; // Paper + public static BlockPos lastPhysicsProblem; // Spigot + private org.spigotmc.TickLimiter entityLimiter; + private org.spigotmc.TickLimiter tileLimiter; +@@ -259,7 +258,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + 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 ++ this.timings = new co.aikar.timings.WorldTimingsHandler(this); // Paper - code below can generate new world and access timings + this.entityLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.entityMaxTickTime); + this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime); + } +@@ -723,15 +722,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + + this.timings.tileEntityTick.stopTiming(); // Spigot + this.tickingBlockEntities = false; ++ co.aikar.timings.TimingHistory.tileEntityTicks += this.blockEntityTickers.size(); // Paper + gameprofilerfiller.pop(); + this.spigotConfig.currentPrimedTnt = 0; // Spigot + } + + 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"); +diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java +index d1cfcc8a36964f006f1af6764c52b5ca458b478d..def3e28edc206e0ba41111e26332db468223fb2e 100644 +--- a/src/main/java/net/minecraft/world/level/block/Block.java ++++ b/src/main/java/net/minecraft/world/level/block/Block.java +@@ -88,6 +88,15 @@ public class Block extends BlockBehaviour implements ItemLike { + public static final int UPDATE_LIMIT = 512; + protected final StateDefinition<Block, BlockState> stateDefinition; + private BlockState defaultBlockState; ++ // Paper start ++ public co.aikar.timings.Timing timing; ++ public co.aikar.timings.Timing getTiming() { ++ if (timing == null) { ++ timing = co.aikar.timings.MinecraftTimings.getBlockTiming(this); ++ } ++ return timing; ++ } ++ // Paper end + @Nullable + private String descriptionId; + @Nullable +diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +index e6c586eb85c6c477a3c130e1e1a37b41f17c30c8..6e35709f2a7c32050908e7e5af5529c9f342b787 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +@@ -34,10 +34,12 @@ import org.bukkit.inventory.InventoryHolder; + // CraftBukkit end + + import org.spigotmc.CustomTimingsHandler; // Spigot ++import co.aikar.timings.MinecraftTimings; // Paper ++import co.aikar.timings.Timing; // Paper + + public abstract class BlockEntity { + +- public CustomTimingsHandler tickTimer = org.bukkit.craftbukkit.SpigotTimings.getTileEntityTimings(this); // Spigot ++ public Timing tickTimer = MinecraftTimings.getTileEntityTimings(this); // Paper + // CraftBukkit start - data containers + private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); + public CraftPersistentDataContainer persistentDataContainer; +diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +index 7898e1aaf82f096fa74bd3f5859f0f4303ea677f..05d959ccc424aaaa465ec256213f2ec4d44ef8b5 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -710,6 +710,7 @@ public class LevelChunk extends ChunkAccess { + server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration)); + + if (this.needsDecoration) { ++ try (co.aikar.timings.Timing ignored = this.level.timings.chunkLoadPopulate.startTiming()) { // Paper + this.needsDecoration = false; + java.util.Random random = new java.util.Random(); + random.setSeed(this.level.getSeed()); +@@ -729,6 +730,7 @@ public class LevelChunk extends ChunkAccess { + } + } + server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk)); ++ } // Paper + } + } + } +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +index 46a090123e205394791cdbde2af84c58ce55f7e1..47f5f3d58bb3bf85cf35f9baae77df7fab5c844f 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +@@ -472,13 +472,10 @@ public class ChunkSerializer { + ListTag nbttaglist1 = ChunkSerializer.getListOfCompoundsOrNull(nbt, "block_entities"); + + return nbttaglist == null && nbttaglist1 == null ? null : (chunk) -> { +- world.timings.syncChunkLoadEntitiesTimer.startTiming(); // Spigot + if (nbttaglist != null) { + world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(nbttaglist, world)); + } +- world.timings.syncChunkLoadEntitiesTimer.stopTiming(); // Spigot + +- world.timings.syncChunkLoadTileEntitiesTimer.startTiming(); // Spigot + if (nbttaglist1 != null) { + for (int i = 0; i < nbttaglist1.size(); ++i) { + CompoundTag nbttagcompound1 = nbttaglist1.getCompound(i); +@@ -496,7 +493,6 @@ public class ChunkSerializer { + } + } + } +- world.timings.syncChunkLoadTileEntitiesTimer.stopTiming(); // Spigot + + }; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index d1699fcca66bcfbbe8fcc426802cb766cf1e580b..de55611daeb6d55f69c4cb72137eb7b050e727f7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -376,7 +376,7 @@ public final class CraftServer implements Server { + this.saveCommandsConfig(); + this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); + this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); +- this.pluginManager.useTimings(this.configuration.getBoolean("settings.plugin-profiling")); ++ //this.pluginManager.useTimings(this.configuration.getBoolean("settings.plugin-profiling")); // Paper - we already moved this + this.overrideSpawnLimits(); + console.autosavePeriod = this.configuration.getInt("ticks-per.autosave"); + this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose")); +@@ -2612,12 +2612,31 @@ public final class CraftServer implements Server { + private final org.bukkit.Server.Spigot spigot = new org.bukkit.Server.Spigot() + { + ++ @Deprecated + @Override + public YamlConfiguration getConfig() + { + return org.spigotmc.SpigotConfig.config; + } + ++ @Override ++ public YamlConfiguration getBukkitConfig() ++ { ++ return configuration; ++ } ++ ++ @Override ++ public YamlConfiguration getSpigotConfig() ++ { ++ return org.spigotmc.SpigotConfig.config; ++ } ++ ++ @Override ++ public YamlConfiguration getPaperConfig() ++ { ++ return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console); ++ } ++ + @Override + public void restart() { + org.spigotmc.RestartCommand.restart(); +diff --git a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java b/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java +deleted file mode 100644 +index b0ffa23faf62629043dfd613315eaf9c5fcc2cfe..0000000000000000000000000000000000000000 +--- a/src/main/java/org/bukkit/craftbukkit/SpigotTimings.java ++++ /dev/null +@@ -1,163 +0,0 @@ +-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 CustomTimingsHandler entityActivationCheckTimer = new CustomTimingsHandler("entityActivationCheck"); +- public static final CustomTimingsHandler checkIfActiveTimer = new CustomTimingsHandler("** checkIfActive"); +- +- 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/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 64aed98084aeb3f29db301adf3c8c49ee9236a0b..0bea424418984e17193ff107d2b4cf13278a3d3e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -2781,6 +2781,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + CraftPlayer.this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundSystemChatPacket(components, position == net.md_5.bungee.api.ChatMessageType.ACTION_BAR)); + } ++ ++ // Paper start ++ @Override ++ public int getPing() ++ { ++ return CraftPlayer.this.getPing(); ++ } ++ // Paper end + }; + + public Player.Spigot spigot() +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +index 0f7c3a44acf3c59ae43605e573f9da7f7c594647..a3ccc2da0927cc49e5fcfbd863e648ad0f25cc0d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +@@ -1,5 +1,6 @@ + package org.bukkit.craftbukkit.scheduler; + ++import co.aikar.timings.MinecraftTimings; // Paper + import com.google.common.base.Preconditions; + import com.google.common.util.concurrent.ThreadFactoryBuilder; + import java.util.ArrayList; +@@ -196,7 +197,8 @@ public class CraftScheduler implements BukkitScheduler { + } + + public BukkitTask scheduleInternalTask(Runnable run, int delay, String taskName) { +- final CraftTask task = new CraftTask(run, nextId(), taskName); ++ final CraftTask task = new CraftTask(run, nextId(), "Internal - " + (taskName != null ? taskName : "Unknown")); ++ task.internal = true; + return handle(task, delay); + } + +@@ -277,7 +279,7 @@ public class CraftScheduler implements BukkitScheduler { + } + return false; + } +- }); ++ }){{this.timings=co.aikar.timings.MinecraftTimings.getCancelTasksTimer();}}; // Paper + this.handle(task, 0L); + for (CraftTask taskPending = this.head.getNext(); taskPending != null; taskPending = taskPending.getNext()) { + if (taskPending == task) { +@@ -312,7 +314,7 @@ public class CraftScheduler implements BukkitScheduler { + } + } + } +- }); ++ }){{this.timings=co.aikar.timings.MinecraftTimings.getCancelTasksTimer(plugin);}}; // Paper + this.handle(task, 0L); + for (CraftTask taskPending = this.head.getNext(); taskPending != null; taskPending = taskPending.getNext()) { + if (taskPending == task) { +@@ -419,9 +421,7 @@ 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) { + // Paper start + String msg = String.format( +@@ -455,8 +455,10 @@ public class CraftScheduler implements BukkitScheduler { + this.runners.remove(task.getTaskId()); + } + } ++ MinecraftTimings.bukkitSchedulerFinishTimer.startTiming(); // Paper + this.pending.addAll(temp); + temp.clear(); ++ MinecraftTimings.bukkitSchedulerFinishTimer.stopTiming(); // Paper + this.debugHead = this.debugHead.getNextHead(currentTick); + } + +@@ -493,6 +495,7 @@ public class CraftScheduler implements BukkitScheduler { + } + + private void parsePending() { ++ MinecraftTimings.bukkitSchedulerPendingTimer.startTiming(); + CraftTask head = this.head; + CraftTask task = head.getNext(); + CraftTask lastTask = head; +@@ -511,6 +514,7 @@ public class CraftScheduler implements BukkitScheduler { + task.setNext(null); + } + this.head = lastTask; ++ MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming(); + } + + private boolean isReady(final int currentTick) { +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java +index d56abf283f38548faa790c57045033f7ade6f958..ea26d9464644b5217879b8c21b4da28e57708dcb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java +@@ -1,12 +1,15 @@ + package org.bukkit.craftbukkit.scheduler; + + import java.util.function.Consumer; ++ ++import co.aikar.timings.NullTimingHandler; + import org.bukkit.Bukkit; + import org.bukkit.plugin.Plugin; + import org.bukkit.scheduler.BukkitTask; + +-import org.bukkit.craftbukkit.SpigotTimings; // Spigot + import org.spigotmc.CustomTimingsHandler; // Spigot ++import co.aikar.timings.MinecraftTimings; // Paper ++import co.aikar.timings.Timing; // Paper + + public class CraftTask implements BukkitTask, Runnable { // Spigot + +@@ -26,13 +29,13 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot + */ + private volatile long period; + private long nextRun; +- private final Runnable rTask; +- private final Consumer<BukkitTask> cTask; ++ public final Runnable rTask; // Paper ++ public final Consumer<BukkitTask> cTask; // Paper ++ public Timing timings; // Paper + private final Plugin plugin; + private final int id; + private final long createdAt = System.nanoTime(); + +- final CustomTimingsHandler timings; // Spigot + CraftTask() { + this(null, null, CraftTask.NO_REPEATING, CraftTask.NO_REPEATING); + } +@@ -52,7 +55,7 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot + this.id = id; + this.period = CraftTask.NO_REPEATING; + this.taskName = taskName; +- this.timings = null; // Will be changed in later patch ++ this.timings = MinecraftTimings.getInternalTaskName(taskName); + } + // Paper end + +@@ -73,7 +76,7 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot + } + this.id = id; + this.period = period; +- this.timings = this.isSync() ? SpigotTimings.getPluginTaskTimings(this, period) : null; // Spigot ++ timings = task != null ? MinecraftTimings.getPluginTaskTimings(this, period) : NullTimingHandler.NULL; // Paper + } + + @Override +@@ -93,11 +96,13 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot + + @Override + public void run() { ++ try (Timing ignored = timings.startTiming()) { // Paper + if (this.rTask != null) { + this.rTask.run(); + } else { + this.cTask.accept(this); + } ++ } // Paper + } + + long getCreatedAt() { +@@ -128,7 +133,7 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot + this.next = next; + } + +- Class<?> getTaskClass() { ++ public Class<?> getTaskClass() { // Paper + return (this.rTask != null) ? this.rTask.getClass() : ((this.cTask != null) ? this.cTask.getClass() : null); + } + +@@ -152,9 +157,4 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot + return true; + } + +- // Spigot start +- public String getTaskName() { +- return (this.getTaskClass() == null) ? "Unknown" : this.getTaskClass().getName(); +- } +- // Spigot end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java b/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java +index f97eccb6a17c7876e1e002d798eb67bbe80571a0..76effc345d362047e64d064eb64a5222612aec14 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftIconCache.java +@@ -8,4 +8,11 @@ public class CraftIconCache implements CachedServerIcon { + public CraftIconCache(final byte[] value) { + this.value = value; + } ++ ++ public String getData() { ++ if (value == null) { ++ return null; ++ } ++ return "data:image/png;base64," + new String(java.util.Base64.getEncoder().encode(value), java.nio.charset.StandardCharsets.UTF_8); ++ } // Paper + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index d551c9d898d8b5128dfef84d206396c84072abe4..99f134d03b76e867a3e5084c5c89e53c74d8e7af 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -217,6 +217,12 @@ public final class CraftMagicNumbers implements UnsafeValues { + } + // Paper end + // ======================================================================== ++ // Paper start ++ @Override ++ public void reportTimings() { ++ co.aikar.timings.TimingsExport.reportTimings(); ++ } ++ // Paper end + + public static byte toLegacyData(BlockState data) { + return CraftLegacy.toLegacyData(data); +@@ -467,6 +473,12 @@ public final class CraftMagicNumbers implements UnsafeValues { + public DamageSource.Builder createDamageSourceBuilder(DamageType damageType) { + return new CraftDamageSourceBuilder(damageType); + } ++ // Paper start ++ @Override ++ public String getTimingsServerName() { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().timings.serverName; ++ } ++ // Paper end + + @Override + public String get(Class<?> aClass, String s) { +diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java +index ff422d4d4f2b764370f0ee2af13034853c1d3fe1..a5da6c1cae0afbde684be250e2fc3c0c32a1265b 100644 +--- a/src/main/java/org/spigotmc/ActivationRange.java ++++ b/src/main/java/org/spigotmc/ActivationRange.java +@@ -27,7 +27,7 @@ import net.minecraft.world.entity.projectile.ThrownTrident; + import net.minecraft.world.entity.raid.Raider; + import net.minecraft.world.level.Level; + import net.minecraft.world.phys.AABB; +-import org.bukkit.craftbukkit.SpigotTimings; ++import co.aikar.timings.MinecraftTimings; + + public class ActivationRange + { +@@ -74,8 +74,8 @@ public class ActivationRange + /** + * These entities are excluded from Activation range checks. + * +- * @param entity +- * @param config ++ * @param entity Entity to initialize ++ * @param config Spigot config to determine ranges + * @return boolean If it should always tick. + */ + public static boolean initializeEntityActivationState(Entity entity, SpigotWorldConfig config) +@@ -110,7 +110,7 @@ public class ActivationRange + */ + public static void activateEntities(Level world) + { +- SpigotTimings.entityActivationCheckTimer.startTiming(); ++ MinecraftTimings.entityActivationCheckTimer.startTiming(); + final int miscActivationRange = world.spigotConfig.miscActivationRange; + final int raiderActivationRange = world.spigotConfig.raiderActivationRange; + final int animalActivationRange = world.spigotConfig.animalActivationRange; +@@ -137,7 +137,7 @@ public class ActivationRange + + world.getEntities().get(ActivationRange.maxBB, ActivationRange::activateEntity); + } +- SpigotTimings.entityActivationCheckTimer.stopTiming(); ++ MinecraftTimings.entityActivationCheckTimer.stopTiming(); + } + + /** +@@ -232,10 +232,8 @@ public class ActivationRange + */ + public static boolean checkIfActive(Entity entity) + { +- SpigotTimings.checkIfActiveTimer.startTiming(); + // Never safe to skip fireworks or entities not yet added to chunk + if ( entity instanceof FireworkRocketEntity ) { +- SpigotTimings.checkIfActiveTimer.stopTiming(); + return true; + } + +@@ -259,7 +257,6 @@ public class ActivationRange + { + isActive = false; + } +- SpigotTimings.checkIfActiveTimer.stopTiming(); + return isActive; + } + } |