Skip to content

Commit

Permalink
feat: downsampling setting
Browse files Browse the repository at this point in the history
This adds a new option to the settings which allows for setting a
downsampler, which is run before converting the component to HTML.

This allows for "simulating" either legacy, or bedrock mode.

Has a TODO to resolve, will probably need better visual clarity (i.e.
something on the main page to show that you're currently in downsample
mode, so you don't forget...?)
4.14.0-SNAPSHOT is currently required since it's the first version which
makes `TextColor.nearestColorTo` public.

Closes #153
  • Loading branch information
rymiel committed May 6, 2023
1 parent 2783d30 commit 7d4b1ba
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 17 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ plugins {

repositories {
mavenCentral()
maven(url = "https://oss.sonatype.org/content/repositories/snapshots/") {
maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/") {
name = "sonatype-oss-snapshots"
mavenContent {
snapshotsOnly()
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
adventure = "4.13.1"
adventure = "4.14.0-SNAPSHOT"
kotlin = "1.8.20"
ktlint = "0.48.2"
ktor = "2.2.4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ public sealed interface Packet
@SerialName("call")
public data class Call(
public val miniMessage: String? = null,
public val isolateNewlines: Boolean = false
public val isolateNewlines: Boolean = false,
public val downsampler: String? = null,
) : Packet

@Serializable
Expand All @@ -26,5 +27,6 @@ public data class Combined(
public val miniMessage: String? = null,
public val placeholders: Placeholders? = null,
public val background: String? = null,
public val mode: String? = null
public val mode: String? = null,
public val downsampler: String? = null,
)
16 changes: 16 additions & 0 deletions src/commonMain/resources/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,22 @@ <h1 class="title mc-font">MiniMessage Viewer</h1>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label">
<label class="label" for="setting-downsample">Downsampler</label>
</div>
<div class="field-body">
<div class="control">
<div class="select">
<select id="setting-downsample">
<option value="none" selected>None</option>
<option value="bedrock">Bedrock</option>
<option value="legacy">Legacy</option>
</select>
</div>
</div>
</div>
</div>
</section>
<footer class="modal-card-foot"></footer>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ public fun restoreFromShortLink(shortCode: String, inputBox: HTMLTextAreaElement
structure.getFromCombinedOrLocalStorage(PARAM_MODE, Combined::mode)?.also { mode ->
setMode(Mode.fromString(mode))
}
structure.getFromCombinedOrLocalStorage(PARAM_DOWNSAMPLE, Combined::downsampler)?.also { downsampler ->
currentDownsampler = downsampler
}
webSocket.send(
Placeholders(stringPlaceholders = stringPlaceholders)
)
Expand Down
25 changes: 22 additions & 3 deletions src/jsMain/kotlin/net/kyori/adventure/webui/js/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ public const val PARAM_MODE: String = "mode"
public const val PARAM_BACKGROUND: String = "bg"
public const val PARAM_STRING_PLACEHOLDERS: String = "st"
public const val PARAM_SHORT_LINK: String = "x"
public const val PARAM_DOWNSAMPLE: String = "ds"

private var isInEditorMode: Boolean = false
private lateinit var editorInput: EditorInput

public lateinit var currentMode: Mode
public lateinit var currentDownsampler: String
private lateinit var webSocket: WebSocket

public fun mainLoaded() {
Expand Down Expand Up @@ -222,6 +224,16 @@ public fun mainLoaded() {
currentBackground = settingBackground.value
}
)
val settingDownsample = document.element<HTMLSelectElement>("setting-downsample")
currentDownsampler = settingDownsample.value
settingDownsample.addEventListener(
"change",
{
console.log(settingDownsample)
currentDownsampler = settingDownsample.value
parse()
}
)

// SHARING
document.getElementById("full-link-share-button")!!.addEventListener(
Expand All @@ -234,6 +246,7 @@ public fun mainLoaded() {
if (currentMode != Mode.SERVER_LIST) {
link += "&$PARAM_BACKGROUND=$currentBackground"
}
link += "&$PARAM_DOWNSAMPLE=$currentDownsampler"
if (!placeholders.stringPlaceholders.isNullOrEmpty()) {
link += "&$PARAM_STRING_PLACEHOLDERS="
link +=
Expand All @@ -254,7 +267,8 @@ public fun mainLoaded() {
miniMessage = input.value,
placeholders = readPlaceholders(),
background = if (currentMode != Mode.SERVER_LIST) currentBackground else null,
mode = currentMode.paramName
mode = currentMode.paramName,
downsampler = currentDownsampler
)
)
.then { code -> "$homeUrl?$PARAM_SHORT_LINK=$code" }
Expand Down Expand Up @@ -297,7 +311,7 @@ public fun mainLoaded() {
{
window.postPacket(
"$URL_API$URL_MINI_TO_JSON",
Combined(miniMessage = input.value, placeholders = readPlaceholders())
Combined(miniMessage = input.value, placeholders = readPlaceholders(), downsampler = currentDownsampler)
)
.then { response -> response.text() }
.then { text -> window.navigator.clipboard.writeText(text) }
Expand Down Expand Up @@ -444,6 +458,10 @@ private fun onWebsocketReady() {
urlParams.getFromParamsOrLocalStorage(PARAM_MODE)?.also { mode ->
setMode(Mode.fromString(mode))
}
// TODO(rymiel): This does not currently set the dropdown to the correct value
urlParams.getFromParamsOrLocalStorage(PARAM_DOWNSAMPLE)?.also { downsampler ->
currentDownsampler = downsampler
}
webSocket.send(
Placeholders(stringPlaceholders = stringPlaceholders)
)
Expand Down Expand Up @@ -594,6 +612,7 @@ private fun parse() {
val input = document.element<HTMLTextAreaElement>("input").value
// Store current input for persistence
window.localStorage[PARAM_INPUT] = input
window.localStorage[PARAM_DOWNSAMPLE] = currentDownsampler

if (input.isEmpty() && currentMode != Mode.SERVER_LIST) {
// we don't want to parse if input is empty (server list mode is an exception!)
Expand All @@ -619,7 +638,7 @@ private fun parse() {
if (line == "") "\u200B" else line
}

webSocket.send(Call(combinedLines, isolateNewlines = currentMode == Mode.LORE))
webSocket.send(Call(combinedLines, isolateNewlines = currentMode == Mode.LORE, downsampler = currentDownsampler))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package net.kyori.adventure.webui.jvm.minimessage

import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.NamedTextColor
import net.kyori.adventure.text.format.TextColor
import java.util.function.UnaryOperator

// This could just be thing which serializes to legacy, and then back. But this thing is way more fun
private class LimitedDownsampler(val colors: List<TextColor>) {
fun render(component: Component): Component {
return component
.children(component.children().map(::render))
.color(component.color()?.let { color -> TextColor.nearestColorTo(colors, color) })
.hoverEvent(null)
.clickEvent(null)
}
}

// Won't be necessary after https://github.com/KyoriPowered/adventure/issues/910 is closed
private val bedrockColors = listOf(
NamedTextColor.DARK_BLUE,
NamedTextColor.DARK_GREEN,
NamedTextColor.DARK_AQUA,
NamedTextColor.DARK_RED,
NamedTextColor.DARK_PURPLE,
NamedTextColor.GOLD,
NamedTextColor.GRAY,
NamedTextColor.DARK_GRAY,
NamedTextColor.BLUE,
NamedTextColor.GREEN,
NamedTextColor.AQUA,
NamedTextColor.RED,
NamedTextColor.LIGHT_PURPLE,
NamedTextColor.YELLOW,
NamedTextColor.WHITE,
TextColor.color(0xddd605), // minecoin_gold
TextColor.color(0xe3d4d1), // material_quartz
TextColor.color(0xcecaca), // material_iron
TextColor.color(0x443a3b), // material_netherite
TextColor.color(0x971607), // material_redstone
TextColor.color(0xb4684d), // material_copper
TextColor.color(0xdEB12d), // material_gold
TextColor.color(0x47a036), // material_emerald
TextColor.color(0x2cbaa8), // material_diamond
TextColor.color(0x21497b), // material_lapis
TextColor.color(0x9a5cc6), // material_amethyst
)
private val legacyDownsampler = LimitedDownsampler(NamedTextColor.NAMES.values().toList())
private val bedrockDownsampler = LimitedDownsampler(bedrockColors)

public enum class Downsampler(private val function: UnaryOperator<Component>) {
NONE(UnaryOperator.identity()),
LEGACY(legacyDownsampler::render),
BEDROCK(bedrockDownsampler::render),
;

public fun apply(component: Component): Component {
return function.apply(component).compact()
}

public companion object {
private val values = Downsampler.values()
public fun of(name: String?): Downsampler {
return values.firstOrNull { i -> i.name.equals(name, ignoreCase = true) } ?: NONE
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public fun Application.miniMessage() {
webSocket(URL_MINI_TO_HTML) {
var tagResolver = TagResolver.empty()
var miniMessage: String? = null
var downsampler: Downsampler = Downsampler.NONE
var isolateNewlines = false

for (frame in incoming) {
Expand All @@ -116,6 +117,7 @@ public fun Application.miniMessage() {
is Call -> {
miniMessage = packet.miniMessage
isolateNewlines = packet.isolateNewlines
downsampler = Downsampler.of(packet.downsampler)
}
is Placeholders -> tagResolver = packet.tagResolver
null -> continue
Expand All @@ -131,16 +133,17 @@ public fun Application.miniMessage() {
.split("\n")
.map { line -> HookManager.render(line) }
.map { line ->
MiniMessage.miniMessage()
.deserialize(line, tagResolver)
MiniMessage.miniMessage().deserialize(line, tagResolver)
}
.map { component -> downsampler.apply(component) }
.map { component -> HookManager.render(component) }
.forEach { component ->
result.appendComponent(component)
result.append("\n")
}
} else {
val component = MiniMessage.miniMessage().deserialize(HookManager.render(miniMessage), tagResolver)
var component = MiniMessage.miniMessage().deserialize(HookManager.render(miniMessage), tagResolver)
component = downsampler.apply(component)
result.appendComponent(HookManager.render(component))
}

Expand All @@ -161,13 +164,10 @@ public fun Application.miniMessage() {
post(URL_MINI_TO_JSON) {
val structure = Serializers.json.tryDecodeFromString<Combined>(call.receiveText())
val input = structure?.miniMessage ?: return@post
call.respondText(
GsonComponentSerializer.gson()
.serialize(
MiniMessage.miniMessage()
.deserialize(input, structure.placeholders.tagResolver)
)
)

var component = MiniMessage.miniMessage().deserialize(input, structure.placeholders.tagResolver)
component = Downsampler.of(structure.downsampler).apply(component)
call.respondText(GsonComponentSerializer.gson().serialize(component))
}

post(URL_MINI_TO_TREE) {
Expand Down

0 comments on commit 7d4b1ba

Please sign in to comment.