feat: add support for legacy spigot 1.8 - 1.12 (#520)

This commit is contained in:
Sekwah 2025-01-25 04:36:35 +00:00 committed by GitHub
parent 414cda8d25
commit 2bdeb5b0b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 2848 additions and 228 deletions

View File

@ -26,7 +26,27 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: 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 needs: release-please
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: release environment: release
@ -39,11 +59,11 @@ jobs:
path: ~/.gradle/caches path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle restore-keys: ${{ runner.os }}-gradle
- name: Set up JDK 16 - name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v3 uses: actions/setup-java@v3
with: with:
distribution: zulu distribution: temurin
java-version: 16 java-version: ${{ matrix.java-version }}
- name: Build and publish (release) - name: Build and publish (release)
env: env:
CURSE_API: ${{ secrets.CURSE_API }} CURSE_API: ${{ secrets.CURSE_API }}
@ -53,4 +73,4 @@ jobs:
IS_RELEASE: true IS_RELEASE: true
run: | run: |
# Build # Build
./gradlew build ${{ matrix.release-task }} ./gradlew build ${{ matrix.project }}:${{ matrix.release-task }}

View File

@ -6,32 +6,31 @@ on:
name: Build name: Build
jobs: jobs:
snapshot: snapshot:
#if: ${{!startsWith(github.ref.split(/)[2], 'release-please')}}
runs-on: ubuntu-latest 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: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
# these if statements ensure that a publication only occurs when
# a new release is created:
- name: Cache Gradle packages - name: Cache Gradle packages
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
path: ~/.gradle/caches path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle restore-keys: ${{ runner.os }}-gradle
- name: Set up JDK 16 - name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v3 uses: actions/setup-java@v3
with: with:
distribution: temurin distribution: temurin
java-version: 16 java-version: ${{ matrix.java-version }}
# - 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
- name: Build and upload preview (run for non-release builds) - name: Build and upload preview (run for non-release builds)
if: ${{ github.ref && !contains( github.ref, 'renovate/deps') }} if: ${{ github.ref && !contains( github.ref, 'renovate/deps') }}
env: env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
run: | run: |
# Build # Build
./gradlew build discordupload ./gradlew ${{ matrix.project }}:discordupload

View File

@ -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.

View File

@ -16,10 +16,7 @@ buildscript {
} }
} }
plugins { 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' 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("Github SHA: ${ext.githubSha}")
println("Sha Ref: ${ext.shaRef}") println("Sha Ref: ${ext.shaRef}")
archivesBaseName = "Advanced-Portals"
group = 'com.sekwah.advancedportals' group = 'com.sekwah.advancedportals'
println "Version: ${getVersion()}" println "Version: ${getVersion()}"
@ -85,174 +81,18 @@ repositories {
maven { url "https://nexus.velocitypowered.com/repository/maven-public/" } maven { url "https://nexus.velocitypowered.com/repository/maven-public/" }
} }
// includeLibs just says to include the library in the final jar // Needed to find generateTemplates task
dependencies { evaluationDependsOn(':core')
includeLibs project(':lang')
includeLibs project(':core')
includeLibs project(':bungee')
includeLibs project(':spigot')
includeLibs project(':velocity')
}
println "Branch ${ext.branch}${ext.shaRef} isRelease: '${ext.isRelease}'" 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 { idea {
project { project {
settings { settings {
taskTriggers { 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'

View File

@ -1,5 +1,5 @@
ext.getReleaseChangelog = { 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 def changelog = "## [${changelogFile.text.split('\n## \\[')[1]}\n\n" // ${project.github}/blob/${branch}/CHANGELOG.md
return changelog return changelog
} }

View File

@ -47,13 +47,6 @@ public class ShowDestiSubCommand
@Override @Override
public void onCommand(CommandSenderContainer sender, String[] args) { 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 = PlayerData tempData =
tempDataServices.getPlayerData(sender.getPlayerContainer()); tempDataServices.getPlayerData(sender.getPlayerContainer());
if (tempData.isDestiVisible()) { if (tempData.isDestiVisible()) {

View File

@ -60,13 +60,6 @@ public class ShowPortalSubCommand
@Override @Override
public void onCommand(CommandSenderContainer sender, String[] args) { 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 = PlayerData tempData =
playerDataServices.getPlayerData(sender.getPlayerContainer()); playerDataServices.getPlayerData(sender.getPlayerContainer());
if (tempData.isPortalVisible()) { if (tempData.isPortalVisible()) {

View File

@ -21,7 +21,7 @@ buildscript {
} }
} }
apply from: 'env-variables.gradle' apply from: rootProject.file('env-variables.gradle')
static String getValueFromCurseAPI(apiKey, endpoint) { static String getValueFromCurseAPI(apiKey, endpoint) {
String API_BASE_URL = 'https://minecraft.curseforge.com' String API_BASE_URL = 'https://minecraft.curseforge.com'
@ -108,9 +108,13 @@ class UploadResponse {
int id int id
} }
ext {
supportedVersions = []
}
// Based on https://github.com/matthewprenger/CurseGradle as it didnt support Bukkit uploads at the time. // Based on https://github.com/matthewprenger/CurseGradle as it didnt support Bukkit uploads at the time.
task curseforge { task curseforge {
group = 'distribute'
dependsOn(jar) dependsOn(jar)
doLast { doLast {
String apiKey = System.getenv("CURSE_API") String apiKey = System.getenv("CURSE_API")
@ -129,29 +133,10 @@ task curseforge {
GameVersion[] gameVersions = gson.fromJson(gameVersionsString, GameVersion[].class) GameVersion[] gameVersions = gson.fromJson(gameVersionsString, GameVersion[].class)
def versions = gameVersions.findAll {it.gameVersionTypeID == gameVersionTypeID} def versions = gameVersions.findAll {it.gameVersionTypeID == gameVersionTypeID}
String[] supportedVersions = [ if (supportedVersions.isEmpty()) {
"1.21", println("No supported versions specified. Please set 'supportedVersions' in the applying file.")
"1.20.6", return
"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"
]
def supportedGameVersions = versions.findAll {supportedVersions.contains(it.name)} def supportedGameVersions = versions.findAll {supportedVersions.contains(it.name)}
int[] supportedGameVersionIds = supportedGameVersions.collect {it.id}.toArray() int[] supportedGameVersionIds = supportedGameVersions.collect {it.id}.toArray()

View File

@ -15,10 +15,11 @@ buildscript {
} }
} }
apply from: 'env-variables.gradle' apply from: rootProject.file('env-variables.gradle')
apply from: 'changelog-util.gradle' apply from: rootProject.file('changelog-util.gradle')
task discordupload { task discordupload {
group = 'Distribute'
dependsOn(jar) dependsOn(jar)
doLast { doLast {
@ -26,6 +27,12 @@ task discordupload {
String discordWebhook = isRelease ? System.getenv("DISCORD_RELEASE_WEBHOOK") : System.getenv("DISCORD_WEBHOOK") String discordWebhook = isRelease ? System.getenv("DISCORD_RELEASE_WEBHOOK") : System.getenv("DISCORD_WEBHOOK")
if(discordWebhook != null) { 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() CloseableHttpClient httpClient = HttpClients.createDefault()
HttpPost uploadFile = new HttpPost(discordWebhook) HttpPost uploadFile = new HttpPost(discordWebhook)

217
legacyspigot/build.gradle Normal file
View File

@ -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'

View File

@ -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());
}
}
}

View File

@ -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);
}
}

View File

@ -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<Block> 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--;
}
}
}
}

View File

@ -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<PermissionBuilder> 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();
}
}

View File

@ -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<String> destiSet = config.getKeys(false);
return destiSet.size();
}
public int getPortalCount() {
ConfigAccessor portalConfig = new ConfigAccessor(
AdvancedPortalsPlugin.getInstance(), "portals.yaml");
FileConfiguration config = portalConfig.getConfig();
Set<String> portalSet = config.getKeys(false);
return portalSet.size();
}
@Override
public boolean hasPermission(CommandSenderContainer sender) {
return Permissions.IMPORT.hasPermission(sender);
}
@Override
public List<String> 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");
}
}

View File

@ -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<String> onTabComplete(CommandSender commandSender,
Command command, String s,
String[] args) {
return this.commandExecutor.onTabComplete(
new LegacySpigotCommandSenderContainer(commandSender), args);
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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()));
}
}

