From 08338a6d6fdc15f8ec5dfd4f9102e5a55ec80961 Mon Sep 17 00:00:00 2001 From: toxicity Date: Sat, 20 Apr 2024 13:32:19 +0900 Subject: [PATCH] Adds self-host pack, Supports offline-mode head. --- .../kr/toxicity/hud/api/nms/NMSVersion.java | 3 +- .../hud/api/scheduler/HudScheduler.java | 8 ++ build.gradle.kts | 2 +- .../kotlin/kr/toxicity/hud/BetterHudImpl.kt | 1 + .../kr/toxicity/hud/manager/ConfigManager.kt | 9 ++ .../toxicity/hud/manager/PlayerHeadManager.kt | 4 +- .../kr/toxicity/hud/manager/PlayerManager.kt | 9 +- .../kr/toxicity/hud/manager/TextManager.kt | 4 +- .../kr/toxicity/hud/pack/PackGenerator.kt | 60 ++++++++-- .../kr/toxicity/hud/pack/PackUploader.kt | 108 ++++++++++++++++++ ...Provider.kt => GameProfileSkinProvider.kt} | 2 +- .../toxicity/hud/player/HttpSkinProvider.kt | 28 +++-- ...ovider.kt => SkinsRestorerSkinProvider.kt} | 2 +- .../kotlin/kr/toxicity/hud/util/Plugins.kt | 1 + dist/src/main/resources/config.yml | 3 + dist/src/main/resources/icon.png | Bin 0 -> 639 bytes .../{default.json => minecraft_default.json} | 0 .../kr/toxicity/hud/nms/v1_20_R4/NMSImpl.kt | 2 +- .../toxicity/hud/scheduler/FoliaScheduler.kt | 14 +++ .../hud/scheduler/StandardScheduler.kt | 13 +++ 20 files changed, 242 insertions(+), 31 deletions(-) create mode 100644 dist/src/main/kotlin/kr/toxicity/hud/pack/PackUploader.kt rename dist/src/main/kotlin/kr/toxicity/hud/player/{GameProfileProvider.kt => GameProfileSkinProvider.kt} (78%) rename dist/src/main/kotlin/kr/toxicity/hud/player/{SkinRestorerProvider.kt => SkinsRestorerSkinProvider.kt} (85%) create mode 100644 dist/src/main/resources/icon.png rename dist/src/main/resources/{default.json => minecraft_default.json} (100%) diff --git a/api/src/main/java/kr/toxicity/hud/api/nms/NMSVersion.java b/api/src/main/java/kr/toxicity/hud/api/nms/NMSVersion.java index eb52d5fa..172161e4 100644 --- a/api/src/main/java/kr/toxicity/hud/api/nms/NMSVersion.java +++ b/api/src/main/java/kr/toxicity/hud/api/nms/NMSVersion.java @@ -17,7 +17,8 @@ public enum NMSVersion { V1_19_R3(19,3, 13), V1_20_R1(20,1, 15), V1_20_R2(20,2, 18), - V1_20_R3(20,3, 22) + V1_20_R3(20,3, 22), + V1_20_R4(20,4, 32) ; /** * Main version. diff --git a/api/src/main/java/kr/toxicity/hud/api/scheduler/HudScheduler.java b/api/src/main/java/kr/toxicity/hud/api/scheduler/HudScheduler.java index e039db0b..606b90e6 100644 --- a/api/src/main/java/kr/toxicity/hud/api/scheduler/HudScheduler.java +++ b/api/src/main/java/kr/toxicity/hud/api/scheduler/HudScheduler.java @@ -14,6 +14,14 @@ public interface HudScheduler { * @return scheduled task. */ @NotNull HudTask task(@NotNull Plugin plugin, @NotNull Runnable runnable); + /** + * Executes sync task. + * @param plugin target plugin. + * @param delay delay + * @param runnable task + * @return scheduled task. + */ + @NotNull HudTask taskLater(@NotNull Plugin plugin, long delay, @NotNull Runnable runnable); /** * Executes async task. * @param plugin target plugin. diff --git a/build.gradle.kts b/build.gradle.kts index 6e39716b..3287e12a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,7 +33,7 @@ allprojects { apply(plugin = "kotlin") group = "kr.toxicity.hud" - version = "beta-15-HOTFIX" + version = "beta-16" repositories { mavenCentral() diff --git a/dist/src/main/kotlin/kr/toxicity/hud/BetterHudImpl.kt b/dist/src/main/kotlin/kr/toxicity/hud/BetterHudImpl.kt index 2b0c1b24..6f763a97 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/BetterHudImpl.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/BetterHudImpl.kt @@ -183,6 +183,7 @@ class BetterHudImpl: BetterHud() { "v1_20_R1" -> kr.toxicity.hud.nms.v1_20_R1.NMSImpl() "v1_20_R2" -> kr.toxicity.hud.nms.v1_20_R2.NMSImpl() "v1_20_R3" -> kr.toxicity.hud.nms.v1_20_R3.NMSImpl() + //"v1_20_R4" -> kr.toxicity.hud.nms.v1_20_R4.NMSImpl() else -> { warn("Unsupported bukkit version: $version") pluginManager.disablePlugin(this) diff --git a/dist/src/main/kotlin/kr/toxicity/hud/manager/ConfigManager.kt b/dist/src/main/kotlin/kr/toxicity/hud/manager/ConfigManager.kt index 9dac3f4d..454c5455 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/manager/ConfigManager.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/manager/ConfigManager.kt @@ -27,11 +27,17 @@ object ConfigManager: BetterHudManager { private set var buildFolderLocation = "BetterHud\\build" private set + var enableProtection = true + private set var mergeBossBar = true private set var packType = PackType.FOLDER private set + var enableSelfHost = false + private set + var selfHostPort = 8163 + private set override fun start() { @@ -66,7 +72,10 @@ object ConfigManager: BetterHudManager { yaml.getString("build-folder-location")?.let { buildFolderLocation = it } + enableProtection = yaml.getBoolean("enable-protection") mergeBossBar = yaml.getBoolean("merge-boss-bar", true) + enableSelfHost = yaml.getBoolean("enable-self-host") + selfHostPort = yaml.getInt("self-host-port", 8163) }.onFailure { e -> warn("Unable to load config.yml") warn("Reason: ${e.message}") diff --git a/dist/src/main/kotlin/kr/toxicity/hud/manager/PlayerHeadManager.kt b/dist/src/main/kotlin/kr/toxicity/hud/manager/PlayerHeadManager.kt index 10096372..cb2fbcf2 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/manager/PlayerHeadManager.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/manager/PlayerHeadManager.kt @@ -12,12 +12,12 @@ import java.awt.image.BufferedImage object PlayerHeadManager: BetterHudManager { private val skinProviders = ArrayList() - private val defaultProviders = GameProfileProvider() + private val defaultProviders = GameProfileSkinProvider() private val headMap = HashMap() override fun start() { if (Bukkit.getPluginManager().isPluginEnabled("SkinsRestorer")) { - skinProviders.add(SkinRestorerProvider()) + skinProviders.add(SkinsRestorerSkinProvider()) } if (!Bukkit.getServer().onlineMode) { skinProviders.add(HttpSkinProvider()) diff --git a/dist/src/main/kotlin/kr/toxicity/hud/manager/PlayerManager.kt b/dist/src/main/kotlin/kr/toxicity/hud/manager/PlayerManager.kt index 0bc3b613..043ecb0a 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/manager/PlayerManager.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/manager/PlayerManager.kt @@ -3,11 +3,9 @@ package kr.toxicity.hud.manager import kr.toxicity.hud.api.event.HudPlayerJoinEvent import kr.toxicity.hud.api.event.HudPlayerQuitEvent import kr.toxicity.hud.api.player.HudPlayer +import kr.toxicity.hud.pack.PackUploader import kr.toxicity.hud.resource.GlobalResource -import kr.toxicity.hud.util.PLUGIN -import kr.toxicity.hud.util.asyncTask -import kr.toxicity.hud.util.call -import kr.toxicity.hud.util.task +import kr.toxicity.hud.util.* import org.bukkit.Bukkit import org.bukkit.entity.Player import org.bukkit.event.EventHandler @@ -48,6 +46,9 @@ object PlayerManager: BetterHudManager { hudPlayer.computeIfAbsent(adaptedPlayer.uniqueId) { val hud = DatabaseManagerImpl.currentDatabase.load(adaptedPlayer) task { + taskLater(20) { + PackUploader.apply(player) + } HudPlayerJoinEvent(adaptedPlayer, hud).call() } hud diff --git a/dist/src/main/kotlin/kr/toxicity/hud/manager/TextManager.kt b/dist/src/main/kotlin/kr/toxicity/hud/manager/TextManager.kt index c3e71946..1756708f 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/manager/TextManager.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/manager/TextManager.kt @@ -140,7 +140,7 @@ object TextManager: BetterHudManager { private fun loadDefaultBitmap() { defaultBitmapImageMap.clear() - PLUGIN.getResource("default.json")?.let { + PLUGIN.getResource("minecraft_default.json")?.let { runCatching { InputStreamReader(it).buffered().use { reader -> JsonParser.parseReader(reader) @@ -174,7 +174,7 @@ object TextManager: BetterHudManager { } } }.onFailure { e -> - warn("Unable to parse default.json") + warn("Unable to parse minecraft_default.json") warn("Reason: ${e.message}") } } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/pack/PackGenerator.kt b/dist/src/main/kotlin/kr/toxicity/hud/pack/PackGenerator.kt index 76f8d297..cc843a7b 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/pack/PackGenerator.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/pack/PackGenerator.kt @@ -1,8 +1,13 @@ package kr.toxicity.hud.pack +import com.google.gson.JsonObject import kr.toxicity.hud.manager.ConfigManager import kr.toxicity.hud.util.* +import org.bukkit.Bukkit import java.io.File +import java.math.BigInteger +import java.security.DigestOutputStream +import java.security.MessageDigest import java.util.Comparator import java.util.TreeMap import java.util.zip.Deflater @@ -12,6 +17,12 @@ import java.util.zip.ZipOutputStream object PackGenerator { private val tasks = TreeMap() + private class ZipBuilder( + val zip: ZipOutputStream + ) { + var byte = 0 + } + fun generate(callback: () -> Unit) { runCatching { val saveTask: Generator = when (ConfigManager.packType) { @@ -62,9 +73,18 @@ object PackGenerator { } } PackType.ZIP -> { - val zip = ZipOutputStream(File(DATA_FOLDER.parentFile, "${ConfigManager.buildFolderLocation}.zip").apply { + val protection = ConfigManager.enableProtection + val host = ConfigManager.enableSelfHost + val message = runCatching { + MessageDigest.getInstance("SHA-1") + }.getOrNull() + val file = File(DATA_FOLDER.parentFile, "${ConfigManager.buildFolderLocation}.zip") + val stream = file.apply { if (!exists()) delete() - }.outputStream().buffered()).apply { + }.outputStream().buffered() + val zip = ZipBuilder(ZipOutputStream(message?.let { + DigestOutputStream(stream, it) + } ?: stream).apply { setComment("BetterHud resource pack.") setLevel(Deflater.BEST_COMPRESSION) PLUGIN.loadAssets("pack") { s, i -> @@ -72,22 +92,46 @@ object PackGenerator { write(i.readAllBytes()) closeEntry() } + }) + fun addEntry(entry: ZipEntry, byte: ByteArray) { + synchronized(zip) { + zip.byte += byte.size + zip.zip.putNextEntry(entry) + zip.zip.write(byte) + zip.zip.closeEntry() + if (protection) { + entry.crc = byte.size.toLong() + entry.size = BigInteger(byte).mod(BigInteger.valueOf(Long.MAX_VALUE)).toLong() + } + } + } + if (host) { + PLUGIN.getResource("icon.png")?.buffered()?.use { + addEntry(ZipEntry("pack.png"), it.readAllBytes()) + } + addEntry(ZipEntry("pack.mcmeta"), JsonObject().apply { + add("pack", JsonObject().apply { + addProperty("pack_format", PLUGIN.nms.version.metaVersion) + addProperty("description", "BetterHud's self host pack.") + }) + }.toByteArray()) } object : Generator { override fun close() { synchronized(zip) { - zip.close() + zip.zip.close() + if (host && message != null) { + PackUploader.upload(message, file.inputStream().buffered().use { + it.readAllBytes() + }) + } else PackUploader.stop() } } override fun invoke(p1: PackFile) { val entry = ZipEntry(p1.path) val byte = p1.array() - synchronized(zip) { - zip.putNextEntry(entry) - zip.write(byte) - zip.closeEntry() - } + addEntry(entry, byte) } } } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/pack/PackUploader.kt b/dist/src/main/kotlin/kr/toxicity/hud/pack/PackUploader.kt new file mode 100644 index 00000000..3142e8fd --- /dev/null +++ b/dist/src/main/kotlin/kr/toxicity/hud/pack/PackUploader.kt @@ -0,0 +1,108 @@ +package kr.toxicity.hud.pack + +import com.google.gson.JsonPrimitive +import com.sun.net.httpserver.HttpServer +import kr.toxicity.hud.api.nms.NMSVersion +import kr.toxicity.hud.manager.ConfigManager +import kr.toxicity.hud.util.* +import org.bukkit.Bukkit +import org.bukkit.entity.Player +import java.net.InetAddress +import java.net.InetSocketAddress +import java.net.URI +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse +import java.security.MessageDigest +import java.util.* + + +object PackUploader { + + private interface PackServer { + fun stop() + fun apply(player: Player) + } + @Volatile + private var server: PackServer? = null + + fun apply(player: Player): Boolean { + return server?.apply(player) != null + } + fun stop(): Boolean { + val result = server?.stop() != null + server = null + return result + } + + fun upload(message: MessageDigest, byteArray: ByteArray) { + val hash = StringBuilder(40) + val useUrl = VERSION >= NMSVersion.V1_20_R3 + val digest = message.digest() + for (element in digest) { + val byte = element.toInt() + hash.append(Character.forDigit((byte shr 4) and 15, 16)) + .append(Character.forDigit(byte and 15, 16)) + } + val string = hash.toString() + var t = 0 + val uuid = UUID.nameUUIDFromBytes(ByteArray(20) { + ((Character.digit(hash.codePointAt(t++), 16) shl 4) or Character.digit(hash.codePointAt(t++), 16)).toByte() + }) + HttpClient.newHttpClient() + .sendAsync(HttpRequest.newBuilder() + .uri(URI.create("http://checkip.amazonaws.com/")) + .GET() + .build(), HttpResponse.BodyHandlers.ofString()).thenAccept { + val host = ConfigManager.selfHostPort + val body = it.body() + val url = "http://${body.substring(0, body.length - 1)}:$host/$string.zip" + runCatching { + server?.stop() + val http = HttpServer.create(InetSocketAddress(InetAddress.getLocalHost(), host), 0).apply { + createContext("/") { exec -> + exec.use { exchange -> + if (exchange.requestURI.path != "/$string.zip") { + exchange.responseHeaders.set("Content-Type", "application/json") + val byte = JsonPrimitive("Invalid file name.").toByteArray() + exchange.sendResponseHeaders(200, byte.size.toLong()) + exchange.responseBody.write(byte) + } else { + exchange.responseHeaders.set("Content-Type", "application/zip") + exchange.sendResponseHeaders(200, byteArray.size.toLong()) + exchange.responseBody.write(byteArray) + } + } + } + start() + } + server = object : PackServer { + override fun stop() { + http.stop(0) + } + override fun apply(player: Player) { + if (useUrl) { + player.setResourcePack(uuid, url, digest, null, false) + } else { + player.setResourcePack(url, digest, null, false) + } + } + } + Bukkit.getOnlinePlayers().forEach { player -> + if (useUrl) { + player.setResourcePack(uuid, url, digest, null, false) + } else { + player.setResourcePack(url, digest, null, false) + } + } + info("Resource pack server opened at $url") + }.onFailure { e -> + e.printStackTrace() + warn("Unable to open server.") + } + }.handle { _, e -> + e.printStackTrace() + warn("Unable to get host's ip.") + } + } +} \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/player/GameProfileProvider.kt b/dist/src/main/kotlin/kr/toxicity/hud/player/GameProfileSkinProvider.kt similarity index 78% rename from dist/src/main/kotlin/kr/toxicity/hud/player/GameProfileProvider.kt rename to dist/src/main/kotlin/kr/toxicity/hud/player/GameProfileSkinProvider.kt index a872ea53..cd03b116 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/player/GameProfileProvider.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/player/GameProfileSkinProvider.kt @@ -3,7 +3,7 @@ package kr.toxicity.hud.player import kr.toxicity.hud.util.textures import org.bukkit.entity.Player -class GameProfileProvider: PlayerSkinProvider { +class GameProfileSkinProvider: PlayerSkinProvider { override fun provide(player: Player): String { return player.textures } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/player/HttpSkinProvider.kt b/dist/src/main/kotlin/kr/toxicity/hud/player/HttpSkinProvider.kt index fb498333..1ca98164 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/player/HttpSkinProvider.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/player/HttpSkinProvider.kt @@ -10,16 +10,24 @@ import java.net.http.HttpResponse class HttpSkinProvider: PlayerSkinProvider { override fun provide(player: Player): String? { - return InputStreamReader(HttpClient.newHttpClient().send(HttpRequest.newBuilder() - .uri(URI.create("https://sessionserver.mojang.com/session/minecraft/profile/${player.uniqueId.toString().replace("_","").lowercase()}")) - .GET() - .build(), HttpResponse.BodyHandlers.ofInputStream()).body()).buffered().use { + return runCatching { + val uuid = InputStreamReader(HttpClient.newHttpClient().send(HttpRequest.newBuilder() + .uri(URI.create("https://api.mojang.com/users/profiles/minecraft/${player.name}?at=${System.currentTimeMillis() / 1000}")) + .GET() + .build(), HttpResponse.BodyHandlers.ofInputStream()).body()).buffered().use { JsonParser.parseReader(it) - }.asJsonObject - .getAsJsonArray("properties") - .get(0) - .asJsonObject - .getAsJsonPrimitive("value") - .asString + }.asJsonObject.getAsJsonPrimitive("id").asString + InputStreamReader(HttpClient.newHttpClient().send(HttpRequest.newBuilder() + .uri(URI.create("https://sessionserver.mojang.com/session/minecraft/profile/$uuid")) + .GET() + .build(), HttpResponse.BodyHandlers.ofInputStream()).body()).buffered().use { + JsonParser.parseReader(it) + }.asJsonObject + .getAsJsonArray("properties") + .get(0) + .asJsonObject + .getAsJsonPrimitive("value") + .asString + }.getOrNull() } } \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/player/SkinRestorerProvider.kt b/dist/src/main/kotlin/kr/toxicity/hud/player/SkinsRestorerSkinProvider.kt similarity index 85% rename from dist/src/main/kotlin/kr/toxicity/hud/player/SkinRestorerProvider.kt rename to dist/src/main/kotlin/kr/toxicity/hud/player/SkinsRestorerSkinProvider.kt index 7f03e8cb..2e52e851 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/player/SkinRestorerProvider.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/player/SkinsRestorerSkinProvider.kt @@ -3,7 +3,7 @@ package kr.toxicity.hud.player import net.skinsrestorer.api.SkinsRestorerProvider import org.bukkit.entity.Player -class SkinRestorerProvider: PlayerSkinProvider { +class SkinsRestorerSkinProvider: PlayerSkinProvider { override fun provide(player: Player): String? { return SkinsRestorerProvider.get().playerStorage.getSkinOfPlayer(player.uniqueId).map { it.value diff --git a/dist/src/main/kotlin/kr/toxicity/hud/util/Plugins.kt b/dist/src/main/kotlin/kr/toxicity/hud/util/Plugins.kt index ce73d448..81fcf30f 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/util/Plugins.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/util/Plugins.kt @@ -18,5 +18,6 @@ fun info(message: String) = PLUGIN.logger.info(message) fun warn(message: String) = PLUGIN.logger.warning(message) fun task(block: () -> Unit) = PLUGIN.scheduler.task(PLUGIN, block) +fun taskLater(delay: Long, block: () -> Unit) = PLUGIN.scheduler.taskLater(PLUGIN, delay, block) fun asyncTask(block: () -> Unit) = PLUGIN.scheduler.asyncTask(PLUGIN, block) fun asyncTaskTimer(delay: Long, period: Long, block: () -> Unit) = PLUGIN.scheduler.asyncTaskTimer(PLUGIN, delay, period, block) \ No newline at end of file diff --git a/dist/src/main/resources/config.yml b/dist/src/main/resources/config.yml index ae7e569b..701237c8 100644 --- a/dist/src/main/resources/config.yml +++ b/dist/src/main/resources/config.yml @@ -8,6 +8,9 @@ disable-to-bedrock-player: true build-folder-location: "BetterHud/build" pack-type: folder #folder, zip +enable-protection: false +enable-self-host: false +self-host-port: 8163 default-hud: - test_hud diff --git a/dist/src/main/resources/icon.png b/dist/src/main/resources/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..031d740f680c9873d6d27d05246b4138211d0fd8 GIT binary patch literal 639 zcmeAS@N?(olHy`uVBq!ia0vp^u^`OB3?x6SpY;()F%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl{K2=EDUO^hwIHTUXYw&D1l3+n1-ODjUFA|fO0+-;4G8%3-V1l<}f%rcV~ zdzfc=N3S+fta%;gy}=+RSk?67^(7Z;W3N5Fvux+VwEvHNm;L`gF|F0pqpouD|Ns9F z9lF?BR0Xu;!)p8biL>4nJ@ErzW#^d=bQh*+*@pN$v z$#8yq?V;Zx1Ch3eok|w2BFp+X-~4+&Y5M0 z2XE`z?9PzQu#ma;-b|{u#^IEe%>1`ibHC}lDt#v(oMmflg#i&o-{?jaVt^(iD zhASmvG1kk1|3xPW=Ka6s`YP7j@%r}NV%yJ|{|gG3m2~NRG|R8%rLOayTP<+fYQWjvxJbF<;?Z?jmFgN;tY>+PiGN^Ee~j)__u z_WEm-y8R0l*_nRvnf$j(kCa)dxcIAIe3AaX>g%q148c3JI_o=J1%Z*n;OXk;vd$@? F2>{!2ELH#j literal 0 HcmV?d00001 diff --git a/dist/src/main/resources/default.json b/dist/src/main/resources/minecraft_default.json similarity index 100% rename from dist/src/main/resources/default.json rename to dist/src/main/resources/minecraft_default.json diff --git a/nms/v1_20_R4/src/main/kotlin/kr/toxicity/hud/nms/v1_20_R4/NMSImpl.kt b/nms/v1_20_R4/src/main/kotlin/kr/toxicity/hud/nms/v1_20_R4/NMSImpl.kt index 222dea02..2ea1db5e 100644 --- a/nms/v1_20_R4/src/main/kotlin/kr/toxicity/hud/nms/v1_20_R4/NMSImpl.kt +++ b/nms/v1_20_R4/src/main/kotlin/kr/toxicity/hud/nms/v1_20_R4/NMSImpl.kt @@ -93,7 +93,7 @@ class NMSImpl: NMS { } override fun getVersion(): NMSVersion { - return NMSVersion.V1_20_R3 + return NMSVersion.V1_20_R4 } override fun getTextureValue(player: Player): String { diff --git a/scheduler/folia/src/main/kotlin/kr/toxicity/hud/scheduler/FoliaScheduler.kt b/scheduler/folia/src/main/kotlin/kr/toxicity/hud/scheduler/FoliaScheduler.kt index c4e32f2d..4e7c5d29 100644 --- a/scheduler/folia/src/main/kotlin/kr/toxicity/hud/scheduler/FoliaScheduler.kt +++ b/scheduler/folia/src/main/kotlin/kr/toxicity/hud/scheduler/FoliaScheduler.kt @@ -21,6 +21,20 @@ class FoliaScheduler: HudScheduler { } } + override fun taskLater(plugin: Plugin, delay: Long, runnable: Runnable): HudTask { + val task = Bukkit.getGlobalRegionScheduler().runDelayed(plugin, { + runnable.run() + }, delay) + return object : HudTask { + override fun isCancelled(): Boolean { + return task.isCancelled + } + override fun cancel() { + task.cancel() + } + } + } + override fun asyncTask(plugin: Plugin, runnable: Runnable): HudTask { val task = Bukkit.getAsyncScheduler().runNow(plugin) { runnable.run() diff --git a/scheduler/standard/src/main/kotlin/kr/toxicity/hud/scheduler/StandardScheduler.kt b/scheduler/standard/src/main/kotlin/kr/toxicity/hud/scheduler/StandardScheduler.kt index 70ee5d40..3ec80f0a 100644 --- a/scheduler/standard/src/main/kotlin/kr/toxicity/hud/scheduler/StandardScheduler.kt +++ b/scheduler/standard/src/main/kotlin/kr/toxicity/hud/scheduler/StandardScheduler.kt @@ -18,6 +18,19 @@ class StandardScheduler: HudScheduler { } } + + override fun taskLater(plugin: Plugin, delay: Long, runnable: Runnable): HudTask { + val task = Bukkit.getScheduler().runTaskLater(plugin, runnable, delay) + return object : HudTask { + override fun isCancelled(): Boolean { + return task.isCancelled + } + override fun cancel() { + task.cancel() + } + } + } + override fun asyncTask(plugin: Plugin, runnable: Runnable): HudTask { val task = Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable) return object : HudTask {