diff --git a/api/bukkit-api/src/main/java/kr/toxicity/hud/api/bukkit/event/HudPlayerQuitEvent.java b/api/bukkit-api/src/main/java/kr/toxicity/hud/api/bukkit/event/HudPlayerQuitEvent.java index 4d7cac2b..26135a4e 100644 --- a/api/bukkit-api/src/main/java/kr/toxicity/hud/api/bukkit/event/HudPlayerQuitEvent.java +++ b/api/bukkit-api/src/main/java/kr/toxicity/hud/api/bukkit/event/HudPlayerQuitEvent.java @@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull; /** - * HudPlayer quit event. + * player quit event. */ @Getter public class HudPlayerQuitEvent extends PlayerEvent implements BetterHudEvent { diff --git a/api/bukkit-api/src/main/java/kr/toxicity/hud/api/bukkit/event/HudUpdateEvent.java b/api/bukkit-api/src/main/java/kr/toxicity/hud/api/bukkit/event/HudUpdateEvent.java index a3adfd7d..5fd8f9ed 100644 --- a/api/bukkit-api/src/main/java/kr/toxicity/hud/api/bukkit/event/HudUpdateEvent.java +++ b/api/bukkit-api/src/main/java/kr/toxicity/hud/api/bukkit/event/HudUpdateEvent.java @@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull; /** - * HudPlayer update event. + * player update event. */ @Getter public class HudUpdateEvent extends PlayerEvent implements BetterHudEvent { diff --git a/api/standard-api/src/main/java/kr/toxicity/hud/api/popup/Popup.java b/api/standard-api/src/main/java/kr/toxicity/hud/api/popup/Popup.java index c0ecadcf..68ec4183 100644 --- a/api/standard-api/src/main/java/kr/toxicity/hud/api/popup/Popup.java +++ b/api/standard-api/src/main/java/kr/toxicity/hud/api/popup/Popup.java @@ -32,12 +32,12 @@ public interface Popup extends HudObject { @Nullable PopupUpdater show(@NotNull UpdateEvent reason, @NotNull HudPlayer player); /** - * Hides popup to some hudPlayer. - * @param hudPlayer target HudPlayer + * Hides popup to some player. + * @param player target player * @return whether to success */ - default boolean hide(@NotNull HudPlayer hudPlayer) { - var group = hudPlayer.getPopupGroupIteratorMap().remove(getGroupName()); + default boolean hide(@NotNull HudPlayer player) { + var group = player.getPopupGroupIteratorMap().remove(getGroupName()); if (group != null) { group.clear(); return true; @@ -46,7 +46,7 @@ default boolean hide(@NotNull HudPlayer hudPlayer) { /** * Gets a last index of popup. - * It equals getMaxStackSize() - 1 + * It equals getMaxStack() - 1 * @return last index */ default int getLastIndex() { diff --git a/bootstrap/bukkit/build.gradle.kts b/bootstrap/bukkit/build.gradle.kts index 41dd7ab7..ff407113 100644 --- a/bootstrap/bukkit/build.gradle.kts +++ b/bootstrap/bukkit/build.gradle.kts @@ -18,10 +18,10 @@ dependencies { compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.4.0-SNAPSHOT") compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT") compileOnly("com.github.MilkBowl:VaultAPI:1.7.1") - compileOnly("com.github.SkriptLang:Skript:2.9.4") + compileOnly("com.github.SkriptLang:Skript:2.9.5") compileOnly("net.skinsrestorer:skinsrestorer-api:15.4.4") compileOnly("com.alessiodp.parties:parties-bukkit:3.2.16") - compileOnly("com.nexomc:nexo:0.1.0-dev.62") + compileOnly("com.nexomc:nexo:0.1.0-dev.73") compileOnly("io.th0rgal:oraxen:1.185.0") } diff --git a/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/BukkitBootstrapImpl.kt b/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/BukkitBootstrapImpl.kt index 4857d922..f9b85465 100644 --- a/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/BukkitBootstrapImpl.kt +++ b/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/BukkitBootstrapImpl.kt @@ -202,12 +202,12 @@ class BukkitBootstrapImpl : BukkitBootstrap, JavaPlugin() { if (pluginManager.isPluginEnabled("GPS")) PlayerManagerImpl.addLocationProvider(GPSLocationProvider()) pluginManager.registerEvents(object : Listener { @EventHandler(priority = EventPriority.HIGHEST) - fun join(e: PlayerJoinEvent) { - register(e.player) + fun PlayerJoinEvent.join() { + register(player) } @EventHandler - fun quit(e: PlayerQuitEvent) { - val player = e.player + fun PlayerQuitEvent.quit() { + val player = player PlayerManagerImpl.removeHudPlayer(player.uniqueId)?.let { it.cancel() HudPlayerQuitEvent(it).call() @@ -255,8 +255,8 @@ class BukkitBootstrapImpl : BukkitBootstrap, JavaPlugin() { warn("Download: https://www.spigotmc.org/resources/115559") Bukkit.getPluginManager().registerEvents(object : Listener { @EventHandler - fun join(e: PlayerJoinEvent) { - val player = e.player + fun PlayerJoinEvent.join() { + val player = player if (player.isOp && ConfigManagerImpl.versionCheck) { val audience = audiences.player(player) audience.info("New BetterHud version found: $body") diff --git a/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/compatibility/nexo/NexoCompatibility.kt b/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/compatibility/nexo/NexoCompatibility.kt index a5f6de8a..2c07865b 100644 --- a/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/compatibility/nexo/NexoCompatibility.kt +++ b/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/compatibility/nexo/NexoCompatibility.kt @@ -34,11 +34,11 @@ class NexoCompatibility : Compatibility { (BOOTSTRAP as BukkitBootstrapImpl).skipInitialReload = true registerListener(object : Listener { @EventHandler - fun generate(event: NexoPrePackGenerateEvent) { + fun NexoPrePackGenerateEvent.generate() { when (val state = PLUGIN.reload()) { is Success -> { state.resourcePack.forEach { - event.addUnknownFile(it.key, it.value) + addUnknownFile(it.key, it.value) } info("Successfully merged with Nexo: (${state.time} ms)") } diff --git a/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/compatibility/oraxen/OraxenCompatibility.kt b/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/compatibility/oraxen/OraxenCompatibility.kt index 8eb15762..2139e94e 100644 --- a/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/compatibility/oraxen/OraxenCompatibility.kt +++ b/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/compatibility/oraxen/OraxenCompatibility.kt @@ -2,7 +2,6 @@ package kr.toxicity.hud.bootstrap.bukkit.compatibility.oraxen import io.th0rgal.oraxen.api.events.OraxenPackGeneratedEvent import io.th0rgal.oraxen.utils.VirtualFile -import kr.toxicity.hud.api.BetterHudAPI import kr.toxicity.hud.api.listener.HudListener import kr.toxicity.hud.api.placeholder.HudPlaceholder import kr.toxicity.hud.api.plugin.ReloadState.* @@ -35,10 +34,10 @@ class OraxenCompatibility : Compatibility { override fun start() { registerListener(object : Listener { @EventHandler - fun generate(event: OraxenPackGeneratedEvent) { + fun OraxenPackGeneratedEvent.generate() { when (val state = PLUGIN.reload()) { is Success -> { - val output = event.output + val output = output state.resourcePack.forEach { output.add( VirtualFile( diff --git a/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/module/bukkit/BukkitItemModule.kt b/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/module/bukkit/BukkitItemModule.kt index 645eb103..640b6af7 100644 --- a/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/module/bukkit/BukkitItemModule.kt +++ b/bootstrap/bukkit/src/main/kotlin/kr/toxicity/hud/bootstrap/bukkit/module/bukkit/BukkitItemModule.kt @@ -23,16 +23,16 @@ class BukkitItemModule : BukkitModule { override fun start() { registerListener(object : Listener { @EventHandler - fun drop(e: PlayerDropItemEvent) { - UpdateItemEvent(e.player, e.itemDrop.itemStack, e).call() + fun PlayerDropItemEvent.drop() { + UpdateItemEvent(player, itemDrop.itemStack, this).call() } @EventHandler - fun pickup(e: EntityPickupItemEvent) { - val entity = e.entity + fun EntityPickupItemEvent.pickup() { + val entity = entity if (entity is Player) UpdateItemEvent( entity, - e.item.itemStack, - e + item.itemStack, + this ).call() } }) diff --git a/changelog/1.10.md b/changelog/1.10.md index e3c7cddb..a4c6f901 100644 --- a/changelog/1.10.md +++ b/changelog/1.10.md @@ -91,6 +91,28 @@ test_head: y: 3.0 static-scale: true ``` +- Add 'placeholder-option' and 'placeholder-string-format' +```yaml +test_text: + texts: + 1: + name: unifont + pattern: | + [name] + [health_percentage]% + placeholder-option: + evaluate: t * 100 + join: " " + placeholder-string-format: + number: "#,###" + background: test + align: center + line-align: center + scale: 0.5 + line: 5 + split-width: 300 + y: 32 +``` - Add these option in config.yml ```yaml disable-legacy-offset: false #If this is true, a correct pixel offset is provided. diff --git a/dist/src/main/kotlin/kr/toxicity/hud/compass/type/CircleCompass.kt b/dist/src/main/kotlin/kr/toxicity/hud/compass/type/CircleCompass.kt index ccaf2b93..a5cd5418 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/compass/type/CircleCompass.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/compass/type/CircleCompass.kt @@ -13,6 +13,7 @@ import kr.toxicity.hud.manager.ConfigManagerImpl import kr.toxicity.hud.pack.PackGenerator import kr.toxicity.hud.resource.GlobalResource import kr.toxicity.hud.location.GuiLocation +import kr.toxicity.hud.placeholder.PlaceholderSource import kr.toxicity.hud.shader.HudShader import kr.toxicity.hud.shader.RenderScale import kr.toxicity.hud.shader.ShaderProperty @@ -30,7 +31,7 @@ class CircleCompass( override val path: String, private val internalName: String, section: YamlObject -) : CompassImpl { +) : CompassImpl, PlaceholderSource by PlaceholderSource.Impl(section) { companion object { private val defaultColorEquation = TEquation("255").run { ColorEquation( @@ -68,7 +69,7 @@ class CircleCompass( ) private var array: JsonArray? = JsonArray() private val images = CompassImage(assets, section["file"]?.asObject().ifNull("file value not set.")) - private val conditions = section.toConditions() build UpdateEvent.EMPTY + private val conditions = section.toConditions(this) build UpdateEvent.EMPTY private val isDefault = ConfigManagerImpl.defaultCompass.contains(internalName) || section.getAsBoolean("default", false) diff --git a/dist/src/main/kotlin/kr/toxicity/hud/element/ImageElement.kt b/dist/src/main/kotlin/kr/toxicity/hud/element/ImageElement.kt index 24ee6c7b..ca484d52 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/element/ImageElement.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/element/ImageElement.kt @@ -10,6 +10,7 @@ import kr.toxicity.hud.manager.ListenerManagerImpl import kr.toxicity.hud.manager.PlaceholderManagerImpl import kr.toxicity.hud.placeholder.Conditions import kr.toxicity.hud.placeholder.ConditionSource +import kr.toxicity.hud.placeholder.PlaceholderSource import kr.toxicity.hud.util.ifNull class ImageElement( @@ -18,7 +19,7 @@ class ImageElement( val image: List, val type: ImageType, setting: YamlObject -) : HudElement, ConditionSource by ConditionSource.Impl(setting) { +) : HudElement, ConditionSource by ConditionSource.Impl(setting), PlaceholderSource by PlaceholderSource.Impl(setting) { val listener = setting["listener"]?.asObject()?.let { ListenerManagerImpl.getListener(it) } @@ -48,11 +49,11 @@ class ImageElement( } val follow = setting["follow"]?.asString()?.let { - PlaceholderManagerImpl.find(it).apply { + PlaceholderManagerImpl.find(it, this).apply { if (!java.lang.String::class.java.isAssignableFrom(clazz)) throw RuntimeException("This placeholder is not a string in image $name: $it") } } val childrenMapper = setting["children-mapper"]?.asObject()?.map { - it.key to Conditions.parse(it.value.asObject()) + it.key to Conditions.parse(it.value.asObject(), this) } } \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/hud/HudImpl.kt b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudImpl.kt index 4c45c82d..3e9f622c 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/hud/HudImpl.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudImpl.kt @@ -14,6 +14,7 @@ import kr.toxicity.hud.manager.ConfigManagerImpl import kr.toxicity.hud.manager.LayoutManager import kr.toxicity.hud.pack.PackGenerator import kr.toxicity.hud.location.GuiLocation +import kr.toxicity.hud.placeholder.PlaceholderSource import kr.toxicity.hud.resource.GlobalResource import kr.toxicity.hud.util.* @@ -22,7 +23,7 @@ class HudImpl( private val internalName: String, resource: GlobalResource, section: YamlObject -) : Hud, HudConfiguration { +) : Hud, HudConfiguration, PlaceholderSource by PlaceholderSource.Impl(section) { private var imageChar = 0xCE000 @@ -37,7 +38,7 @@ class HudImpl( var textIndex = 0 fun getOrCreateSpace(int: Int) = spaces.computeIfAbsent(int) { - (++imageChar).parseChar() + newChar } private val elements = section["layouts"]?.asObject().ifNull("layout configuration not set.").mapSubConfiguration { s, yamlObject -> @@ -86,7 +87,7 @@ class HudImpl( return HudObjectType.HUD } - private val conditions = section.toConditions() build UpdateEvent.EMPTY + private val conditions = section.toConditions(this) build UpdateEvent.EMPTY override fun getComponents(player: HudPlayer): List { if (!conditions(player)) return emptyList() diff --git a/dist/src/main/kotlin/kr/toxicity/hud/layout/HudLayout.kt b/dist/src/main/kotlin/kr/toxicity/hud/layout/HudLayout.kt index afbec07d..a0c013bb 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/layout/HudLayout.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/layout/HudLayout.kt @@ -4,10 +4,11 @@ import kr.toxicity.hud.api.yaml.YamlObject import kr.toxicity.hud.element.HudElement import kr.toxicity.hud.location.PixelLocation import kr.toxicity.hud.placeholder.ConditionSource +import kr.toxicity.hud.placeholder.PlaceholderSource import kr.toxicity.hud.shader.RenderScale import kr.toxicity.hud.shader.ShaderProperty -interface HudLayout : ConditionSource { +interface HudLayout : ConditionSource, PlaceholderSource { val source: T val outline: Boolean val layer: Int @@ -26,7 +27,7 @@ interface HudLayout : ConditionSource { group: LayoutGroup, originalLoc: PixelLocation, yaml: YamlObject - ) : HudLayout, ConditionSource by ConditionSource.Impl(source, yaml) + group { + ) : HudLayout, ConditionSource by source + ConditionSource.Impl(yaml) + group, PlaceholderSource by PlaceholderSource.Impl(yaml) { override val outline: Boolean = yaml.getAsBoolean("outline", false) override val layer: Int = yaml.getAsInt("layer", 0) override val property: Int = ShaderProperty.properties(yaml["properties"]?.asArray()) diff --git a/dist/src/main/kotlin/kr/toxicity/hud/layout/ImageLayout.kt b/dist/src/main/kotlin/kr/toxicity/hud/layout/ImageLayout.kt index 85bb6760..15dfac7e 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/layout/ImageLayout.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/layout/ImageLayout.kt @@ -72,12 +72,12 @@ interface ImageLayout : HudLayout { override val scale: Double = yamlObject.getAsDouble("scale", 1.0) override val space: Int = yamlObject.getAsInt("space", 1) override val stack: PlaceholderBuilder<*>? = yamlObject["stack"]?.asString()?.let { - PlaceholderManagerImpl.find(it).ifNull("this placeholder doesn't exist: $it").apply { + PlaceholderManagerImpl.find(it, this).ifNull("this placeholder doesn't exist: $it").apply { if (clazz != java.lang.Number::class.java) throw RuntimeException("this placeholder is not integer: $it") } } override val maxStack: PlaceholderBuilder<*>? = yamlObject["max-stack"]?.asString()?.let { - PlaceholderManagerImpl.find(it).ifNull("this placeholder doesn't exist: $it").apply { + PlaceholderManagerImpl.find(it, this).ifNull("this placeholder doesn't exist: $it").apply { if (clazz != java.lang.Number::class.java) throw RuntimeException("this placeholder is not integer: $it") } } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/manager/ListenerManagerImpl.kt b/dist/src/main/kotlin/kr/toxicity/hud/manager/ListenerManagerImpl.kt index b4d8c85a..feb05436 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/manager/ListenerManagerImpl.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/manager/ListenerManagerImpl.kt @@ -4,6 +4,7 @@ import kr.toxicity.hud.api.listener.HudListener import kr.toxicity.hud.api.manager.ListenerManager import kr.toxicity.hud.api.update.UpdateEvent import kr.toxicity.hud.api.yaml.YamlObject +import kr.toxicity.hud.placeholder.PlaceholderSource import kr.toxicity.hud.resource.GlobalResource import kr.toxicity.hud.util.ifNull import net.kyori.adventure.audience.Audience @@ -14,8 +15,9 @@ object ListenerManagerImpl : BetterHudManager, ListenerManager { private val listenerMap = mutableMapOf (UpdateEvent) -> HudListener>( "placeholder" to placeholder@ { c -> - val v = PlaceholderManagerImpl.find(c["value"]?.asString().ifNull("value value not set.")) - val m = PlaceholderManagerImpl.find(c["max"]?.asString().ifNull("max value not set.")) + val source = PlaceholderSource.Impl(c) + val v = PlaceholderManagerImpl.find(c["value"]?.asString().ifNull("value value not set."), source) + val m = PlaceholderManagerImpl.find(c["max"]?.asString().ifNull("max value not set."), source) return@placeholder { event -> val value = v build event val max = m build event diff --git a/dist/src/main/kotlin/kr/toxicity/hud/manager/PlaceholderManagerImpl.kt b/dist/src/main/kotlin/kr/toxicity/hud/manager/PlaceholderManagerImpl.kt index bc93906b..ec14a4f2 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/manager/PlaceholderManagerImpl.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/manager/PlaceholderManagerImpl.kt @@ -5,10 +5,14 @@ import kr.toxicity.hud.api.placeholder.HudPlaceholder import kr.toxicity.hud.api.placeholder.PlaceholderContainer import kr.toxicity.hud.api.player.HudPlayer import kr.toxicity.hud.api.update.UpdateEvent +import kr.toxicity.hud.api.yaml.YamlElement +import kr.toxicity.hud.api.yaml.YamlObject import kr.toxicity.hud.equation.TEquation import kr.toxicity.hud.placeholder.Placeholder import kr.toxicity.hud.placeholder.PlaceholderBuilder +import kr.toxicity.hud.placeholder.PlaceholderSource import kr.toxicity.hud.resource.GlobalResource +import kr.toxicity.hud.util.ifNull import net.kyori.adventure.audience.Audience import java.text.DecimalFormat import java.util.Collections @@ -16,6 +20,7 @@ import java.util.function.Function import java.util.regex.Pattern object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { + private val castPattern = Pattern.compile("(\\((?[a-zA-Z]+)\\))") private val stringPattern = Pattern.compile("'(?[\\w|\\W]+)'") private val equationPatter = Pattern.compile("(@(?(([()\\-+*./% ]|[a-zA-Z]|[0-9])+)))") @@ -23,6 +28,7 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { private val doubleDecimal = DecimalFormat("#.###") private val number = PlaceholderContainerImpl( + "number", java.lang.Number::class.java, 0.0, mapOf>( @@ -44,13 +50,24 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { } } }, - ), { + ), + { it.toDoubleOrNull() - }, { + }, + { doubleDecimal.format(it) + }, + mapOf( + "evaluate" to { n, e -> + TEquation(e.asString()).evaluate(n.toDouble()) + } + ), + { a, b -> + DecimalFormat(b).format(a) } ) private val string = PlaceholderContainerImpl( + "string", java.lang.String::class.java, "", mapOf( @@ -62,14 +79,41 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { } } }, - ), { + ), + { val matcher = stringPattern.matcher(it) if (matcher.find()) matcher.group("content") else null - }, { + }, + { it.toString() + }, + mapOf( + "trim" to { s, e -> + if (e.asBoolean()) s.trim() else s + }, + "join" to { s, e -> + val j = e.asString() + buildString { + val point = s.codePoints().toArray() + point.forEachIndexed { index, c -> + appendCodePoint(c) + if (index < point.lastIndex) append(j) + } + } + }, + "replace" to { s, e -> + val obj = e.asObject() + val from = obj["from"].ifNull("Cannot find 'from' section.").asString() + val to = obj["to"].ifNull("Cannot find 'to' section.").asString() + s.replace(from, to) + } + ), + { a, _ -> + a.toString() } ) private val boolean = PlaceholderContainerImpl( + "boolean", java.lang.Boolean::class.java, false, mapOf( @@ -81,14 +125,24 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { } } } - ), { + ), + { when (it) { "true" -> true "false" -> false else -> null } - }, { + }, + { it.toString() + }, + mapOf( + "reversed" to { b, e -> + if (e.asBoolean()) !b else b + } + ), + { a, _ -> + a.toString() } ) @@ -99,22 +153,58 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { ) class PlaceholderContainerImpl( + val name: String, val clazz: Class, val defaultValue: T, private val defaultMap: Map>, val parser: (String) -> T?, - val stringMapper: (R) -> String + val stringMapper: (R) -> String, + private val optionApplier: Map T> = emptyMap(), + private val optionStringApplier: (R, String) -> String ) : PlaceholderContainer { - val map = HashMap(defaultMap) + private val map = HashMap(defaultMap) fun init() { map.clear() map += defaultMap } - fun stringValue(any: Any): String { - return if (clazz.isAssignableFrom(any.javaClass)) stringMapper(clazz.cast(any)) - else any.toString() + fun get(key: String, option: YamlObject): HudPlaceholder? { + val get = map[key] ?: return null + val appliers = option.mapNotNull { (key, element) -> + optionApplier[key]?.let { + { value: T -> + it(value, element) + } + } + } + return if (appliers.isEmpty()) get else object : HudPlaceholder by get { + override fun invoke(args: MutableList, reason: UpdateEvent): Function { + val func = get(args, reason) + return Function { + var value = func.apply(it) + appliers.forEach { + value = it(value) + } + value + } + } + } + } + + fun stringValue(option: YamlObject): (Any) -> String { + val applier = option[name]?.asString()?.let { + { value: Any -> + optionStringApplier(clazz.cast(value), it) + } + } ?: { value: Any -> + stringMapper(clazz.cast(value)) + } + return { any -> + if (clazz.isAssignableFrom(any.javaClass)) { + applier(any) + } else any.toString() + } } override fun addPlaceholder(name: String, placeholder: HudPlaceholder) { @@ -124,7 +214,8 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { override fun getAllPlaceholders(): Map> = Collections.unmodifiableMap(map) } - fun find(target: String): PlaceholderBuilder<*> { + fun find(target: String, source: PlaceholderSource): PlaceholderBuilder<*> { + val (option, stringOption) = source.placeholderOption to source.stringPlaceholderFormat val equation = equationPatter.matcher(target) val numberMapper: (Double) -> Double = if (equation.find()) { TEquation(equation.group("equation")).let { mapper -> @@ -147,7 +238,7 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { val args = if (pattern.length > head.length + 1) pattern.substring(head.length + 1).split(',') else emptyList() val get = types.values.firstNotNullOfOrNull { - it.map[first]?.let { mapper -> + it.get(first, option)?.let { mapper -> it to mapper } } ?: types.values.firstNotNullOfOrNull { @@ -164,6 +255,8 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { val type = types[group] + val stringMapper = type?.stringValue(stringOption) ?: get.first.stringValue(stringOption) + return object : PlaceholderBuilder { override val clazz: Class get() = type?.clazz ?: get.first.clazz @@ -186,15 +279,14 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { } override fun stringValue(player: HudPlayer): String { - val value = invoke(player) - return type?.stringValue(value) ?: get.first.stringValue(value) + return stringMapper(invoke(player)) } } } } } - fun parse(target: String): (UpdateEvent) -> (HudPlayer) -> String { + fun parse(target: String, source: PlaceholderSource): (UpdateEvent) -> (HudPlayer) -> String { var skip = false val builder = ArrayList<(UpdateEvent) -> (HudPlayer) -> String>() val sb = StringBuilder() @@ -204,7 +296,7 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { '/' -> skip = true '[' -> { val build = sb.toString() - builder.add { + builder += { { build } @@ -215,9 +307,9 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { ']' -> { val result = sb.toString() sb.setLength(0) - val find = find(result) + val find = find(result, source) runCatching { - builder.add { r -> + builder += { r -> (find build r).let { b -> { b.stringValue(it) @@ -238,7 +330,7 @@ object PlaceholderManagerImpl : PlaceholderManager, BetterHudManager { } if (sb.isNotEmpty()) { val build = sb.toString() - builder.add { + builder += { { build } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/pack/PackFile.kt b/dist/src/main/kotlin/kr/toxicity/hud/pack/PackFile.kt index 13c8f213..7fcd9de6 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/pack/PackFile.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/pack/PackFile.kt @@ -3,4 +3,4 @@ package kr.toxicity.hud.pack class PackFile( val path: String, val array: () -> ByteArray -) \ No newline at end of file +) : () -> ByteArray by array \ No newline at end of file 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 352c28bc..6a4481c8 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/pack/PackGenerator.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/pack/PackGenerator.kt @@ -40,7 +40,7 @@ object PackGenerator { fun save(packFile: PackFile) { val replace = packFile.path.replace('/', File.separatorChar) - val arr = packFile.array() + val arr = packFile() synchronized(this) { byte += arr.size byteArrayMap[packFile.path] = arr @@ -105,7 +105,7 @@ object PackGenerator { } override fun invoke(p1: PackFile) { - val byte = p1.array() + val byte = p1() synchronized(builder) { builder.byte += byte.size builder.byteArrayMap[p1.path] = byte @@ -157,14 +157,16 @@ object PackGenerator { }) fun addEntry(entry: ZipEntry, byte: ByteArray) { synchronized(zip) { - zip.byteArrayMap[entry.name] = byte - 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() + runWithExceptionHandling(sender, "Unable to write this file: ${entry.name}") { + zip.byteArrayMap[entry.name] = byte + 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() + } } } } @@ -203,7 +205,7 @@ object PackGenerator { override fun invoke(p1: PackFile) { val entry = ZipEntry(p1.path) - val byte = p1.array() + val byte = p1() addEntry(entry, byte) } } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/placeholder/ColorOverride.kt b/dist/src/main/kotlin/kr/toxicity/hud/placeholder/ColorOverride.kt index 3ae1c5fb..dfecb44a 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/placeholder/ColorOverride.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/placeholder/ColorOverride.kt @@ -30,9 +30,9 @@ fun interface ColorOverride : (HudPlayer) -> TextColor? { pair += builder to color } - fun conditional(yaml: YamlObject) { + fun conditional(yaml: YamlObject, source: PlaceholderSource) { conditional( - yaml.toConditions(), + yaml.toConditions(source), yaml["color"] .ifNull("'color' section not found.") .asString() @@ -58,10 +58,10 @@ fun interface ColorOverride : (HudPlayer) -> TextColor? { null } } - fun builder(yaml: YamlObject) : Builder { + fun builder(yaml: YamlObject, source: PlaceholderSource) : Builder { return YamlBuilder().apply { yaml.forEach { - conditional(it.value.asObject()) + conditional(it.value.asObject(), source) } defaultColor = yaml["default-color"]?.asString()?.toTextColor() } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/placeholder/ConditionSource.kt b/dist/src/main/kotlin/kr/toxicity/hud/placeholder/ConditionSource.kt index f5b65949..09a39062 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/placeholder/ConditionSource.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/placeholder/ConditionSource.kt @@ -15,15 +15,15 @@ interface ConditionSource { class Impl( override val colorOverrides: ColorOverride.Builder, - override val conditions: ConditionBuilder + override val conditions: ConditionBuilder, ) : ConditionSource { - constructor(yamlObject: YamlObject): this( - yamlObject.toColorOverrides(), - yamlObject.toConditions() + constructor(yamlObject: YamlObject, source: PlaceholderSource): this( + yamlObject.toColorOverrides(source), + yamlObject.toConditions(source), ) - constructor(parent: ConditionSource, yamlObject: YamlObject): this( - parent.colorOverrides + yamlObject.toColorOverrides(), - parent.conditions and yamlObject.toConditions() + constructor(yamlObject: YamlObject): this( + yamlObject, + PlaceholderSource.Impl(yamlObject) ) } } \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/placeholder/Conditions.kt b/dist/src/main/kotlin/kr/toxicity/hud/placeholder/Conditions.kt index 614cf438..0f8f3fd5 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/placeholder/Conditions.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/placeholder/Conditions.kt @@ -7,11 +7,11 @@ import kr.toxicity.hud.util.ifNull import kr.toxicity.hud.util.warn object Conditions { - fun parse(section: YamlObject, defaultBuilder: ConditionBuilder = ConditionBuilder.alwaysTrue): ConditionBuilder { - var value: ConditionBuilder = defaultBuilder + fun parse(section: YamlObject, source: PlaceholderSource): ConditionBuilder { + var value: ConditionBuilder = ConditionBuilder.alwaysTrue section.forEachSubConfiguration { s, yamlObject -> runCatching { - val new = parse0(yamlObject) + val new = parse0(yamlObject, source) value = when (val gate = yamlObject["gate"]?.asString() ?: "and") { "and" -> value and new "or" -> value or new @@ -30,9 +30,9 @@ object Conditions { } @Suppress("UNCHECKED_CAST") - private fun parse0(section: YamlObject): ConditionBuilder { - val first = PlaceholderManagerImpl.find(section["first"]?.asString().ifNull("first value not set.")) - val second = PlaceholderManagerImpl.find(section["second"]?.asString().ifNull("second value not set.")) + private fun parse0(section: YamlObject, source: PlaceholderSource): ConditionBuilder { + val first = PlaceholderManagerImpl.find(section["first"]?.asString().ifNull("first value not set."), source) + val second = PlaceholderManagerImpl.find(section["second"]?.asString().ifNull("second value not set."), source) val operationValue = section["operation"]?.asString().ifNull("operation value not set") if (first.clazz != second.clazz) throw RuntimeException("type mismatch: ${first.clazz.simpleName} and ${second.clazz.simpleName}") diff --git a/dist/src/main/kotlin/kr/toxicity/hud/placeholder/PlaceholderSource.kt b/dist/src/main/kotlin/kr/toxicity/hud/placeholder/PlaceholderSource.kt new file mode 100644 index 00000000..ff3e6136 --- /dev/null +++ b/dist/src/main/kotlin/kr/toxicity/hud/placeholder/PlaceholderSource.kt @@ -0,0 +1,19 @@ +package kr.toxicity.hud.placeholder + +import kr.toxicity.hud.api.yaml.YamlObject +import kr.toxicity.hud.yaml.YamlObjectImpl + +interface PlaceholderSource { + val placeholderOption: YamlObject + val stringPlaceholderFormat: YamlObject + + class Impl( + override val placeholderOption: YamlObject, + override val stringPlaceholderFormat: YamlObject + ) : PlaceholderSource { + constructor(source: YamlObject): this( + source["placeholder-option"]?.asObject() ?: YamlObjectImpl.empty, + source["placeholder-string-format"]?.asObject() ?: YamlObjectImpl.empty + ) + } +} \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/popup/PopupImpl.kt b/dist/src/main/kotlin/kr/toxicity/hud/popup/PopupImpl.kt index 3169cb76..28ba566c 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/popup/PopupImpl.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/popup/PopupImpl.kt @@ -15,6 +15,7 @@ import kr.toxicity.hud.location.PixelLocation import kr.toxicity.hud.manager.* import kr.toxicity.hud.pack.PackGenerator import kr.toxicity.hud.location.GuiLocation +import kr.toxicity.hud.placeholder.PlaceholderSource import kr.toxicity.hud.resource.GlobalResource import kr.toxicity.hud.util.* import java.util.* @@ -24,7 +25,7 @@ class PopupImpl( resource: GlobalResource, val internalName: String, section: YamlObject -) : Popup, HudConfiguration { +) : Popup, HudConfiguration, PlaceholderSource by PlaceholderSource.Impl(section) { val gui = GuiLocation(section) val move = section["move"]?.asObject()?.let { EquationPairLocation(it) @@ -38,7 +39,7 @@ class PopupImpl( private val default = ConfigManagerImpl.defaultPopup.contains(internalName) || section.getAsBoolean("default", false) private val keyMapping = section.getAsBoolean("key-mapping", false) private val index: ((UpdateEvent) -> (HudPlayer) -> Int)? = section["index"]?.asString()?.let { - PlaceholderManagerImpl.find(it).apply { + PlaceholderManagerImpl.find(it, this).apply { if (clazz != java.lang.Number::class.java) throw RuntimeException("this index is not a number. it is ${clazz.simpleName}.") }.let { { reason -> @@ -92,7 +93,7 @@ class PopupImpl( throw RuntimeException("layouts is empty.") } - private val conditions = section.toConditions() + private val conditions = section.toConditions(this) init { val task = task@ { event: UpdateEvent, uuid: UUID -> diff --git a/dist/src/main/kotlin/kr/toxicity/hud/renderer/HeadRenderer.kt b/dist/src/main/kotlin/kr/toxicity/hud/renderer/HeadRenderer.kt index f7af12ab..19397418 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/renderer/HeadRenderer.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/renderer/HeadRenderer.kt @@ -124,7 +124,7 @@ class HeadRenderer( private val followPlayer = follow?.let { - PlaceholderManagerImpl.find(it).apply { + PlaceholderManagerImpl.find(it, this).apply { if (!java.lang.String::class.java.isAssignableFrom(clazz)) throw RuntimeException("This placeholder is not a string: $it") } } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/renderer/ImageRenderer.kt b/dist/src/main/kotlin/kr/toxicity/hud/renderer/ImageRenderer.kt index be2b4197..689c3c57 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/renderer/ImageRenderer.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/renderer/ImageRenderer.kt @@ -18,7 +18,7 @@ class ImageRenderer( component: ImageComponent ) : ImageLayout by layout { private val followHudPlayer = follow?.let { - PlaceholderManagerImpl.find(it).apply { + PlaceholderManagerImpl.find(it, this).apply { if (!java.lang.String::class.java.isAssignableFrom(clazz)) throw RuntimeException("This placeholder is not a string: $it") } } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/renderer/TextRenderer.kt b/dist/src/main/kotlin/kr/toxicity/hud/renderer/TextRenderer.kt index 051a971e..f5529b4a 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/renderer/TextRenderer.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/renderer/TextRenderer.kt @@ -30,12 +30,12 @@ class TextRenderer( } private val followHudPlayer = follow?.let { - PlaceholderManagerImpl.find(it).apply { + PlaceholderManagerImpl.find(it, this).apply { if (!java.lang.String::class.java.isAssignableFrom(clazz)) throw RuntimeException("This placeholder is not a string: $it") } } - private val parsedPatter = PlaceholderManagerImpl.parse(pattern) + private val parsedPatter = PlaceholderManagerImpl.parse(pattern, this) private val imageCharMapGet = imageCharMap diff --git a/dist/src/main/kotlin/kr/toxicity/hud/util/Functions.kt b/dist/src/main/kotlin/kr/toxicity/hud/util/Functions.kt index 98b51d80..100d9cca 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/util/Functions.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/util/Functions.kt @@ -18,7 +18,12 @@ fun runWithExceptionHandling(sender: Audience, message: String, block: () -> sender.warn(message) sender.warn("Reason: ${it.message ?: it.javaClass.name}") } - if (ConfigManagerImpl.debug) it.printStackTrace() + if (ConfigManagerImpl.debug) { + warn( + "Stack trace:", + it.stackTraceToString() + ) + } } fun T.runWithExceptionHandling(sender: Audience, message: String, block: T.() -> R) = runCatching(block).onFailure { @@ -26,5 +31,10 @@ fun T.runWithExceptionHandling(sender: Audience, message: String, block: sender.warn(message) sender.warn("Reason: ${it.message ?: it.javaClass.name}") } - if (ConfigManagerImpl.debug) it.printStackTrace() + if (ConfigManagerImpl.debug) { + warn( + "Stack trace:", + it.stackTraceToString() + ) + } } \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/util/Yamls.kt b/dist/src/main/kotlin/kr/toxicity/hud/util/Yamls.kt index 19820678..4e9fc665 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/util/Yamls.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/util/Yamls.kt @@ -6,6 +6,7 @@ import kr.toxicity.hud.equation.TEquation import kr.toxicity.hud.placeholder.ColorOverride import kr.toxicity.hud.placeholder.ConditionBuilder import kr.toxicity.hud.placeholder.Conditions +import kr.toxicity.hud.placeholder.PlaceholderSource import kr.toxicity.hud.yaml.YamlArrayImpl import kr.toxicity.hud.yaml.YamlElementImpl import kr.toxicity.hud.yaml.YamlObjectImpl @@ -59,11 +60,11 @@ fun File.forEachAllYaml(sender: Audience, block: (File, String, YamlObject) -> U } } } -fun YamlObject.toConditions() = get("conditions")?.asObject()?.let { - Conditions.parse(it) +fun YamlObject.toConditions(source: PlaceholderSource) = get("conditions")?.asObject()?.let { + Conditions.parse(it, source) } ?: ConditionBuilder.alwaysTrue -fun YamlObject.toColorOverrides() = get("color-overrides")?.asObject()?.let { - ColorOverride.builder(it) +fun YamlObject.toColorOverrides(source: PlaceholderSource) = get("color-overrides")?.asObject()?.let { + ColorOverride.builder(it, source) } ?: ColorOverride.empty fun YamlObject.getTEquation(key: String) = get(key)?.asString()?.let { diff --git a/dist/src/main/kotlin/kr/toxicity/hud/yaml/YamlObjectImpl.kt b/dist/src/main/kotlin/kr/toxicity/hud/yaml/YamlObjectImpl.kt index 9acfd64a..2cd2642e 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/yaml/YamlObjectImpl.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/yaml/YamlObjectImpl.kt @@ -11,6 +11,9 @@ class YamlObjectImpl( path: String, private val map: MutableMap<*, *> ) : YamlConfigurationImpl(path), YamlObject { + companion object { + val empty = YamlObjectImpl("", HashMap()) + } override fun save(file: File) { get().saveToYaml(file)