Compare commits

..

6 Commits

Author SHA1 Message Date
Fortern 03ddc4eee1 ver 1.2 2026-06-07 16:23:02 +08:00
Fortern d4ead15f4a workflows 2026-06-07 16:23:02 +08:00
Fortern be643c3a49 Depending on NBT-API 2026-06-07 16:22:59 +08:00
Fortern e90700264d ver 1.1 2026-06-07 16:22:24 +08:00
Fortern 3dddcd6665 占位符 2026-06-07 16:22:21 +08:00
Fortern c431c21a8e 区块等级 2026-06-07 12:15:40 +08:00
5 changed files with 30 additions and 207 deletions
+1 -15
View File
@@ -9,11 +9,9 @@ jobs:
build:
name: Build with Maven
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Set up JDK 25 and enable Maven cache
uses: actions/setup-java@v5
@@ -30,20 +28,8 @@ jobs:
- 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
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>xyz.fortern</groupId>
<artifactId>fortern-helper</artifactId>
<version>1.3</version>
<version>1.2</version>
<packaging>jar</packaging>
<name>fortern-helper</name>
@@ -4,38 +4,24 @@ 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 commands
Bukkit.getPluginCommand("helper")?.setExecutor(HelperCommand(this, adventure))
// register placeholders
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
expansion = ForternExpansion(this)
@@ -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
}
}
@@ -11,19 +11,17 @@ 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)
@@ -99,48 +97,16 @@ class HelperCommand(
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 nbt = 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
}
if (!file.exists()) return
NBT.readFile(file)
} 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))
}
}
if (!file.exists()) return
NBT.parseNBT(FileReader(file).readAllAsString())
}
sender.inventory.addItem(NBT.itemStackFromNBT(nbt))
return
}
@@ -154,46 +120,19 @@ class HelperCommand(
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
}
val itemNbtDir = File(plugin.dataFolder, "block-nbt")
val readWriteNBT = if (isNbt) {
val file = File(itemNbtDir, "${i}.nbt")
if (!file.exists()) return
NBT.readFile(file)
} else {
val file = File(blockNbtDir, "${i}.txt")
if (!file.exists()) {
fileExists = false
return@run
val file = File(itemNbtDir, "${i}.txt")
if (!file.exists()) return
NBT.parseNBT(FileReader(file).readAllAsString())
}
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
}