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

View File

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

View File

@@ -1,11 +1,12 @@
package dev.solsynth.snConnect.commands package dev.solsynth.snConnect.commands
import dev.solsynth.snConnect.services.* import dev.solsynth.snConnect.services.*
import kotlinx.coroutines.CoroutineScope
import net.md_5.bungee.api.chat.ClickEvent import net.md_5.bungee.api.chat.ClickEvent
import net.md_5.bungee.api.chat.TextComponent import net.md_5.bungee.api.chat.TextComponent
import net.milkbowl.vault.economy.Economy import net.milkbowl.vault.economy.Economy
import net.milkbowl.vault.economy.EconomyResponse import net.milkbowl.vault.economy.EconomyResponse
import org.bukkit.Bukkit.getLogger import org.bukkit.Bukkit
import org.bukkit.ChatColor import org.bukkit.ChatColor
import org.bukkit.Sound import org.bukkit.Sound
import org.bukkit.command.Command import org.bukkit.command.Command
@@ -13,12 +14,18 @@ import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender import org.bukkit.command.CommandSender
import org.bukkit.command.TabCompleter import org.bukkit.command.TabCompleter
import org.bukkit.entity.Player 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( class SnCommand(
private val plugin: JavaPlugin,
private val pluginScope: CoroutineScope,
private val sn: SnService, private val sn: SnService,
private val eco: Economy?, private val eco: Economy?,
private val messages: Map<String, String>, private val messages: Map<String, String>,
private val playerSolarpassMap: MutableMap<String, String?> private val playerSolarpassMap: ConcurrentHashMap<UUID, String?>
) : ) :
CommandExecutor { CommandExecutor {
override fun onCommand(p0: CommandSender, p1: Command, p2: String, p3: Array<out String>): Boolean { 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...") ?: "Confirming payment, please stand by...")
); );
val order: SnOrder pluginScope.launch {
try { try {
order = orderSrv.getOrder(orderNumber); val order = orderSrv.getOrder(orderNumber);
// The update validated the order is created by us // The update validated the order is created by us
orderSrv.updateOrderStatus(orderNumber, false); orderSrv.updateOrderStatus(orderNumber, false);
} catch (_: Exception) {
p0.sendMessage( Bukkit.getScheduler().runTask(plugin, Runnable {
ChatColor.RED.toString() + (messages["command_deposit_pull_error"] if (order.status != 1L) {
?: "An error occurred while pulling transaction. Make sure the order exists then try again later.") p0.sendMessage(
) ChatColor.RED.toString() + (messages["command_deposit_order_not_paid"]
return true; ?: "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; return true;
} }
@@ -102,44 +112,47 @@ class SnCommand(
?: "Creating order, please stand by...") ?: "Creating order, please stand by...")
); );
val order: SnOrder pluginScope.launch {
try { try {
order = orderSrv.createOrder("Deposit to GoatCraft", amount); val order = orderSrv.createOrder("Deposit to GoatCraft", amount);
} catch (e: Exception) { Bukkit.getScheduler().runTask(plugin, Runnable {
p0.sendMessage( val linkComponent =
ChatColor.RED.toString() + (messages["command_deposit_create_error"] TextComponent(
?: "An error occurred while creating order. Try again later.") ChatColor.GOLD.toString() + ChatColor.UNDERLINE.toString() + ChatColor.BOLD.toString() + (messages["command_deposit_click_here"]
) ?: "click here")
e.printStackTrace(); )
return true; 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" -> { "withdraw" -> {
@@ -160,7 +173,7 @@ class SnCommand(
return true; return true;
} }
val playerUuid = p0.uniqueId.toString() val playerUuid = p0.uniqueId
val accountId = playerSolarpassMap[playerUuid] val accountId = playerSolarpassMap[playerUuid]
if (accountId == null) { if (accountId == null) {
p0.sendMessage( p0.sendMessage(
@@ -176,7 +189,7 @@ class SnCommand(
// Takes extra 20% as fee // Takes extra 20% as fee
val fee = amount * 0.2; 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) { if (resp?.type != EconomyResponse.ResponseType.SUCCESS) {
p0.sendMessage( p0.sendMessage(
ChatColor.RED.toString() + (messages["command_withdraw_no_money"] ChatColor.RED.toString() + (messages["command_withdraw_no_money"]
@@ -185,25 +198,31 @@ class SnCommand(
return true; return true;
} }
try { pluginScope.launch {
val transactionSrv = SnBalanceService(sn); try {
transactionSrv.addBalance(amount, "Withdraw from GoatCraft", accountId); val transactionSrv = SnBalanceService(sn);
val transactionHintComponent = transactionSrv.addBalance(amount, "Withdraw from GoatCraft", accountId);
TextComponent(
ChatColor.GREEN.toString() + (messages["command_withdraw_done"]
?: "Done! ")
)
p0.playSound(p0.player!!, Sound.BLOCK_ANVIL_PLACE, 1.0F, 1.0F) Bukkit.getScheduler().runTask(plugin, Runnable {
p0.spigot().sendMessage(transactionHintComponent) val transactionHintComponent =
} catch (e: Exception) { TextComponent(
eco.depositPlayer(p0.player, amount + fee) ChatColor.GREEN.toString() + (messages["command_withdraw_done"]
p0.sendMessage( ?: "Done! ")
ChatColor.RED.toString() + (messages["command_withdraw_error"] )
?: "An error occurred while making transaction. Make sure your wallet exists then try again later.")
) p0.playSound(p0.location, Sound.BLOCK_ANVIL_PLACE, 1.0F, 1.0F)
e.printStackTrace() p0.spigot().sendMessage(transactionHintComponent)
return true })
} 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 package dev.solsynth.snConnect.listeners
import com.Zrips.CMI.CMI
import dev.solsynth.snConnect.services.SnMessageService import dev.solsynth.snConnect.services.SnMessageService
import org.bukkit.Bukkit import kotlinx.coroutines.CoroutineScope
import org.bukkit.entity.Player import kotlinx.coroutines.launch
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority import org.bukkit.event.EventPriority
import org.bukkit.event.Listener import org.bukkit.event.Listener
import org.bukkit.event.entity.PlayerDeathEvent import org.bukkit.event.entity.PlayerDeathEvent
import org.bukkit.event.player.AsyncPlayerChatEvent import org.bukkit.event.player.AsyncPlayerChatEvent
import org.bukkit.event.player.PlayerAdvancementDoneEvent
import org.bukkit.event.player.PlayerJoinEvent import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerQuitEvent import org.bukkit.event.player.PlayerQuitEvent
class SnChatListener( class SnChatListener(
private val pluginScope: CoroutineScope,
private val messageService: SnMessageService, private val messageService: SnMessageService,
private val destinationChatId: String, private val destinationChatId: String,
private val messages: Map<String, String> private val messages: Map<String, String>
@@ -21,31 +20,38 @@ class SnChatListener(
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR)
fun onPlayerChat(event: AsyncPlayerChatEvent) { fun onPlayerChat(event: AsyncPlayerChatEvent) {
val message = "${event.player.name}: ${event.message}" val message = "${event.player.name}: ${event.message}"
messageService.sendMessage(destinationChatId, message) pluginScope.launch {
messageService.sendMessage(destinationChatId, message)
}
} }
@Suppress("SENSELESS_COMPARISON")
@EventHandler() @EventHandler()
fun onPlayerJoin(event: PlayerJoinEvent) { fun onPlayerJoin(event: PlayerJoinEvent) {
val firstTime = Bukkit.getOfflinePlayer(event.player.uniqueId) == null; val firstTime = !event.player.hasPlayedBefore();
val templateKey = if (!firstTime) "join" else "join_first"; val templateKey = if (firstTime) "join_first" else "join";
val template = messages[templateKey] 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) val message = template.replace("{player}", event.player.name)
messageService.sendMessage(destinationChatId, message) pluginScope.launch {
messageService.sendMessage(destinationChatId, message)
}
} }
@EventHandler() @EventHandler()
fun onPlayerQuit(event: PlayerQuitEvent) { fun onPlayerQuit(event: PlayerQuitEvent) {
val template = messages["quit"] ?: "⬅️ {player} left the game." val template = messages["quit"] ?: "⬅️ {player} left the game."
val message = template.replace("{player}", event.player.name) val message = template.replace("{player}", event.player.name)
messageService.sendMessage(destinationChatId, message) pluginScope.launch {
messageService.sendMessage(destinationChatId, message)
}
} }
@EventHandler() @EventHandler()
fun onPlayerDeath(event: PlayerDeathEvent) { 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 ?: "") 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 package dev.solsynth.snConnect.listeners
import dev.solsynth.snConnect.services.AuthUserService import dev.solsynth.snConnect.services.AuthUserService
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.bukkit.Bukkit
import org.bukkit.ChatColor import org.bukkit.ChatColor
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
import org.bukkit.event.Listener import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerJoinEvent import org.bukkit.event.player.PlayerJoinEvent
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
class SolarpassCheckListener( class SolarpassCheckListener(
private val pluginScope: CoroutineScope,
private val authUserService: AuthUserService, private val authUserService: AuthUserService,
private val messages: Map<String, String>, private val messages: Map<String, String>,
private val playerSolarpassMap: MutableMap<String, String?> private val playerSolarpassMap: ConcurrentHashMap<UUID, String?>
) : Listener { ) : Listener {
@EventHandler() @EventHandler()
fun onPlayerJoin(event: PlayerJoinEvent) { fun onPlayerJoin(event: PlayerJoinEvent) {
GlobalScope.launch { pluginScope.launch {
try { try {
val playerUuid = event.player.uniqueId.toString() val playerUuid = event.player.uniqueId
var solarpassId = playerSolarpassMap[playerUuid] if (playerSolarpassMap.containsKey(playerUuid)) {
if (solarpassId == null) { return@launch
solarpassId = authUserService.getSnByPlayer(playerUuid)
playerSolarpassMap[playerUuid] = solarpassId
} }
val solarpassId = authUserService.getSnByPlayer(playerUuid.toString())
playerSolarpassMap[playerUuid] = solarpassId
if (solarpassId == null) { if (solarpassId == null) {
// Send suggestion message // Send suggestion message
val message = messages["solarpass_bind_suggestion"] ?: "${ChatColor.YELLOW}To get more features, please bind your Solarpass account!" 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) { } catch (e: Exception) {
// Optionally log the error or handle it // 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?.close(1000, "Disconnecting")
websocket = null websocket = null
} }
fun sendPing() {
websocket?.send("{\"type\":\"ping\"}")
}
} }