♻️ Optimize code by Gemini 3 Pro

This commit is contained in:
2025-12-07 17:24:38 +08:00
parent 80d58ea4e2
commit a33f1364b4
6 changed files with 258 additions and 273 deletions

View File

@@ -12,7 +12,13 @@ import dev.solsynth.snConnect.models.SnChatMessage
import dev.solsynth.snConnect.models.WebSocketPacket
import dev.solsynth.snConnect.services.SnMessageService
import dev.solsynth.snConnect.services.SnService
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import net.md_5.bungee.api.ChatColor
import net.md_5.bungee.api.chat.ClickEvent
import net.md_5.bungee.api.chat.ComponentBuilder
@@ -24,9 +30,12 @@ import org.bukkit.Bukkit.getOnlinePlayers
import org.bukkit.configuration.file.YamlConfiguration
import org.bukkit.plugin.java.JavaPlugin
import java.io.InputStreamReader
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
class SolarNetworkConnect : JavaPlugin() {
private val pluginScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
private var economy: Economy? = null
private var sn: SnService? = null
private var authService: AuthService? = null
@@ -34,9 +43,8 @@ class SolarNetworkConnect : JavaPlugin() {
private var messageService: SnMessageService? = null
private var syncChatRooms: List<String> = emptyList()
private var destinationChatId: String? = null
private var webSocketJob: Job? = null
private var messages: Map<String, String> = mapOf()
private var playerSolarpassMap: MutableMap<String, String?> = mutableMapOf()
private var playerSolarpassMap: ConcurrentHashMap<UUID, String?> = ConcurrentHashMap()
private fun handleWebSocketPacket(packet: WebSocketPacket) {
if (config.getBoolean("debug"))
@@ -74,9 +82,11 @@ class SolarNetworkConnect : JavaPlugin() {
}
}
val component = componentBuilder.create()
for (player in getOnlinePlayers()) {
player.spigot().sendMessage(*component)
}
Bukkit.getScheduler().runTask(this, Runnable {
for (player in getOnlinePlayers()) {
player.spigot().sendMessage(*component)
}
})
}
}
}
@@ -109,17 +119,17 @@ class SolarNetworkConnect : JavaPlugin() {
}
if (messageService != null && destinationChatId != null) {
server.pluginManager.registerEvents(SnChatListener(messageService!!, destinationChatId!!, messages), this)
server.pluginManager.registerEvents(SnChatListener(pluginScope, messageService!!, destinationChatId!!, messages), this)
}
if (authUserService != null) {
server.pluginManager.registerEvents(
SolarpassCheckListener(authUserService!!, messages, playerSolarpassMap),
SolarpassCheckListener(pluginScope, authUserService!!, messages, playerSolarpassMap),
this
)
}
Bukkit.getPluginCommand("solar")!!.setExecutor(SnCommand(this.sn!!, this.economy, messages, playerSolarpassMap))
Bukkit.getPluginCommand("solar")!!.setExecutor(SnCommand(this, pluginScope, this.sn!!, this.economy, messages, playerSolarpassMap))
Bukkit.getPluginCommand("solar")!!.tabCompleter = SnCommandCompleter()
Bukkit.getPluginCommand("eatrock")!!.setExecutor(BedrockRemoverCommand(this.economy))
@@ -135,7 +145,9 @@ class SolarNetworkConnect : JavaPlugin() {
// Send server start message
try {
destinationChatId?.let { chatId ->
messageService?.sendMessage(chatId, messages["server_start"] ?: "🚀 Server started successfully")
pluginScope.launch {
messageService?.sendMessage(chatId, messages["server_start"] ?: "🚀 Server started successfully")
}
}
} catch (e: Exception) {
logger.warning("Failed to send server start message: ${e.message}")
@@ -148,14 +160,16 @@ class SolarNetworkConnect : JavaPlugin() {
// Send server stop message
try {
destinationChatId?.let { chatId ->
messageService?.sendMessage(chatId, messages["server_stop"] ?: "⏹️ Server stopped")
pluginScope.launch {
messageService?.sendMessage(chatId, messages["server_stop"] ?: "⏹️ Server stopped")
}
}
} catch (e: Exception) {
logger.warning("Failed to send server stop message: ${e.message}")
}
sn?.disconnect()
webSocketJob?.cancel()
pluginScope.cancel()
}
private fun setupNetwork(): Boolean {
@@ -175,11 +189,19 @@ class SolarNetworkConnect : JavaPlugin() {
authService = AuthService(authUrl, siteSecret);
authUserService = AuthUserService(authService!!)
webSocketJob = GlobalScope.launch {
pluginScope.launch {
sn!!.connectWebSocketAsFlow().collect { packet ->
handleWebSocketPacket(packet)
}
}
pluginScope.launch {
while(isActive) {
delay(60000)
sn?.sendPing()
}
}
return true;
}

View File

@@ -14,11 +14,11 @@ import org.bukkit.inventory.ItemStack
class BedrockRemoverCommand(private val economy: Economy?) : CommandExecutor {
private val paymentMethods = listOf("money", "materials")
private val requiredMaterials = listOf(
Material.PISTON,
Material.TNT,
Material.LEVER,
Material.OAK_TRAPDOOR // Representative for trapdoor group
private val requiredMaterials = mapOf(
Material.PISTON to 1,
Material.TNT to 1,
Material.LEVER to 1,
Material.OAK_TRAPDOOR to 1
)
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
@@ -27,41 +27,30 @@ class BedrockRemoverCommand(private val economy: Economy?) : CommandExecutor {
return true
}
if (args.isEmpty() || args.size > 1) {
sender.sendMessage(ChatColor.RED.toString() + "Usage: /bedrockremove <money/materials>")
if (args.size != 1 || args[0].lowercase() !in paymentMethods) {
sender.sendMessage(ChatColor.RED.toString() + "Usage: /bedrockremove <money|materials>")
return true
}
val paymentMethod = args[0].lowercase()
if (paymentMethod !in paymentMethods) {
sender.sendMessage(ChatColor.RED.toString() + "Invalid payment method. Use: money or materials.")
return true
}
// Get the block the player is looking at
val targetBlock = sender.getTargetBlock(null, 10)
if (targetBlock == null || targetBlock.type != Material.BEDROCK) {
if (targetBlock?.type != Material.BEDROCK) {
sender.sendMessage(ChatColor.RED.toString() + "You must be looking at a bedrock block within 10 blocks.")
return true
}
// Attempt payment
val paymentMethod = args[0].lowercase()
val success = when (paymentMethod) {
"money" -> payWithMoney(sender, 100.0)
"materials" -> payWithAllMaterials(sender)
else -> return false
"materials" -> payWithMaterials(sender)
else -> false
}
if (!success) {
// Error messages are handled in the pay methods
return true
if (success) {
targetBlock.type = Material.AIR
sender.sendMessage(ChatColor.GREEN.toString() + "Bedrock removed successfully!")
sender.playSound(sender.location, Sound.BLOCK_STONE_BREAK, 1.0f, 1.0f)
}
// Remove the bedrock
targetBlock.type = Material.AIR
sender.sendMessage(ChatColor.GREEN.toString() + "Bedrock removed successfully!")
sender.playSound(sender.location, Sound.BLOCK_STONE_BREAK, 1.0f, 1.0f)
return true
}
@@ -70,136 +59,72 @@ class BedrockRemoverCommand(private val economy: Economy?) : CommandExecutor {
player.sendMessage(ChatColor.RED.toString() + "Economy not available.")
return false
}
val response = economy.withdrawPlayer(player, "Bedrock removal", amount)
val response = economy.withdrawPlayer(player, amount)
if (response.type != EconomyResponse.ResponseType.SUCCESS) {
player.sendMessage(ChatColor.RED.toString() + "Insufficient funds. You need ${amount}.")
player.sendMessage(ChatColor.RED.toString() + "Insufficient funds. You need ${economy.format(amount)}.")
return false
}
player.sendMessage(ChatColor.GREEN.toString() + "Withdrew $amount from your account.")
player.sendMessage(ChatColor.GREEN.toString() + "Withdrew ${economy.format(amount)} from your account.")
return true
}
private fun payWithMaterial(player: Player, material: Material): Boolean {
private fun payWithMaterials(player: Player): Boolean {
val inventory = player.inventory
val itemsToRemove = mutableListOf<ItemStack>()
// Special handling for materials with multiple variants
val hasItem = when (material) {
Material.OAK_TRAPDOOR -> {
// Check for any trapdoor type
inventory.contents.any { item -> item != null && item.type.name.endsWith("_TRAPDOOR") }
}
Material.PISTON -> {
// Check for any piston type
inventory.contents.any { item -> item != null && (item.type == Material.PISTON || item.type == Material.STICKY_PISTON) }
}
else -> inventory.contains(material, 1)
}
if (!hasItem) {
player.sendMessage(ChatColor.RED.toString() + "You don't have a ${material.name.lowercase()} in your inventory.")
return false
}
// Remove the item
when (material) {
Material.OAK_TRAPDOOR -> {
// Find and remove any trapdoor
for (item in inventory.contents) {
if (item != null && item.type.name.endsWith("_TRAPDOOR")) {
val amount = item.amount
if (amount > 1) {
item.amount = amount - 1
} else {
inventory.remove(item)
}
break
}
}
}
Material.PISTON -> {
// Find and remove any piston
for (item in inventory.contents) {
if (item != null && (item.type == Material.PISTON || item.type == Material.STICKY_PISTON)) {
val amount = item.amount
if (amount > 1) {
item.amount = amount - 1
} else {
inventory.remove(item)
}
break
}
}
}
else -> {
inventory.removeItem(ItemStack(material, 1))
}
}
player.sendMessage(ChatColor.GREEN.toString() + "Consumed 1 ${material.name.lowercase()}.")
return true
}
private fun payWithAllMaterials(player: Player): Boolean {
val inventory = player.inventory
// Check if player has all required materials
for (material in requiredMaterials) {
val hasItem = when (material) {
Material.OAK_TRAPDOOR -> {
// Check for any trapdoor type
inventory.contents.any { item -> item != null && item.type.name.endsWith("_TRAPDOOR") }
}
Material.PISTON -> {
// Check for any piston type
inventory.contents.any { item -> item != null && (item.type == Material.PISTON || item.type == Material.STICKY_PISTON) }
}
else -> inventory.contains(material, 1)
}
if (!hasItem) {
player.sendMessage(ChatColor.RED.toString() + "You don't have all required materials: piston, tnt, lever, and trapdoor.")
for ((material, amount) in requiredMaterials) {
val foundItems = findRequiredItems(inventory, material, amount)
if (foundItems == null) {
player.sendMessage(ChatColor.RED.toString() + "You don't have all required materials: piston, TNT, lever, and a trapdoor.")
return false
}
itemsToRemove.addAll(foundItems)
}
// Remove one of each material
for (material in requiredMaterials) {
when (material) {
Material.OAK_TRAPDOOR -> {
// Find and remove any trapdoor
for (item in inventory.contents) {
if (item != null && item.type.name.endsWith("_TRAPDOOR")) {
val amount = item.amount
if (amount > 1) {
item.amount = amount - 1
} else {
inventory.remove(item)
}
break
}
}
}
Material.PISTON -> {
// Find and remove any piston
for (item in inventory.contents) {
if (item != null && (item.type == Material.PISTON || item.type == Material.STICKY_PISTON)) {
val amount = item.amount
if (amount > 1) {
item.amount = amount - 1
} else {
inventory.remove(item)
}
break
}
}
}
else -> {
inventory.removeItem(ItemStack(material, 1))
}
// This check-then-act approach has a potential race condition if the player
// modifies their inventory between the check and the removal. For this plugin,
// the risk is low, but in a more critical system, a more robust transactional
// approach would be needed.
inventory.removeItem(*itemsToRemove.toTypedArray())
player.sendMessage(ChatColor.GREEN.toString() + "Consumed materials: piston, TNT, lever, trapdoor.")
return true
}
private fun findRequiredItems(inventory: org.bukkit.inventory.Inventory, material: Material, requiredAmount: Int): List<ItemStack>? {
val foundItems = mutableListOf<ItemStack>()
var amountFound = 0
for (item in inventory.contents) {
if (item != null && isMaterialMatch(item.type, material)) {
amountFound += item.amount
foundItems.add(item)
}
}
player.sendMessage(ChatColor.GREEN.toString() + "Consumed materials: piston, tnt, lever, trapdoor.")
return true
if (amountFound >= requiredAmount) {
// We have enough, now determine the exact stacks to remove
val toRemove = mutableListOf<ItemStack>()
var amountToRemove = requiredAmount
for (item in foundItems) {
val itemClone = item.clone()
if (amountToRemove <= 0) break
val amountFromThisStack = itemClone.amount.coerceAtMost(amountToRemove)
itemClone.amount = amountFromThisStack
toRemove.add(itemClone)
amountToRemove -= amountFromThisStack
}
return toRemove
}
return null
}
private fun isMaterialMatch(itemType: Material, requiredMaterial: Material): Boolean {
return when (requiredMaterial) {
Material.OAK_TRAPDOOR -> itemType.name.endsWith("_TRAPDOOR")
Material.PISTON -> itemType == Material.PISTON || itemType == Material.STICKY_PISTON
else -> itemType == requiredMaterial
}
}
}
@@ -212,9 +137,10 @@ class BedrockRemoverCompleter : TabCompleter {
label: String,
args: Array<out String>
): MutableList<String> {
return when (args.size) {
1 -> paymentMethods.filter { it.startsWith(args[0], ignoreCase = true) }.toMutableList()
else -> mutableListOf()
return if (args.size == 1) {
paymentMethods.filter { it.startsWith(args[0], ignoreCase = true) }.toMutableList()
} else {
mutableListOf()
}
}
}

View File

@@ -1,11 +1,12 @@
package dev.solsynth.snConnect.commands
import dev.solsynth.snConnect.services.*
import kotlinx.coroutines.CoroutineScope
import net.md_5.bungee.api.chat.ClickEvent
import net.md_5.bungee.api.chat.TextComponent
import net.milkbowl.vault.economy.Economy
import net.milkbowl.vault.economy.EconomyResponse
import org.bukkit.Bukkit.getLogger
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Sound
import org.bukkit.command.Command
@@ -13,12 +14,18 @@ import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender
import org.bukkit.command.TabCompleter
import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import kotlinx.coroutines.launch
class SnCommand(
private val plugin: JavaPlugin,
private val pluginScope: CoroutineScope,
private val sn: SnService,
private val eco: Economy?,
private val messages: Map<String, String>,
private val playerSolarpassMap: MutableMap<String, String?>
private val playerSolarpassMap: ConcurrentHashMap<UUID, String?>
) :
CommandExecutor {
override fun onCommand(p0: CommandSender, p1: Command, p2: String, p3: Array<out String>): Boolean {
@@ -48,42 +55,45 @@ class SnCommand(
?: "Confirming payment, please stand by...")
);
val order: SnOrder
try {
order = orderSrv.getOrder(orderNumber);
// The update validated the order is created by us
orderSrv.updateOrderStatus(orderNumber, false);
} catch (_: Exception) {
p0.sendMessage(
ChatColor.RED.toString() + (messages["command_deposit_pull_error"]
?: "An error occurred while pulling transaction. Make sure the order exists then try again later.")
)
return true;
pluginScope.launch {
try {
val order = orderSrv.getOrder(orderNumber);
// The update validated the order is created by us
orderSrv.updateOrderStatus(orderNumber, false);
Bukkit.getScheduler().runTask(plugin, Runnable {
if (order.status != 1L) {
p0.sendMessage(
ChatColor.RED.toString() + (messages["command_deposit_order_not_paid"]
?: "Order was not paid yet.")
)
return@Runnable
}
val bal = order.amount;
eco?.depositPlayer(p0, bal)
val doneComponent =
TextComponent(ChatColor.GREEN.toString() + (messages["command_deposit_done"] ?: "Done!"))
val moneyComponent = TextComponent(ChatColor.GOLD.toString() + ChatColor.BOLD + " $bal$")
val suffixComponent =
TextComponent(
ChatColor.GREEN.toString() + (messages["command_deposit_added_balance"]
?: " has been added to your balance.")
)
p0.playSound(p0.location, Sound.BLOCK_ANVIL_PLACE, 1.0F, 1.0F)
p0.spigot().sendMessage(doneComponent, moneyComponent, suffixComponent)
})
} catch (_: Exception) {
Bukkit.getScheduler().runTask(plugin, Runnable {
p0.sendMessage(
ChatColor.RED.toString() + (messages["command_deposit_pull_error"]
?: "An error occurred while pulling transaction. Make sure the order exists then try again later.")
)
})
}
}
if (order.status != 1L) {
p0.sendMessage(
ChatColor.RED.toString() + (messages["command_deposit_order_not_paid"]
?: "Order was not paid yet.")
)
return true;
}
val bal = order.amount;
eco?.depositPlayer(p0.player, bal)
val doneComponent =
TextComponent(ChatColor.GREEN.toString() + (messages["command_deposit_done"] ?: "Done!"))
val moneyComponent = TextComponent(ChatColor.GOLD.toString() + ChatColor.BOLD + " $bal$")
val suffixComponent =
TextComponent(
ChatColor.GREEN.toString() + (messages["command_deposit_added_balance"]
?: " has been added to your balance.")
)
p0.playSound(p0.player!!, Sound.BLOCK_ANVIL_PLACE, 1.0F, 1.0F)
p0.spigot().sendMessage(doneComponent, moneyComponent, suffixComponent)
return true;
}
@@ -102,44 +112,47 @@ class SnCommand(
?: "Creating order, please stand by...")
);
val order: SnOrder
try {
order = orderSrv.createOrder("Deposit to GoatCraft", amount);
} catch (e: Exception) {
p0.sendMessage(
ChatColor.RED.toString() + (messages["command_deposit_create_error"]
?: "An error occurred while creating order. Try again later.")
)
e.printStackTrace();
return true;
pluginScope.launch {
try {
val order = orderSrv.createOrder("Deposit to GoatCraft", amount);
Bukkit.getScheduler().runTask(plugin, Runnable {
val linkComponent =
TextComponent(
ChatColor.GOLD.toString() + ChatColor.UNDERLINE.toString() + ChatColor.BOLD.toString() + (messages["command_deposit_click_here"]
?: "click here")
)
linkComponent.clickEvent =
ClickEvent(ClickEvent.Action.OPEN_URL, "https://solian.app/orders/${order.id}");
val orderHintComponent =
TextComponent(
ChatColor.GRAY.toString() + (messages["command_deposit_order_created"]
?: "Order created, number ") + ChatColor.WHITE + ChatColor.BOLD + "#${order.id.take(6)}" + " "
)
val followingComponent = TextComponent(
ChatColor.GRAY.toString() + (messages["command_deposit_to_payment_page"] ?: " to the payment page.")
)
p0.spigot()
.sendMessage(orderHintComponent, linkComponent, followingComponent);
val afterPaidComponent =
TextComponent(
ChatColor.UNDERLINE.toString() + ChatColor.YELLOW + (messages["command_deposit_after_paid"]
?: "After you paid, click here to confirm payment.")
)
afterPaidComponent.clickEvent =
ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sn deposit confirm ${order.id}")
p0.spigot().sendMessage(afterPaidComponent);
})
} catch (e: Exception) {
Bukkit.getScheduler().runTask(plugin, Runnable {
p0.sendMessage(
ChatColor.RED.toString() + (messages["command_deposit_create_error"]
?: "An error occurred while creating order. Try again later.")
)
e.printStackTrace();
})
}
}
val linkComponent =
TextComponent(
ChatColor.GOLD.toString() + ChatColor.UNDERLINE.toString() + ChatColor.BOLD.toString() + (messages["command_deposit_click_here"]
?: "click here")
)
linkComponent.clickEvent =
ClickEvent(ClickEvent.Action.OPEN_URL, "https://solian.app/orders/${order.id}");
val orderHintComponent =
TextComponent(
ChatColor.GRAY.toString() + (messages["command_deposit_order_created"]
?: "Order created, number ") + ChatColor.WHITE + ChatColor.BOLD + "#${order.id.take(6)}" + " "
)
val followingComponent = TextComponent(
ChatColor.GRAY.toString() + (messages["command_deposit_to_payment_page"] ?: " to the payment page.")
)
p0.spigot()
.sendMessage(orderHintComponent, linkComponent, followingComponent);
val afterPaidComponent =
TextComponent(
ChatColor.UNDERLINE.toString() + ChatColor.YELLOW + (messages["command_deposit_after_paid"]
?: "After you paid, click here to confirm payment.")
)
afterPaidComponent.clickEvent =
ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sn deposit confirm ${order.id}")
p0.spigot().sendMessage(afterPaidComponent);
}
"withdraw" -> {
@@ -160,7 +173,7 @@ class SnCommand(
return true;
}
val playerUuid = p0.uniqueId.toString()
val playerUuid = p0.uniqueId
val accountId = playerSolarpassMap[playerUuid]
if (accountId == null) {
p0.sendMessage(
@@ -176,7 +189,7 @@ class SnCommand(
// Takes extra 20% as fee
val fee = amount * 0.2;
val resp = eco?.withdrawPlayer(p0.player, amount + fee);
val resp = eco?.withdrawPlayer(p0, amount + fee);
if (resp?.type != EconomyResponse.ResponseType.SUCCESS) {
p0.sendMessage(
ChatColor.RED.toString() + (messages["command_withdraw_no_money"]
@@ -185,25 +198,31 @@ class SnCommand(
return true;
}
try {
val transactionSrv = SnBalanceService(sn);
transactionSrv.addBalance(amount, "Withdraw from GoatCraft", accountId);
val transactionHintComponent =
TextComponent(
ChatColor.GREEN.toString() + (messages["command_withdraw_done"]
?: "Done! ")
)
pluginScope.launch {
try {
val transactionSrv = SnBalanceService(sn);
transactionSrv.addBalance(amount, "Withdraw from GoatCraft", accountId);
p0.playSound(p0.player!!, Sound.BLOCK_ANVIL_PLACE, 1.0F, 1.0F)
p0.spigot().sendMessage(transactionHintComponent)
} catch (e: Exception) {
eco.depositPlayer(p0.player, amount + fee)
p0.sendMessage(
ChatColor.RED.toString() + (messages["command_withdraw_error"]
?: "An error occurred while making transaction. Make sure your wallet exists then try again later.")
)
e.printStackTrace()
return true
Bukkit.getScheduler().runTask(plugin, Runnable {
val transactionHintComponent =
TextComponent(
ChatColor.GREEN.toString() + (messages["command_withdraw_done"]
?: "Done! ")
)
p0.playSound(p0.location, Sound.BLOCK_ANVIL_PLACE, 1.0F, 1.0F)
p0.spigot().sendMessage(transactionHintComponent)
})
} catch (e: Exception) {
Bukkit.getScheduler().runTask(plugin, Runnable {
eco.depositPlayer(p0, amount + fee)
p0.sendMessage(
ChatColor.RED.toString() + (messages["command_withdraw_error"]
?: "An error occurred while making transaction. Make sure your wallet exists then try again later.")
)
e.printStackTrace()
})
}
}
}

View File

@@ -1,19 +1,18 @@
package dev.solsynth.snConnect.listeners
import com.Zrips.CMI.CMI
import dev.solsynth.snConnect.services.SnMessageService
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.entity.PlayerDeathEvent
import org.bukkit.event.player.AsyncPlayerChatEvent
import org.bukkit.event.player.PlayerAdvancementDoneEvent
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerQuitEvent
class SnChatListener(
private val pluginScope: CoroutineScope,
private val messageService: SnMessageService,
private val destinationChatId: String,
private val messages: Map<String, String>
@@ -21,31 +20,38 @@ class SnChatListener(
@EventHandler(priority = EventPriority.MONITOR)
fun onPlayerChat(event: AsyncPlayerChatEvent) {
val message = "${event.player.name}: ${event.message}"
messageService.sendMessage(destinationChatId, message)
pluginScope.launch {
messageService.sendMessage(destinationChatId, message)
}
}
@Suppress("SENSELESS_COMPARISON")
@EventHandler()
fun onPlayerJoin(event: PlayerJoinEvent) {
val firstTime = Bukkit.getOfflinePlayer(event.player.uniqueId) == null;
val templateKey = if (!firstTime) "join" else "join_first";
val firstTime = !event.player.hasPlayedBefore();
val templateKey = if (firstTime) "join_first" else "join";
val template = messages[templateKey]
?: if (!firstTime) "➡️ {player} joined the game." else "➡️ {player} first time joined the game."
?: if (firstTime) "➡️ {player} first time joined the game." else "➡️ {player} joined the game."
val message = template.replace("{player}", event.player.name)
messageService.sendMessage(destinationChatId, message)
pluginScope.launch {
messageService.sendMessage(destinationChatId, message)
}
}
@EventHandler()
fun onPlayerQuit(event: PlayerQuitEvent) {
val template = messages["quit"] ?: "⬅️ {player} left the game."
val message = template.replace("{player}", event.player.name)
messageService.sendMessage(destinationChatId, message)
pluginScope.launch {
messageService.sendMessage(destinationChatId, message)
}
}
@EventHandler()
fun onPlayerDeath(event: PlayerDeathEvent) {
val template = messages["death"] ?: "💀 {player} {message}"
val template = messages["death"] ?: "💀 {message}"
val message = template.replace("{player}", event.entity.name).replace("{message}", event.deathMessage ?: "")
messageService.sendMessage(destinationChatId, message)
pluginScope.launch {
messageService.sendMessage(destinationChatId, message)
}
}
}

View File

@@ -1,33 +1,41 @@
package dev.solsynth.snConnect.listeners
import dev.solsynth.snConnect.services.AuthUserService
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerJoinEvent
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
class SolarpassCheckListener(
private val pluginScope: CoroutineScope,
private val authUserService: AuthUserService,
private val messages: Map<String, String>,
private val playerSolarpassMap: MutableMap<String, String?>
private val playerSolarpassMap: ConcurrentHashMap<UUID, String?>
) : Listener {
@EventHandler()
fun onPlayerJoin(event: PlayerJoinEvent) {
GlobalScope.launch {
pluginScope.launch {
try {
val playerUuid = event.player.uniqueId.toString()
var solarpassId = playerSolarpassMap[playerUuid]
if (solarpassId == null) {
solarpassId = authUserService.getSnByPlayer(playerUuid)
playerSolarpassMap[playerUuid] = solarpassId
val playerUuid = event.player.uniqueId
if (playerSolarpassMap.containsKey(playerUuid)) {
return@launch
}
val solarpassId = authUserService.getSnByPlayer(playerUuid.toString())
playerSolarpassMap[playerUuid] = solarpassId
if (solarpassId == null) {
// Send suggestion message
val message = messages["solarpass_bind_suggestion"] ?: "${ChatColor.YELLOW}To get more features, please bind your Solarpass account!"
event.player.sendMessage(message)
Bukkit.getScheduler().runTask(Bukkit.getPluginManager().getPlugin("SolarNetworkConnect")!!, Runnable {
event.player.sendMessage(message)
})
}
} catch (e: Exception) {
// Optionally log the error or handle it

View File

@@ -95,4 +95,8 @@ class SnService(private val baseUrl: String, val clientId: String, val clientSec
websocket?.close(1000, "Disconnecting")
websocket = null
}
fun sendPing() {
websocket?.send("{\"type\":\"ping\"}")
}
}