Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ plots:
Typ zapisanej działki wybiera właściwe rozszerzanie niezależnie od aktualnego
`claiming.mode`. Działka klasyczna otrzymuje kwadratowy segment. Działka chunkowa
otrzymuje jeden wolny chunk przylegający bokiem do chunka, w którym stoi właściciel.
Oba warianty są obsługiwane przez panel; na zgodnym Paper używany jest natywny dialog,
a na starszym lub tłumaczonym kliencie GUI ekwipunkowe.
Oba warianty są obsługiwane przez GUI ekwipunkowe. Natywne dialogi są zarezerwowane
dla operacji wymagających wpisania tekstu, takich jak zmiana nazwy działki.

Zakup chunkowy używa osobnego cennika `plots.chunks.expansion`. Cena następnego
chunka to `price × priceMultiplier ^ liczba_dokupionych_chunków`. Obowiązują
Expand Down
10 changes: 5 additions & 5 deletions docs/dialogs.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Dialogi działek

PlotsX wybiera natywne dialogi, jeśli serwer udostępnia Paper Dialog API (wprowadzone w Paper 1.21.7). Na starszych serwerach, w tym 1.20.6 i 1.21.6, pozostają dotychczasowe menu ekwipunku i zmiana nazwy przez czat. Minimum w `paper-plugin.yml` pozostaje 1.20.6, a bytecode Java 21.
PlotsX używa natywnego dialogu wyłącznie wtedy, gdy interakcja wymaga wpisania tekstu, obecnie przy zmianie nazwy działki. Dialog jest wybierany, jeśli serwer udostępnia Paper Dialog API (wprowadzone w Paper 1.21.7). Na starszych serwerach, w tym 1.20.6 i 1.21.6, zmiana nazwy odbywa się przez czat. Minimum w `paper-plugin.yml` pozostaje 1.20.6, a bytecode Java 21.

Dialogi obejmują zmianę nazwy, potwierdzenie tworzenia, usuwania i rozszerzania działki oraz usunięcia członka i przekazania własności. Główne menu i listy pozostają menu ekwipunku. Istniejące komendy z kompletnymi argumentami zachowują dotychczasowe działanie.
Potwierdzenia tworzenia, usuwania i rozszerzania działki oraz usunięcia członka i przekazania własności zawsze pozostają w menu ekwipunku. Natywny dialog nie zastępuje ekranów, które nie wymagają wprowadzenia treści. Istniejące komendy z kompletnymi argumentami zachowują dotychczasowe działanie.

