diff --git a/api/src/main/java/com/viaversion/viaversion/api/ViaManager.java b/api/src/main/java/com/viaversion/viaversion/api/ViaManager.java index 97b639ca0..17faa9b14 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/ViaManager.java +++ b/api/src/main/java/com/viaversion/viaversion/api/ViaManager.java @@ -131,4 +131,11 @@ public interface ViaManager { * @param runnable runnable to be executed */ void addEnableListener(Runnable runnable); + + /** + * Returns whether the manager has been initialized (and protocols have been loaded). + * + * @return whether the manager has been initialized + */ + boolean isInitialized(); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/configuration/ViaVersionConfig.java b/api/src/main/java/com/viaversion/viaversion/api/configuration/ViaVersionConfig.java index fbb45f95d..5e00f8b80 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/configuration/ViaVersionConfig.java +++ b/api/src/main/java/com/viaversion/viaversion/api/configuration/ViaVersionConfig.java @@ -256,6 +256,8 @@ public interface ViaVersionConfig { */ boolean is1_13TeamColourFix(); + boolean shouldRegisterUserConnectionOnJoin(); + /** * Should we fix shift quick move action for 1.12 clients * diff --git a/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/ViaBukkitListener.java b/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/ViaBukkitListener.java index 201dbcf9d..95e669976 100644 --- a/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/ViaBukkitListener.java +++ b/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/ViaBukkitListener.java @@ -57,10 +57,12 @@ public class ViaBukkitListener extends ViaListener implements Listener { */ @Override public void register() { - if (isRegistered()) return; + if (isRegistered()) { + return; + } - plugin.getServer().getPluginManager().registerEvents(this, plugin); setRegistered(true); + plugin.getServer().getPluginManager().registerEvents(this, plugin); } public Plugin getPlugin() { diff --git a/bukkit/src/main/java/com/viaversion/viaversion/ViaVersionPlugin.java b/bukkit/src/main/java/com/viaversion/viaversion/ViaVersionPlugin.java index 11f4fde1c..9263cc102 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/ViaVersionPlugin.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/ViaVersionPlugin.java @@ -27,6 +27,7 @@ import com.viaversion.viaversion.api.platform.UnsupportedSoftware; import com.viaversion.viaversion.api.platform.ViaPlatform; import com.viaversion.viaversion.bukkit.commands.BukkitCommandHandler; import com.viaversion.viaversion.bukkit.commands.BukkitCommandSender; +import com.viaversion.viaversion.bukkit.listeners.JoinListener; import com.viaversion.viaversion.bukkit.platform.BukkitViaAPI; import com.viaversion.viaversion.bukkit.platform.BukkitViaConfig; import com.viaversion.viaversion.bukkit.platform.BukkitViaInjector; @@ -35,6 +36,7 @@ import com.viaversion.viaversion.bukkit.platform.BukkitViaTask; import com.viaversion.viaversion.bukkit.platform.BukkitViaTaskTask; import com.viaversion.viaversion.bukkit.platform.PaperViaInjector; import com.viaversion.viaversion.dump.PluginInfo; +import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ChatRewriter; import com.viaversion.viaversion.unsupported.UnsupportedPlugin; import com.viaversion.viaversion.unsupported.UnsupportedServerSoftware; import com.viaversion.viaversion.util.GsonUtil; @@ -79,6 +81,15 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform // Config magic conf = new BukkitViaConfig(); + + // Load a bunch of classes early with slow reflection and more classloading + Via.getManager().getScheduler().execute(() -> { + if (conf.shouldRegisterUserConnectionOnJoin()) { + JoinListener.init(); + } + + ChatRewriter.init(); + }); } @Override diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/JoinListener.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/JoinListener.java index 04a52ec3f..8ef85b911 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/JoinListener.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/JoinListener.java @@ -42,13 +42,13 @@ public class JoinListener implements Listener { private static final Field CHANNEL; static { - Method gh = null; - Field conn = null, nm = null, ch = null; + Method getHandleMethod = null; + Field gamePacketListenerField = null, connectionField = null, channelField = null; try { - gh = NMSUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle"); - conn = findField(gh.getReturnType(), "PlayerConnection", "ServerGamePacketListenerImpl"); - nm = findField(conn.getType(), "NetworkManager", "Connection"); - ch = findField(nm.getType(), "Channel"); + getHandleMethod = NMSUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle"); + gamePacketListenerField = findField(getHandleMethod.getReturnType(), "PlayerConnection", "ServerGamePacketListenerImpl"); + connectionField = findField(gamePacketListenerField.getType(), "NetworkManager", "Connection"); + channelField = findField(connectionField.getType(), Class.forName("io.netty.channel.Channel")); } catch (NoSuchMethodException | NoSuchFieldException | ClassNotFoundException e) { Via.getPlatform().getLogger().log( Level.WARNING, @@ -56,27 +56,47 @@ public class JoinListener implements Listener { "Login race condition fixer will be disabled.\n" + " Some plugins that use ViaAPI on join event may work incorrectly.", e); } - GET_HANDLE = gh; - CONNECTION = conn; - NETWORK_MANAGER = nm; - CHANNEL = ch; + GET_HANDLE = getHandleMethod; + CONNECTION = gamePacketListenerField; + NETWORK_MANAGER = connectionField; + CHANNEL = channelField; + } + + public static void init() { } // Loosely search a field with any name, as long as it matches a type name. - private static Field findField(Class cl, String... types) throws NoSuchFieldException { - for (Field field : cl.getDeclaredFields()) { + private static Field findField(Class clazz, String... types) throws NoSuchFieldException { + for (Field field : clazz.getDeclaredFields()) { + String fieldTypeName = field.getType().getSimpleName(); for (String type : types) { - if (field.getType().getSimpleName().equals(type)) { - if (!Modifier.isPublic(field.getModifiers())) { - field.setAccessible(true); - } - return field; + if (!fieldTypeName.equals(type)) { + continue; } + + if (!Modifier.isPublic(field.getModifiers())) { + field.setAccessible(true); + } + return field; } } throw new NoSuchFieldException(types[0]); } + private static Field findField(Class clazz, Class fieldType) throws NoSuchFieldException { + for (Field field : clazz.getDeclaredFields()) { + if (field.getType() != fieldType) { + continue; + } + + if (!Modifier.isPublic(field.getModifiers())) { + field.setAccessible(true); + } + return field; + } + throw new NoSuchFieldException(fieldType.getSimpleName()); + } + @EventHandler(priority = EventPriority.LOWEST) public void onJoin(PlayerJoinEvent e) { if (CHANNEL == null) return; diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaConfig.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaConfig.java index 439587e3c..b85e3bb52 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaConfig.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaConfig.java @@ -32,6 +32,7 @@ public class BukkitViaConfig extends AbstractViaConfig { private boolean hitboxFix1_14; private String blockConnectionMethod; private boolean armorToggleFix; + private boolean registerUserConnectionOnJoin; public BukkitViaConfig() { super(new File(((Plugin) Via.getPlatform()).getDataFolder(), "config.yml")); @@ -41,6 +42,7 @@ public class BukkitViaConfig extends AbstractViaConfig { @Override protected void loadFields() { super.loadFields(); + registerUserConnectionOnJoin = getBoolean("register-userconnections-on-join", true); quickMoveActionFix = getBoolean("quick-move-action-fix", false); hitboxFix1_9 = getBoolean("change-1_9-hitbox", false); hitboxFix1_14 = getBoolean("change-1_14-hitbox", false); @@ -52,6 +54,11 @@ public class BukkitViaConfig extends AbstractViaConfig { protected void handleConfig(Map config) { } + @Override + public boolean shouldRegisterUserConnectionOnJoin() { + return registerUserConnectionOnJoin; + } + @Override public boolean is1_12QuickMoveActionFix() { return quickMoveActionFix; diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaInjector.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaInjector.java index e3e0690d9..955433748 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaInjector.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaInjector.java @@ -187,7 +187,7 @@ public class BukkitViaInjector extends LegacyViaInjector { @Override public boolean lateProtocolVersionSetting() { - return !PaperViaInjector.PAPER_PROTOCOL_METHOD && !HAS_SHARED_CONSTANTS; + return !(PaperViaInjector.PAPER_PROTOCOL_METHOD || HAS_SHARED_CONSTANTS); } public boolean isBinded() { diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaLoader.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaLoader.java index 2a3f36151..62c17976a 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaLoader.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaLoader.java @@ -51,16 +51,13 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.scheduler.BukkitTask; public class BukkitViaLoader implements ViaPlatformLoader { - private final ViaVersionPlugin plugin; - private final Set listeners = new HashSet<>(); private final Set tasks = new HashSet<>(); - + private final ViaVersionPlugin plugin; private HandItemCache handItemCache; public BukkitViaLoader(ViaVersionPlugin plugin) { @@ -68,21 +65,21 @@ public class BukkitViaLoader implements ViaPlatformLoader { } public void registerListener(Listener listener) { - Bukkit.getPluginManager().registerEvents(storeListener(listener), plugin); + plugin.getServer().getPluginManager().registerEvents(listener, plugin); } + @Deprecated/*(forRemoval = true)*/ public T storeListener(T listener) { - listeners.add(listener); return listener; } @Override public void load() { - // Update Listener registerListener(new UpdateListener()); - // Login listener - registerListener(new JoinListener()); + if (Via.getConfig().shouldRegisterUserConnectionOnJoin()) { + registerListener(new JoinListener()); + } /* Base Protocol */ final ViaVersionPlugin plugin = (ViaVersionPlugin) Bukkit.getPluginManager().getPlugin("ViaVersion"); @@ -92,13 +89,18 @@ public class BukkitViaLoader implements ViaPlatformLoader { ProtocolSupportCompat.registerPSConnectListener(plugin); } + if (!Via.getAPI().getServerVersion().isKnown()) { + Via.getPlatform().getLogger().severe("Server version has not been loaded yet, cannot register additional listeners"); + return; + } + int serverProtocolVersion = Via.getAPI().getServerVersion().lowestSupportedVersion(); /* 1.9 client to 1.8 server */ if (serverProtocolVersion < ProtocolVersion.v1_9.getVersion()) { - storeListener(new ArmorListener(plugin)).register(); - storeListener(new DeathListener(plugin)).register(); - storeListener(new BlockListener(plugin)).register(); + new ArmorListener(plugin).register(); + new DeathListener(plugin).register(); + new BlockListener(plugin).register(); if (plugin.getConf().isItemCache()) { handItemCache = new HandItemCache(); @@ -110,7 +112,7 @@ public class BukkitViaLoader implements ViaPlatformLoader { boolean use1_9Fix = plugin.getConf().is1_9HitboxFix() && serverProtocolVersion < ProtocolVersion.v1_9.getVersion(); if (use1_9Fix || plugin.getConf().is1_14HitboxFix()) { try { - storeListener(new PlayerSneakListener(plugin, use1_9Fix, plugin.getConf().is1_14HitboxFix())).register(); + new PlayerSneakListener(plugin, use1_9Fix, plugin.getConf().is1_14HitboxFix()).register(); } catch (ReflectiveOperationException e) { Via.getPlatform().getLogger().warning("Could not load hitbox fix - please report this on our GitHub"); e.printStackTrace(); @@ -121,7 +123,7 @@ public class BukkitViaLoader implements ViaPlatformLoader { if (serverProtocolVersion < ProtocolVersion.v1_15.getVersion()) { try { Class.forName("org.bukkit.event.entity.EntityToggleGlideEvent"); - storeListener(new EntityToggleGlideListener(plugin)).register(); + new EntityToggleGlideListener(plugin).register(); } catch (ClassNotFoundException ignored) { } } @@ -138,12 +140,12 @@ public class BukkitViaLoader implements ViaPlatformLoader { } } if (paper) { - storeListener(new PaperPatch(plugin)).register(); + new PaperPatch(plugin).register(); } } if (serverProtocolVersion < ProtocolVersion.v1_19_4.getVersion() && plugin.getConf().isArmorToggleFix()) { - storeListener(new ArmorToggleListener(plugin)).register(); + new ArmorToggleListener(plugin).register(); } /* Providers */ @@ -189,16 +191,12 @@ public class BukkitViaLoader implements ViaPlatformLoader { } if (serverProtocolVersion < ProtocolVersion.v1_19.getVersion()) { Via.getManager().getProviders().use(AckSequenceProvider.class, new BukkitAckSequenceProvider(plugin)); - storeListener(new BlockBreakListener(plugin)).register(); + new BlockBreakListener(plugin).register(); } } @Override public void unload() { - for (Listener listener : listeners) { - HandlerList.unregisterAll(listener); - } - listeners.clear(); for (BukkitTask task : tasks) { task.cancel(); } diff --git a/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java b/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java index 4edba529d..72d97ebc3 100644 --- a/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java @@ -63,6 +63,7 @@ public class ViaManagerImpl implements ViaManager { private final Set subPlatforms = new HashSet<>(); private List enableListeners = new ArrayList<>(); private PlatformTask mappingLoadingTask; + private boolean initialized; public ViaManagerImpl(ViaPlatform platform, ViaInjector injector, ViaCommandHandler commandHandler, ViaPlatformLoader loader) { this.platform = platform; @@ -105,6 +106,8 @@ public class ViaManagerImpl implements ViaManager { listener.run(); } enableListeners = null; + + initialized = true; } public void onServerLoaded() { @@ -149,9 +152,6 @@ public class ViaManagerImpl implements ViaManager { // Check for unsupported plugins/software unsupportedSoftwareWarning(); - // Load Listeners / Tasks - protocolManager.onServerLoaded(); - // Load Platform loader.load(); // Common tasks @@ -324,6 +324,11 @@ public class ViaManagerImpl implements ViaManager { enableListeners.add(runnable); } + @Override + public boolean isInitialized() { + return initialized; + } + public static final class ViaManagerBuilder { private ViaPlatform platform; private ViaInjector injector; diff --git a/common/src/main/java/com/viaversion/viaversion/configuration/AbstractViaConfig.java b/common/src/main/java/com/viaversion/viaversion/configuration/AbstractViaConfig.java index 623aa6934..384c4dddb 100644 --- a/common/src/main/java/com/viaversion/viaversion/configuration/AbstractViaConfig.java +++ b/common/src/main/java/com/viaversion/viaversion/configuration/AbstractViaConfig.java @@ -383,6 +383,11 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf return nbtArrayFix; } + @Override + public boolean shouldRegisterUserConnectionOnJoin() { + return false; + } + @Override public boolean is1_12QuickMoveActionFix() { return false; diff --git a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java index d4639705a..bc5f388d3 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java @@ -109,11 +109,10 @@ public class ProtocolManagerImpl implements ProtocolManager { // Input Version -> Output Version & Protocol (Allows fast lookup) private final Int2ObjectMap> registryMap = new Int2ObjectOpenHashMap<>(32); - private final Map, Protocol> protocols = new HashMap<>(); + private final Map, Protocol> protocols = new HashMap<>(64); private final Map> pathCache = new ConcurrentHashMap<>(); private final Set supportedVersions = new HashSet<>(); private final List, Protocol>> baseProtocols = Lists.newCopyOnWriteArrayList(); - private final List registerList = new ArrayList<>(); private final ReadWriteLock mappingLoaderLock = new ReentrantReadWriteLock(); private Map, CompletableFuture> mappingLoaderFutures = new HashMap<>(); @@ -208,11 +207,9 @@ public class ProtocolManagerImpl implements ProtocolManager { protocolMap.put(serverVersion, protocol); } - if (Via.getPlatform().isPluginEnabled()) { - protocol.register(Via.getManager().getProviders()); + protocol.register(Via.getManager().getProviders()); + if (Via.getManager().isInitialized()) { refreshVersions(); - } else { - registerList.add(protocol); } if (protocol.hasMappingDataToLoad()) { @@ -232,11 +229,9 @@ public class ProtocolManagerImpl implements ProtocolManager { baseProtocol.initialize(); baseProtocols.add(new Pair<>(supportedProtocols, baseProtocol)); - if (Via.getPlatform().isPluginEnabled()) { - baseProtocol.register(Via.getManager().getProviders()); + baseProtocol.register(Via.getManager().getProviders()); + if (Via.getManager().isInitialized()) { refreshVersions(); - } else { - registerList.add(baseProtocol); } } @@ -498,16 +493,6 @@ public class ProtocolManagerImpl implements ProtocolManager { return new PacketWrapperImpl(packetId, buf, connection); } - /** - * Called when the server is enabled, to register any non-registered listeners. - */ - public void onServerLoaded() { - for (Protocol protocol : registerList) { - protocol.register(Via.getManager().getProviders()); - } - registerList.clear(); - } - public void shutdownLoaderExecutor() { Preconditions.checkArgument(!mappingsLoaded); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/ChatRewriter.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/ChatRewriter.java index 7f7bd75ed..1a1622eec 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/ChatRewriter.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/ChatRewriter.java @@ -28,6 +28,10 @@ import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.legacy.Leg public final class ChatRewriter { public static final GsonComponentSerializer HOVER_GSON_SERIALIZER = GsonComponentSerializer.builder().emitLegacyHoverEvent().legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get()).build(); + public static final JsonElement EMPTY_COMPONENT = GsonComponentSerializer.gson().serializeToTree(Component.empty()); + + public static void init() { + } public static String legacyTextToJsonString(String message, boolean itemData) { // Not used for chat messages, so no need for url extraction diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_4to1_19_3/Protocol1_19_4To1_19_3.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_4to1_19_3/Protocol1_19_4To1_19_3.java index 29ae5e2e4..e1262b1e2 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_4to1_19_3/Protocol1_19_4To1_19_3.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_4to1_19_3/Protocol1_19_4To1_19_3.java @@ -28,6 +28,7 @@ import com.viaversion.viaversion.api.type.types.version.Types1_19_4; import com.viaversion.viaversion.data.entity.EntityTrackerBase; import com.viaversion.viaversion.libs.kyori.adventure.text.Component; import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ChatRewriter; import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ClientboundPackets1_19_3; import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ServerboundPackets1_19_3; import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.data.MappingData; @@ -42,7 +43,6 @@ import java.util.Base64; public final class Protocol1_19_4To1_19_3 extends AbstractProtocol { public static final MappingData MAPPINGS = new MappingData(); - private static final JsonElement EMPTY_COMPONENT = GsonComponentSerializer.gson().serializeToTree(Component.empty()); private final EntityPackets entityRewriter = new EntityPackets(this); private final InventoryPackets itemRewriter = new InventoryPackets(this); @@ -60,7 +60,6 @@ public final class Protocol1_19_4To1_19_3 extends AbstractProtocol(this) { @Override public void handleArgument(final PacketWrapper wrapper, final String argumentType) throws Exception { @@ -78,7 +77,7 @@ public final class Protocol1_19_4To1_19_3 extends AbstractProtocol> 8); final short enchantID = (short) (value & 0xFF); - wrapper.create(wrapper.getId(), new PacketHandler() { - @Override - public void handle(PacketWrapper wrapper) throws Exception { - wrapper.write(Type.UNSIGNED_BYTE, windowId); - wrapper.write(Type.SHORT, property); - wrapper.write(Type.SHORT, enchantID); - } + wrapper.create(wrapper.getId(), propertyPacket -> { + propertyPacket.write(Type.UNSIGNED_BYTE, windowId); + propertyPacket.write(Type.SHORT, property); + propertyPacket.write(Type.SHORT, enchantID); }).scheduleSend(Protocol1_9To1_8.class); wrapper.set(Type.SHORT, 0, (short) (property + 3)); diff --git a/common/src/main/resources/assets/viaversion/config.yml b/common/src/main/resources/assets/viaversion/config.yml index 90a5bed66..f19749ef6 100644 --- a/common/src/main/resources/assets/viaversion/config.yml +++ b/common/src/main/resources/assets/viaversion/config.yml @@ -102,6 +102,9 @@ tracking-max-kick-msg: "You are sending too many packets, :(" # MULTIPLE VERSIONS OPTIONS # #----------------------------------------------------------# # +# Whether to make sure ViaVersion's UserConnection object is already available in the PlayerJoinEvent. +# You may disable this for faster startup/join time if you are 100% sure no plugin requires this. +register-userconnections-on-join: true # Should we enable our hologram patch? # If they're in the wrong place enable this hologram-patch: false