commit ad7e50738d2a7a2bd825c253d231376fb5cfd7a4 Author: justuser-31 Date: Sat Nov 22 19:22:35 2025 +0300 Черновой вариант diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4788b4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,113 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +target/ + +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next + +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.flattened-pom.xml + +# Common working directory +run/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..03f4569 --- /dev/null +++ b/pom.xml @@ -0,0 +1,146 @@ + + + 4.0.0 + + main + vp_server_integration + 1.0 + jar + + vp_server_integration + + + 17 + 2.3.0-RC + UTF-8 + + + + clean package + ${project.basedir}/src/main/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.3 + + + package + + shade + + + + + + + + src/main/resources + true + + + + + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + org.spigotmc + spigot-api + 1.12.2-R0.1-SNAPSHOT + provided + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + ${kotlin.version} + + + + + + + myDeploy + + + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + commons-net + commons-net + 3.9.0 + + + + + + ftps-upload + install + + + + + + + + + + + + run + + + + + + http-notification + install + + + + + + + + + + + + run + + + + + + + + + + diff --git a/src/main/kotlin/main/vp_server_integration/Vp_server_integration.kt b/src/main/kotlin/main/vp_server_integration/Vp_server_integration.kt new file mode 100644 index 0000000..0b23f4b --- /dev/null +++ b/src/main/kotlin/main/vp_server_integration/Vp_server_integration.kt @@ -0,0 +1,35 @@ +package main.vp_server_integration + +import org.bukkit.plugin.java.JavaPlugin +import org.bukkit.Bukkit +import java.util.logging.Logger + +class Vp_server_integration : JavaPlugin() { + companion object { + lateinit var LOGGER: Logger + lateinit var SERVER: org.bukkit.Server + var PLUGIN_API_PORT: Int = 8010 + lateinit var USERNAME: String + lateinit var TOKEN: String + lateinit var USER_API_URL: String + const val DEFAULT_USER_API_URL: String = "http://127.0.0.1:8010/api/" + const val DEFAULT_TOKEN: String = "test" + const val COLOR_CHAR: Char = '&' + } + + override fun onEnable() { + // Initialize logger + LOGGER = this.logger + + // Get server instance + SERVER = Bukkit.getServer() + + // Plugin startup logic + LOGGER.info("VP Server Integration plugin enabled!") + } + + override fun onDisable() { + // Plugin shutdown logic + LOGGER.info("VP Server Integration plugin disabled!") + } +} diff --git a/src/main/kotlin/main/vp_server_integration/VpcApi.kt b/src/main/kotlin/main/vp_server_integration/VpcApi.kt new file mode 100644 index 0000000..a885f81 --- /dev/null +++ b/src/main/kotlin/main/vp_server_integration/VpcApi.kt @@ -0,0 +1,176 @@ +package main.vp_server_integration + +import com.google.gson.Gson +import com.google.gson.JsonElement +import com.google.gson.JsonParser +import com.google.gson.JsonSyntaxException +import org.bukkit.ChatColor +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import java.io.BufferedReader +import java.io.InputStreamReader +import java.io.OutputStream +import java.net.HttpURLConnection +import java.net.URI +import java.net.URISyntaxException +import java.util.* + +class VpcApi { + companion object { + // Using Gson for JSON serialization - much cleaner than manual string building + fun jsonify(args: List): String { + val map = mutableMapOf() + for (i in args.indices step 2) { + if (i + 1 < args.size) { + map[args[i]] = args[i + 1] + } + } + return Gson().toJson(map) + } + + // Response wrapper class that supports both dot notation and bracket access + data class ApiResponse( + val status: Int, + val data: Map?, + val rawResponse: String + ) { + operator fun get(key: String): Any? = data?.get(key) + } + + fun sendPost(urlPoint: String, json: String, customUrl: Boolean = false, baseurl: String = ""): ApiResponse { + var uri: URI + try { + uri = if (customUrl) { + URI.create(baseurl + urlPoint) + } else { + URI.create(Vp_server_integration.DEFAULT_USER_API_URL + urlPoint) + } + } catch (e: URISyntaxException) { + return ApiResponse(-1, null, "Error: Invalid URL syntax") + } + + var connection: HttpURLConnection? = null + try { + connection = uri.toURL().openConnection() as HttpURLConnection + connection.requestMethod = "POST" + connection.setRequestProperty("Content-Type", "application/json; utf-8") + connection.doOutput = true + + // Using proper OutputStream handling + val os: OutputStream = connection.outputStream + os.write(json.toByteArray(Charsets.UTF_8)) + os.close() + + val responseCode = connection.responseCode + var rawResponse = "" + var responseData: Map? = null + + // Handle both success (2xx) and error (4xx, 5xx) responses + val inputStream = if (responseCode in 200..299) { + connection.inputStream + } else { + connection.errorStream + } + + // Read response if available + if (inputStream != null) { + rawResponse = BufferedReader(InputStreamReader(inputStream, "utf-8")).readText() + try { + // Try to parse response as JSON + // For Java 8 / Gson < 2.8.6, use JsonParser() constructor and parse() method + val jsonElement: JsonElement = JsonParser().parse(rawResponse) + if (jsonElement.isJsonObject) { + // If it's a JSON object, parse it as before + val jsonObject = jsonElement.asJsonObject + responseData = jsonObject.entrySet().associate { it.key to it.value.toString().trim('"') } + } else { + // If it's not a JSON object (e.g., raw string like "OK"), keep raw response + responseData = null + } + } catch (e: JsonSyntaxException) { + // If not valid JSON at all, keep raw response + responseData = null + } + } + + rawResponse = rawResponse.replace("\"", "") + return ApiResponse(responseCode, responseData, rawResponse) + + } catch (e: Exception) { + // Handle network errors and other exceptions + return ApiResponse(-1, null, "Error: ${e.message}") + } finally { + connection?.disconnect() + } + } + + fun send(source: CommandSender, message: String, prefix: String = "&9[&bVPC&9] &3") { + // Translate color codes for Spigot + val coloredMessage = ChatColor.translateAlternateColorCodes('&', prefix + message) + source.sendMessage(coloredMessage) + } + + fun get_super_UUID(source: CommandSender): String { + if (source is Player) { + val uuid = source.uniqueId + val username = source.name + val address = source.address?.hostString ?: "unknown" + // Note: Some properties don't exist in 1.12.2, using available alternatives + val merged = "$uuid$username$address" + return hash(merged) + } else { + return "None" + } + } + + fun user_in_db(source: CommandSender? = null, username: String? = null): Map? { + var mine_uuid: String? = null + // Determine which parameter to use + val userParam = when { + username != null -> "username" to username + source is Player -> "username" to source.name + else -> throw IllegalArgumentException("Either source or username must be provided") + } + + val response = sendPost( + "user_in_db/", jsonify( + listOf( + "token", Vp_server_integration.DEFAULT_TOKEN, + userParam.first, userParam.second + ) + ) + ) + + // response["someKey"] (map-like access) + return if (response.status == 200) { + response.data + } else { + null + } + } + + fun transfer_coins(src_username: String, dst_username: String, amount: Float): Any? { + val response = sendPost( + "transfer_coins/", jsonify( + listOf( + "token", Vp_server_integration.DEFAULT_TOKEN, + "src_username", src_username, + "dst_username", dst_username, + "amount", amount.toString() + ) + ) + ) + + return if (response.status == 200) { + response.rawResponse + } else { + response.data?.get("detail") + } + } + + // Simple hash function (you might want to replace this with a proper hashing algorithm) + private fun hash(input: String): String { + return UUID.nameUUIDFromBytes(input.toByteArray()).toString() + } + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..38801bd --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,7 @@ +name: vp_server_integration +version: '1.0' +main: main.vp_server_integration.Vp_server_integration +load: STARTUP +authors: [ _SAN5_SkeLet0n_ ] +description: Integrate VPC into your server +website: voidproject.del.pw