basic 2-way communication

This commit is contained in:
leca 2025-02-05 23:02:39 +03:00
parent 51d1f14cd8
commit 4820ac5e04
8 changed files with 180 additions and 6 deletions

44
pom.xml
View File

@ -14,6 +14,7 @@
<properties> <properties>
<java.version>17</java.version> <java.version>17</java.version>
<kotlin.version>2.1.20-Beta2</kotlin.version> <kotlin.version>2.1.20-Beta2</kotlin.version>
<serialization.version>1.8.0</serialization.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
@ -21,6 +22,42 @@
<defaultGoal>clean package</defaultGoal> <defaultGoal>clean package</defaultGoal>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory> <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>copy-plugin</id>
<phase>install</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<copy file="${project.build.directory}/${project.build.finalName}.jar"
todir="/home/leca/Downloads/test-server/plugins"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
<!-- <plugin>-->
<!-- <groupId>org.apache.maven.plugins</groupId>-->
<!-- <artifactId>maven-shade-plugin</artifactId>-->
<!-- <version>3.2.4</version> &lt;!&ndash; Use the latest version &ndash;&gt;-->
<!-- <executions>-->
<!-- <execution>-->
<!-- <phase>package</phase>-->
<!-- <goals>-->
<!-- <goal>shade</goal>-->
<!-- </goals>-->
<!-- <configuration>-->
<!-- <createDependencyReducedPom>false</createDependencyReducedPom>-->
<!-- </configuration>-->
<!-- </execution>-->
<!-- </executions>-->
<!-- </plugin>-->
<plugin> <plugin>
<groupId>org.jetbrains.kotlin</groupId> <groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId> <artifactId>kotlin-maven-plugin</artifactId>
@ -83,5 +120,12 @@
<artifactId>kotlin-stdlib-jdk8</artifactId> <artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version> <version>${kotlin.version}</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>3.9.0</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,4 +1,25 @@
package org.foxarmy.chatProxy package org.foxarmy.chatProxy
class ChatListener { import com.google.gson.Gson
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.AsyncPlayerChatEvent
import org.bukkit.plugin.java.JavaPlugin
import java.time.Instant
class ChatListener(private val kafkaClient: KafkaClient) : Listener{
@EventHandler
fun onChat(event: AsyncPlayerChatEvent) {
val player = event.player
val message = event.message
val timestamp = Instant.now().epochSecond
val data = MessageJson(player.name, message, "server", timestamp)
val gson = Gson()
val gsonData = gson.toJson(data)
kafkaClient.sendData(gsonData)
}
} }

View File

@ -5,7 +5,15 @@ import org.bukkit.plugin.java.JavaPlugin
class ChatProxy : JavaPlugin() { class ChatProxy : JavaPlugin() {
override fun onEnable() { override fun onEnable() {
// Plugin startup logic saveDefaultConfig()
reloadConfig()
val kafkaClient = KafkaClient(this, config.getStringList("kafkaBrokers"))
server.pluginManager.registerEvents(ChatListener(kafkaClient), this)
this.getCommand("chatproxy")?.setExecutor(Commands(this))
} }
override fun onDisable() { override fun onDisable() {

View File

@ -1,4 +1,35 @@
package org.foxarmy.chatProxy package org.foxarmy.chatProxy
class Commands { import org.bukkit.command.Command
import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender
import org.bukkit.plugin.java.JavaPlugin
import java.util.*
class Commands(private val plugin: JavaPlugin) : CommandExecutor {
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
if (!sender.hasPermission("chatproxy.use")) {
sender.sendMessage("You do not have permission to use this command.")
return true
}
if (args.isEmpty()) {
sender.sendMessage("Usage: /chatproxy <subcommand>")
return true
}
when (args[0].lowercase(Locale.getDefault())) {
"reload" -> {
reloadConfig(sender)
return true
}
else -> {
sender.sendMessage("Unknown subcommand. Usage: /chatproxy <reload>")
return true
}
}
}
private fun reloadConfig(sender: CommandSender) {
plugin.reloadConfig()
sender.sendMessage("Configuration reloaded successfully.")
}
} }

View File

@ -1,4 +1,60 @@
package org.foxarmy.chatProxy package org.foxarmy.chatProxy
class KafkaClient { import com.google.gson.Gson
import org.apache.kafka.clients.consumer.Consumer
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.clients.consumer.ConsumerRecords
import org.apache.kafka.clients.consumer.KafkaConsumer
import org.apache.kafka.clients.producer.KafkaProducer
import org.apache.kafka.clients.producer.Producer
import org.apache.kafka.clients.producer.ProducerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.kafka.common.serialization.StringSerializer
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.event.player.AsyncPlayerChatEvent
import org.bukkit.plugin.java.JavaPlugin
import java.time.Duration
import java.util.*
class KafkaClient(plugin: JavaPlugin, brokers: List<String>) {
private val consumer: Consumer<String, String>
private val producer: Producer<String, String>
init {
Thread.currentThread().contextClassLoader = null;
val props = Properties()
props["bootstrap.servers"] = brokers
props["group.id"] = "chat-listener"
props["key.deserializer"] = StringDeserializer::class.java.name
props["value.deserializer"] = StringDeserializer::class.java.name
props["key.serializer"] = StringSerializer::class.java.canonicalName
props["value.serializer"] = StringSerializer::class.java.canonicalName
producer = KafkaProducer<String, String>(props)
consumer = KafkaConsumer<String, String>(props)
consumer.subscribe(listOf("chatMessage"))
listenForMessages(plugin)
}
private fun listenForMessages(plugin: JavaPlugin) {
Bukkit.getScheduler().runTaskTimer(
plugin, Runnable {
val records: ConsumerRecords<String, String> = consumer.poll(Duration.ofMillis(100))
for (record: ConsumerRecord<String, String> in records) {
val recordJSON = Gson().fromJson(record.value(), MessageJson::class.java)
if (recordJSON.origin == "server") continue
Bukkit.broadcastMessage("<${recordJSON.author}> ${recordJSON.content}")
recordJSON.origin = "server"
sendData(recordJSON.toString())
}
}, 0L, 20L
)
}
fun sendData(data: String) {
val futureResult = producer.send(ProducerRecord<String, String>("chatMessage", data))
}
} }

View File

@ -1,4 +1,3 @@
package org.foxarmy.chatProxy package org.foxarmy.chatProxy
class MessageJson { data class MessageJson(val author: String, val content: String, var origin: String, val timestamp: Long)
}

View File

@ -0,0 +1,3 @@
kafkaBrokers:
- localhost:9092
- kafka:9092

View File

@ -6,3 +6,15 @@ prefix: Chatproxy
authors: [ leca ] authors: [ leca ]
description: Plugin for proxying chat messages from mc server to site description: Plugin for proxying chat messages from mc server to site
website: https://git.foxarmy.org/leca/Chatproxy website: https://git.foxarmy.org/leca/Chatproxy
commands:
chatproxy:
description: Chat proxy commands
usage: /<command> <subcommand>
aliases: [ cprox ]
permission: chatproxy.use
permission-message: You do not have permission to use this command.
reload:
description: Reload plugin's configuration
usage: /<command> reload
permission: chatproxy.reload
permission-message: You do not have permission to reload configuration.