Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c38923b65 | |||
| a5a9f8c393 | |||
| 7c4dbf6727 | |||
| 47977d9be2 | |||
| e78badda3c |
@@ -1,49 +0,0 @@
|
||||
name: Build Plugin
|
||||
run-name: Building Plugin 🚀
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'ver/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build with Maven
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up JDK 25 and enable Maven cache
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'liberica'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
|
||||
- name: Set up Maven
|
||||
uses: stCarolas/setup-maven@v5
|
||||
with:
|
||||
maven-version: 3.9.16
|
||||
|
||||
- name: Build and package with Maven
|
||||
run: mvn -B package
|
||||
|
||||
- name: Determine version
|
||||
id: set-version
|
||||
shell: bash
|
||||
run: |
|
||||
VERSION=${GITHUB_REF#refs/tags/ver/}
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload built artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: maven-artifacts
|
||||
path: target/spigot/*.jar
|
||||
|
||||
- uses: akkuman/gitea-release-action@v1
|
||||
with:
|
||||
name: '${{ steps.set-version.outputs.version }} Release'
|
||||
files: target/spigot/*.jar
|
||||
@@ -6,85 +6,17 @@
|
||||
|
||||
<groupId>xyz.fortern</groupId>
|
||||
<artifactId>fortern-helper</artifactId>
|
||||
<version>1.3</version>
|
||||
<version>1.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>fortern-helper</name>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigotmc-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>placeholderapi</id>
|
||||
<url>https://repo.helpch.at/releases/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codemc-repo</id>
|
||||
<url>https://repo.codemc.io/repository/maven-public/</url>
|
||||
<layout>default</layout>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<properties>
|
||||
<java.version>25</java.version>
|
||||
<kotlin.version>2.4.0</kotlin.version>
|
||||
<kotlin.version>2.3.21</kotlin.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spigot API -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>26.1-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Kotlin Stdlib https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib -->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- JetBrains Java Annotations https://mvnrepository.com/artifact/org.jetbrains/annotations -->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>26.1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Adventure API https://mvnrepository.com/artifact/net.kyori/adventure-api -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.26.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Adventure Platform Bukkit https://mvnrepository.com/artifact/net.kyori/adventure-platform-bukkit -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bukkit</artifactId>
|
||||
<version>4.4.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- PlaceholderAPI -->
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.12.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- NBT-API -->
|
||||
<dependency>
|
||||
<groupId>de.tr7zw</groupId>
|
||||
<artifactId>item-nbt-api-plugin</artifactId>
|
||||
<version>2.15.7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
||||
@@ -118,11 +50,6 @@
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<finalName>${project.artifactId}-spigot-${project.version}</finalName>
|
||||
<outputDirectory>${project.build.directory}/spigot</outputDirectory>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
@@ -132,4 +59,59 @@
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigotmc-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>placeholderapi</id>
|
||||
<url>https://repo.helpch.at/releases/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spigot API -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>26.1-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Kotlin Stdlib https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib -->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
<!-- JetBrains Java Annotations https://mvnrepository.com/artifact/org.jetbrains/annotations -->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>26.1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Adventure API https://mvnrepository.com/artifact/net.kyori/adventure-api -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.26.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Adventure Platform Bukkit https://mvnrepository.com/artifact/net.kyori/adventure-platform-bukkit -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bukkit</artifactId>
|
||||
<version>4.4.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- PlaceholderAPI -->
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.12.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -4,41 +4,27 @@ import me.clip.placeholderapi.expansion.PlaceholderExpansion
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import xyz.fortern.forternhelper.async.AsyncManager
|
||||
import xyz.fortern.forternhelper.command.HelperCommand
|
||||
import xyz.fortern.forternhelper.listener.ForternListener
|
||||
import xyz.fortern.forternhelper.placeholder.ForternExpansion
|
||||
import java.io.File
|
||||
|
||||
class Helper : JavaPlugin() {
|
||||
private lateinit var adventure: BukkitAudiences
|
||||
|
||||
private lateinit var expansion: PlaceholderExpansion
|
||||
|
||||
private lateinit var asyncManager: AsyncManager
|
||||
|
||||
override fun onEnable() {
|
||||
// Plugin startup logic
|
||||
this.adventure = BukkitAudiences.create(this)
|
||||
|
||||
// init data-folders
|
||||
logger.info("Initializing data-folders...")
|
||||
File(this.dataFolder, "block-nbt").mkdirs()
|
||||
File(this.dataFolder, "item-nbt").mkdirs()
|
||||
|
||||
// register asyncManager
|
||||
logger.info("Registering asyncManager...")
|
||||
asyncManager = AsyncManager(this)
|
||||
|
||||
// register listeners
|
||||
logger.info("Registering listeners...")
|
||||
// register listeners
|
||||
Bukkit.getPluginManager().registerEvents(ForternListener(this), this)
|
||||
// register commands
|
||||
logger.info("Registering commands...")
|
||||
Bukkit.getPluginCommand("helper")!!.setExecutor(HelperCommand(this, adventure, asyncManager))
|
||||
// register placeholders
|
||||
// register commands
|
||||
Bukkit.getPluginCommand("helper")?.setExecutor(HelperCommand(this, adventure))
|
||||
// register placeholder
|
||||
expansion = ForternExpansion(this)
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
|
||||
expansion = ForternExpansion(this)
|
||||
logger.info("Registering placeholders...")
|
||||
expansion.register()
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
package xyz.fortern.forternhelper.async
|
||||
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.logging.Level
|
||||
|
||||
class AsyncManager(
|
||||
private val plugin: JavaPlugin,
|
||||
) {
|
||||
private val tasks: MutableSet<AsyncTask> = HashSet()
|
||||
|
||||
init {
|
||||
// sync
|
||||
Bukkit.getScheduler().runTaskTimer(plugin, Runnable {
|
||||
val iterator = tasks.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val asyncTaskTracker = iterator.next()
|
||||
try {
|
||||
val result = asyncTaskTracker.tick()
|
||||
if (result == AsyncTask.Result.RUNNING) {
|
||||
continue
|
||||
} else if (result == AsyncTask.Result.TIMEOUT) {
|
||||
plugin.logger.warning("Async task timed out: ${asyncTaskTracker.info}")
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
plugin.logger.log(Level.SEVERE, "Error while ticking AsyncManager", t)
|
||||
}
|
||||
iterator.remove()
|
||||
}
|
||||
}, 0, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个异步任务[asyncFun],该异步任务结束后,会在主线程同步执行另一个任务[syncFun]。
|
||||
* 需要超时时间[timeout]。
|
||||
* 此方法应当在主线程调用。
|
||||
*/
|
||||
fun execInMainAfterAsync(info: String, timeout: Int, asyncFun: () -> Unit, syncFun: () -> Unit) {
|
||||
val future = CompletableFuture<Void>()
|
||||
val bukkitTask = Bukkit.getScheduler().runTaskAsynchronously(plugin, Runnable {
|
||||
try {
|
||||
asyncFun()
|
||||
future.complete(null)
|
||||
} catch (t: Throwable) {
|
||||
future.completeExceptionally(t)
|
||||
}
|
||||
})
|
||||
val asyncTaskTracker = AsyncTask(bukkitTask.taskId, info, future, timeout, syncFun)
|
||||
tasks.add(asyncTaskTracker)
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncTask(
|
||||
val id: Int,
|
||||
val info: String,
|
||||
val future: CompletableFuture<Void>,
|
||||
var timeout: Int,
|
||||
val syncFun: () -> Unit,
|
||||
) {
|
||||
/**
|
||||
* 每tick执行一次。 返回 [Result.TIMEOUT] 如果超时; 返回 [Result.TIMEOUT] 如果正在运行; 返回 [Result.DONE] 如果完成。
|
||||
*
|
||||
* @throws Throwable 当异步任务或同步任务执行出现异常时,抛出那个异常
|
||||
*/
|
||||
@Throws(Throwable::class)
|
||||
fun tick(): Result {
|
||||
if (future.isDone) {
|
||||
if (!future.isCompletedExceptionally) {
|
||||
syncFun.invoke()
|
||||
} else {
|
||||
throw future.exceptionNow()
|
||||
}
|
||||
return Result.DONE
|
||||
}
|
||||
timeout--
|
||||
if (timeout < 0) {
|
||||
future.cancel(true)
|
||||
return Result.TIMEOUT
|
||||
}
|
||||
return Result.RUNNING
|
||||
}
|
||||
|
||||
enum class Result {
|
||||
RUNNING, DONE, TIMEOUT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package xyz.fortern.forternhelper.command
|
||||
|
||||
import de.tr7zw.nbtapi.NBT
|
||||
import de.tr7zw.nbtapi.iface.ReadWriteNBT
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.format.NamedTextColor
|
||||
@@ -11,19 +9,15 @@ import org.bukkit.command.CommandSender
|
||||
import org.bukkit.command.TabExecutor
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import xyz.fortern.forternhelper.async.AsyncManager
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.util.logging.Level
|
||||
|
||||
class HelperCommand(
|
||||
private val plugin: JavaPlugin,
|
||||
private val adventure: BukkitAudiences,
|
||||
private val asyncManager: AsyncManager,
|
||||
) : TabExecutor {
|
||||
|
||||
) : TabExecutor {
|
||||
private val subCommands: List<String> = listOf("loadlevel")
|
||||
private val helpMessages = listOf(
|
||||
Component.text("fortern-helper v${plugin.description.version}", NamedTextColor.GREEN),
|
||||
Component.text("Minehunt v${plugin.description.version}", NamedTextColor.GREEN),
|
||||
Component.text("/helper help ", NamedTextColor.GOLD)
|
||||
.append(Component.text("帮助信息", NamedTextColor.WHITE)),
|
||||
Component.text("/helper loadlevel <chunkPosX> <chunkPosZ> [world] ", NamedTextColor.GOLD)
|
||||
@@ -60,24 +54,8 @@ class HelperCommand(
|
||||
}
|
||||
}
|
||||
return when (args[0]) {
|
||||
"help" -> {
|
||||
onHelp(sender, exe)
|
||||
}
|
||||
|
||||
"loadlevel" -> {
|
||||
onLoadLevel(sender, args, exe)
|
||||
}
|
||||
|
||||
"setblock" -> {
|
||||
setBlockFromNbt(sender, args, exe)
|
||||
null
|
||||
}
|
||||
|
||||
"getitem" -> {
|
||||
getItemFromNbt(sender, args, exe)
|
||||
null
|
||||
}
|
||||
|
||||
"help" -> onHelp(sender, exe)
|
||||
"loadlevel" -> onLoadLevel(sender, args, exe)
|
||||
else -> {
|
||||
if (exe) {
|
||||
adventure.sender(sender).sendMessage(Component.text("错误的子命令"))
|
||||
@@ -90,113 +68,6 @@ class HelperCommand(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getItemFromNbt(sender: CommandSender, args: List<String>, exe: Boolean) {
|
||||
// args[0]:getitem | args[1]:0 | args[2]:txt
|
||||
if (!exe) return
|
||||
if (sender !is Player) return
|
||||
if (!sender.isOp) return
|
||||
if (args.size < 2) return
|
||||
val i = args[1]
|
||||
val isNbt = if (args.size > 2) args[2] == "nbt" else false
|
||||
val itemNbtDir = File(plugin.dataFolder, "item-nbt")
|
||||
|
||||
var readWriteNBT: ReadWriteNBT? = null
|
||||
var fileExists = true
|
||||
var parse = true
|
||||
|
||||
asyncManager.execInMainAfterAsync("read item nbt in helper command", 20, run@{
|
||||
if (isNbt) {
|
||||
val file = File(itemNbtDir, "${i}.nbt")
|
||||
if (!file.exists()) {
|
||||
fileExists = false
|
||||
return@run
|
||||
}
|
||||
try {
|
||||
readWriteNBT = NBT.readFile(file)
|
||||
} catch (ex: Exception) {
|
||||
plugin.logger.log(Level.WARNING, "Error reading nbt", ex)
|
||||
parse = false
|
||||
}
|
||||
} else {
|
||||
val file = File(itemNbtDir, "${i}.txt")
|
||||
if (!file.exists()) {
|
||||
fileExists = false
|
||||
return@run
|
||||
}
|
||||
try {
|
||||
readWriteNBT = NBT.parseNBT(FileReader(file).readAllAsString())
|
||||
} catch (ex: Exception) {
|
||||
plugin.logger.log(Level.WARNING, "Error reading nbt", ex)
|
||||
parse = false
|
||||
}
|
||||
}
|
||||
}) {
|
||||
if (!fileExists) {
|
||||
adventure.sender(sender).sendMessage(Component.text("文件不存在"))
|
||||
} else if (!parse) {
|
||||
adventure.sender(sender).sendMessage(Component.text("文件解析错误"))
|
||||
} else {
|
||||
if (readWriteNBT != null) {
|
||||
sender.inventory.addItem(NBT.itemStackFromNBT(readWriteNBT))
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
private fun setBlockFromNbt(sender: CommandSender, args: List<String>, exe: Boolean) {
|
||||
// args[0]:setblock | args[1]:0 | args[2]:txt
|
||||
if (!exe) return
|
||||
if (sender !is Player) return
|
||||
if (!sender.isOp) return
|
||||
if (args.size < 2) return
|
||||
val i = args[1]
|
||||
val isNbt = if (args.size > 2) args[2] == "nbt" else false
|
||||
val world = sender.world
|
||||
val blockState = world.getBlockState(0, 128, 0)
|
||||
val blockNbtDir = File(plugin.dataFolder, "block-nbt")
|
||||
|
||||
var readWriteNBT: ReadWriteNBT? = null
|
||||
var fileExists = true
|
||||
var parse = true
|
||||
|
||||
asyncManager.execInMainAfterAsync("read block nbt in helper command", 20, run@{
|
||||
if (isNbt) {
|
||||
val file = File(blockNbtDir, "${i}.nbt")
|
||||
if (!file.exists()) {
|
||||
fileExists = false
|
||||
return@run
|
||||
}
|
||||
try {
|
||||
readWriteNBT = NBT.readFile(file)
|
||||
} catch (ex: Exception) {
|
||||
plugin.logger.log(Level.WARNING, "Error reading nbt", ex)
|
||||
parse = false
|
||||
}
|
||||
} else {
|
||||
val file = File(blockNbtDir, "${i}.txt")
|
||||
if (!file.exists()) {
|
||||
fileExists = false
|
||||
return@run
|
||||
}
|
||||
readWriteNBT = NBT.parseNBT(FileReader(file).readAllAsString())
|
||||
}
|
||||
}) {
|
||||
if (!fileExists) {
|
||||
adventure.sender(sender).sendMessage(Component.text("文件不存在"))
|
||||
} else if (!parse) {
|
||||
adventure.sender(sender).sendMessage(Component.text("文件解析错误"))
|
||||
} else {
|
||||
if (readWriteNBT != null) {
|
||||
NBT.modify(blockState) { nbt: ReadWriteNBT ->
|
||||
nbt.mergeCompound(readWriteNBT)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
private fun onHelp(sender: CommandSender, exe: Boolean): List<String>? {
|
||||
if (exe) sendHelp(sender)
|
||||
return null
|
||||
|
||||
@@ -3,10 +3,7 @@ version: '${version}'
|
||||
authors: [ Fortern ]
|
||||
api-version: '26.1'
|
||||
main: xyz.fortern.forternhelper.Helper
|
||||
softdepend:
|
||||
- PlaceholderAPI
|
||||
depend:
|
||||
- NBTAPI
|
||||
softdepend: ["PlaceholderAPI"]
|
||||
|
||||
libraries:
|
||||
- org.jetbrains.kotlin:kotlin-stdlib:2.3.21
|
||||
@@ -16,8 +13,3 @@ libraries:
|
||||
commands:
|
||||
helper:
|
||||
description: "游戏主命令"
|
||||
permission: fortern.helper
|
||||
|
||||
permissions:
|
||||
fortern.helper:
|
||||
default: op
|
||||
|
||||
Reference in New Issue
Block a user