diff --git a/.gitignore b/.gitignore index 4675fdb..83979f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -# Created by https://www.toptal.com/developers/gitignore/api/java,macos,maven,gradle,eclipse,windows,jetbrains+all -# Edit at https://www.toptal.com/developers/gitignore?templates=java,macos,maven,gradle,eclipse,windows,jetbrains+all +# Created by https://www.toptal.com/developers/gitignore/api/java,gradle,maven,intellij+all,eclipse,windows,linux,macos +# Edit at https://www.toptal.com/developers/gitignore?templates=java,gradle,maven,intellij+all,eclipse,windows,linux,macos ### Eclipse ### .metadata @@ -67,33 +67,7 @@ local.properties # Spring Boot Tooling .sts4-cache/ -### Java ### -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -replay_pid* - -### JetBrains+all ### +### Intellij+all ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 @@ -127,14 +101,14 @@ replay_pid* # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr +.idea/artifacts +.idea/compiler.xml +.idea/jarRepositories.xml +.idea/modules.xml +.idea/*.iml +.idea/modules +*.iml +*.ipr # CMake cmake-build-*/ @@ -172,7 +146,7 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser -### JetBrains+all Patch ### +### Intellij+all Patch ### # Ignore everything but code style settings and run configurations # that are supposed to be shared within teams. @@ -181,6 +155,47 @@ fabric.properties !.idea/codeStyles !.idea/runConfigurations +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + ### macOS ### # General .DS_Store @@ -284,4 +299,4 @@ gradle-app.setting # Java heap dump *.hprof -# End of https://www.toptal.com/developers/gitignore/api/java,macos,maven,gradle,eclipse,windows,jetbrains+all +# End of https://www.toptal.com/developers/gitignore/api/java,gradle,maven,intellij+all,eclipse,windows,linux,macos diff --git a/Jenkinsfile b/Jenkinsfile index 3fe1e6e..241fbd7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -3,20 +3,20 @@ pipeline { tools { jdk 'Jdk17' - maven 'maven' + maven 'gradle' } stages { stage('Build') { steps { echo 'Building..' - sh 'mvn clean package' + sh './gradlew clean build' } post { success { - archiveArtifacts 'spigot/target/GeyserBlockPlatform-Spigot.jar' - archiveArtifacts 'bungeecord/target/GeyserBlockPlatform-Bungeecord.jar' - archiveArtifacts 'velocity/target/GeyserBlockPlatform-Velocity.jar' + archiveArtifacts 'spigot/build/libs/GeyserBlockPlatform-Spigot.jar' + archiveArtifacts 'bungeecord/build/libs/GeyserBlockPlatform-Bungeecord.jar' + archiveArtifacts 'velocity/build/libs/GeyserBlockPlatform-Velocity.jar' } } } @@ -59,7 +59,7 @@ pipeline { env.changes = message } - discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.projectg.dev/job/GeyserBlockPlatform/)", footer: 'ProjectG', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), result: currentBuild.currentResult, title: "${env.JOB_NAME}", webhookURL: "${env.DISCORD_WEBHOOK}" + discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.kejonamc.dev/job/GeyserBlockPlatform/)", footer: 'kejonaMC', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), result: currentBuild.currentResult, title: "${env.JOB_NAME}", webhookURL: "${env.DISCORD_WEBHOOK}" } } } \ No newline at end of file diff --git a/LICENSE b/LICENSE index e02ae9f..af4cf1b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 Camotoy +Copyright (c) 2021 kejonaMC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..5c3174b --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,58 @@ + +plugins { + `java-library` + id("idea") + id("com.github.johnrengelman.shadow") version "8.1.1" apply false +} + +allprojects { + group = "dev.kejona.geyserblockplatform" + version = "2.0-SNAPSHOT" + description = "Prevent specific Bedrock platforms from joining your server" + + tasks { + withType { + options.encoding = "UTF-8" + } + } +} + +subprojects { + apply(plugin = "java-library") + + java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(8)) + } + } + + dependencies { + annotationProcessor("org.projectlombok:lombok:1.18.28") + compileOnly("org.projectlombok:lombok:1.18.28") + + compileOnly("org.jetbrains:annotations:24.0.1") + } + + repositories { + mavenCentral() + maven("https://repo.opencollab.dev/main/") + maven("https://oss.sonatype.org/content/repositories/snapshots") + maven("https://repo.spongepowered.org/maven/") + } + + tasks.processResources { + filesMatching(listOf("bungee.yml", "spigot.yml", "extension.yml")) { + expand( + "description" to project.description, + "version" to project.version, + ) + } + } +} + +idea { + module { + isDownloadJavadoc = true + isDownloadSources = true + } +} diff --git a/bungeecord/.gitignore b/bungeecord/.gitignore deleted file mode 100644 index 4788b4b..0000000 --- a/bungeecord/.gitignore +++ /dev/null @@ -1,113 +0,0 @@ -# User-specific stuff -.idea/ - -*.iml -*.ipr -*.iws - -# IntelliJ -out/ - -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -# Windows thumbnail cache files -Thumbs.db -Thumbs.db:encryptable -ehthumbs.db -ehthumbs_vista.db - -# Dump file -*.stackdump - -# Folder config file -[Dd]esktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp - -# Windows shortcuts -*.lnk - -target/ - -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next - -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties -.mvn/wrapper/maven-wrapper.jar -.flattened-pom.xml - -# Common working directory -run/ diff --git a/bungeecord/build.gradle.kts b/bungeecord/build.gradle.kts new file mode 100644 index 0000000..9222c1c --- /dev/null +++ b/bungeecord/build.gradle.kts @@ -0,0 +1,23 @@ + +plugins { + id("com.github.johnrengelman.shadow") +} + +dependencies { + api(projects.common) + compileOnly("net.md-5:bungeecord-api:1.19-R0.1-SNAPSHOT") +} + +tasks { + shadowJar { + val prefix = "${project.group}.${project.name}.shaded" + relocate("org.spongepowered.configurate", "$prefix.configurate") + relocate("io.leangen.geantyref", "$prefix.geantyref") + + archiveFileName.set("GeyserBlockPlatform-Bungeecord.jar") + } + + build { + dependsOn(shadowJar) + } +} diff --git a/bungeecord/pom.xml b/bungeecord/pom.xml deleted file mode 100644 index 46523c6..0000000 --- a/bungeecord/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - GeyserBlockPlatform - com.github.camotoy.geyserblockplatform - 1.1-SNAPSHOT - - 4.0.0 - - bungeecord - - - GeyserBlockPlatform-Bungeecord - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - ${java.version} - ${java.version} - - - - org.apache.maven.plugins - maven-shade-plugin - 3.2.4 - - - - com.fasterxml.jackson - com.github.camotoy.geyserblockplatform.relocations.jackson - - - org.yaml.snakeyaml - com.github.camotoy.geyserblockplatform.relocations.snakeyaml - - - - - - package - - shade - - - false - - - - - - - - src/main/resources - true - - - - - - - net.md-5 - bungeecord-api - 1.19-R0.1-SNAPSHOT - provided - - - org.geysermc.geyser - common - 2.1.1-SNAPSHOT - provided - - - com.github.camotoy.geyserblockplatform - common - 1.1-SNAPSHOT - compile - - - diff --git a/bungeecord/src/main/java/com/github/camotoy/geyserblockplatform/bungeecord/GeyserBlockPlatformBungee.java b/bungeecord/src/main/java/com/github/camotoy/geyserblockplatform/bungeecord/GeyserBlockPlatformBungee.java deleted file mode 100644 index 6076326..0000000 --- a/bungeecord/src/main/java/com/github/camotoy/geyserblockplatform/bungeecord/GeyserBlockPlatformBungee.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.github.camotoy.geyserblockplatform.bungeecord; - -import com.github.camotoy.geyserblockplatform.common.Permissions; -import com.github.camotoy.geyserblockplatform.common.config.Configurate; -import com.github.camotoy.geyserblockplatform.common.device.SupportedDeviceOSList; -import com.github.camotoy.geyserblockplatform.common.platformchecker.BedrockPlatformChecker; -import com.github.camotoy.geyserblockplatform.common.platformchecker.FloodgateBedrockPlatformChecker; -import com.github.camotoy.geyserblockplatform.common.platformchecker.GeyserBedrockPlatformChecker; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.ProxyServer; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.event.ServerConnectedEvent; -import net.md_5.bungee.api.plugin.Listener; -import net.md_5.bungee.api.plugin.Plugin; -import net.md_5.bungee.event.EventHandler; -import org.geysermc.floodgate.util.DeviceOs; - -import java.util.UUID; - -public final class GeyserBlockPlatformBungee extends Plugin implements Listener { - private BedrockPlatformChecker platformChecker; - private Configurate config = null; - - @Override - public void onEnable() { - config = Configurate.create(this.getDataFolder().toPath()); - boolean hasFloodgate = ProxyServer.getInstance().getPluginManager().getPlugin("floodgate") != null; - boolean hasGeyser = ProxyServer.getInstance().getPluginManager().getPlugin("Geyser-Bungeecord") != null; - - if (!hasFloodgate && !hasGeyser) { - getLogger().warning("There is no Geyser or Floodgate plugin detected! Disabling..."); - this.onDisable(); - return; - } - - if (hasFloodgate) { - this.platformChecker = new FloodgateBedrockPlatformChecker(); - } else { - this.platformChecker = new GeyserBedrockPlatformChecker(); - } - - ProxyServer.getInstance().getPluginManager().registerListener(this, this); - } - - @EventHandler - public void onPlayerServerConnect(ServerConnectedEvent event) { - if (event.getPlayer().hasPermission(Permissions.bypassPermission)) { - return; - } - - // Check if player is a bedrock player - if (platformChecker.isBedrockPlayer(event.getPlayer().getUniqueId())) { - String servername = event.getServer().getInfo().getName(); - // First check if the "deny-server-access:" list contains the server name. - if (config.getNoServerAccess().contains(servername) - // Then check if the list contains "all" in case they want full network deny - || config.getNoServerAccess().contains("all")) { - // Check if the client platform isn't blocked - if (!connectionAllowed(event.getPlayer().getUniqueId())) { - // Disconnect player - event.getPlayer().disconnect(new TextComponent(ChatColor.translateAlternateColorCodes('&', config.getNoAccessMessage()))); - } - } - } - } - - /** - * Checks the supportedDeviceOSList to see if a connection from platform is allowed - * - * @param uuid the players uuid - * @return checks if the players platform is blocked - */ - public boolean connectionAllowed(UUID uuid) { - DeviceOs deviceOS = this.platformChecker.getBedrockPlatform(uuid); - - if (deviceOS == null) { - return false; - } - - return SupportedDeviceOSList.supportedDeviceOSList(config).contains(deviceOS); - } -} diff --git a/bungeecord/src/main/java/dev/kejona/geyserblockplatform/bungeecord/GeyserBlockPlatformBungee.java b/bungeecord/src/main/java/dev/kejona/geyserblockplatform/bungeecord/GeyserBlockPlatformBungee.java new file mode 100644 index 0000000..0026dbb --- /dev/null +++ b/bungeecord/src/main/java/dev/kejona/geyserblockplatform/bungeecord/GeyserBlockPlatformBungee.java @@ -0,0 +1,61 @@ +package dev.kejona.geyserblockplatform.bungeecord; + +import dev.kejona.geyserblockplatform.common.BlockResult; +import dev.kejona.geyserblockplatform.common.Permissions; +import dev.kejona.geyserblockplatform.common.bedrock.BaseApiHandler; +import dev.kejona.geyserblockplatform.common.bedrock.BedrockHandler; +import dev.kejona.geyserblockplatform.common.bedrock.FloodgateHandler; +import dev.kejona.geyserblockplatform.common.config.Config; +import dev.kejona.geyserblockplatform.common.config.ConfigLoader; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.event.PostLoginEvent; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.api.plugin.PluginManager; +import net.md_5.bungee.event.EventHandler; +import net.md_5.bungee.event.EventPriority; + +public final class GeyserBlockPlatformBungee extends Plugin implements Listener { + private BedrockHandler handler; + private Config config; + + @Override + public void onEnable() { + PluginManager pluginManager = getProxy().getPluginManager(); + if (pluginManager.getPlugin("floodgate") != null) { + handler = new FloodgateHandler(); + } else if (pluginManager.getPlugin("Geyser-Bungeecord") != null) { + handler = new BaseApiHandler(); + } else { + getLogger().warning("There is no Geyser or Floodgate plugin detected! Disabling..."); + onDisable(); + } + + try { + config = ConfigLoader.loadConfig(getDataFolder().toPath()); + } catch (Exception e) { + getLogger().severe("Failed to load config"); + e.printStackTrace(); + return; + } + ProxyServer.getInstance().getPluginManager().registerListener(this, this); + } + + @EventHandler(priority = EventPriority.HIGH) + public void onPostLogin(PostLoginEvent event) { + ProxiedPlayer player = event.getPlayer(); + if (player.hasPermission(Permissions.BYPASS)) { + return; + } + + BlockResult result = config.computeResult(player.getUniqueId(), handler); + if (!result.allowed()) { + BlockResult.Denied deniedResult = (BlockResult.Denied) result; + player.disconnect(TextComponent.fromLegacyText(deniedResult.message())); + } else { + result.warnings().forEach(warning -> player.sendMessage(TextComponent.fromLegacyText(warning))); + } + } +} diff --git a/bungeecord/src/main/resources/bungee.yml b/bungeecord/src/main/resources/bungee.yml index 84119e2..615fb0f 100644 --- a/bungeecord/src/main/resources/bungee.yml +++ b/bungeecord/src/main/resources/bungee.yml @@ -1,6 +1,11 @@ name: GeyserBlockPlatform -version: '${project.version}' -main: com.github.camotoy.geyserblockplatform.bungeecord.GeyserBlockPlatformBungee +description: "${description}" +version: "${version}" +author: kejonaMC + +main: dev.kejona.geyserblockplatform.bungeecord.GeyserBlockPlatformBungee +softDepends: [floodgate, Geyser-Bungeecord] + permissions: geyserblockplatform.bypass: description: Give player a bypass for platform checker \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts new file mode 100644 index 0000000..2b17ce0 --- /dev/null +++ b/common/build.gradle.kts @@ -0,0 +1,8 @@ + +dependencies { + api("org.spongepowered:configurate-yaml:4.2.0-SNAPSHOT") + + compileOnlyApi("org.geysermc.geyser:common:2.1.2-SNAPSHOT") + compileOnly("org.geysermc.api:base-api:1.0.0-SNAPSHOT") + compileOnly("org.geysermc.floodgate:api:2.2.2-SNAPSHOT") +} diff --git a/common/pom.xml b/common/pom.xml deleted file mode 100644 index bdd711a..0000000 --- a/common/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - GeyserBlockPlatform - com.github.camotoy.geyserblockplatform - 1.1-SNAPSHOT - - 4.0.0 - - common - - - - org.geysermc.geyser - core - 2.1.1-SNAPSHOT - provided - - - * - * - - - - - org.geysermc.floodgate - core - 2.2.2-SNAPSHOT - provided - - - com.fasterxml.jackson.core - jackson-databind - 2.13.3 - compile - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - 2.13.3 - compile - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - ${java.version} - ${java.version} - - - - - - src/main/resources - true - - - - - \ No newline at end of file diff --git a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/Permissions.java b/common/src/main/java/com/github/camotoy/geyserblockplatform/common/Permissions.java deleted file mode 100644 index 97b67ff..0000000 --- a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/Permissions.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.github.camotoy.geyserblockplatform.common; - -public class Permissions { - public static final String bypassPermission = "geyserblockplatform.bypass"; -} diff --git a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/config/Configurate.java b/common/src/main/java/com/github/camotoy/geyserblockplatform/common/config/Configurate.java deleted file mode 100644 index 8f1e0c5..0000000 --- a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/config/Configurate.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.github.camotoy.geyserblockplatform.common.config; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class Configurate { - /** - * Load config - * - * @param dataDirectory The config's directory - */ - public static Configurate create(Path dataDirectory) { - File folder = dataDirectory.toFile(); - File file = new File(folder, "config.yml"); - - if (!file.exists()) { - if (!file.getParentFile().exists()) { - file.getParentFile().mkdirs(); - } - try (InputStream input = Configurate.class.getResourceAsStream("/" + file.getName())) { - if (input != null) { - Files.copy(input, file.toPath()); - } else { - file.createNewFile(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - try { - final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); - return mapper.readValue(dataDirectory.resolve("config.yml").toFile(), Configurate.class); - } catch (IOException e) { - throw new RuntimeException("Cannot create GeyserBlockPlatform config!", e); - } - } - - @JsonProperty("unknown-platform-enabled") - private boolean unknownEnabled = true; - @JsonProperty("android-enabled") - private boolean androidEnabled = true; - @JsonProperty("ios-enabled") - private boolean iosEnabled = true; - @JsonProperty("macos-enabled") - private boolean macOsEnabled = true; - @JsonProperty("gearvr-enabled") - private boolean gearVrEnabled = true; - @JsonProperty("windows10-enabled") - private boolean windows10Enabled = true; - @JsonProperty("windowsedu-enabled") - private boolean windowsEduEnabled = true; - @JsonProperty("ps4-enabled") - private boolean ps4Enabled = true; - @JsonProperty("switch-enabled") - private boolean switchEnabled = true; - @JsonProperty("xboxone-enabled") - private boolean xboxOneEnabled = true; - @JsonProperty("windowsphone-enabled") - private boolean windowsPhoneEnabled = true; - - @JsonProperty("deny-server-access") - private List noServerAccess; - - @JsonProperty("no-access-message") - private String noAccessMessage; - - public boolean isUnknownEnabled() { - return unknownEnabled; - } - - public boolean isAndroidEnabled() { - return androidEnabled; - } - - public boolean isIosEnabled() { - return iosEnabled; - } - - public boolean isMacOsEnabled() { - return macOsEnabled; - } - - public boolean isGearVrEnabled() { - return gearVrEnabled; - } - - public boolean isWindows10Enabled() { - return windows10Enabled; - } - - public boolean isWindowsEduEnabled() { - return windowsEduEnabled; - } - - public boolean isPs4Enabled() { - return ps4Enabled; - } - - public boolean isSwitchEnabled() { - return switchEnabled; - } - - public boolean isXboxOneEnabled() { - return xboxOneEnabled; - } - - public boolean isWindowsPhoneEnabled() { - return windowsPhoneEnabled; - } - - public String getNoAccessMessage() { - return noAccessMessage; - } - - public List getNoServerAccess() { - return noServerAccess; - } -} diff --git a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/device/DeviceOsFixer.java b/common/src/main/java/com/github/camotoy/geyserblockplatform/common/device/DeviceOsFixer.java deleted file mode 100644 index 5c444ba..0000000 --- a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/device/DeviceOsFixer.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.github.camotoy.geyserblockplatform.common.device; - - -import org.geysermc.floodgate.util.DeviceOs; - -public class DeviceOsFixer { - /** - * Fix Geyser and Floodgate's DeviceOS enumeration being incorrect - */ - public static DeviceOs getProperDeviceOs(DeviceOs deviceOS) { - if (deviceOS == DeviceOs.NX) { - return DeviceOs.PS4; - } - - return deviceOS; - } -} diff --git a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/device/SupportedDeviceOSList.java b/common/src/main/java/com/github/camotoy/geyserblockplatform/common/device/SupportedDeviceOSList.java deleted file mode 100644 index 33724fe..0000000 --- a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/device/SupportedDeviceOSList.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.github.camotoy.geyserblockplatform.common.device; - -import com.github.camotoy.geyserblockplatform.common.config.Configurate; -import org.geysermc.floodgate.util.DeviceOs; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Supplier; - -public class SupportedDeviceOSList { - - /** - * Load the supportedDeviceOSList. - * - * @param config configuration - * @return a list of blocked/unblocked platforms - */ - public static List supportedDeviceOSList(Configurate config) { - List getSupportedDeviceOSList = new ArrayList<>(); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.UNKNOWN, config::isUnknownEnabled); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.GOOGLE, config::isAndroidEnabled); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.IOS, config::isIosEnabled); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.OSX, config::isMacOsEnabled); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.GEARVR, config::isGearVrEnabled); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.UWP, config::isWindows10Enabled); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.WIN32, config::isWindowsEduEnabled); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.PS4, config::isPs4Enabled); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.NX, config::isSwitchEnabled); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.XBOX, config::isXboxOneEnabled); - addValueIfTrue(getSupportedDeviceOSList, DeviceOs.WINDOWS_PHONE, config::isWindowsPhoneEnabled); - - return getSupportedDeviceOSList; - } - private static void addValueIfTrue(List list, DeviceOs deviceOs, Supplier function) { - if (function.get()) { - list.add(deviceOs); - } - } -} diff --git a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/platformchecker/BedrockPlatformChecker.java b/common/src/main/java/com/github/camotoy/geyserblockplatform/common/platformchecker/BedrockPlatformChecker.java deleted file mode 100644 index 29ec2a0..0000000 --- a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/platformchecker/BedrockPlatformChecker.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.github.camotoy.geyserblockplatform.common.platformchecker; - -import org.geysermc.floodgate.util.DeviceOs; - -import java.util.UUID; - -public interface BedrockPlatformChecker { - boolean isBedrockPlayer(UUID uuid); - DeviceOs getBedrockPlatform(UUID uuid); -} diff --git a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/platformchecker/FloodgateBedrockPlatformChecker.java b/common/src/main/java/com/github/camotoy/geyserblockplatform/common/platformchecker/FloodgateBedrockPlatformChecker.java deleted file mode 100644 index 121d751..0000000 --- a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/platformchecker/FloodgateBedrockPlatformChecker.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.github.camotoy.geyserblockplatform.common.platformchecker; - -import com.github.camotoy.geyserblockplatform.common.device.DeviceOsFixer; -import org.geysermc.floodgate.api.FloodgateApi; -import org.geysermc.floodgate.api.player.FloodgatePlayer; -import org.geysermc.floodgate.util.DeviceOs; - -import java.util.UUID; - -public class FloodgateBedrockPlatformChecker implements BedrockPlatformChecker { - - @Override - public boolean isBedrockPlayer(UUID uuid) { - return FloodgateApi.getInstance().isFloodgatePlayer(uuid); - } - - @Override - public DeviceOs getBedrockPlatform(UUID uuid) { - FloodgatePlayer player = FloodgateApi.getInstance().getPlayer(uuid); - if (player != null) { - return DeviceOsFixer.getProperDeviceOs(player.getDeviceOs()); - } - return null; - } -} diff --git a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/platformchecker/GeyserBedrockPlatformChecker.java b/common/src/main/java/com/github/camotoy/geyserblockplatform/common/platformchecker/GeyserBedrockPlatformChecker.java deleted file mode 100644 index 55b5c55..0000000 --- a/common/src/main/java/com/github/camotoy/geyserblockplatform/common/platformchecker/GeyserBedrockPlatformChecker.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.github.camotoy.geyserblockplatform.common.platformchecker; - -import com.github.camotoy.geyserblockplatform.common.device.DeviceOsFixer; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.floodgate.util.DeviceOs; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.session.GeyserSession; - -import java.util.UUID; - -public class GeyserBedrockPlatformChecker implements BedrockPlatformChecker { - - private final GeyserImpl geyser; - - public GeyserBedrockPlatformChecker() { - this.geyser = GeyserImpl.getInstance(); - } - - @Override - public boolean isBedrockPlayer(UUID uuid) { - return geyser.isBedrockPlayer(uuid); - } - - @Override - public DeviceOs getBedrockPlatform(UUID uuid) { - @Nullable GeyserSession session = geyser.connectionByUuid(uuid); - if (session != null) { - return DeviceOsFixer.getProperDeviceOs(session.getClientData().getDeviceOs()); - } - return null; - } -} diff --git a/common/src/main/java/dev/kejona/geyserblockplatform/common/BlockResult.java b/common/src/main/java/dev/kejona/geyserblockplatform/common/BlockResult.java new file mode 100644 index 0000000..6db8a26 --- /dev/null +++ b/common/src/main/java/dev/kejona/geyserblockplatform/common/BlockResult.java @@ -0,0 +1,53 @@ +package dev.kejona.geyserblockplatform.common; + +import lombok.Getter; +import lombok.experimental.Accessors; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Collections; +import java.util.List; + +@Accessors(fluent = true) +@Getter +public class BlockResult { + + private static final BlockResult ACCEPTED = new BlockResult(true, null); + + private final boolean allowed; + + @NonNull + private final List warnings; + + private BlockResult(boolean allowed, @Nullable List warnings) { + this.allowed = allowed; + + if (warnings == null) { + this.warnings = Collections.emptyList(); + } else { + this.warnings = warnings; + } + } + + public static BlockResult allowedResult() { + return ACCEPTED; + } + + public static BlockResult warn(List warnings) { + return new BlockResult(true, warnings); + } + + public static BlockResult.Denied denied(String type) { + return new Denied(type); + } + + @Getter + public static class Denied extends BlockResult { + private final String message; + + private Denied(String message) { + super(false, null); + this.message = message; + } + } +} diff --git a/common/src/main/java/dev/kejona/geyserblockplatform/common/Permissions.java b/common/src/main/java/dev/kejona/geyserblockplatform/common/Permissions.java new file mode 100644 index 0000000..cf177f0 --- /dev/null +++ b/common/src/main/java/dev/kejona/geyserblockplatform/common/Permissions.java @@ -0,0 +1,5 @@ +package dev.kejona.geyserblockplatform.common; + +public final class Permissions { + public static final String BYPASS = "geyserblockplatform.bypass"; +} diff --git a/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/BaseApiHandler.java b/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/BaseApiHandler.java new file mode 100644 index 0000000..3665275 --- /dev/null +++ b/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/BaseApiHandler.java @@ -0,0 +1,30 @@ +package dev.kejona.geyserblockplatform.common.bedrock; + +import org.geysermc.api.Geyser; +import org.geysermc.api.GeyserApiBase; +import org.geysermc.api.connection.Connection; +import org.geysermc.floodgate.util.DeviceOs; +import org.geysermc.floodgate.util.InputMode; +import org.geysermc.floodgate.util.UiProfile; + +import java.util.Objects; +import java.util.UUID; + +public class BaseApiHandler implements BedrockHandler { + private final GeyserApiBase api = Objects.requireNonNull(Geyser.api(), "geyser base-api"); + + @Override + public boolean isBedrockPlayer(UUID uuid) { + return api.isBedrockPlayer(uuid); + } + + @Override + public Profile profile(UUID uuid) { + Connection connection = Objects.requireNonNull(api.connectionByUuid(uuid), "connection for " + uuid); + return new Profile( + DeviceOs.fromId(connection.platform().ordinal()), + InputMode.fromId(connection.inputMode().ordinal()), + UiProfile.fromId(connection.uiProfile().ordinal()) + ); + } +} diff --git a/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/BedrockHandler.java b/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/BedrockHandler.java new file mode 100644 index 0000000..a46d1df --- /dev/null +++ b/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/BedrockHandler.java @@ -0,0 +1,8 @@ +package dev.kejona.geyserblockplatform.common.bedrock; + +import java.util.UUID; + +public interface BedrockHandler { + boolean isBedrockPlayer(UUID uuid); + Profile profile(UUID uuid); +} diff --git a/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/FloodgateHandler.java b/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/FloodgateHandler.java new file mode 100644 index 0000000..e6d25b0 --- /dev/null +++ b/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/FloodgateHandler.java @@ -0,0 +1,26 @@ +package dev.kejona.geyserblockplatform.common.bedrock; + +import org.geysermc.floodgate.api.FloodgateApi; +import org.geysermc.floodgate.api.player.FloodgatePlayer; + +import java.util.Objects; +import java.util.UUID; + +public class FloodgateHandler implements BedrockHandler { + private final FloodgateApi api = Objects.requireNonNull(FloodgateApi.getInstance(), "floodgate api"); + + @Override + public boolean isBedrockPlayer(UUID uuid) { + return api.isFloodgatePlayer(uuid); + } + + @Override + public Profile profile(UUID uuid) { + FloodgatePlayer player = Objects.requireNonNull(api.getPlayer(uuid), "floodgate player for " + uuid); + return new Profile( + player.getDeviceOs(), + player.getInputMode(), + player.getUiProfile() + ); + } +} diff --git a/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/Profile.java b/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/Profile.java new file mode 100644 index 0000000..cc2ed18 --- /dev/null +++ b/common/src/main/java/dev/kejona/geyserblockplatform/common/bedrock/Profile.java @@ -0,0 +1,19 @@ +package dev.kejona.geyserblockplatform.common.bedrock; + +import lombok.Data; +import lombok.experimental.Accessors; +import org.geysermc.floodgate.util.DeviceOs; +import org.geysermc.floodgate.util.InputMode; +import org.geysermc.floodgate.util.UiProfile; + +/** + * The data here still uses the geyser-common classes because the current Floodgate release doesn't implement the geyser + * base-api yet. Once it does, the classes from the base-api will be used. + */ +@Accessors(fluent = true) +@Data +public class Profile { + private final DeviceOs platform; + private final InputMode inputMode; + private final UiProfile uiProfile; +} diff --git a/common/src/main/java/dev/kejona/geyserblockplatform/common/config/Config.java b/common/src/main/java/dev/kejona/geyserblockplatform/common/config/Config.java new file mode 100644 index 0000000..55ddcc7 --- /dev/null +++ b/common/src/main/java/dev/kejona/geyserblockplatform/common/config/Config.java @@ -0,0 +1,122 @@ +package dev.kejona.geyserblockplatform.common.config; + + +import dev.kejona.geyserblockplatform.common.BlockResult; +import dev.kejona.geyserblockplatform.common.bedrock.BedrockHandler; +import dev.kejona.geyserblockplatform.common.bedrock.Profile; +import org.geysermc.floodgate.util.DeviceOs; +import org.geysermc.floodgate.util.InputMode; +import org.geysermc.floodgate.util.UiProfile; +import org.spongepowered.configurate.NodePath; +import org.spongepowered.configurate.objectmapping.ConfigSerializable; +import org.spongepowered.configurate.objectmapping.meta.Required; +import org.spongepowered.configurate.transformation.ConfigurationTransformation; +import org.spongepowered.configurate.transformation.TransformAction; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@ConfigSerializable +public class Config { + + public static final String FILE = "config.yml"; + public static final String VERSION_KEY = "config-version"; + + private Map platforms = Collections.emptyMap(); + private Map inputs = Collections.emptyMap(); + private Map profiles = Collections.emptyMap(); + + private String platformMessage = "Invalid bedrock platform:§4 %s"; + private String inputMessage = "Invalid input mode:§4 %s"; + private String profileMessage = "Invalid UI profile:§4 %s"; + + public BlockResult computeResult(UUID player, BedrockHandler handler) { + if (!handler.isBedrockPlayer(player)) { + return BlockResult.allowedResult(); + } + Profile data = handler.profile(player); + + List warnings = new ArrayList<>(3); + + Entry platform = platforms.get(data.platform()); + if (platform != null) { + if (platform.allowed) { + if (platform.warningMessage != null) { + warnings.add(platform.warningMessage); + } + } else { + return BlockResult.denied(String.format(platformMessage, data.platform().toString())); + } + } + + Entry input = inputs.get(data.inputMode()); + if (input != null) { + if (input.allowed) { + if (input.warningMessage != null) { + warnings.add(input.warningMessage); + } + } else { + return BlockResult.denied(String.format(inputMessage, data.inputMode().toString())); + } + } + + Entry uiProfile = profiles.get(data.uiProfile()); + if (uiProfile != null) { + if (uiProfile.allowed) { + if (uiProfile.warningMessage != null) { + warnings.add(uiProfile.warningMessage); + } + } else { + return BlockResult.denied(String.format(profileMessage, data.uiProfile().toString())); + } + } + + if (!warnings.isEmpty()) { + return BlockResult.warn(warnings); + } + return BlockResult.allowedResult(); + } + + public static ConfigurationTransformation.Versioned updater() { + return ConfigurationTransformation.versionedBuilder() + .versionKey(VERSION_KEY) + .addVersion(2, update1_2()) + .build(); + } + + private static ConfigurationTransformation update1_2() { + return ConfigurationTransformation.builder() + // other settings + .addAction(NodePath.path("no-access-message"), TransformAction.rename("platform-message")) + .addAction(NodePath.path("deny-server-access"), TransformAction.remove()) + // platforms + .addAction(NodePath.path("unknown-platform-enabled"), movePlatform("UNKNOWN")) + .addAction(NodePath.path("android-enabled"), movePlatform("GOOGLE")) + .addAction(NodePath.path("ios-enabled"), movePlatform("IOS")) + .addAction(NodePath.path("macos-enabled"), movePlatform("OSX")) + .addAction(NodePath.path("gearvr-enabled"), movePlatform("GEARVR")) + .addAction(NodePath.path("windows10-enabled"), movePlatform("UWP")) + .addAction(NodePath.path("ps4-enabled"), movePlatform("PS4")) + .addAction(NodePath.path("switch-enabled"), movePlatform("NX")) + .addAction(NodePath.path("xboxone-enabled"), movePlatform("XBOX")) + .addAction(NodePath.path("windowsphone-enabled"), movePlatform("WINDOWS_PHONE")) + .build(); + } + + private static TransformAction movePlatform(String newName) { + return ((path, value) -> new Object[] {"platforms", newName}); + } + + @ConfigSerializable + public static class Entry { + + @Required + @ScalarParent(mapKey = "allowed") + private boolean allowed = true; + + private String warningMessage = null; + } +} diff --git a/common/src/main/java/dev/kejona/geyserblockplatform/common/config/ConfigLoader.java b/common/src/main/java/dev/kejona/geyserblockplatform/common/config/ConfigLoader.java new file mode 100644 index 0000000..6e70f13 --- /dev/null +++ b/common/src/main/java/dev/kejona/geyserblockplatform/common/config/ConfigLoader.java @@ -0,0 +1,91 @@ +package dev.kejona.geyserblockplatform.common.config; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.objectmapping.ObjectMapper; +import org.spongepowered.configurate.objectmapping.meta.NodeResolver; +import org.spongepowered.configurate.transformation.ConfigurationTransformation; +import org.spongepowered.configurate.yaml.NodeStyle; +import org.spongepowered.configurate.yaml.YamlConfigurationLoader; + +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.function.Consumer; + +public final class ConfigLoader { + + public static Config loadConfig(Path dataDirectory) throws Exception { + return load(dataDirectory.resolve(Config.FILE), Config.class, node -> { + try { + ConfigurationTransformation.Versioned updater = Config.updater(); + + ConfigurationNode version = node.node(updater.versionKey()); + if (version.virtual()) { + version.set(1); // first config didn't have config version - lets pretend it was 1 + } + + updater.apply(node); // update the config + } catch (ConfigurateException e) { + throw new RuntimeException(e); + } + }); + } + + public static T load(Path file, Class configType, Consumer preprocessor) throws Exception { + if (!Files.exists(file)) { + Files.createDirectories(file.getParent()); + String name = file.toFile().getName(); + + try (InputStream input = Config.class.getResourceAsStream("/" + name)) { + Objects.requireNonNull(input, name + " resource"); + Files.copy(input, file); + } + } + + ObjectMapper.Factory mapperFactory = ObjectMapper.factoryBuilder() + .addNodeResolver(nodeFromScalarParent()) + .build(); + + YamlConfigurationLoader loader = YamlConfigurationLoader.builder() + .file(file.toFile()) + .nodeStyle(NodeStyle.BLOCK) + .indent(2) + .defaultOptions(opts -> + opts.implicitInitialization(false) + .shouldCopyDefaults(false) + .serializers(builder -> builder.registerAnnotatedObjects(mapperFactory)) + ) + .build(); + + ConfigurationNode node = loader.load(); + preprocessor.accept(node); + + T config = node.get(configType); + Objects.requireNonNull(config, "deserialized config of type " + configType + " from " + file.toAbsolutePath()); + return config; + } + + /** + * Creates resolvers that get the node at a specified key (like {@link NodeResolver#keyFromSetting()}), + * only if the containing node is a map.
+ * Otherwise, it is assumed that the containing node is a scalar, and it is resolved (like {@link NodeResolver#nodeFromParent()}). + */ + public static NodeResolver.Factory nodeFromScalarParent() { + return (name, element) -> { + final @Nullable ScalarParent scalarParent = element.getAnnotation(ScalarParent.class); + if (scalarParent != null) { + return node -> { + if (node.isMap()) { + // just get the value for this field like normal + return node.node(scalarParent.mapKey()); + } + return node; // try to use the scalar value of the containing node for this field + }; + } + return null; + }; + } +} diff --git a/common/src/main/java/dev/kejona/geyserblockplatform/common/config/ScalarParent.java b/common/src/main/java/dev/kejona/geyserblockplatform/common/config/ScalarParent.java new file mode 100644 index 0000000..4b85652 --- /dev/null +++ b/common/src/main/java/dev/kejona/geyserblockplatform/common/config/ScalarParent.java @@ -0,0 +1,9 @@ +package dev.kejona.geyserblockplatform.common.config; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface ScalarParent { + String mapKey(); +} diff --git a/common/src/main/resources/config.yml b/common/src/main/resources/config.yml index ca27cdf..8d43845 100644 --- a/common/src/main/resources/config.yml +++ b/common/src/main/resources/config.yml @@ -1,22 +1,39 @@ -# Disable or enable platforms. -unknown-platform-enabled: true -android-enabled: true -ios-enabled: true -macos-enabled: true -gearvr-enabled: true -windows10-enabled: true -windowsedu-enabled: true -ps4-enabled: true -switch-enabled: true -xboxone-enabled: true -windowsphone-enabled: true -# Disconnect message to players. -no-access-message: "&6Sorry your platform does not have access to this server!" +# Kick message when the bedrock platform is not allowed +platform-message: "Invalid bedrock platform:§4 %s" +# Kick message when the input mode is not allowed +input-message: "Invalid input mode:§4 %s" +# Kick message when the UI profile is not allowed +profile-message: "Invalid UI profile:§4 %s" -# Proxy options to exclude specified server. -# The "all" option will deny access to the whole network. -deny-server-access: -# - "all" - - "serverhere" +# See https://github.com/GeyserMC/api/blob/master/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java#L31-L45 +# for more descriptive names +platforms: + UNKNOWN: true + GOOGLE: true + IOS: true + OSX: true + AMAZON: true + GEARVR: true + HOLOLENS: true + UWP: true + WIN32: true + DEDICATED: true + TVOS: true + PS4: true + NX: true + XBOX: true + WINDOWS_PHONE: true +# Input mode +inputs: + UNKNOWN: true + KEYBOARD_MOUSE: true + TOUCH: true + CONTROLLER: true + VR: true + +# UI profile +profiles: + CLASSIC: true + POCKET: true diff --git a/extension/build.gradle.kts b/extension/build.gradle.kts new file mode 100644 index 0000000..5b6c7bb --- /dev/null +++ b/extension/build.gradle.kts @@ -0,0 +1,29 @@ + +plugins { + id("com.github.johnrengelman.shadow") +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +dependencies { + api(projects.common) + compileOnly("org.geysermc.geyser:api:2.1.2-SNAPSHOT") +} + +tasks { + shadowJar { + val prefix = "${project.group}.${project.name}.shaded" + relocate("org.spongepowered.configurate", "$prefix.configurate") + relocate("io.leangen.geantyref", "$prefix.geantyref") + + archiveFileName.set("GeyserBlockPlatform-Extension.jar") + } + + build { + dependsOn(shadowJar) + } +} diff --git a/extension/src/main/java/dev/kejona/geyserblockplatform/extension/GeyserBlockPlatformExtension.java b/extension/src/main/java/dev/kejona/geyserblockplatform/extension/GeyserBlockPlatformExtension.java new file mode 100644 index 0000000..117f5c2 --- /dev/null +++ b/extension/src/main/java/dev/kejona/geyserblockplatform/extension/GeyserBlockPlatformExtension.java @@ -0,0 +1,48 @@ +package dev.kejona.geyserblockplatform.extension; + +import dev.kejona.geyserblockplatform.common.BlockResult; +import dev.kejona.geyserblockplatform.common.bedrock.BaseApiHandler; +import dev.kejona.geyserblockplatform.common.bedrock.BedrockHandler; +import dev.kejona.geyserblockplatform.common.config.Config; +import dev.kejona.geyserblockplatform.common.config.ConfigLoader; +import org.geysermc.event.subscribe.Subscribe; +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.event.bedrock.SessionLoginEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent; +import org.geysermc.geyser.api.extension.Extension; + +public class GeyserBlockPlatformExtension implements Extension { + + private BedrockHandler handler; + private Config config; + + @Subscribe + public void onPostInitialize(GeyserPostInitializeEvent event) { + logger().info("Loading GeyserBlockPlatform extension..."); + + this.handler = new BaseApiHandler(); + + try { + this.config = ConfigLoader.loadConfig(this.dataFolder()); + } catch (Exception e) { + logger().severe("Failed to load config"); + e.printStackTrace(); + disable(); + } + + logger().info("Loaded GeyserBlockPlatform extension!"); + } + + @Subscribe + public void onLogin(SessionLoginEvent event) { + GeyserConnection connection = event.connection(); + + BlockResult result = config.computeResult(connection.javaUuid(), handler); + if (!result.allowed()) { + BlockResult.Denied deniedResult = (BlockResult.Denied) result; + event.setCancelled(true, deniedResult.message()); + } else { + result.warnings().forEach(connection::sendMessage); + } + } +} diff --git a/extension/src/main/resources/extension.yml b/extension/src/main/resources/extension.yml new file mode 100644 index 0000000..3ae72d8 --- /dev/null +++ b/extension/src/main/resources/extension.yml @@ -0,0 +1,7 @@ +id: geyserblockplatform +name: GeyserBlockPlatform +version: "${version}" +authors: [onebeastchris, Konicai] + +main: dev.kejona.geyserblockplatform.extension.GeyserBlockPlatformExtension +api: 1.0.0 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..c1962a7 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37aef8d --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..aeb74cb --- /dev/null +++ b/gradlew @@ -0,0 +1,245 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 9cb7c32..0000000 --- a/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - 4.0.0 - - com.github.camotoy.geyserblockplatform - GeyserBlockPlatform - 1.1-SNAPSHOT - - common - spigot - bungeecord - velocity - - pom - - GeyserBlockPlatform - - Prevent Java players from joining your server - - 1.8 - UTF-8 - - - - - spigotmc-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - sonatype - https://oss.sonatype.org/content/groups/public/ - - - opencollab-release-repo - https://repo.opencollab.dev/main/ - - - jitpack.io - https://jitpack.io - - - diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..9d365ac --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,9 @@ +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") + +rootProject.name = "GeyserBlockPlatform" + +include(":common") +include(":extension") +include(":bungeecord") +include(":spigot") +include(":velocity") diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts new file mode 100644 index 0000000..4b70c8f --- /dev/null +++ b/spigot/build.gradle.kts @@ -0,0 +1,27 @@ + +plugins { + id("com.github.johnrengelman.shadow") +} + +dependencies { + api(projects.common) + compileOnly("org.spigotmc:spigot-api:1.13.2-R0.1-SNAPSHOT") +} + +repositories { + maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") +} + +tasks { + shadowJar { + val prefix = "${project.group}.${project.name}.shaded" + relocate("org.spongepowered.configurate", "$prefix.configurate") + relocate("io.leangen.geantyref", "$prefix.geantyref") + + archiveFileName.set("GeyserBlockPlatform-Spigot.jar") + } + + build { + dependsOn(shadowJar) + } +} diff --git a/spigot/pom.xml b/spigot/pom.xml deleted file mode 100644 index cc60633..0000000 --- a/spigot/pom.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - GeyserBlockPlatform - com.github.camotoy.geyserblockplatform - 1.1-SNAPSHOT - - 4.0.0 - - spigot - - - - com.github.camotoy.geyserblockplatform - common - 1.1-SNAPSHOT - compile - - - org.spigotmc - spigot-api - 1.13.2-R0.1-SNAPSHOT - provided - - - org.geysermc.geyser - common - 2.1.1-SNAPSHOT - provided - - - - - GeyserBlockPlatform-Spigot - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - ${java.version} - ${java.version} - - - - org.apache.maven.plugins - maven-shade-plugin - 3.2.4 - - - - com.fasterxml.jackson - com.github.camotoy.geyserblockplatform.relocations.jackson - - - org.yaml.snakeyaml - com.github.camotoy.geyserblockplatform.relocations.snakeyaml - - - - - - package - - shade - - - false - - - - - - - - src/main/resources - true - - - - - - \ No newline at end of file diff --git a/spigot/src/main/java/com/github/camotoy/geyserblockplatform/spigot/GeyserBlockPlatformSpigot.java b/spigot/src/main/java/com/github/camotoy/geyserblockplatform/spigot/GeyserBlockPlatformSpigot.java deleted file mode 100644 index 6d9fce4..0000000 --- a/spigot/src/main/java/com/github/camotoy/geyserblockplatform/spigot/GeyserBlockPlatformSpigot.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.github.camotoy.geyserblockplatform.spigot; - -import com.github.camotoy.geyserblockplatform.common.Permissions; -import com.github.camotoy.geyserblockplatform.common.config.Configurate; -import com.github.camotoy.geyserblockplatform.common.platformchecker.FloodgateBedrockPlatformChecker; -import com.github.camotoy.geyserblockplatform.common.platformchecker.GeyserBedrockPlatformChecker; -import com.github.camotoy.geyserblockplatform.common.platformchecker.BedrockPlatformChecker; -import com.github.camotoy.geyserblockplatform.common.device.SupportedDeviceOSList; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.plugin.java.JavaPlugin; -import org.geysermc.floodgate.util.DeviceOs; - -public final class GeyserBlockPlatformSpigot extends JavaPlugin implements Listener { - private BedrockPlatformChecker platformChecker; - private Configurate config = null; - - @Override - public void onEnable() { - config = Configurate.create(this.getDataFolder().toPath()); - boolean hasFloodgate = Bukkit.getPluginManager().getPlugin("floodgate") != null; - boolean hasGeyser = Bukkit.getPluginManager().getPlugin("Geyser-Spigot") != null; - - if (!hasFloodgate && !hasGeyser) { - getLogger().warning("There is no Geyser or Floodgate plugin detected! Disabling..."); - Bukkit.getPluginManager().disablePlugin(this); - return; - } - - if (hasFloodgate) { - this.platformChecker = new FloodgateBedrockPlatformChecker(); - } else { - this.platformChecker = new GeyserBedrockPlatformChecker(); - } - - Bukkit.getPluginManager().registerEvents(this, this); - } - - @Override - public void onDisable() { - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - if (event.getPlayer().hasPermission(Permissions.bypassPermission)) { - return; - } - // Check if player is a bedrock player - if (platformChecker.isBedrockPlayer(event.getPlayer().getUniqueId())) { - DeviceOs deviceOS = this.platformChecker.getBedrockPlatform(event.getPlayer().getUniqueId()); - - if (deviceOS == null) { - return; - } - - if (!SupportedDeviceOSList.supportedDeviceOSList(config).contains(deviceOS)) { - event.getPlayer().kickPlayer(ChatColor.translateAlternateColorCodes('&', config.getNoAccessMessage())); - } - } - } -} \ No newline at end of file diff --git a/spigot/src/main/java/dev/kejona/geyserblockplatform/spigot/GeyserBlockPlatformSpigot.java b/spigot/src/main/java/dev/kejona/geyserblockplatform/spigot/GeyserBlockPlatformSpigot.java new file mode 100644 index 0000000..cd9fd64 --- /dev/null +++ b/spigot/src/main/java/dev/kejona/geyserblockplatform/spigot/GeyserBlockPlatformSpigot.java @@ -0,0 +1,65 @@ +package dev.kejona.geyserblockplatform.spigot; + +import dev.kejona.geyserblockplatform.common.BlockResult; +import dev.kejona.geyserblockplatform.common.Permissions; +import dev.kejona.geyserblockplatform.common.bedrock.BaseApiHandler; +import dev.kejona.geyserblockplatform.common.bedrock.BedrockHandler; +import dev.kejona.geyserblockplatform.common.bedrock.FloodgateHandler; +import dev.kejona.geyserblockplatform.common.config.Config; +import dev.kejona.geyserblockplatform.common.config.ConfigLoader; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + +public final class GeyserBlockPlatformSpigot extends JavaPlugin implements Listener { + private BedrockHandler handler; + private Config config; + + @Override + public void onEnable() { + PluginManager pluginManager = Bukkit.getPluginManager(); + if (pluginManager.getPlugin("floodgate") != null) { + handler = new FloodgateHandler(); + } else if (pluginManager.getPlugin("Geyser-Spigot") != null) { + handler = new BaseApiHandler(); + } else { + getLogger().warning("There is no Geyser or Floodgate plugin detected! Disabling..."); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + + try { + config = ConfigLoader.loadConfig(getDataFolder().toPath()); + } catch (Exception e) { + getLogger().severe("Failed to load config"); + e.printStackTrace(); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + + Bukkit.getPluginManager().registerEvents(this, this); + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onPlayerLogin(PlayerLoginEvent event) { + Player player = event.getPlayer(); + if (player.hasPermission(Permissions.BYPASS)) { + return; + } + + BlockResult result = config.computeResult(player.getUniqueId(), handler); + + if (!result.allowed()) { + BlockResult.Denied deniedResult = (BlockResult.Denied) result; + event.setResult(PlayerLoginEvent.Result.KICK_OTHER); + event.setKickMessage(deniedResult.message()); + } else { + result.warnings().forEach(player::sendMessage); + } + } +} \ No newline at end of file diff --git a/spigot/src/main/resources/plugin.yml b/spigot/src/main/resources/plugin.yml index 489251e..9744177 100644 --- a/spigot/src/main/resources/plugin.yml +++ b/spigot/src/main/resources/plugin.yml @@ -1,9 +1,12 @@ name: GeyserBlockPlatform -version: ${project.version} -main: com.github.camotoy.geyserblockplatform.spigot.GeyserBlockPlatformSpigot +description: "${description}" +version: "${version}" +authors: [Camotoy, Konicai, Jens] + +main: dev.kejona.geyserblockplatform.spigot.GeyserBlockPlatformSpigot api-version: 1.13 -description: Prevent specific Bedrock platforms from joining your server. softdepend: [floodgate, Geyser-Spigot] + permissions: geyserblockplatform.bypass: description: Give player a bypass for platform checker diff --git a/velocity/.gitignore b/velocity/.gitignore deleted file mode 100644 index 4788b4b..0000000 --- a/velocity/.gitignore +++ /dev/null @@ -1,113 +0,0 @@ -# User-specific stuff -.idea/ - -*.iml -*.ipr -*.iws - -# IntelliJ -out/ - -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -# Windows thumbnail cache files -Thumbs.db -Thumbs.db:encryptable -ehthumbs.db -ehthumbs_vista.db - -# Dump file -*.stackdump - -# Folder config file -[Dd]esktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp - -# Windows shortcuts -*.lnk - -target/ - -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next - -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties -.mvn/wrapper/maven-wrapper.jar -.flattened-pom.xml - -# Common working directory -run/ diff --git a/velocity/build.gradle.kts b/velocity/build.gradle.kts new file mode 100644 index 0000000..506f58b --- /dev/null +++ b/velocity/build.gradle.kts @@ -0,0 +1,34 @@ + +plugins { + id("com.github.johnrengelman.shadow") +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } +} + +dependencies { + api(projects.common) + annotationProcessor("com.velocitypowered:velocity-api:3.1.1") + compileOnly("com.velocitypowered:velocity-api:3.1.1") +} + +repositories { + maven("https://repo.papermc.io/repository/maven-public/") +} + +tasks { + shadowJar { + val prefix = "${project.group}.${project.name}.shaded" + relocate("org.spongepowered.configurate", "$prefix.configurate") + relocate("io.leangen.geantyref", "$prefix.geantyref") + + archiveFileName.set("GeyserBlockPlatform-Velocity.jar") + } + + build { + dependsOn(shadowJar) + } +} diff --git a/velocity/pom.xml b/velocity/pom.xml deleted file mode 100644 index c7cb060..0000000 --- a/velocity/pom.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - GeyserBlockPlatform - com.github.camotoy.geyserblockplatform - 1.1-SNAPSHOT - - 4.0.0 - - velocity - - - GeyserBlockPlatform-Velocity - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - ${java.version} - ${java.version} - - - - org.apache.maven.plugins - maven-shade-plugin - 3.2.4 - - - - com.fasterxml.jackson - com.github.camotoy.geyserblockplatform.relocations.jackson - - - org.yaml.snakeyaml - com.github.camotoy.geyserblockplatform.relocations.snakeyaml - - - - - - package - - shade - - - false - - - - - - - - src/main/resources - true - - - - - - - papermc-repo - https://papermc.io/repo/repository/maven-public/ - - - - - - com.velocitypowered - velocity-api - 3.1.1 - provided - - - org.geysermc.geyser - common - 2.1.1-SNAPSHOT - provided - - - com.github.camotoy.geyserblockplatform - common - 1.1-SNAPSHOT - compile - - - diff --git a/velocity/src/main/java/com/github/camotoy/geyserblockplatform/velocity/GeyserBlockPlatformVelocity.java b/velocity/src/main/java/com/github/camotoy/geyserblockplatform/velocity/GeyserBlockPlatformVelocity.java deleted file mode 100644 index a571803..0000000 --- a/velocity/src/main/java/com/github/camotoy/geyserblockplatform/velocity/GeyserBlockPlatformVelocity.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.github.camotoy.geyserblockplatform.velocity; - -import com.github.camotoy.geyserblockplatform.common.Permissions; -import com.github.camotoy.geyserblockplatform.common.config.Configurate; -import com.github.camotoy.geyserblockplatform.common.device.SupportedDeviceOSList; -import com.github.camotoy.geyserblockplatform.common.platformchecker.BedrockPlatformChecker; -import com.github.camotoy.geyserblockplatform.common.platformchecker.FloodgateBedrockPlatformChecker; -import com.github.camotoy.geyserblockplatform.common.platformchecker.GeyserBedrockPlatformChecker; -import com.google.inject.Inject; -import com.velocitypowered.api.event.PostOrder; -import com.velocitypowered.api.event.player.ServerConnectedEvent; -import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; -import com.velocitypowered.api.event.Subscribe; -import com.velocitypowered.api.plugin.Plugin; -import com.velocitypowered.api.plugin.annotation.DataDirectory; -import com.velocitypowered.api.proxy.ProxyServer; -import net.kyori.adventure.text.TextComponent; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.geysermc.floodgate.util.DeviceOs; -import org.slf4j.Logger; - -import java.nio.file.Path; -import java.util.UUID; - -@Plugin( - id = "geyserblockplatform", - name = "GeyserBlockPlatformVelocity", - version = "1.1-SNAPSHOT" -) -public class GeyserBlockPlatformVelocity { - private final ProxyServer server; - private final Logger logger; - private BedrockPlatformChecker platformChecker; - private Configurate config = null; - private final Path dataDirectory; - private static LegacyComponentSerializer serializer = LegacyComponentSerializer.builder().character('&').hexCharacter('#').hexColors().build(); - - @Inject - public GeyserBlockPlatformVelocity(ProxyServer server, Logger logger, @DataDirectory final Path folder) { - this.server = server; - this.logger = logger; - this.dataDirectory = folder; - } - - @Subscribe - public void onProxyInitialization(ProxyInitializeEvent event) { - config = Configurate.create(dataDirectory); - boolean hasFloodgate = server.getPluginManager().isLoaded("floodgate"); - boolean hasGeyser = server.getPluginManager().isLoaded("Geyser-Velocity"); - - if (!hasFloodgate && !hasGeyser) { - logger.warn("There is no Geyser or Floodgate plugin detected! Disabling..."); - return; - } - - if (hasFloodgate) { - this.platformChecker = new FloodgateBedrockPlatformChecker(); - } else { - this.platformChecker = new GeyserBedrockPlatformChecker(); - } - - } - - @Subscribe(order = PostOrder.FIRST) - public void onPlayerChangeServer(ServerConnectedEvent event) { - if (event.getPlayer().hasPermission(Permissions.bypassPermission)) { - return; - } - // Check if player is a bedrock player - if (platformChecker.isBedrockPlayer(event.getPlayer().getUniqueId())) { - String servername = event.getServer().getServerInfo().getName(); - // First check if the "deny-server-access:" list contains the server name. - if (config.getNoServerAccess().contains(servername) - // Then check if the list contains "all" in case they want full network deny - || config.getNoServerAccess().contains("all")) { - // Check if the client platform isn't blocked - if (!connectionAllowed(event.getPlayer().getUniqueId())) { - // Disconnect player - event.getPlayer().disconnect(color(config.getNoAccessMessage())); - } - } - } - } - - /** - * Checks the supportedDeviceOSList to see if a connection from platform is allowed - * - * @param uuid the players uuid - * @return checks if the players platform is blocked - */ - public boolean connectionAllowed(UUID uuid) { - DeviceOs deviceOS = this.platformChecker.getBedrockPlatform(uuid); - - if (deviceOS == null) { - return false; - } - - return SupportedDeviceOSList.supportedDeviceOSList(config).contains(deviceOS); - } - - public static TextComponent color(String s) { - return serializer.deserialize(s); - } -} diff --git a/velocity/src/main/java/dev/kejona/geyserblockplatform/velocity/GeyserBlockPlatformVelocity.java b/velocity/src/main/java/dev/kejona/geyserblockplatform/velocity/GeyserBlockPlatformVelocity.java new file mode 100644 index 0000000..96ba028 --- /dev/null +++ b/velocity/src/main/java/dev/kejona/geyserblockplatform/velocity/GeyserBlockPlatformVelocity.java @@ -0,0 +1,75 @@ +package dev.kejona.geyserblockplatform.velocity; + +import dev.kejona.geyserblockplatform.common.BlockResult; +import dev.kejona.geyserblockplatform.common.Permissions; +import dev.kejona.geyserblockplatform.common.config.Config; +import dev.kejona.geyserblockplatform.common.config.ConfigLoader; +import dev.kejona.geyserblockplatform.common.bedrock.BedrockHandler; +import dev.kejona.geyserblockplatform.common.bedrock.FloodgateHandler; +import dev.kejona.geyserblockplatform.common.bedrock.BaseApiHandler; +import com.google.inject.Inject; +import com.velocitypowered.api.event.PostOrder; +import com.velocitypowered.api.event.ResultedEvent; +import com.velocitypowered.api.event.connection.LoginEvent; +import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.plugin.Plugin; +import com.velocitypowered.api.plugin.PluginManager; +import com.velocitypowered.api.plugin.annotation.DataDirectory; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ProxyServer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; + +import java.nio.file.Path; + +@Plugin(id = "geyserblockplatform", name = "GeyserBlockPlatformVelocity", version = "2.0-SNAPSHOT") +public class GeyserBlockPlatformVelocity { + + private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacySection(); + + private final ProxyServer server; + private final Path dataDirectory; + + private BedrockHandler handler; + private Config config; + + @Inject + public GeyserBlockPlatformVelocity(ProxyServer server, @DataDirectory Path folder) { + this.server = server; + this.dataDirectory = folder; + } + + @Subscribe + public void onProxyInitialization(ProxyInitializeEvent event) throws Exception { + PluginManager pluginManager = server.getPluginManager(); + if (pluginManager.isLoaded("floodgate")) { + handler = new FloodgateHandler(); + } else if (pluginManager.isLoaded("Geyser-Velocity")) { + handler = new BaseApiHandler(); + } else { + throw new IllegalStateException("There is no Geyser or Floodgate plugin detected!"); + } + + config = ConfigLoader.loadConfig(dataDirectory); + } + + @Subscribe(order = PostOrder.LATE) + public void onLoginEvent(LoginEvent event) { + if (!event.getResult().isAllowed()) { + return; + } + + Player player = event.getPlayer(); + if (player.hasPermission(Permissions.BYPASS)) { + return; + } + + BlockResult result = config.computeResult(player.getUniqueId(), handler); + if (!result.allowed()) { + BlockResult.Denied deniedResult = (BlockResult.Denied) result; + event.setResult(ResultedEvent.ComponentResult.denied(LEGACY_SERIALIZER.deserialize(deniedResult.message()))); + } else { + result.warnings().forEach(warning -> player.sendMessage(LEGACY_SERIALIZER.deserialize(warning))); + } + } +}