From 2bdeb5b0b6219c1695a8f46268dcb5770e714d9a Mon Sep 17 00:00:00 2001 From: Sekwah Date: Sat, 25 Jan 2025 04:36:35 +0000 Subject: [PATCH] feat: add support for legacy spigot 1.8 - 1.12 (#520) --- .github/workflows/release-please.yml | 30 +- .github/workflows/snapshots.yml | 21 +- DragAndDropStarter.bat | 7 - build.gradle | 166 +--- changelog-util.gradle | 2 +- .../desti/ShowDestiSubCommand.java | 7 - .../portal/ShowPortalSubCommand.java | 7 - curse.gradle | 33 +- discord.gradle | 11 +- legacyspigot/build.gradle | 217 +++++ .../legacyspigot/AdvancedPortalsPlugin.java | 138 +++ .../legacyspigot/LegacySpigotInfoLogger.java | 28 + .../legacyspigot/Listeners.java | 217 +++++ .../PermissionsGeneratorSpigot.java | 46 + .../portal/ImportPortalSubCommand.java | 98 +++ .../command/LegacySpigotCommandHandler.java | 35 + .../command/LegacySpigotCommandRegister.java | 28 + .../LegacySpigotCommandSenderContainer.java | 35 + .../LegacySpigotEntityContainer.java | 75 ++ .../LegacySpigotPlayerContainer.java | 141 ++++ .../LegacySpigotServerContainer.java | 167 ++++ .../container/LegacySpigotWorldContainer.java | 55 ++ .../legacyspigot/importer/ConfigAccessor.java | 72 ++ .../legacyspigot/importer/LegacyImporter.java | 210 +++++ .../legacyspigot/metrics/Metrics.java | 787 ++++++++++++++++++ .../legacyspigot/tags/ConditionsTag.java | 176 ++++ .../legacyspigot/utils/ContainerHelpers.java | 18 + .../warpeffects/EnderWarpEffect.java | 64 ++ .../warpeffects/SpigotWarpEffects.java | 13 + legacyspigot/src/main/templates/plugin.yml | 17 + settings.gradle | 1 + spigot/build.gradle | 154 +++- 32 files changed, 2848 insertions(+), 228 deletions(-) delete mode 100644 DragAndDropStarter.bat create mode 100644 legacyspigot/build.gradle create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/AdvancedPortalsPlugin.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/LegacySpigotInfoLogger.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/Listeners.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/PermissionsGeneratorSpigot.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/commands/subcommands/portal/ImportPortalSubCommand.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/command/LegacySpigotCommandHandler.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/command/LegacySpigotCommandRegister.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotCommandSenderContainer.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotEntityContainer.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotPlayerContainer.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotServerContainer.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotWorldContainer.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/importer/ConfigAccessor.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/importer/LegacyImporter.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/metrics/Metrics.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/tags/ConditionsTag.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/utils/ContainerHelpers.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/warpeffects/EnderWarpEffect.java create mode 100644 legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/warpeffects/SpigotWarpEffects.java create mode 100644 legacyspigot/src/main/templates/plugin.yml diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 2fca7dbd..39230076 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -26,7 +26,27 @@ jobs: strategy: fail-fast: false matrix: - release-task: [curseforge, discordupload, modrinth] + include: + # Java 8 for legacyspigot + - project: legacyspigot + java-version: 8 + release-task: curseforge + - project: legacyspigot + java-version: 8 + release-task: discordupload + - project: legacyspigot + java-version: 8 + release-task: modrinth + # Java 16 for spigot + - project: spigot + java-version: 16 + release-task: curseforge + - project: spigot + java-version: 16 + release-task: discordupload + - project: spigot + java-version: 16 + release-task: modrinth needs: release-please runs-on: ubuntu-latest environment: release @@ -39,11 +59,11 @@ jobs: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: ${{ runner.os }}-gradle - - name: Set up JDK 16 + - name: Set up JDK ${{ matrix.java-version }} uses: actions/setup-java@v3 with: - distribution: zulu - java-version: 16 + distribution: temurin + java-version: ${{ matrix.java-version }} - name: Build and publish (release) env: CURSE_API: ${{ secrets.CURSE_API }} @@ -53,4 +73,4 @@ jobs: IS_RELEASE: true run: | # Build - ./gradlew build ${{ matrix.release-task }} + ./gradlew build ${{ matrix.project }}:${{ matrix.release-task }} diff --git a/.github/workflows/snapshots.yml b/.github/workflows/snapshots.yml index d457f352..1b03cc5e 100644 --- a/.github/workflows/snapshots.yml +++ b/.github/workflows/snapshots.yml @@ -6,32 +6,31 @@ on: name: Build jobs: snapshot: - #if: ${{!startsWith(github.ref.split(’/’)[2], 'release-please')}} runs-on: ubuntu-latest - # https://github.com/google-github-actions/release-please-action in case more config is needed + strategy: + matrix: + include: + - project: spigot + java-version: 16 + - project: legacyspigot + java-version: 8 steps: - uses: actions/checkout@v3 - # these if statements ensure that a publication only occurs when - # a new release is created: - name: Cache Gradle packages uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: ${{ runner.os }}-gradle - - name: Set up JDK 16 + - name: Set up JDK ${{ matrix.java-version }} uses: actions/setup-java@v3 with: distribution: temurin - java-version: 16 -# - name: Download MC assets -# run: ./gradlew downloadAssets --info --debug || ./gradlew downloadAssets --info --debug || (sleep 30s && ./gradlew downloadAssets --info --debug) -# - name: Run DataGen -# run: ./gradlew runData + java-version: ${{ matrix.java-version }} - name: Build and upload preview (run for non-release builds) if: ${{ github.ref && !contains( github.ref, 'renovate/deps') }} env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} run: | # Build - ./gradlew build discordupload + ./gradlew ${{ matrix.project }}:discordupload diff --git a/DragAndDropStarter.bat b/DragAndDropStarter.bat deleted file mode 100644 index 7266fce0..00000000 --- a/DragAndDropStarter.bat +++ /dev/null @@ -1,7 +0,0 @@ -REM Use this file for testing cases for different versions, just drag the version you want to test the plugin in and it will start. -@ECHO OFF -:A -java -Xmx4096M -DIReallyKnowWhatIAmDoingISwear=true -jar %1 -REM Could add a 32 bit test part but noone uses 32 bit anymore -GOTO A -PAUSE. diff --git a/build.gradle b/build.gradle index 2b0b89b2..061eda99 100644 --- a/build.gradle +++ b/build.gradle @@ -16,10 +16,7 @@ buildscript { } } - plugins { - id "com.modrinth.minotaur" version "2.+" - id 'dev.s7a.gradle.minecraft.server' version '1.1.0' id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7' } @@ -67,7 +64,6 @@ println("Snapshot Name: ${ext.snapshotName}") println("Github SHA: ${ext.githubSha}") println("Sha Ref: ${ext.shaRef}") -archivesBaseName = "Advanced-Portals" group = 'com.sekwah.advancedportals' println "Version: ${getVersion()}" @@ -85,174 +81,18 @@ repositories { maven { url "https://nexus.velocitypowered.com/repository/maven-public/" } } -// includeLibs just says to include the library in the final jar -dependencies { - includeLibs project(':lang') - includeLibs project(':core') - includeLibs project(':bungee') - includeLibs project(':spigot') - includeLibs project(':velocity') -} +// Needed to find generateTemplates task +evaluationDependsOn(':core') println "Branch ${ext.branch}${ext.shaRef} isRelease: '${ext.isRelease}'" -tasks.named('jar') { - dependsOn(':core:shadowJar') -} - -jar { - // Filters the files out that are in the build folders. Look to see if there is a better way to do this? - from configurations.includeLibs.filter { - it.path.contains("${File.separator}build${File.separator}libs") - } .collect { - println("Will Include: ${it.name}") - it.isDirectory() ? it : zipTree(it) - } - -} - -// This is used to download my plugin for helping reload the server in tandem with the copyPlugin task -tasks.register('downloadSekCDevToolsPlugin') { - doLast { - // Define the URL and destination path - def url = 'https://github.com/sekwah41/SekCDevToolsPlugin/releases/download/v1.0.0/SekCDevToolsPlugin-1.0-SNAPSHOT.jar' - def destinationDir = new File("$buildDir/MinecraftServer/plugins") - def destinationFile = new File(destinationDir, 'SekCDevToolsPlugin-1.0-SNAPSHOT.jar') - - // Create the directory if it doesn't exist - if (!destinationDir.exists()) { - destinationDir.mkdirs() - } - - // Download the file if it doesn't exist - if (!destinationFile.exists()) { - println "Downloading SekCDevToolsPlugin..." - new URL(url).withInputStream { i -> - destinationFile.withOutputStream { - it << i - } - } - } else { - println "SekCDevToolsPlugin already downloaded" - } - } -} - -tasks.launchMinecraftServer.dependsOn(downloadSekCDevToolsPlugin) - -minecraftServerConfig { - jarUrl.set('https://download.getbukkit.org/spigot/spigot-1.20.2.jar') - jvmArgument = ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005", "-DIReallyKnowWhatIAmDoingISwear=true"] -} - -tasks.withType(Jar).configureEach { - duplicatesStrategy = DuplicatesStrategy.WARN -} - -/** - * Will build then copy it to the minecraft server folder for use with the launch task and dev tools plugin - */ -tasks.register('copyPlugin') { - dependsOn(build) - doLast { - copy { - def sourceFilePath = Paths.get("$buildDir/libs/Advanced-Portals-${getVersion()}.jar") - def destinationFilePath = Paths.get("$buildDir/MinecraftServer/plugins/Advanced-Portals.jar") - - println "Handling file: $destinationFilePath" - - byte[] newContent = Files.readAllBytes(sourceFilePath) - - if (Files.exists(destinationFilePath)) { - println "File exists. Overwriting with new binary content." - - Files.write(destinationFilePath, newContent, StandardOpenOption.TRUNCATE_EXISTING) - } else { - println "File does not exist. Copying from source." - - Files.copy(sourceFilePath, destinationFilePath, StandardCopyOption.REPLACE_EXISTING) - } - } - } -} - -// Set SPIGOT_LOC to the location of your server and SPIGOT_JAR as the name of the jar file in the server you want to run -// DIReallyKnowWhatIAmDoingISwear is to remove the stupid pause spigot has at the start -tasks.register('runJar') { - doLast { - javaexec { - main "-jar" - args "${System.env.MC_SERVER_LOC}\\${System.env.MC_SERVER_JAR}.jar" - jvmArgs = ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005", "-DIReallyKnowWhatIAmDoingISwear=true"] - workingDir "${System.env.MC_SERVER_LOC}" - } - } -} - - idea { project { settings { taskTriggers { - afterSync(project(':core').tasks.named('generateTemplates')) + afterSync(project(':core').tasks.named('generateTemplates').get()) } } } } -modrinth { - token = System.getenv("MODRINTH_TOKEN") - projectId = project.modrinth_slug - versionType = "release" - uploadFile = jar - loaders = ["spigot", "bukkit", "paper", "velocity", "waterfall", "bungeecord", "purpur"] - gameVersions = [ - "1.13", - "1.13.1", - "1.13.2", - "1.14", - "1.14.1", - "1.14.2", - "1.14.3", - "1.14.4", - "1.15", - "1.15.1", - "1.15.2", - "1.16", - "1.16.1", - "1.16.2", - "1.16.3", - "1.16.4", - "1.16.5", - "1.17", - "1.17.1", - "1.18", - "1.18.1", - "1.18.2", - "1.19", - "1.19.1", - "1.19.2", - "1.19.3", - "1.19.4", - "1.20", - "1.20.1", - "1.20.2", - "1.20.3", - "1.20.4", - "1.20.5", - "1.20.6", - "1.21", - "1.21.1", - "1.21.2", - "1.21.3", - "1.21.4" - ] - changelog = getReleaseChangelog() - syncBodyFrom = rootProject.file("README.md").text -} - -tasks.modrinth.dependsOn(tasks.modrinthSyncBody) - - -apply from: 'curse.gradle' -apply from: 'discord.gradle' diff --git a/changelog-util.gradle b/changelog-util.gradle index e914fe41..102d96e3 100644 --- a/changelog-util.gradle +++ b/changelog-util.gradle @@ -1,5 +1,5 @@ ext.getReleaseChangelog = { - def changelogFile = file('CHANGELOG.md') + def changelogFile = rootProject.file('CHANGELOG.md') def changelog = "## [${changelogFile.text.split('\n## \\[')[1]}\n\n" // ${project.github}/blob/${branch}/CHANGELOG.md return changelog } diff --git a/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/desti/ShowDestiSubCommand.java b/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/desti/ShowDestiSubCommand.java index 11481d26..ff1ffcb5 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/desti/ShowDestiSubCommand.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/desti/ShowDestiSubCommand.java @@ -47,13 +47,6 @@ public class ShowDestiSubCommand @Override public void onCommand(CommandSenderContainer sender, String[] args) { - if (core.getMcVersion()[1] < 16) { - sender.sendMessage( - Lang.getNegativePrefix() - + Lang.translate("command.portal.show.unsupported")); - return; - } - PlayerData tempData = tempDataServices.getPlayerData(sender.getPlayerContainer()); if (tempData.isDestiVisible()) { diff --git a/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/portal/ShowPortalSubCommand.java b/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/portal/ShowPortalSubCommand.java index 441d26b0..f4c9b58e 100644 --- a/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/portal/ShowPortalSubCommand.java +++ b/core/src/main/java/com/sekwah/advancedportals/core/commands/subcommands/portal/ShowPortalSubCommand.java @@ -60,13 +60,6 @@ public class ShowPortalSubCommand @Override public void onCommand(CommandSenderContainer sender, String[] args) { - if (core.getMcVersion()[1] < 16) { - sender.sendMessage( - Lang.getNegativePrefix() - + Lang.translate("command.portal.show.unsupported")); - return; - } - PlayerData tempData = playerDataServices.getPlayerData(sender.getPlayerContainer()); if (tempData.isPortalVisible()) { diff --git a/curse.gradle b/curse.gradle index bafc2898..0bd8da2c 100644 --- a/curse.gradle +++ b/curse.gradle @@ -21,7 +21,7 @@ buildscript { } } -apply from: 'env-variables.gradle' +apply from: rootProject.file('env-variables.gradle') static String getValueFromCurseAPI(apiKey, endpoint) { String API_BASE_URL = 'https://minecraft.curseforge.com' @@ -108,9 +108,13 @@ class UploadResponse { int id } +ext { + supportedVersions = [] +} // Based on https://github.com/matthewprenger/CurseGradle as it didnt support Bukkit uploads at the time. task curseforge { + group = 'distribute' dependsOn(jar) doLast { String apiKey = System.getenv("CURSE_API") @@ -129,29 +133,10 @@ task curseforge { GameVersion[] gameVersions = gson.fromJson(gameVersionsString, GameVersion[].class) def versions = gameVersions.findAll {it.gameVersionTypeID == gameVersionTypeID} - String[] supportedVersions = [ - "1.21", - "1.20.6", - "1.20.5", - "1.20.4", - "1.20.3", - "1.20.2", - "1.20.1", - "1.20", - "1.19.4", - "1.19.3", - "1.19.2", - "1.19.1", - "1.19", - "1.18.2", - "1.18.1", - "1.18", - "1.17", - "1.16", - "1.15", - "1.14", - "1.13" - ] + if (supportedVersions.isEmpty()) { + println("No supported versions specified. Please set 'supportedVersions' in the applying file.") + return + } def supportedGameVersions = versions.findAll {supportedVersions.contains(it.name)} int[] supportedGameVersionIds = supportedGameVersions.collect {it.id}.toArray() diff --git a/discord.gradle b/discord.gradle index c4412f0d..fc27988b 100644 --- a/discord.gradle +++ b/discord.gradle @@ -15,10 +15,11 @@ buildscript { } } -apply from: 'env-variables.gradle' -apply from: 'changelog-util.gradle' +apply from: rootProject.file('env-variables.gradle') +apply from: rootProject.file('changelog-util.gradle') task discordupload { + group = 'Distribute' dependsOn(jar) doLast { @@ -26,6 +27,12 @@ task discordupload { String discordWebhook = isRelease ? System.getenv("DISCORD_RELEASE_WEBHOOK") : System.getenv("DISCORD_WEBHOOK") if(discordWebhook != null) { + def jarFile = file(jar.archiveFile) + long fileSizeInBytes = jarFile.length() + double fileSizeInMB = fileSizeInBytes / (1024.0 * 1024.0) + + println("Selected file: ${jarFile.name}") + println("File size: ${String.format("%.2f", fileSizeInMB)} MB") CloseableHttpClient httpClient = HttpClients.createDefault() HttpPost uploadFile = new HttpPost(discordWebhook) diff --git a/legacyspigot/build.gradle b/legacyspigot/build.gradle new file mode 100644 index 00000000..ff0f8ee7 --- /dev/null +++ b/legacyspigot/build.gradle @@ -0,0 +1,217 @@ +import java.nio.file.Files +import java.nio.file.Paths +import java.nio.file.StandardCopyOption +import java.nio.file.StandardOpenOption + +plugins { + id "com.modrinth.minotaur" version "2.+" + id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7' +} + +// Check the root build.gradle under allprojects for common settings +configurations { + // configuration that holds jars to copy into lib + includeLibs +} +archivesBaseName = "Advanced-Portals-Legacy-Spigot" + +repositories { + maven { url "https://repo.maven.apache.org/maven2" } + maven { url "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" } + maven { + name = "papermc" + url = uri("https://repo.papermc.io/repository/maven-public/") + } + maven { url 'https://repo.extendedclip.com/releases/'} +} + +// includeLibs just says to include the library in the final jar +dependencies { + implementation project(":core") + runtimeOnly project(path: ':core', configuration: 'shadow') + + // For spigot api + // We are using an older version to try and ensure that we are not using anything new older versions cant use. + compileOnly "org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT" + // compileOnly "com.mojang:authlib:3.5.41" + // Be careful to only use what you need to from paper, otherwise it will become incompatible with spigot. + // compileOnly 'com.destroystokyo.paper:paper-api:1.16.5-R0.1-SNAPSHOT' + + // Soft dependencies + compileOnly 'me.clip:placeholderapi:2.11.6' + + includeLibs project(':lang') + includeLibs project(':core') + includeLibs project(':bungee') + includeLibs project(':velocity') +} + +tasks.named('compileJava') { + dependsOn(':core:shadowJar') +} + +jar { + dependsOn(':bungee:jar', ':lang:jar', ':proxycore:jar', ':velocity:jar') + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + // Filters the files out that are in the build folders. Look to see if there is a better way to do this? + from configurations.includeLibs.filter { + it.path.contains("${File.separator}build${File.separator}libs") + } .collect { + println("Will Include: ${it.name}") + it.isDirectory() ? it : zipTree(it) + } +} + +/** + * Will build then copy it to the minecraft server folder for use with the launch task and dev tools plugin + */ +tasks.register('copyPlugin') { + dependsOn(build) + doLast { + copy { + def sourceFilePath = Paths.get("$buildDir/libs/Advanced-Portals-Legacy-Spigot-${getVersion()}.jar") + def destinationFilePath = Paths.get("$buildDir/MinecraftServer/plugins/Advanced-Portals-Legacy-Spigot.jar") + + println "Handling file: $destinationFilePath" + + byte[] newContent = Files.readAllBytes(sourceFilePath) + + if (Files.exists(destinationFilePath)) { + println "File exists. Overwriting with new binary content." + + Files.write(destinationFilePath, newContent, StandardOpenOption.TRUNCATE_EXISTING) + } else { + println "File does not exist. Copying from source." + + Files.copy(sourceFilePath, destinationFilePath, StandardCopyOption.REPLACE_EXISTING) + } + } + } +} + +// Code for generating extra data in plugins.yml +// This may be able to be simplified drastically, though the goal is to get this working for now +// as it has gone through a few iterations. +sourceSets { + permissionsGen { + java { + srcDirs = ['src/main/java'] + } + } +} + +configurations { + permissionsGenCompileClasspath.extendsFrom compileClasspath +} + +def compilePermissionsGen = tasks.register('compilePermissionsGen', JavaCompile) { + source = sourceSets.permissionsGen.allJava + classpath = configurations.permissionsGenCompileClasspath + destinationDirectory = file("$buildDir/classes/permissionsGen") +} + +def templateSource = file('src/main/templates') +def templateDest = layout.buildDirectory.dir('generated/resources/templates') + +def generatePermissionsYaml = tasks.register('generatePermissionsYaml') { + dependsOn compilePermissionsGen + + doLast { + println "Generating permissions.yml file" + + def classFiles = [] + classFiles.addAll(files("$buildDir/classes/permissionsGen", sourceSets.permissionsGen.runtimeClasspath) + .collect { it.toURI().toURL() }) + + classFiles.addAll(project(':core').sourceSets.main.output.classesDirs + .collect { it.toURI().toURL() }) + + def urls = classFiles.toArray(new URL[0]) + + def parentClassLoader = Thread.currentThread().contextClassLoader + def classLoader = new URLClassLoader(urls, parentClassLoader) + + def permissionsGeneratorClass = classLoader.loadClass('com.sekwah.advancedportals.legacyspigot.PermissionsGeneratorSpigot') + def getPermissionsMethod = permissionsGeneratorClass.getMethod('getPermissions') + def permissionsYaml = getPermissionsMethod.invoke(null) + + def permissionsFile = file("$buildDir/generated/resources/permissions.yml") + permissionsFile.parentFile.mkdirs() + permissionsFile.text = permissionsYaml + + println "Permissions YAML generated at: $permissionsFile" + } +} + +def generateTemplates = tasks.register('generateTemplates', Copy) { task -> + dependsOn generatePermissionsYaml + + def props = [ + 'permissions': { -> file("$buildDir/generated/resources/permissions.yml").text }, + 'pluginVersion': { -> project.version } + ] + + task.inputs.properties(props) + task.from(templateSource) + task.into(templateDest) + task.expand(props) + + doFirst { + println "Running generateTemplates task" + } +} + +generateTemplates.configure { + outputs.upToDateWhen { false } +} + +sourceSets.main.resources.srcDir(generateTemplates.map { it.outputs }) + + +apply from: '../curse.gradle' + +supportedVersions = [ + "1.8", + "1.8.1", + "1.8.2", + "1.8.3", + "1.8.4", + "1.8.5", + "1.8.6", + "1.8.7", + "1.8.8", + "1.8.9", + "1.9", + "1.9.1", + "1.9.2", + "1.9.3", + "1.9.4", + "1.10", + "1.10.1", + "1.10.2", + "1.11", + "1.11.1", + "1.11.2", + "1.12", + "1.12.1", + "1.12.2", +] + +modrinth { + token = System.getenv("MODRINTH_TOKEN") + projectId = project.modrinth_slug + versionType = "release" + uploadFile = jar + loaders = ["spigot", "bukkit", "paper", "velocity", "waterfall", "bungeecord", "purpur"] + gameVersions = supportedVersions + changelog = getReleaseChangelog() + versionName = "Legacy Spigot [MC 1.8.8 - 1.12.2]" + getVersion() + versionNumber = getVersion() + "-LegacySpigot" + syncBodyFrom = rootProject.file("README.md").text +} + +tasks.modrinth.group = "distribute" + +apply from: '../discord.gradle' + diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/AdvancedPortalsPlugin.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/AdvancedPortalsPlugin.java new file mode 100644 index 00000000..33cb62b1 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/AdvancedPortalsPlugin.java @@ -0,0 +1,138 @@ +package com.sekwah.advancedportals.legacyspigot; + +import com.sekwah.advancedportals.core.AdvancedPortalsCore; +import com.sekwah.advancedportals.core.connector.commands.CommandRegister; +import com.sekwah.advancedportals.core.module.AdvancedPortalsModule; +import com.sekwah.advancedportals.core.permissions.Permissions; +import com.sekwah.advancedportals.core.repository.ConfigRepository; +import com.sekwah.advancedportals.core.services.DestinationServices; +import com.sekwah.advancedportals.core.services.PortalServices; +import com.sekwah.advancedportals.core.util.GameScheduler; +import com.sekwah.advancedportals.shadowed.inject.Inject; +import com.sekwah.advancedportals.shadowed.inject.Injector; +import org.bukkit.plugin.java.JavaPlugin; + +import com.sekwah.advancedportals.legacyspigot.commands.subcommands.portal.ImportPortalSubCommand; +import com.sekwah.advancedportals.legacyspigot.connector.command.LegacySpigotCommandRegister; +import com.sekwah.advancedportals.legacyspigot.connector.container.LegacySpigotServerContainer; +import com.sekwah.advancedportals.legacyspigot.importer.LegacyImporter; +import com.sekwah.advancedportals.legacyspigot.metrics.Metrics; +import com.sekwah.advancedportals.legacyspigot.tags.ConditionsTag; +import com.sekwah.advancedportals.legacyspigot.warpeffects.SpigotWarpEffects; +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class AdvancedPortalsPlugin extends JavaPlugin { + private AdvancedPortalsCore portalsCore; + + @Inject + DestinationServices destinationServices; + + @Inject + PortalServices portalServices; + + @Inject + ConfigRepository configRepo; + + private static AdvancedPortalsPlugin instance; + + public static AdvancedPortalsPlugin getInstance() { + return instance; + } + + public AdvancedPortalsPlugin() { + instance = this; + } + + @Override + public void onEnable() { + new Metrics(this); + + Permissions.hasPermissionManager = true; + + String mcVersion = this.getServer().getVersion(); + Pattern pattern = Pattern.compile("\\(MC: ([\\d.]+)\\)"); + Matcher matcher = pattern.matcher(mcVersion); + LegacySpigotServerContainer serverContainer = + new LegacySpigotServerContainer(this.getServer()); + this.portalsCore = new AdvancedPortalsCore( + matcher.find() ? matcher.group(1) : "0.0.0", this.getDataFolder(), + new LegacySpigotInfoLogger(this), serverContainer); + AdvancedPortalsModule module = this.portalsCore.getModule(); + + module.addInstanceBinding(CommandRegister.class, + new LegacySpigotCommandRegister(this)); + + Injector injector = module.getInjector(); + + injector.injectMembers(this); + injector.injectMembers(this.portalsCore); + injector.injectMembers(serverContainer); + + Listeners listeners = injector.getInstance(Listeners.class); + injector.injectMembers(listeners); + this.getServer().getPluginManager().registerEvents(listeners, this); + + GameScheduler scheduler = injector.getInstance(GameScheduler.class); + this.getServer().getScheduler().scheduleSyncRepeatingTask( + this, scheduler::tick, 1, 1); + + SpigotWarpEffects warpEffects = new SpigotWarpEffects(); + injector.injectMembers(warpEffects); + warpEffects.registerEffects(); + + // Try to do this after setting up everything that would need to be + // injected to. + this.portalsCore.onEnable(); + + this.portalsCore.registerPortalCommand("import", + new ImportPortalSubCommand()); + + checkAndCreateConfig(); + registerPlaceholderAPI(); + } + + private void checkAndCreateConfig() { + if (!this.getDataFolder().exists()) { + this.getDataFolder().mkdirs(); + } + + File destiFile = new File(this.getDataFolder(), "destinations.yml"); + File destiFolder = new File(this.getDataFolder(), "desti"); + if (destiFile.exists() && !destiFolder.exists()) { + destiFolder.mkdirs(); + getLogger().info( + "Importing old destinations from destinations.yml"); + LegacyImporter.importDestinations(this.destinationServices); + } + + File portalFile = new File(this.getDataFolder(), "portals.yml"); + File portalFolder = new File(this.getDataFolder(), "portals"); + if (portalFile.exists() && !portalFolder.exists()) { + portalFolder.mkdirs(); + getLogger().info("Importing old portals from portals.yml"); + LegacyImporter.importPortals(this.portalServices); + } + + // Check if config.yml exists and config.yaml doesnt exist + File configFile = new File(this.getDataFolder(), "config.yml"); + File configYamlFile = new File(this.getDataFolder(), "config.yaml"); + if (configFile.exists() && !configYamlFile.exists()) { + LegacyImporter.importConfig(this.configRepo); + } + } + + @Override + public void onDisable() { + this.portalsCore.onDisable(); + } + + public void registerPlaceholderAPI() { + if (this.getServer().getPluginManager().getPlugin("PlaceholderAPI") + != null) { + AdvancedPortalsCore.getInstance().getTagRegistry().registerTag( + new ConditionsTag()); + } + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/LegacySpigotInfoLogger.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/LegacySpigotInfoLogger.java new file mode 100644 index 00000000..5be93e81 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/LegacySpigotInfoLogger.java @@ -0,0 +1,28 @@ +package com.sekwah.advancedportals.legacyspigot; + +import com.sekwah.advancedportals.core.util.InfoLogger; + +import java.util.logging.Level; + +public class LegacySpigotInfoLogger extends InfoLogger { + private final AdvancedPortalsPlugin plugin; + + public LegacySpigotInfoLogger(AdvancedPortalsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void warning(String s) { + plugin.getLogger().warning(s); + } + + @Override + public void info(String s) { + plugin.getLogger().info(s); + } + + @Override + public void error(Exception e) { + plugin.getLogger().log(Level.SEVERE, e.getMessage(), e); + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/Listeners.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/Listeners.java new file mode 100644 index 00000000..e2301ff2 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/Listeners.java @@ -0,0 +1,217 @@ +package com.sekwah.advancedportals.legacyspigot; + +import com.sekwah.advancedportals.core.CoreListeners; +import com.sekwah.advancedportals.core.repository.ConfigRepository; +import com.sekwah.advancedportals.core.serializeddata.BlockLocation; +import com.sekwah.advancedportals.core.services.PortalServices; +import com.sekwah.advancedportals.legacyspigot.connector.container.LegacySpigotEntityContainer; +import com.sekwah.advancedportals.shadowed.inject.Inject; +import com.sekwah.advancedportals.legacyspigot.connector.container.LegacySpigotPlayerContainer; +import com.sekwah.advancedportals.legacyspigot.utils.ContainerHelpers; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.*; +import org.bukkit.event.entity.*; +import org.bukkit.event.player.*; +import org.bukkit.inventory.ItemStack; +import java.util.List; + +/** + * Some of these will be passed to the core listener to handle the events, + * others it's easier to just check directly. + */ +public class Listeners implements Listener { + @Inject + private CoreListeners coreListeners; + + @Inject + private PortalServices portalServices; + + @Inject + private ConfigRepository configRepository; + + // Entity and portal events + @EventHandler + public void onJoinEvent(PlayerJoinEvent event) { + coreListeners.playerJoin(new LegacySpigotPlayerContainer(event.getPlayer())); + } + + @EventHandler + public void onPlayerQuitEvent(PlayerQuitEvent event) { + coreListeners.playerLeave(new LegacySpigotPlayerContainer(event.getPlayer())); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onMoveEvent(PlayerMoveEvent event) { + Location to = event.getTo(); + coreListeners.playerMove(new LegacySpigotPlayerContainer(event.getPlayer()), + ContainerHelpers.toPlayerLocation(to)); + } + + @EventHandler(ignoreCancelled = true) + public void onEntityPortalEvent(EntityPortalEvent event) { + if (!this.coreListeners.entityPortalEvent( + new LegacySpigotEntityContainer(event.getEntity()))) { + event.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true) + public void onPortalEvent(PlayerPortalEvent event) { + if (!this.coreListeners.playerPortalEvent( + new LegacySpigotPlayerContainer(event.getPlayer()), + ContainerHelpers.toPlayerLocation(event.getFrom()))) { + event.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true) + public void onDamEvent(EntityDamageEvent event) { + if (event.getEntity() instanceof Player + && (event.getCause() == EntityDamageEvent.DamageCause.LAVA + || event.getCause() == EntityDamageEvent.DamageCause.FIRE + || event.getCause() + == EntityDamageEvent.DamageCause.FIRE_TICK)) { + if (this.coreListeners.preventEntityCombust( + new LegacySpigotEntityContainer(event.getEntity()))) { + event.setCancelled(true); + } + } + } + + @EventHandler(ignoreCancelled = true) + public void onCombustEntityEvent(EntityCombustEvent event) { + if (this.coreListeners.preventEntityCombust( + new LegacySpigotEntityContainer(event.getEntity()))) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void onBlockPlace(BlockPlaceEvent event) { + if (!event.isCancelled()) { + Location blockloc = event.getBlock().getLocation(); + if (!this.coreListeners.blockPlace( + new LegacySpigotPlayerContainer(event.getPlayer()), + new BlockLocation( + blockloc.getWorld().getName(), blockloc.getBlockX(), + blockloc.getBlockY(), blockloc.getBlockZ()), + event.getBlockPlaced().getType().toString(), + event.getItemInHand().getType().toString(), + event.getItemInHand().getItemMeta().getDisplayName())) { + event.setCancelled(true); + } + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void onPhysicsEvent(BlockPhysicsEvent event) { + if (!coreListeners.physicsEvent( + ContainerHelpers.toBlockLocation( + event.getBlock().getLocation()), + event.getBlock().getType().toString())) { + event.setCancelled(true); + } + } + + @EventHandler + public void onWorldChangeEvent(PlayerChangedWorldEvent event) { + coreListeners.worldChange(new LegacySpigotPlayerContainer(event.getPlayer())); + } + + @EventHandler + public void onItemInteract(PlayerInteractEvent event) { + if (!event.isCancelled() + && (event.getAction() == Action.LEFT_CLICK_BLOCK + || event.getAction() == Action.RIGHT_CLICK_BLOCK) + && event.getItem() != null) { + if (event.getClickedBlock() == null) + return; + if (event.getItem().getItemMeta() == null) + return; + + Location blockloc = event.getClickedBlock().getLocation(); + + if (blockloc.getWorld() == null) + return; + + boolean allowEvent = this.coreListeners.playerInteractWithBlock( + new LegacySpigotPlayerContainer(event.getPlayer()), + event.getClickedBlock().getType().toString(), + event.getMaterial().toString(), + event.getItem().getItemMeta().getDisplayName(), + new BlockLocation(blockloc.getWorld().getName(), + blockloc.getBlockX(), blockloc.getBlockY(), + blockloc.getBlockZ()), + event.getAction() == Action.LEFT_CLICK_BLOCK); + event.setCancelled(!allowEvent); + } + } + + @EventHandler(ignoreCancelled = true) + public void spawnMobEvent(CreatureSpawnEvent event) { + if (event.getSpawnReason() + == CreatureSpawnEvent.SpawnReason.NETHER_PORTAL + && portalServices.inPortalRegionProtected( + ContainerHelpers.toPlayerLocation(event.getLocation()))) { + event.setCancelled(true); + } + } + + // Block events + + @EventHandler(priority = EventPriority.HIGH) + public void onBlockFromTo(BlockFromToEvent event) { + if (!configRepository.getStopWaterFlow()) { + return; + } + if (!coreListeners.blockPlace(null, + ContainerHelpers.toBlockLocation( + event.getBlock().getLocation()), + event.getBlock().getType().toString(), + null, null) + || !coreListeners.blockPlace(null, + ContainerHelpers.toBlockLocation( + event.getToBlock().getLocation()), + event.getBlock().getType().toString(), + null, null)) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void onBlockBreak(BlockBreakEvent event) { + ItemStack itemInHand = event.getPlayer().getItemInHand(); + if (!coreListeners.blockBreak( + new LegacySpigotPlayerContainer(event.getPlayer()), + ContainerHelpers.toBlockLocation( + event.getBlock().getLocation()), + event.getBlock().getType().toString(), + itemInHand == null ? null : itemInHand.getType().toString(), + itemInHand == null || itemInHand.getItemMeta() == null + ? null + : itemInHand.getItemMeta().getDisplayName())) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void onExplosion(EntityExplodeEvent event) { + if (!configRepository.getPortalProtection()) + return; + + List blockList = event.blockList(); + for (int i = 0; i < blockList.size(); i++) { + Block block = blockList.get(i); + if (portalServices.inPortalRegionProtected( + ContainerHelpers.toBlockLocation(block.getLocation()))) { + blockList.remove(i); + i--; + } + } + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/PermissionsGeneratorSpigot.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/PermissionsGeneratorSpigot.java new file mode 100644 index 00000000..b0aef5c3 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/PermissionsGeneratorSpigot.java @@ -0,0 +1,46 @@ +package com.sekwah.advancedportals.legacyspigot; + +import com.sekwah.advancedportals.core.permissions.PermissionBuilder; +import com.sekwah.advancedportals.core.permissions.Permissions; + +import java.util.List; + +public class PermissionsGeneratorSpigot { + private PermissionsGeneratorSpigot() { + } + + public static String getPermissions() { + return toPermBlock(Permissions.ROOT); + } + + public static String toPermBlock(PermissionBuilder permission) { + StringBuilder builder = new StringBuilder(); + builder.append("\n"); + String indent = " "; + if (!permission.isDoNotExport()) { + builder.append(indent).append(permission).append(":\n"); + builder.append(indent).append(indent).append("default: "); + builder.append( + permission.getPermissionDefault().toString().toLowerCase()); + builder.append("\n"); + if (permission.getDescription() != null) { + builder.append(indent).append(indent).append("description: "); + builder.append(permission.getDescription()).append("\n"); + } + List children = permission.getGrantChildren(); + if (!children.isEmpty()) { + builder.append(indent).append(indent).append("children:\n"); + for (PermissionBuilder child : children) { + builder.append(indent).append(indent).append(indent); + builder.append(child.toString()) + .append(": true") + .append("\n"); + } + } + } + for (PermissionBuilder child : permission.getChildren()) { + builder.append(toPermBlock(child)); + } + return builder.toString(); + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/commands/subcommands/portal/ImportPortalSubCommand.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/commands/subcommands/portal/ImportPortalSubCommand.java new file mode 100644 index 00000000..dce6832a --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/commands/subcommands/portal/ImportPortalSubCommand.java @@ -0,0 +1,98 @@ +package com.sekwah.advancedportals.legacyspigot.commands.subcommands.portal; + +import com.sekwah.advancedportals.core.AdvancedPortalsCore; +import com.sekwah.advancedportals.core.commands.SubCommand; +import com.sekwah.advancedportals.core.connector.containers.CommandSenderContainer; +import com.sekwah.advancedportals.core.permissions.Permissions; +import com.sekwah.advancedportals.core.repository.ConfigRepository; +import com.sekwah.advancedportals.core.services.DestinationServices; +import com.sekwah.advancedportals.core.services.PortalServices; +import com.sekwah.advancedportals.core.util.Lang; +import com.sekwah.advancedportals.legacyspigot.AdvancedPortalsPlugin; +import com.sekwah.advancedportals.legacyspigot.importer.ConfigAccessor; +import com.sekwah.advancedportals.legacyspigot.importer.LegacyImporter; +import com.sekwah.advancedportals.shadowed.inject.Inject; +import org.bukkit.configuration.file.FileConfiguration; + +import java.util.List; +import java.util.Set; + +public class ImportPortalSubCommand implements SubCommand { + @Inject + private AdvancedPortalsCore portalsCore; + + @Inject + DestinationServices destinationServices; + + @Inject + PortalServices portalServices; + + @Inject + ConfigRepository configRepo; + + @Override + public void onCommand(CommandSenderContainer sender, String[] args) { + if (args.length > 1 && "confirm".equals(args[1])) { + sender.sendMessage(Lang.getPositivePrefix() + + Lang.translateInsertVariables( + "command.portal.import.confirm")); + int destinations = + LegacyImporter.importDestinations(destinationServices); + int portals = LegacyImporter.importPortals(portalServices); + LegacyImporter.importConfig(this.configRepo); + + portalsCore.loadPortalConfig(); + portalServices.loadPortals(); + destinationServices.loadDestinations(); + + sender.sendMessage( + Lang.getPositivePrefix() + + Lang.translateInsertVariables( + "command.portal.import.complete", portals, destinations)); + return; + } + sender.sendMessage(Lang.getPositivePrefix() + + Lang.translateInsertVariables( + "command.portal.import", getPortalCount(), + getDestinationCount())); + } + + public int getDestinationCount() { + ConfigAccessor destiConfig = new ConfigAccessor( + AdvancedPortalsPlugin.getInstance(), "destinations.yaml"); + FileConfiguration config = destiConfig.getConfig(); + Set destiSet = config.getKeys(false); + + return destiSet.size(); + } + + public int getPortalCount() { + ConfigAccessor portalConfig = new ConfigAccessor( + AdvancedPortalsPlugin.getInstance(), "portals.yaml"); + FileConfiguration config = portalConfig.getConfig(); + Set portalSet = config.getKeys(false); + + return portalSet.size(); + } + + @Override + public boolean hasPermission(CommandSenderContainer sender) { + return Permissions.IMPORT.hasPermission(sender); + } + + @Override + public List onTabComplete(CommandSenderContainer sender, + String[] args) { + return null; + } + + @Override + public String getBasicHelpText() { + return Lang.translate("command.portal.import.help"); + } + + @Override + public String getDetailedHelpText() { + return Lang.translate("command.portal.import.detailedhelp"); + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/command/LegacySpigotCommandHandler.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/command/LegacySpigotCommandHandler.java new file mode 100644 index 00000000..305c7fde --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/command/LegacySpigotCommandHandler.java @@ -0,0 +1,35 @@ +package com.sekwah.advancedportals.legacyspigot.connector.command; + +import com.sekwah.advancedportals.core.commands.CommandTemplate; +import com.sekwah.advancedportals.legacyspigot.connector.container.LegacySpigotCommandSenderContainer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; + +import java.util.List; + +public class LegacySpigotCommandHandler implements CommandExecutor, TabCompleter { + private final CommandTemplate commandExecutor; + + public LegacySpigotCommandHandler(CommandTemplate commandExecutor) { + this.commandExecutor = commandExecutor; + } + + @Override + public boolean onCommand(CommandSender commandSender, Command command, + String s, String[] args) { + this.commandExecutor.onCommand( + new LegacySpigotCommandSenderContainer(commandSender), command.getName(), + args); + return true; + } + + @Override + public List onTabComplete(CommandSender commandSender, + Command command, String s, + String[] args) { + return this.commandExecutor.onTabComplete( + new LegacySpigotCommandSenderContainer(commandSender), args); + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/command/LegacySpigotCommandRegister.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/command/LegacySpigotCommandRegister.java new file mode 100644 index 00000000..aeb167de --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/command/LegacySpigotCommandRegister.java @@ -0,0 +1,28 @@ +package com.sekwah.advancedportals.legacyspigot.connector.command; + +import com.sekwah.advancedportals.core.commands.CommandTemplate; +import com.sekwah.advancedportals.core.connector.commands.CommandRegister; +import com.sekwah.advancedportals.legacyspigot.AdvancedPortalsPlugin; + +/** + * Register the CommandTemplate files to the appropriate system + */ +public class LegacySpigotCommandRegister implements CommandRegister { + private final AdvancedPortalsPlugin plugin; + + public LegacySpigotCommandRegister(AdvancedPortalsPlugin plugin) { + this.plugin = plugin; + } + + /** + * Registers the command to the appropriate system + * + * @param commandName + * @param commandExecutor + */ + public void registerCommand(String commandName, + CommandTemplate commandExecutor) { + this.plugin.getCommand(commandName) + .setExecutor(new LegacySpigotCommandHandler(commandExecutor)); + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotCommandSenderContainer.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotCommandSenderContainer.java new file mode 100644 index 00000000..28892ca0 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotCommandSenderContainer.java @@ -0,0 +1,35 @@ +package com.sekwah.advancedportals.legacyspigot.connector.container; + +import com.sekwah.advancedportals.core.connector.containers.CommandSenderContainer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class LegacySpigotCommandSenderContainer implements CommandSenderContainer { + private final CommandSender sender; + + public LegacySpigotCommandSenderContainer(CommandSender commandSender) { + this.sender = commandSender; + } + + public void sendMessage(String message) { + sender.sendMessage(message); + } + + public boolean isOp() { + return sender.isOp(); + } + + /** + * @return null if there isnt a player e.g. the console + */ + public LegacySpigotPlayerContainer getPlayerContainer() { + if (sender instanceof Player) { + return new LegacySpigotPlayerContainer((Player) sender); + } + return null; + } + + public boolean hasPermission(String permission) { + return sender.hasPermission(permission); + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotEntityContainer.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotEntityContainer.java new file mode 100644 index 00000000..48398a31 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotEntityContainer.java @@ -0,0 +1,75 @@ +package com.sekwah.advancedportals.legacyspigot.connector.container; + +import com.sekwah.advancedportals.core.AdvancedPortalsCore; +import com.sekwah.advancedportals.core.connector.containers.EntityContainer; +import com.sekwah.advancedportals.core.connector.containers.WorldContainer; +import com.sekwah.advancedportals.core.serializeddata.BlockLocation; +import com.sekwah.advancedportals.core.serializeddata.PlayerLocation; +import com.sekwah.advancedportals.core.serializeddata.Vector; +import com.sekwah.advancedportals.shadowed.inject.Inject; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; + +/** + * Just a temporary container for whenever advanced portals needs to get data + * from a player + */ +public class LegacySpigotEntityContainer implements EntityContainer { + @Inject + private AdvancedPortalsCore portalsCore; + + private final Entity entity; + + public LegacySpigotEntityContainer(Entity entity) { + this.entity = entity; + } + + @Override + public PlayerLocation getLoc() { + Location loc = this.entity.getLocation(); + return new PlayerLocation(loc.getWorld().getName(), loc.getX(), + loc.getY(), loc.getZ(), loc.getYaw(), + loc.getPitch()); + } + + @Override + public BlockLocation getBlockLoc() { + Location loc = this.entity.getLocation(); + return new BlockLocation(loc.getWorld().getName(), loc.getBlockX(), + loc.getBlockY(), loc.getBlockZ()); + } + + @Override + public double getHeight() { + return 1.5; + } + + @Override + public boolean teleport(PlayerLocation location) { + return this.entity.teleport(new Location( + Bukkit.getWorld(location.getWorldName()), location.getPosX(), + location.getPosY(), location.getPosZ())); + } + + @Override + public WorldContainer getWorld() { + return new LegacySpigotWorldContainer(this.entity.getWorld()); + } + + @Override + public String getName() { + return this.entity.getName(); + } + + @Override + public String getWorldName() { + return this.entity.getWorld().getName(); + } + + @Override + public void setVelocity(Vector vector) { + this.entity.setVelocity(new org.bukkit.util.Vector( + vector.getX(), vector.getY(), vector.getZ())); + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotPlayerContainer.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotPlayerContainer.java new file mode 100644 index 00000000..8f1ec907 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotPlayerContainer.java @@ -0,0 +1,141 @@ +package com.sekwah.advancedportals.legacyspigot.connector.container; + +import com.sekwah.advancedportals.core.AdvancedPortalsCore; +import com.sekwah.advancedportals.core.connector.containers.GameMode; +import com.sekwah.advancedportals.core.connector.containers.PlayerContainer; +import com.sekwah.advancedportals.core.connector.containers.ServerContainer; +import com.sekwah.advancedportals.core.serializeddata.PlayerLocation; +import com.sekwah.advancedportals.core.serializeddata.Vector; +import com.sekwah.advancedportals.shadowed.inject.Inject; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Bukkit; +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.awt.*; +import com.sekwah.advancedportals.legacyspigot.AdvancedPortalsPlugin; +import java.util.Arrays; +import java.util.UUID; + +/** + * Just a temporary container for whenever advanced portals needs to get data + * from a player + */ +public class LegacySpigotPlayerContainer + extends LegacySpigotEntityContainer implements PlayerContainer { + @Inject + private AdvancedPortalsCore portalsCore; + + private final Player player; + + public LegacySpigotPlayerContainer(Player player) { + super(player); + this.player = player; + } + + @Override + public UUID getUUID() { + return player.getUniqueId(); + } + + @Override + public void sendMessage(String message) { + player.sendMessage(message); + } + + @Override + public void sendActionBar(String message) { + try { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); + } catch (NoSuchMethodError e) { + player.sendMessage(message); + } + } + + @Override + public boolean isOp() { + return this.player.isOp(); + } + + @Override + public boolean teleport(PlayerLocation location) { + return this.player.teleport(new Location( + Bukkit.getWorld(location.getWorldName()), location.getPosX(), + location.getPosY(), location.getPosZ(), location.getYaw(), + location.getPitch())); + } + + @Override + public boolean hasPermission(String permission) { + return this.player.hasPermission(permission); + } + + @Override + public void giveItem(String material, String itemName, + String... itemDescription) { + ItemStack regionselector = + new ItemStack(Material.getMaterial(material)); + ItemMeta selectorname = regionselector.getItemMeta(); + selectorname.setDisplayName(itemName); + selectorname.setLore(Arrays.asList(itemDescription)); + regionselector.setItemMeta(selectorname); + this.player.getInventory().addItem(regionselector); + } + + @Override + public boolean sendPacket(String channel, byte[] bytes) { + player.sendPluginMessage(AdvancedPortalsPlugin.getInstance(), channel, + bytes); + return true; + } + + @Override + public GameMode getGameMode() { + try { + return GameMode.valueOf(this.player.getGameMode().name()); + } catch (IllegalArgumentException e) { + return GameMode.SURVIVAL; + } + } + + public Player getPlayer() { + return this.player; + } + + @Override + public void playSound(String sound, float volume, float pitch) { + this.player.playSound(this.player.getLocation(), sound, volume, pitch); + } + + @Override + public ServerContainer getServer() { + return new LegacySpigotServerContainer(this.player.getServer()); + } + + @Override + public void spawnColoredDust(Vector position, double xSpread, + double ySpread, double zSpread, int count, + Color color) { + // Check distance to player + if (this.player.getLocation().distance( + new Location(this.player.getWorld(), position.getX(), + position.getY(), position.getZ())) + > 180) { + return; + } + + // If red is 0 it seems to treat it as fully red too + if(color.getRed() == 0) { + color = new Color(1, color.getGreen(), color.getBlue()); + } + + + this.player.spigot().playEffect(new Location(player.getWorld(), position.getX(), position.getY(), position.getZ()), Effect.COLOURED_DUST, 0, 0,color.getRed() / 255.0f, color.getGreen() / 255.0f, color.getBlue() / 255.0f, 1, 0, 64); + } +} + diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotServerContainer.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotServerContainer.java new file mode 100644 index 00000000..1ad8bdb2 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotServerContainer.java @@ -0,0 +1,167 @@ +package com.sekwah.advancedportals.legacyspigot.connector.container; + +import com.sekwah.advancedportals.core.CoreListeners; +import com.sekwah.advancedportals.core.connector.containers.PlayerContainer; +import com.sekwah.advancedportals.core.connector.containers.ServerContainer; +import com.sekwah.advancedportals.core.connector.containers.WorldContainer; +import com.sekwah.advancedportals.core.tags.CommandTag; +import com.sekwah.advancedportals.legacyspigot.AdvancedPortalsPlugin; +import com.sekwah.advancedportals.shadowed.inject.Inject; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.permissions.PermissionAttachment; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class LegacySpigotServerContainer implements ServerContainer { + @Inject + private CoreListeners coreListeners; + private final Server server; + // Create an array of items + private final List commonTriggerBlockList = + Stream.of(Material.WATER, Material.LAVA, Material.AIR, + Material.PORTAL, Material.ENDER_PORTAL) + .map(Enum::name) + .collect(Collectors.toList()); + + private final List fullTriggerBlockList = + Arrays.stream(Material.values()) + .map(Enum::name) + .collect(Collectors.toList()); + + public LegacySpigotServerContainer(Server server) { + this.server = server; + } + + @Override + public WorldContainer getWorld(String name) { + World world = server.getWorld(name); + if (world != null) { + return new LegacySpigotWorldContainer(world); + } else { + return null; + } + } + + @Override + public PlayerContainer getPlayer(String name) { + Player player = server.getPlayer(name); + if (player != null) { + return new LegacySpigotPlayerContainer(player); + } else { + return null; + } + } + + @Override + public PlayerContainer getPlayer(UUID name) { + Player player = server.getPlayer(name); + if (player != null) { + return new LegacySpigotPlayerContainer(player); + } else { + return null; + } + } + + @Override + public List getAllTriggerBlocks() { + return this.fullTriggerBlockList; + } + + @Override + public List getCommonTriggerBlocks() { + return this.commonTriggerBlockList; + } + + @Override + public PlayerContainer[] getPlayers() { + return server.getOnlinePlayers() + .stream() + .map(LegacySpigotPlayerContainer::new) + .toArray(PlayerContainer[] ::new); + } + + @Override + public void registerOutgoingChannel(String channel) { + server.getMessenger().registerOutgoingPluginChannel( + AdvancedPortalsPlugin.getInstance(), channel); + } + + @Override + public void registerIncomingChannel(String channel) { + server.getMessenger().registerIncomingPluginChannel( + AdvancedPortalsPlugin.getInstance(), channel, + (s, player, bytes) + -> coreListeners.incomingMessage( + new LegacySpigotPlayerContainer(player), s, bytes)); + } + + @Override + public void dispatchCommand(UUID uuid, String command, + CommandTag.CommandLevel commandLevel) { + Player player = server.getPlayer(uuid); + switch (commandLevel) { + case CONSOLE: + server.dispatchCommand(server.getConsoleSender(), command); + break; + case PLAYER: + server.dispatchCommand(player, command); + break; + case OP: + case PERMISSION_WILDCARD: + executeCommandWithPermission(player, server, command, + commandLevel); + break; + } + } + + // Execute commands with elevated permissions method + private void executeCommandWithPermission( + Player player, Server server, String command, + CommandTag.CommandLevel commandLevel) { + switch (commandLevel) { + case PERMISSION_WILDCARD: + if (player.hasPermission("*")) { + server.dispatchCommand(player, command); + return; + } + PermissionAttachment permissionAttachment = + player.addAttachment( + server.getPluginManager().getPlugin("AdvancedPortals")); + try { + permissionAttachment.setPermission("*", true); + server.dispatchCommand(player, command); + } finally { + player.removeAttachment(permissionAttachment); + } + break; + case OP: + if (player.isOp()) { + server.dispatchCommand(player, command); + return; + } + try { + player.setOp(true); + server.dispatchCommand(player, command); + } finally { + player.setOp(false); + } + break; + } + } + + @Override + public String matchMaterialName(String materialName) { + return Arrays.stream(Material.values()) + .map(Enum::name) + .filter(name -> name.equalsIgnoreCase(materialName)) + .findFirst() + .orElse(null); + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotWorldContainer.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotWorldContainer.java new file mode 100644 index 00000000..2f649408 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/connector/container/LegacySpigotWorldContainer.java @@ -0,0 +1,55 @@ +package com.sekwah.advancedportals.legacyspigot.connector.container; + +import com.sekwah.advancedportals.core.connector.containers.WorldContainer; +import com.sekwah.advancedportals.core.data.BlockAxis; +import com.sekwah.advancedportals.core.portal.AdvancedPortal; +import com.sekwah.advancedportals.core.serializeddata.BlockLocation; +import org.bukkit.Material; +import org.bukkit.World; + + +public class LegacySpigotWorldContainer implements WorldContainer { + private final World world; + + public LegacySpigotWorldContainer(World world) { + this.world = world; + } + + public void setBlock(BlockLocation location, String material) { + Material mat = Material.getMaterial(material); + if (mat != null) + this.world + .getBlockAt(location.getPosX(), location.getPosY(), + location.getPosZ()) + .setType(mat); + } + + public String getBlock(BlockLocation location) { + return this.world + .getBlockAt(location.getPosX(), location.getPosY(), + location.getPosZ()) + .getType() + .toString(); + } + + @Override + public void disableBeacon(BlockLocation location) { + } + + @Override + public BlockAxis getBlockAxis(BlockLocation location) { + return null; + } + + @Override + public void setBlockAxis(BlockLocation location, BlockAxis axis) { + + } + + @Override + public void disableBeacon(AdvancedPortal portal) { + + } + + +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/importer/ConfigAccessor.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/importer/ConfigAccessor.java new file mode 100644 index 00000000..7c519828 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/importer/ConfigAccessor.java @@ -0,0 +1,72 @@ +package com.sekwah.advancedportals.legacyspigot.importer; + +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.IOException; +import java.util.logging.Level; + +public class ConfigAccessor { + private final String fileName; + private final JavaPlugin plugin; + + private File configFile; + private FileConfiguration fileConfiguration; + + public ConfigAccessor(JavaPlugin plugin, String fileName) { + this.plugin = plugin; + this.fileName = fileName; + } + + // gets all of the + public void reloadConfig() { + if (configFile == null) { + File dataFolder = plugin.getDataFolder(); + if (dataFolder == null) + throw new IllegalStateException(); + configFile = new File(dataFolder, fileName); + } + fileConfiguration = YamlConfiguration.loadConfiguration(configFile); + } + + public FileConfiguration getConfig() { + if (fileConfiguration == null) { + this.reloadConfig(); + } + return fileConfiguration; + } + + // Saves all the data to the selected yml file + public void saveConfig() { + if (fileConfiguration == null || configFile == null) { + return; + } else { + try { + getConfig().save(configFile); + } catch (IOException ex) { + plugin.getLogger().log( + Level.SEVERE, "Could not save config to " + configFile, ex); + } + } + } + + // Saves + + /** + * public void saveDefaultConfig() { if (!configFile.exists()) { + * this.plugin.saveResource(fileName, false); } } + */ + + // New save default config saving code, it checks if the needed config is in + // the jar file before overriding it. + public void saveDefaultConfig() { + if (configFile == null) { + configFile = new File(plugin.getDataFolder(), fileName); + } + if (!configFile.exists()) { + plugin.saveResource(fileName, false); + } + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/importer/LegacyImporter.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/importer/LegacyImporter.java new file mode 100644 index 00000000..c744571e --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/importer/LegacyImporter.java @@ -0,0 +1,210 @@ +package com.sekwah.advancedportals.legacyspigot.importer; + +import com.sekwah.advancedportals.core.destination.Destination; +import com.sekwah.advancedportals.core.portal.AdvancedPortal; +import com.sekwah.advancedportals.core.repository.ConfigRepository; +import com.sekwah.advancedportals.core.serializeddata.BlockLocation; +import com.sekwah.advancedportals.core.serializeddata.DataTag; +import com.sekwah.advancedportals.core.serializeddata.PlayerLocation; +import com.sekwah.advancedportals.core.serializeddata.config.CommandPortalConfig; +import com.sekwah.advancedportals.core.serializeddata.config.Config; +import com.sekwah.advancedportals.core.serializeddata.config.WarpEffectConfig; +import com.sekwah.advancedportals.core.services.DestinationServices; +import com.sekwah.advancedportals.core.services.PortalServices; +import com.sekwah.advancedportals.legacyspigot.AdvancedPortalsPlugin; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class LegacyImporter { + private LegacyImporter() { + } + + public static int importPortals(PortalServices portalServices) { + // Check if the file exists and skip if it doesn't + ConfigAccessor portalConfig = new ConfigAccessor( + AdvancedPortalsPlugin.getInstance(), "portals.yml"); + FileConfiguration config = portalConfig.getConfig(); + Set portalSet = config.getKeys(false); + + int count = 0; + for (String portalName : portalSet) { + BlockLocation pos1 = + new BlockLocation(config.getString(portalName + ".world"), + config.getInt(portalName + ".pos1.X"), + config.getInt(portalName + ".pos1.Y"), + config.getInt(portalName + ".pos1.Z")); + BlockLocation pos2 = + new BlockLocation(config.getString(portalName + ".world"), + config.getInt(portalName + ".pos2.X"), + config.getInt(portalName + ".pos2.Y"), + config.getInt(portalName + ".pos2.Z")); + List args = new ArrayList<>(); + args.add(new DataTag("name", portalName)); + String triggerblock = + config.getString(portalName + ".triggerblock"); + if (triggerblock != null) + args.add(new DataTag("triggerblock", triggerblock.split(","))); + // It's called bungee as that's the implementation behind it + + String destination = config.getString(portalName + ".destination"); + if (destination != null) + args.add(new DataTag("destination", destination.split(","))); + + String bungee = config.getString(portalName + ".bungee"); + if (bungee != null) { + if (destination == null) { + args.add(new DataTag("bungee", bungee.split(","))); + } else { + args.add(new DataTag("proxy", bungee.split(","))); + } + } + + ConfigurationSection portalConfigSection = + config.getConfigurationSection(portalName); + ConfigurationSection portalArgsConf = + portalConfigSection.getConfigurationSection("portalArgs"); + + if (portalArgsConf != null) { + Set argsSet = portalArgsConf.getKeys(true); + for (Object argName : argsSet.toArray()) { + // skip if it argName starts with command. + if (portalArgsConf.isString(argName.toString())) { + args.add(new DataTag( + argName.toString(), + portalArgsConf.getString(argName.toString()))); + } + } + } + // Check if command.1 is set + List commands = new ArrayList<>(); + if (getArg(args, "command.1") != null) { + int i = 1; + while (getArg(args, "command." + i) != null) { + commands.add(getArg(args, "command." + i)); + i++; + } + } + if (!commands.isEmpty()) { + args.add( + new DataTag("command", commands.toArray(new String[0]))); + } + args.stream() + .filter(dataTag -> dataTag.NAME.startsWith("command.")) + .collect(Collectors.toList()) + .forEach(args::remove); + + // Find an arg called "delayed" and add a new one called portalEvent + String delayed = getArg(args, "delayed"); + if (delayed != null) { + args.add(new DataTag("portalEvent", delayed)); + args.removeIf(dataTag -> dataTag.NAME.equals("delayed")); + } + + AdvancedPortal portal = + portalServices.createPortal(null, pos1, pos2, args); + + if (portal != null) + count++; + } + + return count; + } + + public static int importDestinations( + DestinationServices destinationServices) { + ConfigAccessor destiConfig = new ConfigAccessor( + AdvancedPortalsPlugin.getInstance(), "destinations.yml"); + FileConfiguration config = destiConfig.getConfig(); + Set destiSet = config.getKeys(false); + + int count = 0; + for (String destiName : destiSet) { + String destiPos = destiName + ".pos"; + Destination desti = destinationServices.createDesti( + new PlayerLocation( + config.getString(destiName + ".world"), + config.getDouble(destiPos + ".X"), + config.getDouble(destiPos + ".Y"), + config.getDouble(destiPos + ".Z"), + (float) config.getDouble(destiPos + ".yaw"), + (float) config.getDouble(destiPos + ".pitch")), + Collections.singletonList(new DataTag("name", destiName))); + if (desti != null) + count++; + } + return count; + } + + public static String getArg(List tags, String arg) { + for (DataTag portalArg : tags) { + if (arg.equals(portalArg.NAME)) { + return portalArg.VALUES[0]; + } + } + return null; + } + + public static void importConfig(ConfigRepository configRepo) { + Config config = new Config(); + ConfigAccessor configOldAccessor = new ConfigAccessor( + AdvancedPortalsPlugin.getInstance(), "config.yml"); + FileConfiguration configOld = configOldAccessor.getConfig(); + + config.useOnlySpecialAxe = configOld.getBoolean( + "UseOnlyServerMadeAxe", config.useOnlySpecialAxe); + config.blockSpectatorMode = configOld.getBoolean( + "BlockSpectatorMode", config.blockSpectatorMode); + config.selectorMaterial = + configOld.getString("AxeItemId", config.selectorMaterial); + config.portalProtection = + configOld.getBoolean("PortalProtection", config.portalProtection); + config.portalProtectionRadius = configOld.getInt( + "PortalProtectionArea", config.portalProtectionRadius); + config.defaultTriggerBlock = configOld.getString( + "DefaultPortalTriggerBlock", config.defaultTriggerBlock); + if (config.defaultTriggerBlock.equals("PORTAL")) { + config.defaultTriggerBlock = "NETHER_PORTAL"; + } + config.stopWaterFlow = + configOld.getBoolean("StopWaterFlow", config.stopWaterFlow); + config.joinCooldown = + configOld.getInt("PortalCooldown", config.joinCooldown); + config.throwbackStrength = + configOld.getDouble("ThrowbackAmount", config.throwbackStrength); + config.playFailSound = + configOld.getBoolean("PlayFailSound", config.playFailSound); + config.warpMessageOnActionBar = + configOld.getInt("WarpMessageDisplay", 2) == 2; + config.warpMessageInChat = + configOld.getInt("WarpMessageDisplay", 2) == 1; + config.enableProxySupport = configOld.getBoolean( + "ForceEnableProxySupport", config.enableProxySupport); + config.disableGatewayBeam = configOld.getBoolean( + "DisableGatewayBeam", config.disableGatewayBeam); + + CommandPortalConfig commandConfig = new CommandPortalConfig(); + String commandString = configOld.getString("CommandLevels", "opcb"); + commandConfig.enabled = !commandString.contains("n"); + commandConfig.op = commandString.contains("o"); + commandConfig.permsWildcard = commandString.contains("p"); + commandConfig.console = commandString.contains("c"); + commandConfig.proxy = commandString.contains("b"); + + config.commandPortals = commandConfig; + + WarpEffectConfig warpEffectConfig = new WarpEffectConfig(); + warpEffectConfig.visualEffect = + configOld.getInt("WarpParticles", 1) == 1 ? "ender" : null; + warpEffectConfig.soundEffect = + configOld.getInt("WarpSound", 1) == 1 ? "ender" : null; + config.warpEffect = warpEffectConfig; + + configRepo.importConfig(config); + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/metrics/Metrics.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/metrics/Metrics.java new file mode 100644 index 00000000..2b133120 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/metrics/Metrics.java @@ -0,0 +1,787 @@ +package com.sekwah.advancedportals.legacyspigot.metrics; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; + +/** + * bStats collects some data for plugin authors. + * + *

Check out https://bStats.org/ to learn more about bStats! + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +public class Metrics { + static { + // You can use the property to disable the check in your test + // environment + if (System.getProperty("bstats.relocatecheck") == null + || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have + // to use this little "trick" ... :D + final String defaultPackage = new String( + new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', + '.', 'b', 'u', 'k', 'k', 'i', 't'}); + final String examplePackage = new String(new byte[] { + 'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure nobody just copy & pastes the example and + // use the wrong package names + if (Metrics.class.getPackage().getName().equals(defaultPackage) + || Metrics.class.getPackage().getName().equals( + examplePackage)) { + throw new IllegalStateException( + "bStats Metrics class has not been relocated correctly!"); + } + } + } + + // The version of this bStats class + public static final int B_STATS_VERSION = 1; + + // The url to which the data is sent + private static final String URL = "https://bStats.org/submitData/bukkit"; + + // Is bStats enabled on this server? + private final boolean enabled; + + // Should failed requests be logged? + private static boolean logFailedRequests; + + // Should the sent data be logged? + private static boolean logSentData; + + // Should the response text be logged? + private static boolean logResponseStatusText; + + // The uuid of the server + private static String serverUUID; + + // The plugin + private final Plugin plugin; + + // A list with all custom charts + private final List charts = new ArrayList<>(); + + /** + * Class constructor. + * + * @param plugin The plugin which stats should be submitted. + */ + public Metrics(Plugin plugin) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + + // Get the config file + File bStatsFolder = + new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yaml"); + YamlConfiguration config = + YamlConfiguration.loadConfiguration(configFile); + + // Check if the config file exists + if (!config.isSet("serverUuid")) { + // Add default values + config.addDefault("enabled", true); + // Every server gets it's unique random id. + config.addDefault("serverUuid", UUID.randomUUID().toString()); + // Should failed request be logged? + config.addDefault("logFailedRequests", false); + // Should the sent data be logged? + config.addDefault("logSentData", false); + // Should the response text be logged? + config.addDefault("logResponseStatusText", false); + + // Inform the server owners about bStats + config.options() + .header( + "bStats collects some data for plugin authors like how " + + "many servers are" + + " using their plugins.\n" + + "To honor their work, you should not disable it.\n" + + "This has nearly no effect on the server performance!\n" + + "Check out https://bStats.org/ to learn more :)") + .copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { + } + } + + // Load the data + enabled = config.getBoolean("enabled", true); + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + logSentData = config.getBoolean("logSentData", false); + logResponseStatusText = + config.getBoolean("logResponseStatusText", false); + + if (enabled) { + boolean found = false; + // Search for all other bStats Metrics classes to see if we are the + // first one + for (Class service : + Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + found = true; // We aren't the first + break; + } catch (NoSuchFieldException ignored) { + } + } + // Register our service + Bukkit.getServicesManager().register(Metrics.class, this, plugin, + ServicePriority.Normal); + if (!found) { + // We are the first! + startSubmitting(); + } + } + } + + /** + * Checks if bStats is enabled. + * + * @return Whether bStats is enabled or not. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + if (chart == null) { + throw new IllegalArgumentException("Chart cannot be null!"); + } + charts.add(chart); + } + + /** + * Starts the Scheduler which submits our data every 30 minutes. + */ + private void startSubmitting() { + final Timer timer = + new Timer(true); // We use a timer cause the Bukkit + // scheduler is affected by server lags + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + if (!plugin.isEnabled()) { // Plugin was disabled + timer.cancel(); + return; + } + // Nevertheless we want our code to run in the Bukkit main + // thread, so we have to use the Bukkit scheduler Don't be + // afraid! The connection to the bStats server is still async, + // only the stats collection is sync ;) + Bukkit.getScheduler().runTask(plugin, () -> submitData()); + } + }, 1000 * 60 * 5, 1000 * 60 * 30); + // Submit the data every 30 minutes, first time after 5 minutes to give + // other plugins enough time to start WARNING: Changing the frequency + // has no effect but your plugin WILL be blocked/deleted! WARNING: Just + // don't do it! + } + + /** + * Gets the plugin specific data. This method is called using Reflection. + * + * @return The plugin specific data. + */ + public JsonObject getPluginData() { + JsonObject data = new JsonObject(); + + String pluginName = plugin.getDescription().getName(); + String pluginVersion = plugin.getDescription().getVersion(); + + data.addProperty("pluginName", + pluginName); // Append the name of the plugin + data.addProperty("pluginVersion", + pluginVersion); // Append the version of the plugin + JsonArray customCharts = new JsonArray(); + for (CustomChart customChart : charts) { + // Add the data of the custom charts + JsonObject chart = customChart.getRequestJsonObject(); + if (chart == null) { // If the chart is null, we skip it + continue; + } + customCharts.add(chart); + } + data.add("customCharts", customCharts); + + return data; + } + + /** + * Gets the server specific data. + * + * @return The server specific data. + */ + private JsonObject getServerData() { + // Minecraft specific data + int playerAmount; + try { + // Around MC 1.8 the return type was changed to a collection from an + // array, This fixes java.lang.NoSuchMethodError: + // org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server") + .getMethod("getOnlinePlayers"); + playerAmount = + onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke( + Bukkit.getServer())) + .size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())) + .length; + } catch (Exception e) { + playerAmount = + Bukkit.getOnlinePlayers() + .size(); // Just use the new method if the Reflection failed + } + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = Bukkit.getVersion(); + String bukkitName = Bukkit.getName(); + + // OS/Java specific data + String javaVersion = System.getProperty("java.version"); + String osName = System.getProperty("os.name"); + String osArch = System.getProperty("os.arch"); + String osVersion = System.getProperty("os.version"); + int coreCount = Runtime.getRuntime().availableProcessors(); + + JsonObject data = new JsonObject(); + + data.addProperty("serverUUID", serverUUID); + + data.addProperty("playerAmount", playerAmount); + data.addProperty("onlineMode", onlineMode); + data.addProperty("bukkitVersion", bukkitVersion); + data.addProperty("bukkitName", bukkitName); + + data.addProperty("javaVersion", javaVersion); + data.addProperty("osName", osName); + data.addProperty("osArch", osArch); + data.addProperty("osVersion", osVersion); + data.addProperty("coreCount", coreCount); + + return data; + } + + /** + * Collects the data and sends it afterwards. + */ + private void submitData() { + final JsonObject data = getServerData(); + + JsonArray pluginData = new JsonArray(); + // Search for all other bStats Metrics classes to get their plugin data + for (Class service : + Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + + for (RegisteredServiceProvider provider : + Bukkit.getServicesManager().getRegistrations(service)) { + try { + Object plugin = provider.getService() + .getMethod("getPluginData") + .invoke(provider.getProvider()); + if (plugin instanceof JsonObject) { + pluginData.add((JsonObject) plugin); + } else { // old bstats version compatibility + try { + Class jsonObjectJsonSimple = + Class.forName("org.json.simple.JSONObject"); + if (plugin.getClass().isAssignableFrom( + jsonObjectJsonSimple)) { + Method jsonStringGetter = + jsonObjectJsonSimple.getDeclaredMethod( + "toJSONString"); + jsonStringGetter.setAccessible(true); + String jsonString = + (String) jsonStringGetter.invoke( + plugin); + JsonObject object = new JsonParser() + .parse(jsonString) + .getAsJsonObject(); + pluginData.add(object); + } + } catch (ClassNotFoundException e) { + // minecraft version 1.14+ + if (logFailedRequests) { + this.plugin.getLogger().log( + Level.SEVERE, + "Encountered unexpected exception", e); + } + continue; // continue looping since we cannot do + // any other thing. + } + } + } catch (NullPointerException | NoSuchMethodException + | IllegalAccessException + | InvocationTargetException ignored) { + } + } + } catch (NoSuchFieldException ignored) { + } + } + + data.add("plugins", pluginData); + + // Create a new thread for the connection to the bStats server + new Thread(new Runnable() { + @Override + public void run() { + try { + // Send the data + sendData(plugin, data); + } catch (Exception e) { + // Something went wrong! :( + if (logFailedRequests) { + plugin.getLogger().log( + Level.WARNING, + "Could not submit plugin stats of " + + plugin.getName(), + e); + } + } + } + }).start(); + } + + /** + * Sends the data to the bStats server. + * + * @param plugin Any plugin. It's just used to get a logger instance. + * @param data The data to send. + * @throws Exception If the request failed. + */ + private static void sendData(Plugin plugin, JsonObject data) + throws Exception { + if (data == null) { + throw new IllegalArgumentException("Data cannot be null!"); + } + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException( + "This method must not be called from the main thread!"); + } + if (logSentData) { + plugin.getLogger().info("Sending data to bStats: " + + data.toString()); + } + HttpsURLConnection connection = + (HttpsURLConnection) new URL(URL).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + // Add headers + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", + "gzip"); // We gzip our request + connection.addRequestProperty("Content-Length", + String.valueOf(compressedData.length)); + connection.setRequestProperty( + "Content-Type", + "application/json"); // We send our data in JSON format + connection.setRequestProperty("User-Agent", + "MC-Server/" + B_STATS_VERSION); + + // Send data + connection.setDoOutput(true); + DataOutputStream outputStream = + new DataOutputStream(connection.getOutputStream()); + outputStream.write(compressedData); + outputStream.flush(); + outputStream.close(); + + InputStream inputStream = connection.getInputStream(); + BufferedReader bufferedReader = + new BufferedReader(new InputStreamReader(inputStream)); + + StringBuilder builder = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + bufferedReader.close(); + if (logResponseStatusText) { + plugin.getLogger().info( + "Sent data to bStats and received response: " + + builder.toString()); + } + } + + /** + * Gzips the given String. + * + * @param str The string to gzip. + * @return The gzipped String. + * @throws IOException If the compression failed. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + GZIPOutputStream gzip = new GZIPOutputStream(outputStream); + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + gzip.close(); + return outputStream.toByteArray(); + } + + /** + * Represents a custom chart. + */ + public abstract static class CustomChart { + // The id of the chart + final String chartId; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + */ + CustomChart(String chartId) { + if (chartId == null || chartId.isEmpty()) { + throw new IllegalArgumentException( + "ChartId cannot be null or empty!"); + } + this.chartId = chartId; + } + + private JsonObject getRequestJsonObject() { + JsonObject chart = new JsonObject(); + chart.addProperty("chartId", chartId); + try { + JsonObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + chart.add("data", data); + } catch (Throwable t) { + if (logFailedRequests) { + Bukkit.getLogger().log( + Level.WARNING, + "Failed to get data for custom chart with id " + + chartId, + t); + } + return null; + } + return chart; + } + + protected abstract JsonObject getChartData() throws Exception; + } + + /** + * Represents a custom simple pie. + */ + public static class SimplePie extends CustomChart { + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + data.addProperty("value", value); + return data; + } + } + + /** + * Represents a custom advanced pie. + */ + public static class AdvancedPie extends CustomChart { + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, + Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + JsonObject values = new JsonObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.addProperty(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.add("values", values); + return data; + } + } + + /** + * Represents a custom drilldown pie. + */ + public static class DrilldownPie extends CustomChart { + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie( + String chartId, + Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + JsonObject values = new JsonObject(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : + map.entrySet()) { + JsonObject value = new JsonObject(); + boolean allSkipped = true; + for (Map.Entry valueEntry : + map.get(entryValues.getKey()).entrySet()) { + value.addProperty(valueEntry.getKey(), + valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + values.add(entryValues.getKey(), value); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + data.add("values", values); + return data; + } + } + + /** + * Represents a custom single line chart. + */ + public static class SingleLineChart extends CustomChart { + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + data.addProperty("value", value); + return data; + } + } + + /** + * Represents a custom multi line chart. + */ + public static class MultiLineChart extends CustomChart { + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, + Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + JsonObject values = new JsonObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.addProperty(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.add("values", values); + return data; + } + } + + /** + * Represents a custom simple bar chart. + */ + public static class SimpleBarChart extends CustomChart { + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, + Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + JsonObject values = new JsonObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + JsonArray categoryValues = new JsonArray(); + categoryValues.add(new JsonPrimitive(entry.getValue())); + values.add(entry.getKey(), categoryValues); + } + data.add("values", values); + return data; + } + + /** + * Represents a custom advanced bar chart. + */ + public static class AdvancedBarChart extends CustomChart { + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + JsonObject data = new JsonObject(); + JsonObject values = new JsonObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + continue; // Skip this invalid + } + allSkipped = false; + JsonArray categoryValues = new JsonArray(); + for (int categoryValue : entry.getValue()) { + categoryValues.add(new JsonPrimitive(categoryValue)); + } + values.add(entry.getKey(), categoryValues); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.add("values", values); + return data; + } + } + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/tags/ConditionsTag.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/tags/ConditionsTag.java new file mode 100644 index 00000000..95a0dd5b --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/tags/ConditionsTag.java @@ -0,0 +1,176 @@ +package com.sekwah.advancedportals.legacyspigot.tags; + +import com.sekwah.advancedportals.core.connector.containers.PlayerContainer; +import com.sekwah.advancedportals.core.registry.TagTarget; +import com.sekwah.advancedportals.core.util.InfoLogger; +import com.sekwah.advancedportals.core.util.Lang; +import com.sekwah.advancedportals.core.warphandler.ActivationData; +import com.sekwah.advancedportals.core.warphandler.Tag; +import com.sekwah.advancedportals.shadowed.inject.Inject; +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.entity.Player; + +import com.sekwah.advancedportals.legacyspigot.connector.container.LegacySpigotPlayerContainer; + +public class ConditionsTag implements Tag.Activation, Tag.Split, Tag.Creation { + @Inject + private InfoLogger infoLogger; + + @Override + public boolean preActivated(TagTarget target, PlayerContainer player, + ActivationData activeData, String[] argData) { + for (String condition : argData) { + if (player instanceof LegacySpigotPlayerContainer) { + LegacySpigotPlayerContainer spigotPlayer = + (LegacySpigotPlayerContainer) player; + + if (!checkConditions(condition, spigotPlayer.getPlayer())) { + spigotPlayer.sendMessage( + Lang.getNegativePrefix() + + Lang.translate("tag.conditions.fail")); + return false; + } + } + } + + return true; + } + + @Override + public void postActivated(TagTarget target, PlayerContainer player, + ActivationData activationData, String[] argData) { + } + + @Override + public boolean activated(TagTarget target, PlayerContainer player, + ActivationData activationData, String[] argData) { + return false; + } + + @Override + public TagType[] getTagTypes() { + return new TagType[] {TagType.PORTAL}; + } + + @Override + public String getName() { + return "conditions"; + } + + @Override + public String[] getAliases() { + return new String[0]; + } + + @Override + public String description() { + return Lang.translate("tag.conditions.description"); + } + + private boolean checkConditions(String condition, Player player) { + // Remove whitespaces before splitting the condition + String trimmedCondition = condition.replaceAll("\\s+", ""); + + // Check if the condition contains a valid operator + if (!trimmedCondition.matches(".*(<=|>=|<|>|==).*")) { + // Log a warning or handle the case where the condition format is + // invalid + infoLogger.warning("Invalid operator: " + condition); + return false; + } + + // Split the condition into placeholder and value parts + String[] parts = trimmedCondition.split("<=|>=|<|>|=="); + + if (parts.length == 2) { + // Trim to remove any leading/trailing whitespaces + String placeholder = parts[0].trim(); + String actualValue = + PlaceholderAPI.setPlaceholders(player, placeholder); + String restOfCondition = parts[1].trim(); + + // Preserve the operator + String operator = + condition + .substring(placeholder.length(), + condition.length() - restOfCondition.length()) + .trim(); + + return performComparison(actualValue, operator, restOfCondition); + } else { + // Log a warning or handle the case where the condition format is + // invalid + infoLogger.warning("Invalid condition format: " + condition); + return false; + } + } + + private boolean performComparison(String actualValue, String operator, + String expectedValue) { + if (isNumeric(actualValue) && isNumeric(expectedValue)) { + // Numeric comparison + double actualNumeric = Double.parseDouble(actualValue); + double expectedNumeric = Double.parseDouble(expectedValue); + + switch (operator) { + case "==": + return actualNumeric == expectedNumeric; + case "<": + return actualNumeric < expectedNumeric; + case ">": + return actualNumeric > expectedNumeric; + case "<=": + return actualNumeric <= expectedNumeric; + case ">=": + return actualNumeric >= expectedNumeric; + default: + return false; // Unsupported operator + } + } else if (isBoolean(actualValue) && isBoolean(expectedValue)) { + // Boolean comparison + boolean actualBoolean = Boolean.parseBoolean(actualValue); + boolean expectedBoolean = Boolean.parseBoolean(expectedValue); + + return actualBoolean == expectedBoolean; + } else { + // String comparison + return actualValue.equals(expectedValue); + } + } + + private boolean isNumeric(String str) { + try { + Double.parseDouble(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + private boolean isBoolean(String str) { + return str.equalsIgnoreCase("true") || str.equalsIgnoreCase("false"); + } + + @Override + public boolean created(TagTarget target, PlayerContainer player, + String[] argData) { + for (String condition : argData) { + if (player instanceof LegacySpigotPlayerContainer) { + LegacySpigotPlayerContainer spigotPlayer = + (LegacySpigotPlayerContainer) player; + if (!checkConditions(condition, spigotPlayer.getPlayer())) { + spigotPlayer.sendMessage( + Lang.getNegativePrefix() + + Lang.translate("tag.conditions.invalid")); + return false; + } + } + } + return true; + } + + @Override + public void destroyed(TagTarget target, PlayerContainer player, + String[] argData) { + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/utils/ContainerHelpers.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/utils/ContainerHelpers.java new file mode 100644 index 00000000..ad71d079 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/utils/ContainerHelpers.java @@ -0,0 +1,18 @@ +package com.sekwah.advancedportals.legacyspigot.utils; + +import com.sekwah.advancedportals.core.serializeddata.BlockLocation; +import com.sekwah.advancedportals.core.serializeddata.PlayerLocation; +import org.bukkit.Location; + +public class ContainerHelpers { + public static PlayerLocation toPlayerLocation(Location loc) { + return new PlayerLocation(loc.getWorld().getName(), loc.getX(), + loc.getY(), loc.getZ(), loc.getYaw(), + loc.getPitch()); + } + + public static BlockLocation toBlockLocation(Location loc) { + return new BlockLocation(loc.getWorld().getName(), loc.getBlockX(), + loc.getBlockY(), loc.getBlockZ()); + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/warpeffects/EnderWarpEffect.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/warpeffects/EnderWarpEffect.java new file mode 100644 index 00000000..f7d20c0d --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/warpeffects/EnderWarpEffect.java @@ -0,0 +1,64 @@ +package com.sekwah.advancedportals.legacyspigot.warpeffects; + +import com.sekwah.advancedportals.core.connector.containers.PlayerContainer; +import com.sekwah.advancedportals.core.effect.WarpEffect; +import com.sekwah.advancedportals.legacyspigot.AdvancedPortalsPlugin; +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.World; +import org.bukkit.entity.Player; + +import com.sekwah.advancedportals.legacyspigot.connector.container.LegacySpigotPlayerContainer; + +public class EnderWarpEffect implements WarpEffect.Visual, WarpEffect.Sound { + + org.bukkit.Sound sound; + + { + try { + sound = org.bukkit.Sound.valueOf("ENTITY_ENDERMEN_TELEPORT"); + } catch (IllegalArgumentException e) { + try { + sound = org.bukkit.Sound.valueOf("ENDERMAN_TELEPORT"); + } catch (IllegalArgumentException e2) { + AdvancedPortalsPlugin.getInstance().getLogger().warning("Could not find the sound ENTITY_ENDERMAN_TELEPORT or ENDERMAN_TELEPORT"); + } + } + } + + @Override + public void onWarpSound(PlayerContainer playerContainer, + Action action) { + if (playerContainer instanceof LegacySpigotPlayerContainer) { + LegacySpigotPlayerContainer spigotPlayerContainer = + (LegacySpigotPlayerContainer) playerContainer; + Player player = spigotPlayerContainer.getPlayer(); + + if(sound == null) { + return; + } + player.getWorld().playSound(player.getLocation(), + sound, 1, 1); + } + } + + @Override + public void onWarpVisual(PlayerContainer playerContainer, + Action action) { + if (playerContainer instanceof LegacySpigotPlayerContainer) { + LegacySpigotPlayerContainer spigotPlayerContainer = + (LegacySpigotPlayerContainer) playerContainer; + Player player = spigotPlayerContainer.getPlayer(); + World world = player.getWorld(); + Location loc = player.getLocation().clone(); + for (int i = 0; i < 10; i++) { + world.playEffect(loc, Effect.ENDER_SIGNAL, 0); + } + loc.add(0D, 1D, 0D); + for (int i = 0; i < 10; i++) { + world.playEffect(loc, Effect.ENDER_SIGNAL, 0); + } + } + } +} diff --git a/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/warpeffects/SpigotWarpEffects.java b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/warpeffects/SpigotWarpEffects.java new file mode 100644 index 00000000..6f0b3b32 --- /dev/null +++ b/legacyspigot/src/main/java/com/sekwah/advancedportals/legacyspigot/warpeffects/SpigotWarpEffects.java @@ -0,0 +1,13 @@ +package com.sekwah.advancedportals.legacyspigot.warpeffects; + +import com.sekwah.advancedportals.core.registry.WarpEffectRegistry; +import com.sekwah.advancedportals.shadowed.inject.Inject; + +public class SpigotWarpEffects { + @Inject + private WarpEffectRegistry warpEffectRegistry; + + public void registerEffects() { + warpEffectRegistry.registerEffect("ender", new EnderWarpEffect()); + } +} diff --git a/legacyspigot/src/main/templates/plugin.yml b/legacyspigot/src/main/templates/plugin.yml new file mode 100644 index 00000000..15391bd0 --- /dev/null +++ b/legacyspigot/src/main/templates/plugin.yml @@ -0,0 +1,17 @@ +main: com.sekwah.advancedportals.legacyspigot.AdvancedPortalsPlugin +name: AdvancedPortals +version: ${pluginVersion} +author: sekwah41 +description: An advanced portals plugin for bukkit. +api-version: 1.8.8 +softdepend: [PlaceholderAPI] +commands: + portal: + description: The main command for the advanced portals + aliases: [portals, aportals, advancedportals] + usage: / + destination: + description: Can be used to access portal destinations. + aliases: [desti] + usage: / +permissions: ${permissions} diff --git a/settings.gradle b/settings.gradle index 4a36b19d..5652f06f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,6 +6,7 @@ include 'lang' // Implementations include 'spigot' +include 'legacyspigot' // Proxies include 'velocity' diff --git a/spigot/build.gradle b/spigot/build.gradle index e203722b..fe7d6e21 100644 --- a/spigot/build.gradle +++ b/spigot/build.gradle @@ -1,3 +1,13 @@ +import java.nio.file.Files +import java.nio.file.Paths +import java.nio.file.StandardCopyOption +import java.nio.file.StandardOpenOption + +plugins { + id "com.modrinth.minotaur" version "2.+" + id 'dev.s7a.gradle.minecraft.server' version '1.1.0' + id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7' +} // Check the root build.gradle under allprojects for common settings configurations { @@ -5,6 +15,11 @@ configurations { includeLibs } +archivesBaseName = "Advanced-Portals-Spigot" + +apply from: rootProject.file('env-variables.gradle') +apply from: rootProject.file('changelog-util.gradle') + repositories { maven { url "https://repo.maven.apache.org/maven2" } maven { url "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" } @@ -30,6 +45,11 @@ dependencies { // Soft dependencies compileOnly 'me.clip:placeholderapi:2.11.6' + + includeLibs project(':lang') + includeLibs project(':core') + includeLibs project(':bungee') + includeLibs project(':velocity') } tasks.named('compileJava') { @@ -37,11 +57,46 @@ tasks.named('compileJava') { } jar { - from configurations.includeLibs.collect { + dependsOn(':bungee:jar', ':lang:jar', ':proxycore:jar', ':velocity:jar') + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + // Filters the files out that are in the build folders. Look to see if there is a better way to do this? + from configurations.includeLibs.filter { + it.path.contains("${File.separator}build${File.separator}libs") + } .collect { + println("Will Include: ${it.name}") it.isDirectory() ? it : zipTree(it) } } +/** + * Will build then copy it to the minecraft server folder for use with the launch task and dev tools plugin + */ +tasks.register('copyPlugin') { + dependsOn(build) + doLast { + copy { + def sourceFilePath = Paths.get("$buildDir/libs/Advanced-Portals-Spigot-${getVersion()}.jar") + def destinationFilePath = Paths.get("$buildDir/MinecraftServer/plugins/Advanced-Portals-Spigot.jar") + + println "Handling file: $destinationFilePath" + + byte[] newContent = Files.readAllBytes(sourceFilePath) + + if (Files.exists(destinationFilePath)) { + println "File exists. Overwriting with new binary content." + + Files.write(destinationFilePath, newContent, StandardOpenOption.TRUNCATE_EXISTING) + } else { + println "File does not exist. Copying from source." + + Files.copy(sourceFilePath, destinationFilePath, StandardCopyOption.REPLACE_EXISTING) + } + } + } +} + + // Code for generating extra data in plugins.yml // This may be able to be simplified drastically, though the goal is to get this working for now // as it has gone through a few iterations. @@ -119,3 +174,100 @@ generateTemplates.configure { } sourceSets.main.resources.srcDir(generateTemplates.map { it.outputs }) + +tasks.register('downloadSekCDevToolsPlugin') { + doLast { + // Define the URL and destination path + def url = 'https://github.com/sekwah41/SekCDevToolsPlugin/releases/download/v1.0.0/SekCDevToolsPlugin-1.0-SNAPSHOT.jar' + def destinationDir = new File("$buildDir/MinecraftServer/plugins") + def destinationFile = new File(destinationDir, 'SekCDevToolsPlugin-1.0-SNAPSHOT.jar') + + // Create the directory if it doesn't exist + if (!destinationDir.exists()) { + destinationDir.mkdirs() + } + + // Download the file if it doesn't exist + if (!destinationFile.exists()) { + println "Downloading SekCDevToolsPlugin..." + new URL(url).withInputStream { i -> + destinationFile.withOutputStream { + it << i + } + } + } else { + println "SekCDevToolsPlugin already downloaded" + } + } +} + +tasks.launchMinecraftServer.dependsOn(downloadSekCDevToolsPlugin) + +minecraftServerConfig { + jarUrl.set('https://api.papermc.io/v2/projects/paper/versions/1.19.4/builds/550/downloads/paper-1.19.4-550.jar') + jvmArgument = ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005", "-DIReallyKnowWhatIAmDoingISwear=true"] +} + +apply from: '../curse.gradle' + +supportedVersions = [ + "1.13", + "1.13.1", + "1.13.2", + "1.14", + "1.14.1", + "1.14.2", + "1.14.3", + "1.14.4", + "1.15", + "1.15.1", + "1.15.2", + "1.16", + "1.16.1", + "1.16.2", + "1.16.3", + "1.16.4", + "1.16.5", + "1.17", + "1.17.1", + "1.18", + "1.18.1", + "1.18.2", + "1.19", + "1.19.1", + "1.19.2", + "1.19.3", + "1.19.4", + "1.20", + "1.20.1", + "1.20.2", + "1.20.3", + "1.20.4", + "1.20.5", + "1.20.6", + "1.21", + "1.21.1", + "1.21.2", + "1.21.3", + "1.21.4" +] + + +modrinth { + token = System.getenv("MODRINTH_TOKEN") + projectId = project.modrinth_slug + versionType = "release" + uploadFile = jar + loaders = ["spigot", "bukkit", "paper", "velocity", "waterfall", "bungeecord", "purpur"] + gameVersions = supportedVersions + changelog = getReleaseChangelog() + versionName = "Spigot [MC 1.13+]" + getVersion() + versionNumber = getVersion() + "-Spigot" + syncBodyFrom = rootProject.file("README.md").text +} + +tasks.modrinth.dependsOn(tasks.modrinthSyncBody) +tasks.modrinth.group = "distribute" + +apply from: '../discord.gradle' +