Skip to content

Instantly share code, notes, and snippets.

@Grabsky
Last active January 26, 2026 12:28
Show Gist options
  • Select an option

  • Save Grabsky/d17927a4ad80dbce1f7caa30241122db to your computer and use it in GitHub Desktop.

Select an option

Save Grabsky/d17927a4ad80dbce1f7caa30241122db to your computer and use it in GitHub Desktop.
/*
* https://gist.github.com/Grabsky/d17927a4ad80dbce1f7caa30241122db
*
* Copyright (C) Grabsky (michal.czopek.foss@proton.me)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License v3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License v3 for more details.
*/
@file:Suppress("UnstableApiUsage")
import com.google.gson.FormattingStyle
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import com.google.gson.Strictness
import java.time.Duration
object Const {
// This Gson instance is set to output a human-readable format, as well as ignore some strict formatting rules.
val GSON = GsonBuilder().setFormattingStyle(FormattingStyle.PRETTY).setStrictness(Strictness.LENIENT).create()!!
}
command("edit") {
permission = "kite.command.edit"
execute { sender, _ ->
if (sender is Player) {
val item = sender.inventory.itemInMainHand
// If player hand is empty, sending an error message and skipping other logic.
if (item.isEmpty) {
sender.sendRichMessage("<dark_gray>› <red>You must hold an item in your hand.")
return@execute
}
// Getting JSON data of currently held item.
val initial = Const.GSON.toJson(Bukkit.getUnsafe().serializeItemAsJson(item))
// Creating dialog and showing it to player.
val dialog = Dialog.create {
it.empty()
.base(DialogBase.builder(Component.text("Item Editor"))
.inputs(listOf(
DialogInput.text("value", Component.text("Be cautious when editing raw data, as it can permanently break your item!"))
.initial(initial)
.width(400)
.maxLength(Int.MAX_VALUE)
.multiline(TextDialogInput.MultilineOptions.create(Int.MAX_VALUE, 200))
.build()
))
.build())
.type(DialogType.confirmation(
ActionButton.builder(Component.text("Confirm"))
.action(DialogAction.customClick({ response, _ ->
val value = response.getText("value")
try {
val json = Const.GSON.fromJson(value, JsonObject::class.java)
val item = Bukkit.getUnsafe().deserializeItemFromJson(json)
// Updating player's hand with new item.
sender.inventory.setItemInMainHand(item)
// At this point, operation should've been successful (unless it has thrown); sending confirmation message.
sender.sendRichMessage("<dark_gray>› <gray>Item in your hand has been modified.")
} catch (e: Throwable) {
sender.sendRichMessage("<dark_gray>› <red>Failed to deserialize item from JSON input string.")
server.logger.severe("Failed to deserialize item from JSON input string:")
// Otherwise, just printing the exception message.
server.logger.severe(" (1) " + e::class.simpleName + ": " + e.message?.split("\n")[0])
if (e.cause != null)
server.logger.severe(" (2) " + e.cause!!::class.simpleName + ": " + e.cause!!.message?.split("\n")[0])
}
}, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(30)).build()))
.build(),
ActionButton.builder(Component.text("Decline")).build()
))
}
sender.showDialog(dialog)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment