From 65a9ef5acf00b978bd605090790a638384769c1c Mon Sep 17 00:00:00 2001 From: mani123 <70480001+mani1232@users.noreply.github.com> Date: Sun, 11 Jun 2023 02:08:11 +0200 Subject: [PATCH] Initial Folia support (#2346) Co-authored-by: Dan Mulloy --- .../com/comphenix/protocol/ProtocolLib.java | 13 +- .../events/SerializedOfflinePlayer.java | 161 +++++++++++------- .../protocol/updater/SpigotUpdater.java | 33 ++-- .../protocol/utility/SchedulerUtil.java | 72 ++++++++ .../com/comphenix/protocol/utility/Util.java | 5 + src/main/resources/plugin.yml | 2 + 6 files changed, 198 insertions(+), 88 deletions(-) create mode 100644 src/main/java/com/comphenix/protocol/utility/SchedulerUtil.java diff --git a/src/main/java/com/comphenix/protocol/ProtocolLib.java b/src/main/java/com/comphenix/protocol/ProtocolLib.java index a4315669..8864d60a 100644 --- a/src/main/java/com/comphenix/protocol/ProtocolLib.java +++ b/src/main/java/com/comphenix/protocol/ProtocolLib.java @@ -27,12 +27,10 @@ import com.comphenix.protocol.injector.PacketFilterManager; import com.comphenix.protocol.metrics.Statistics; import com.comphenix.protocol.updater.Updater; import com.comphenix.protocol.updater.Updater.UpdateType; -import com.comphenix.protocol.utility.ByteBuddyFactory; -import com.comphenix.protocol.utility.ChatExtensions; -import com.comphenix.protocol.utility.MinecraftVersion; -import com.comphenix.protocol.utility.Util; +import com.comphenix.protocol.utility.*; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; + import java.io.File; import java.io.IOException; import java.util.HashSet; @@ -44,6 +42,7 @@ import java.util.logging.LogRecord; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; + import org.bukkit.Server; import org.bukkit.command.CommandExecutor; import org.bukkit.command.PluginCommand; @@ -57,7 +56,6 @@ import org.bukkit.plugin.java.JavaPlugin; * @author Kristian */ public class ProtocolLib extends JavaPlugin { - // Every possible error or warning report type public static final ReportType REPORT_CANNOT_DELETE_CONFIG = new ReportType( "Cannot delete old ProtocolLib configuration."); @@ -490,9 +488,8 @@ public class ProtocolLib extends JavaPlugin { } // Attempt to create task - this.packetTask = server.getScheduler().scheduleSyncRepeatingTask(this, () -> { + this.packetTask = SchedulerUtil.scheduleSyncRepeatingTask(this, () -> { AsyncFilterManager manager = (AsyncFilterManager) protocolManager.getAsynchronousManager(); - // We KNOW we're on the main thread at the moment manager.sendProcessedPackets(ProtocolLib.this.tickCounter++, true); @@ -567,7 +564,7 @@ public class ProtocolLib extends JavaPlugin { // Clean up if (this.packetTask >= 0) { - this.getServer().getScheduler().cancelTask(this.packetTask); + SchedulerUtil.cancelTask(this, packetTask); this.packetTask = -1; } diff --git a/src/main/java/com/comphenix/protocol/events/SerializedOfflinePlayer.java b/src/main/java/com/comphenix/protocol/events/SerializedOfflinePlayer.java index ea6b611a..fab48df2 100644 --- a/src/main/java/com/comphenix/protocol/events/SerializedOfflinePlayer.java +++ b/src/main/java/com/comphenix/protocol/events/SerializedOfflinePlayer.java @@ -2,21 +2,45 @@ * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * Copyright (C) 2012 Kristian S. Stangeland * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ package com.comphenix.protocol.events; +import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.MethodAccessor; +import com.comphenix.protocol.utility.ByteBuddyFactory; +import com.comphenix.protocol.utility.Util; +import net.bytebuddy.description.ByteCodeElement; +import net.bytebuddy.description.modifier.Visibility; +import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; +import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy; +import net.bytebuddy.implementation.FieldAccessor; +import net.bytebuddy.implementation.InvocationHandlerAdapter; +import net.bytebuddy.implementation.MethodCall; +import net.bytebuddy.implementation.MethodDelegation; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.FieldValue; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; +import org.bukkit.*; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.profile.PlayerProfile; +import org.jetbrains.annotations.NotNull; + import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -28,33 +52,9 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import com.comphenix.protocol.reflect.accessors.Accessors; -import com.comphenix.protocol.reflect.accessors.MethodAccessor; -import com.comphenix.protocol.utility.ByteBuddyFactory; - -import org.bukkit.*; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.profile.PlayerProfile; - -import net.bytebuddy.description.ByteCodeElement; -import net.bytebuddy.description.modifier.Visibility; -import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; -import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy; -import net.bytebuddy.implementation.FieldAccessor; -import net.bytebuddy.implementation.InvocationHandlerAdapter; -import net.bytebuddy.implementation.MethodCall; -import net.bytebuddy.implementation.MethodDelegation; -import net.bytebuddy.implementation.bind.annotation.AllArguments; -import net.bytebuddy.implementation.bind.annotation.Origin; -import net.bytebuddy.implementation.bind.annotation.FieldValue; -import net.bytebuddy.implementation.bind.annotation.RuntimeType; -import net.bytebuddy.matcher.ElementMatcher; -import net.bytebuddy.matcher.ElementMatchers; - /** * Represents a player object that can be serialized by Java. - * + * * @author Kristian */ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { @@ -65,7 +65,7 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { private static final long serialVersionUID = -2728976288470282810L; private transient Location bedSpawnLocation; - + // Relevant data about an offline player private String name; private UUID uuid; @@ -76,6 +76,8 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { private boolean playedBefore; private boolean online; private boolean whitelisted; + private long lastLogin; + private long lastSeen; private static final Constructor proxyPlayerConstructor = setupProxyPlayerConstructor(); @@ -85,9 +87,10 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { public SerializedOfflinePlayer() { // Do nothing } - + /** * Initialize this serializable offline player from another player. + * * @param offline - another player. */ public SerializedOfflinePlayer(OfflinePlayer offline) { @@ -100,8 +103,14 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { this.playedBefore = offline.hasPlayedBefore(); this.online = offline.isOnline(); this.whitelisted = offline.isWhitelisted(); + + // TODO needs to be reflectively obtained + if (Util.isUsingFolia()) { + // this.lastSeen = offline.getLastSeen(); + // this.lastLogin = offline.getLastLogin(); + } } - + @Override public boolean isOp() { return operator; @@ -122,49 +131,74 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { return bedSpawnLocation; } + // @Override + public long getLastLogin() { + return lastLogin; + } + + // @Override + public long getLastSeen() { + return lastSeen; + } + // TODO do we need to implement this? - - public void incrementStatistic(Statistic statistic) throws IllegalArgumentException { } - public void decrementStatistic(Statistic statistic) throws IllegalArgumentException { } + public void incrementStatistic(Statistic statistic) throws IllegalArgumentException { + } - public void incrementStatistic(Statistic statistic, int i) throws IllegalArgumentException { } + public void decrementStatistic(Statistic statistic) throws IllegalArgumentException { + } - public void decrementStatistic(Statistic statistic, int i) throws IllegalArgumentException { } + public void incrementStatistic(Statistic statistic, int i) throws IllegalArgumentException { + } - public void setStatistic(Statistic statistic, int i) throws IllegalArgumentException { } + public void decrementStatistic(Statistic statistic, int i) throws IllegalArgumentException { + } + + public void setStatistic(Statistic statistic, int i) throws IllegalArgumentException { + } public int getStatistic(Statistic statistic) throws IllegalArgumentException { return 0; } - public void incrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { } + public void incrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { + } - public void decrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { } + public void decrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { + } public int getStatistic(Statistic statistic, Material material) throws IllegalArgumentException { return 0; } - public void incrementStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException { } + public void incrementStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException { + } - public void decrementStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException { } + public void decrementStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException { + } - public void setStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException { } + public void setStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException { + } - public void incrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { } + public void incrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { + } - public void decrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { } + public void decrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { + } public int getStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { return 0; } - public void incrementStatistic(Statistic statistic, EntityType entityType, int i) throws IllegalArgumentException { } + public void incrementStatistic(Statistic statistic, EntityType entityType, int i) throws IllegalArgumentException { + } - public void decrementStatistic(Statistic statistic, EntityType entityType, int i) { } + public void decrementStatistic(Statistic statistic, EntityType entityType, int i) { + } - public void setStatistic(Statistic statistic, EntityType entityType, int i) { } + public void setStatistic(Statistic statistic, EntityType entityType, int i) { + } @Override public Location getLastDeathLocation() { @@ -187,7 +221,7 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { } @Override - public PlayerProfile getPlayerProfile() { + public @NotNull PlayerProfile getPlayerProfile() { return null; } @@ -195,7 +229,7 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { public String getName() { return name; } - + @Override public boolean hasPlayedBefore() { return playedBefore; @@ -209,7 +243,7 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { public void setBanned(boolean banned) { this.banned = banned; } - + @Override public boolean isOnline() { return online; @@ -227,14 +261,14 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { private void writeObject(ObjectOutputStream output) throws IOException { output.defaultWriteObject(); - + // Serialize the bed spawn location output.writeUTF(bedSpawnLocation.getWorld().getName()); output.writeDouble(bedSpawnLocation.getX()); output.writeDouble(bedSpawnLocation.getY()); output.writeDouble(bedSpawnLocation.getZ()); } - + private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException { input.defaultReadObject(); @@ -246,7 +280,7 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { input.readDouble() ); } - + private World getWorld(String name) { try { // Try to get the world at least @@ -256,7 +290,7 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { return null; } } - + @Override public Player getPlayer() { try { @@ -266,11 +300,12 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { return getProxyPlayer(); } } - + /** * Retrieve a player object that implements OfflinePlayer by referring to this object. *

* All other methods cause an exception. + * * @return Proxy object. */ public Player getProxyPlayer() { @@ -285,8 +320,7 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { } } - private static Constructor setupProxyPlayerConstructor() - { + private static Constructor setupProxyPlayerConstructor() { final Method[] offlinePlayerMethods = OfflinePlayer.class.getMethods(); final String[] methodNames = new String[offlinePlayerMethods.length]; for (int idx = 0; idx < offlinePlayerMethods.length; ++idx) @@ -321,9 +355,9 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { }); final InvocationHandlerAdapter throwException = InvocationHandlerAdapter.of((obj, method, args) -> { - throw new UnsupportedOperationException( + throw new UnsupportedOperationException( "The method " + method.getName() + " is not supported for offline players."); - }); + }); return ByteBuddyFactory.getInstance() .createSubclass(PlayerUnion.class, ConstructorStrategy.Default.NO_CONSTRUCTORS) @@ -354,7 +388,6 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable { * This interface extends both OfflinePlayer and Player (in that order) so that the class generated by ByteBuddy * looks at OfflinePlayer's methods first while still being a Player. */ - private interface PlayerUnion extends OfflinePlayer, Player - { + private interface PlayerUnion extends OfflinePlayer, Player { } } diff --git a/src/main/java/com/comphenix/protocol/updater/SpigotUpdater.java b/src/main/java/com/comphenix/protocol/updater/SpigotUpdater.java index 57d6d0db..9cc40801 100644 --- a/src/main/java/com/comphenix/protocol/updater/SpigotUpdater.java +++ b/src/main/java/com/comphenix/protocol/updater/SpigotUpdater.java @@ -1,24 +1,25 @@ /** - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2015 dmulloy2 - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2015 dmulloy2 + *

+ * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License along with this program; + * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA */ package com.comphenix.protocol.updater; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.error.Report; import com.comphenix.protocol.utility.Closer; +import com.comphenix.protocol.utility.SchedulerUtil; import org.bukkit.plugin.Plugin; import java.io.BufferedReader; @@ -42,7 +43,7 @@ public final class SpigotUpdater extends Updater { @Override public void start(UpdateType type) { waitForThread(); - + this.type = type; this.thread = new Thread(new SpigotUpdateRunnable()); this.thread.start(); @@ -80,7 +81,7 @@ public final class SpigotUpdater extends Updater { } finally { // Invoke the listeners on the main thread for (Runnable listener : listeners) { - plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, listener); + SchedulerUtil.execute(plugin, listener); } } } diff --git a/src/main/java/com/comphenix/protocol/utility/SchedulerUtil.java b/src/main/java/com/comphenix/protocol/utility/SchedulerUtil.java new file mode 100644 index 00000000..aa186b86 --- /dev/null +++ b/src/main/java/com/comphenix/protocol/utility/SchedulerUtil.java @@ -0,0 +1,72 @@ +package com.comphenix.protocol.utility; + +import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.MethodAccessor; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; + +import java.util.function.Consumer; + +public class SchedulerUtil { + private Object foliaScheduler; + private MethodAccessor runAtFixedRate; + private MethodAccessor cancelTasks; + private MethodAccessor execute; + + private static SchedulerUtil getInstance() { + return Holder.INSTANCE; + } + + private static class Holder { + private static final SchedulerUtil INSTANCE = new SchedulerUtil(); + } + + private SchedulerUtil() { + if (Util.isUsingFolia()) { + MethodAccessor getScheduler = Accessors.getMethodAccessor(Bukkit.getServer().getClass(), "getGlobalRegionScheduler"); + foliaScheduler = getScheduler.invoke(Bukkit.getServer()); + + runAtFixedRate = Accessors.getMethodAccessor(foliaScheduler.getClass(), "runAtFixedRate", Plugin.class, + Consumer.class, long.class, long.class); + cancelTasks = Accessors.getMethodAccessor(foliaScheduler.getClass(), "cancelTasks", Plugin.class); + execute = Accessors.getMethodAccessor(foliaScheduler.getClass(), "execute", Plugin.class, Runnable.class); + } + } + + public static int scheduleSyncRepeatingTask(Plugin plugin, Runnable runnable, long delay, long period) { + return getInstance().doScheduleSyncRepeatingTask(plugin, runnable, delay, period); + } + + private int doScheduleSyncRepeatingTask(Plugin plugin, Runnable runnable, long delay, long period) { + if (Util.isUsingFolia()) { + runAtFixedRate.invoke(foliaScheduler, plugin, (Consumer)(task -> runnable.run()), delay, period); + return 1; + } else { + return plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, runnable, delay, period); + } + } + + private void doCancelTask(Plugin plugin, int id) { + if (Util.isUsingFolia()) { + cancelTasks.invoke(foliaScheduler, plugin); + } else { + plugin.getServer().getScheduler().cancelTask(id); + } + } + + public static void cancelTask(Plugin plugin, int id) { + getInstance().doCancelTask(plugin, id); + } + + private void doExecute(Plugin plugin, Runnable runnable) { + if (Util.isUsingFolia()) { + execute.invoke(foliaScheduler, plugin, runnable); + } else { + plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, runnable); + } + } + + public static void execute(Plugin plugin, Runnable runnable) { + getInstance().doExecute(plugin, runnable); + } +} diff --git a/src/main/java/com/comphenix/protocol/utility/Util.java b/src/main/java/com/comphenix/protocol/utility/Util.java index 1691a61e..3f496d47 100644 --- a/src/main/java/com/comphenix/protocol/utility/Util.java +++ b/src/main/java/com/comphenix/protocol/utility/Util.java @@ -22,6 +22,7 @@ package com.comphenix.protocol.utility; public final class Util { private static final boolean SPIGOT = classExists("org.spigotmc.SpigotConfig"); + private static final boolean FOLIA = classExists("io.papermc.paper.threadedregions.RegionizedServer"); private static Class cachedBundleClass; public static boolean classExists(String className) { @@ -43,6 +44,10 @@ public final class Util { return SPIGOT; } + public static boolean isUsingFolia() { + return FOLIA; + } + /** * Checks if the server is getting reloaded by walking down the current thread stack trace. * diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 3db7f73c..f499d374 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -8,6 +8,8 @@ load: STARTUP database: false api-version: "1.13" +folia-supported: true + commands: protocol: description: Performs administrative tasks regarding ProtocolLib.