diff --git a/api/src/main/java/kr/toxicity/hud/api/player/HudPlayer.java b/api/src/main/java/kr/toxicity/hud/api/player/HudPlayer.java index 18ad98f0..2407407e 100644 --- a/api/src/main/java/kr/toxicity/hud/api/player/HudPlayer.java +++ b/api/src/main/java/kr/toxicity/hud/api/player/HudPlayer.java @@ -13,6 +13,7 @@ import java.util.Set; public interface HudPlayer { + @NotNull HudPlayerHead getHead(); @NotNull Player getBukkitPlayer(); @NotNull WidthComponent getHudComponent(); void setAdditionalComponent(@Nullable WidthComponent component); diff --git a/api/src/main/java/kr/toxicity/hud/api/player/HudPlayerHead.java b/api/src/main/java/kr/toxicity/hud/api/player/HudPlayerHead.java index 2a132554..d92a1916 100644 --- a/api/src/main/java/kr/toxicity/hud/api/player/HudPlayerHead.java +++ b/api/src/main/java/kr/toxicity/hud/api/player/HudPlayerHead.java @@ -1,4 +1,11 @@ package kr.toxicity.hud.api.player; +import net.kyori.adventure.text.format.TextColor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Unmodifiable; + +import java.util.List; + public interface HudPlayerHead { + @NotNull @Unmodifiable List getColors(); } diff --git a/build.gradle.kts b/build.gradle.kts index f88021f8..4e50d25b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,7 +12,7 @@ allprojects { apply(plugin = "kotlin") group = "kr.toxicity.hud" - version = "beta-4.2" + version = "beta-4.3" repositories { mavenCentral() diff --git a/dist/src/main/kotlin/kr/toxicity/hud/hud/HudElement.kt b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudElement.kt index 7023ff59..65624d26 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/hud/HudElement.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudElement.kt @@ -3,27 +3,32 @@ package kr.toxicity.hud.hud import kr.toxicity.hud.api.player.HudPlayer import kr.toxicity.hud.api.update.UpdateEvent import kr.toxicity.hud.component.LayoutComponentContainer +import kr.toxicity.hud.image.ImageLocation import kr.toxicity.hud.layout.LayoutGroup +import kr.toxicity.hud.shader.GuiLocation import kr.toxicity.hud.util.EMPTY_WIDTH_COMPONENT import kr.toxicity.hud.util.subFolder import java.io.File -class HudElement(hud: HudImpl, name: String, file: File, private val layout: LayoutGroup, x: Double, y: Double) { +class HudElement(hud: HudImpl, name: String, file: File, private val layout: LayoutGroup, gui: GuiLocation, pixel: ImageLocation) { private val imageElement = layout.image.map {image -> - HudImageElement(hud, image, x, y, layout.animation) + HudImageElement(hud, image, gui, pixel) } private val textElement = run { val subFile = file.subFolder("text") layout.text.mapIndexed { index, textLayout -> - HudTextElement(hud, name, subFile, textLayout, index, x, y, layout.animation) + HudTextElement(hud, name, subFile, textLayout, index, gui, pixel) } } + private val headElement = layout.head.map {image -> + HudHeadElement(hud, image, gui, pixel) + } val conditions = layout.conditions.build(UpdateEvent.EMPTY) - private val max = imageElement.maxOf { + private val max = imageElement.maxOfOrNull { it.max - } + } ?: 0 fun getComponent(player: HudPlayer) = if (conditions(player)) LayoutComponentContainer(layout.align, max) .append(imageElement.map { @@ -32,5 +37,8 @@ class HudElement(hud: HudImpl, name: String, file: File, private val layout: Lay .append(textElement.map { it.getText(player) }) + .append(headElement.map { + it.getHead(player) + }) .build() else EMPTY_WIDTH_COMPONENT } \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/hud/HudHeadElement.kt b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudHeadElement.kt new file mode 100644 index 00000000..7b3f82c7 --- /dev/null +++ b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudHeadElement.kt @@ -0,0 +1,45 @@ +package kr.toxicity.hud.hud + +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import kr.toxicity.hud.api.player.HudPlayer +import kr.toxicity.hud.api.update.UpdateEvent +import kr.toxicity.hud.image.ImageLocation +import kr.toxicity.hud.layout.HeadLayout +import kr.toxicity.hud.renderer.HeadRenderer +import kr.toxicity.hud.shader.GuiLocation +import kr.toxicity.hud.shader.HudShader +import kr.toxicity.hud.util.NAME_SPACE +import kr.toxicity.hud.util.parseChar +import net.kyori.adventure.text.Component + +class HudHeadElement(parent: HudImpl, private val head: HeadLayout, gui: GuiLocation, pixel: ImageLocation) { + private val renderer = run { + val final = head.location + pixel + val shader = HudShader( + gui, + head.layer, + head.outline + ) + HeadRenderer( + (0..7).map { i -> + val char = (++parent.imageChar).parseChar() + parent.jsonArray.add(JsonObject().apply { + addProperty("type", "bitmap") + addProperty("file", "$NAME_SPACE:head/pixel_${head.head.pixel}.png") + addProperty("ascent", HudImpl.createBit(final.y - (7 - i) * head.head.pixel, shader)) + addProperty("height", head.head.pixel) + add("chars", JsonArray().apply { + add(char) + }) + }) + Component.text(char).font(parent.imageKey) + }, + head.head.pixel, + final.x, + head.conditions.and(head.head.conditions) + ) + } + + fun getHead(player: HudPlayer) = renderer.getHead(UpdateEvent.EMPTY)(player) +} \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/hud/HudImageElement.kt b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudImageElement.kt index e3a1c680..9080b6e5 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/hud/HudImageElement.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudImageElement.kt @@ -16,7 +16,7 @@ import kr.toxicity.hud.util.* import net.kyori.adventure.text.Component import kotlin.math.round -class HudImageElement(parent: HudImpl, private val image: ImageLayout, x: Double, y: Double, animation: List) { +class HudImageElement(parent: HudImpl, private val image: ImageLayout, gui: GuiLocation, pixel: ImageLocation) { private val chars = run { @@ -24,48 +24,44 @@ class HudImageElement(parent: HudImpl, private val image: ImageLayout, x: Double val isSingle = hud.image.size == 1 val shader = HudShader( - GuiLocation(x, y), + gui, image.layer, image.outline ) + val list = ArrayList() + if (hud is ListenerHudImage) { + list.add(EMPTY_PIXEL_COMPONENT) + } + val finalPixel = image.location + pixel + hud.image.forEach { pair -> - animation.map { imageLocation -> - val list = ArrayList() - if (hud is ListenerHudImage) { - list.add(EMPTY_PIXEL_COMPONENT) - } - hud.image.forEach { pair -> - val c = (++parent.imageChar).parseChar() - val height = round(pair.image.image.height.toDouble() * image.scale).toInt() - val scale = height.toDouble() / pair.image.image.height - val finalWidth = WidthComponent(Component.text(c).font(parent.imageKey), round((pair.image.image.width).toDouble() * scale).toInt()) + NEGATIVE_ONE_SPACE_COMPONENT + NEW_LAYER - parent.jsonArray.add(JsonObject().apply { - addProperty("type", "bitmap") - if (isSingle) addProperty("file", "$NAME_SPACE:image/${pair.name}") - else addProperty("file", "$NAME_SPACE:image/${hud.name}/${pair.name}") - addProperty("ascent", HudImpl.createBit((image.location.y + imageLocation.y).coerceAtLeast(-HudImpl.ADD_HEIGHT).coerceAtMost(HudImpl.ADD_HEIGHT), shader)) - addProperty("height", height) - add("chars", JsonArray().apply { - add(c) - }) + val c = (++parent.imageChar).parseChar() + val height = round(pair.image.image.height.toDouble() * image.scale).toInt() + val scale = height.toDouble() / pair.image.image.height + val finalWidth = WidthComponent(Component.text(c).font(parent.imageKey), round((pair.image.image.width).toDouble() * scale).toInt()) + NEGATIVE_ONE_SPACE_COMPONENT + NEW_LAYER + parent.jsonArray.add(JsonObject().apply { + addProperty("type", "bitmap") + if (isSingle) addProperty("file", "$NAME_SPACE:image/${pair.name}") + else addProperty("file", "$NAME_SPACE:image/${hud.name}/${pair.name}") + addProperty("ascent", HudImpl.createBit((finalPixel.y).coerceAtLeast(-HudImpl.ADD_HEIGHT).coerceAtMost(HudImpl.ADD_HEIGHT), shader)) + addProperty("height", height) + add("chars", JsonArray().apply { + add(c) }) - list.add(finalWidth.toPixelComponent(image.location.x + imageLocation.x + round(pair.image.xOffset * scale).toInt())) - } - ImageRenderer( - hud, - list, - image.conditions.and(image.image.conditions) - ) + }) + list.add(finalWidth.toPixelComponent(finalPixel.x + round(pair.image.xOffset * scale).toInt())) } - + ImageRenderer( + hud, + list, + image.conditions.and(image.image.conditions) + ) } - val max = chars.maxOf { - it.max() - } + val max = chars.max() - fun getComponent(player: HudPlayer): PixelComponent = chars[(player.tick % chars.size).toInt()].getComponent( + fun getComponent(player: HudPlayer): PixelComponent = chars.getComponent( UpdateEvent.EMPTY)(player) } \ 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 f13a06e0..d34a2b66 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/hud/HudImpl.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudImpl.kt @@ -6,9 +6,11 @@ import kr.toxicity.hud.api.component.WidthComponent import kr.toxicity.hud.api.hud.Hud import kr.toxicity.hud.api.player.HudPlayer import kr.toxicity.hud.api.update.UpdateEvent +import kr.toxicity.hud.image.ImageLocation import kr.toxicity.hud.manager.ConfigManager import kr.toxicity.hud.manager.LayoutManager import kr.toxicity.hud.manager.ShaderManager +import kr.toxicity.hud.shader.GuiLocation import kr.toxicity.hud.shader.HudShader import kr.toxicity.hud.util.* import net.kyori.adventure.key.Key @@ -34,18 +36,22 @@ class HudImpl(private val internalName: String, file: File, section: Configurati private val elements = run { val subFile = file.subFolder(internalName) - ArrayList().apply { + ArrayList>().apply { section.getConfigurationSection("layouts").ifNull("layout configuration not set.").forEachSubConfiguration { s, configurationSection -> - add(HudElement( - this@HudImpl, - internalName, - subFile, - configurationSection.getString("name").ifNull("name value not set: $s").let { - LayoutManager.getLayout(it).ifNull("this layout doesn't exist: $it") - }, - configurationSection.getDouble("x").coerceAtLeast(0.0).coerceAtMost(100.0), - configurationSection.getDouble("y").coerceAtLeast(0.0).coerceAtMost(100.0) - )) + val layout = configurationSection.getString("name").ifNull("name value not set: $s").let { + LayoutManager.getLayout(it).ifNull("this layout doesn't exist: $it") + } + val gui = GuiLocation(configurationSection) + add(layout.animation.map { + HudElement( + this@HudImpl, + internalName, + subFile, + layout, + gui, + ImageLocation(it.x, it.y) + ) + }) } }.ifEmpty { throw RuntimeException("layout is empty.") @@ -63,7 +69,7 @@ class HudImpl(private val internalName: String, file: File, section: Configurati override fun getComponents(player: HudPlayer): List { if (!conditions(player)) return emptyList() return elements.map { - it.getComponent(player) + it[(player.tick % it.size).toInt()].getComponent(player) } } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/hud/HudTextElement.kt b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudTextElement.kt index 1f8a365c..c9395283 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/hud/HudTextElement.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/hud/HudTextElement.kt @@ -18,59 +18,58 @@ import net.kyori.adventure.text.format.Style import java.io.File import kotlin.math.ceil -class HudTextElement(parent: HudImpl, name: String, file: File, private val text: TextLayout, index: Int, x: Double, y: Double, animation: List) { +class HudTextElement(parent: HudImpl, name: String, file: File, private val text: TextLayout, index: Int, gui: GuiLocation, pixel: ImageLocation) { private val renderer = run { val shader = HudShader( - GuiLocation(x, y), + gui, text.layer, text.outline ) - animation.map { imageLocation -> - val yAxis = (text.location.y + imageLocation.y).coerceAtLeast(-HudImpl.ADD_HEIGHT).coerceAtMost(HudImpl.ADD_HEIGHT) - val group = ShaderGroup(shader, text.text.name, yAxis) - val scale = ceil(text.text.height * text.scale).toInt() - val key = TextManager.getKey(group) ?: run { - val index2 = (++parent.textIndex) - val key = Key.key("$NAME_SPACE:hud/$name/text/text_${index + 1}_${index2 + 1}") - val array = JsonArray().apply { - add(JsonObject().apply { - addProperty("type", "space") - add("advances", JsonObject().apply { - addProperty(" ", 4) - }) + val loc = text.location + pixel + val yAxis = (loc.y).coerceAtLeast(-HudImpl.ADD_HEIGHT).coerceAtMost(HudImpl.ADD_HEIGHT) + val group = ShaderGroup(shader, text.text.name, yAxis) + val scale = ceil(text.text.height * text.scale).toInt() + val key = TextManager.getKey(group) ?: run { + val index2 = (++parent.textIndex) + val key = Key.key("$NAME_SPACE:hud/$name/text/text_${index + 1}_${index2 + 1}") + val array = JsonArray().apply { + add(JsonObject().apply { + addProperty("type", "space") + add("advances", JsonObject().apply { + addProperty(" ", 4) }) - } - text.text.array.forEach { - array.add(JsonObject().apply { - addProperty("type", "bitmap") - addProperty("file", "$NAME_SPACE:text/${text.text.fontName}/${it.file}") - addProperty("ascent", HudImpl.createBit(yAxis, shader)) - addProperty("height", scale) - add("chars", it.chars) - }) - } - JsonObject().apply { - add("providers", array) - }.save(File(file, "text_${index + 1}_${index2 + 1}.json")) - TextManager.setKey(group, key) - key + }) + } + text.text.array.forEach { + array.add(JsonObject().apply { + addProperty("type", "bitmap") + addProperty("file", "$NAME_SPACE:text/${text.text.fontName}/${it.file}") + addProperty("ascent", HudImpl.createBit(yAxis, shader)) + addProperty("height", scale) + add("chars", it.chars) + }) } - TextRenderer( - text.text.charWidth, - Style.style(text.color).font(key), - text.pattern, - text.align, - scale.toDouble() / text.text.height, - text.location.x + imageLocation.x, - text.space, - text.numberEquation, - text.numberFormat, - text.conditions.and(text.text.conditions) - ) + JsonObject().apply { + add("providers", array) + }.save(File(file, "text_${index + 1}_${index2 + 1}.json")) + TextManager.setKey(group, key) + key } + TextRenderer( + text.text.charWidth, + Style.style(text.color).font(key), + text.pattern, + text.align, + scale.toDouble() / text.text.height, + loc.x, + text.space, + text.numberEquation, + text.numberFormat, + text.conditions.and(text.text.conditions) + ) } - fun getText(player: HudPlayer): PixelComponent = renderer[(player.tick % renderer.size).toInt()].getText( + fun getText(player: HudPlayer): PixelComponent = renderer.getText( UpdateEvent.EMPTY)(player) } \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/layout/HeadLayout.kt b/dist/src/main/kotlin/kr/toxicity/hud/layout/HeadLayout.kt new file mode 100644 index 00000000..43fa502a --- /dev/null +++ b/dist/src/main/kotlin/kr/toxicity/hud/layout/HeadLayout.kt @@ -0,0 +1,13 @@ +package kr.toxicity.hud.layout + +import kr.toxicity.hud.image.ImageLocation +import kr.toxicity.hud.placeholder.ConditionBuilder +import kr.toxicity.hud.player.HudHead + +class HeadLayout( + val head: HudHead, + val location: ImageLocation, + val outline: Boolean, + val layer: Int, + val conditions: ConditionBuilder +) \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/layout/LayoutGroup.kt b/dist/src/main/kotlin/kr/toxicity/hud/layout/LayoutGroup.kt index 38636194..5111a94d 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/layout/LayoutGroup.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/layout/LayoutGroup.kt @@ -5,6 +5,7 @@ import kr.toxicity.hud.equation.TEquation import kr.toxicity.hud.image.ImageLocation import kr.toxicity.hud.manager.ConfigManager import kr.toxicity.hud.manager.ImageManager +import kr.toxicity.hud.manager.PlayerHeadManager import kr.toxicity.hud.manager.TextManager import kr.toxicity.hud.util.forEachSubConfiguration import kr.toxicity.hud.util.ifNull @@ -72,6 +73,21 @@ class LayoutGroup(section: ConfigurationSection) { ) } } + val head: List = ArrayList().apply { + section.getConfigurationSection("heads")?.forEachSubConfiguration { s, configurationSection -> + add( + HeadLayout( + configurationSection.getString("name").ifNull("name value not set.").let { + PlayerHeadManager.getHead(it).ifNull("this head doesn't exist: $it") + }, + ImageLocation(configurationSection) + loc, + configurationSection.getBoolean("outline"), + configurationSection.getInt("layer"), + configurationSection.toConditions() + ) + ) + } + } val conditions = section.toConditions() val animation = section.getConfigurationSection("animations")?.let { animations -> 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 a278bdea..84f74e9c 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/manager/PlayerHeadManager.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/manager/PlayerHeadManager.kt @@ -1,21 +1,42 @@ package kr.toxicity.hud.manager +import kr.toxicity.hud.player.HudHead import kr.toxicity.hud.resource.GlobalResource -import kr.toxicity.hud.util.DATA_FOLDER -import kr.toxicity.hud.util.subFolder +import kr.toxicity.hud.util.* +import java.awt.Color +import java.awt.image.BufferedImage +import java.io.File object PlayerHeadManager: BetterHudManager { - + private val headMap = HashMap() override fun start() { } + fun getHead(name: String) = headMap[name] + override fun reload(resource: GlobalResource) { val saveLocation = resource.textures.subFolder("head") - DATA_FOLDER.subFolder("heads") - + DATA_FOLDER.subFolder("heads").forEachAllYaml { file, s, configurationSection -> + runCatching { + val head = HudHead(s , configurationSection) + val pixel = head.pixel + val targetFile = File(saveLocation, "pixel_$pixel.png") + if (!targetFile.exists()) BufferedImage(pixel, pixel ,BufferedImage.TYPE_INT_ARGB).apply { + createGraphics().run { + color = Color.WHITE + fillRect(0, 0, pixel, pixel) + dispose() + } + }.save(targetFile) + headMap[head.name] = head + }.onFailure { e -> + warn("Unable to load this head: $s in ${file.name}") + warn("Reason: ${e.message}") + } + } } override fun end() { diff --git a/dist/src/main/kotlin/kr/toxicity/hud/player/HudHead.kt b/dist/src/main/kotlin/kr/toxicity/hud/player/HudHead.kt new file mode 100644 index 00000000..7a19f351 --- /dev/null +++ b/dist/src/main/kotlin/kr/toxicity/hud/player/HudHead.kt @@ -0,0 +1,9 @@ +package kr.toxicity.hud.player + +import kr.toxicity.hud.util.toConditions +import org.bukkit.configuration.ConfigurationSection + +class HudHead(val name: String, section: ConfigurationSection) { + val pixel = section.getInt("pixel", 1).coerceAtLeast(1) + val conditions = section.toConditions() +} \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/player/HudPlayerHeadImpl.kt b/dist/src/main/kotlin/kr/toxicity/hud/player/HudPlayerHeadImpl.kt index 33bc2d54..b4f3600f 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/player/HudPlayerHeadImpl.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/player/HudPlayerHeadImpl.kt @@ -4,6 +4,7 @@ import com.google.gson.JsonParser import kr.toxicity.hud.api.player.HudPlayerHead import kr.toxicity.hud.util.gameProfile import kr.toxicity.hud.util.toImage +import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.format.TextColor import org.bukkit.entity.Player import java.net.URI @@ -13,21 +14,30 @@ import java.net.http.HttpResponse.BodyHandlers import java.util.* class HudPlayerHeadImpl(player: Player): HudPlayerHead { - private val array = HttpClient.newHttpClient().send( - HttpRequest.newBuilder() - .uri(URI.create(JsonParser.parseString(String(Base64.getDecoder().decode(player.gameProfile.properties.get("textures").first().value))) - .asJsonObject - .getAsJsonObject("textures") - .getAsJsonObject("SKIN") - .getAsJsonPrimitive("url") - .asString)) - .GET() - .build(), - BodyHandlers.ofInputStream() - ).body().buffered().use { - val image = it.toImage().getSubimage(8, 8, 8, 8) - (0..63).map { i -> - TextColor.color(image.getRGB(i % 8, i / 8) and 0xFFFFFF) + companion object { + private val allBlack = (0..63).map { + NamedTextColor.BLACK } } + + private val colorList = runCatching { + HttpClient.newHttpClient().send( + HttpRequest.newBuilder() + .uri(URI.create(JsonParser.parseString(String(Base64.getDecoder().decode(player.gameProfile.properties.get("textures").first().value))) + .asJsonObject + .getAsJsonObject("textures") + .getAsJsonObject("SKIN") + .getAsJsonPrimitive("url") + .asString)) + .GET() + .build(), + BodyHandlers.ofInputStream() + ).body().buffered().use { + val image = it.toImage().getSubimage(8, 8, 8, 8) + (0..63).map { i -> + TextColor.color(image.getRGB(i % 8, i / 8)) + } + } + }.getOrNull() ?: allBlack + override fun getColors(): List = colorList } \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/player/HudPlayerImpl.kt b/dist/src/main/kotlin/kr/toxicity/hud/player/HudPlayerImpl.kt index b8f9605f..35e873ad 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/player/HudPlayerImpl.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/player/HudPlayerImpl.kt @@ -3,6 +3,7 @@ package kr.toxicity.hud.player import kr.toxicity.hud.api.component.WidthComponent import kr.toxicity.hud.api.hud.Hud import kr.toxicity.hud.api.player.HudPlayer +import kr.toxicity.hud.api.player.HudPlayerHead import kr.toxicity.hud.api.popup.Popup import kr.toxicity.hud.api.popup.PopupIteratorGroup import kr.toxicity.hud.api.scheduler.HudTask @@ -18,6 +19,9 @@ class HudPlayerImpl( huds: MutableSet, popups: MutableSet ): HudPlayer { + + private val h = HudPlayerHeadImpl(player) + private val huds = huds.apply { addAll(HudManagerImpl.defaultHuds) } @@ -71,6 +75,7 @@ class HudPlayerImpl( override fun getTick(): Long = tick override fun getBukkitPlayer(): Player = player override fun getVariableMap(): MutableMap = variable + override fun getHead(): HudPlayerHead = h override fun save() { DatabaseManagerImpl.currentDatabase.save(this) } diff --git a/dist/src/main/kotlin/kr/toxicity/hud/popup/PopupLayout.kt b/dist/src/main/kotlin/kr/toxicity/hud/popup/PopupLayout.kt index d8eb21f4..4fca9960 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/popup/PopupLayout.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/popup/PopupLayout.kt @@ -13,6 +13,7 @@ import kr.toxicity.hud.image.ListenerHudImage import kr.toxicity.hud.image.LocationGroup import kr.toxicity.hud.layout.LayoutGroup import kr.toxicity.hud.manager.TextManager +import kr.toxicity.hud.renderer.HeadRenderer import kr.toxicity.hud.renderer.ImageRenderer import kr.toxicity.hud.renderer.TextRenderer import kr.toxicity.hud.shader.GuiLocation @@ -96,6 +97,9 @@ class PopupLayout( val textProcessing = texts.map { it.getText(reason) } + val headProcessing = heads.map { + it.getHead(reason) + } return { player -> LayoutComponentContainer(layout.align, max) .append(imageProcessing.map { @@ -104,6 +108,9 @@ class PopupLayout( .append(textProcessing.map { it(player) }) + .append(headProcessing.map { + it(player) + }) .build() } } @@ -159,9 +166,9 @@ class PopupLayout( ) } - private val max = image.maxOf { + private val max = image.maxOfOrNull { it.max() - } + } ?: 0 val texts = layout.text.map { textLayout -> val pixel = location + pair.pixel + textLayout.location @@ -211,5 +218,32 @@ class PopupLayout( textLayout.conditions.and(textLayout.text.conditions) ) } + + val heads = layout.head.map { headLayout -> + val pixel = location + pair.pixel + headLayout.location + val shader = HudShader( + gui, + headLayout.layer, + headLayout.outline + ) + HeadRenderer( + (0..7).map { i -> + val char = (++imageChar).parseChar() + array.add(JsonObject().apply { + addProperty("type", "bitmap") + addProperty("file", "$NAME_SPACE:head/pixel_${headLayout.head.pixel}.png") + addProperty("ascent", HudImpl.createBit(pixel.y - (7 - i) * headLayout.head.pixel, shader)) + addProperty("height", headLayout.head.pixel) + add("chars", JsonArray().apply { + add(char) + }) + }) + Component.text(char).font(imageKey) + }, + headLayout.head.pixel, + pixel.x, + headLayout.conditions.and(headLayout.head.conditions) + ) + } } } \ No newline at end of file diff --git a/dist/src/main/kotlin/kr/toxicity/hud/renderer/HeadRenderer.kt b/dist/src/main/kotlin/kr/toxicity/hud/renderer/HeadRenderer.kt new file mode 100644 index 00000000..aacddf17 --- /dev/null +++ b/dist/src/main/kotlin/kr/toxicity/hud/renderer/HeadRenderer.kt @@ -0,0 +1,34 @@ +package kr.toxicity.hud.renderer + +import kr.toxicity.hud.api.component.PixelComponent +import kr.toxicity.hud.api.component.WidthComponent +import kr.toxicity.hud.api.player.HudPlayer +import kr.toxicity.hud.api.update.UpdateEvent +import kr.toxicity.hud.placeholder.ConditionBuilder +import kr.toxicity.hud.util.* +import net.kyori.adventure.text.Component +import java.util.UUID + +class HeadRenderer( + private val components: List, + private val pixel: Int, + private val x: Int, + private val conditions: ConditionBuilder, +) { + private val componentMap = HashMap() + private val nextPixel = (-pixel * 8).toSpaceComponent() + NEGATIVE_ONE_SPACE_COMPONENT + + fun getHead(event: UpdateEvent): (HudPlayer) -> PixelComponent { + val cond = conditions.build(event) + return { player -> + if (cond(player)) componentMap.computeIfAbsent(player.bukkitPlayer.uniqueId) { + var comp = EMPTY_WIDTH_COMPONENT + player.head.colors.forEachIndexed { index, textColor -> + comp += WidthComponent(components[index / 8].color(textColor), pixel) + comp += if (index < 63 && index % 8 == 7) nextPixel else NEGATIVE_ONE_SPACE_COMPONENT + } + comp.toPixelComponent(x) + } else EMPTY_PIXEL_COMPONENT + } + } +} \ No newline at end of file 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 f6a96ea1..1f1a08ca 100644 --- a/dist/src/main/kotlin/kr/toxicity/hud/renderer/ImageRenderer.kt +++ b/dist/src/main/kotlin/kr/toxicity/hud/renderer/ImageRenderer.kt @@ -33,7 +33,7 @@ class ImageRenderer( } } - fun max() = components.maxOf { + fun max() = components.maxOfOrNull { it.component.width - } + } ?: 0 } \ No newline at end of file