From 7da903ae21e237bedafbfc63a33c1ea1215f5dbc Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 20 Oct 2026 05:22:52 +0200 Subject: [PATCH 1/5] feat: add placeholders module --- README.md | 2 +- .../main/kotlin/simplecloud.base-conventions.gradle.kts | 1 + gradle/libs.versions.toml | 2 ++ server/placeholders/placeholders-paper/build.gradle.kts | 7 +++++++ server/placeholders/placeholders-shared/build.gradle.kts | 4 ++++ 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d958b5..c252bbe 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,6 @@ ## Todo - [x] release publishing -- [ ] placeholders +- [x] placeholders - [ ] signs - [ ] npcs diff --git a/build-logic/src/main/kotlin/simplecloud.base-conventions.gradle.kts b/build-logic/src/main/kotlin/simplecloud.base-conventions.gradle.kts index 69af428..c7cb35f 100644 --- a/build-logic/src/main/kotlin/simplecloud.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/simplecloud.base-conventions.gradle.kts @@ -31,6 +31,7 @@ repositories { maven("https://repo.waterdog.dev/snapshots/") maven("https://repo.opencollab.dev/maven-releases/") maven("https://repo.opencollab.dev/maven-snapshots/") + maven("https://repo.extendedclip.com/releases/") } dependencies { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5bb6c31..7c73236 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,6 +14,7 @@ bungeecord = "1.21-R0.4" waterdog = "2.0.4-SNAPSHOT" paper = "26.3.build.+" minestom = "26_3-SNAPSHOT" +placeholderapi = "2.12.3" adventure = "5.2.0" adventure-platform-bungeecord = "4.4.1" @@ -42,6 +43,7 @@ bungeecord-api = { module = "net.md-5:bungeecord-api", version.ref = "bungeecord waterdog-api = { module = "dev.waterdog.waterdogpe:waterdog", version.ref = "waterdog" } paper-api = { module = "io.papermc.paper:paper-api", version.ref = "paper" } minestom = { module = "net.minestom:minestom", version.ref = "minestom" } +placeholderapi = { module = "me.clip:placeholderapi", version.ref = "placeholderapi" } adventure = { module = "net.kyori:adventure-api", version.ref = "adventure" } adventure-text-minimessage = { module = "net.kyori:adventure-text-minimessage", version.ref = "adventure" } diff --git a/server/placeholders/placeholders-paper/build.gradle.kts b/server/placeholders/placeholders-paper/build.gradle.kts index fedbf37..6f6017a 100644 --- a/server/placeholders/placeholders-paper/build.gradle.kts +++ b/server/placeholders/placeholders-paper/build.gradle.kts @@ -1,3 +1,10 @@ plugins { id("simplecloud.base-conventions") } + +dependencies { + implementation(projects.server.placeholders.placeholdersShared) + compileOnly(libs.simplecloud.api) + compileOnly(libs.paper.api) + compileOnly(libs.placeholderapi) +} diff --git a/server/placeholders/placeholders-shared/build.gradle.kts b/server/placeholders/placeholders-shared/build.gradle.kts index fedbf37..2bf11fb 100644 --- a/server/placeholders/placeholders-shared/build.gradle.kts +++ b/server/placeholders/placeholders-shared/build.gradle.kts @@ -1,3 +1,7 @@ plugins { id("simplecloud.base-conventions") } + +dependencies { + compileOnly(libs.simplecloud.api) +} From 256bbda03843cc3c34e3e0bc0b87bbf95bc12b97 Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 20 Oct 2026 05:55:47 +0200 Subject: [PATCH 2/5] feat: add placeholder plugin --- .../src/main/kotlin/.gitkeep | 0 .../paper/PaperPlaceholdersPlugin.kt | 19 +++++ .../expansion/PlaceholderApiExpansion.kt | 20 ++++++ .../src/main/resources/paper-plugin.yml | 19 +++++ .../placeholders-shared/build.gradle.kts | 1 + .../src/main/kotlin/.gitkeep | 0 .../placeholders/shared/PlaceholdersPlugin.kt | 26 +++++++ .../shared/placeholder/GroupPlaceholders.kt | 35 ++++++++++ .../PersistentServerPlaceholders.kt | 42 +++++++++++ .../shared/placeholder/PlaceholderType.kt | 16 +++++ .../shared/placeholder/ServerPlaceholders.kt | 61 ++++++++++++++++ .../shared/query/PlaceholderQuery.kt | 9 +++ .../shared/query/PlaceholderQueryParser.kt | 30 ++++++++ .../shared/resolve/PlaceholderResolver.kt | 69 +++++++++++++++++++ 14 files changed, 347 insertions(+) delete mode 100644 server/placeholders/placeholders-paper/src/main/kotlin/.gitkeep create mode 100644 server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt create mode 100644 server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/PlaceholderApiExpansion.kt create mode 100644 server/placeholders/placeholders-paper/src/main/resources/paper-plugin.yml delete mode 100644 server/placeholders/placeholders-shared/src/main/kotlin/.gitkeep create mode 100644 server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt create mode 100644 server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/GroupPlaceholders.kt create mode 100644 server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/PersistentServerPlaceholders.kt create mode 100644 server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/PlaceholderType.kt create mode 100644 server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/ServerPlaceholders.kt create mode 100644 server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/query/PlaceholderQuery.kt create mode 100644 server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/query/PlaceholderQueryParser.kt create mode 100644 server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt diff --git a/server/placeholders/placeholders-paper/src/main/kotlin/.gitkeep b/server/placeholders/placeholders-paper/src/main/kotlin/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt new file mode 100644 index 0000000..becca3b --- /dev/null +++ b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt @@ -0,0 +1,19 @@ +package app.simplecloud.plugin.placeholders.paper + +import app.simplecloud.plugin.placeholders.paper.expansion.PlaceholderApiExpansion +import app.simplecloud.plugin.placeholders.shared.PlaceholdersPlugin +import org.bukkit.plugin.java.JavaPlugin + +class PaperPlaceholdersPlugin : JavaPlugin() { + + private val placeholders = PlaceholdersPlugin() + + override fun onEnable() { + placeholders.start() + PlaceholderApiExpansion(placeholders.resolver).register() + } + + override fun onDisable() { + placeholders.shutdown() + } +} diff --git a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/PlaceholderApiExpansion.kt b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/PlaceholderApiExpansion.kt new file mode 100644 index 0000000..51d565f --- /dev/null +++ b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/PlaceholderApiExpansion.kt @@ -0,0 +1,20 @@ +package app.simplecloud.plugin.placeholders.paper.expansion + +import app.simplecloud.plugin.placeholders.shared.resolve.PlaceholderResolver +import me.clip.placeholderapi.expansion.PlaceholderExpansion +import org.bukkit.OfflinePlayer + +class PlaceholderApiExpansion( + private val resolver: PlaceholderResolver, +) : PlaceholderExpansion() { + + override fun getIdentifier() = "simplecloud" + + override fun getAuthor() = "SimpleCloud" + + override fun getVersion() = "0.0.0" + + override fun persist() = true + + override fun onRequest(player: OfflinePlayer?, params: String): String? = resolver.resolve(params) +} diff --git a/server/placeholders/placeholders-paper/src/main/resources/paper-plugin.yml b/server/placeholders/placeholders-paper/src/main/resources/paper-plugin.yml new file mode 100644 index 0000000..8c4e5fd --- /dev/null +++ b/server/placeholders/placeholders-paper/src/main/resources/paper-plugin.yml @@ -0,0 +1,19 @@ +name: simplecloud-placeholder +version: ${version} +main: app.simplecloud.plugin.placeholders.paper.PaperPlaceholdersPlugin +api-version: "1.20" +author: SimpleCloud Maintainers +description: Provides SimpleCloud placeholders for PlaceholderAPI +website: https://github.com/simplecloudapp/plugins +folia-supported: true + +dependencies: + server: + PlaceholderAPI: + load: BEFORE + required: true + join-classpath: true + simplecloud-api: + load: BEFORE + required: true + join-classpath: true diff --git a/server/placeholders/placeholders-shared/build.gradle.kts b/server/placeholders/placeholders-shared/build.gradle.kts index 2bf11fb..0b29f3a 100644 --- a/server/placeholders/placeholders-shared/build.gradle.kts +++ b/server/placeholders/placeholders-shared/build.gradle.kts @@ -4,4 +4,5 @@ plugins { dependencies { compileOnly(libs.simplecloud.api) + compileOnly(libs.slf4j.api) } diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/.gitkeep b/server/placeholders/placeholders-shared/src/main/kotlin/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt new file mode 100644 index 0000000..bb9c5ae --- /dev/null +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt @@ -0,0 +1,26 @@ +package app.simplecloud.plugin.placeholders.shared + +import app.simplecloud.api.CloudApi +import app.simplecloud.api.CloudApiOptions +import app.simplecloud.plugin.placeholders.shared.placeholder.GroupPlaceholders +import app.simplecloud.plugin.placeholders.shared.placeholder.PersistentServerPlaceholders +import app.simplecloud.plugin.placeholders.shared.placeholder.ServerPlaceholders +import app.simplecloud.plugin.placeholders.shared.resolve.PlaceholderResolver +import kotlinx.coroutines.* + +class PlaceholdersPlugin { + + private val api: CloudApi = CloudApi.create(CloudApiOptions.builder().component("placeholders").build()) + private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) + + val resolver = PlaceholderResolver(api, scope) + + fun start() { + resolver.preloadCurrent(listOf(ServerPlaceholders, GroupPlaceholders, PersistentServerPlaceholders)) + } + + fun shutdown() { + scope.cancel() + api.close() + } +} diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/GroupPlaceholders.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/GroupPlaceholders.kt new file mode 100644 index 0000000..2fb8a80 --- /dev/null +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/GroupPlaceholders.kt @@ -0,0 +1,35 @@ +package app.simplecloud.plugin.placeholders.shared.placeholder + +import app.simplecloud.api.CloudApi +import app.simplecloud.api.group.Group +import app.simplecloud.api.runtime.SimpleCloudRuntime +import app.simplecloud.api.server.ServerQuery +import kotlinx.coroutines.future.await + +object GroupPlaceholders : PlaceholderType { + + data class Data(val group: Group, val playerCount: Int) + + override val prefix = "group" + + override val properties = setOf("name", "type", "min_memory", "max_memory", "max_players", "player_count") + + override fun getValue(resource: Data, property: String): Any? = when (property) { + "name" -> resource.group.name + "type" -> resource.group.type + "min_memory" -> resource.group.minMemory + "max_memory" -> resource.group.maxMemory + "max_players" -> resource.group.maxPlayers + "player_count" -> resource.playerCount + else -> null + } + + override suspend fun loadCurrent(api: CloudApi): Data? = load(api, SimpleCloudRuntime.groupName()) + + override suspend fun load(api: CloudApi, target: String): Data? { + val group = api.group().getGroupByName(target).await() ?: return null + val query = ServerQuery.create().filterByServerGroupName(group.name) + val servers = api.server().getAllServers(query).await() + return Data(group, servers.sumOf { it.playerCount ?: 0 }) + } +} diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/PersistentServerPlaceholders.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/PersistentServerPlaceholders.kt new file mode 100644 index 0000000..fbdc4e4 --- /dev/null +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/PersistentServerPlaceholders.kt @@ -0,0 +1,42 @@ +package app.simplecloud.plugin.placeholders.shared.placeholder + +import app.simplecloud.api.CloudApi +import app.simplecloud.api.persistentserver.PersistentServer +import app.simplecloud.api.runtime.SimpleCloudRuntime +import kotlinx.coroutines.future.await + +object PersistentServerPlaceholders : PlaceholderType { + + override val prefix = "persistent_server" + + override val properties = setOf( + "id", + "name", + "type", + "host", + "max_players", + "min_memory", + "max_memory", + "player_count", + "is_active", + ) + + override fun getValue(resource: PersistentServer, property: String): Any? = when (property) { + "id" -> resource.persistentServerId + "name" -> resource.name + "type" -> resource.type + "host" -> resource.serverhostId + "max_players" -> resource.maxPlayers + "min_memory" -> resource.minMemory + "max_memory" -> resource.maxMemory + "player_count" -> resource.playerCount + "is_active" -> resource.isActive + else -> null + } + + override suspend fun loadCurrent(api: CloudApi): PersistentServer? = + api.persistentServer().getPersistentServerById(SimpleCloudRuntime.serverId()).await() + + override suspend fun load(api: CloudApi, target: String): PersistentServer? = + api.persistentServer().getPersistentServerByName(target).await() +} diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/PlaceholderType.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/PlaceholderType.kt new file mode 100644 index 0000000..cc774d0 --- /dev/null +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/PlaceholderType.kt @@ -0,0 +1,16 @@ +package app.simplecloud.plugin.placeholders.shared.placeholder + +import app.simplecloud.api.CloudApi + +interface PlaceholderType { + + val prefix: String + + val properties: Set + + fun getValue(resource: T, property: String): Any? + + suspend fun loadCurrent(api: CloudApi): T? + + suspend fun load(api: CloudApi, target: String): T? +} diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/ServerPlaceholders.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/ServerPlaceholders.kt new file mode 100644 index 0000000..e61400e --- /dev/null +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/placeholder/ServerPlaceholders.kt @@ -0,0 +1,61 @@ +package app.simplecloud.plugin.placeholders.shared.placeholder + +import app.simplecloud.api.CloudApi +import app.simplecloud.api.runtime.SimpleCloudRuntime +import app.simplecloud.api.server.Server +import kotlinx.coroutines.future.await + +object ServerPlaceholders : PlaceholderType { + + private const val ID_PREFIX = "id:" + + override val prefix = "server" + + override val properties = setOf( + "id", + "type", + "host", + "numerical_id", + "ip", + "port", + "max_players", + "min_memory", + "max_memory", + "player_count", + "state", + ) + + override fun getValue(resource: Server, property: String): Any? = when (property) { + "id" -> resource.serverId + "type" -> resource.serverBase.type + "host" -> resource.serverhostId + "numerical_id" -> resource.numericalId + "ip" -> resource.ip + "port" -> resource.port + "max_players" -> resource.maxPlayers + "min_memory" -> resource.minMemory + "max_memory" -> resource.maxMemory + "player_count" -> resource.playerCount + "state" -> resource.state + else -> null + } + + override suspend fun loadCurrent(api: CloudApi): Server? = api.server().getServerById(SimpleCloudRuntime.serverId()).await() + + override suspend fun load(api: CloudApi, target: String): Server? = + if (target.startsWith(ID_PREFIX)) loadById(api, target.removePrefix(ID_PREFIX)) else loadByNumericalId(api, target) + + private suspend fun loadById(api: CloudApi, serverId: String): Server? { + if (serverId.isBlank()) return null + return api.server().getServerById(serverId).await() + } + + private suspend fun loadByNumericalId(api: CloudApi, target: String): Server? { + val separator = target.lastIndexOf(':') + if (separator <= 0) return null + + val groupName = target.substring(0, separator) + val numericalId = target.substring(separator + 1).toIntOrNull() ?: return null + return api.server().getServerByNumericalId(groupName, numericalId).await() + } +} diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/query/PlaceholderQuery.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/query/PlaceholderQuery.kt new file mode 100644 index 0000000..ec2cd51 --- /dev/null +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/query/PlaceholderQuery.kt @@ -0,0 +1,9 @@ +package app.simplecloud.plugin.placeholders.shared.query + +import app.simplecloud.plugin.placeholders.shared.placeholder.PlaceholderType + +data class PlaceholderQuery( + val type: PlaceholderType<*>, + val target: String?, + val property: String, +) diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/query/PlaceholderQueryParser.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/query/PlaceholderQueryParser.kt new file mode 100644 index 0000000..0d94d01 --- /dev/null +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/query/PlaceholderQueryParser.kt @@ -0,0 +1,30 @@ +package app.simplecloud.plugin.placeholders.shared.query + +import app.simplecloud.plugin.placeholders.shared.placeholder.GroupPlaceholders +import app.simplecloud.plugin.placeholders.shared.placeholder.PersistentServerPlaceholders +import app.simplecloud.plugin.placeholders.shared.placeholder.PlaceholderType +import app.simplecloud.plugin.placeholders.shared.placeholder.ServerPlaceholders + +class PlaceholderQueryParser(private val types: List> = DEFAULT_TYPES) { + + fun parse(params: String): PlaceholderQuery? { + for (type in types) { + val prefix = "${type.prefix}_" + if (!params.startsWith(prefix)) continue + + val rest = params.removePrefix(prefix) + val property = findProperty(type, rest) ?: continue + val target = rest.removeSuffix(property).removeSuffix("_").ifEmpty { null } + return PlaceholderQuery(type, target, property) + } + return null + } + + private fun findProperty(type: PlaceholderType<*>, rest: String): String? = type.properties + .sortedByDescending { it.length } + .firstOrNull { rest == it || rest.endsWith("_$it") } + + private companion object { + val DEFAULT_TYPES = listOf(PersistentServerPlaceholders, ServerPlaceholders, GroupPlaceholders) + } +} diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt new file mode 100644 index 0000000..9444cb8 --- /dev/null +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt @@ -0,0 +1,69 @@ +package app.simplecloud.plugin.placeholders.shared.resolve + +import app.simplecloud.api.CloudApi +import app.simplecloud.plugin.placeholders.shared.placeholder.PlaceholderType +import app.simplecloud.plugin.placeholders.shared.query.PlaceholderQuery +import app.simplecloud.plugin.placeholders.shared.query.PlaceholderQueryParser +import kotlinx.coroutines.* +import java.util.concurrent.ConcurrentHashMap +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds +import kotlin.time.TimeMark +import kotlin.time.TimeSource + +class PlaceholderResolver( + private val api: CloudApi, + private val scope: CoroutineScope, + private val parser: PlaceholderQueryParser = PlaceholderQueryParser(), + private val ttl: Duration = 5.seconds, +) { + + private val cache = ConcurrentHashMap() + private val loading = ConcurrentHashMap.newKeySet() + + fun resolve(params: String): String? { + val query = parser.parse(params) ?: return null + return resolve(query) + } + + fun resolve(query: PlaceholderQuery): String { + val key = ResourceKey(query.type, query.target) + val cached = cache[key] + if (cached == null || cached.loadedAt.elapsedNow() > ttl) refresh(key) + + val resource = cached?.resource ?: return "" + return query.type.read(resource, query.property)?.toString().orEmpty() + } + + fun preloadCurrent(types: List>) { + types.forEach { refresh(ResourceKey(it, null)) } + } + + private fun refresh(key: ResourceKey) { + if (!loading.add(key)) return + + scope.launch { + try { + cache[key] = CachedResource(load(key), TimeSource.Monotonic.markNow()) + } finally { + loading.remove(key) + } + } + } + + private suspend fun load(key: ResourceKey): Any? = try { + if (key.target == null) key.type.loadCurrent(api) else key.type.load(api, key.target) + } catch (e: CancellationException) { + throw e + } catch (_: Exception) { + null + } + + @Suppress("UNCHECKED_CAST") + private fun PlaceholderType<*>.read(resource: Any, property: String): Any? = + (this as PlaceholderType).getValue(resource, property) + + private data class ResourceKey(val type: PlaceholderType<*>, val target: String?) + + private class CachedResource(val resource: Any?, val loadedAt: TimeMark) +} From afe397c09c29813e01d37971bb5c35a512d802fa Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 20 Oct 2026 06:22:06 +0200 Subject: [PATCH 3/5] feat: add support for MiniPlaceholders --- gradle/libs.versions.toml | 2 + .../placeholders-paper/build.gradle.kts | 1 + .../paper/PaperPlaceholdersPlugin.kt | 23 +++++++++- .../expansion/MiniPlaceholdersExpansion.kt | 43 +++++++++++++++++++ .../src/main/resources/paper-plugin.yml | 10 +++-- .../placeholders/shared/PlaceholdersPlugin.kt | 7 ++- 6 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/MiniPlaceholdersExpansion.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c73236..dd8c70c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ waterdog = "2.0.4-SNAPSHOT" paper = "26.3.build.+" minestom = "26_3-SNAPSHOT" placeholderapi = "2.12.3" +miniplaceholders = "3.2.0" adventure = "5.2.0" adventure-platform-bungeecord = "4.4.1" @@ -44,6 +45,7 @@ waterdog-api = { module = "dev.waterdog.waterdogpe:waterdog", version.ref = "wat paper-api = { module = "io.papermc.paper:paper-api", version.ref = "paper" } minestom = { module = "net.minestom:minestom", version.ref = "minestom" } placeholderapi = { module = "me.clip:placeholderapi", version.ref = "placeholderapi" } +miniplaceholders-api = { module = "io.github.miniplaceholders:miniplaceholders-api", version.ref = "miniplaceholders" } adventure = { module = "net.kyori:adventure-api", version.ref = "adventure" } adventure-text-minimessage = { module = "net.kyori:adventure-text-minimessage", version.ref = "adventure" } diff --git a/server/placeholders/placeholders-paper/build.gradle.kts b/server/placeholders/placeholders-paper/build.gradle.kts index 6f6017a..7421853 100644 --- a/server/placeholders/placeholders-paper/build.gradle.kts +++ b/server/placeholders/placeholders-paper/build.gradle.kts @@ -7,4 +7,5 @@ dependencies { compileOnly(libs.simplecloud.api) compileOnly(libs.paper.api) compileOnly(libs.placeholderapi) + compileOnly(libs.miniplaceholders.api) } diff --git a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt index becca3b..68e891e 100644 --- a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt +++ b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt @@ -1,5 +1,6 @@ package app.simplecloud.plugin.placeholders.paper +import app.simplecloud.plugin.placeholders.paper.expansion.MiniPlaceholdersExpansion import app.simplecloud.plugin.placeholders.paper.expansion.PlaceholderApiExpansion import app.simplecloud.plugin.placeholders.shared.PlaceholdersPlugin import org.bukkit.plugin.java.JavaPlugin @@ -8,12 +9,32 @@ class PaperPlaceholdersPlugin : JavaPlugin() { private val placeholders = PlaceholdersPlugin() + private var placeholderApiExpansion: PlaceholderApiExpansion? = null + private var miniPlaceholdersExpansion: MiniPlaceholdersExpansion? = null + override fun onEnable() { placeholders.start() - PlaceholderApiExpansion(placeholders.resolver).register() + + val version = pluginMeta.version + if (server.pluginManager.isPluginEnabled("PlaceholderAPI")) { + val expansion = PlaceholderApiExpansion(placeholders.resolver) + expansion.register() + placeholderApiExpansion = expansion + } + if (server.pluginManager.isPluginEnabled("MiniPlaceholders")) { + val expansion = MiniPlaceholdersExpansion(placeholders.resolver, placeholders.types, version) + expansion.register() + miniPlaceholdersExpansion = expansion + } + + if (placeholderApiExpansion == null && miniPlaceholdersExpansion == null) { + logger.warning("Neither PlaceholderAPI nor MiniPlaceholders is installed, no placeholders will be registered") + } } override fun onDisable() { + placeholderApiExpansion?.unregister() + miniPlaceholdersExpansion?.unregister() placeholders.shutdown() } } diff --git a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/MiniPlaceholdersExpansion.kt b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/MiniPlaceholdersExpansion.kt new file mode 100644 index 0000000..71613a9 --- /dev/null +++ b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/MiniPlaceholdersExpansion.kt @@ -0,0 +1,43 @@ +package app.simplecloud.plugin.placeholders.paper.expansion + +import app.simplecloud.plugin.placeholders.shared.placeholder.PlaceholderType +import app.simplecloud.plugin.placeholders.shared.query.PlaceholderQuery +import app.simplecloud.plugin.placeholders.shared.resolve.PlaceholderResolver +import io.github.miniplaceholders.api.Expansion +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.minimessage.tag.Tag +import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue + +class MiniPlaceholdersExpansion( + private val resolver: PlaceholderResolver, + types: List>, + version: String, +) { + + private val expansion: Expansion + + init { + val builder = Expansion.builder("simplecloud").author("SimpleCloud").version(version) + types.forEach { type -> + type.properties.forEach { property -> + builder.globalPlaceholder("${type.prefix}_$property") { queue, _ -> resolve(type, property, queue) } + } + } + expansion = builder.build() + } + + fun register() = expansion.register() + + fun unregister() { + if (expansion.registered()) expansion.unregister() + } + + private fun resolve(type: PlaceholderType<*>, property: String, queue: ArgumentQueue): Tag { + val arguments = mutableListOf() + while (queue.hasNext()) arguments += queue.pop().value() + + val target = arguments.joinToString(":").ifEmpty { null } + val value = resolver.resolve(PlaceholderQuery(type, target, property)) + return Tag.selfClosingInserting(Component.text(value)) + } +} diff --git a/server/placeholders/placeholders-paper/src/main/resources/paper-plugin.yml b/server/placeholders/placeholders-paper/src/main/resources/paper-plugin.yml index 8c4e5fd..630ff8d 100644 --- a/server/placeholders/placeholders-paper/src/main/resources/paper-plugin.yml +++ b/server/placeholders/placeholders-paper/src/main/resources/paper-plugin.yml @@ -1,9 +1,9 @@ name: simplecloud-placeholder version: ${version} main: app.simplecloud.plugin.placeholders.paper.PaperPlaceholdersPlugin -api-version: "1.20" +api-version: "1.21.11" author: SimpleCloud Maintainers -description: Provides SimpleCloud placeholders for PlaceholderAPI +description: Provides SimpleCloud placeholders for PlaceholderAPI and MiniPlaceholders website: https://github.com/simplecloudapp/plugins folia-supported: true @@ -11,7 +11,11 @@ dependencies: server: PlaceholderAPI: load: BEFORE - required: true + required: false + join-classpath: true + MiniPlaceholders: + load: BEFORE + required: false join-classpath: true simplecloud-api: load: BEFORE diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt index bb9c5ae..7a1c945 100644 --- a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt @@ -4,7 +4,9 @@ import app.simplecloud.api.CloudApi import app.simplecloud.api.CloudApiOptions import app.simplecloud.plugin.placeholders.shared.placeholder.GroupPlaceholders import app.simplecloud.plugin.placeholders.shared.placeholder.PersistentServerPlaceholders +import app.simplecloud.plugin.placeholders.shared.placeholder.PlaceholderType import app.simplecloud.plugin.placeholders.shared.placeholder.ServerPlaceholders +import app.simplecloud.plugin.placeholders.shared.query.PlaceholderQueryParser import app.simplecloud.plugin.placeholders.shared.resolve.PlaceholderResolver import kotlinx.coroutines.* @@ -13,10 +15,11 @@ class PlaceholdersPlugin { private val api: CloudApi = CloudApi.create(CloudApiOptions.builder().component("placeholders").build()) private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) - val resolver = PlaceholderResolver(api, scope) + val types: List> = listOf(PersistentServerPlaceholders, ServerPlaceholders, GroupPlaceholders) + val resolver = PlaceholderResolver(api, scope, PlaceholderQueryParser(types)) fun start() { - resolver.preloadCurrent(listOf(ServerPlaceholders, GroupPlaceholders, PersistentServerPlaceholders)) + resolver.preloadCurrent(types) } fun shutdown() { From d10b0886d1aff2aa904550a6cdabc1321fe1e705 Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 20 Oct 2026 06:40:47 +0200 Subject: [PATCH 4/5] refactor: use caffeine for placeholder cache --- gradle/libs.versions.toml | 3 + .../placeholders-shared/build.gradle.kts | 1 + .../shared/resolve/PlaceholderResolver.kt | 58 +++++++++---------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dd8c70c..bec13d7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,6 +22,7 @@ adventure-platform-bungeecord = "4.4.1" configurate = "4.2.0" +caffeine = "3.3.1" slf4j = "2.0.20" cloud = "2.1.0" @@ -58,6 +59,8 @@ configurate-yaml = { module = "org.spongepowered:configurate-yaml", version.ref configurate-gson = { module = "org.spongepowered:configurate-gson", version.ref = "configurate" } configurate-extra-kotlin = { module = "org.spongepowered:configurate-extra-kotlin", version.ref = "configurate" } +caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version.ref = "caffeine" } + slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } cloud-core = { module = "org.incendo:cloud-core", version.ref = "cloud" } diff --git a/server/placeholders/placeholders-shared/build.gradle.kts b/server/placeholders/placeholders-shared/build.gradle.kts index 0b29f3a..b83b0c1 100644 --- a/server/placeholders/placeholders-shared/build.gradle.kts +++ b/server/placeholders/placeholders-shared/build.gradle.kts @@ -5,4 +5,5 @@ plugins { dependencies { compileOnly(libs.simplecloud.api) compileOnly(libs.slf4j.api) + implementation(libs.caffeine) } diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt index 9444cb8..2aeb275 100644 --- a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt @@ -4,22 +4,30 @@ import app.simplecloud.api.CloudApi import app.simplecloud.plugin.placeholders.shared.placeholder.PlaceholderType import app.simplecloud.plugin.placeholders.shared.query.PlaceholderQuery import app.simplecloud.plugin.placeholders.shared.query.PlaceholderQueryParser +import com.github.benmanes.caffeine.cache.AsyncCacheLoader +import com.github.benmanes.caffeine.cache.AsyncLoadingCache +import com.github.benmanes.caffeine.cache.Caffeine import kotlinx.coroutines.* -import java.util.concurrent.ConcurrentHashMap -import kotlin.time.Duration +import kotlinx.coroutines.future.future +import org.slf4j.LoggerFactory +import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds -import kotlin.time.TimeMark -import kotlin.time.TimeSource +import kotlin.time.toJavaDuration class PlaceholderResolver( private val api: CloudApi, private val scope: CoroutineScope, private val parser: PlaceholderQueryParser = PlaceholderQueryParser(), - private val ttl: Duration = 5.seconds, + private val loadingValue: String = "...", ) { - private val cache = ConcurrentHashMap() - private val loading = ConcurrentHashMap.newKeySet() + private val logger = LoggerFactory.getLogger(PlaceholderResolver::class.java) + + private val cache: AsyncLoadingCache = Caffeine.newBuilder() + .maximumSize(1_000L) + .refreshAfterWrite(5.seconds.toJavaDuration()) + .expireAfterAccess(5.minutes.toJavaDuration()) + .buildAsync(AsyncCacheLoader { key, _ -> scope.future { CachedResource(load(key)) } }) fun resolve(params: String): String? { val query = parser.parse(params) ?: return null @@ -27,43 +35,31 @@ class PlaceholderResolver( } fun resolve(query: PlaceholderQuery): String { - val key = ResourceKey(query.type, query.target) - val cached = cache[key] - if (cached == null || cached.loadedAt.elapsedNow() > ttl) refresh(key) + val future = cache.get(ResourceKey(query.type, query.target)) + if (!future.isDone) return loadingValue - val resource = cached?.resource ?: return "" - return query.type.read(resource, query.property)?.toString().orEmpty() - } + val resource = future.exceptionally { null }.getNow(null)?.resource ?: return "" - fun preloadCurrent(types: List>) { - types.forEach { refresh(ResourceKey(it, null)) } + @Suppress("UNCHECKED_CAST") + val type = query.type as PlaceholderType + return type.getValue(resource, query.property)?.toString().orEmpty() } - private fun refresh(key: ResourceKey) { - if (!loading.add(key)) return - - scope.launch { - try { - cache[key] = CachedResource(load(key), TimeSource.Monotonic.markNow()) - } finally { - loading.remove(key) - } - } + fun preloadCurrent(types: List>) { + types.forEach { cache.get(ResourceKey(it, null)) } } private suspend fun load(key: ResourceKey): Any? = try { if (key.target == null) key.type.loadCurrent(api) else key.type.load(api, key.target) } catch (e: CancellationException) { throw e - } catch (_: Exception) { + } catch (e: Exception) { + logger.warn("Failed to load {} placeholder for target {}", key.type.prefix, key.target ?: "", e) null } - @Suppress("UNCHECKED_CAST") - private fun PlaceholderType<*>.read(resource: Any, property: String): Any? = - (this as PlaceholderType).getValue(resource, property) - private data class ResourceKey(val type: PlaceholderType<*>, val target: String?) - private class CachedResource(val resource: Any?, val loadedAt: TimeMark) + private class CachedResource(val resource: Any?) + } From 621be5552f21421bdeefcdccd9a260bdae4cfb77 Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 20 Oct 2026 06:57:07 +0200 Subject: [PATCH 5/5] feat: add build constants to placeholders --- .../placeholders/placeholders-paper/build.gradle.kts | 11 +++++++++++ .../plugin/placeholders/BuildConstants.kt.peb | 5 +++++ .../placeholders/paper/PaperPlaceholdersPlugin.kt | 3 +-- .../paper/expansion/MiniPlaceholdersExpansion.kt | 4 ++-- .../paper/expansion/PlaceholderApiExpansion.kt | 3 ++- .../plugin/placeholders/shared/PlaceholdersPlugin.kt | 6 ++---- .../shared/resolve/PlaceholderResolver.kt | 9 +++++++-- 7 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 server/placeholders/placeholders-paper/src/main/kotlin-templates/app/simplecloud/plugin/placeholders/BuildConstants.kt.peb diff --git a/server/placeholders/placeholders-paper/build.gradle.kts b/server/placeholders/placeholders-paper/build.gradle.kts index 7421853..4a37ab7 100644 --- a/server/placeholders/placeholders-paper/build.gradle.kts +++ b/server/placeholders/placeholders-paper/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("simplecloud.base-conventions") + alias(libs.plugins.blossom) } dependencies { @@ -9,3 +10,13 @@ dependencies { compileOnly(libs.placeholderapi) compileOnly(libs.miniplaceholders.api) } + +sourceSets { + main { + blossom { + kotlinSources { + property("version", project.version.toString()) + } + } + } +} diff --git a/server/placeholders/placeholders-paper/src/main/kotlin-templates/app/simplecloud/plugin/placeholders/BuildConstants.kt.peb b/server/placeholders/placeholders-paper/src/main/kotlin-templates/app/simplecloud/plugin/placeholders/BuildConstants.kt.peb new file mode 100644 index 0000000..f1be4f5 --- /dev/null +++ b/server/placeholders/placeholders-paper/src/main/kotlin-templates/app/simplecloud/plugin/placeholders/BuildConstants.kt.peb @@ -0,0 +1,5 @@ +package app.simplecloud.plugin.placeholders + +object BuildConstants { + const val VERSION = "{{ version }}" +} \ No newline at end of file diff --git a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt index 68e891e..758b16e 100644 --- a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt +++ b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/PaperPlaceholdersPlugin.kt @@ -15,14 +15,13 @@ class PaperPlaceholdersPlugin : JavaPlugin() { override fun onEnable() { placeholders.start() - val version = pluginMeta.version if (server.pluginManager.isPluginEnabled("PlaceholderAPI")) { val expansion = PlaceholderApiExpansion(placeholders.resolver) expansion.register() placeholderApiExpansion = expansion } if (server.pluginManager.isPluginEnabled("MiniPlaceholders")) { - val expansion = MiniPlaceholdersExpansion(placeholders.resolver, placeholders.types, version) + val expansion = MiniPlaceholdersExpansion(placeholders.resolver, placeholders.types) expansion.register() miniPlaceholdersExpansion = expansion } diff --git a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/MiniPlaceholdersExpansion.kt b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/MiniPlaceholdersExpansion.kt index 71613a9..78a3ebe 100644 --- a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/MiniPlaceholdersExpansion.kt +++ b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/MiniPlaceholdersExpansion.kt @@ -1,5 +1,6 @@ package app.simplecloud.plugin.placeholders.paper.expansion +import app.simplecloud.plugin.placeholders.BuildConstants import app.simplecloud.plugin.placeholders.shared.placeholder.PlaceholderType import app.simplecloud.plugin.placeholders.shared.query.PlaceholderQuery import app.simplecloud.plugin.placeholders.shared.resolve.PlaceholderResolver @@ -11,13 +12,12 @@ import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue class MiniPlaceholdersExpansion( private val resolver: PlaceholderResolver, types: List>, - version: String, ) { private val expansion: Expansion init { - val builder = Expansion.builder("simplecloud").author("SimpleCloud").version(version) + val builder = Expansion.builder("simplecloud").author("SimpleCloud").version(BuildConstants.VERSION) types.forEach { type -> type.properties.forEach { property -> builder.globalPlaceholder("${type.prefix}_$property") { queue, _ -> resolve(type, property, queue) } diff --git a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/PlaceholderApiExpansion.kt b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/PlaceholderApiExpansion.kt index 51d565f..5a2a35a 100644 --- a/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/PlaceholderApiExpansion.kt +++ b/server/placeholders/placeholders-paper/src/main/kotlin/app/simplecloud/plugin/placeholders/paper/expansion/PlaceholderApiExpansion.kt @@ -1,5 +1,6 @@ package app.simplecloud.plugin.placeholders.paper.expansion +import app.simplecloud.plugin.placeholders.BuildConstants import app.simplecloud.plugin.placeholders.shared.resolve.PlaceholderResolver import me.clip.placeholderapi.expansion.PlaceholderExpansion import org.bukkit.OfflinePlayer @@ -12,7 +13,7 @@ class PlaceholderApiExpansion( override fun getAuthor() = "SimpleCloud" - override fun getVersion() = "0.0.0" + override fun getVersion() = BuildConstants.VERSION override fun persist() = true diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt index 7a1c945..be0c99a 100644 --- a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/PlaceholdersPlugin.kt @@ -8,22 +8,20 @@ import app.simplecloud.plugin.placeholders.shared.placeholder.PlaceholderType import app.simplecloud.plugin.placeholders.shared.placeholder.ServerPlaceholders import app.simplecloud.plugin.placeholders.shared.query.PlaceholderQueryParser import app.simplecloud.plugin.placeholders.shared.resolve.PlaceholderResolver -import kotlinx.coroutines.* class PlaceholdersPlugin { private val api: CloudApi = CloudApi.create(CloudApiOptions.builder().component("placeholders").build()) - private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) val types: List> = listOf(PersistentServerPlaceholders, ServerPlaceholders, GroupPlaceholders) - val resolver = PlaceholderResolver(api, scope, PlaceholderQueryParser(types)) + val resolver = PlaceholderResolver(api, PlaceholderQueryParser(types)) fun start() { resolver.preloadCurrent(types) } fun shutdown() { - scope.cancel() + resolver.shutdown() api.close() } } diff --git a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt index 2aeb275..ed20701 100644 --- a/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt +++ b/server/placeholders/placeholders-shared/src/main/kotlin/app/simplecloud/plugin/placeholders/shared/resolve/PlaceholderResolver.kt @@ -16,11 +16,12 @@ import kotlin.time.toJavaDuration class PlaceholderResolver( private val api: CloudApi, - private val scope: CoroutineScope, private val parser: PlaceholderQueryParser = PlaceholderQueryParser(), private val loadingValue: String = "...", ) { + private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) + private val logger = LoggerFactory.getLogger(PlaceholderResolver::class.java) private val cache: AsyncLoadingCache = Caffeine.newBuilder() @@ -45,10 +46,15 @@ class PlaceholderResolver( return type.getValue(resource, query.property)?.toString().orEmpty() } + @Suppress("IgnoredReturnValue") fun preloadCurrent(types: List>) { types.forEach { cache.get(ResourceKey(it, null)) } } + fun shutdown() { + scope.cancel() + } + private suspend fun load(key: ResourceKey): Any? = try { if (key.target == null) key.type.loadCurrent(api) else key.type.load(api, key.target) } catch (e: CancellationException) { @@ -61,5 +67,4 @@ class PlaceholderResolver( private data class ResourceKey(val type: PlaceholderType<*>, val target: String?) private class CachedResource(val resource: Any?) - }