Реструктурирование кода, улучшение его качества.

This commit is contained in:
justuser-31 2025-11-24 18:57:46 +03:00
parent 71ac89690b
commit be8f5e37f0
2 changed files with 387 additions and 250 deletions

View File

@ -16,13 +16,13 @@ class MyLogger(debugEnabled: Boolean, private val loggerOriginal: java.util.logg
fun info(message: String) {
if (debug_enabled) {
loggerSpigot.info(message)
loggerSpigot.info("[DBG] $message")
}
}
fun error(message: String) {
if (debug_enabled) {
loggerSpigot.severe(message)
loggerSpigot.severe("[DBG] message")
}
}
}

View File

@ -82,7 +82,40 @@ class Vp_server_integration() : JavaPlugin(), CommandExecutor {
val configFile = File(dataFolder, "config.properties")
if (!configFile.exists()) {
// Create default config file
createDefaultConfig(configFile)
}
// Load properties from file
val properties = Properties()
FileInputStream(configFile).use { properties.load(it) }
// Parse configuration values
DEBUG_FLAG = properties.getProperty("debug", false.toString()).replace("'", "").toBoolean()
USERNAME = properties.getProperty("username", DEFAULT_USERNAME).replace("'", "")
USER_TOKEN = properties.getProperty("user_token", DEFAULT_USER_TOKEN).replace("'", "")
USER_API_URL = properties.getProperty("user_api_url", DEFAULT_USER_API_URL).replace("'", "")
COMMAND_ADD_COINS = properties.getProperty("command_add_coins", DEFAULT_COMMAND_ADD_COINS).replace("'", "")
COMMAND_REMOVE_MODE = properties.getProperty("command_remove_mode", DEFAULT_COMMAND_REMOVE_MODE).replace("'", "")
COMMAND_REMOVE_COINS = properties.getProperty("command_remove_coins", DEFAULT_COMMAND_REMOVE_COINS).replace("'", "")
COMMAND_REMOVE_ERROR = properties.getProperty("command_remove_error", DEFAULT_COMMAND_REMOVE_ERROR).replace("'", "")
COURSE_MODE = properties.getProperty("course_mode", DEFAULT_COURSE_MODE).replace("'", "")
COURSE_STATIC_VALUE = properties.getProperty("course_static_value", DEFAULT_COURSE_STATIC_VALUE.toString()).replace("'", "").toDouble()
COURSE_DYNAMIC_COMMAND = properties.getProperty("course_dynamic_command", DEFAULT_COURSE_DYNAMIC_COMMAND).replace("'", "")
COURSE_COMMISSION = properties.getProperty("course_commission", DEFAULT_COURSE_COMMISSION.toString()).replace("'", "").toFloat()
logger.info("Configuration loaded successfully - Username: $USERNAME, API URL: $USER_API_URL")
} catch (e: Exception) {
logger.severe("Failed to load configuration, using defaults: ${e.message}")
USERNAME = DEFAULT_USERNAME
USER_TOKEN = DEFAULT_USER_TOKEN
USER_API_URL = DEFAULT_USER_API_URL
}
}
/**
* Create default configuration file with documentation
*/
private fun createDefaultConfig(configFile: File) {
configFile.writeText(
"""
# VPC Integration Configuration
@ -100,7 +133,6 @@ user_token=$DEFAULT_USER_TOKEN
user_api_url='http://127.0.0.1:8010/api/'
# -------------------- END ------------------------
# ---------- Part for work with server ------------
# Which command run to add coins? (will run from console)
command_add_coins='$DEFAULT_COMMAND_ADD_COINS'
@ -115,7 +147,6 @@ command_remove_coins='$DEFAULT_COMMAND_REMOVE_COINS'
command_remove_error='$DEFAULT_COMMAND_REMOVE_ERROR'
# -------------------- END ------------------------
# --------- Part with configure course ------------
# Which mode use (dynamic/static, dynamic - set course based
course_mode=$DEFAULT_COURSE_MODE
@ -136,33 +167,6 @@ course_commission=$DEFAULT_COURSE_COMMISSION
)
}
// Load properties
val properties = Properties()
FileInputStream(configFile).use { properties.load(it) }
DEBUG_FLAG = properties.getProperty("debug", false.toString()).replace("'", "").toBoolean()
USERNAME = properties.getProperty("username", DEFAULT_USERNAME).replace("'", "")
USER_TOKEN = properties.getProperty("user_token", DEFAULT_USER_TOKEN).replace("'", "")
USER_API_URL = properties.getProperty("user_api_url", DEFAULT_USER_API_URL).replace("'", "")
COMMAND_ADD_COINS = properties.getProperty("command_add_coins", DEFAULT_COMMAND_ADD_COINS).replace("'", "")
COMMAND_REMOVE_MODE = properties.getProperty("command_remove_mode", DEFAULT_COMMAND_REMOVE_MODE).replace("'", "")
COMMAND_REMOVE_COINS = properties.getProperty("command_remove_coins", DEFAULT_COMMAND_REMOVE_COINS).replace("'", "")
COMMAND_REMOVE_ERROR = properties.getProperty("command_remove_error", DEFAULT_COMMAND_REMOVE_ERROR).replace("'", "")
COURSE_MODE = properties.getProperty("course_mode", DEFAULT_COURSE_MODE).replace("'", "")
COURSE_STATIC_VALUE = properties.getProperty("course_static_value", DEFAULT_COURSE_STATIC_VALUE.toString()).replace("'", "").toDouble()
COURSE_DYNAMIC_COMMAND = properties.getProperty("course_dynamic_command", DEFAULT_COURSE_DYNAMIC_COMMAND).replace("'", "")
COURSE_COMMISSION = properties.getProperty("course_commission", DEFAULT_COURSE_COMMISSION.toString()).replace("'", "").toFloat()
logger.info("Loaded configuration: username: $USERNAME, user_api_url: $USER_API_URL")
} catch (e: Exception) {
// In Spigot, we use severe() for error logging
logger.severe("Failed to load configuration, using defaults: ${e.message}")
USERNAME = DEFAULT_USERNAME
USER_TOKEN = DEFAULT_USER_TOKEN
USER_API_URL = DEFAULT_USER_API_URL
}
}
override fun onEnable() {
// Get server instance
SERVER = Bukkit.getServer()
@ -173,6 +177,7 @@ course_commission=$DEFAULT_COURSE_COMMISSION
// Initialize logger
LOGGER = MyLogger(DEBUG_FLAG, this.logger)
// Register command executor
getCommand("vpi")?.setExecutor(this)
// Background checks such a auth, invoice check, ...
@ -192,146 +197,269 @@ course_commission=$DEFAULT_COURSE_COMMISSION
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
if (command.name.equals("vpi", ignoreCase = true)) {
if (sender !is Player) {
sender.sendMessage("&cТолько игроки могут выполнять команды.")
sender.sendMessage("&cТолько игроки могут выполнять данные команды.")
return true
}
if ((args.size == 3 || args.size == 4) && args[0] == "convert") {
LOGGER.error("Step 1")
when {
// Handle currency conversion command
(args.size == 3 || args.size == 4) && args[0] == "convert" -> {
handleCurrencyConversion(sender, args)
}
// Show usage for convert command
args.isNotEmpty() && args[0] == "convert" -> {
Utils.send(sender, "/vpi convert <vpc/lc> <сумма>")
}
// Handle authentication command
args.size == 2 && args[0] == "auth" -> {
handleAuthentication(sender, args)
}
// Show usage for auth command
args.isNotEmpty() && args[0] == "auth" -> {
Utils.send(sender, "/vpi auth <ник>")
}
// Show general help
else -> {
showHelpMenu(sender)
}
}
return true
}
return false
}
/**
* Handle currency conversion logic
*/
private fun handleCurrencyConversion(sender: Player, args: Array<out String>) {
LOGGER.info("Starting currency conversion process - Step 1")
// Check if player is authenticated
val vpcUsername = DataManager.getPlayerVPCUsername(sender.name)
if (vpcUsername == null) {
Utils.send(sender, "&cНеобходимо авторизоваться через: /vpi auth")
return true
Utils.send(sender, "&cВы должны авторизоваться сначала: /vpi auth")
return
}
LOGGER.error("Step 2")
LOGGER.info("Player is authenticated - Step 2")
val direction = args[1]
val amount = abs(args[2].toDouble())
if (!listOf<String>("vpc", "lc").contains(direction)) {
Utils.send(sender, "&cНе существует такого направление, правильные: vpc/lc")
return true
// Validate conversion direction
if (!listOf("vpc", "lc").contains(direction)) {
Utils.send(sender, "&cНеверное направление. Используйте: vpc or lc")
return
}
LOGGER.error("Step 3")
val course: Double // VPC to LC
if (COURSE_MODE == "static") {
course = COURSE_STATIC_VALUE
LOGGER.info("Valid direction provided - Step 3")
// Calculate exchange rate
val course = calculateExchangeRate()
LOGGER.info("Exchange rate calculated: $course")
if (course.isInfinite()) {
LOGGER.error("Zero global balance?")
Utils.send(sender, "&cПроизошла ошибка при расчёте курса. Обратитесь к администратору или повторите позже.")
return
} else if (course == 0.0) {
LOGGER.error("Infinite global balance?")
Utils.send(sender, "&cПроизошла ошибка при расчёте курса. Обратитесь к администратору или повторите позже.")
return
}
when (direction) {
"vpc" -> handleVpcConversion(sender, amount, course, args)
"lc" -> handleLcConversion(sender, amount, course, args)
}
}
/**
* Calculate exchange rate based on configuration
*/
private fun calculateExchangeRate(): Double {
return if (COURSE_MODE == "static") {
COURSE_STATIC_VALUE
} else {
if (COURSE_DYNAMIC_COMMAND == "baltop force") {
LOGGER.error("Step 4.1")
calculateDynamicRate()
}
}
/**
* Calculate dynamic exchange rate
*/
private fun calculateDynamicRate(): Double {
return if (COURSE_DYNAMIC_COMMAND == "baltop force") {
LOGGER.info("Calculating dynamic rate using baltop - Step 4.1")
CommandCapture.execute("baltop force")
val globalBalance = TotalBalanceModules.getEssentialsBalance()
LOGGER.info("globalBalance PRE CHECK: $globalBalance")
LOGGER.error("Step 4.1.2")
LOGGER.info("Global balance: $globalBalance")
val vpcUser = VpcApi.user_in_db(username = USERNAME)
LOGGER.error("Step 4.1.3")
val vpcBalance: Double
LOGGER.error("Step 4.1.4")
if (vpcUser == null) {
throw Exception("null vpcUser")
throw Exception("VPC user not found")
}
LOGGER.error("Step 4.1.6")
LOGGER.info(vpcUser["balance"].toString())
vpcBalance = vpcUser["balance"].toString().toDouble()
LOGGER.error("Step 4.1.7")
LOGGER.info("globalBalance: $globalBalance")
LOGGER.info("vpcBalance: $vpcBalance")
course = globalBalance/vpcBalance
LOGGER.info("course: $course")
val vpcBalance = vpcUser["balance"].toString().toDouble()
LOGGER.info("VPC balance: $vpcBalance")
val rate = globalBalance / vpcBalance
LOGGER.info("Calculated exchange rate: $rate")
rate
} else {
LOGGER.error("Step 4.2")
LOGGER.info("Calculating dynamic rate using custom command - Step 4.2")
val globalBalance = CommandCapture.execute(COURSE_DYNAMIC_COMMAND).toString().toDouble()
LOGGER.error("$globalBalance")
val vpcUser = VpcApi.user_in_db(username = USERNAME)
val vpcBalance: Double
if (vpcUser == null) {
throw Exception("null vpcUser")
throw Exception("VPC user not found")
}
vpcBalance = vpcUser["balance"].toString().toDouble()
course = globalBalance/vpcBalance
val vpcBalance = vpcUser["balance"].toString().toDouble()
globalBalance / vpcBalance
}
}
if (direction == "vpc") {
val amountVPC: Double = amount/course * (1 - COURSE_COMMISSION/100)
if (args.size == 4) {
LOGGER.error("Step 5")
val result: String = CommandCapture.execute(COMMAND_REMOVE_COINS.replace("%player%", sender.name).replace("%amount%", amount.toString()))[0]
LOGGER.error("Step 6")
if (result.contains(COMMAND_REMOVE_ERROR)) {
Utils.send(sender, "&cОшибка, возможно недостаточно средств.")
return true
/**
* Handle VPC to local currency conversion
*/
private fun handleVpcConversion(sender: Player, amount: Double, course: Double, args: Array<out String>) {
val amountVPC = amount / course * (1 - COURSE_COMMISSION / 100)
val vpcUsername = DataManager.getPlayerVPCUsername(sender.name)
if (vpcUsername == null) {
Utils.send(sender, "&cВы должны авторизоваться сначала: /vpi auth")
return
}
LOGGER.error("Step 8")
if (args.size == 4) {
// Execute confirmed conversion
LOGGER.info("Executing confirmed conversion - Step 5")
val result = CommandCapture.execute(
COMMAND_REMOVE_COINS
.replace("%player%", sender.name)
.replace("%amount%", amount.toString())
)[0]
LOGGER.info("Command executed - Step 6")
if (result.contains(COMMAND_REMOVE_ERROR)) {
Utils.send(sender, "&cОшибка. Возможно недостаточно средств.")
return
}
LOGGER.info("Transferring coins to VPC - Step 8")
VpcApi.transfer_coins(vpcUsername, amountVPC)
} else {
val colored = ChatColor.translateAlternateColorCodes('&', "${PREFIX}Кликните здесь, чтобы конвертировать &6$amount&3 в &6${String.format("%.4f", amountVPC)} VPC")
// Show confirmation prompt
val colored = ChatColor.translateAlternateColorCodes('&',
"${PREFIX}Нажмите здесь, чтобы конвертировать &6$amount&3 в &6${String.format("%.4f", amountVPC)} VPC")
val message = TextComponent(colored)
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpi convert vpc $amount confirm")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("/vpi convert vpc $amount confirm").create())
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT,
ComponentBuilder("/vpi convert vpc $amount confirm").create())
sender.spigot().sendMessage(message)
}
} else if (direction == "lc") {
}
/**
* Handle local currency to VPC conversion
*/
private fun handleLcConversion(sender: Player, amount: Double, course: Double, args: Array<out String>) {
// Check if there's an existing pending invoice
if (sender.name in TO_PAY_INVOICES) {
val invoice_id = TO_PAY_INVOICES[sender.name]
val amount = INVOICES_AMOUNT[invoice_id]
if (amount == null) return true // Stupid Kotlin, it's not null
val amountLC: Double = amount*course * (1 + COURSE_COMMISSION/100)
val colored = ChatColor.translateAlternateColorCodes('&', "${PREFIX}Кликните здесь, чтобы перевести &6$amount VPC &3в &6${String.format("%.4f", amountLC)}")
val message = TextComponent(colored)
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc pay $USERNAME $amount $invoice_id")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("/vpc pay $USERNAME $amount $invoice_id").create())
sender.spigot().sendMessage(message)
return true
handleExistingInvoice(sender)
return
}
LOGGER.error("amount: $amount")
LOGGER.error("course: $course")
val amountLC: Double = amount*course * (1 + COURSE_COMMISSION/100)
LOGGER.error("amountLC: $amountLC")
val invoice_id = VpcApi.create_invoice(amount).toString()
TO_PAY_INVOICES[sender.name] = invoice_id
INVOICES_AMOUNT[invoice_id] = amountLC
val colored = ChatColor.translateAlternateColorCodes('&', "${PREFIX}Кликните здесь, чтобы перевести &6$amount VPC &3в &6${String.format("%.4f", amountLC)}")
LOGGER.info("Amount: $amount, Course: $course")
val amountLC = amount * course * (1 + COURSE_COMMISSION / 100)
LOGGER.info("Converted amount: $amountLC")
// Create new invoice
val invoiceId = VpcApi.create_invoice(amount).toString()
TO_PAY_INVOICES[sender.name] = invoiceId
INVOICES_AMOUNT[invoiceId] = amountLC
sendPaymentPrompt(sender, amount, amountLC, invoiceId)
}
/**
* Handle existing payment invoice
*/
private fun handleExistingInvoice(sender: Player) {
val invoiceId = TO_PAY_INVOICES[sender.name]
val amount = INVOICES_AMOUNT[invoiceId]
if (amount == null) return
val course = if (COURSE_MODE == "static") COURSE_STATIC_VALUE else calculateDynamicRate()
val amountLC = amount * course * (1 + COURSE_COMMISSION / 100)
sendPaymentPrompt(sender, amount, amountLC, invoiceId)
}
/**
* Send payment prompt to player
*/
private fun sendPaymentPrompt(sender: Player, amount: Double, amountLC: Double, invoiceId: String?) {
val colored = ChatColor.translateAlternateColorCodes('&',
"${PREFIX}Нажмите здесь, чтобы конвертировать &6$amount VPC &3d &6${String.format("%.4f", amountLC)}")
val message = TextComponent(colored)
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc pay $USERNAME $amount $invoice_id")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("/vpc pay $USERNAME $amount $invoice_id").create())
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc pay $USERNAME $amount $invoiceId")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT,
ComponentBuilder("/vpc pay $USERNAME $amount $invoiceId").create())
sender.spigot().sendMessage(message)
}
} else if (args.isNotEmpty() && args[0] == "convert") {
Utils.send(sender, "/vpi convert <vpc/lc> <сумма>")
} else if (args.size == 2 && args[0] == "auth") {
/**
* Handle player authentication process
*/
private fun handleAuthentication(sender: Player, args: Array<out String>) {
val vpcUsername = DataManager.getPlayerVPCUsername(sender.name)
if (vpcUsername != null) {
Utils.send(sender, "Вы уже авторизованы!")
return true
Utils.send(sender, "&cВы уже авторизованы!")
return
}
// Check if authentication is already in progress
if (sender.name in TO_AUTH_PLAYERS) {
val colored = ChatColor.translateAlternateColorCodes('&', "${PREFIX}Кликните здесь, чтобы перевести &60.001 VPC")
val message = TextComponent(colored)
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc pay $USERNAME 0.001 ${TO_AUTH_PLAYERS_INVOICES[sender.name]}")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("/vpc pay $USERNAME 0.001 ${TO_AUTH_PLAYERS_INVOICES[sender.name]}").create())
sender.spigot().sendMessage(message)
return true
val invoiceId = TO_AUTH_PLAYERS_INVOICES[sender.name]
sendAuthPrompt(sender, invoiceId ?: "")
return
}
val invoice_id = VpcApi.create_invoice(0.001)
val vpc_username = args[1]
LOGGER.error("Adding to lists")
// Start new authentication process
val invoiceId = VpcApi.create_invoice(0.001)
val vpcUsernameInput = args[1]
LOGGER.info("Adding player to authentication lists")
synchronized(TO_AUTH_PLAYERS) {
TO_AUTH_PLAYERS[sender.name] = vpc_username
TO_AUTH_PLAYERS_INVOICES[sender.name] = invoice_id.toString()
TO_AUTH_PLAYERS[sender.name] = vpcUsernameInput
TO_AUTH_PLAYERS_INVOICES[sender.name] = invoiceId.toString()
}
LOGGER.error("TO_AUTH_PLAYERS: $TO_AUTH_PLAYERS")
LOGGER.error("TO_AUTH_PLAYERS_INVOICES: $TO_AUTH_PLAYERS_INVOICES")
val colored = ChatColor.translateAlternateColorCodes('&', "${PREFIX}Кликните здесь, чтобы перевести 0.001 VPC")
LOGGER.info("Authentication lists updated")
sendAuthPrompt(sender, invoiceId.toString())
}
/**
* Send authentication prompt to player
*/
private fun sendAuthPrompt(sender: Player, invoiceId: String) {
val colored = ChatColor.translateAlternateColorCodes('&',
"${PREFIX}Нажмите, чтобы перевести &60.001 VPC&3 для авторизации")
val message = TextComponent(colored)
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc pay $USERNAME 0.001 $invoice_id")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("/vpc pay $USERNAME 0.001 $invoice_id").create())
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc pay $USERNAME 0.001 $invoiceId")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT,
ComponentBuilder("/vpc pay $USERNAME 0.001 $invoiceId").create())
sender.spigot().sendMessage(message)
}
} else if (args.isNotEmpty() && args[0] == "auth") {
Utils.send(sender, "/vpi auth <ник>")
} else {
/**
* Display help menu to player
*/
private fun showHelpMenu(sender: CommandSender) {
Utils.send(sender, """Использование команд:
/vpi auth <ник> - Авторизация
/vpi convert <куда: vpc/lc> <сумма> - Обмен VPC на локальную валюту или наоборот
@ -343,11 +471,6 @@ course_commission=$DEFAULT_COURSE_COMMISSION
Группа ДС: discord.gg/zwNt5DJj6J""".trimIndent())
}
return true
}
return false
}
override fun onTabComplete(sender: CommandSender, command: Command, alias: String, args: Array<out String>): List<String> {
val completions = mutableListOf<String>()
if (command.name.equals("vpi", ignoreCase = true)) {
@ -371,11 +494,22 @@ course_commission=$DEFAULT_COURSE_COMMISSION
return completions.filter { it.startsWith(args.lastOrNull()?.lowercase() ?: "") }.sorted()
}
/**
* Start background checks for invoice processing
*/
private fun startBackgroundChecks() {
object : BukkitRunnable() {
override fun run() {
// Safely check and process TO_AUTH_PLAYERS_INVOICES
processAuthenticationInvoices()
processPaymentInvoices()
}
}.runTaskTimerAsynchronously(this, 0L, 20L)
}
/**
* Process authentication invoices in background
*/
private fun processAuthenticationInvoices() {
synchronized(TO_AUTH_PLAYERS_INVOICES) {
if (TO_AUTH_PLAYERS_INVOICES.isNotEmpty()) {
val iterator = TO_AUTH_PLAYERS_INVOICES.iterator()
@ -384,34 +518,37 @@ course_commission=$DEFAULT_COURSE_COMMISSION
try {
val result = VpcApi.get_invoice(entry.value) as Map<*, *>?
// Add null safety checks
if (result != null) {
val status = result["status"]
LOGGER.error("Invoice ${entry.value} status: $status")
LOGGER.info("Auth invoice ${entry.value} status: $status")
if (status != null && status.toString() == "true") {
LOGGER.error("DELETE!!!!!!!!!!!!!!!!")
LOGGER.info("Processing successful authentication")
VpcApi.delete_invoice(entry.value)
DataManager.setPlayerVPCUsername(entry.key, TO_AUTH_PLAYERS[entry.key].toString())
Utils.send(Bukkit.getPlayer(entry.key.toString()), "&aВы успешно авторизованы!")
Utils.send(Bukkit.getPlayer(entry.key.toString()), "&aУспешная авторизация!")
// Safely remove from both maps
// Clean up tracking maps
TO_AUTH_PLAYERS.remove(entry.key)
iterator.remove() // Safe removal during iteration
iterator.remove()
}
} else {
logger.warning("Received null result for invoice ${entry.value}")
logger.warning("Received null result for auth invoice ${entry.value}")
}
} catch (e: Exception) {
LOGGER.error("Error processing invoice ${entry.value}: ${e.message}")
LOGGER.error("Error processing auth invoice ${entry.value}: ${e.message}")
e.printStackTrace()
}
}
}
}
}
// Safely check and process TO_PAY_INVOICES
/**
* Process payment invoices in background
*/
private fun processPaymentInvoices() {
synchronized(TO_PAY_INVOICES) {
if (TO_PAY_INVOICES.isNotEmpty()) {
val iterator = TO_PAY_INVOICES.iterator()
@ -420,43 +557,43 @@ course_commission=$DEFAULT_COURSE_COMMISSION
try {
val result = VpcApi.get_invoice(entry.value) as Map<*, *>?
// Add null safety checks
if (result != null) {
val status = result["status"]
LOGGER.error("Invoice ${entry.value} status: $status")
LOGGER.info("Payment invoice ${entry.value} status: $status")
if (status != null && status.toString() == "true") {
LOGGER.error("DELETE!!!!!!!!!!!!!!!!")
LOGGER.info("Processing successful payment")
VpcApi.delete_invoice(entry.value)
val amountLC = INVOICES_AMOUNT[entry.value]
// Fix: Schedule command execution on main thread
val commandToAddCoins = COMMAND_ADD_COINS.replace("%player%", entry.key).replace("%amount%", amountLC.toString())
// Execute coin addition on main thread
val commandToAddCoins = COMMAND_ADD_COINS
.replace("%player%", entry.key)
.replace("%amount%", amountLC.toString())
Bukkit.getScheduler().runTask(this@Vp_server_integration, Runnable {
try {
CommandCapture.execute(commandToAddCoins)
} catch (e: Exception) {
LOGGER.error("Error executing command: ${e.message}")
LOGGER.error("Error executing coin addition command: ${e.message}")
e.printStackTrace()
}
})
// Safely remove from both maps
// Clean up tracking maps
INVOICES_AMOUNT.remove(entry.key)
iterator.remove() // Safe removal during iteration
iterator.remove()
}
} else {
logger.warning("Received null result for invoice ${entry.value}")
logger.warning("Received null result for payment invoice ${entry.value}")
}
} catch (e: Exception) {
LOGGER.error("Error processing invoice ${entry.value}: ${e.message}")
LOGGER.error("Error processing payment invoice ${entry.value}: ${e.message}")
e.printStackTrace()
}
}
}
}
}
}.runTaskTimerAsynchronously(this, 0L, 20L) // Changed to 20L (1 second) for better performance
}
}