View File

@ -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);
}
}

View File

@ -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<String> commonTriggerBlockList =
Stream.of(Material.WATER, Material.LAVA, Material.AIR,
Material.PORTAL, Material.ENDER_PORTAL)
.map(Enum::name)
.collect(Collectors.toList());
private final List<String> 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<String> getAllTriggerBlocks() {
return this.fullTriggerBlockList;
}
@Override
public List<String> 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);
}
}

View File

@ -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) {
}
}

View File

@ -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);
}
}
}

View File

@ -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<String> 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<DataTag> 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<String> 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<String> 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<String> 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<DataTag> 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);
}
}

View File

@ -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.
*
* <p>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<CustomChart> 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<String> 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<String> 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<Map<String, Integer>> 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<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> 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<Map<String, Map<String, Integer>>> 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<Map<String, Map<String, Integer>>> callable) {
super(chartId);
this.callable = callable;
}
@Override
public JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
Map<String, Map<String, Integer>> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean reallyAllSkipped = true;
for (Map.Entry<String, Map<String, Integer>> entryValues :
map.entrySet()) {
JsonObject value = new JsonObject();
boolean allSkipped = true;
for (Map.Entry<String, Integer> 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<Integer> 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<Integer> 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<Map<String, Integer>> 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<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> 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<Map<String, Integer>> 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<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
for (Map.Entry<String, Integer> 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<Map<String, int[]>> 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<Map<String, int[]>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
Map<String, int[]> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, int[]> 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;
}
}
}
}

