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
+
+
+
+ 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