Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add experimental packetevents support #461

Merged
merged 5 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ dependencies {
compileOnly 'org.apache.logging.log4j:log4j-core:2.17.1'
compileOnly 'org.yaml:snakeyaml:2.0'

compileOnly 'com.github.retrooper:packetevents-api:2.7.0'

implementation 'org.slf4j:slf4j-nop:1.7.36'
implementation 'com.zaxxer:HikariCP:4.0.3'
implementation('com.tananaev:json-patch:1.1') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public LoaderBootstrap loadPlugin() {
}
}

if (flags.contains(LoaderFlag.VENDOR_PACKET_EVENTS)) {
relocations.add(new Relocation("com/github/retrooper/packetevents", "com/rexcantor64/triton/lib/packetevents/api"));
relocations.add(new Relocation("io/github/retrooper/packetevents", "com/rexcantor64/triton/lib/packetevents/impl"));
}

@SuppressWarnings("resource")
JarInJarClassLoader loader = new JarInJarClassLoader(getClass().getClassLoader(), relocations, CORE_JAR_NAME, jarInJarName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
public enum LoaderFlag {
SHADE_ADVENTURE,
RELOCATE_ADVENTURE,
VENDOR_PACKET_EVENTS,
}
46 changes: 43 additions & 3 deletions core/src/main/java/com/rexcantor64/triton/Triton.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
import com.rexcantor64.triton.config.interfaces.ConfigurationProvider;
import com.rexcantor64.triton.config.interfaces.YamlConfiguration;
import com.rexcantor64.triton.debug.DumpManager;
import com.rexcantor64.triton.dependencies.Dependency;
import com.rexcantor64.triton.language.LanguageManager;
import com.rexcantor64.triton.language.TranslationManager;
import com.rexcantor64.triton.language.parser.AdventureParser;
import com.rexcantor64.triton.loader.utils.LoaderFlag;
import com.rexcantor64.triton.logger.TritonLogger;
import com.rexcantor64.triton.migration.LanguageMigration;
import com.rexcantor64.triton.player.LanguagePlayer;
import com.rexcantor64.triton.packetinterceptor.PacketEventsManager;
import com.rexcantor64.triton.player.TritonLanguagePlayer;
import com.rexcantor64.triton.player.PlayerManager;
import com.rexcantor64.triton.plugin.Platform;
import com.rexcantor64.triton.plugin.PluginLoader;
Expand All @@ -26,6 +29,7 @@
import com.rexcantor64.triton.web.TwinManager;
import lombok.Getter;
import lombok.val;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.InputStreamReader;
Expand All @@ -35,7 +39,7 @@
import java.util.UUID;

@Getter
public abstract class Triton<P extends LanguagePlayer, B extends BridgeManager> implements com.rexcantor64.triton.api.Triton {
public abstract class Triton<P extends TritonLanguagePlayer<?>, B extends BridgeManager> implements com.rexcantor64.triton.api.Triton {

// Main instances
protected static Triton<?, ?> instance;
Expand All @@ -58,6 +62,7 @@ public abstract class Triton<P extends LanguagePlayer, B extends BridgeManager>
private Storage storage;
private TritonLogger logger;
private DumpManager dumpManager;
protected @Nullable PacketEventsManager packetEventsManager;

protected Triton(PlayerManager<P> playerManager, B bridgeManager) {
this.playerManager = playerManager;
Expand Down Expand Up @@ -106,6 +111,29 @@ protected void onEnable() {
reload();

twinManager = new TwinManager(this);

if (config.isUsePacketEvents()) {
val dependencyManager = Triton.get().getLoader().getDependencyManager();
val isPacketEventsVendored = dependencyManager.hasLoaderFlag(LoaderFlag.VENDOR_PACKET_EVENTS);
if (isPacketEventsVendored) {
// load packet events dependency (netty and platform related modules are loaded later)
dependencyManager.loadDependency(Dependency.PACKET_EVENTS_API);
}
this.initPacketEventsManager();
}

if (this.packetEventsManager != null) {
// TODO: when spigot is supported, onLoad needs to be called earlier
this.packetEventsManager.onLoad();
this.packetEventsManager.onEnable();
}
}

protected void onDisable() {
// TODO: this should be called at some point
if (this.packetEventsManager != null) {
this.packetEventsManager.onDisable();
}
}

public void reload() {
Expand All @@ -117,13 +145,25 @@ public void reload() {
setupStorage();
languageManager.setup();
translationManager.setup();
if (this.packetEventsManager != null) {
this.packetEventsManager.onReload();
}
startConfigRefreshTask();
}

/**
* Initialize the platform's {@link PacketEventsManager} by setting the
* {@link Triton#packetEventsManager} variable.
* A platform is allowed to not do anything in case PacketEvents is not supported (yet).
*
* @since 4.0.0
*/
protected abstract void initPacketEventsManager();

public void refreshPlayers() {
playerManager.getAll().stream()
.filter(Objects::nonNull)
.forEach(LanguagePlayer::refreshAll);
.forEach(TritonLanguagePlayer::refreshAll);
}

public Configuration loadYAML(String fileName, String internalFileName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import com.rexcantor64.triton.commands.handler.CommandEvent;
import com.rexcantor64.triton.language.item.LanguageSign;
import com.rexcantor64.triton.language.item.LanguageText;
import com.rexcantor64.triton.player.LanguagePlayer;
import com.rexcantor64.triton.player.TritonLanguagePlayer;
import com.rexcantor64.triton.storage.LocalStorage;
import lombok.Getter;
import lombok.NonNull;
Expand Down Expand Up @@ -202,7 +202,7 @@ public static List<byte[]> buildTranslationData(String serverName, byte @NonNull
return outList;
}

public static byte[] buildPlayerLanguageData(LanguagePlayer lp) {
public static byte[] buildPlayerLanguageData(TritonLanguagePlayer<?> lp) {
val out = ByteStreams.newDataOutput();
out.writeByte(ActionP2S.SEND_PLAYER_LANGUAGE.getKey());
val uuid = lp.getUUID();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public class MainConfig implements TritonConfig {
private boolean preventPlaceholdersInChat;
private int maxPlaceholdersInMessage;
private boolean asyncProtocolLib;
private boolean usePacketEvents;

private String storageType = "local";
private String serverName;
Expand Down Expand Up @@ -182,6 +183,7 @@ private void setup(Configuration section) {
this.logLevel = section.getInt("log-level", 0);
this.configAutoRefresh = section.getInt("config-auto-refresh-interval", -1);
this.asyncProtocolLib = section.getBoolean("experimental-async-protocol-lib", false);
this.usePacketEvents = section.getBoolean("experimental-use-packetevents", false);
Configuration languageCreation = section.getSection("language-creation");
setupLanguageCreation(languageCreation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.rexcantor64.triton.Triton;
import com.rexcantor64.triton.api.config.FeatureSyntax;
import com.rexcantor64.triton.api.language.Localized;
import com.rexcantor64.triton.player.LanguagePlayer;
import com.rexcantor64.triton.player.TritonLanguagePlayer;
import lombok.Cleanup;
import lombok.Getter;
import lombok.val;
Expand Down Expand Up @@ -70,7 +70,7 @@ public void enableForEveryone(Collection<FeatureSyntax> enabledTypes) {
/**
* Enable message dumping for messages of certain types (chat, action bars, etc.)
* sent to a given player.
* Some messages that are not translated using the {@link com.rexcantor64.triton.player.LanguagePlayer}
* Some messages that are not translated using the {@link TritonLanguagePlayer}
* instance might not be correctly identified.
* <p>
* If the message dumping is already enabled for the player, current
Expand Down Expand Up @@ -149,8 +149,8 @@ private boolean shouldDump(Localized localized, FeatureSyntax type) {
// Quickly determine that dumping is disabled without querying the Map
return false;
}
if (localized instanceof LanguagePlayer) {
val uuid = ((LanguagePlayer) localized).getUUID();
if (localized instanceof TritonLanguagePlayer) {
val uuid = ((TritonLanguagePlayer<?>) localized).getUUID();
val playerSettings = filter.get(uuid);
if (playerSettings != null) {
// Use referential equality instead of object equality, since we want to compare if the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,33 @@ public enum Dependency {
"1.0.0",
"K95aei1z+hFmoPFmOiLDr30naP/E/qMxd0w8D2IiXRE=",
relocate("net{}kyori{}option", "kyori{}option")
),

// PacketEvents
PACKET_EVENTS_API(
"com{}github{}retrooper",
"packetevents-api",
"2.7.0",
"XoTsr+ybxGU/vsYeRgJz2DHaHTFrNl9fSI+pCtIRIqk=",
relocate("com{}github{}retrooper{}packetevents", "packetevents{}api"),
relocate("io{}github{}retrooper{}packetevents", "packetevents{}impl")
// TODO relocate adventure (?)
),
PACKET_EVENTS_NETTY_COMMON(
"com{}github{}retrooper",
"packetevents-netty-common",
"2.7.0",
"cpJZ4KLNP9JRnRma3fi4mg7YrMqVTLzYgo43Sq8REEQ=",
relocate("com{}github{}retrooper{}packetevents", "packetevents{}api"),
relocate("io{}github{}retrooper{}packetevents", "packetevents{}impl")
),
PACKET_EVENTS_VELOCITY(
"com{}github{}retrooper",
"packetevents-velocity",
"2.7.0",
"B6QY2bgD6c4z7YngG5kc9N02/veLKT6NH9wRiflKNXY=",
relocate("com{}github{}retrooper{}packetevents", "packetevents{}api"),
relocate("io{}github{}retrooper{}packetevents", "packetevents{}impl")
);

@Getter
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.rexcantor64.triton.packetinterceptor;

import com.github.retrooper.packetevents.event.PacketListener;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.rexcantor64.triton.Triton;
import com.rexcantor64.triton.packetinterceptor.handlers.ScoreboardPacketHandler;
import com.rexcantor64.triton.player.TritonLanguagePlayer;
import lombok.val;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

/**
* Main entrypoint for intercepting packets with PacketEvents.
* <p>
* The {@link PacketEventsListener#setupHandlers()} function is NOT
* called on constructor and thus needs to be called separately.
*
* @since 4.0.0
*/
public class PacketEventsListener implements PacketListener {

private Map<PacketTypeCommon, BiConsumer<PacketSendEvent, TritonLanguagePlayer<?>>> receiveHandlers = Collections.emptyMap();

/**
* Setup handlers according to what is enabled on config.
*
* @since 4.0.0
*/
public void setupHandlers() {
val parser = Triton.get().getMessageParser();
val config = Triton.get().getConfig();
val updatedHandlers = new HashMap<PacketTypeCommon, BiConsumer<PacketSendEvent, TritonLanguagePlayer<?>>>();

if (config.isScoreboards()) {
val scoreboardHandler = new ScoreboardPacketHandler(parser, config);
updatedHandlers.put(PacketType.Play.Server.TEAMS, scoreboardHandler::onTeamsPacket);
updatedHandlers.put(PacketType.Play.Server.SCOREBOARD_OBJECTIVE, scoreboardHandler::onObjectivePacket);
}

receiveHandlers = Collections.unmodifiableMap(updatedHandlers);
}

@Override
public void onPacketSend(PacketSendEvent event) {
val type = event.getPacketType();

val handler = receiveHandlers.get(type);
if (handler != null) {
val languagePlayer = Triton.get().getPlayerManager().get(event.getUser().getUUID());
handler.accept(event, languagePlayer);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.rexcantor64.triton.packetinterceptor;

import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.PacketEventsAPI;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.rexcantor64.triton.Triton;
import com.rexcantor64.triton.dependencies.Dependency;
import com.rexcantor64.triton.loader.utils.LoaderFlag;
import lombok.NonNull;
import lombok.val;

/**
* This class exists to avoid {@link NoClassDefFoundError} when not using PacketEvents.
* It acts as a "buffer" so that the PacketEvents classes are not loaded by Java unless
* PacketEvents support is enabled for Triton.
*
* @since 4.0.0
*/
public abstract class PacketEventsManager {

private final @NonNull PacketEventsListener packetEventsListener = new PacketEventsListener();

public void onLoad() {
val dependencyManager = Triton.get().getLoader().getDependencyManager();
val isPacketEventsVendored = dependencyManager.hasLoaderFlag(LoaderFlag.VENDOR_PACKET_EVENTS);
if (isPacketEventsVendored) {
// load packet events dependency (api is loaded in the Triton class to allow this class to load successfully)
dependencyManager.loadDependency(Dependency.PACKET_EVENTS_NETTY_COMMON);
dependencyManager.loadDependency(this.getPlatformPacketEventsDependency());

initPacketEventsPlatform();
}
this.packetEventsListener.setupHandlers();
PacketEvents.getAPI().load();
if (isPacketEventsVendored) {
// Don't check for PacketEvents updates if it's vendored (the user can't do anything)
// noinspection UnstableApiUsage
PacketEvents.getAPI().getSettings().checkForUpdates(false);
}
PacketEvents.getAPI().getEventManager().registerListener(this.packetEventsListener, PacketListenerPriority.HIGHEST);
}

public void onEnable() {
PacketEvents.getAPI().init();
}

public void onDisable() {
PacketEvents.getAPI().terminate();
}

public void onReload() {
this.packetEventsListener.setupHandlers();
}

/**
* Call {@link PacketEvents#setAPI(PacketEventsAPI)} with the appropriate platform.
*
* @since 4.0.0
*/
protected abstract void initPacketEventsPlatform();

/**
* @return Get the PacketEvents dependency to download for the current platform
* @since 4.0.0
*/
protected abstract @NonNull Dependency getPlatformPacketEventsDependency();
}
Loading
Loading