commit 7b66cdedcdc396ff9ab45ae7a492aa8b732f9d98 Author: LittleSheep Date: Mon Feb 3 02:51:36 2025 +0800 :tada: Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5f737e --- /dev/null +++ b/.gitignore @@ -0,0 +1,119 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# 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 + +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Cache of project +.gradletasknamecache + +**/build/ + +# Common working directory +run/ +runs/ + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..c289558 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,48 @@ +plugins { + kotlin("jvm") version "2.1.20-Beta2" + kotlin("plugin.serialization") version "2.1.10" + id("com.github.johnrengelman.shadow") version "8.1.1" +} + +group = "dev.solsynth" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() + maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") { + name = "spigotmc-repo" + } + maven("https://oss.sonatype.org/content/groups/public/") { + name = "sonatype" + } + maven("https://jitpack.io") { + name = "jitpack" + } +} + +dependencies { + compileOnly("org.spigotmc:spigot-api:1.21.4-R0.1-SNAPSHOT") + compileOnly("com.github.MilkBowl:VaultAPI:1.7") + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0") + implementation("com.squareup.okhttp3:okhttp:4.12.0") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") +} + +val targetJavaVersion = 21 +kotlin { + jvmToolchain(targetJavaVersion) +} + +tasks.build { + dependsOn("shadowJar") +} + +tasks.processResources { + val props = mapOf("version" to version) + inputs.properties(props) + filteringCharset = "UTF-8" + filesMatching("plugin.yml") { + expand(props) + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..e69de29 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0d8ab51 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..10c9c69 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "SolarNetworkConnect" diff --git a/src/main/kotlin/dev/solsynth/snConnect/SolarNetworkConnect.kt b/src/main/kotlin/dev/solsynth/snConnect/SolarNetworkConnect.kt new file mode 100644 index 0000000..e7528a8 --- /dev/null +++ b/src/main/kotlin/dev/solsynth/snConnect/SolarNetworkConnect.kt @@ -0,0 +1,64 @@ +package dev.solsynth.snConnect + +import dev.solsynth.snConnect.commands.SnCommand +import dev.solsynth.snConnect.commands.SnCommandCompleter +import dev.solsynth.snConnect.services.SnService +import net.milkbowl.vault.economy.Economy +import org.bukkit.Bukkit +import org.bukkit.plugin.java.JavaPlugin + + +class SolarNetworkConnect : JavaPlugin() { + private var economy: Economy? = null + private var sn: SnService? = null + + override fun onEnable() { + logger.info(String.format("Enabling Version %s", description.version)); + + this.saveDefaultConfig() + + if (!setupNetwork()) { + logger.severe("Failed to setup Solar Network Network, check your configuration.") + } + if (!setupEconomy()) { + logger.warning( + "Failed to load vault, economy related features will not available." + ) + } + + Bukkit.getPluginCommand("solar")!!.setExecutor(SnCommand(this.sn!!)) + Bukkit.getPluginCommand("solar")!!.tabCompleter = SnCommandCompleter() + + logger.info( + String.format( + "Successfully loaded Solar Network Connect connected with %s", + config.getString("sn.endpoint") + ) + ); + } + + override fun onDisable() { + logger.info(String.format("Disabled Version %s", description.version)); + } + + private fun setupNetwork(): Boolean { + val baseUrl = config.getString("sn.endpoint") ?: return false; + val clientId = config.getString("sn.client_id") ?: return false; + val clientSecret = config.getString("sn.client_secret") ?: return false; + sn = SnService(baseUrl, clientId, clientSecret); + return true; + } + + private fun setupEconomy(): Boolean { + if (server.pluginManager.getPlugin("Vault") == null) { + logger.warning( + "No Vault dependency found!" + ); + return false + } + val rsp = server.servicesManager.getRegistration(Economy::class.java) ?: return false + economy = rsp.provider + @Suppress("KotlinConstantConditions") + return economy != null + } +} diff --git a/src/main/kotlin/dev/solsynth/snConnect/commands/SnCommand.kt b/src/main/kotlin/dev/solsynth/snConnect/commands/SnCommand.kt new file mode 100644 index 0000000..7e8f7f2 --- /dev/null +++ b/src/main/kotlin/dev/solsynth/snConnect/commands/SnCommand.kt @@ -0,0 +1,63 @@ +package dev.solsynth.snConnect.commands + +import dev.solsynth.snConnect.services.SnOrderService +import dev.solsynth.snConnect.services.SnService +import net.md_5.bungee.api.chat.ClickEvent +import net.md_5.bungee.api.chat.TextComponent +import org.bukkit.ChatColor +import org.bukkit.command.Command +import org.bukkit.command.CommandExecutor +import org.bukkit.command.CommandSender +import org.bukkit.command.TabCompleter +import org.bukkit.entity.Player + +class SnCommand(private val sn: SnService) : CommandExecutor { + override fun onCommand(p0: CommandSender, p1: Command, p2: String, p3: Array): Boolean { + if (p0 !is Player) { + return false; + } + + if (p3.isEmpty()) return false; + + when (p3[0].lowercase()) { + "deposit" -> { + if (p3.size < 2) { + p0.sendMessage(ChatColor.RED.toString() + "You need to specific an amount to deposit.") + return true; + } + + val amount = p3[1].toDoubleOrNull(); + if (amount == null) { + p0.sendMessage(ChatColor.RED.toString() + "You need to specific an amount of number to deposit.") + return true; + } + + val orderSrv = SnOrderService(sn); + val order = orderSrv.createOrder("Deposit to Highland MC", amount / 100); + + val linkComponent = TextComponent(ChatColor.GOLD.toString() + "Click here to payment page") + linkComponent.clickEvent = + ClickEvent(ClickEvent.Action.OPEN_URL, "https://solsynth.dev/orders/${order.id}"); + p0.spigot().sendMessage(linkComponent); + } + + else -> return false; + } + + return true; + } +} + +class SnCommandCompleter : TabCompleter { + override fun onTabComplete( + p0: CommandSender, + p1: Command, + p2: String, + p3: Array + ): MutableList { + return when (p3.size) { + 1 -> mutableListOf("deposit", "withdraw"); + else -> mutableListOf(); + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/solsynth/snConnect/services/SnOrderService.kt b/src/main/kotlin/dev/solsynth/snConnect/services/SnOrderService.kt new file mode 100644 index 0000000..7dbfd1a --- /dev/null +++ b/src/main/kotlin/dev/solsynth/snConnect/services/SnOrderService.kt @@ -0,0 +1,69 @@ +package dev.solsynth.snConnect.services + +import kotlinx.datetime.Instant +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import java.io.IOException + +@Serializable +class SnOrderRequest( + @SerialName("client_id") + val clientId: String, + @SerialName("client_secret") + val clientSecret: String, + val remark: String, + val amount: Double +) + +@Serializable +data class SnOrder( + val id: Long, + @SerialName("created_at") + val createdAt: Instant, + @SerialName("updated_at") + val updatedAt: Instant, + @SerialName("deleted_at") + val deletedAt: Instant? = null, + val status: Long, + val remark: String, + val amount: String, + @SerialName("payer_id") + val payerID: Int? = null, + @SerialName("payee_id") + val payeeID: Int? = null, + @SerialName("transaction_id") + val transactionID: Int? = null, + @SerialName("client_id") + val clientID: Long +) + +class SnOrderService(private val sn: SnService) { + private val json = Json { + ignoreUnknownKeys = true + } + + fun createOrder(remark: String, amount: Double): SnOrder { + val body = SnOrderRequest( + sn.clientId, + sn.clientSecret, + remark, + amount, + ); + val request = Request.Builder() + .url(sn.getUrl("wa", "/orders")) + .post(Json.encodeToString(body).toRequestBody("application/json".toMediaTypeOrNull())) + .build() + + sn.client.newCall(request).execute().use { response -> + if (!response.isSuccessful) throw IOException("Unexpected code $response") + val responseBody = response.body!!.string() + val out = json.decodeFromString(responseBody) + + return out + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/solsynth/snConnect/services/SnService.kt b/src/main/kotlin/dev/solsynth/snConnect/services/SnService.kt new file mode 100644 index 0000000..1d934a8 --- /dev/null +++ b/src/main/kotlin/dev/solsynth/snConnect/services/SnService.kt @@ -0,0 +1,11 @@ +package dev.solsynth.snConnect.services + +import okhttp3.OkHttpClient + +class SnService(private val baseUrl: String, val clientId: String, val clientSecret: String) { + val client = OkHttpClient.Builder().build(); + + fun getUrl(service: String, segment: String): String { + return "$baseUrl/cgi/$service$segment" + } +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..7b94856 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,4 @@ +sn: + endpoint: https://api.sn.solsynth.dev + client_id: highland-mc + client_secret: 12345678 \ 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..f594edc --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,23 @@ +name: SolarNetworkConnect +version: '1.0-SNAPSHOT' +main: dev.solsynth.snConnect.SolarNetworkConnect +api-version: '1.21' +authors: [ LittleSheepOvO ] +description: Solar Network Connect provide features connect with Solar Network +loadbefore: + - CMI + - CMIEInjector + - CMILib +depend: + - Vault +commands: + solar: + description: Solar Network Related Command + usage: §e/solar §r + aliases: ['sn'] + permission: solar-network.command.sn + permission-message: §cYou don't have the permission -> §6[solar-network.command.sn] +permissions: + solar-network.command.sn: + description: Permission of uses Solar Network Command + default: true \ No newline at end of file