View File

@ -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) {
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}
}
}

View File

@ -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());
}
}

View File

@ -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: /<command>
destination:
description: Can be used to access portal destinations.
aliases: [desti]
usage: /<command>
permissions: ${permissions}

View File

@ -6,6 +6,7 @@ include 'lang'
// Implementations // Implementations
include 'spigot' include 'spigot'
include 'legacyspigot'
// Proxies // Proxies
include 'velocity' include 'velocity'

View File

@ -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 // Check the root build.gradle under allprojects for common settings
configurations { configurations {
@ -5,6 +15,11 @@ configurations {
includeLibs includeLibs
} }
archivesBaseName = "Advanced-Portals-Spigot"
apply from: rootProject.file('env-variables.gradle')
apply from: rootProject.file('changelog-util.gradle')
repositories { repositories {
maven { url "https://repo.maven.apache.org/maven2" } maven { url "https://repo.maven.apache.org/maven2" }
maven { url "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" } maven { url "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" }
@ -30,6 +45,11 @@ dependencies {
// Soft dependencies // Soft dependencies
compileOnly 'me.clip:placeholderapi:2.11.6' compileOnly 'me.clip:placeholderapi:2.11.6'
includeLibs project(':lang')
includeLibs project(':core')
includeLibs project(':bungee')
includeLibs project(':velocity')
} }
tasks.named('compileJava') { tasks.named('compileJava') {
@ -37,11 +57,46 @@ tasks.named('compileJava') {
} }
jar { 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) 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 // 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 // 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. // as it has gone through a few iterations.
@ -119,3 +174,100 @@ generateTemplates.configure {
} }
sourceSets.main.resources.srcDir(generateTemplates.map { it.outputs }) 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'