Portal module
This commit is contained in:
119
.gitignore
vendored
Normal file
119
.gitignore
vendored
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
# User-specific stuff
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Ignore Gradle GUI config
|
||||||
|
gradle-app.setting
|
||||||
|
|
||||||
|
# Cache of project
|
||||||
|
.gradletasknamecache
|
||||||
|
|
||||||
|
**/build/
|
||||||
|
|
||||||
|
# Common working directory
|
||||||
|
run/
|
||||||
|
runs/
|
||||||
|
|
||||||
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
|
!gradle-wrapper.jar
|
||||||
50
build.gradle.kts
Normal file
50
build.gradle.kts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("jvm") version "2.2.0-Beta2"
|
||||||
|
id("com.gradleup.shadow") version "8.3.0"
|
||||||
|
id("xyz.jpenilla.run-paper") version "2.3.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.pobnellion"
|
||||||
|
version = "2.0-SNAPSHOT"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://repo.papermc.io/repository/maven-public/") {
|
||||||
|
name = "papermc-repo"
|
||||||
|
}
|
||||||
|
maven("https://oss.sonatype.org/content/groups/public/") {
|
||||||
|
name = "sonatype"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly("io.papermc.paper:paper-api:1.21.5-R0.1-SNAPSHOT")
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
runServer {
|
||||||
|
// Configure the Minecraft version for our task.
|
||||||
|
// This is the only required configuration besides applying the plugin.
|
||||||
|
// Your plugin's jar (or shadowJar if present) will be used automatically.
|
||||||
|
minecraftVersion("1.21")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetJavaVersion = 21
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(targetJavaVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.build {
|
||||||
|
dependsOn("shadowJar")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.processResources {
|
||||||
|
val props = mapOf("version" to version)
|
||||||
|
inputs.properties(props)
|
||||||
|
filteringCharset = "UTF-8"
|
||||||
|
filesMatching("plugin.yml") {
|
||||||
|
expand(props)
|
||||||
|
}
|
||||||
|
}
|
||||||
0
gradle.properties
Normal file
0
gradle.properties
Normal file
1
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
1
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||||
1
settings.gradle.kts
Normal file
1
settings.gradle.kts
Normal file
@ -0,0 +1 @@
|
|||||||
|
rootProject.name = "pobutils"
|
||||||
77
src/main/kotlin/com/pobnellion/pobutils/Pobutils.kt
Normal file
77
src/main/kotlin/com/pobnellion/pobutils/Pobutils.kt
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package com.pobnellion.pobutils
|
||||||
|
|
||||||
|
import com.pobnellion.pobutils.modules.CmdModule
|
||||||
|
import com.pobnellion.pobutils.modules.ModuleBase
|
||||||
|
import com.pobnellion.pobutils.modules.portals.Portals
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
|
||||||
|
|
||||||
|
class Pobutils : JavaPlugin() {
|
||||||
|
companion object {
|
||||||
|
val availableModules = mutableMapOf<String, ModuleBase>()
|
||||||
|
val enabledModules : MutableMap<String, ModuleBase> = mutableMapOf()
|
||||||
|
fun getDisabledModuleNames() = availableModules.keys.filter { name -> !enabledModules.containsKey(name) }
|
||||||
|
fun isEnabled(moduleName: String) : Boolean = enabledModules.containsKey(moduleName)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnable() {
|
||||||
|
loadDefaultConfig()
|
||||||
|
|
||||||
|
CmdModule.register(this)
|
||||||
|
|
||||||
|
registerModule(Portals(this))
|
||||||
|
|
||||||
|
logger.info("Registered ${availableModules.size} modules: [${availableModules.keys.joinToString()}]")
|
||||||
|
|
||||||
|
// Enable modules
|
||||||
|
for ((name, module) in availableModules) {
|
||||||
|
if (config.getBoolean("modules.${name}")) {
|
||||||
|
module.onEnable()
|
||||||
|
enabledModules[name] = module
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Loaded ${enabledModules.size} modules: [${enabledModules.keys.joinToString()}]")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisable() {
|
||||||
|
// Plugin shutdown logic
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerModule(module: ModuleBase) {
|
||||||
|
availableModules[module.name] = module
|
||||||
|
module.register()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadDefaultConfig() {
|
||||||
|
saveResource("config.yml", false)
|
||||||
|
|
||||||
|
config.addDefault("modules.noJoinMessage", false)
|
||||||
|
config.addDefault("modules.sit", false)
|
||||||
|
config.addDefault("modules.spawn", false)
|
||||||
|
config.addDefault("modules.portals", false)
|
||||||
|
config.addDefault("modules.warp", false)
|
||||||
|
config.addDefault("modules.hub", false)
|
||||||
|
config.addDefault("modules.disableTNT", false)
|
||||||
|
config.addDefault("modules.tabList", false)
|
||||||
|
config.addDefault("modules.formatChat", false)
|
||||||
|
config.addDefault("modules.disableTrample", false)
|
||||||
|
config.addDefault("modules.snowballDamage", false)
|
||||||
|
config.addDefault("data.spawn.location", "")
|
||||||
|
config.addDefault("data.spawn.spawnOnJoin", false)
|
||||||
|
config.addDefault("data.spawn.spawnOnDeath", false)
|
||||||
|
|
||||||
|
// config.addDefault("data.spawn.spawnOnFirstJoin", false);
|
||||||
|
config.addDefault("data.portals", "")
|
||||||
|
config.addDefault("data.warps", "")
|
||||||
|
config.addDefault("data.formatChat.serverAlias", "?")
|
||||||
|
config.addDefault("data.formatChat.messageFormat", "<gray><server_alias> <white><username>: <message>")
|
||||||
|
config.addDefault("data.formatChat.formatMessageText", true)
|
||||||
|
|
||||||
|
config.addDefault("settings.snowballDamage.damageExceptions", ArrayList<String?>())
|
||||||
|
config.addDefault("settings.snowballDamage.snowmenDontHitEachother", true)
|
||||||
|
|
||||||
|
config.options().copyDefaults(true)
|
||||||
|
saveConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
96
src/main/kotlin/com/pobnellion/pobutils/modules/CmdModule.kt
Normal file
96
src/main/kotlin/com/pobnellion/pobutils/modules/CmdModule.kt
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package com.pobnellion.pobutils.modules
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||||
|
import com.pobnellion.pobutils.Pobutils
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack
|
||||||
|
import io.papermc.paper.command.brigadier.Commands
|
||||||
|
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.TextComponent
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
object CmdModule {
|
||||||
|
fun register(plugin: JavaPlugin) {
|
||||||
|
val command = Commands.literal("module")
|
||||||
|
.requires { source -> source.sender.hasPermission("pobutils.admin") }
|
||||||
|
.then(handleAction("enable", plugin))
|
||||||
|
.then(handleAction("disable", plugin))
|
||||||
|
.then(handleAction("reload", plugin))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
plugin.lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS) {commands ->
|
||||||
|
commands.registrar().register(command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleAction(action: String, plugin: JavaPlugin) : LiteralArgumentBuilder<CommandSourceStack> {
|
||||||
|
return Commands.literal(action)
|
||||||
|
.then(Commands.argument("module", StringArgumentType.word())
|
||||||
|
.suggests { ctx, builder ->
|
||||||
|
when (action) {
|
||||||
|
"enable" -> Pobutils.getDisabledModuleNames().forEach { module -> builder.suggest(module) }
|
||||||
|
"disable" -> Pobutils.enabledModules.keys.forEach { module -> builder.suggest(module) }
|
||||||
|
"reload" -> Pobutils.enabledModules.keys.forEach { module -> builder.suggest(module) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return@suggests builder.buildFuture()
|
||||||
|
}
|
||||||
|
.executes { ctx ->
|
||||||
|
val moduleName = StringArgumentType.getString(ctx, "module")
|
||||||
|
|
||||||
|
val module = Pobutils.availableModules[moduleName]
|
||||||
|
|
||||||
|
if (module == null) {
|
||||||
|
ctx.source.sender.sendMessage(Component.text("No module named '$moduleName'", NamedTextColor.RED))
|
||||||
|
return@executes Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
val message : TextComponent
|
||||||
|
when (action) {
|
||||||
|
"enable" -> {
|
||||||
|
if (Pobutils.isEnabled(moduleName)) {
|
||||||
|
message = Component.text("Module '$moduleName' is already enabled", NamedTextColor.RED)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Pobutils.enabledModules[moduleName] = module
|
||||||
|
module.onEnable()
|
||||||
|
plugin.config.set("modules.$moduleName", true)
|
||||||
|
plugin.saveConfig()
|
||||||
|
message = Component.text("Module '$moduleName' enabled", NamedTextColor.YELLOW)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"disable" -> {
|
||||||
|
if (!Pobutils.isEnabled(moduleName)) {
|
||||||
|
message = Component.text("Module '$moduleName' is already disabled", NamedTextColor.RED)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Pobutils.enabledModules.remove(moduleName)
|
||||||
|
module.onDisable()
|
||||||
|
plugin.config.set("modules.$moduleName", false)
|
||||||
|
plugin.saveConfig()
|
||||||
|
message = Component.text("Module '$moduleName' disabled", NamedTextColor.YELLOW)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"reload" -> {
|
||||||
|
if (!Pobutils.isEnabled(moduleName)) {
|
||||||
|
message = Component.text("Module '$moduleName' is not currently enabled", NamedTextColor.RED)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
module.reload()
|
||||||
|
message = Component.text("Module '$moduleName' reloaded", NamedTextColor.YELLOW)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> message = Component.text("Unknown argument '$action'", NamedTextColor.RED)
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.server.onlinePlayers.forEach { player -> player.updateCommands() }
|
||||||
|
ctx.source.sender.sendMessage(message)
|
||||||
|
|
||||||
|
return@executes Command.SINGLE_SUCCESS
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.pobnellion.pobutils.modules
|
||||||
|
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
|
||||||
|
abstract class ModuleBase(val plugin: JavaPlugin) {
|
||||||
|
abstract val name : String
|
||||||
|
abstract fun register()
|
||||||
|
abstract fun reload()
|
||||||
|
abstract fun onDisable()
|
||||||
|
abstract fun onEnable()
|
||||||
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
package com.pobnellion.pobutils.modules.portals
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||||
|
import com.pobnellion.pobutils.Pobutils
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack
|
||||||
|
import io.papermc.paper.command.brigadier.Commands
|
||||||
|
import io.papermc.paper.command.brigadier.argument.ArgumentTypes
|
||||||
|
import io.papermc.paper.command.brigadier.argument.resolvers.BlockPositionResolver
|
||||||
|
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
object CmdPortal {
|
||||||
|
val serverList: MutableList<String> = mutableListOf()
|
||||||
|
|
||||||
|
fun register(plugin: JavaPlugin, portals: Portals) {
|
||||||
|
val command = Commands.literal("portal")
|
||||||
|
.requires { source ->
|
||||||
|
Pobutils.isEnabled("portals") &&
|
||||||
|
source.sender.hasPermission("pobutils.admin") &&
|
||||||
|
source.sender is Player
|
||||||
|
}
|
||||||
|
.then(addOrUpdatePortal("add", portals))
|
||||||
|
.then(addOrUpdatePortal("update", portals))
|
||||||
|
.then(removePortal(portals))
|
||||||
|
.then(listPortals(portals))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
plugin.lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS) { commands ->
|
||||||
|
commands.registrar().register(command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addOrUpdatePortal(action: String, portals: Portals) : LiteralArgumentBuilder<CommandSourceStack> {
|
||||||
|
var portalSubCommand = Commands.argument("name", StringArgumentType.word())
|
||||||
|
|
||||||
|
if (action == "update")
|
||||||
|
portalSubCommand = portalSubCommand.suggests { ctx, builder ->
|
||||||
|
portals.portals.forEach { portal -> builder.suggest(portal.name) }
|
||||||
|
return@suggests builder.buildFuture()
|
||||||
|
}
|
||||||
|
|
||||||
|
portalSubCommand.then(Commands.argument("location1", ArgumentTypes.blockPosition())
|
||||||
|
.then(Commands.argument("location2", ArgumentTypes.blockPosition())
|
||||||
|
.then(Commands.argument("destinationServer", StringArgumentType.word())
|
||||||
|
.suggests { ctx, builder ->
|
||||||
|
serverList.forEach { serverName -> builder.suggest(serverName) }
|
||||||
|
return@suggests builder.buildFuture()
|
||||||
|
}
|
||||||
|
.executes { ctx ->
|
||||||
|
val name = StringArgumentType.getString(ctx, "name")
|
||||||
|
val destServer = StringArgumentType.getString(ctx, "destinationServer")
|
||||||
|
val location1 = ctx.getArgument("location1", BlockPositionResolver::class.java).resolve(ctx.source)
|
||||||
|
val location2 = ctx.getArgument("location2", BlockPositionResolver::class.java).resolve(ctx.source)
|
||||||
|
|
||||||
|
if (!serverList.contains(destServer)) {
|
||||||
|
ctx.source.sender.sendMessage(Component.text("No server named $destServer", NamedTextColor.RED))
|
||||||
|
return@executes Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
when (action) {
|
||||||
|
"add" if portals.exists(name) -> ctx.source.sender.sendMessage(Component.text("A portal called $name already exists!", NamedTextColor.RED))
|
||||||
|
"update" if !portals.exists(name) -> ctx.source.sender.sendMessage(Component.text("No portal named $name!", NamedTextColor.RED))
|
||||||
|
else -> {
|
||||||
|
portals.addOrUpdate(name, location1, location2, destServer)
|
||||||
|
val actionVerb = if (action == "add") "Added" else "Updated"
|
||||||
|
ctx.source.sender.sendMessage(Component.text("$actionVerb portal '$name'", NamedTextColor.YELLOW))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return@executes Command.SINGLE_SUCCESS
|
||||||
|
})))
|
||||||
|
|
||||||
|
return Commands
|
||||||
|
.literal(action)
|
||||||
|
.then(portalSubCommand)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removePortal(portals: Portals) : LiteralArgumentBuilder<CommandSourceStack> {
|
||||||
|
return Commands.literal("remove")
|
||||||
|
.then(Commands.argument("portal", StringArgumentType.word())
|
||||||
|
.suggests { ctx, builder ->
|
||||||
|
portals.portals.forEach { portal -> builder.suggest(portal.name) }
|
||||||
|
return@suggests builder.buildFuture()
|
||||||
|
}
|
||||||
|
.executes { ctx ->
|
||||||
|
val name = StringArgumentType.getString(ctx, "portal")
|
||||||
|
|
||||||
|
if (!portals.exists(name))
|
||||||
|
ctx.source.sender.sendMessage(Component.text("No portal named $name!", NamedTextColor.RED))
|
||||||
|
else
|
||||||
|
portals.remove(name)
|
||||||
|
|
||||||
|
return@executes Command.SINGLE_SUCCESS
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun listPortals(portals: Portals) : LiteralArgumentBuilder<CommandSourceStack> {
|
||||||
|
return Commands.literal("list")
|
||||||
|
.executes { ctx ->
|
||||||
|
ctx.source.sender.sendMessage(Component.text("There are ${portals.portals.count()} portals:", NamedTextColor.YELLOW))
|
||||||
|
|
||||||
|
portals.portals.forEach { portal ->
|
||||||
|
ctx.source.sender.sendMessage(Component.text(portal.toString(), NamedTextColor.YELLOW))
|
||||||
|
}
|
||||||
|
|
||||||
|
return@executes Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.pobnellion.pobutils.modules.portals
|
||||||
|
|
||||||
|
import org.bukkit.Location
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
class Portal {
|
||||||
|
|
||||||
|
val name: String
|
||||||
|
val destServer: String
|
||||||
|
private val x1: Int
|
||||||
|
private val y1: Int
|
||||||
|
private val z1: Int
|
||||||
|
private val x2: Int
|
||||||
|
private val y2: Int
|
||||||
|
private val z2: Int
|
||||||
|
|
||||||
|
constructor(name: String, destServer: String, x1: Int, y1: Int, z1: Int, x2: Int, y2: Int, z2: Int) {
|
||||||
|
this.name = name
|
||||||
|
this.destServer = destServer
|
||||||
|
this.x1 = min(x1, x2)
|
||||||
|
this.y1 = min(y1, y2)
|
||||||
|
this.z1 = min(z1, z2)
|
||||||
|
this.x2 = max(x1, x2)
|
||||||
|
this.y2 = max(y1, y2)
|
||||||
|
this.z2 = max(z1, z2)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun deserialize(name: String, serializedData: String) : Portal {
|
||||||
|
val data = serializedData.split(" ")
|
||||||
|
|
||||||
|
return Portal(
|
||||||
|
name,
|
||||||
|
data[6],
|
||||||
|
data[0].toInt(),
|
||||||
|
data[1].toInt(),
|
||||||
|
data[2].toInt(),
|
||||||
|
data[3].toInt(),
|
||||||
|
data[4].toInt(),
|
||||||
|
data[5].toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun serialize(): String {
|
||||||
|
return "$x1 $y1 $z1 $x2 $y2 $z2 $destServer"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun contains(location: Location) : Boolean {
|
||||||
|
return location.blockX >= x1 && location.blockX <= x2 &&
|
||||||
|
location.blockY >= y1 && location.blockY <= y2 &&
|
||||||
|
location.blockZ >= z1 && location.blockZ <= z2
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString() : String {
|
||||||
|
return "[$name] ($x1 $y1 $z1) ($x2 $y2 $z2) dest: $destServer"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,164 @@
|
|||||||
|
package com.pobnellion.pobutils.modules.portals
|
||||||
|
|
||||||
|
import com.google.common.io.ByteStreams
|
||||||
|
import com.pobnellion.pobutils.Pobutils
|
||||||
|
import com.pobnellion.pobutils.modules.ModuleBase
|
||||||
|
import io.papermc.paper.math.BlockPosition
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.attribute.Attribute
|
||||||
|
import org.bukkit.attribute.AttributeModifier
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
import org.bukkit.plugin.messaging.PluginMessageListener
|
||||||
|
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
class Portals(plugin: JavaPlugin) : ModuleBase(plugin), Listener, PluginMessageListener {
|
||||||
|
val portals: MutableList<Portal> = mutableListOf()
|
||||||
|
val portalCooldowns: MutableMap<Player, Location> = mutableMapOf()
|
||||||
|
override val name: String = "portals"
|
||||||
|
|
||||||
|
override fun register() {
|
||||||
|
Bukkit.getPluginManager().registerEvents(this, plugin)
|
||||||
|
plugin.server.pluginManager.registerEvents(this, plugin)
|
||||||
|
|
||||||
|
CmdPortal.register(plugin, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reload() {
|
||||||
|
onDisable()
|
||||||
|
onEnable()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnable() {
|
||||||
|
loadConfig()
|
||||||
|
|
||||||
|
plugin.server.messenger.registerOutgoingPluginChannel(plugin, "BungeeCord")
|
||||||
|
plugin.server.messenger.registerIncomingPluginChannel(plugin, "BungeeCord", this)
|
||||||
|
|
||||||
|
// use a player to trigger server list refresh (otherwise refresh will happen on player join)
|
||||||
|
if (plugin.server.onlinePlayers.count() > 0)
|
||||||
|
refreshServerList(plugin.server.onlinePlayers.first())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisable() {
|
||||||
|
portals.clear()
|
||||||
|
CmdPortal.serverList.clear()
|
||||||
|
|
||||||
|
plugin.server.messenger.unregisterOutgoingPluginChannel(plugin)
|
||||||
|
plugin.server.messenger.unregisterIncomingPluginChannel(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadConfig() {
|
||||||
|
plugin.reloadConfig()
|
||||||
|
val config = plugin.config.getConfigurationSection("data.portals")
|
||||||
|
|
||||||
|
if (config != null)
|
||||||
|
portals.addAll(config.getKeys(false)
|
||||||
|
.map { name -> Portal.deserialize(name, config.get(name) as String) })
|
||||||
|
|
||||||
|
plugin.logger.info("Loaded ${portals.count()} portals")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateConfig() {
|
||||||
|
val portalsConfig = portals.associateBy(
|
||||||
|
{ portal -> portal.name },
|
||||||
|
{ portal -> portal.serialize() })
|
||||||
|
|
||||||
|
plugin.config.set("data.portals", portalsConfig)
|
||||||
|
plugin.saveConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addOrUpdate(name: String, p1: BlockPosition, p2: BlockPosition, destServer: String) {
|
||||||
|
portals.removeIf { portal -> portal.name == name }
|
||||||
|
val portal = Portal(name, destServer, p1.blockX(), p1.blockY(), p1.blockZ(), p2.blockX(), p2.blockY(), p2.blockZ())
|
||||||
|
portals.add(portal)
|
||||||
|
updateConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun remove(name: String) {
|
||||||
|
if (!portals.removeIf { portal -> portal.name == name })
|
||||||
|
plugin.componentLogger.error("Failed to remove portal $name")
|
||||||
|
updateConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exists(name: String?) : Boolean {
|
||||||
|
if (name == null)
|
||||||
|
return false
|
||||||
|
|
||||||
|
return portals.any { portal -> portal.name == name }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshServerList(player: Player) {
|
||||||
|
plugin.logger.info("Refreshing server list")
|
||||||
|
val message = ByteStreams.newDataOutput()
|
||||||
|
message.writeUTF("GetServers")
|
||||||
|
player.sendPluginMessage(plugin, "BungeeCord", message.toByteArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun usePortal(event: PlayerMoveEvent, portal: Portal) {
|
||||||
|
val stopModifier = AttributeModifier(NamespacedKey.minecraft("stop"), -1.0, AttributeModifier.Operation.ADD_SCALAR)
|
||||||
|
event.player.getAttribute(Attribute.MOVEMENT_SPEED)!!.addTransientModifier(stopModifier)
|
||||||
|
event.player.getAttribute(Attribute.JUMP_STRENGTH)!!.addTransientModifier(stopModifier)
|
||||||
|
portalCooldowns[event.player] = event.from
|
||||||
|
|
||||||
|
val message = ByteStreams.newDataOutput()
|
||||||
|
message.writeUTF("Connect")
|
||||||
|
message.writeUTF(portal.destServer)
|
||||||
|
event.player.sendPluginMessage(plugin, "BungeeCord", message.toByteArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPluginMessageReceived(channel: String, player: Player, message: ByteArray) {
|
||||||
|
if (channel != "BungeeCord")
|
||||||
|
return
|
||||||
|
|
||||||
|
val message = ByteStreams.newDataInput(message)
|
||||||
|
val subchannel = message.readUTF()
|
||||||
|
if (subchannel == "GetServers") {
|
||||||
|
val serverList = message.readUTF()
|
||||||
|
CmdPortal.serverList.clear()
|
||||||
|
CmdPortal.serverList.addAll(serverList.split(", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch player server when they enter a portal
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerMove(event: PlayerMoveEvent) {
|
||||||
|
if (!Pobutils.isEnabled(this.name))
|
||||||
|
return
|
||||||
|
|
||||||
|
if (portalCooldowns.containsKey(event.player))
|
||||||
|
return
|
||||||
|
|
||||||
|
for (portal in portals) {
|
||||||
|
if (portal.contains(event.to)) {
|
||||||
|
usePortal(event, portal)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When they leave, reset player to where they were before they entered the portal
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerQuit(event: PlayerQuitEvent) {
|
||||||
|
if (portalCooldowns.containsKey(event.player)) {
|
||||||
|
event.player.teleport(portalCooldowns[event.player] as Location)
|
||||||
|
portalCooldowns.remove(event.player)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update server list used for command completion
|
||||||
|
// Plugin message requires a player to send the event so we wait for a player
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerJoin(event: PlayerJoinEvent) {
|
||||||
|
if (Pobutils.isEnabled(this.name) && CmdPortal.serverList.isEmpty())
|
||||||
|
plugin.server.scheduler.runTaskLaterAsynchronously(plugin, {_ -> refreshServerList(event.player) }, 10 )
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/main/resources/config.yml
Normal file
27
src/main/resources/config.yml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
modules:
|
||||||
|
noJoinMessage: true
|
||||||
|
sit: true
|
||||||
|
spawn: false
|
||||||
|
portals: false
|
||||||
|
warp: false
|
||||||
|
hub: true
|
||||||
|
disableTNT: false
|
||||||
|
tabList: false
|
||||||
|
formatChat: true
|
||||||
|
disableTrample: false
|
||||||
|
snowballDamage: false
|
||||||
|
data:
|
||||||
|
spawn:
|
||||||
|
location: ''
|
||||||
|
spawnOnJoin: false
|
||||||
|
spawnOnDeath: false
|
||||||
|
portals: ''
|
||||||
|
warps: ''
|
||||||
|
formatChat:
|
||||||
|
serverAlias: '?'
|
||||||
|
messageFormat: '<gray><server_alias> <white><username>: <message>'
|
||||||
|
formatMessageText: true
|
||||||
|
settings:
|
||||||
|
snowballDamage:
|
||||||
|
damageExceptions: []
|
||||||
|
snowmenDontHitEachother: true
|
||||||
49
src/main/resources/plugin.yml
Normal file
49
src/main/resources/plugin.yml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
name: pobutils
|
||||||
|
version: '2.0-SNAPSHOT'
|
||||||
|
main: com.pobnellion.pobutils.Pobutils
|
||||||
|
api-version: '1.21'
|
||||||
|
prefix: PobUtils
|
||||||
|
authors: [ Bizink ]
|
||||||
|
|
||||||
|
commands:
|
||||||
|
module:
|
||||||
|
description: configure a module
|
||||||
|
usage: /module <module> <enable|disable|config>
|
||||||
|
permission: pobutils.admin
|
||||||
|
|
||||||
|
spawn:
|
||||||
|
description: Teleport to spawn
|
||||||
|
usage: /spawn
|
||||||
|
permission: pobutils.user
|
||||||
|
|
||||||
|
setspawn:
|
||||||
|
description: Set spawn location
|
||||||
|
usage: /setspawn [location]
|
||||||
|
permission: pobutils.admin
|
||||||
|
|
||||||
|
sit:
|
||||||
|
description: Sit down for a while buddy
|
||||||
|
usage: /sit
|
||||||
|
permission: pobutils.user
|
||||||
|
|
||||||
|
portal:
|
||||||
|
description: add or remove a portal to another server
|
||||||
|
usage: /portal <add|update|remove> <name> [x1] [y1] [z1] [x2] [y2] [z2] [destinationServer]
|
||||||
|
permission: pobutils.admin
|
||||||
|
|
||||||
|
warp:
|
||||||
|
description: list or go to warps
|
||||||
|
usage: /warp [add|del|list|warpName] [warpName] [x] [y] [z] [yaw] [pitch]
|
||||||
|
permission: pobutils.user
|
||||||
|
|
||||||
|
hub:
|
||||||
|
description: go to hub server
|
||||||
|
usage: /hub
|
||||||
|
permission: pobutils.user
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pobutils.user:
|
||||||
|
default: true
|
||||||
|
|
||||||
|
pobutils.admin:
|
||||||
|
default: op
|
||||||
Reference in New Issue
Block a user