diff --git a/.gitignore b/.gitignore index a6e3daf..53c9a3c 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,8 @@ hs_err_pid* replay_pid* # idea -.idea +.idea/* # build sources -target - +target/* +# spigot test server +spigot/* diff --git a/README.md b/README.md index fa96990..0d60cf7 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,26 @@ # spigot_ontime_handler +Spigot plugin to send Minecraft derivates to OnMemberJoin, OnMemberRemove & OnMessage to the KDB-API to be processed +accordingly + +## Execute + +### Install dependencies: + +Install ```spigot server``` in folder ```./spigot``` first!! + +```bash +mvn install +``` + +### Build and Run the plugin: + +```bash +./run.sh +``` + +### Build only: + +```bash +./build.sh +``` \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..0c35637 --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +mvn package -f pom.xml \ No newline at end of file diff --git a/kd_ontime_handler_spigot.iml b/kd_ontime_handler_spigot.iml index 43cdacd..4f789f1 100644 --- a/kd_ontime_handler_spigot.iml +++ b/kd_ontime_handler_spigot.iml @@ -1,8 +1,18 @@ + + + + + SPIGOT + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index f2fc94a..20c0809 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,6 @@ 1.19.2-R0.1-SNAPSHOT provided - org.jetbrains.kotlin kotlin-test-junit5 @@ -49,6 +48,21 @@ kotlin-stdlib-jdk8 1.7.21 + + org.jetbrains.kotlin + kotlin-compiler + 1.7.21 + + + org.json + json + 20220924 + + + com.google.okhttp + okhttp + 20120626 + @@ -81,7 +95,33 @@ exec-maven-plugin 1.6.0 - MainKt + OntimeHandlerPlugin + + + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + ${project.artifactId}-${project.version} + false diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..fd9919b --- /dev/null +++ b/run.sh @@ -0,0 +1,5 @@ +bash build.sh +cp target/kd_ontime_handler_spigot-*-SNAPSHOT.jar spigot/plugins +cd spigot +export PLUGIN_ENVIRONMENT=development +java -Xms1G -Xmx8G -jar spigot.jar --nogui \ No newline at end of file diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt deleted file mode 100644 index f2a59b6..0000000 --- a/src/main/kotlin/Main.kt +++ /dev/null @@ -1,7 +0,0 @@ -fun main(args: Array) { - println("Hello World!") - - // Try adding program arguments via Run/Debug configuration. - // Learn more about running applications: https://www.jetbrains.com/help/idea/running-applications.html. - println("Program arguments: ${args.joinToString()}") -} \ No newline at end of file diff --git a/src/main/kotlin/de/sh_edraft/OntimeHandlerPlugin.kt b/src/main/kotlin/de/sh_edraft/OntimeHandlerPlugin.kt new file mode 100644 index 0000000..0e8fb3a --- /dev/null +++ b/src/main/kotlin/de/sh_edraft/OntimeHandlerPlugin.kt @@ -0,0 +1,43 @@ +package de.sh_edraft + +import de.sh_edraft.config.Config +import de.sh_edraft.data.DataService +import de.sh_edraft.events.OnJoinListener +import de.sh_edraft.events.OnLeftListener +import org.bukkit.Bukkit +import org.bukkit.plugin.java.JavaPlugin + +open class OntimeHandlerPlugin() : JavaPlugin() { + + private lateinit var config: Config + + private lateinit var dataService: DataService + + override fun onEnable() { + this.config = Config(logger) + this.config.read("plugins/kd_ontime/config.properties", false) + this.config.read("plugins/kd_ontime/config.${this.config.environment}.properties", true) + this.config.read("plugins/kd_ontime/config.${this.config.hostName}.properties", true) + + this.dataService = DataService(logger, this.config) + + server.pluginManager.registerEvents(OnJoinListener(logger, this.dataService), this) + server.pluginManager.registerEvents(OnLeftListener(logger, this.dataService), this) + + logger.info("OntimeHandlerPlugin enabled :D") + } + + override fun onDisable() { + try { + for (player in Bukkit.getOnlinePlayers()) { + logger.info("Logout player" + player.displayName) + val playerId = this.dataService.getPlayerGlobalId(player.player!!.displayName) ?: return + this.dataService.sendLeftPlayer(playerId) + } + } catch (ex: Exception) { + logger.severe(ex.message) + } + + logger.info("OntimeHandlerPlugin disabled :(") + } +} \ No newline at end of file diff --git a/src/main/kotlin/de/sh_edraft/config/Config.kt b/src/main/kotlin/de/sh_edraft/config/Config.kt new file mode 100644 index 0000000..51e37e4 --- /dev/null +++ b/src/main/kotlin/de/sh_edraft/config/Config.kt @@ -0,0 +1,79 @@ +package de.sh_edraft.config + +import java.io.File +import java.net.InetAddress +import java.net.UnknownHostException +import java.util.* +import java.util.logging.Logger + + +class Config(private var logger: Logger) { + private val properties = Properties() + + var hostName: String = "" + get() { + return this.getHostname() ?: "localhost" + } + private set + + var environment: String = "" + get() { + return System.getenv("PLUGIN_ENVIRONMENT") ?: "production" + } + private set + + lateinit var ApiURL: String + private set + + lateinit var ApiKey: String + private set + + private fun getHostname(): String? { + try { + return InetAddress.getLocalHost().hostName + } catch (ex: UnknownHostException) { + println("Hostname can not be resolved") + } + return null + } + + fun read(filename: String, optional: Boolean = false) { + logger.config("Try to read config ${filename}") + var foundFile = false + try { + val file = File(filename); + if (!file.exists()) { + if (!optional) { + file.parentFile.mkdirs(); + logger.config("${filename} not found") + file.writeText( + """ + apiURL: http://localhost/api/graphql + apiKey: abcd + """.trimIndent() + ) + } + return + } + this.properties.load(file.reader()) + logger.info("Found config ${filename}") + foundFile = true + } catch (e: Exception) { + this.logger.warning("Error loading ${filename}") + } + + if (!foundFile) { + return + } + try { + this.ApiURL = this.getProperty("apiURL").toString() + this.ApiKey = this.getProperty("apiKey").toString() + } catch (e: Exception) { + this.logger.severe("Error loading config") + } + } + + private fun getProperty(key: String): String? { + return this.properties.getProperty(key) + } +} \ No newline at end of file diff --git a/src/main/kotlin/de/sh_edraft/data/DataService.kt b/src/main/kotlin/de/sh_edraft/data/DataService.kt new file mode 100644 index 0000000..130f5d0 --- /dev/null +++ b/src/main/kotlin/de/sh_edraft/data/DataService.kt @@ -0,0 +1,94 @@ +package de.sh_edraft.data + +import de.sh_edraft.config.Config +import java.net.URI +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse +import java.util.logging.Logger +import org.json.JSONObject + +class DataService( + private val logger: Logger, + private val config: Config +) { + + private fun getUserJoinedMutation(id: String): String { + return JSONObject( + """ + { + "query": "mutation { userJoinedGameServer { userJoined(input: { ident: \"$id\" }) { id } } }" + } + """.trimIndent() + ).toString() + } + + private fun getUserLeftMutation(id: String): String { + return JSONObject( + """ + { + "query": "mutation { userJoinedGameServer { userLeft(input: { ident: \"$id\" }) { id } } }" + } + """.trimIndent() + ).toString() + } + + fun getPlayerGlobalId(name: String): String? { + val client = HttpClient.newBuilder().build(); + val request = HttpRequest.newBuilder() + .uri(URI.create("https://api.mojang.com/users/profiles/minecraft/$name")) + .build(); + + val response = client.send(request, HttpResponse.BodyHandlers.ofString()).body() ?: return null; + val json = JSONObject(response) + return json.getString("id"); + } + + fun sendJoinedPlayer(id: String) { + val client = HttpClient.newBuilder().build(); + + val request = HttpRequest.newBuilder() + .uri(URI.create(this.config.ApiURL)) + .POST(HttpRequest.BodyPublishers.ofString(this.getUserJoinedMutation(id))) + .header("Authorization", "API-Key ${this.config.ApiKey}") + .header("Content-Type", "application/json") + .build(); + + val response = client.send(request, HttpResponse.BodyHandlers.ofString()); + try { + // check if response is valid + val joinId = JSONObject(response.body()) + .getJSONObject("data") + .getJSONObject("userJoinedGameServer") + .getJSONObject("userJoined") + .getString("id") + .toIntOrNull(); + } catch (e: Exception) { + logger.severe(e.message); + } + } + + fun sendLeftPlayer(id: String) { + val client = HttpClient.newBuilder().build(); + + val request = HttpRequest.newBuilder() + .uri(URI.create(this.config.ApiURL)) + .POST(HttpRequest.BodyPublishers.ofString(this.getUserLeftMutation(id))) + .header("Authorization", "API-Key ${this.config.ApiKey}") + .header("Content-Type", "application/json") + .build(); + + val response = client.send(request, HttpResponse.BodyHandlers.ofString()); + try { + // check if response is valid + val joinId = JSONObject(response.body()) + .getJSONObject("data") + .getJSONObject("userJoinedGameServer") + .getJSONObject("userJoined") + .getString("id") + .toIntOrNull(); + } catch (e: Exception) { + logger.severe(e.message); + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/de/sh_edraft/events/OnJoinListener.kt b/src/main/kotlin/de/sh_edraft/events/OnJoinListener.kt new file mode 100644 index 0000000..e15a711 --- /dev/null +++ b/src/main/kotlin/de/sh_edraft/events/OnJoinListener.kt @@ -0,0 +1,21 @@ +package de.sh_edraft.events + +import de.sh_edraft.data.DataService +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.player.PlayerJoinEvent +import java.util.logging.Logger + +class OnJoinListener( + private val logger: Logger, + private val dataService: DataService +) : Listener { + @EventHandler + fun onPlayerJoin(p: PlayerJoinEvent) { + if (p.player.player == null) { + return; + } + val playerId = this.dataService.getPlayerGlobalId(p.player.player!!.displayName) ?: return; + this.dataService.sendJoinedPlayer(playerId); + } +} \ No newline at end of file diff --git a/src/main/kotlin/de/sh_edraft/events/OnLeftListener.kt b/src/main/kotlin/de/sh_edraft/events/OnLeftListener.kt new file mode 100644 index 0000000..8f02336 --- /dev/null +++ b/src/main/kotlin/de/sh_edraft/events/OnLeftListener.kt @@ -0,0 +1,33 @@ +package de.sh_edraft.events + +import de.sh_edraft.data.DataService +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.player.PlayerEvent +import org.bukkit.event.player.PlayerKickEvent +import org.bukkit.event.player.PlayerQuitEvent +import java.util.logging.Logger + +class OnLeftListener( + private val logger: Logger, + private val dataService: DataService +) : Listener { + + private fun handleQuit(p: PlayerEvent) { + if (p.player.player == null) { + return; + } + val playerId = this.dataService.getPlayerGlobalId(p.player.player!!.displayName) ?: return; + this.dataService.sendLeftPlayer(playerId); + } + + @EventHandler + fun onPlayerQuit(p: PlayerQuitEvent) { + this.handleQuit(p) + } + + @EventHandler + fun onPlayerKick(p: PlayerKickEvent) { + this.handleQuit(p) + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..873804b --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,3 @@ +name: sh_edraft.OntimeHandlerPlugin +version: 1.0 +main: de.sh_edraft.OntimeHandlerPlugin \ No newline at end of file diff --git a/target/classes/META-INF/kd_ontime_handler_spigot.kotlin_module b/target/classes/META-INF/kd_ontime_handler_spigot.kotlin_module deleted file mode 100644 index 4e7592e..0000000 Binary files a/target/classes/META-INF/kd_ontime_handler_spigot.kotlin_module and /dev/null differ diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties deleted file mode 100644 index a173de2..0000000 --- a/target/maven-archiver/pom.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Generated by Maven -#Thu Jan 12 20:27:56 CET 2023 -groupId=de.sh-edraft -artifactId=kd_ontime_handler_spigot -version=1.0-SNAPSHOT diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst deleted file mode 100644 index e69de29..0000000 diff --git a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst deleted file mode 100644 index e69de29..0000000