Реструктурирование кода, улучшение его качества.
This commit is contained in:
parent
71ac89690b
commit
be8f5e37f0
@ -16,13 +16,13 @@ class MyLogger(debugEnabled: Boolean, private val loggerOriginal: java.util.logg
|
|||||||
|
|
||||||
fun info(message: String) {
|
fun info(message: String) {
|
||||||
if (debug_enabled) {
|
if (debug_enabled) {
|
||||||
loggerSpigot.info(message)
|
loggerSpigot.info("[DBG] $message")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun error(message: String) {
|
fun error(message: String) {
|
||||||
if (debug_enabled) {
|
if (debug_enabled) {
|
||||||
loggerSpigot.severe(message)
|
loggerSpigot.severe("[DBG] message")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,9 +82,42 @@ class Vp_server_integration() : JavaPlugin(), CommandExecutor {
|
|||||||
|
|
||||||
val configFile = File(dataFolder, "config.properties")
|
val configFile = File(dataFolder, "config.properties")
|
||||||
if (!configFile.exists()) {
|
if (!configFile.exists()) {
|
||||||
// Create default config file
|
createDefaultConfig(configFile)
|
||||||
configFile.writeText(
|
}
|
||||||
"""
|
|
||||||
|
// 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
|
# VPC Integration Configuration
|
||||||
# For get extra output
|
# For get extra output
|
||||||
debug=false
|
debug=false
|
||||||
@ -100,7 +133,6 @@ user_token=$DEFAULT_USER_TOKEN
|
|||||||
user_api_url='http://127.0.0.1:8010/api/'
|
user_api_url='http://127.0.0.1:8010/api/'
|
||||||
# -------------------- END ------------------------
|
# -------------------- END ------------------------
|
||||||
|
|
||||||
|
|
||||||
# ---------- Part for work with server ------------
|
# ---------- Part for work with server ------------
|
||||||
# Which command run to add coins? (will run from console)
|
# Which command run to add coins? (will run from console)
|
||||||
command_add_coins='$DEFAULT_COMMAND_ADD_COINS'
|
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'
|
command_remove_error='$DEFAULT_COMMAND_REMOVE_ERROR'
|
||||||
# -------------------- END ------------------------
|
# -------------------- END ------------------------
|
||||||
|
|
||||||
|
|
||||||
# --------- Part with configure course ------------
|
# --------- Part with configure course ------------
|
||||||
# Which mode use (dynamic/static, dynamic - set course based
|
# Which mode use (dynamic/static, dynamic - set course based
|
||||||
course_mode=$DEFAULT_COURSE_MODE
|
course_mode=$DEFAULT_COURSE_MODE
|
||||||
@ -133,34 +164,7 @@ course_dynamic_command='$DEFAULT_COURSE_DYNAMIC_COMMAND'
|
|||||||
course_commission=$DEFAULT_COURSE_COMMISSION
|
course_commission=$DEFAULT_COURSE_COMMISSION
|
||||||
# -------------------- END ------------------------
|
# -------------------- END ------------------------
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
// 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() {
|
override fun onEnable() {
|
||||||
@ -173,6 +177,7 @@ course_commission=$DEFAULT_COURSE_COMMISSION
|
|||||||
// Initialize logger
|
// Initialize logger
|
||||||
LOGGER = MyLogger(DEBUG_FLAG, this.logger)
|
LOGGER = MyLogger(DEBUG_FLAG, this.logger)
|
||||||
|
|
||||||
|
// Register command executor
|
||||||
getCommand("vpi")?.setExecutor(this)
|
getCommand("vpi")?.setExecutor(this)
|
||||||
|
|
||||||
// Background checks such a auth, invoice check, ...
|
// Background checks such a auth, invoice check, ...
|
||||||
@ -192,162 +197,280 @@ course_commission=$DEFAULT_COURSE_COMMISSION
|
|||||||
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 {
|
||||||
if (command.name.equals("vpi", ignoreCase = true)) {
|
if (command.name.equals("vpi", ignoreCase = true)) {
|
||||||
if (sender !is Player) {
|
if (sender !is Player) {
|
||||||
sender.sendMessage("&cТолько игроки могут выполнять команды.")
|
sender.sendMessage("&cТолько игроки могут выполнять данные команды.")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((args.size == 3 || args.size == 4) && args[0] == "convert") {
|
when {
|
||||||
LOGGER.error("Step 1")
|
// Handle currency conversion command
|
||||||
val vpcUsername = DataManager.getPlayerVPCUsername(sender.name)
|
(args.size == 3 || args.size == 4) && args[0] == "convert" -> {
|
||||||
if (vpcUsername == null) {
|
handleCurrencyConversion(sender, args)
|
||||||
Utils.send(sender, "&cНеобходимо авторизоваться через: /vpi auth")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
LOGGER.error("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
|
|
||||||
}
|
|
||||||
LOGGER.error("Step 3")
|
|
||||||
val course: Double // VPC to LC
|
|
||||||
if (COURSE_MODE == "static") {
|
|
||||||
course = COURSE_STATIC_VALUE
|
|
||||||
} else {
|
|
||||||
if (COURSE_DYNAMIC_COMMAND == "baltop force") {
|
|
||||||
LOGGER.error("Step 4.1")
|
|
||||||
CommandCapture.execute("baltop force")
|
|
||||||
val globalBalance = TotalBalanceModules.getEssentialsBalance()
|
|
||||||
LOGGER.info("globalBalance PRE CHECK: $globalBalance")
|
|
||||||
LOGGER.error("Step 4.1.2")
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
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")
|
|
||||||
} else {
|
|
||||||
LOGGER.error("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")
|
|
||||||
}
|
|
||||||
vpcBalance = vpcUser["balance"].toString().toDouble()
|
|
||||||
course = globalBalance/vpcBalance
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (direction == "vpc") {
|
// Show usage for convert command
|
||||||
val amountVPC: Double = amount/course * (1 - COURSE_COMMISSION/100)
|
args.isNotEmpty() && args[0] == "convert" -> {
|
||||||
if (args.size == 4) {
|
Utils.send(sender, "/vpi convert <vpc/lc> <сумма>")
|
||||||
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
|
|
||||||
}
|
|
||||||
LOGGER.error("Step 8")
|
|
||||||
VpcApi.transfer_coins(vpcUsername, amountVPC)
|
|
||||||
} else {
|
|
||||||
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())
|
|
||||||
sender.spigot().sendMessage(message)
|
|
||||||
}
|
|
||||||
} else if (direction == "lc") {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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)}")
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
} else if (args.isNotEmpty() && args[0] == "convert") {
|
|
||||||
Utils.send(sender, "/vpi convert <vpc/lc> <сумма>")
|
|
||||||
|
|
||||||
} else if (args.size == 2 && args[0] == "auth") {
|
// Handle authentication command
|
||||||
val vpcUsername = DataManager.getPlayerVPCUsername(sender.name)
|
args.size == 2 && args[0] == "auth" -> {
|
||||||
if (vpcUsername != null) {
|
handleAuthentication(sender, args)
|
||||||
Utils.send(sender, "Вы уже авторизованы!")
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
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 invoice_id = VpcApi.create_invoice(0.001)
|
|
||||||
val vpc_username = args[1]
|
|
||||||
LOGGER.error("Adding to lists")
|
|
||||||
synchronized(TO_AUTH_PLAYERS) {
|
|
||||||
TO_AUTH_PLAYERS[sender.name] = vpc_username
|
|
||||||
TO_AUTH_PLAYERS_INVOICES[sender.name] = invoice_id.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")
|
|
||||||
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())
|
|
||||||
sender.spigot().sendMessage(message)
|
|
||||||
|
|
||||||
} else if (args.isNotEmpty() && args[0] == "auth") {
|
// Show usage for auth command
|
||||||
Utils.send(sender, "/vpi auth <ник>")
|
args.isNotEmpty() && args[0] == "auth" -> {
|
||||||
|
Utils.send(sender, "/vpi auth <ник>")
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
// Show general help
|
||||||
Utils.send(sender, """Использование команд:
|
else -> {
|
||||||
/vpi auth <ник> - Авторизация
|
showHelpMenu(sender)
|
||||||
/vpi convert <куда: vpc/lc> <сумма> - Обмен VPC на локальную валюту или наоборот
|
}
|
||||||
|
|
||||||
Почему 'VPC-I'? Потому что это интеграция на конечном сервере - 'VPC Integration'
|
|
||||||
|
|
||||||
Соглашение: voidproject.del.pw/vpc_agreement
|
|
||||||
Группа ТГ: @void_project_mc
|
|
||||||
Группа ДС: discord.gg/zwNt5DJj6J""".trimIndent())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("Player is authenticated - Step 2")
|
||||||
|
|
||||||
|
val direction = args[1]
|
||||||
|
val amount = abs(args[2].toDouble())
|
||||||
|
|
||||||
|
// Validate conversion direction
|
||||||
|
if (!listOf("vpc", "lc").contains(direction)) {
|
||||||
|
Utils.send(sender, "&cНеверное направление. Используйте: vpc or lc")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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("Global balance: $globalBalance")
|
||||||
|
|
||||||
|
val vpcUser = VpcApi.user_in_db(username = USERNAME)
|
||||||
|
if (vpcUser == null) {
|
||||||
|
throw Exception("VPC user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
val vpcBalance = vpcUser["balance"].toString().toDouble()
|
||||||
|
LOGGER.info("VPC balance: $vpcBalance")
|
||||||
|
|
||||||
|
val rate = globalBalance / vpcBalance
|
||||||
|
LOGGER.info("Calculated exchange rate: $rate")
|
||||||
|
rate
|
||||||
|
} else {
|
||||||
|
LOGGER.info("Calculating dynamic rate using custom command - Step 4.2")
|
||||||
|
val globalBalance = CommandCapture.execute(COURSE_DYNAMIC_COMMAND).toString().toDouble()
|
||||||
|
val vpcUser = VpcApi.user_in_db(username = USERNAME)
|
||||||
|
|
||||||
|
if (vpcUser == null) {
|
||||||
|
throw Exception("VPC user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
val vpcBalance = vpcUser["balance"].toString().toDouble()
|
||||||
|
globalBalance / vpcBalance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
// 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())
|
||||||
|
sender.spigot().sendMessage(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
handleExistingInvoice(sender)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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 $invoiceId")
|
||||||
|
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT,
|
||||||
|
ComponentBuilder("/vpc pay $USERNAME $amount $invoiceId").create())
|
||||||
|
sender.spigot().sendMessage(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, "&cВы уже авторизованы!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if authentication is already in progress
|
||||||
|
if (sender.name in TO_AUTH_PLAYERS) {
|
||||||
|
val invoiceId = TO_AUTH_PLAYERS_INVOICES[sender.name]
|
||||||
|
sendAuthPrompt(sender, invoiceId ?: "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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] = vpcUsernameInput
|
||||||
|
TO_AUTH_PLAYERS_INVOICES[sender.name] = invoiceId.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 $invoiceId")
|
||||||
|
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT,
|
||||||
|
ComponentBuilder("/vpc pay $USERNAME 0.001 $invoiceId").create())
|
||||||
|
sender.spigot().sendMessage(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display help menu to player
|
||||||
|
*/
|
||||||
|
private fun showHelpMenu(sender: CommandSender) {
|
||||||
|
Utils.send(sender, """Использование команд:
|
||||||
|
/vpi auth <ник> - Авторизация
|
||||||
|
/vpi convert <куда: vpc/lc> <сумма> - Обмен VPC на локальную валюту или наоборот
|
||||||
|
|
||||||
|
Почему 'VPC-I'? Потому что это интеграция на конечном сервере - 'VPC Integration'
|
||||||
|
|
||||||
|
Соглашение: voidproject.del.pw/vpc_agreement
|
||||||
|
Группа ТГ: @void_project_mc
|
||||||
|
Группа ДС: discord.gg/zwNt5DJj6J""".trimIndent())
|
||||||
|
}
|
||||||
|
|
||||||
override fun onTabComplete(sender: CommandSender, command: Command, alias: String, args: Array<out String>): List<String> {
|
override fun onTabComplete(sender: CommandSender, command: Command, alias: String, args: Array<out String>): List<String> {
|
||||||
val completions = mutableListOf<String>()
|
val completions = mutableListOf<String>()
|
||||||
if (command.name.equals("vpi", ignoreCase = true)) {
|
if (command.name.equals("vpi", ignoreCase = true)) {
|
||||||
@ -371,92 +494,106 @@ course_commission=$DEFAULT_COURSE_COMMISSION
|
|||||||
return completions.filter { it.startsWith(args.lastOrNull()?.lowercase() ?: "") }.sorted()
|
return completions.filter { it.startsWith(args.lastOrNull()?.lowercase() ?: "") }.sorted()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start background checks for invoice processing
|
||||||
|
*/
|
||||||
private fun startBackgroundChecks() {
|
private fun startBackgroundChecks() {
|
||||||
object : BukkitRunnable() {
|
object : BukkitRunnable() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
// Safely check and process TO_AUTH_PLAYERS_INVOICES
|
processAuthenticationInvoices()
|
||||||
synchronized(TO_AUTH_PLAYERS_INVOICES) {
|
processPaymentInvoices()
|
||||||
if (TO_AUTH_PLAYERS_INVOICES.isNotEmpty()) {
|
}
|
||||||
val iterator = TO_AUTH_PLAYERS_INVOICES.iterator()
|
}.runTaskTimerAsynchronously(this, 0L, 20L)
|
||||||
while (iterator.hasNext()) {
|
}
|
||||||
val entry = iterator.next()
|
|
||||||
try {
|
|
||||||
val result = VpcApi.get_invoice(entry.value) as Map<*, *>?
|
|
||||||
|
|
||||||
// Add null safety checks
|
/**
|
||||||
if (result != null) {
|
* Process authentication invoices in background
|
||||||
val status = result["status"]
|
*/
|
||||||
LOGGER.error("Invoice ${entry.value} status: $status")
|
private fun processAuthenticationInvoices() {
|
||||||
|
synchronized(TO_AUTH_PLAYERS_INVOICES) {
|
||||||
|
if (TO_AUTH_PLAYERS_INVOICES.isNotEmpty()) {
|
||||||
|
val iterator = TO_AUTH_PLAYERS_INVOICES.iterator()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val entry = iterator.next()
|
||||||
|
try {
|
||||||
|
val result = VpcApi.get_invoice(entry.value) as Map<*, *>?
|
||||||
|
|
||||||
if (status != null && status.toString() == "true") {
|
if (result != null) {
|
||||||
LOGGER.error("DELETE!!!!!!!!!!!!!!!!")
|
val status = result["status"]
|
||||||
VpcApi.delete_invoice(entry.value)
|
LOGGER.info("Auth invoice ${entry.value} status: $status")
|
||||||
|
|
||||||
DataManager.setPlayerVPCUsername(entry.key, TO_AUTH_PLAYERS[entry.key].toString())
|
if (status != null && status.toString() == "true") {
|
||||||
Utils.send(Bukkit.getPlayer(entry.key.toString()), "&aВы успешно авторизованы!")
|
LOGGER.info("Processing successful authentication")
|
||||||
|
VpcApi.delete_invoice(entry.value)
|
||||||
|
|
||||||
// Safely remove from both maps
|
DataManager.setPlayerVPCUsername(entry.key, TO_AUTH_PLAYERS[entry.key].toString())
|
||||||
TO_AUTH_PLAYERS.remove(entry.key)
|
Utils.send(Bukkit.getPlayer(entry.key.toString()), "&aУспешная авторизация!")
|
||||||
iterator.remove() // Safe removal during iteration
|
|
||||||
}
|
// Clean up tracking maps
|
||||||
} else {
|
TO_AUTH_PLAYERS.remove(entry.key)
|
||||||
logger.warning("Received null result for invoice ${entry.value}")
|
iterator.remove()
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
LOGGER.error("Error processing invoice ${entry.value}: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Safely check and process TO_PAY_INVOICES
|
|
||||||
synchronized(TO_PAY_INVOICES) {
|
|
||||||
if (TO_PAY_INVOICES.isNotEmpty()) {
|
|
||||||
val iterator = TO_PAY_INVOICES.iterator()
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
val entry = iterator.next()
|
|
||||||
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")
|
|
||||||
|
|
||||||
if (status != null && status.toString() == "true") {
|
|
||||||
LOGGER.error("DELETE!!!!!!!!!!!!!!!!")
|
|
||||||
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())
|
|
||||||
Bukkit.getScheduler().runTask(this@Vp_server_integration, Runnable {
|
|
||||||
try {
|
|
||||||
CommandCapture.execute(commandToAddCoins)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
LOGGER.error("Error executing command: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Safely remove from both maps
|
|
||||||
INVOICES_AMOUNT.remove(entry.key)
|
|
||||||
iterator.remove() // Safe removal during iteration
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.warning("Received null result for invoice ${entry.value}")
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
LOGGER.error("Error processing invoice ${entry.value}: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logger.warning("Received null result for auth invoice ${entry.value}")
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
LOGGER.error("Error processing auth invoice ${entry.value}: ${e.message}")
|
||||||
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.runTaskTimerAsynchronously(this, 0L, 20L) // Changed to 20L (1 second) for better performance
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process payment invoices in background
|
||||||
|
*/
|
||||||
|
private fun processPaymentInvoices() {
|
||||||
|
synchronized(TO_PAY_INVOICES) {
|
||||||
|
if (TO_PAY_INVOICES.isNotEmpty()) {
|
||||||
|
val iterator = TO_PAY_INVOICES.iterator()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val entry = iterator.next()
|
||||||
|
try {
|
||||||
|
val result = VpcApi.get_invoice(entry.value) as Map<*, *>?
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
val status = result["status"]
|
||||||
|
LOGGER.info("Payment invoice ${entry.value} status: $status")
|
||||||
|
|
||||||
|
if (status != null && status.toString() == "true") {
|
||||||
|
LOGGER.info("Processing successful payment")
|
||||||
|
VpcApi.delete_invoice(entry.value)
|
||||||
|
|
||||||
|
val amountLC = INVOICES_AMOUNT[entry.value]
|
||||||
|
|
||||||
|
// 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 coin addition command: ${e.message}")
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Clean up tracking maps
|
||||||
|
INVOICES_AMOUNT.remove(entry.key)
|
||||||
|
iterator.remove()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warning("Received null result for payment invoice ${entry.value}")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
LOGGER.error("Error processing payment invoice ${entry.value}: ${e.message}")
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user