diff --git a/build.gradle b/build.gradle index bad25652..723aff41 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ plugins { } // Core versioning -version = "0.5.2b2" +version = "0.5.2b3" allprojects { apply from: "${rootDir}/gradle/tasks.gradle" diff --git a/gradle-plugin/build.gradle b/gradle-plugin/build.gradle index 8bd7ac5e..bd12d50f 100644 --- a/gradle-plugin/build.gradle +++ b/gradle-plugin/build.gradle @@ -2,7 +2,7 @@ repositories { gradlePluginPortal() } -version = "1.0.1b4" +version = "1.0.1b5" apply plugin: "java-gradle-plugin" apply plugin: "maven-publish" diff --git a/gradle-plugin/src/main/java/io/fairyproject/gradle/FairyExtension.java b/gradle-plugin/src/main/java/io/fairyproject/gradle/FairyExtension.java index 3062e775..dd9c808f 100644 --- a/gradle-plugin/src/main/java/io/fairyproject/gradle/FairyExtension.java +++ b/gradle-plugin/src/main/java/io/fairyproject/gradle/FairyExtension.java @@ -55,7 +55,7 @@ public FairyExtension(ObjectFactory objectFactory) { this.fairyPlatforms = objectFactory.listProperty(PlatformType.class).convention(Collections.singleton(PlatformType.BUKKIT)); // Libraries - this.aspectJVersion = objectFactory.property(String.class).convention("1.8.7"); + this.aspectJVersion = objectFactory.property(String.class).convention("1.9.7"); // Plugin this.classifier = objectFactory.property(String.class).convention("all"); diff --git a/gradle-plugin/src/main/java/io/fairyproject/gradle/FairyPlugin.java b/gradle-plugin/src/main/java/io/fairyproject/gradle/FairyPlugin.java index 5ef46dee..f73c5cb6 100644 --- a/gradle-plugin/src/main/java/io/fairyproject/gradle/FairyPlugin.java +++ b/gradle-plugin/src/main/java/io/fairyproject/gradle/FairyPlugin.java @@ -131,9 +131,10 @@ public void apply(@NotNull Project project) { } try { - new ModuleReader(project, extension, fairyModuleConfiguration, copy, new HashSet<>()).load(moduleEntry.getKey(), dependency, new ArrayList<>()); + new ModuleReader(project, extension, fairyModuleConfiguration, copy, new HashSet<>()) + .load(moduleEntry.getKey(), dependency, new ArrayList<>()); } catch (IOException e) { - throw new IllegalArgumentException("An error occurs while reading dependency"); + throw new IllegalArgumentException("An error occurs while reading dependency", e); } } diff --git a/gradle.properties b/gradle.properties index 9b4170ca..d45951b9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,7 +24,7 @@ jackson.version = 2.11.2 caffeine.version = 2.9.0 -aspectj.version = 1.8.7 +aspectj.version = 1.9.7 guava.version = 30.0-jre gson.version = 2.8.6 log4j.version = 2.15.0 @@ -38,4 +38,5 @@ deploy.imanityLibraries = true # Minecraft adventure.version = 4.9.3 -netty.version = 4.1.69.Final \ No newline at end of file +netty.version = 4.1.69.Final +packetevents.version = v2.0.0-beta-1 \ No newline at end of file diff --git a/gradle/builder.gradle b/gradle/builder.gradle index f743215f..f074bcde 100644 --- a/gradle/builder.gradle +++ b/gradle/builder.gradle @@ -37,6 +37,8 @@ project.afterEvaluate(p -> { shadowJar { // XSeries exclude("com/cryptomorin/xseries/messages/*") + + relocate("com.github.retrooper.packetevents", "io.fairyproject.protocol.packetevents") relocate("com.cryptomorin.xseries", "io.fairyproject.bukkit.xseries") relocate "net.kyori", relocate + "kyori" diff --git a/gradle/tasks.gradle b/gradle/tasks.gradle index a5e0f24e..f4f039d8 100644 --- a/gradle/tasks.gradle +++ b/gradle/tasks.gradle @@ -1,6 +1,7 @@ import com.google.common.io.Files import io.fairyproject.gradle.ExtensionUtil import io.fairyproject.gradle.FairyVersion +import org.gradle.internal.jvm.Jvm import org.yaml.snakeyaml.Yaml abstract class VersionModificationTask extends DefaultTask { @@ -95,6 +96,12 @@ abstract class RunDebugBukkit extends DefaultTask { "#Tue Jun 22 20:59:57 ICT 2021\n" + "eula=true\n") + if (Jvm.current().javaVersion.ordinal() > 8) + project.tasks.execBukkit.jvmArgs = [ + "--add-opens", "java.base/java.net=ALL-UNNAMED", + "--add-opens", "java.base/java.lang=ALL-UNNAMED", + "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED" + ] project.tasks.execBukkit.mainClass.set("-jar") project.tasks.execBukkit.args = [ file.toPath().toString() @@ -140,6 +147,7 @@ abstract class RunDebugApp extends DefaultTask { project.tasks.execApp.args = [ file.toPath().toString() ] + project.tasks.execApp.standardInput = System.in project.tasks.execApp.workingDir("debug/app") } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a0f7639f..b1159fc5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/io.fairyproject.modules/module.command/bukkit-command/src/main/java/io/fairyproject/bukkit/command/parameters/GameModeArgTransformer.java b/io.fairyproject.modules/module.command/bukkit-command/src/main/java/io/fairyproject/bukkit/command/parameters/GameModeArgTransformer.java index 29880b93..b8a06bcc 100644 --- a/io.fairyproject.modules/module.command/bukkit-command/src/main/java/io/fairyproject/bukkit/command/parameters/GameModeArgTransformer.java +++ b/io.fairyproject.modules/module.command/bukkit-command/src/main/java/io/fairyproject/bukkit/command/parameters/GameModeArgTransformer.java @@ -52,7 +52,7 @@ public class GameModeArgTransformer extends BukkitArgTransformer { MAP.put("adventure", GameMode.ADVENTURE); MAP.put("2", GameMode.ADVENTURE); - if (MCProtocol.INSTANCE.getProtocolMapping().getVersion().isOrAbove(MCVersion.V1_8)) { + if (MCProtocol.INSTANCE.version().isOrAbove(MCVersion.V1_8)) { MAP.put("spectator", GameMode.SPECTATOR); MAP.put("3", GameMode.SPECTATOR); } diff --git a/io.fairyproject.modules/module.locale/mc-locale/build.gradle b/io.fairyproject.modules/module.locale/mc-locale/build.gradle index 3a397be7..c1e8c5f6 100644 --- a/io.fairyproject.modules/module.locale/mc-locale/build.gradle +++ b/io.fairyproject.modules/module.locale/mc-locale/build.gradle @@ -4,6 +4,7 @@ module { abstraction = true platform("mc") + depend("module.config") depend("module.storage:core-storage") } \ No newline at end of file diff --git a/io.fairyproject.modules/module.locale/mc-locale/src/main/java/io/fairyproject/locale/Locales.java b/io.fairyproject.modules/module.locale/mc-locale/src/main/java/io/fairyproject/locale/Locales.java index 62b92609..effc08e0 100644 --- a/io.fairyproject.modules/module.locale/mc-locale/src/main/java/io/fairyproject/locale/Locales.java +++ b/io.fairyproject.modules/module.locale/mc-locale/src/main/java/io/fairyproject/locale/Locales.java @@ -28,7 +28,6 @@ import io.fairyproject.container.ContainerHolder; import lombok.experimental.UtilityClass; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.Template; import java.util.Locale; import java.util.UUID; @@ -70,8 +69,4 @@ public Component translate(String key) { return Component.translatable(key); } - public Template template(String placeholder, String localeKey) { - return Template.template(placeholder, Component.translatable(localeKey)); - } - } diff --git a/io.fairyproject.modules/platform.mc/module.bossbar/bukkit-bossbar/build.gradle b/io.fairyproject.modules/platform.mc/module.bossbar/bukkit-bossbar/build.gradle index d2c990ea..27d18441 100644 --- a/io.fairyproject.modules/platform.mc/module.bossbar/bukkit-bossbar/build.gradle +++ b/io.fairyproject.modules/platform.mc/module.bossbar/bukkit-bossbar/build.gradle @@ -1,4 +1,4 @@ -version = "0.0.1b1" +version = "0.0.1b2" dependencies { compileOnly project.spigot() diff --git a/io.fairyproject.modules/platform.mc/module.nametag/build.gradle b/io.fairyproject.modules/platform.mc/module.nametag/build.gradle index 5f64977e..2dcc5391 100644 --- a/io.fairyproject.modules/platform.mc/module.nametag/build.gradle +++ b/io.fairyproject.modules/platform.mc/module.nametag/build.gradle @@ -1,4 +1,4 @@ -version = "0.0.1b1" +version = "0.0.1b2" module { platform("mc") diff --git a/io.fairyproject.modules/platform.mc/module.nametag/src/main/java/io/fairyproject/mc/nametag/NameTagService.java b/io.fairyproject.modules/platform.mc/module.nametag/src/main/java/io/fairyproject/mc/nametag/NameTagService.java index c8d4abb4..0918a2bb 100644 --- a/io.fairyproject.modules/platform.mc/module.nametag/src/main/java/io/fairyproject/mc/nametag/NameTagService.java +++ b/io.fairyproject.modules/platform.mc/module.nametag/src/main/java/io/fairyproject/mc/nametag/NameTagService.java @@ -85,8 +85,9 @@ public void onPlayerQuit(MCPlayerQuitEvent event) { if (nameTag != null) { nameTag.removeName(name); list.removeNameTag(name); + other.sendPacket(PacketPlay.Out.ScoreboardTeam.builder() - .player(nameTag.getName()) + .players(nameTag.getName()) .players(Collections.singleton(name)) .teamAction(TeamAction.LEAVE) .build()); @@ -154,7 +155,7 @@ private void updateForInternal(MCPlayer player, MCPlayer target) { list.addNameTag(target.getName(), nametag); player.sendPacket(PacketPlay.Out.ScoreboardTeam.builder() - .player(nametag.getName()) + .players(nametag.getName()) .players(Collections.singleton(target.getName())) .teamAction(TeamAction.JOIN) .build()); @@ -185,7 +186,7 @@ protected NameTag getOrCreate(Component prefix, Component suffix) { private void sendPacket(MCPlayer mcPlayer, NameTag info) { mcPlayer.sendPacket(PacketPlay.Out.ScoreboardTeam.builder() - .player(info.getName()) + .players(info.getName()) .teamAction(TeamAction.ADD) .parameters(Optional.of(PacketPlay.Out.ScoreboardTeam.Parameters.builder() .playerPrefix(info.getPrefix()) diff --git a/io.fairyproject.modules/platform.mc/module.sidebar/build.gradle b/io.fairyproject.modules/platform.mc/module.sidebar/build.gradle index e2e02548..b043ecd5 100644 --- a/io.fairyproject.modules/platform.mc/module.sidebar/build.gradle +++ b/io.fairyproject.modules/platform.mc/module.sidebar/build.gradle @@ -1,4 +1,4 @@ -version = "0.0.1b3" +version = "0.0.1b4" module { platform("mc") diff --git a/io.fairyproject.modules/platform.mc/module.sidebar/src/main/java/io/fairyproject/sidebar/Sidebar.java b/io.fairyproject.modules/platform.mc/module.sidebar/src/main/java/io/fairyproject/sidebar/Sidebar.java index 474c9d36..e4157a2d 100644 --- a/io.fairyproject.modules/platform.mc/module.sidebar/src/main/java/io/fairyproject/sidebar/Sidebar.java +++ b/io.fairyproject.modules/platform.mc/module.sidebar/src/main/java/io/fairyproject/sidebar/Sidebar.java @@ -60,6 +60,7 @@ public Sidebar(MCPlayer player) { .displaySlot(ObjectiveDisplaySlot.SIDEBAR) .objectiveName(player.getName()) .build()); + } public void setTitle(Component title) { @@ -163,7 +164,7 @@ public void remove() { } private PacketPlay.Out.ScoreboardTeam getOrRegisterTeam(int line) { - final PacketPlay.Out.ScoreboardTeam.ScoreboardTeamBuilder builder = PacketPlay.Out.ScoreboardTeam.builder(); + final PacketPlay.Out.ScoreboardTeam.Factory builder = PacketPlay.Out.ScoreboardTeam.builder(); builder.name("-sb" + line); builder.teamAction(TeamAction.ADD); @@ -182,7 +183,7 @@ private PacketPlay.Out.ScoreboardTeam getOrRegisterTeam(int line) { .build(); builder.teamAction(TeamAction.ADD); - builder.player(getEntry(line)); + builder.players(getEntry(line)); this.player.sendPacket(score); return builder.build(); diff --git a/io.fairyproject.modules/platform.mc/module.tablist/build.gradle b/io.fairyproject.modules/platform.mc/module.tablist/build.gradle index af1cd80c..53691d8d 100644 --- a/io.fairyproject.modules/platform.mc/module.tablist/build.gradle +++ b/io.fairyproject.modules/platform.mc/module.tablist/build.gradle @@ -1,4 +1,4 @@ -version = "0.0.2b2" +version = "0.0.2b3" module { platform("mc") diff --git a/io.fairyproject.modules/platform.mc/module.tablist/src/main/java/io/fairyproject/mc/tablist/Tablist.java b/io.fairyproject.modules/platform.mc/module.tablist/src/main/java/io/fairyproject/mc/tablist/Tablist.java index 5ea45646..bdd2fbc8 100644 --- a/io.fairyproject.modules/platform.mc/module.tablist/src/main/java/io/fairyproject/mc/tablist/Tablist.java +++ b/io.fairyproject.modules/platform.mc/module.tablist/src/main/java/io/fairyproject/mc/tablist/Tablist.java @@ -75,7 +75,7 @@ private void setup() { .playerPrefix(Component.empty()) .playerSuffix(Component.empty()) .build())) - .player(LegacyClientUtil.entry(i - 1)) + .players(LegacyClientUtil.entry(i - 1)) .build(); player.sendPacket(packet); diff --git a/io.fairyproject.modules/platform.mc/module.tablist/src/main/java/io/fairyproject/mc/tablist/util/impl/MainTablistImpl.java b/io.fairyproject.modules/platform.mc/module.tablist/src/main/java/io/fairyproject/mc/tablist/util/impl/MainTablistImpl.java index 22c898b9..ae3eff31 100644 --- a/io.fairyproject.modules/platform.mc/module.tablist/src/main/java/io/fairyproject/mc/tablist/util/impl/MainTablistImpl.java +++ b/io.fairyproject.modules/platform.mc/module.tablist/src/main/java/io/fairyproject/mc/tablist/util/impl/MainTablistImpl.java @@ -48,7 +48,7 @@ public class MainTablistImpl implements TablistImpl { public void removeSelf(MCPlayer player) { final PacketPlay.Out.PlayerInfo playerInfo = PacketPlay.Out.PlayerInfo.builder() .action(io.fairyproject.mc.protocol.item.PlayerInfoAction.REMOVE_PLAYER) - .entry(MCPlayer.from(player).asInfoData()) + .entries(MCPlayer.from(player).asInfoData()) .build(); MCPlayer.all().forEach(mcPlayer -> mcPlayer.sendPacket(playerInfo)); @@ -72,7 +72,7 @@ public TabEntry createFakePlayer(Tablist tablist, String string, TabColumn colum final PacketPlay.Out.PlayerInfo packet = PacketPlay.Out.PlayerInfo.builder() .action(io.fairyproject.mc.protocol.item.PlayerInfoAction.ADD_PLAYER) - .entry(new PlayerInfoData(1, profile, io.fairyproject.mc.GameMode.SURVIVAL, Component.empty())) + .entries(new PlayerInfoData(1, profile, io.fairyproject.mc.GameMode.SURVIVAL, Component.empty())) .build(); player.sendPacket(packet); return new TabEntry(string, profile.getUuid(), Component.empty(), tablist, Skin.GRAY, column, slot, rawSlot, 0); @@ -96,7 +96,7 @@ public void updateFakeName(Tablist tablist, TabEntry tabEntry, Component text) { .playerPrefix(MCAdventure.LEGACY.deserialize(newStrings[0])) .playerPrefix(MCAdventure.LEGACY.deserialize(newStrings.length > 1 ? CC.translate(newStrings[1]) : "")) .build())) - .player(LegacyClientUtil.entry(tabEntry.getRawSlot() - 1)) + .players(LegacyClientUtil.entry(tabEntry.getRawSlot() - 1)) .teamAction(TeamAction.CHANGE) .build(); @@ -104,7 +104,7 @@ public void updateFakeName(Tablist tablist, TabEntry tabEntry, Component text) { } else { final PacketPlay.Out.PlayerInfo packet = PacketPlay.Out.PlayerInfo.builder() .action(PlayerInfoAction.UPDATE_DISPLAY_NAME) - .entry(new PlayerInfoData(tabEntry.getLatency(), this.getGameProfile(version, tabEntry), GameMode.SURVIVAL, text)) + .entries(new PlayerInfoData(tabEntry.getLatency(), this.getGameProfile(version, tabEntry), GameMode.SURVIVAL, text)) .build(); player.sendPacket(packet); @@ -120,7 +120,7 @@ public void updateFakeLatency(Tablist tablist, TabEntry tabEntry, int latency) { final MCVersion version = tablist.getPlayer().getVersion(); final PacketPlay.Out.PlayerInfo packet = PacketPlay.Out.PlayerInfo.builder() .action(PlayerInfoAction.UPDATE_LATENCY) - .entry(new PlayerInfoData(tabEntry.getLatency(), this.getGameProfile(version, tabEntry), GameMode.SURVIVAL, tabEntry.getText())) + .entries(new PlayerInfoData(tabEntry.getLatency(), this.getGameProfile(version, tabEntry), GameMode.SURVIVAL, tabEntry.getText())) .build(); tablist.getPlayer().sendPacket(packet); @@ -147,11 +147,11 @@ public void updateFakeSkin(Tablist tablist, TabEntry tabEntry, Skin skin) { final PlayerInfoData playerInfoData = new PlayerInfoData(tabEntry.getLatency(), gameProfile, GameMode.SURVIVAL, tabEntry.getText()); final PacketPlay.Out.PlayerInfo remove = PacketPlay.Out.PlayerInfo.builder() .action(PlayerInfoAction.REMOVE_PLAYER) - .entry(playerInfoData) + .entries(playerInfoData) .build(); final PacketPlay.Out.PlayerInfo add = PacketPlay.Out.PlayerInfo.builder() .action(PlayerInfoAction.ADD_PLAYER) - .entry(playerInfoData) + .entries(playerInfoData) .build(); tablist.getPlayer().sendPacket(remove); diff --git a/io.fairyproject.platforms/bukkit-platform/build.gradle b/io.fairyproject.platforms/bukkit-platform/build.gradle index 5034a430..4e789dd1 100644 --- a/io.fairyproject.platforms/bukkit-platform/build.gradle +++ b/io.fairyproject.platforms/bukkit-platform/build.gradle @@ -26,6 +26,7 @@ import org.apache.tools.ant.filters.ReplaceTokens dependencies { api project(":io.fairyproject.platforms:mc-platform") + implementation 'com.github.terminalsin.packetevents:spigot:' + findProperty("packetevents.version") implementation "net.kyori:adventure-platform-bukkit:4.0.1" compileOnly "com.destroystokyo.paper:paper-api:" + findProperty("bukkit.version") diff --git a/io.fairyproject.platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/FairyBukkitPlatform.java b/io.fairyproject.platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/FairyBukkitPlatform.java index 96b218de..f9bad474 100644 --- a/io.fairyproject.platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/FairyBukkitPlatform.java +++ b/io.fairyproject.platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/FairyBukkitPlatform.java @@ -24,6 +24,7 @@ package io.fairyproject.bukkit; +import com.github.retrooper.packetevents.PacketEvents; import io.fairyproject.ExtendedClassLoader; import io.fairyproject.FairyPlatform; import io.fairyproject.bukkit.events.PostServicesInitialEvent; @@ -42,6 +43,7 @@ import io.fairyproject.task.ITaskScheduler; import io.fairyproject.util.terminable.TerminableConsumer; import io.fairyproject.util.terminable.composite.CompositeTerminable; +import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -86,6 +88,8 @@ public void load() { PluginManager.initialize(new BukkitPluginHandler()); ModuleService.init(); MinecraftReflection.init(); + PacketEvents.setAPI(SpigotPacketEventsBuilder.build(PLUGIN)); + PacketEvents.getAPI().load(); this.createMCInitializer().apply(); } @@ -98,10 +102,14 @@ public void enable() { super.enable(); ModuleService.INSTANCE.enable(); + PacketEvents.getAPI().getSettings().debug(false).bStats(false).checkForUpdates(true); + PacketEvents.getAPI().init(); } @Override public void disable() { + PacketEvents.getAPI().terminate(); + super.disable(); } diff --git a/io.fairyproject.platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCInitializer.java b/io.fairyproject.platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCInitializer.java index 507d5904..cd5bf4a3 100644 --- a/io.fairyproject.platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCInitializer.java +++ b/io.fairyproject.platforms/bukkit-platform/src/main/java/io/fairyproject/bukkit/mc/BukkitMCInitializer.java @@ -1,11 +1,12 @@ package io.fairyproject.bukkit.mc; +import com.github.retrooper.packetevents.PacketEventsAPI; +import io.fairyproject.bukkit.FairyBukkitPlatform; import io.fairyproject.bukkit.protocol.BukkitNettyInjector; import io.fairyproject.bukkit.util.Players; import io.fairyproject.mc.*; -import io.fairyproject.mc.protocol.mapping.MCProtocolMapping; -import io.fairyproject.mc.protocol.mapping.MCProtocolMapping1_8; import io.fairyproject.mc.protocol.netty.NettyInjector; +import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -21,8 +22,8 @@ public NettyInjector createNettyInjector() { } @Override - public MCProtocolMapping createProtocolMapping() { - return new MCProtocolMapping1_8(); // TODO + public PacketEventsAPI createPacketEvents() { + return SpigotPacketEventsBuilder.build(FairyBukkitPlatform.PLUGIN); } @Override diff --git a/io.fairyproject.platforms/core-platform/src/main/java/io/fairyproject/library/LibraryHandler.java b/io.fairyproject.platforms/core-platform/src/main/java/io/fairyproject/library/LibraryHandler.java index cf9710a7..93b50a22 100644 --- a/io.fairyproject.platforms/core-platform/src/main/java/io/fairyproject/library/LibraryHandler.java +++ b/io.fairyproject.platforms/core-platform/src/main/java/io/fairyproject/library/LibraryHandler.java @@ -31,10 +31,10 @@ import io.fairyproject.plugin.PluginListenerAdapter; import io.fairyproject.plugin.PluginManager; import io.fairyproject.util.FairyThreadFactory; +import io.fairyproject.util.FileUtil; import io.fairyproject.util.Stacktrace; import io.fairyproject.util.URLClassLoaderAccess; import lombok.Getter; -import org.apache.commons.io.FilenameUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.maven.repository.internal.MavenRepositorySystemUtils; @@ -236,8 +236,8 @@ private List remapLibrary(Library library, List normalFile) { List retVal = new ArrayList<>(); for (Path path : normalFile) { final String name = path.getFileName().toString(); - final String fileName = FilenameUtils.getName(name); - final String extension = FilenameUtils.getExtension(name); + final String fileName = FileUtil.getName(name); + final String extension = FileUtil.getExtension(name); Path remappedFile = this.libFolder.resolve(fileName + "-remapped." + extension); if (Files.exists(remappedFile)) { diff --git a/io.fairyproject.platforms/core-platform/src/main/java/io/fairyproject/util/FileUtil.java b/io.fairyproject.platforms/core-platform/src/main/java/io/fairyproject/util/FileUtil.java index bb07f852..111d415f 100644 --- a/io.fairyproject.platforms/core-platform/src/main/java/io/fairyproject/util/FileUtil.java +++ b/io.fairyproject.platforms/core-platform/src/main/java/io/fairyproject/util/FileUtil.java @@ -37,7 +37,19 @@ @UtilityClass public class FileUtil { + private final char UNIX_SEPARATOR = '/'; + private final char WINDOWS_SEPARATOR = '\\'; + private final char SYSTEM_SEPARATOR = File.separatorChar; + private final char OTHER_SEPARATOR; + private final char EXTENSION_SEPARATOR = '.'; + static { + if (isSystemWindows()) { + OTHER_SEPARATOR = UNIX_SEPARATOR; + } else { + OTHER_SEPARATOR = WINDOWS_SEPARATOR; + } + } public File getSelfJar() throws URISyntaxException { return new File(FileUtil.class.getProtectionDomain().getCodeSource().getLocation() .toURI()); @@ -136,4 +148,68 @@ public void createNewFileAndPath(File file) { } } + public String getName(final String fileName) { + if (fileName == null) { + return null; + } + final int index = indexOfLastSeparator(fileName); + return fileName.substring(index + 1); + } + + public int indexOfLastSeparator(final String fileName) { + if (fileName == null) { + return -1; + } + final int lastUnixPos = fileName.lastIndexOf(UNIX_SEPARATOR); + final int lastWindowsPos = fileName.lastIndexOf(WINDOWS_SEPARATOR); + return Math.max(lastUnixPos, lastWindowsPos); + } + + public String getExtension(final String fileName) throws IllegalArgumentException { + if (fileName == null) { + return null; + } + final int index = indexOfExtension(fileName); + if (index == -1) { + return ""; + } + return fileName.substring(index + 1); + } + + public int indexOfExtension(final String fileName) throws IllegalArgumentException { + if (fileName == null) { + return -1; + } + if (isSystemWindows()) { + // Special handling for NTFS ADS: Don't accept colon in the fileName. + final int offset = fileName.indexOf(':', getAdsCriticalOffset(fileName)); + if (offset != -1) { + throw new IllegalArgumentException("NTFS ADS separator (':') in file name is forbidden."); + } + } + final int extensionPos = fileName.lastIndexOf(EXTENSION_SEPARATOR); + final int lastSeparator = indexOfLastSeparator(fileName); + return lastSeparator > extensionPos ? -1 : extensionPos; + } + + private int getAdsCriticalOffset(final String fileName) { + // Step 1: Remove leading path segments. + final int offset1 = fileName.lastIndexOf(SYSTEM_SEPARATOR); + final int offset2 = fileName.lastIndexOf(OTHER_SEPARATOR); + if (offset1 == -1) { + if (offset2 == -1) { + return 0; + } + return offset2 + 1; + } + if (offset2 == -1) { + return offset1 + 1; + } + return Math.max(offset1, offset2) + 1; + } + + boolean isSystemWindows() { + return SYSTEM_SEPARATOR == WINDOWS_SEPARATOR; + } + } diff --git a/io.fairyproject.platforms/mc-platform/build.gradle b/io.fairyproject.platforms/mc-platform/build.gradle index 601ac951..5d4e9b1c 100644 --- a/io.fairyproject.platforms/mc-platform/build.gradle +++ b/io.fairyproject.platforms/mc-platform/build.gradle @@ -1,6 +1,9 @@ dependencies { compileOnly "io.netty:netty-all:" + findProperty("netty.version") + // PacketEvents, for packets + api 'com.github.terminalsin.packetevents:api:' + findProperty("packetevents.version") + // Adventure, for user-interface api "net.kyori:adventure-api:" + findProperty("adventure.version") api "net.kyori:adventure-text-minimessage:4.2.0-SNAPSHOT" diff --git a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCAdventure.java b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCAdventure.java index 25e91f96..794a4586 100644 --- a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCAdventure.java +++ b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCAdventure.java @@ -18,12 +18,12 @@ public class MCAdventure { public void initialize() { final GsonComponentSerializer.Builder builder = GsonComponentSerializer.builder(); - if (!MCProtocol.INSTANCE.getProtocolMapping().getVersion().isHexColorSupport()) { + if (!MCProtocol.INSTANCE.version().isHexColorSupport()) { builder.downsampleColors(); } final LegacyComponentSerializer.Builder legacyBuilder = LegacyComponentSerializer.builder(); - if (MCProtocol.INSTANCE.getProtocolMapping().getVersion().isHexColorSupport()) { + if (MCProtocol.INSTANCE.version().isHexColorSupport()) { legacyBuilder.hexColors(); } @@ -44,7 +44,7 @@ public String asLegacyString(Component component, Locale locale) { } public String asItemString(Component component, Locale locale) { - if (MCProtocol.INSTANCE.getProtocolMapping().getVersion().isOrAbove(MCVersion.V1_13)) { + if (MCProtocol.INSTANCE.version().isOrAbove(MCVersion.V1_13)) { return asJsonString(component, locale); } else { return asLegacyString(component, locale); diff --git a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCInitializer.java b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCInitializer.java index da08e59b..c4f2182b 100644 --- a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCInitializer.java +++ b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCInitializer.java @@ -1,13 +1,13 @@ package io.fairyproject.mc; +import com.github.retrooper.packetevents.PacketEventsAPI; import io.fairyproject.mc.protocol.MCProtocol; -import io.fairyproject.mc.protocol.mapping.MCProtocolMapping; import io.fairyproject.mc.protocol.netty.NettyInjector; public interface MCInitializer { default void apply() { - MCProtocol.initialize(this.createNettyInjector(), this.createProtocolMapping()); + MCProtocol.initialize(this.createNettyInjector(), this.createPacketEvents()); MCServer.Companion.CURRENT = this.createMCServer(); MCEntity.Companion.BRIDGE = this.createEntityBridge(); MCWorld.Companion.BRIDGE = this.createWorldBridge(); @@ -16,7 +16,7 @@ default void apply() { } NettyInjector createNettyInjector(); - MCProtocolMapping createProtocolMapping(); + PacketEventsAPI createPacketEvents(); MCServer createMCServer(); MCEntity.Bridge createEntityBridge(); MCWorld.Bridge createWorldBridge(); diff --git a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCPlayer.java b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCPlayer.java index ce44139f..fac29d7c 100644 --- a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCPlayer.java +++ b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/MCPlayer.java @@ -1,5 +1,7 @@ package io.fairyproject.mc; +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; import io.fairyproject.mc.protocol.MCPacket; import io.fairyproject.mc.protocol.MCProtocol; import io.fairyproject.mc.protocol.MCVersion; @@ -218,19 +220,8 @@ default void sendMessage(char colorCode, Iterable messages) { * * @param packet the packet */ - default void sendPacket(MCPacket packet) { - final int id = MCProtocol.INSTANCE.getProtocolMapping() - .getProtocol(getProtocolId()) - .fromPacketClass(packet.getClass()); - - final ByteBuf buffer = this.getChannel().alloc().buffer(); - final FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buffer); - friendlyByteBuf.setLocale(Locale.forLanguageTag(this.getGameLocale())); - - friendlyByteBuf.writeVarInt(id); - packet.write(friendlyByteBuf); - - sendRawPacket(friendlyByteBuf); + default void sendPacket(PacketWrapper packet) { + PacketEvents.getAPI().getProtocolManager().sendPacket(this.getChannel(), packet); } /** diff --git a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/MCProtocol.java b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/MCProtocol.java index 15e8e862..b7ade801 100644 --- a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/MCProtocol.java +++ b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/MCProtocol.java @@ -1,32 +1,35 @@ package io.fairyproject.mc.protocol; +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.PacketEventsAPI; import io.fairyproject.mc.MCAdventure; import lombok.Getter; -import io.fairyproject.mc.protocol.mapping.MCProtocolMapping; import io.fairyproject.mc.protocol.netty.NettyInjector; @Getter public class MCProtocol { - public static MCProtocol INSTANCE; - public static void initialize(NettyInjector injector, MCProtocolMapping protocolMapping) { - new MCProtocol(injector, protocolMapping); + + private final NettyInjector injector; + private final PacketEventsAPI packetEvents; + + public static void initialize(NettyInjector injector, PacketEventsAPI packetEvents) { + new MCProtocol(injector, packetEvents); MCAdventure.initialize(); } - private final NettyInjector injector; - private final MCProtocolMapping protocolMapping; - - private MCProtocol(NettyInjector injector, MCProtocolMapping protocolMapping) { + private MCProtocol(NettyInjector injector, PacketEventsAPI packetEvents) { INSTANCE = this; this.injector = injector; - this.protocolMapping = protocolMapping; + this.packetEvents = packetEvents; } public MCVersion version() { - return this.protocolMapping.getVersion(); + return MCVersion.getVersionFromRaw( + PacketEvents.getAPI().getServerManager().getVersion().getProtocolVersion() + ); } } diff --git a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/mapping/MCProtocolMapping.java b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/mapping/MCProtocolMapping.java deleted file mode 100644 index 5dfdf84d..00000000 --- a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/mapping/MCProtocolMapping.java +++ /dev/null @@ -1,107 +0,0 @@ -package io.fairyproject.mc.protocol.mapping; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import io.fairyproject.mc.protocol.MCPacket; -import io.fairyproject.mc.protocol.netty.FriendlyByteBuf; -import io.fairyproject.mc.protocol.packet.PacketDeserializer; -import io.fairyproject.mc.protocol.packet.PacketDirection; -import io.fairyproject.mc.protocol.MCVersion; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; - -import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; - -public abstract class MCProtocolMapping { - - protected final Map protocols = new HashMap<>(); - - public Protocol getProtocol(int id) { - return this.protocols.get(id); - } - - public void registerProtocol(int id, Protocol protocol) { - this.protocols.put(id, protocol); - } - - public abstract MCVersion getVersion(); - - public interface Protocol { - - Class fromId(int id, PacketDirection direction); - - int fromPacketClass(Class packetClass); - - } - - public static abstract class AbstractProtocol implements Protocol { - - private final EnumMap> deserializers; - private final EnumMap, Integer>> packets; - - public AbstractProtocol() { - this.deserializers = new EnumMap<>(PacketDirection.class); - this.packets = new EnumMap<>(PacketDirection.class); - this.init(); - } - - private Int2ObjectMap getDeserializers(PacketDirection direction) { - return this.deserializers.computeIfAbsent(direction, ignored -> new Int2ObjectOpenHashMap<>()); - } - - private BiMap, Integer> getPackets(PacketDirection direction) { - return this.packets.computeIfAbsent(direction, ignored -> HashBiMap.create()); - } - - public abstract void init(); - - public MCPacket deserialize(PacketDirection direction, FriendlyByteBuf byteBuf, int id) { - final PacketDeserializer packetDeserializer = this.getDeserializers(direction).getOrDefault(id, PacketDeserializer.DEFAULT); - final Class packetClass = this.fromId(id, direction); - - return packetDeserializer.deserialize(this, byteBuf, id, packetClass); - } - - public void registerInDeserializer(int id, PacketDeserializer deserializer) { - this.getDeserializers(PacketDirection.IN).put(id, deserializer); - } - - public void registerOutDeserializer(int id, PacketDeserializer deserializer) { - this.getDeserializers(PacketDirection.OUT).put(id, deserializer); - } - - public void registerIn(int id, Class packetClass) { - this.getPackets(PacketDirection.IN).put(packetClass, id); - } - - public void registerOut(int id, Class packetClass) { - this.getPackets(PacketDirection.OUT).put(packetClass, id); - } - - @Override - public Class fromId(int id, PacketDirection direction) { - final Class in = this.getPackets(PacketDirection.IN).inverse().getOrDefault(id, null); - if (in != null) - return in; - final Class out = this.getPackets(PacketDirection.OUT).inverse().getOrDefault(id, null); - if (out != null) - return out; - throw new IllegalArgumentException(id + " " + direction.name()); - } - - @Override - public int fromPacketClass(Class packetClass) { - final Integer in = this.getPackets(PacketDirection.IN).getOrDefault(packetClass, null); - if (in != null) - return in; - final Integer out = this.getPackets(PacketDirection.OUT).getOrDefault(packetClass, null); - if (out != null) - return out; - throw new IllegalArgumentException(packetClass.getName()); - } - - } - -} diff --git a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/mapping/MCProtocolMapping1_8.java b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/mapping/MCProtocolMapping1_8.java deleted file mode 100644 index d689787c..00000000 --- a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/mapping/MCProtocolMapping1_8.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.fairyproject.mc.protocol.mapping; - -import io.fairyproject.mc.protocol.MCPacket; -import io.fairyproject.mc.protocol.packet.PacketDeserializer; -import io.fairyproject.mc.protocol.packet.PacketPlay; -import io.fairyproject.mc.protocol.MCVersion; - -public class MCProtocolMapping1_8 extends MCProtocolMapping { - - public MCProtocolMapping1_8() { - // Handshake - this.registerProtocol(-1, new AbstractProtocol() { - @Override - public void init() { - - } - }); - - // Play - this.registerProtocol(0, new AbstractProtocol() { - @Override - public void init() { - // Titles - this.registerOut(56, PacketPlay.Out.PlayerInfo.class); - this.registerOut(59, PacketPlay.Out.ScoreboardObjective.class); - this.registerOut(60, PacketPlay.Out.ScoreboardScore.class); - this.registerOut(61, PacketPlay.Out.ScoreboardDisplayObjective.class); - this.registerOut(62, PacketPlay.Out.ScoreboardTeam.class); - this.registerOut(69, PacketPlay.Out.Title.class); - this.registerOutDeserializer(69, (protocol, byteBuf, packetId, defaultType) -> { - final int titleAction = byteBuf.readVarInt(); - - Class packetClass; - switch (titleAction) { - case 0: - packetClass = PacketPlay.Out.Title.class; - break; - case 1: - packetClass = PacketPlay.Out.SubTitle.class; - break; - case 2: - packetClass = PacketPlay.Out.TitleTimes.class; - break; - case 3: - case 4: - packetClass = PacketPlay.Out.TitleClear.class; - break; - default: - throw new IllegalStateException("unrecognized title action."); - } - - final MCPacket packet = PacketDeserializer.DEFAULT.deserialize(protocol, byteBuf, packetId, packetClass); - if (packet instanceof PacketPlay.Out.TitleClear) { - ((PacketPlay.Out.TitleClear) packet).setResetTimes(titleAction == 4); - } - - return packet; - }); - this.registerOut(71, PacketPlay.Out.Tablist.class); - } - }); - - // Status - this.registerProtocol(1, new AbstractProtocol() { - @Override - public void init() { - - } - }); - - // Login - this.registerProtocol(2, new AbstractProtocol() { - @Override - public void init() { - - } - }); - } - - @Override - public MCVersion getVersion() { - return MCVersion.V1_8; - } -} diff --git a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/packet/PacketDeserializer.java b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/packet/PacketDeserializer.java deleted file mode 100644 index 874490d7..00000000 --- a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/packet/PacketDeserializer.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.fairyproject.mc.protocol.packet; - -import io.fairyproject.mc.protocol.MCPacket; -import io.fairyproject.mc.protocol.mapping.MCProtocolMapping; -import io.fairyproject.mc.protocol.netty.FriendlyByteBuf; - -public interface PacketDeserializer { - - PacketDeserializer DEFAULT = (protocol, byteBuf, packetId, defaultType) -> { - try { - return defaultType.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - throw new IllegalStateException(e); - } - }; - - MCPacket deserialize(MCProtocolMapping.Protocol protocol, FriendlyByteBuf byteBuf, int packetId, Class defaultType); - -} diff --git a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/packet/PacketPlay.java b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/packet/PacketPlay.java index 91915afd..5af408bc 100644 --- a/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/packet/PacketPlay.java +++ b/io.fairyproject.platforms/mc-platform/src/main/java/io/fairyproject/mc/protocol/packet/PacketPlay.java @@ -1,329 +1,364 @@ package io.fairyproject.mc.protocol.packet; -import io.fairyproject.mc.protocol.MCPacket; -import io.fairyproject.mc.protocol.MCProtocol; -import io.fairyproject.mc.protocol.MCVersion; +import com.github.retrooper.packetevents.event.PacketSendEvent; +import com.github.retrooper.packetevents.protocol.player.GameMode; +import com.github.retrooper.packetevents.protocol.player.TextureProperty; +import com.github.retrooper.packetevents.protocol.player.UserProfile; +import com.github.retrooper.packetevents.wrapper.play.server.*; +import io.fairyproject.mc.MCAdventure; import io.fairyproject.mc.protocol.item.*; -import io.fairyproject.mc.protocol.netty.FriendlyByteBuf; import lombok.*; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.jetbrains.annotations.NotNull; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.util.*; +import java.util.stream.Collectors; +@Deprecated public class PacketPlay { - + @Deprecated public static class Out { + @Getter @Setter @Deprecated + public static class ScoreboardScore extends WrapperPlayServerUpdateScore { - @Getter @Setter @Builder - public static class ScoreboardScore implements MCPacket { - - private String owner; - private String objectiveName; - private int score; - private ScoreAction action; - - @Override - public void read(FriendlyByteBuf byteBuf) { - this.owner = byteBuf.readUtf(); - this.action = byteBuf.readEnum(ScoreAction.class); - String string = byteBuf.readUtf(); - this.objectiveName = Objects.equals(string, "") ? null : string; - if (this.action != ScoreAction.REMOVE) { - this.score = byteBuf.readVarInt(); - } else { - this.score = 0; - } + public ScoreboardScore(String entityName, Action action, String objectiveName, Optional value) { + super(entityName, action, objectiveName, value); + } + + public static Factory builder() { + return new Factory(); } - @Override - public void write(FriendlyByteBuf byteBuf) { - if (action != ScoreAction.REMOVE && this.objectiveName == null) { - throw new IllegalArgumentException("Need an objective name."); + public static class Factory { + private String owner; + private String objectiveName; + private Integer score; + private ScoreAction action; + + public Factory owner(String owner) { + this.owner = owner; + return this; } - byteBuf.writeUtf(this.owner); - byteBuf.writeEnum(this.action); - byteBuf.writeUtf(this.objectiveName == null ? "" : this.objectiveName); - if (this.action != ScoreAction.REMOVE) { - byteBuf.writeVarInt(this.score); + + public Factory objectiveName(String objectiveName) { + this.objectiveName = objectiveName; + return this; } - } - } - @Getter @Setter @Builder - public static class ScoreboardDisplayObjective implements MCPacket { + public Factory score(Integer score) { + this.score = score; + return this; + } - private ObjectiveDisplaySlot displaySlot; - private String objectiveName; + public Factory action(ScoreAction action) { + this.action = action; + return this; + } - @Override - public void read(FriendlyByteBuf byteBuf) { - this.displaySlot = ObjectiveDisplaySlot.IDS.value((int) byteBuf.readByte()); - this.objectiveName = byteBuf.readUtf(); - } + public ScoreboardScore build() { + final Action action = Action.values()[this.action.ordinal()]; - @Override - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeByte(this.displaySlot.getSerializeId()); - byteBuf.writeUtf(this.objectiveName); + return new ScoreboardScore( + owner, + action, + objectiveName, + Optional.ofNullable(score) + ); + } } } - @Getter @Setter @Builder - public static class ScoreboardObjective implements MCPacket { - private String objectiveName; - private Component displayName; - private ObjectiveRenderType renderType; - private int method; - - @Override - public void read(FriendlyByteBuf byteBuf) { - this.objectiveName = byteBuf.readUtf(); - this.method = byteBuf.readByte(); - if (this.method != 0 && this.method != 2) { - this.displayName = Component.empty(); - this.renderType = ObjectiveRenderType.INTEGER; - } else { - this.displayName = byteBuf.readComponent(MCProtocol.INSTANCE.version().below(MCVersion.V1_13)); - this.renderType = byteBuf.readEnum(ObjectiveRenderType.class); - } + @Getter @Setter @Deprecated + public static class ScoreboardDisplayObjective extends WrapperPlayServerDisplayScoreboard { + public ScoreboardDisplayObjective(int position, String scoreName) { + super(position, scoreName); + } + + public static Factory builder() { + return new Factory(); } - @Override - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeUtf(this.objectiveName); - byteBuf.writeByte(this.method); - if (method == 0 || method == 2) { - byteBuf.writeComponent(this.displayName, MCProtocol.INSTANCE.version().below(MCVersion.V1_13)); - byteBuf.writeEnum(this.renderType); + public static class Factory { + private ObjectiveDisplaySlot displaySlot; + private String objectiveName; + + public Factory displaySlot(ObjectiveDisplaySlot displaySlot) { + this.displaySlot = displaySlot; + return this; + } + + public Factory objectiveName(String objectiveName) { + this.objectiveName = objectiveName; + return this; + } + + public ScoreboardDisplayObjective build() { + return new ScoreboardDisplayObjective( + displaySlot.getSerializeId(), + objectiveName + ); } } } - @Getter @Setter @Builder - public static class Tablist implements MCPacket { - private Component header, footer; - @Override - public void read(FriendlyByteBuf byteBuf) { - this.header = byteBuf.readComponent(); - this.footer = byteBuf.readComponent(); + @Getter @Setter @Deprecated + public static class ScoreboardObjective extends WrapperPlayServerScoreboardObjective { + public ScoreboardObjective(String name, ObjectiveMode mode, Optional displayName, Optional display) { + super(name, mode, displayName, display); } - @Override - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeComponent(this.header); - byteBuf.writeComponent(this.footer); + public static Factory builder() { + return new Factory(); + } + + public static class Factory { + private String objectiveName; + private Component displayName; + private ObjectiveRenderType renderType; + private Integer method; + + public Factory objectiveName(String objectiveName) { + this.objectiveName = objectiveName; + return this; + } + + public Factory displayName(Component displayName) { + this.displayName = displayName; + return this; + } + + public Factory renderType(ObjectiveRenderType renderType) { + this.renderType = renderType; + return this; + } + + public Factory method(Integer method) { + this.method = method; + return this; + } + + public ScoreboardObjective build() { + final ObjectiveMode mode = ObjectiveMode.values()[renderType.ordinal()]; + final Optional method = Optional.ofNullable(this.method == null + ? null + : HealthDisplay.values()[this.method] + ); + + return new ScoreboardObjective( + objectiveName, + mode, + displayName == null + ? Optional.empty() + : Optional.of(MCAdventure.asJsonString(displayName, Locale.getDefault())), + method + ); + } } } - @Getter @Setter @Builder - public static class PlayerInfo implements MCPacket { - private PlayerInfoAction action; - @Singular - private List entries; - @Override - public void read(FriendlyByteBuf byteBuf) { - this.action = byteBuf.readEnum(PlayerInfoAction.class); - this.entries = byteBuf.readList(this.action::read); + @Getter @Setter @Deprecated + public static class Tablist extends WrapperPlayServerPlayerListHeaderAndFooter { + + public Tablist(Component headerComponent, Component footerComponent) { + super(headerComponent, footerComponent); + } + + public Tablist(String headerJson, String footerJson) { + super(headerJson, footerJson); } - @Override - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeEnum(this.action); - byteBuf.writeCollection(this.entries, this.action::write); + + public static Factory builder() { + return new Factory(); } - } - @Getter @Setter @Builder - public static class ScoreboardTeam implements MCPacket { - private String name; - private TeamAction teamAction; - private NameTagVisibility nameTagVisibility; - @Singular - private List players; - private Optional parameters; - - @Override - public void read(FriendlyByteBuf byteBuf) { - this.name = byteBuf.readUtf(); - this.teamAction = TeamAction.getById(byteBuf.readByte()); - if (this.teamAction.isHasParameters()) { - this.parameters = Optional.of(new Parameters(byteBuf)); - } else { - this.parameters = Optional.empty(); + public static class Factory { + private Component header, footer; + + public Factory header(Component header) { + this.header = header; + return this; } - if (this.teamAction.isHasPlayers()) { - this.players = byteBuf.readList(FriendlyByteBuf::readUtf); - } else { - this.players = Collections.emptyList(); + public Factory footer(Component footer) { + this.footer = footer; + return this; + } + + public Tablist build() { + return new Tablist(header, footer); } } - @Override - public void write(FriendlyByteBuf byteBuf) { - byteBuf.writeUtf(this.name); - byteBuf.writeByte(this.teamAction.getId()); - if (this.teamAction.isHasParameters()) { - this.parameters.orElseThrow(() -> new IllegalStateException("Parameters not present, but method is " + this.teamAction.name())).write(byteBuf); + } + + @Getter @Setter @Deprecated + public static class PlayerInfo extends WrapperPlayServerPlayerInfo { + + public PlayerInfo(@NotNull Action action, List playerDataList) { + super(action, playerDataList); + } + + public PlayerInfo(@NotNull Action action, PlayerData... playerData) { + super(action, playerData); + } + + public PlayerInfo(@NotNull Action action, PlayerData playerData) { + super(action, playerData); + } + + public static Factory builder() { + return new Factory(); + } + + public static class Factory { + private PlayerInfoAction action; + @Singular + private List entries; + + public Factory action(PlayerInfoAction action) { + this.action = action; + return this; } - if (this.teamAction.isHasPlayers()) { - byteBuf.writeCollection(this.players, FriendlyByteBuf::writeUtf); + public Factory entries(List entries) { + this.entries = entries; + return this; } - } - @NoArgsConstructor @AllArgsConstructor @Getter @Setter @Builder - public static class Parameters { - @Builder.Default - private Component displayName = Component.empty(); - @Builder.Default - private Component playerPrefix = Component.empty(); - @Builder.Default - private Component playerSuffix = Component.empty(); - @Builder.Default - private NameTagVisibility nametagVisibility = NameTagVisibility.ALWAYS; - @Builder.Default - private CollisionRule collisionRule = CollisionRule.ALWAYS; - @Builder.Default - private ChatFormatting color = ChatFormatting.BLACK; - private int options; - public Parameters(FriendlyByteBuf buf) { - switch (MCProtocol.INSTANCE.version()) { - case V1_7: - this.displayName = buf.readComponent(true); - this.playerPrefix = buf.readComponent(true); - this.playerSuffix = buf.readComponent(true); - this.options = buf.readByte(); - this.color = buf.readEnum(ChatFormatting.class); - this.nametagVisibility = NameTagVisibility.ALWAYS; - this.collisionRule = CollisionRule.ALWAYS; - break; - case V1_8: - this.displayName = buf.readComponent(true); - this.playerPrefix = buf.readComponent(true); - this.playerSuffix = buf.readComponent(true); - this.options = buf.readByte(); - this.nametagVisibility = NameTagVisibility.getByName(buf.readUtf(40)); - this.collisionRule = CollisionRule.ALWAYS; - this.color = buf.readEnum(ChatFormatting.class); - break; - case V1_9: - default: - this.displayName = buf.readComponent(); - this.options = buf.readByte(); - this.nametagVisibility = NameTagVisibility.getByName(buf.readUtf(40)); - this.collisionRule = CollisionRule.getByName(buf.readUtf(40)); - this.color = buf.readEnum(ChatFormatting.class); - this.playerPrefix = buf.readComponent(MCProtocol.INSTANCE.version().below(MCVersion.V1_13)); - this.playerSuffix = buf.readComponent(MCProtocol.INSTANCE.version().below(MCVersion.V1_13)); - break; - } + public Factory entries(PlayerInfoData... entries) { + this.entries = Arrays.asList(entries); + return this; } - public void write(FriendlyByteBuf buf) { - buf.writeComponent(this.displayName, MCProtocol.INSTANCE.version().below(MCVersion.V1_13)); - switch (MCProtocol.INSTANCE.version()) { - case V1_7: - buf.writeComponent(this.playerPrefix, true); - buf.writeComponent(this.playerSuffix, true); - buf.writeByte(this.options); - buf.writeEnum(this.color); - break; - case V1_8: - buf.writeComponent(this.playerPrefix, true); - buf.writeComponent(this.playerSuffix, true); - buf.writeByte(this.options); - buf.writeUtf(this.nametagVisibility.name); - buf.writeEnum(this.color); - break; - case V1_9: - default: - buf.writeByte(this.options); - buf.writeUtf(this.nametagVisibility.name); - buf.writeUtf(this.collisionRule.name); - buf.writeEnum(this.color); - buf.writeComponent(this.playerPrefix, MCProtocol.INSTANCE.version().below(MCVersion.V1_13)); - buf.writeComponent(this.playerSuffix, MCProtocol.INSTANCE.version().below(MCVersion.V1_13)); - break; + public PlayerInfo build() { + final Action action = Action.values()[this.action.ordinal()]; + final List playerDataList = new ArrayList<>(); + if (entries != null) { + for (PlayerInfoData entry : entries) { + final UserProfile profile = new UserProfile( + entry.getGameProfile().getUuid(), + entry.getGameProfile().getName(), + entry.getGameProfile().getProperties() + .stream() + .map(e -> new TextureProperty(e.getName(), e.getValue(), e.getSignature())) + .collect(Collectors.toList()) + ); + final PlayerData playerData = new PlayerData( + entry.getComponent(), + profile, + GameMode.getById(entry.getGameMode().getValue()), + entry.getPing() + ); + + playerDataList.add(playerData); + } } + + return new PlayerInfo(action, playerDataList); } } } - @Getter @Setter @Builder - public static class Title implements MCPacket { - private Component component; - @Override - public void read(FriendlyByteBuf byteBuf) { - this.component = byteBuf.readComponent(); + @Getter @Setter @Deprecated + public static class ScoreboardTeam extends WrapperPlayServerTeams { + public ScoreboardTeam(String teamName, TeamMode teamMode, Optional teamInfo, Collection entities) { + super(teamName, teamMode, teamInfo, entities); } - @Override - public void write(FriendlyByteBuf byteBuf) { - if (MCProtocol.INSTANCE.getProtocolMapping().getVersion().below(MCVersion.V1_17)) { - byteBuf.writeVarInt(0); - } - byteBuf.writeComponent(component); + + public ScoreboardTeam(String teamName, TeamMode teamMode, Optional teamInfo, String... entities) { + super(teamName, teamMode, teamInfo, entities); } - } - @Getter @Setter @Builder - public static class SubTitle implements MCPacket { - private Component component; - @Override - public void read(FriendlyByteBuf byteBuf) { - this.component = byteBuf.readComponent(); + public ScoreboardTeam(PacketSendEvent event) { + super(event); } - @Override - public void write(FriendlyByteBuf byteBuf) { - if (MCProtocol.INSTANCE.version().below(MCVersion.V1_17)) { - byteBuf.writeVarInt(1); - } - byteBuf.writeComponent(component); + + public void setTeamAction(TeamAction action) { + super.setTeamMode(TeamMode.values()[action.ordinal()]); } - } - @Getter @Setter @Builder - public static class TitleTimes implements MCPacket { - private int fadeIn; - private int stay; - private int fadeOut; - @Override - public void read(FriendlyByteBuf byteBuf) { - this.fadeIn = byteBuf.readInt(); - this.stay = byteBuf.readInt(); - this.fadeOut = byteBuf.readInt(); + public void setParameters(final Optional parameters) { + super.setTeamInfo( + parameters.map(e -> new ScoreBoardTeamInfo( + e.getDisplayName(), + e.getPlayerPrefix(), + e.getPlayerSuffix(), + e.getNametagVisibility(), + e.getCollisionRule(), + e.getColor() == null ? null : e.getColor().getColor() == null ? null : NamedTextColor.ofExact(e.getColor().getColor()), + OptionData.fromValue((byte) e.getOptions()) + )) + ); } - @Override - public void write(FriendlyByteBuf byteBuf) { - if (MCProtocol.INSTANCE.version().below(MCVersion.V1_17)) { - byteBuf.writeVarInt(2); - } - byteBuf.writeInt(this.fadeIn); - byteBuf.writeInt(this.stay); - byteBuf.writeInt(this.fadeOut); + + public static Factory builder() { + return new Factory(); } - } - @Getter @Setter @Builder - public static class TitleClear implements MCPacket { - private boolean resetTimes; - @Override - public void read(FriendlyByteBuf byteBuf) { - if (MCProtocol.INSTANCE.version().isOrAbove(MCVersion.V1_17)) { - this.resetTimes = byteBuf.readBoolean(); + public static class Factory { + private String name; + private TeamAction teamAction; + @Singular + private Collection players = Collections.emptyList(); + private Optional parameters = Optional.empty(); + + public Factory name(String name) { + this.name = name; + return this; } - } - @Override - public void write(FriendlyByteBuf byteBuf) { - if (MCProtocol.INSTANCE.version().below(MCVersion.V1_17)) { - byteBuf.writeVarInt(resetTimes ? 4 : 3); - } else { - byteBuf.writeBoolean(this.resetTimes); + + public Factory teamAction(TeamAction teamAction) { + this.teamAction = teamAction; + return this; + } + + public Factory players(Collection players) { + this.players = players; + return this; + } + + public Factory players(String... players) { + this.players = Arrays.asList(players); + return this; + } + + public Factory parameters(Optional parameters) { + this.parameters = parameters; + return this; + } + + public ScoreboardTeam build() { + final String name = this.name; + final TeamMode mode = TeamMode.values()[teamAction.ordinal()]; + final Optional info = parameters.map(e -> new ScoreBoardTeamInfo( + e.getDisplayName(), + e.getPlayerPrefix(), + e.getPlayerSuffix(), + e.getNametagVisibility(), + e.getCollisionRule(), + e.getColor() == null ? null : e.getColor().getColor() == null ? null : NamedTextColor.ofExact(e.getColor().getColor()), + OptionData.fromValue((byte) e.getOptions()) + )); + + return new ScoreboardTeam(name, mode, info, players); } } - } + @Builder @NoArgsConstructor @AllArgsConstructor @Getter @Setter + public static class Parameters { + private Component displayName = Component.empty(); + @Builder.Default + private Component playerPrefix = Component.empty(); + @Builder.Default + private Component playerSuffix = Component.empty(); + @Builder.Default + private NameTagVisibility nametagVisibility = NameTagVisibility.ALWAYS; + @Builder.Default + private CollisionRule collisionRule = CollisionRule.ALWAYS; + @Builder.Default + private ChatFormatting color = ChatFormatting.BLACK; + private int options; + } + } } - } diff --git a/io.fairyproject.tests/mc-tests/src/main/java/io/fairyproject/tests/mc/MCPlayerMock.java b/io.fairyproject.tests/mc-tests/src/main/java/io/fairyproject/tests/mc/MCPlayerMock.java index 181401ad..c66e577a 100644 --- a/io.fairyproject.tests/mc-tests/src/main/java/io/fairyproject/tests/mc/MCPlayerMock.java +++ b/io.fairyproject.tests/mc-tests/src/main/java/io/fairyproject/tests/mc/MCPlayerMock.java @@ -1,9 +1,9 @@ package io.fairyproject.tests.mc; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; import io.fairyproject.mc.GameMode; import io.fairyproject.mc.MCGameProfile; import io.fairyproject.mc.MCPlayer; -import io.fairyproject.mc.protocol.MCPacket; import io.fairyproject.mc.protocol.MCVersion; import io.netty.channel.Channel; import lombok.RequiredArgsConstructor; @@ -21,7 +21,7 @@ public class MCPlayerMock implements MCPlayer { private final String name; private final MCVersion version; private final Object originalInstance; - private final LinkedList packetQueue = new LinkedList<>(); + private final LinkedList> packetQueue = new LinkedList<>(); @Nullable private Component displayName; @@ -103,13 +103,13 @@ public T as(Class playerClass) { } @Override - public void sendPacket(MCPacket packet) { + public void sendPacket(PacketWrapper packet) { synchronized (this) { this.packetQueue.add(packet); } } - public MCPacket nextPacket() { + public PacketWrapper nextPacket() { synchronized (this) { return this.packetQueue.pop(); } diff --git a/settings.gradle b/settings.gradle index 68a4aa76..4b284c84 100644 --- a/settings.gradle +++ b/settings.gradle @@ -22,6 +22,14 @@ * SOFTWARE. */ +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + } +} + + rootProject.name = "fairy-parent" void initPlatforms() { diff --git a/test-plugin/build.gradle b/test-plugin/build.gradle index 66aabca8..e18fafb4 100644 --- a/test-plugin/build.gradle +++ b/test-plugin/build.gradle @@ -1,17 +1,17 @@ -import io.fairyproject.gradle.FairyPlugin - buildscript { repositories { mavenCentral() } +} - dependencies { - classpath project(":gradle-plugin") - } +plugins { + id 'java' + id 'io.fairyproject' version '1.0.1b5' } -apply plugin: "java" -apply plugin: FairyPlugin +repositories { + mavenLocal() +} fairy { name = "debugPlugin" @@ -20,12 +20,7 @@ fairy { fairyIde = true - platform("app") - - module("discord") - module("config") - module("command") - module("storage") + platform("bukkit") } test { diff --git a/test-plugin/src/main/java/io/fairyproject/debug/DebugPlugin.java b/test-plugin/src/main/java/io/fairyproject/debug/DebugPlugin.java index 6cd4ecea..1a71fefa 100644 --- a/test-plugin/src/main/java/io/fairyproject/debug/DebugPlugin.java +++ b/test-plugin/src/main/java/io/fairyproject/debug/DebugPlugin.java @@ -2,9 +2,9 @@ import io.fairyproject.Debug; import io.fairyproject.ScheduledAtFixedRate; -import io.fairyproject.app.Application; +import io.fairyproject.plugin.Plugin; -public class DebugPlugin extends Application { +public class DebugPlugin extends Plugin { @Override public void onInitial() {