```yaml
interactions:
Expand All @@ -14,7 +14,7 @@ interactions:

Nowe komunikaty znajdują się w sekcji `dialogs` plików językowych PL i EN. Nazwa ma maksymalnie 255 znaków, zgodnie ze schematem bazy. Czat i dialog stosują tę samą walidację, filtr CleanerX i kontrolę uprawnień. Zapis obecnej nazwy jest dozwolony.

Formularz jest związany z graczem, wygasa po 60 sekundach i może zostać zatwierdzony tylko raz. Kolejny formularz, otwarcie ekwipunku lub wyjście gracza unieważniają poprzednią sesję. Anulowanie nie wykonuje operacji. Przy tworzeniu działki zmiana pozycji X/Z, świata albo promienia wymaga ponownego wywołania `/claim`. Rozszerzenie nadal weryfikuje aktualność ceny i poziomu przed pobraniem pieniędzy.
Formularz jest związany z graczem, wygasa po 60 sekundach i może zostać zatwierdzony tylko raz. Kolejny formularz, otwarcie ekwipunku lub wyjście gracza unieważniają poprzednią sesję. Anulowanie nie wykonuje operacji.

Adapter dialogowy jest ładowany refleksyjnie; wspólna fasada nie zawiera typów Dialog API. Błąd wyświetlenia przywraca obsługiwane menu lub czat. Przełączanie na dialog i obsługa odpowiedzi używają schedulera gracza. Nie jest to audyt zgodności całego pluginu z Folia — istniejące operacje bazy/cache i wizualizacje zawierają również starsze wywołania schedulerów.

Expand All @@ -25,9 +25,9 @@ Automatyczne testy `DialogSessionsTest` obejmują stare formularze, obcego gracz
Przed wydaniem należy wykonać testy w grze (nie są zastąpione przez testy jednostkowe):

- Paper 1.20.6 i 1.21.6: start JAR bez błędów brakujących klas, wszystkie operacje w starym interfejsie.
- Paper 1.21.7, 1.21.11 i wspierane 26.x: każdy nowy ekran, zapis, Anuluj/Escape i timeout.
- Paper 1.21.7, 1.21.11 i wspierane 26.x: dialog zmiany nazwy, zapis, Anuluj/Escape i timeout; pozostałe operacje w menu ekwipunku.
- `mode: legacy` oraz konfiguracja translatora: działający fallback, w tym obsługa kliknięć w menu.
- Odebranie uprawnień, usunięcie działki lub zmiana właściciela przy otwartym formularzu: odrzucenie nieaktualnej operacji.
- Rozszerzenie: zmiana ceny/poziomu, podwójne zatwierdzenie, brak środków i poprawne rozliczenie.
- Rozszerzenie w menu ekwipunku: zmiana ceny/poziomu, podwójne zatwierdzenie, brak środków i poprawne rozliczenie.
- Zmiana nazwy: pusta/niedozwolona nazwa, duplikat, bieżąca nazwa i awaria filtra; błędy zachowują wpis w formularzu.
- Folia: osobny test całych operacji z istniejącymi usługami pluginu.
2 changes: 1 addition & 1 deletion docs/wiki/Panel-dzialki.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Na serwerze z dostępnym Paper Dialog API (od 1.21.7) opcja otwiera formularz z

Na starszych wersjach lub przy wymuszonym starym interfejsie masz 60 sekund na wpisanie nazwy na czacie. Wiadomość posłuży jako nazwa, zamiast trafić na czat ogólny. Gdy czas minie, otwórz opcję ponownie. Maksymalna długość nazwy wynosi 255 znaków.

Dialogi obsługują także potwierdzenia tworzenia, usuwania i rozszerzania działek oraz usuwania członków i przekazywania własności. Szczegóły wyboru interfejsu i obsługi translatorów protokołu opisuje [konfiguracja dialogów](../dialogs.md).
Pozostałe operacje, w tym tworzenie, usuwanie i rozszerzanie działek oraz zarządzanie członkami, używają menu ekwipunku. Dialog jest przeznaczony wyłącznie dla interakcji wymagających wpisania tekstu. Szczegóły wyboru interfejsu i obsługi translatorów protokołu opisuje [konfiguracja dialogów](../dialogs.md).

Nie możesz nadać dwóch swoim działkom tej samej nazwy. Wybieraj proste nazwy, na przykład `Baza`, `Farma` i `Port`. Unikaj nazw `add`, `remove` i `members`, bo są używane przez komendy.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class UnclaimCMD(private val plugin: PlotsX) : BasicCommand {
private fun openUnclaimGui(player: Player, plotId: Int) {
val gui = UnclaimConfirmGUI(
plugin = plugin,
plotName = plugin.databaseHandler.getPlotById(plotId)?.name ?: plotId.toString(),
player = player,
onConfirm = { p ->
val current = plugin.databaseHandler.getPlotById(plotId)
Expand Down
39 changes: 1 addition & 38 deletions src/main/kotlin/pl/syntaxdevteam/plotsx/gui/ChunkExpandGUI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,30 +30,7 @@ internal class ChunkExpandGUI(private val plugin: PlotsX, private val plotId: In
override fun open(player: Player) {
val plot = prepareOffer(player) ?: return
renderInventory(player, plot)
val geometry = plot.geometry as ChunkGeometry
val availableDirections = ExpansionDirection.entries
.filter { value -> source?.let { geometry.expansion(value, it) }?.let { candidate ->
plugin.cacheManager.getCachedPlots().none { other ->
other.id != plot.id && other.world.equals(plot.world, true) &&
other.geometry.intersects(ChunkGeometry(setOf(candidate)))
} && plugin.regionProtectionHook?.overlapsBounds(player.world, candidate.bounds) != true
} == true }
.associate { it.name to text("expand.directions.${it.name.lowercase()}") }
val body = listOf(
if (source == null) text("expand.stand_inside") else text("expand.source", mapOf(
"x" to source!!.x.toString(), "z" to source!!.z.toString())),
text("expand.chunk_count", mapOf("count" to plot.chunks.size.toString(),
"max" to plugin.hookHandler.getMaxChunksPerPlot(player).toString())),
text("expand.price", mapOf("price" to (price?.toPlainString() ?: "?"))),
plugin.interactions.text("chunk_expand_choose")
)
if (!plugin.interactions.choose(player, plugin.interactions.text("chunk_expand_title"), body,
availableDirections, onChoice = { selected, value ->
direction = ExpansionDirection.valueOf(value)
val refreshed = prepareOffer(selected) ?: return@choose
renderInventory(selected, refreshed)
openNativeConfirmation(selected, refreshed)
}, fallback = { openLegacy(player) })) openLegacy(player)
openLegacy(player)
}

private fun prepareOffer(player: Player): PlotData? {
Expand Down Expand Up @@ -82,20 +59,6 @@ internal class ChunkExpandGUI(private val plugin: PlotsX, private val plotId: In
inventory.setItem(24, item(Material.BARRIER, "expand.cancel"))
}

private fun openNativeConfirmation(player: Player, plot: PlotData) {
val to = target ?: run { player.sendMessage(text("expand.direction_blocked")); open(player); return }
val body = listOf(
text("expand.directions.${direction.name.lowercase()}"),
text("expand.chunk_target", mapOf("x" to to.x.toString(), "z" to to.z.toString())),
text("expand.chunk_count", mapOf("count" to plot.chunks.size.toString(),
"max" to plugin.hookHandler.getMaxChunksPerPlot(player).toString())),
text("expand.price", mapOf("price" to (price?.toPlainString() ?: "?")))
)
if (!plugin.interactions.confirm(player, plugin.interactions.text("chunk_expand_confirm"), body,
onConfirm = { if (!submitted) { submitted = true; submit(it) } },
onCancel = { open(it) }, fallback = { openLegacy(player) })) openLegacy(player)
}

private fun openLegacy(player: Player) { plugin.guiHandler.openLegacy(player, this) }

override fun handleClick(event: InventoryClickEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ class ClaimConfirmGUI(
"world" to loc.world.name, "x" to loc.blockX.toString(), "z" to loc.blockZ.toString(),
"radius" to plugin.hookHandler.getClaimRadius(player).toString()))
inventory.setItem(13, plugin.guiHandler.createItem(Material.MAP, body))
if (!plugin.interactions.confirm(player,
message.stringMessageToComponentNoPrefix("GUI", "claim.title_claim"), listOf(body),
onConfirm = { submit(it, true) }, onCancel = { submit(it, false) },
fallback = { openLegacy(player) })) openLegacy(player)
openLegacy(player)
}

private fun openLegacy(player: Player) { plugin.guiHandler.openLegacy(player, this) }
Expand Down
9 changes: 0 additions & 9 deletions src/main/kotlin/pl/syntaxdevteam/plotsx/gui/MembersGUI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,6 @@ class MembersGUI(
else -> show(it)
}
}
if (screen in listOf("remove", "transfer") && target != null &&
plugin.interactions.confirm(player,
plugin.messageHandler.stringMessageToComponentNoPrefix("members", "confirm_$screen",
mapOf("player" to operations.name(target))),
listOf(plugin.interactions.text("${screen}_body", mapOf(
"plot" to plot.name, "player" to operations.name(target)))),
onConfirm = { run(it, if (screen == "transfer") listOf("transfer", target.toString(), "confirm")
else listOf("remove", target.toString())) },
onCancel = { show(it) }, fallback = { openLegacy(player) })) return
openLegacy(player)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ class UnclaimConfirmGUI(
private val plugin: PlotsX,
private val player: Player,
private val onConfirm: (Player) -> Unit,
private val onCancel: (Player) -> Unit,
private val plotName: String = ""
private val onCancel: (Player) -> Unit
) : AbstractGUI(plugin.messageHandler.stringMessageToComponentNoPrefix("GUI", "unclaim.title_unclaim"), 3*9) {

private val message = plugin.messageHandler
Expand All @@ -20,11 +19,7 @@ class UnclaimConfirmGUI(
private var submitted = false

override fun open(player: Player) {
if (!plugin.interactions.confirm(player,
message.stringMessageToComponentNoPrefix("GUI", "unclaim.title_unclaim"),
listOf(plugin.interactions.text("unclaim_body", mapOf("plot" to plotName))),
onConfirm = { submit(it, true) }, onCancel = { submit(it, false) },
fallback = { openLegacy(player) })) openLegacy(player)
openLegacy(player)
}

private fun openLegacy(player: Player) { plugin.guiHandler.openLegacy(player, this) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import java.time.Duration
/** Loaded reflectively only when Paper's dialog API exists. */
@Suppress("UnstableApiUsage")
class PaperDialogBackend : DialogBackend {
override fun show(player: Player, title: Component, body: List<Component>, initial: String?,
yes: Component, no: Component, reply: (String?) -> Unit) {
override fun showTextInput(player: Player, title: Component, body: List<Component>, initial: String,
yes: Component, no: Component, reply: (String?) -> Unit) {
val options = ClickCallback.Options.builder().uses(1).lifetime(Duration.ofSeconds(60)).build()
val accept = ActionButton.builder(yes).action(DialogAction.customClick({ response, audience ->
if (audience is Player && audience.uniqueId == player.uniqueId)
reply(if (initial == null) "" else response.getText("name") ?: "")
reply(response.getText("name") ?: "")
}, options)).build()
val cancel = ActionButton.builder(no).action(DialogAction.customClick({ _, audience ->
if (audience is Player && audience.uniqueId == player.uniqueId) reply(null)
Expand All @@ -29,35 +29,12 @@ class PaperDialogBackend : DialogBackend {
builder.empty().base(DialogBase.builder(title)
.canCloseWithEscape(true)
.body(body.map { DialogBody.plainMessage(it) })
.inputs(if (initial == null) emptyList() else listOf(
DialogInput.text("name", title).initial(initial.take(255)).maxLength(255).build()))
.inputs(listOf(DialogInput.text("name", title)
.initial(initial.take(255)).maxLength(255).build()))
.build())
.type(DialogType.confirmation(accept, cancel))
}
player.showDialog(dialog)
}

override fun showChoices(player: Player, title: Component, body: List<Component>,
choices: Map<String, Component>, cancel: Component,
reply: (String?) -> Unit) {
val buttons = choices.map { (value, label) ->
ActionButton.builder(label).action(DialogAction.customClick({ _, audience ->
if (audience is Player && audience.uniqueId == player.uniqueId) reply(value)
}, callbackOptions())).build()
}
val cancelButton = ActionButton.builder(cancel).action(DialogAction.customClick({ _, audience ->
if (audience is Player && audience.uniqueId == player.uniqueId) reply(null)
}, callbackOptions())).build()
val dialog = Dialog.create { builder ->
builder.empty().base(DialogBase.builder(title)
.canCloseWithEscape(true)
.body(body.map { DialogBody.plainMessage(it) })
.build())
.type(DialogType.multiAction(buttons, cancelButton, 2))
}
player.showDialog(dialog)
}

private fun callbackOptions(): ClickCallback.Options =
ClickCallback.Options.builder().uses(1).lifetime(Duration.ofSeconds(60)).build()
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ import pl.syntaxdevteam.plotsx.PlotsX

/** No dialog API types may escape the optional adapter into this baseline facade. */
interface DialogBackend {
fun show(player: Player, title: Component, body: List<Component>, initial: String?,
yes: Component, no: Component, reply: (String?) -> Unit)
fun showChoices(player: Player, title: Component, body: List<Component>, choices: Map<String, Component>,
cancel: Component, reply: (String?) -> Unit)
fun showTextInput(player: Player, title: Component, body: List<Component>, initial: String,
yes: Component, no: Component, reply: (String?) -> Unit)
}

class PlotInteractions(private val plugin: PlotsX) : Listener {
Expand All @@ -35,22 +33,6 @@ class PlotInteractions(private val plugin: PlotsX) : Listener {
.none { plugin.server.pluginManager.isPluginEnabled(it) } &&
!plugin.config.getBoolean("interactions.translated-clients", false)

fun confirm(player: Player, title: Component, body: List<Component>, yes: Component = text("confirm"),
no: Component = text("cancel"), onConfirm: (Player) -> Unit, onCancel: (Player) -> Unit = {},
fallback: () -> Unit): Boolean =
show(player, title, body, null, yes, no, { p, value ->
if (value != null) onConfirm(p) else onCancel(p)
}, fallback)

fun choose(player: Player, title: Component, body: List<Component>, choices: Map<String, Component>,
onChoice: (Player, String) -> Unit, onCancel: (Player) -> Unit = {},
fallback: () -> Unit): Boolean {
if (choices.isEmpty()) return false
return showSession(player, fallback, { reply ->
backend!!.showChoices(player, title, body, choices, text("cancel"), reply)
}) { p, value -> if (value == null) onCancel(p) else onChoice(p, value) }
}

fun rename(player: Player, plotId: Int, initial: String, error: Component? = null): Boolean =
show(player, text("rename"), listOfNotNull(error), initial, text("save"), text("cancel"), { p, value ->
if (value != null) {
Expand All @@ -61,10 +43,10 @@ class PlotInteractions(private val plugin: PlotsX) : Listener {
}
}, { plugin.renamePlotChatListener.startRenameProcess(player, plotId) })

private fun show(player: Player, title: Component, body: List<Component>, initial: String?,
private fun show(player: Player, title: Component, body: List<Component>, initial: String,
yes: Component, no: Component, reply: (Player, String?) -> Unit,
fallback: () -> Unit): Boolean = showSession(player, fallback, { callback ->
backend!!.show(player, title, body, initial, yes, no, callback)
backend!!.showTextInput(player, title, body, initial, yes, no, callback)
}, reply)

private fun showSession(player: Player, fallback: () -> Unit,
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ config-version: 100
# If you would like to add your own language file, please contact us on Discord (https://discord.gg/Zk6mxv7eMh).
language: "EN"

# auto: native dialogs when available; legacy: existing inventory menus and chat.
# auto: native text-entry dialogs when available; legacy: text entry through chat.
interactions:
mode: auto
# Set true when a proxy translates client protocols (e.g. ViaVersion/Geyser).
Expand Down
7 changes: 0 additions & 7 deletions src/main/resources/lang/messages_en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,6 @@ flags:
name: "Team Management"
description: "Add or remove all members of your team from the plot."
dialogs:
confirm: "Confirm"
cancel: "Cancel"
save: "Save"
rename: "Plot name"
Expand All @@ -409,12 +408,6 @@ dialogs:
claim_body: "Create a plot in <world>, at X: <x>, Z: <z>, radius: <radius>?"
claim_chunk_body: "Claim chunk <chunk_x>, <chunk_z> in <world>? Area: 256 blocks."
claim_changed: "Your position or claim radius changed. Run /claim again."
chunk_expand_title: "Expand chunk plot"
chunk_expand_choose: "Choose an adjacent direction. The exact target and price will be confirmed next."
chunk_expand_confirm: "Confirm chunk purchase"
unclaim_body: "Delete plot <plot>? Its protection will be removed."
transfer_body: "Transfer ownership of <plot> to <player>? You will lose owner privileges."
remove_body: "Remove <player> from plot <plot>?"

help:
header: "<gold><bold><plugin> commands</bold></gold>"
Expand Down
Loading
Loading