Skip to content

Commit

Permalink
add tooltip interface
Browse files Browse the repository at this point in the history
  • Loading branch information
toxicity188 committed Nov 3, 2023
1 parent e80e03a commit 9c44dfa
Show file tree
Hide file tree
Showing 22 changed files with 995 additions and 224 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public interface IDialog {
public interface IDialog extends Mechanic {
/**
* Get a key of that Dialog
* @return A yaml key of Dialog
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kor.toxicity.questadder.api.mechanic;

import org.jetbrains.annotations.NotNull;

public interface Mechanic {
@NotNull MechanicBlueprint getOriginalBlueprint();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package kor.toxicity.questadder.api.mechanic;

import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;

public interface MechanicBlueprint {
@NotNull ConfigurationSection getConfig();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,9 @@ public record SoundData(@NotNull String name, float volume, float pitch) {
public void play(@NotNull Player player) {
player.playSound(player.getLocation(), name, volume, pitch);
}

@Override
public String toString() {
return name + " " + volume + " " + pitch;
}
}
Binary file not shown.
Binary file added nms/v1_20_R2/shade/CrazyAdvancementsAPI.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
package kor.toxicity.questadder.extension

import kor.toxicity.questadder.QuestAdderBukkit
import net.kyori.adventure.key.Key
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.TextComponent
import net.kyori.adventure.text.format.NamedTextColor
import net.kyori.adventure.text.format.TextColor
import net.kyori.adventure.text.format.TextDecoration
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer


val SPACE_FONT = Key.key("questadder:space")
val BUILD_FONT = Key.key("questadder:build")
val LEGACY_SPACE_FONT = Key.key("questadder:legacy_space")
val GUI_FONT = Key.key("questadder:gui")
val FADE_COMPONENT_UPPER = Component.text("").font(Key.key("questadder:fade"))
val FADE_COMPONENT_UNDER = Component.text("").font(Key.key("questadder:fade"))

val RED: TextColor = NamedTextColor.RED
val GREEN: TextColor = NamedTextColor.GREEN
val GRAY: TextColor = NamedTextColor.GRAY
val WHITE: TextColor = NamedTextColor.WHITE
Expand Down Expand Up @@ -40,4 +50,6 @@ fun Component.deepColor(color: TextColor?): Component {

fun Component.onlyText(): String {
return PlainTextComponentSerializer.plainText().serialize(this)
}
}

fun Int.parseToSpaceComponent() = if (QuestAdderBukkit.nms.getVersion().version >= 19) (0xD0000 + this).parseChar().asComponent().font(SPACE_FONT) else (0xFFC00 + this).parseChar().asComponent().font(LEGACY_SPACE_FONT)
57 changes: 57 additions & 0 deletions plugin/src/main/java/kor/toxicity/questadder/extension/Configs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import org.bukkit.NamespacedKey
import org.bukkit.attribute.Attribute
import org.bukkit.attribute.AttributeModifier
import org.bukkit.configuration.ConfigurationSection
import org.bukkit.configuration.MemoryConfiguration
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.EquipmentSlot
import org.bukkit.inventory.ItemFlag
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import java.util.*
import java.util.regex.Pattern
import kotlin.collections.ArrayList

private const val ATTRIBUTE_NAME = "questadder.attribute"
private val ATTRIBUTE_UUID = UUID.fromString("8d1fc1b6-00fe-11ee-be56-0242ac120002")
Expand Down Expand Up @@ -143,3 +145,58 @@ fun ConfigurationSection.getAsItemStack(key: String, apply: (ItemMeta) -> Unit =
null
} else ItemManager.getItem(it)
} else null

fun ConfigurationSection.copy(): ConfigurationSection {
fun copy0(any: Any): Any {
return if (any is ConfigurationSection) {
val config = MemoryConfiguration()
any.getKeys(false).forEach {
any.get(it)?.let { any0 ->
config.set(it,copy0(any0))
}
}
config
} else any
}
val config = MemoryConfiguration()
getKeys(false).forEach {
get(it)?.let { any ->
config.set(it, copy0(any))
}
}
return config
}

inline fun <reified T> Array<T>.addElement(element: T) = toMutableList().apply {
add(element)
}.toTypedArray()
inline fun <reified T> Array<T>.addElement(index: Int, element: T): Array<T> {
return if (index > lastIndex) addElement(element) else toMutableList().apply {
add(index, element)
}.toTypedArray()
}
inline fun <reified T> Array<T>.removeLast(): Array<T>? {
if (size <= 1) return null
return toMutableList().apply {
removeAt(lastIndex)
}.toTypedArray()
}
inline fun <reified T> Array<T>.removeAt(int: Int): Array<T> = toMutableList().apply {
removeAt(int)
}.toTypedArray()

private val INT_PATTERN = Pattern.compile("([0-9]+)")
fun ConfigurationSection.rebase(pos: Int, add: Int) {
val tree = TreeMap<Int, Any>()
getKeys(false).forEach {
if (!INT_PATTERN.matcher(it).find()) return@forEach
val int = it.toInt()
val any = get(it) ?: return@forEach
if (int > pos) tree[int + add] = any
else tree[int] = any
set(it, null)
}
tree.forEach {
set(it.key.toString(), it.value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ fun Int.parseChar(): String {
val t = this - 0x10000
"${((t ushr 10) + 0xD800).toChar()}${((t and 1023) + 0xDC00).toChar()}"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kor.toxicity.questadder.font

import net.kyori.adventure.text.Component

data class GuiFontData(
val height: Int,
val width: Int,
val component: Component
)
169 changes: 169 additions & 0 deletions plugin/src/main/java/kor/toxicity/questadder/font/QuestFont.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package kor.toxicity.questadder.font

import com.google.gson.Gson
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.google.gson.stream.JsonWriter
import kor.toxicity.questadder.extension.parseToSpaceComponent
import net.kyori.adventure.key.Key
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.TextComponent
import net.kyori.adventure.text.format.Style
import net.kyori.adventure.text.format.TextDecoration
import java.awt.AlphaComposite
import java.awt.Font
import java.awt.RenderingHints
import java.awt.font.FontRenderContext
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
import kotlin.math.round

class QuestFont(
file: File,
private val scale: Int,
private val height: Int,
private val ascent: Int,

width: Double,
widthMultiplier: Double,

private val blank: Int,

private val jsonDir: File,
private val fontDir: File
) {
companion object {
private const val ESTIMATED_WIDTH = 16
private val frc = FontRenderContext(null, true, true)
private val gson = Gson()
}

//Font
private val font = file.inputStream().buffered().use {
Font.createFont(Font.TRUETYPE_FONT, it)
}.deriveFont(scale.toFloat())

private val availableChar = run {
val list = (Char.MIN_VALUE..Char.MAX_VALUE).filter {
font.canDisplay(it)
}
list.subList(0, list.size - list.size % ESTIMATED_WIDTH)
}

private val metrics = run {
val image = BufferedImage(1,1,BufferedImage.TYPE_INT_ARGB)
val graphics = image.createGraphics()
val metrics = graphics.getFontMetrics(font)
graphics.dispose()
metrics
}
private val fileName = file.nameWithoutExtension
private val jsonName = "${fileName}_${ascent}_$height"
private val key = Key.key("questadder:tooltip/$jsonName")

private val charWidth = availableChar.associateWith {
val bound = font.getStringBounds(it.toString(), frc)
round((bound.width * height / bound.height / 1.4 + width) * widthMultiplier).toInt()
}

init {
createBitmap()
createJson()
}

private fun createBitmap() {
val newDir = File(fontDir, fileName)
if (!newDir.exists()) {
newDir.mkdir()
var i = 0
var num = 0
val yAxis = (metrics.height * 1.4F).toInt()
while (i < availableChar.size) {
val image = BufferedImage(scale * ESTIMATED_WIDTH, yAxis * ESTIMATED_WIDTH, BufferedImage.TYPE_INT_ARGB)
val graphics = image.createGraphics().apply {
composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER)
font = this@QuestFont.font
setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON)
setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON)
}
for ((y,i2) in (0 until ESTIMATED_WIDTH).withIndex()) {
val max = (i + (i2 + 1) * ESTIMATED_WIDTH)
if (max >= availableChar.size) break
availableChar.subList(i + i2 * ESTIMATED_WIDTH, max).forEachIndexed { x, c ->
val str = c.toString()
graphics.drawString(str, x * scale, ((y + 0.75) * yAxis).toInt())
}
}
graphics.dispose()
ImageIO.write(image, "png", File(newDir, "${fileName}_${++num}.png"))

i += ESTIMATED_WIDTH * ESTIMATED_WIDTH
}
}
}
private fun createJson() {
val json = File(jsonDir, "$jsonName.json")
if (!json.exists()) {
val array = JsonArray().apply {
add(JsonObject().apply {
addProperty("type","space")
add("advances",JsonObject().apply {
addProperty(" ", 4)
})
})
}
var i = 0
var num = 0
while (i < availableChar.size) {
array.add(JsonObject().apply {
addProperty("type", "bitmap")
addProperty("file", "questadder:font/tooltip/$fileName/${fileName}_${++num}.png")
addProperty("ascent", ascent)
addProperty("height", height)
add("chars", JsonArray().apply {
for (i2 in 0 until ESTIMATED_WIDTH) {
val max = (i + (i2 + 1) * ESTIMATED_WIDTH)
if (max >= availableChar.size) break
add(availableChar.subList(i + i2 * ESTIMATED_WIDTH, max).joinToString(""))
}
})
})
i += ESTIMATED_WIDTH * ESTIMATED_WIDTH
}
JsonWriter(json.bufferedWriter()).use {
gson.toJson(JsonObject().apply {
add("providers", array)
}, it)
}
}
}

fun asComponent(component: Component): Component {
component as TextComponent
var comp = Component.empty()
val style = component.style()
component.content().forEach {
comp = comp.append(asComponent(it, style))
}
component.children().forEach {
comp = comp.append(asComponent(it))
}
return comp
}
fun asComponent(char: Char, style: Style): Component {
var width = if (char == ' ') 4 else charWidth[char] ?: 0
if (style.hasDecoration(TextDecoration.BOLD)) width++
if (style.hasDecoration(TextDecoration.ITALIC)) width++
return Component.text(char).style(style.font(key)).append((-width).parseToSpaceComponent()).append(blank.parseToSpaceComponent())
}
fun widthComponent(int: Int) = (blank * int).parseToSpaceComponent()
fun widthComponent(component: Component): Int {
component as TextComponent
var width = component.content().length * blank
component.children().forEach {
width += widthComponent(it)
}
return width
}
}
11 changes: 11 additions & 0 deletions plugin/src/main/java/kor/toxicity/questadder/font/ToolTip.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package kor.toxicity.questadder.font

data class ToolTip(
val gui: GuiFontData,
val fade: Boolean,
val split: Int,
val offset: Int,
val chatOffset: Int,
val talker: ToolTipFontData,
val talk: List<ToolTipFontData>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package kor.toxicity.questadder.font

data class ToolTipFontData(
val offset: Int,
val font: QuestFont
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,37 @@ import com.comphenix.protocol.events.PacketEvent
import com.comphenix.protocol.wrappers.BlockPosition
import com.comphenix.protocol.wrappers.WrappedBlockData
import kor.toxicity.questadder.QuestAdderBukkit
import kor.toxicity.questadder.extension.info
import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.AsyncPlayerChatEvent
import org.bukkit.event.player.PlayerQuitEvent
import java.util.UUID

object CallbackManager: QuestAdderManager {
private val signMap = HashMap<UUID,(Array<String>) -> Unit>()
private val chatMap = HashMap<UUID,(String) -> Unit>()
override fun start(adder: QuestAdderBukkit) {
Bukkit.getPluginManager().registerEvents(object : Listener {
@EventHandler
fun chat(e: AsyncPlayerChatEvent) {
val player = e.player
chatMap.remove(player.uniqueId)?.let {
val message = e.message
if (message == "cancel") {
player.info("your action was cancelled.")
} else it(message)
}
}
@EventHandler
fun quit(e: PlayerQuitEvent) {
chatMap.remove(e.player.uniqueId)
}
}, adder)
ProtocolLibrary.getProtocolManager().addPacketListener(object : PacketAdapter(adder, PacketType.Play.Client.UPDATE_SIGN) {
override fun onPacketReceiving(event: PacketEvent) {
val player = event.player
Expand All @@ -24,6 +47,9 @@ object CallbackManager: QuestAdderManager {
}
})
}
fun openChat(player: Player, callback: (String) -> Unit) {
chatMap[player.uniqueId] = callback
}
fun openSign(player: Player, array: List<Component>, callback: (Array<String>) -> Unit) {
val loc = player.location.apply {
y = 0.0
Expand Down
Loading

0 comments on commit 9c44dfa

Please sign in to comment.