From 146c37505ce230b9c3a9d87abac2fce1319af631 Mon Sep 17 00:00:00 2001 From: AlphaKR93 Date: Fri, 30 Sep 2022 23:22:25 +0900 Subject: [PATCH] Readd Flare patch from Airplane --- .../0001-Pufferfish-Server-Changes.patch | 825 +++++++++++++++++- .../server/0002-Purpur-Server-Changes.patch | 18 +- patches/server/0005-Rebrand.patch | 4 +- ...mmit-disable-pufferfish-mechanical-c.patch | 6 +- 4 files changed, 833 insertions(+), 20 deletions(-) diff --git a/patches/server/0001-Pufferfish-Server-Changes.patch b/patches/server/0001-Pufferfish-Server-Changes.patch index 829c88b..7bc5a95 100644 --- a/patches/server/0001-Pufferfish-Server-Changes.patch +++ b/patches/server/0001-Pufferfish-Server-Changes.patch @@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/build.gradle.kts b/build.gradle.kts -index 2374cc9bab5039d0a0dc11d4b2ec573ab75778a7..0485d126f799789b5d5abcaf96da96df25a12dfd 100644 +index 44e0f265432487fe5c3c00c5245041298ade16a0..7b74ec475b1e953080d5aa8b0a10d1680e7c46f1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,8 +9,12 @@ plugins { @@ -37,7 +37,7 @@ index 2374cc9bab5039d0a0dc11d4b2ec573ab75778a7..0485d126f799789b5d5abcaf96da96df // Paper start implementation("org.jline:jline-terminal-jansi:3.21.0") implementation("net.minecrell:terminalconsoleappender:1.3.0") -@@ -44,6 +48,13 @@ dependencies { +@@ -44,6 +48,14 @@ dependencies { runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.3") runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.3") @@ -47,11 +47,12 @@ index 2374cc9bab5039d0a0dc11d4b2ec573ab75778a7..0485d126f799789b5d5abcaf96da96df + exclude(group="org.yaml", module="snakeyaml") + } + // Pufferfish end ++ implementation("com.github.technove:Flare:34637f3f87") // Pufferfish - flare + testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test testImplementation("junit:junit:4.13.2") testImplementation("org.hamcrest:hamcrest-library:1.3") -@@ -52,6 +63,14 @@ dependencies { +@@ -52,6 +64,14 @@ dependencies { } val craftbukkitPackageVersion = "1_19_R1" // Paper @@ -66,7 +67,7 @@ index 2374cc9bab5039d0a0dc11d4b2ec573ab75778a7..0485d126f799789b5d5abcaf96da96df tasks.jar { archiveClassifier.set("dev") -@@ -64,7 +83,7 @@ tasks.jar { +@@ -64,7 +84,7 @@ tasks.jar { attributes( "Main-Class" to "org.bukkit.craftbukkit.Main", "Implementation-Title" to "CraftBukkit", @@ -610,10 +611,10 @@ index 0000000000000000000000000000000000000000..020368da69b9a492155f6de6297f7473 +} diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java new file mode 100644 -index 0000000000000000000000000000000000000000..ed9c8e882739c02d0d04129d251e4c726b422c07 +index 0000000000000000000000000000000000000000..5d75693abb78f1a6cb3595a4af6d1ca0795c1025 --- /dev/null +++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -@@ -0,0 +1,283 @@ +@@ -0,0 +1,315 @@ +package gg.pufferfish.pufferfish; + +import gg.pufferfish.pufferfish.simd.SIMDDetection; @@ -631,6 +632,7 @@ index 0000000000000000000000000000000000000000..ed9c8e882739c02d0d04129d251e4c72 +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.List; ++import gg.pufferfish.pufferfish.flare.FlareCommand; +import net.minecraft.server.MinecraftServer; +import org.apache.logging.log4j.Level; +import org.bukkit.configuration.ConfigurationSection; @@ -639,6 +641,13 @@ index 0000000000000000000000000000000000000000..ed9c8e882739c02d0d04129d251e4c72 +import org.simpleyaml.configuration.comments.CommentType; +import org.simpleyaml.configuration.file.YamlFile; +import org.simpleyaml.exceptions.InvalidConfigurationException; ++import org.bukkit.command.SimpleCommandMap; ++ ++import java.lang.reflect.Method; ++import java.lang.reflect.Modifier; ++import java.util.List; ++import java.net.URI; ++import java.util.Collections; + +public class PufferfishConfig { + @@ -862,6 +871,30 @@ index 0000000000000000000000000000000000000000..ed9c8e882739c02d0d04129d251e4c72 + + setComment("dab", "Optimizes entity brains when", "they're far away from the player"); + } ++ ++ public static URI profileWebUrl; ++ private static void profilerOptions() { ++ profileWebUrl = URI.create(getString("flare.url", "https://flare.airplane.gg", "Sets the server to use for profiles.")); ++ ++ setComment("flare", "Configures Flare, the built-in profiler"); ++ } ++ ++ ++ public static String accessToken; ++ private static void airplaneWebServices() { ++ accessToken = getString("web-services.token", ""); ++ // todo lookup token (off-thread) and let users know if their token is valid ++ if (accessToken.length() > 0) { ++ gg.pufferfish.pufferfish.flare.FlareSetup.init(); // Pufferfish ++ SimpleCommandMap commandMap = MinecraftServer.getServer().server.getCommandMap(); ++ if (commandMap.getCommand("flare") == null) { ++ commandMap.register("flare", "Pufferfish", new FlareCommand()); ++ } ++ } ++ ++ setComment("web-services", "Options for connecting to Pufferfish/Airplane's online utilities"); ++ ++ } + + public static Map projectileTimeouts; + private static void projectileTimeouts() { @@ -1062,6 +1095,699 @@ index 0000000000000000000000000000000000000000..e877921370f6009a4bd204d9b17d2d58 + } +} \ No newline at end of file +diff --git a/src/main/java/gg/pufferfish/pufferfish/compat/ServerConfigurations.java b/src/main/java/gg/pufferfish/pufferfish/compat/ServerConfigurations.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4ad189d52b27560424ddb311d0817a334637dc95 +--- /dev/null ++++ b/src/main/java/gg/pufferfish/pufferfish/compat/ServerConfigurations.java +@@ -0,0 +1,78 @@ ++package gg.pufferfish.pufferfish.compat; ++ ++import co.aikar.timings.TimingsManager; ++import com.google.common.io.Files; ++import org.bukkit.configuration.InvalidConfigurationException; ++import org.bukkit.configuration.file.YamlConfiguration; ++ ++import java.io.ByteArrayOutputStream; ++import java.io.File; ++import java.io.FileInputStream; ++import java.io.IOException; ++import java.nio.charset.StandardCharsets; ++import java.util.Arrays; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++import java.util.Properties; ++import java.util.stream.Collectors; ++ ++public class ServerConfigurations { ++ ++ public static final String[] configurationFiles = new String[]{ ++ "server.properties", ++ "bukkit.yml", ++ "spigot.yml", ++ // "paper.yml", // TODO: Figure out what to do with this. ++ "pufferfish.yml" ++ }; ++ ++ public static Map getCleanCopies() throws IOException { ++ Map files = new HashMap<>(configurationFiles.length); ++ for (String file : configurationFiles) { ++ files.put(file, getCleanCopy(file)); ++ } ++ return files; ++ } ++ ++ public static String getCleanCopy(String configName) throws IOException { ++ File file = new File(configName); ++ List hiddenConfigs = TimingsManager.hiddenConfigs; ++ ++ switch (Files.getFileExtension(configName)) { ++ case "properties": { ++ Properties properties = new Properties(); ++ try (FileInputStream inputStream = new FileInputStream(file)) { ++ properties.load(inputStream); ++ } ++ for (String hiddenConfig : hiddenConfigs) { ++ properties.remove(hiddenConfig); ++ } ++ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ++ properties.store(outputStream, ""); ++ return Arrays.stream(outputStream.toString() ++ .split("\n")) ++ .filter(line -> !line.startsWith("#")) ++ .collect(Collectors.joining("\n")); ++ } ++ case "yml": { ++ YamlConfiguration configuration = new YamlConfiguration(); ++ try { ++ configuration.load(file); ++ } catch (InvalidConfigurationException e) { ++ throw new IOException(e); ++ } ++ configuration.options().header(null); ++ for (String key : configuration.getKeys(true)) { ++ if (hiddenConfigs.contains(key)) { ++ configuration.set(key, null); ++ } ++ } ++ return configuration.saveToString(); ++ } ++ default: ++ throw new IllegalArgumentException("Bad file type " + configName); ++ } ++ } ++ ++} +diff --git a/src/main/java/gg/pufferfish/pufferfish/flare/CustomCategories.java b/src/main/java/gg/pufferfish/pufferfish/flare/CustomCategories.java +new file mode 100644 +index 0000000000000000000000000000000000000000..401b42e29bccb5251684062f10b2e0f8b091bc95 +--- /dev/null ++++ b/src/main/java/gg/pufferfish/pufferfish/flare/CustomCategories.java +@@ -0,0 +1,8 @@ ++package gg.pufferfish.pufferfish.flare; ++ ++import co.technove.flare.live.category.GraphCategory; ++ ++public class CustomCategories { ++ public static final GraphCategory MC_PERF = new GraphCategory("MC Performance"); ++ public static final GraphCategory ENTITIES_AND_CHUNKS = new GraphCategory("Entities & Chunks"); ++} +diff --git a/src/main/java/gg/pufferfish/pufferfish/flare/FlareCommand.java b/src/main/java/gg/pufferfish/pufferfish/flare/FlareCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3785d1512eb650f91d58903672c059e7449598fc +--- /dev/null ++++ b/src/main/java/gg/pufferfish/pufferfish/flare/FlareCommand.java +@@ -0,0 +1,136 @@ ++package gg.pufferfish.pufferfish.flare; ++ ++import co.technove.flare.exceptions.UserReportableException; ++import co.technove.flare.internal.profiling.ProfileType; ++import gg.pufferfish.pufferfish.PufferfishConfig; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.event.ClickEvent; ++import net.kyori.adventure.text.format.NamedTextColor; ++import net.kyori.adventure.text.format.TextColor; ++import net.kyori.adventure.text.format.TextDecoration; ++import net.minecraft.server.MinecraftServer; ++import org.apache.logging.log4j.Level; ++import org.bukkit.Bukkit; ++import org.bukkit.command.Command; ++import org.bukkit.command.CommandSender; ++import org.bukkit.command.ConsoleCommandSender; ++import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin; ++import org.bukkit.util.StringUtil; ++import org.jetbrains.annotations.NotNull; ++ ++import java.time.Duration; ++import java.util.ArrayList; ++import java.util.Collections; ++import java.util.List; ++ ++public class FlareCommand extends Command { ++ ++ private static final String BASE_URL = "https://blog.airplane.gg/flare-tutorial/#setting-the-access-token"; ++ private static final TextColor HEX = TextColor.fromHexString("#e3eaea"); ++ private static final Component PREFIX = Component.text() ++ .append(Component.text("Flare ✈") ++ .color(TextColor.fromHexString("#6a7eda")) ++ .decoration(TextDecoration.BOLD, true) ++ .append(Component.text(" ", HEX) ++ .decoration(TextDecoration.BOLD, false))) ++ .asComponent(); ++ ++ public FlareCommand() { ++ super("flare", "Profile your server with Flare", "/flare", Collections.singletonList("profile")); ++ this.setPermission("airplane.flare"); ++ } ++ ++ @Override ++ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, String @NotNull [] args) { ++ if (!testPermission(sender)) return true; ++ if (PufferfishConfig.accessToken.length() == 0) { ++ Component clickable = Component.text(BASE_URL, HEX, TextDecoration.UNDERLINED).clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, BASE_URL)); ++ ++ sender.sendMessage(PREFIX.append(Component.text("Flare currently requires an access token to use. To learn more, visit ").color(HEX).append(clickable))); ++ return true; ++ } ++ ++ if (!FlareSetup.isSupported()) { ++ sender.sendMessage(PREFIX.append( ++ Component.text("Profiling is not supported in this environment, check your startup logs for the error.", NamedTextColor.RED))); ++ return true; ++ } ++ if (ProfilingManager.isProfiling()) { ++ if (args.length == 1 && args[0].equalsIgnoreCase("status")) { ++ sender.sendMessage(PREFIX.append(Component.text("Current profile has been ran for " + ProfilingManager.getTimeRan().toString(), HEX))); ++ return true; ++ } ++ if (ProfilingManager.stop()) { ++ if (!(sender instanceof ConsoleCommandSender)) { ++ sender.sendMessage(PREFIX.append(Component.text("Profiling has been stopped.", HEX))); ++ } ++ } else { ++ sender.sendMessage(PREFIX.append(Component.text("Profiling has already been stopped.", HEX))); ++ } ++ } else { ++ ProfileType profileType = ProfileType.ITIMER; ++ if (args.length > 0) { ++ try { ++ profileType = ProfileType.valueOf(args[0].toUpperCase()); ++ } catch (Exception e) { ++ sender.sendMessage(PREFIX.append(Component ++ .text("Invalid profile type ", HEX) ++ .append(Component.text(args[0], HEX, TextDecoration.BOLD) ++ .append(Component.text("!", HEX))) ++ )); ++ } ++ } ++ ProfileType finalProfileType = profileType; ++ Bukkit.getScheduler().runTaskAsynchronously(new MinecraftInternalPlugin(), () -> { ++ try { ++ if (ProfilingManager.start(finalProfileType)) { ++ if (!(sender instanceof ConsoleCommandSender)) { ++ sender.sendMessage(PREFIX.append(Component ++ .text("Flare has been started: " + ProfilingManager.getProfilingUri(), HEX) ++ .clickEvent(ClickEvent.openUrl(ProfilingManager.getProfilingUri())) ++ )); ++ sender.sendMessage(PREFIX.append(Component.text(" Run /" + commandLabel + " to stop the Flare.", HEX))); ++ } ++ } else { ++ sender.sendMessage(PREFIX.append(Component ++ .text("Flare has already been started: " + ProfilingManager.getProfilingUri(), HEX) ++ .clickEvent(ClickEvent.openUrl(ProfilingManager.getProfilingUri())) ++ )); ++ } ++ } catch (UserReportableException e) { ++ sender.sendMessage(Component.text("Flare failed to start: " + e.getUserError(), NamedTextColor.RED)); ++ if (e.getCause() != null) { ++ MinecraftServer.LOGGER.warn("Flare failed to start", e); ++ } ++ } ++ }); ++ } ++ return true; ++ } ++ ++ @Override ++ public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, String @NotNull [] args) throws IllegalArgumentException { ++ List list = new ArrayList<>(); ++ if (ProfilingManager.isProfiling()) { ++ if (args.length == 1) { ++ String lastWord = args[0]; ++ if (StringUtil.startsWithIgnoreCase("status", lastWord)) { ++ list.add("status"); ++ } ++ if (StringUtil.startsWithIgnoreCase("stop", lastWord)) { ++ list.add("stop"); ++ } ++ } ++ } else { ++ if (args.length <= 1) { ++ String lastWord = args.length == 0 ? "" : args[0]; ++ for (ProfileType value : ProfileType.values()) { ++ if (StringUtil.startsWithIgnoreCase(value.getInternalName(), lastWord)) { ++ list.add(value.name().toLowerCase()); ++ } ++ } ++ } ++ } ++ return list; ++ } ++} +diff --git a/src/main/java/gg/pufferfish/pufferfish/flare/FlareSetup.java b/src/main/java/gg/pufferfish/pufferfish/flare/FlareSetup.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cd22e4dcc8b7b57b10a95ef084637249a98e524f +--- /dev/null ++++ b/src/main/java/gg/pufferfish/pufferfish/flare/FlareSetup.java +@@ -0,0 +1,33 @@ ++package gg.pufferfish.pufferfish.flare; ++ ++import co.technove.flare.FlareInitializer; ++import co.technove.flare.internal.profiling.InitializationException; ++import net.minecraft.server.MinecraftServer; ++import org.apache.logging.log4j.Level; ++ ++public class FlareSetup { ++ ++ private static boolean initialized = false; ++ private static boolean supported = false; ++ ++ public static void init() { ++ if (initialized) { ++ return; ++ } ++ ++ initialized = true; ++ try { ++ for (String warning : FlareInitializer.initialize()) { ++ MinecraftServer.LOGGER.warn("Flare warning: " + warning); ++ } ++ supported = true; ++ } catch (InitializationException e) { ++ MinecraftServer.LOGGER.warn("Failed to enable Flare:", e); ++ } ++ } ++ ++ public static boolean isSupported() { ++ return supported; ++ } ++ ++} +diff --git a/src/main/java/gg/pufferfish/pufferfish/flare/PluginLookup.java b/src/main/java/gg/pufferfish/pufferfish/flare/PluginLookup.java +new file mode 100644 +index 0000000000000000000000000000000000000000..74aab5eb4b54ffbaf19b8976ffb8ca4a64584006 +--- /dev/null ++++ b/src/main/java/gg/pufferfish/pufferfish/flare/PluginLookup.java +@@ -0,0 +1,44 @@ ++package gg.pufferfish.pufferfish.flare; ++ ++import com.google.common.cache.Cache; ++import com.google.common.cache.CacheBuilder; ++import org.bukkit.Bukkit; ++import org.bukkit.plugin.Plugin; ++import org.bukkit.plugin.java.PluginClassLoader; ++ ++import java.util.Optional; ++import java.util.concurrent.TimeUnit; ++ ++public class PluginLookup { ++ private static final Cache pluginNameCache = CacheBuilder.newBuilder() ++ .expireAfterAccess(1, TimeUnit.MINUTES) ++ .maximumSize(1024) ++ .build(); ++ ++ public static Optional getPluginForClass(String name) { ++ if (name.startsWith("net.minecraft") || name.startsWith("java.") || name.startsWith("com.mojang") || ++ name.startsWith("com.google") || name.startsWith("it.unimi") || name.startsWith("sun")) { ++ return Optional.empty(); ++ } ++ ++ String existing = pluginNameCache.getIfPresent(name); ++ if (existing != null) { ++ return Optional.ofNullable(existing.isEmpty() ? null : existing); ++ } ++ ++ String newValue = ""; ++ ++ for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { ++ ClassLoader classLoader = plugin.getClass().getClassLoader(); ++ if (classLoader instanceof PluginClassLoader) { ++ if (((PluginClassLoader) classLoader)._airplane_hasClass(name)) { ++ newValue = plugin.getName(); ++ break; ++ } ++ } ++ } ++ ++ pluginNameCache.put(name, newValue); ++ return Optional.ofNullable(newValue.isEmpty() ? null : newValue); ++ } ++} +diff --git a/src/main/java/gg/pufferfish/pufferfish/flare/ProfilingManager.java b/src/main/java/gg/pufferfish/pufferfish/flare/ProfilingManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e3f76eb11a261c3347f0cd89b5da309bc2dc82f9 +--- /dev/null ++++ b/src/main/java/gg/pufferfish/pufferfish/flare/ProfilingManager.java +@@ -0,0 +1,151 @@ ++package gg.pufferfish.pufferfish.flare; ++ ++import co.technove.flare.Flare; ++import co.technove.flare.FlareAuth; ++import co.technove.flare.FlareBuilder; ++import co.technove.flare.exceptions.UserReportableException; ++import co.technove.flare.internal.profiling.ProfileType; ++import gg.pufferfish.pufferfish.PufferfishConfig; ++import gg.pufferfish.pufferfish.PufferfishLogger; ++import gg.pufferfish.pufferfish.compat.ServerConfigurations; ++import gg.pufferfish.pufferfish.flare.collectors.GCEventCollector; ++import gg.pufferfish.pufferfish.flare.collectors.StatCollector; ++import gg.pufferfish.pufferfish.flare.collectors.TPSCollector; ++import gg.pufferfish.pufferfish.flare.collectors.WorldCountCollector; ++import org.bukkit.Bukkit; ++import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin; ++import org.bukkit.scheduler.BukkitTask; ++import oshi.SystemInfo; ++import oshi.hardware.CentralProcessor; ++import oshi.hardware.GlobalMemory; ++import oshi.hardware.HardwareAbstractionLayer; ++import oshi.hardware.VirtualMemory; ++import oshi.software.os.OperatingSystem; ++ ++import java.io.IOException; ++import java.net.URI; ++import java.time.Duration; ++import java.util.Objects; ++import java.util.logging.Level; ++ ++public class ProfilingManager { ++ ++ private static Flare currentFlare; ++ private static BukkitTask currentTask = null; ++ ++ public static synchronized boolean isProfiling() { ++ return currentFlare != null && currentFlare.isRunning(); ++ } ++ ++ public static synchronized String getProfilingUri() { ++ return Objects.requireNonNull(currentFlare).getURI().map(URI::toString).orElse("Flare is not running"); ++ } ++ ++ public static Duration getTimeRan() { ++ Flare flare = currentFlare; // copy reference so no need to sync ++ if (flare == null) { ++ return Duration.ofMillis(0); ++ } ++ return flare.getCurrentDuration(); ++ } ++ ++ public static synchronized boolean start(ProfileType profileType) throws UserReportableException { ++ if (currentFlare != null && !currentFlare.isRunning()) { ++ currentFlare = null; // errored out ++ } ++ if (isProfiling()) { ++ return false; ++ } ++ if (Bukkit.isPrimaryThread()) { ++ throw new UserReportableException("Profiles should be started off-thread"); ++ } ++ ++ try { ++ OperatingSystem os = new SystemInfo().getOperatingSystem(); ++ ++ SystemInfo systemInfo = new SystemInfo(); ++ HardwareAbstractionLayer hardware = systemInfo.getHardware(); ++ ++ CentralProcessor processor = hardware.getProcessor(); ++ CentralProcessor.ProcessorIdentifier processorIdentifier = processor.getProcessorIdentifier(); ++ ++ GlobalMemory memory = hardware.getMemory(); ++ VirtualMemory virtualMemory = memory.getVirtualMemory(); ++ ++ FlareBuilder builder = new FlareBuilder() ++ .withProfileType(profileType) ++ .withMemoryProfiling(true) ++ .withAuth(FlareAuth.fromTokenAndUrl(PufferfishConfig.accessToken, PufferfishConfig.profileWebUrl)) ++ ++ .withFiles(ServerConfigurations.getCleanCopies()) ++ .withVersion("Primary Version", Bukkit.getVersion()) ++ .withVersion("Bukkit Version", Bukkit.getBukkitVersion()) ++ .withVersion("Minecraft Version", Bukkit.getMinecraftVersion()) ++ ++ .withGraphCategories(CustomCategories.ENTITIES_AND_CHUNKS, CustomCategories.MC_PERF) ++ .withCollectors(new TPSCollector(), new WorldCountCollector(), new GCEventCollector(), new StatCollector()) ++ .withClassIdentifier(PluginLookup::getPluginForClass) ++ ++ .withHardware(new FlareBuilder.HardwareBuilder() ++ .setCoreCount(processor.getPhysicalProcessorCount()) ++ .setThreadCount(processor.getLogicalProcessorCount()) ++ .setCpuModel(processorIdentifier.getName()) ++ .setCpuFrequency(processor.getMaxFreq()) ++ ++ .setTotalMemory(memory.getTotal()) ++ .setTotalSwap(virtualMemory.getSwapTotal()) ++ .setTotalVirtual(virtualMemory.getVirtualMax()) ++ ) ++ ++ .withOperatingSystem(new FlareBuilder.OperatingSystemBuilder() ++ .setManufacturer(os.getManufacturer()) ++ .setFamily(os.getFamily()) ++ .setVersion(os.getVersionInfo().toString()) ++ .setBitness(os.getBitness()) ++ ); ++ ++ currentFlare = builder.build(); ++ } catch (IOException e) { ++ PufferfishLogger.LOGGER.log(Level.WARNING, "Failed to read configuration files:", e); ++ throw new UserReportableException("Failed to load configuration files, check logs for further details."); ++ } ++ ++ try { ++ currentFlare.start(); ++ } catch (IllegalStateException e) { ++ PufferfishLogger.LOGGER.log(Level.WARNING, "Error starting Flare:", e); ++ throw new UserReportableException("Failed to start Flare, check logs for further details."); ++ } ++ ++ currentTask = Bukkit.getScheduler().runTaskLater(new MinecraftInternalPlugin(), ProfilingManager::stop, 20 * 60 * 15); ++ PufferfishLogger.LOGGER.log(Level.INFO, "Flare has been started: " + getProfilingUri()); ++ return true; ++ } ++ ++ public static synchronized boolean stop() { ++ if (!isProfiling()) { ++ return false; ++ } ++ if (!currentFlare.isRunning()) { ++ currentFlare = null; ++ return true; ++ } ++ PufferfishLogger.LOGGER.log(Level.INFO, "Flare has been stopped: " + getProfilingUri()); ++ try { ++ currentFlare.stop(); ++ } catch (IllegalStateException e) { ++ PufferfishLogger.LOGGER.log(Level.WARNING, "Error occurred stopping Flare", e); ++ } ++ currentFlare = null; ++ ++ try { ++ currentTask.cancel(); ++ } catch (Throwable t) { ++ PufferfishLogger.LOGGER.log(Level.WARNING, "Error occurred stopping Flare", t); ++ } ++ ++ currentTask = null; ++ return true; ++ } ++ ++} +diff --git a/src/main/java/gg/pufferfish/pufferfish/flare/collectors/GCEventCollector.java b/src/main/java/gg/pufferfish/pufferfish/flare/collectors/GCEventCollector.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d426575c669020f369960107da1e2de2f11f082f +--- /dev/null ++++ b/src/main/java/gg/pufferfish/pufferfish/flare/collectors/GCEventCollector.java +@@ -0,0 +1,66 @@ ++package gg.pufferfish.pufferfish.flare.collectors; ++ ++import co.technove.flare.Flare; ++import co.technove.flare.internal.FlareInternal; ++import co.technove.flare.live.CollectorData; ++import co.technove.flare.live.EventCollector; ++import co.technove.flare.live.LiveEvent; ++import co.technove.flare.live.category.GraphCategory; ++import co.technove.flare.live.formatter.DataFormatter; ++import com.google.common.collect.ImmutableMap; ++import com.sun.management.GarbageCollectionNotificationInfo; ++ ++import javax.management.ListenerNotFoundException; ++import javax.management.Notification; ++import javax.management.NotificationEmitter; ++import javax.management.NotificationListener; ++import javax.management.openmbean.CompositeData; ++import java.lang.management.GarbageCollectorMXBean; ++import java.lang.management.ManagementFactory; ++ ++public class GCEventCollector extends EventCollector implements NotificationListener { ++ ++ private static final CollectorData MINOR_GC = new CollectorData("builtin:gc:minor", "Minor GC", "A small pause in the program to allow Garbage Collection to run.", DataFormatter.MILLISECONDS, GraphCategory.SYSTEM); ++ private static final CollectorData MAJOR_GC = new CollectorData("builtin:gc:major", "Major GC", "A large pause in the program to allow Garbage Collection to run.", DataFormatter.MILLISECONDS, GraphCategory.SYSTEM); ++ private static final CollectorData UNKNOWN_GC = new CollectorData("builtin:gc:generic", "Major GC", "A run of the Garbage Collection.", DataFormatter.MILLISECONDS, GraphCategory.SYSTEM); ++ ++ public GCEventCollector() { ++ super(MINOR_GC, MAJOR_GC, UNKNOWN_GC); ++ } ++ ++ private static CollectorData fromString(String string) { ++ if (string.endsWith("minor GC")) { ++ return MINOR_GC; ++ } else if (string.endsWith("major GC")) { ++ return MAJOR_GC; ++ } ++ return UNKNOWN_GC; ++ } ++ ++ @Override ++ public void start(Flare flare) { ++ for (GarbageCollectorMXBean garbageCollectorBean : ManagementFactory.getGarbageCollectorMXBeans()) { ++ NotificationEmitter notificationEmitter = (NotificationEmitter) garbageCollectorBean; ++ notificationEmitter.addNotificationListener(this, null, null); ++ } ++ } ++ ++ @Override ++ public void stop(Flare flare) { ++ for (GarbageCollectorMXBean garbageCollectorBean : ManagementFactory.getGarbageCollectorMXBeans()) { ++ NotificationEmitter notificationEmitter = (NotificationEmitter) garbageCollectorBean; ++ try { ++ notificationEmitter.removeNotificationListener(this); ++ } catch (ListenerNotFoundException e) { ++ } ++ } ++ } ++ ++ @Override ++ public void handleNotification(Notification notification, Object o) { ++ if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { ++ GarbageCollectionNotificationInfo gcInfo = GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData()); ++ reportEvent(new LiveEvent(fromString(gcInfo.getGcAction()), System.currentTimeMillis(), (int) gcInfo.getGcInfo().getDuration(), ImmutableMap.of())); ++ } ++ } ++} +diff --git a/src/main/java/gg/pufferfish/pufferfish/flare/collectors/StatCollector.java b/src/main/java/gg/pufferfish/pufferfish/flare/collectors/StatCollector.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a22c6dbae53667e4c72464fa27153aee30c7946e +--- /dev/null ++++ b/src/main/java/gg/pufferfish/pufferfish/flare/collectors/StatCollector.java +@@ -0,0 +1,41 @@ ++package gg.pufferfish.pufferfish.flare.collectors; ++ ++import co.technove.flare.live.CollectorData; ++import co.technove.flare.live.LiveCollector; ++import co.technove.flare.live.category.GraphCategory; ++import co.technove.flare.live.formatter.DataFormatter; ++import com.sun.management.OperatingSystemMXBean; ++import oshi.SystemInfo; ++import oshi.hardware.CentralProcessor; ++ ++import java.lang.management.ManagementFactory; ++import java.time.Duration; ++ ++public class StatCollector extends LiveCollector { ++ ++ private static final CollectorData CPU = new CollectorData("builtin:stat:cpu", "CPU Load", "The total amount of CPU usage across all cores.", DataFormatter.PERCENT, GraphCategory.SYSTEM); ++ private static final CollectorData CPU_PROCESS = new CollectorData("builtin:stat:cpu_process", "Process CPU", "The amount of CPU being used by this process.", DataFormatter.PERCENT, GraphCategory.SYSTEM); ++ private static final CollectorData MEMORY = new CollectorData("builtin:stat:memory_used", "Memory", "The amount of memory being used currently.", DataFormatter.BYTES, GraphCategory.SYSTEM); ++ private static final CollectorData MEMORY_TOTAL = new CollectorData("builtin:stat:memory_total", "Memory Total", "The total amount of memory allocated.", DataFormatter.BYTES, GraphCategory.SYSTEM); ++ ++ private final OperatingSystemMXBean bean; ++ private final CentralProcessor processor; ++ ++ public StatCollector() { ++ super(CPU, CPU_PROCESS, MEMORY, MEMORY_TOTAL); ++ this.interval = Duration.ofSeconds(5); ++ ++ this.bean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); ++ this.processor = new SystemInfo().getHardware().getProcessor(); ++ } ++ ++ @Override ++ public void run() { ++ Runtime runtime = Runtime.getRuntime(); ++ ++ this.report(CPU, this.processor.getSystemLoadAverage(1)[0] / 100); // percentage ++ this.report(CPU_PROCESS, this.bean.getProcessCpuLoad()); ++ this.report(MEMORY, runtime.totalMemory() - runtime.freeMemory()); ++ this.report(MEMORY_TOTAL, runtime.totalMemory()); ++ } ++} +diff --git a/src/main/java/gg/pufferfish/pufferfish/flare/collectors/TPSCollector.java b/src/main/java/gg/pufferfish/pufferfish/flare/collectors/TPSCollector.java +new file mode 100644 +index 0000000000000000000000000000000000000000..40447d00aefb5ffedb8a2ee87155a04088f0649f +--- /dev/null ++++ b/src/main/java/gg/pufferfish/pufferfish/flare/collectors/TPSCollector.java +@@ -0,0 +1,31 @@ ++package gg.pufferfish.pufferfish.flare.collectors; ++ ++import co.technove.flare.live.CollectorData; ++import co.technove.flare.live.LiveCollector; ++import co.technove.flare.live.formatter.SuffixFormatter; ++import gg.pufferfish.pufferfish.flare.CustomCategories; ++import net.minecraft.server.MinecraftServer; ++import org.bukkit.Bukkit; ++ ++import java.time.Duration; ++import java.util.Arrays; ++ ++public class TPSCollector extends LiveCollector { ++ private static final CollectorData TPS = new CollectorData("airplane:tps", "TPS", "Ticks per second, or how fast the server updates. For a smooth server this should be a constant 20TPS.", SuffixFormatter.of("TPS"), CustomCategories.MC_PERF); ++ private static final CollectorData MSPT = new CollectorData("airplane:mspt", "MSPT", "Milliseconds per tick, which can show how well your server is performing. This value should always be under 50mspt.", SuffixFormatter.of("mspt"), CustomCategories.MC_PERF); ++ ++ public TPSCollector() { ++ super(TPS, MSPT); ++ ++ this.interval = Duration.ofSeconds(5); ++ } ++ ++ @Override ++ public void run() { ++ long[] times = MinecraftServer.getServer().tickTimes5s.getTimes(); ++ double mspt = ((double) Arrays.stream(times).sum() / (double) times.length) * 1.0E-6D; ++ ++ this.report(TPS, Math.min(20D, Math.round(Bukkit.getServer().getTPS()[0] * 100d) / 100d)); ++ this.report(MSPT, (double) Math.round(mspt * 100d) / 100d); ++ } ++} +diff --git a/src/main/java/gg/pufferfish/pufferfish/flare/collectors/WorldCountCollector.java b/src/main/java/gg/pufferfish/pufferfish/flare/collectors/WorldCountCollector.java +new file mode 100644 +index 0000000000000000000000000000000000000000..337a18cad9d328762f8431d1b3f2f8f822485064 +--- /dev/null ++++ b/src/main/java/gg/pufferfish/pufferfish/flare/collectors/WorldCountCollector.java +@@ -0,0 +1,45 @@ ++package gg.pufferfish.pufferfish.flare.collectors; ++ ++import co.technove.flare.live.CollectorData; ++import co.technove.flare.live.LiveCollector; ++import co.technove.flare.live.formatter.SuffixFormatter; ++import gg.pufferfish.pufferfish.flare.CustomCategories; ++import org.bukkit.Bukkit; ++import org.bukkit.World; ++import org.bukkit.craftbukkit.CraftWorld; ++ ++import java.time.Duration; ++ ++public class WorldCountCollector extends LiveCollector { ++ ++ private static final CollectorData PLAYER_COUNT = new CollectorData("airplane:world:playercount", "Player Count", "The number of players currently on the server.", new SuffixFormatter(" Player", " Players"), CustomCategories.ENTITIES_AND_CHUNKS); ++ private static final CollectorData ENTITY_COUNT = new CollectorData("airplane:world:entitycount", "Entity Count", "The number of entities in all worlds", new SuffixFormatter(" Entity", " Entities"), CustomCategories.ENTITIES_AND_CHUNKS); ++ private static final CollectorData CHUNK_COUNT = new CollectorData("airplane:world:chunkcount", "Chunk Count", "The number of chunks currently loaded.", new SuffixFormatter(" Chunk", " Chunks"), CustomCategories.ENTITIES_AND_CHUNKS); ++ private static final CollectorData TILE_ENTITY_COUNT = new CollectorData("airplane:world:blockentitycount", "Block Entity Count", "The number of block entities currently loaded.", new SuffixFormatter(" Block Entity", " Block Entities"), CustomCategories.ENTITIES_AND_CHUNKS); ++ ++ public WorldCountCollector() { ++ super(PLAYER_COUNT, ENTITY_COUNT, CHUNK_COUNT, TILE_ENTITY_COUNT); ++ ++ this.interval = Duration.ofSeconds(5); ++ } ++ ++ @Override ++ public void run() { ++ int entities = 0; ++ int chunkCount = 0; ++ int tileEntityCount = 0; ++ ++ if (!Bukkit.isStopping()) { ++ for (World world : Bukkit.getWorlds()) { ++ entities += ((CraftWorld) world).getHandle().getEntityLookup().getCount(); ++ chunkCount += world.getChunkCount(); ++ tileEntityCount += world.getTileEntityCount(); ++ } ++ } ++ ++ this.report(PLAYER_COUNT, Bukkit.getOnlinePlayers().size()); ++ this.report(ENTITY_COUNT, entities); ++ this.report(CHUNK_COUNT, chunkCount); ++ this.report(TILE_ENTITY_COUNT, tileEntityCount); ++ } ++} diff --git a/src/main/java/gg/pufferfish/pufferfish/sentry/PufferfishSentryAppender.java b/src/main/java/gg/pufferfish/pufferfish/sentry/PufferfishSentryAppender.java new file mode 100644 index 0000000000000000000000000000000000000000..731ef11c7a025ae95ed8a757b530d834733d0621 @@ -1415,6 +2141,18 @@ index 0000000000000000000000000000000000000000..facd55463d44cb7e3d2ca6892982f549 + return backingMap.size(); + } +} +diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java +index 7d7540cb917564c497eb3a5ef98fb068944694ea..eb22acd39de0c57a9089b452136c39bdf186f316 100644 +--- a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java ++++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java +@@ -36,6 +36,7 @@ import java.util.function.Consumer; + import java.util.function.Predicate; + + public final class EntityLookup implements LevelEntityGetter { ++ @Override public int getCount() { return this.accessibleEntities.size(); } // Pufferfish // Prismarine - Flare + + private static final Logger LOGGER = LogUtils.getLogger(); + diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java index 4a8286c78a9a5e305b19cc5d316bc73a78e49b4d..54bca103347e89f116fb7fbf37449a32ac094286 100644 --- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java @@ -3312,6 +4050,32 @@ index 4cdfc433df67afcd455422e9baf56f167dd712ae..57fcf3910f45ce371ac2e237b277b103 private void ensureActiveIsNotIterated() { // Paper - replace with better logic, do not delay removals +diff --git a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java +index 9723a0ad61548c8c6c4c5ef20a150d5b17d80afd..bdc430feebba71077405d1a33fca0dd3efabd5de 100644 +--- a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java ++++ b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetter.java +@@ -6,6 +6,8 @@ import javax.annotation.Nullable; + import net.minecraft.world.phys.AABB; + + public interface LevelEntityGetter { ++ int getCount(); // Pufferfish ++ + @Nullable + T get(int id); + +diff --git a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java +index d5129c12c79eb6fe6b7e5f8eed4d24226423f5fd..a9e19ae9b0ad0779dc046c38894beb4dc58042a2 100644 +--- a/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java ++++ b/src/main/java/net/minecraft/world/level/entity/LevelEntityGetterAdapter.java +@@ -14,6 +14,8 @@ public class LevelEntityGetterAdapter implements LevelEn + this.sectionStorage = cache; + } + ++ @Override public int getCount() { return this.visibleEntities.count(); } // Pufferfish ++ + @Nullable + @Override + public T get(int id) { diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java index ff40fe323964f173561a6838fb443e79abf9df38..c2c3ed6ba79f9f41497e042571f699a0fc6e9335 100644 --- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java @@ -3541,6 +4305,43 @@ index 0b3b46348ac9195bff1492ffc11fcbff7d3f5c6f..4010052c53f3a2831b4d5aa1c041d858 + MinecraftServer.getServer().getRecipeManager().addRecipe(new net.minecraft.world.item.crafting.ShapelessRecipe(CraftNamespacedKey.toMinecraft(this.getKey()), this.getGroup(), CraftItemStack.asNMSCopy(this.getResult()), data, true)); } } +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java b/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java +index 909b2c98e7a9117d2f737245e4661792ffafb744..0d9e2b3728f9ab500bd5e44702718535d338e9a5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java +@@ -22,7 +22,8 @@ public class MinecraftInternalPlugin extends PluginBase { + private boolean enabled = true; + + private final String pluginName; +- private PluginDescriptionFile pdf; ++ private org.bukkit.plugin.PluginLogger logger; ++ private PluginDescriptionFile pdf; // Pufferfish + + public MinecraftInternalPlugin() { + this.pluginName = "Minecraft"; +@@ -75,7 +76,12 @@ public class MinecraftInternalPlugin extends PluginBase { + + @Override + public PluginLogger getLogger() { +- throw new UnsupportedOperationException("Not supported."); ++ // Pufferfish start ++ if (this.logger == null) { ++ this.logger = new org.bukkit.plugin.PluginLogger(this); // Pufferfish ++ } ++ return this.logger; ++ // Pufferfish end + } + + @Override +@@ -85,7 +91,7 @@ public class MinecraftInternalPlugin extends PluginBase { + + @Override + public Server getServer() { +- throw new UnsupportedOperationException("Not supported."); ++ return org.bukkit.Bukkit.getServer(); // Pufferfish - impl + } + + @Override diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java index 1628913b1e9b91e68dcd942a38da4aed95b12d4a..05cc8f9cdcd7e920bf9503f68efb16cd74a359a2 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -3554,6 +4355,18 @@ index 1628913b1e9b91e68dcd942a38da4aed95b12d4a..05cc8f9cdcd7e920bf9503f68efb16cd } @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java +index e948ec5a573b22645664eb53bc3e9932246544e4..e3845dc3357bbb74885ae3a1a08525adde581235 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java +@@ -11,6 +11,7 @@ public class ServerShutdownThread extends Thread { + + @Override + public void run() { ++ try { gg.pufferfish.pufferfish.flare.ProfilingManager.stop(); } catch (Throwable t) {} // Pufferfish - shut down Flare if it's running + try { + // Paper start - try to shutdown on main + server.safeShutdown(false, false); diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java index 774556a62eb240da42e84db4502e2ed43495be17..80553face9c70c2a3d897681e7761df85b22d464 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java diff --git a/patches/server/0002-Purpur-Server-Changes.patch b/patches/server/0002-Purpur-Server-Changes.patch index fe35885..70004d5 100644 --- a/patches/server/0002-Purpur-Server-Changes.patch +++ b/patches/server/0002-Purpur-Server-Changes.patch @@ -25,7 +25,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/build.gradle.kts b/build.gradle.kts -index 9746ce97d05cace4104e6992126fb983beadc4cf..a61a0f4f1ce89681336d2ed246e6b616aa6fe73d 100644 +index 7b74ec475b1e953080d5aa8b0a10d1680e7c46f1..e2ee97d7a98e6eac3db4f2a06eaa35f1dde45db1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ plugins { @@ -56,7 +56,7 @@ index 9746ce97d05cace4104e6992126fb983beadc4cf..a61a0f4f1ce89681336d2ed246e6b616 exclude(group="org.yaml", module="snakeyaml") } // Pufferfish end -@@ -83,7 +86,7 @@ tasks.jar { +@@ -84,7 +87,7 @@ tasks.jar { attributes( "Main-Class" to "org.bukkit.craftbukkit.Main", "Implementation-Title" to "CraftBukkit", @@ -65,7 +65,7 @@ index 9746ce97d05cace4104e6992126fb983beadc4cf..a61a0f4f1ce89681336d2ed246e6b616 "Implementation-Vendor" to date, // Paper "Specification-Title" to "Bukkit", "Specification-Version" to project.version, -@@ -182,7 +185,7 @@ fun TaskContainer.registerRunTask( +@@ -183,7 +186,7 @@ fun TaskContainer.registerRunTask( name: String, block: JavaExec.() -> Unit ): TaskProvider = register(name) { @@ -273,10 +273,10 @@ index 46cab7a8c7b87ab01b26074b04f5a02b3907cfc4..f7449f6ec04356175a0349001a6daa27 } } diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -index ed9c8e882739c02d0d04129d251e4c726b422c07..c9ae76401278057f87ebef13619a114722e81a1d 100644 +index 5d75693abb78f1a6cb3595a4af6d1ca0795c1025..7cda3da7f9eb68e06570765ef8e0fa0b92ffb1ab 100644 --- a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java +++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -@@ -28,6 +28,7 @@ public class PufferfishConfig { +@@ -36,6 +36,7 @@ public class PufferfishConfig { private static final YamlFile config = new YamlFile(); private static int updates = 0; @@ -284,7 +284,7 @@ index ed9c8e882739c02d0d04129d251e4c726b422c07..c9ae76401278057f87ebef13619a1147 private static ConfigurationSection convertToBukkit(org.simpleyaml.configuration.ConfigurationSection section) { ConfigurationSection newSection = new MemoryConfiguration(); -@@ -50,7 +51,7 @@ public class PufferfishConfig { +@@ -58,7 +59,7 @@ public class PufferfishConfig { } public static void load() throws IOException { @@ -293,7 +293,7 @@ index ed9c8e882739c02d0d04129d251e4c726b422c07..c9ae76401278057f87ebef13619a1147 if (configFile.exists()) { try { -@@ -113,6 +114,22 @@ public class PufferfishConfig { +@@ -121,6 +122,22 @@ public class PufferfishConfig { config.setComment(key, String.join("\n", comment), CommentType.BLOCK); } } @@ -316,7 +316,7 @@ index ed9c8e882739c02d0d04129d251e4c726b422c07..c9ae76401278057f87ebef13619a1147 private static boolean getBoolean(String key, boolean defaultValue, String... comment) { return getBoolean(key, null, defaultValue, comment); -@@ -222,7 +239,7 @@ public class PufferfishConfig { +@@ -230,7 +247,7 @@ public class PufferfishConfig { public static int activationDistanceMod; private static void dynamicActivationOfBrains() throws IOException { @@ -325,7 +325,7 @@ index ed9c8e882739c02d0d04129d251e4c726b422c07..c9ae76401278057f87ebef13619a1147 startDistance = getInt("dab.start-distance", "activation-range.start-distance", 12, "This value determines how far away an entity has to be", "from the player to start being effected by DEAR."); -@@ -266,7 +283,7 @@ public class PufferfishConfig { +@@ -298,7 +315,7 @@ public class PufferfishConfig { public static boolean throttleInactiveGoalSelectorTick; private static void inactiveGoalSelectorThrottle() { diff --git a/patches/server/0005-Rebrand.patch b/patches/server/0005-Rebrand.patch index 7088904..fdca6b2 100644 --- a/patches/server/0005-Rebrand.patch +++ b/patches/server/0005-Rebrand.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Rebrand diff --git a/build.gradle.kts b/build.gradle.kts -index 4e4bc7e55a81dc44d7f6cfc6a8761141d0d3bb6c..86b5ec9cc5cf3dbfdaef3ad33d547d245d261ea1 100644 +index e2ee97d7a98e6eac3db4f2a06eaa35f1dde45db1..762d7405ddb661ce2913dff6963e076767297a52 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ plugins { @@ -17,7 +17,7 @@ index 4e4bc7e55a81dc44d7f6cfc6a8761141d0d3bb6c..86b5ec9cc5cf3dbfdaef3ad33d547d24 // Pufferfish start implementation("io.papermc.paper:paper-mojangapi:1.19.2-R0.1-SNAPSHOT") { exclude("io.papermc.paper", "paper-api") -@@ -86,7 +86,7 @@ tasks.jar { +@@ -87,7 +87,7 @@ tasks.jar { attributes( "Main-Class" to "org.bukkit.craftbukkit.Main", "Implementation-Title" to "CraftBukkit", diff --git a/patches/server/0026-Revert-Purpur-commit-disable-pufferfish-mechanical-c.patch b/patches/server/0026-Revert-Purpur-commit-disable-pufferfish-mechanical-c.patch index 35aae4d..3c3388a 100644 --- a/patches/server/0026-Revert-Purpur-commit-disable-pufferfish-mechanical-c.patch +++ b/patches/server/0026-Revert-Purpur-commit-disable-pufferfish-mechanical-c.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Revert Purpur commit "disable pufferfish mechanical changes diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -index c9ae76401278057f87ebef13619a114722e81a1d..e7266845645982dfbc7708e702ed39135ac5f732 100644 +index 7cda3da7f9eb68e06570765ef8e0fa0b92ffb1ab..86cdfabc754c55f68f6d8328e4a91473db254ddd 100644 --- a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java +++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -@@ -239,7 +239,7 @@ public class PufferfishConfig { +@@ -247,7 +247,7 @@ public class PufferfishConfig { public static int activationDistanceMod; private static void dynamicActivationOfBrains() throws IOException { @@ -18,7 +18,7 @@ index c9ae76401278057f87ebef13619a114722e81a1d..e7266845645982dfbc7708e702ed3913 startDistance = getInt("dab.start-distance", "activation-range.start-distance", 12, "This value determines how far away an entity has to be", "from the player to start being effected by DEAR."); -@@ -283,7 +283,7 @@ public class PufferfishConfig { +@@ -315,7 +315,7 @@ public class PufferfishConfig { public static boolean throttleInactiveGoalSelectorTick; private static void inactiveGoalSelectorThrottle() {