From 770dcbfb1dc68e1c3c5c46614445764437fe98e7 Mon Sep 17 00:00:00 2001 From: Legends11 <235496468+tickwarden@users.noreply.github.com> Date: Sun, 20 Sep 2026 10:33:57 +0300 Subject: [PATCH] Add files via upload --- packs/guikit-datapack/README.md | 40 ++++++++- .../data/guikit/function/api/open.mcfunction | 2 + .../guikit/function/cond/check.mcfunction | 4 + .../guikit/function/cond/comp_pick.mcfunction | 3 + .../guikit/function/cond/comp_run.mcfunction | 17 ++++ .../guikit/function/cond/comp_step.mcfunction | 15 ++++ .../guikit/function/cond/load_cur.mcfunction | 14 ++++ .../guikit/function/cond/t_all.mcfunction | 5 ++ .../guikit/function/cond/t_any.mcfunction | 5 ++ .../function/internal/btn_afford.mcfunction | 8 ++ .../internal/btn_afford_item.mcfunction | 8 ++ .../internal/btn_afford_score.mcfunction | 2 + .../function/internal/btn_click.mcfunction | 10 ++- .../function/internal/btn_cond.mcfunction | 15 +--- .../function/internal/btn_gate.mcfunction | 6 ++ .../function/internal/btn_pay.mcfunction | 5 ++ .../function/internal/btn_pay_item.mcfunction | 5 ++ .../function/internal/btn_poor.mcfunction | 6 ++ .../function/internal/btn_visual.mcfunction | 4 +- .../internal/cleanup_scores.mcfunction | 6 ++ .../function/internal/clear_cond.mcfunction | 1 + .../function/internal/clear_tmp.mcfunction | 3 + .../internal/containers_builtin.mcfunction | 19 ++--- .../function/internal/follow.mcfunction | 3 + .../function/click/open_chest_boat.mcfunction | 9 ++ .../data/demo/function/main/page2.mcfunction | 83 +++++++++++++++++++ .../data/demo/function/main/probe.mcfunction | 64 ++++++++++++++ .../data/demo/function/register.mcfunction | 40 +++++++++ 28 files changed, 372 insertions(+), 30 deletions(-) create mode 100644 packs/guikit-datapack/data/guikit/function/cond/comp_pick.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/cond/comp_run.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/cond/comp_step.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/cond/load_cur.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/cond/t_all.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/cond/t_any.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/internal/btn_afford.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/internal/btn_afford_item.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/internal/btn_afford_score.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/internal/btn_gate.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/internal/btn_pay.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/internal/btn_pay_item.mcfunction create mode 100644 packs/guikit-datapack/data/guikit/function/internal/btn_poor.mcfunction create mode 100644 packs/guikit-datapack/examples/guikit-demo/data/demo/function/click/open_chest_boat.mcfunction create mode 100644 packs/guikit-datapack/examples/guikit-demo/data/demo/function/main/page2.mcfunction create mode 100644 packs/guikit-datapack/examples/guikit-demo/data/demo/function/main/probe.mcfunction create mode 100644 packs/guikit-datapack/examples/guikit-demo/data/demo/function/register.mcfunction diff --git a/packs/guikit-datapack/README.md b/packs/guikit-datapack/README.md index 10a90480..9228d601 100644 --- a/packs/guikit-datapack/README.md +++ b/packs/guikit-datapack/README.md @@ -53,6 +53,8 @@ storage `guikit:reg containers.`. If the name is not registered it is take | `trapped_chest` | `chest_minecart` | 27 | red | Trapped Chest | | `shulker_box` | `chest_minecart` | 27 | magenta | Shulker Box | | `copper_chest` | `chest_minecart` | 27 | orange | Copper Chest | +| `oak_chest_boat`, `spruce_...`, `birch_...`, `jungle_...`, `acacia_...`, `dark_oak_...`, `mangrove_...`, `cherry_...` `_chest_boat`, `bamboo_chest_raft` | the same id | 27 | gray | | +| `donkey`, `mule` | the same id | 15 | gray | registered, **not usable yet** (see below) | The themed ones are cosmetic: Minecraft has no ender chest / barrel **entity**, and the framework needs `/summon` + `item replace entity @s container.N`, so they are a `chest_minecart` with a different pad and title. @@ -71,6 +73,13 @@ data modify storage guikit:reg menus."ns:shop" set value {alias:"ns_shop", conta | `pad` | item id `widget/pad` puts in every slot | `minecraft:gray_stained_glass_pane` | | `title` | optional **SNBT text component** (`{text:"Shop"}`), becomes the container title | none | +- **Chest boats / rafts** are in `#guikit:container`, but only minecarts follow their owner (`internal/follow` + teleports `chest_minecart` and `hopper_minecart`). A boat stays where it was summoned, so the owner has to ride it: + `ride @s mount ` right after `api/open` (see `demo:click/open_chest_boat`; match the cart by + `guikit.uid`, the nearest cart can belong to another player). +- **`donkey` / `mule`** are registered but deliberately not in `#guikit:container` (their inventory slot numbering + under `container.N` is unconfirmed), so opening such a menu is refused by `internal/open_fail`. There is no `offset` + key. - Registry names are plain keys (`shop`, `ns_shop`); quote the path if you use a colon: `containers."ns:shop"`. - `title` must be a compound, not `'{"text":"Shop"}'`: in 26.3 a quoted string is a plain string and the title would show the JSON itself. @@ -108,10 +117,22 @@ Runs `as` the player. Result: `#cond guikit.tmp` = 1 / 0 (also the return value) | `advancement` | `adv` | e.g. `minecraft:story/root` | | `predicate` | `pred` | any predicate, so anything not listed can still be a condition | | `level` | optional `min`, `max` | XP **level** (the number above the hotbar, not a scoreboard); with neither key any level passes. Not verified in a live client | +| `all` | `of:[{...}, {...}]` | passes when **every** element passes (empty list passes); stops at the first failure | +| `any` | `of:[{...}, {...}]` | passes when **at least one** element passes (empty list fails); stops at the first pass | -`not:1b` inverts. An unknown `type` or a missing key **fails** (result 0). Every type is its own small function +```mcfunction +data merge storage guikit:cond {type:"all", of:[{type:"tag", tag:"vip"}, {type:"level", min:5}, {type:"tag", tag:"banned", not:1b}]} +function guikit:cond/check +``` + +`all`/`any` are one level deep: an element must be a plain type, an element that is itself `all`/`any` is not +evaluated and counts as **failed**. Every element can carry its own `not`, and so can the `all`/`any` itself. +A missing `of` fails (`not` is not applied to it). + +`not:1b` inverts. An unknown `type` or a missing key **fails** (result 0), except that a `not:1b` next to an +unknown type / missing key flips that 0 to 1 (known quirk of the leaf types; the `all`/`any` path does not have it). Every type is its own small function (`guikit:cond/t_*`); `min`/`max` are two open-ended ranges, never a closed `A..B`. -New key -> add it to `guikit:internal/clear_cond` (and to `guikit:internal/btn_cond` if buttons should support it). +New key -> add it to `guikit:internal/clear_cond` and to `guikit:cond/load_cur` (that copy list is shared by buttons and by `all`/`any`). ## Command buttons (`guikit:widget/button`) @@ -140,17 +161,23 @@ Definition keys: | `url` | prints a clickable `open_url` link in chat instead (combine with `close:1b`, chat is hidden behind the menu) | | `cond` | any condition from the table above (same keys, incl. `not`). Failing: `deny` message, nothing runs | | `deny` | message when `cond` fails, default `Not available.` (no double quotes in it) | +| `cost` | `{obj:"coins", amount:5}` (score) or `{item:"minecraft:diamond", count:3}` (item, `count` defaults to 1). Charged after `cond` passed and before `cmd` / `url`; not enough -> `poor` message, nothing runs, nothing is taken | +| `poor` | message when the cost cannot be paid, default `You can't afford that.` (no double quotes) | | `close` | `1b` = close the menu after the command | | `timer` | reset the menu timeout to N ticks on a successful click | -| `locked_item` | what is drawn while `cond` fails (default `minecraft:barrier`). Cosmetic: the click re-checks `cond` | +| `locked_item` | what is drawn while `cond` fails **or the cost is not affordable** (default `minecraft:barrier`). Cosmetic: the click re-checks both | Notes: - `cmd` is macro-expanded raw. If it contains double quotes, write it as a single-quoted SNBT string: `cmd:'tellraw @s {"text":"hi"}'`. - `cmd` runs with the permission level datapack functions get (`function-permission-level`, default 2), not the player's. **`cmd` / `url` must come from your menu code, never from player input** (command injection). +- An item `cost` first removes the widget items from the inventory (the clicked widget is still there while the + click is handled), so a button that costs its own item type neither counts nor takes the widget instead of your + items. The look check (`locked_item`) uses the same rule as the `item_count` condition. Score cost = `pay_score`, + item cost = `pay_item`. - A working example is on page 2 of `examples/guikit-demo` (`demo:apple`, `demo:coin`, - `demo:sword`, `demo:vip`, `demo:link`). `/function demo:open`, then navigate to page 2. + `demo:sword`, `demo:vip`, `demo:lvl`, `demo:combo` = `all` condition + score cost, `demo:link`). `/function demo:open`, then navigate to page 2. ## Widget: single-select (`guikit:widget/radio`) Generalizes `toggle` from a bool to N states: each option in the group calls it with its own @@ -260,6 +287,11 @@ execute unless function guikit:widget/cooldown_start run function guikit:interna client: `experience query @s levels` storing into a score, `playsound ... ui @s` argument order, the `execute unless function ...` form used in the `cd_notify` example, and the `on_close` firing on menu switch described above. +- **`all` / `any` conditions, button `cost` / `poor`, the `guikit.drop` detection branch in `tick_player`, chest boats / + rafts and the hopper `follow` are new and untested beyond `mecha .`** (all 83 macro lines in the pack were also + expanded with sample values and linted). Not checked in a real client: the `comp_step` recursion, the `cnd` scratch + storage, `cost` charging order (cond -> cost -> cmd), whether a boat can be ridden while the menu is open, and + whether the `minecraft.custom:minecraft.drop` statistic reacts to Q-dropping a widget out of the cart. - **Still not done:** behavior in a real game (`clear` + `custom_data` match, `summon`, tick ordering, multiplayer). Only the load step has been observed. - **The container registry (`internal/containers_builtin`, `summon`, `pad_cart_dyn`, `open_fail`), the `radio`/`meter` diff --git a/packs/guikit-datapack/data/guikit/function/api/open.mcfunction b/packs/guikit-datapack/data/guikit/function/api/open.mcfunction index 5d9f95ca..d5b1895b 100644 --- a/packs/guikit-datapack/data/guikit/function/api/open.mcfunction +++ b/packs/guikit-datapack/data/guikit/function/api/open.mcfunction @@ -30,6 +30,8 @@ scoreboard players operation @e[type=#guikit:container,tag=guikit.new,distance=. tag @e[type=#guikit:container,tag=guikit.new,distance=..1] remove guikit.new # state +# guikit.drop is the vanilla drop statistic: it also counts drops made while no menu was open, so start clean +scoreboard players set @s guikit.drop 0 execute store result score @s guikit.page run data get storage guikit:in page execute store result score @s guikit.timer run data get storage guikit:in timer data modify storage guikit:ctx menu set from storage guikit:in menu diff --git a/packs/guikit-datapack/data/guikit/function/cond/check.mcfunction b/packs/guikit-datapack/data/guikit/function/cond/check.mcfunction index 0d053f7f..94afad0b 100644 --- a/packs/guikit-datapack/data/guikit/function/cond/check.mcfunction +++ b/packs/guikit-datapack/data/guikit/function/cond/check.mcfunction @@ -9,6 +9,8 @@ # advancement {adv:"minecraft:story/root"} # predicate {pred:"ns:name"} # level {[min:N], [max:N]} XP level (not a scoreboard); both optional +# all / any {of:[{type:..}, {type:..}]} every / at least one element passes. Elements must be +# leaf types above (a nested all/any counts as failed) # `not:1b` inverts the result. Unknown type / missing key = fails (closed). # # function guikit:internal/clear_cond @@ -18,6 +20,8 @@ # # One small function per type (no big execute chains), same as the rest of the pack. scoreboard players set #cond guikit.tmp 0 +execute if data storage guikit:cond {type:"all"} run return run function guikit:cond/t_all +execute if data storage guikit:cond {type:"any"} run return run function guikit:cond/t_any execute if data storage guikit:cond {type:"score"} run function guikit:cond/t_score execute if data storage guikit:cond {type:"item_count"} run function guikit:cond/t_item_count execute if data storage guikit:cond {type:"tag"} if data storage guikit:cond tag run function guikit:cond/t_tag with storage guikit:cond diff --git a/packs/guikit-datapack/data/guikit/function/cond/comp_pick.mcfunction b/packs/guikit-datapack/data/guikit/function/cond/comp_pick.mcfunction new file mode 100644 index 00000000..f8a3efbd --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/cond/comp_pick.mcfunction @@ -0,0 +1,3 @@ +# macro: $(i) +data remove storage guikit:cnd cur +$data modify storage guikit:cnd cur set from storage guikit:cnd items[$(i)] diff --git a/packs/guikit-datapack/data/guikit/function/cond/comp_run.mcfunction b/packs/guikit-datapack/data/guikit/function/cond/comp_run.mcfunction new file mode 100644 index 00000000..19408aff --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/cond/comp_run.mcfunction @@ -0,0 +1,17 @@ +# guikit :: cond/comp_run as player #cmode 0 = all / 1 = any, #cacc = starting value +# Walks the list guikit:cond of, loading each element into guikit:cond and running cond/check on it. +# One level only: an element that is itself all/any is not evaluated and counts as FAILED. A missing +# `of` fails (return 0, `not` is not applied). Result in #cond guikit.tmp, also returned. +execute store success score #cnot guikit.tmp if data storage guikit:cond {not:1b} +data remove storage guikit:cnd items +data modify storage guikit:cnd items set from storage guikit:cond of +execute unless data storage guikit:cnd items run return 0 +execute store result score #cn guikit.tmp run data get storage guikit:cnd items +scoreboard players set #ci guikit.tmp 0 +function guikit:cond/comp_step +scoreboard players operation #cond guikit.tmp = #cacc guikit.tmp +execute if score #cnot guikit.tmp matches 1 run function guikit:cond/negate +data remove storage guikit:cnd items +data remove storage guikit:cnd cur +function guikit:internal/clear_cond +return run scoreboard players get #cond guikit.tmp diff --git a/packs/guikit-datapack/data/guikit/function/cond/comp_step.mcfunction b/packs/guikit-datapack/data/guikit/function/cond/comp_step.mcfunction new file mode 100644 index 00000000..9e2d1af7 --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/cond/comp_step.mcfunction @@ -0,0 +1,15 @@ +# guikit :: cond/comp_step as player one element per call, recurses until the list is done or the result is decided +execute unless score #ci guikit.tmp < #cn guikit.tmp run return 0 +execute store result storage guikit:cnd i int 1 run scoreboard players get #ci guikit.tmp +function guikit:cond/comp_pick with storage guikit:cnd +function guikit:internal/clear_cond +function guikit:cond/load_cur +scoreboard players set #cond guikit.tmp 0 +execute unless data storage guikit:cond {type:"all"} unless data storage guikit:cond {type:"any"} run function guikit:cond/check +execute if score #cmode guikit.tmp matches 0 if score #cond guikit.tmp matches 0 run scoreboard players set #cacc guikit.tmp 0 +execute if score #cmode guikit.tmp matches 1 if score #cond guikit.tmp matches 1 run scoreboard players set #cacc guikit.tmp 1 +scoreboard players add #ci guikit.tmp 1 +# decided already: all stops at the first failure, any at the first pass +execute if score #cmode guikit.tmp matches 0 if score #cacc guikit.tmp matches 0 run return 0 +execute if score #cmode guikit.tmp matches 1 if score #cacc guikit.tmp matches 1 run return 0 +function guikit:cond/comp_step diff --git a/packs/guikit-datapack/data/guikit/function/cond/load_cur.mcfunction b/packs/guikit-datapack/data/guikit/function/cond/load_cur.mcfunction new file mode 100644 index 00000000..e9e50c70 --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/cond/load_cur.mcfunction @@ -0,0 +1,14 @@ +# guikit :: cond/load_cur copies the condition compound in storage guikit:cnd cur into guikit:cond, key by key +# (a root-level `data modify storage X {} set from ...` is avoided on purpose, see README "Validation status"). +# Call internal/clear_cond first. Keep this list in sync with internal/clear_cond. +execute if data storage guikit:cnd cur.type run data modify storage guikit:cond type set from storage guikit:cnd cur.type +execute if data storage guikit:cnd cur.obj run data modify storage guikit:cond obj set from storage guikit:cnd cur.obj +execute if data storage guikit:cnd cur.min run data modify storage guikit:cond min set from storage guikit:cnd cur.min +execute if data storage guikit:cnd cur.max run data modify storage guikit:cond max set from storage guikit:cnd cur.max +execute if data storage guikit:cnd cur.item run data modify storage guikit:cond item set from storage guikit:cnd cur.item +execute if data storage guikit:cnd cur.tag run data modify storage guikit:cond tag set from storage guikit:cnd cur.tag +execute if data storage guikit:cnd cur.mode run data modify storage guikit:cond mode set from storage guikit:cnd cur.mode +execute if data storage guikit:cnd cur.adv run data modify storage guikit:cond adv set from storage guikit:cnd cur.adv +execute if data storage guikit:cnd cur.pred run data modify storage guikit:cond pred set from storage guikit:cnd cur.pred +execute if data storage guikit:cnd cur.not run data modify storage guikit:cond not set from storage guikit:cnd cur.not +execute if data storage guikit:cnd cur.of run data modify storage guikit:cond of set from storage guikit:cnd cur.of diff --git a/packs/guikit-datapack/data/guikit/function/cond/t_all.mcfunction b/packs/guikit-datapack/data/guikit/function/cond/t_all.mcfunction new file mode 100644 index 00000000..918a518f --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/cond/t_all.mcfunction @@ -0,0 +1,5 @@ +# guikit :: cond/t_all storage guikit:cond {type:"all", of:[{...}, ...], [not]} +# Passes when EVERY element passes (empty list = passes). See cond/comp_run. +scoreboard players set #cmode guikit.tmp 0 +scoreboard players set #cacc guikit.tmp 1 +return run function guikit:cond/comp_run diff --git a/packs/guikit-datapack/data/guikit/function/cond/t_any.mcfunction b/packs/guikit-datapack/data/guikit/function/cond/t_any.mcfunction new file mode 100644 index 00000000..f15abb43 --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/cond/t_any.mcfunction @@ -0,0 +1,5 @@ +# guikit :: cond/t_any storage guikit:cond {type:"any", of:[{...}, ...], [not]} +# Passes when AT LEAST ONE element passes (empty list = fails). See cond/comp_run. +scoreboard players set #cmode guikit.tmp 1 +scoreboard players set #cacc guikit.tmp 0 +return run function guikit:cond/comp_run diff --git a/packs/guikit-datapack/data/guikit/function/internal/btn_afford.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/btn_afford.mcfunction new file mode 100644 index 00000000..ffadb9ea --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/internal/btn_afford.mcfunction @@ -0,0 +1,8 @@ +# guikit :: internal/btn_afford as player reads storage guikit:btn cur.cost +# cost:{obj:"coins", amount:5} score cost +# cost:{item:"minecraft:diamond", [count:3]} item cost (count defaults to 1) +# Result in #cond guikit.tmp (1 = enough). Does not charge. +scoreboard players set #cond guikit.tmp 1 +execute unless data storage guikit:btn cur.cost.count run data modify storage guikit:btn cur.cost.count set value 1 +execute if data storage guikit:btn cur.cost.obj run function guikit:internal/btn_afford_score with storage guikit:btn cur.cost +execute if data storage guikit:btn cur.cost.item run function guikit:internal/btn_afford_item diff --git a/packs/guikit-datapack/data/guikit/function/internal/btn_afford_item.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/btn_afford_item.mcfunction new file mode 100644 index 00000000..456d645f --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/internal/btn_afford_item.mcfunction @@ -0,0 +1,8 @@ +# guikit :: internal/btn_afford_item as player +# Reuses the item_count condition, which does not count the clicked widget item (see cond/t_item_count_do). +scoreboard players set #cond guikit.tmp 0 +function guikit:internal/clear_cond +data modify storage guikit:cond item set from storage guikit:btn cur.cost.item +data modify storage guikit:cond min set from storage guikit:btn cur.cost.count +function guikit:cond/t_item_count_do with storage guikit:cond +function guikit:internal/clear_cond diff --git a/packs/guikit-datapack/data/guikit/function/internal/btn_afford_score.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/btn_afford_score.mcfunction new file mode 100644 index 00000000..e5202a93 --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/internal/btn_afford_score.mcfunction @@ -0,0 +1,2 @@ +# macro: $(obj) $(amount) as player +$execute unless score @s $(obj) matches $(amount).. run scoreboard players set #cond guikit.tmp 0 diff --git a/packs/guikit-datapack/data/guikit/function/internal/btn_click.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/btn_click.mcfunction index 82059fbd..8fd86dda 100644 --- a/packs/guikit-datapack/data/guikit/function/internal/btn_click.mcfunction +++ b/packs/guikit-datapack/data/guikit/function/internal/btn_click.mcfunction @@ -4,9 +4,12 @@ # url:"https://.." prints a clickable link in chat instead (use close:1b so the player can see chat) # cond:{...} any guikit:cond type, see cond/check. Fails -> `deny` message, nothing runs # deny:"..." message when cond fails (no double quotes). Default "Not available." +# cost:{...} {obj:"coins", amount:5} or {item:"minecraft:diamond", [count:3]}; charged after cond passes, +# before cmd/url. Not enough -> `poor` message, nothing runs, nothing is taken +# poor:"..." message when the cost cannot be paid (no double quotes). Default "You can't afford that." # close:1b close the menu after the command # timer:N reset the menu timeout to N ticks on a successful click -# locked_item:"minecraft:barrier" look when cond fails (widget/button) +# locked_item:"minecraft:barrier" look when cond fails or the cost is not affordable (widget/button) data remove storage guikit:btn cur $data modify storage guikit:btn cur set from storage guikit:btn defs."$(id)" execute unless data storage guikit:btn cur run return 0 @@ -14,6 +17,11 @@ execute unless data storage guikit:btn cur run return 0 function guikit:internal/btn_cond execute if score #cond guikit.tmp matches 0 run return run function guikit:internal/btn_deny +# cost: charged only now (cond passed), before the command runs +scoreboard players set #paid guikit.tmp 1 +execute if data storage guikit:btn cur.cost run function guikit:internal/btn_pay +execute if score #paid guikit.tmp matches 0 run return run function guikit:internal/btn_poor + # decide now: the command may overwrite guikit:btn cur (e.g. by running another button) execute store success score #btn_close guikit.tmp if data storage guikit:btn cur{close:1b} execute if data storage guikit:btn cur.timer run function guikit:internal/btn_timer with storage guikit:btn cur diff --git a/packs/guikit-datapack/data/guikit/function/internal/btn_cond.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/btn_cond.mcfunction index 7521bdb1..c1a25cf3 100644 --- a/packs/guikit-datapack/data/guikit/function/internal/btn_cond.mcfunction +++ b/packs/guikit-datapack/data/guikit/function/internal/btn_cond.mcfunction @@ -1,18 +1,9 @@ # guikit :: internal/btn_cond as player reads storage guikit:btn cur.cond # Result: #cond guikit.tmp = 1 when the button has no condition or it passes, else 0. -# Copies key by key into guikit:cond (a root-level `data modify ... set from` is avoided on purpose, -# see README "Validation status"). Keep this list in sync with internal/clear_cond. scoreboard players set #cond guikit.tmp 1 execute unless data storage guikit:btn cur.cond run return 1 function guikit:internal/clear_cond -execute if data storage guikit:btn cur.cond.type run data modify storage guikit:cond type set from storage guikit:btn cur.cond.type -execute if data storage guikit:btn cur.cond.obj run data modify storage guikit:cond obj set from storage guikit:btn cur.cond.obj -execute if data storage guikit:btn cur.cond.min run data modify storage guikit:cond min set from storage guikit:btn cur.cond.min -execute if data storage guikit:btn cur.cond.max run data modify storage guikit:cond max set from storage guikit:btn cur.cond.max -execute if data storage guikit:btn cur.cond.item run data modify storage guikit:cond item set from storage guikit:btn cur.cond.item -execute if data storage guikit:btn cur.cond.tag run data modify storage guikit:cond tag set from storage guikit:btn cur.cond.tag -execute if data storage guikit:btn cur.cond.mode run data modify storage guikit:cond mode set from storage guikit:btn cur.cond.mode -execute if data storage guikit:btn cur.cond.adv run data modify storage guikit:cond adv set from storage guikit:btn cur.cond.adv -execute if data storage guikit:btn cur.cond.pred run data modify storage guikit:cond pred set from storage guikit:btn cur.cond.pred -execute if data storage guikit:btn cur.cond.not run data modify storage guikit:cond not set from storage guikit:btn cur.cond.not +data remove storage guikit:cnd cur +data modify storage guikit:cnd cur set from storage guikit:btn cur.cond +function guikit:cond/load_cur function guikit:cond/check diff --git a/packs/guikit-datapack/data/guikit/function/internal/btn_gate.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/btn_gate.mcfunction new file mode 100644 index 00000000..2ee7dbf2 --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/internal/btn_gate.mcfunction @@ -0,0 +1,6 @@ +# guikit :: internal/btn_gate as player reads storage guikit:btn cur +# Result: #cond guikit.tmp = 1 when the button's cond passes AND its cost is affordable, else 0. +# Nothing is charged here (used when drawing, to decide the locked look). +function guikit:internal/btn_cond +execute if score #cond guikit.tmp matches 0 run return 0 +execute if data storage guikit:btn cur.cost run function guikit:internal/btn_afford diff --git a/packs/guikit-datapack/data/guikit/function/internal/btn_pay.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/btn_pay.mcfunction new file mode 100644 index 00000000..266b7568 --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/internal/btn_pay.mcfunction @@ -0,0 +1,5 @@ +# guikit :: internal/btn_pay as player reads storage guikit:btn cur.cost +# Charges the cost through the existing helpers. Result in #paid guikit.tmp (1 = paid, 0 = not enough). +execute unless data storage guikit:btn cur.cost.count run data modify storage guikit:btn cur.cost.count set value 1 +execute if data storage guikit:btn cur.cost.obj run function guikit:internal/pay_score with storage guikit:btn cur.cost +execute if data storage guikit:btn cur.cost.item run function guikit:internal/btn_pay_item diff --git a/packs/guikit-datapack/data/guikit/function/internal/btn_pay_item.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/btn_pay_item.mcfunction new file mode 100644 index 00000000..346965a6 --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/internal/btn_pay_item.mcfunction @@ -0,0 +1,5 @@ +# guikit :: internal/btn_pay_item as player +# The clicked widget is still in the inventory here. Remove widget items first so pay_item can neither +# count it nor clear it instead of the player's real items (a button that costs its own item type). +function guikit:internal/safe_clear +function guikit:internal/pay_item with storage guikit:btn cur.cost diff --git a/packs/guikit-datapack/data/guikit/function/internal/btn_poor.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/btn_poor.mcfunction new file mode 100644 index 00000000..504b1452 --- /dev/null +++ b/packs/guikit-datapack/data/guikit/function/internal/btn_poor.mcfunction @@ -0,0 +1,6 @@ +# guikit :: internal/btn_poor as player reads storage guikit:btn cur.poor +function guikit:internal/clear_in +data modify storage guikit:in msg set value "You can't afford that." +execute if data storage guikit:btn cur.poor run data modify storage guikit:in msg set from storage guikit:btn cur.poor +data modify storage guikit:in color set value "red" +function guikit:widget/say diff --git a/packs/guikit-datapack/data/guikit/function/internal/btn_visual.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/btn_visual.mcfunction index 288d4916..45378f1a 100644 --- a/packs/guikit-datapack/data/guikit/function/internal/btn_visual.mcfunction +++ b/packs/guikit-datapack/data/guikit/function/internal/btn_visual.mcfunction @@ -2,8 +2,8 @@ # Swaps guikit:w item for the definition's locked_item when its cond currently fails. data remove storage guikit:btn cur $data modify storage guikit:btn cur set from storage guikit:btn defs."$(id)" -execute unless data storage guikit:btn cur.cond run return 0 -function guikit:internal/btn_cond +execute unless data storage guikit:btn cur.cond unless data storage guikit:btn cur.cost run return 0 +function guikit:internal/btn_gate execute if score #cond guikit.tmp matches 1 run return 0 data modify storage guikit:w item set value "minecraft:barrier" execute if data storage guikit:btn cur.locked_item run data modify storage guikit:w item set from storage guikit:btn cur.locked_item diff --git a/packs/guikit-datapack/data/guikit/function/internal/cleanup_scores.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/cleanup_scores.mcfunction index 8be9cf76..5f2627fc 100644 --- a/packs/guikit-datapack/data/guikit/function/internal/cleanup_scores.mcfunction +++ b/packs/guikit-datapack/data/guikit/function/internal/cleanup_scores.mcfunction @@ -24,5 +24,11 @@ scoreboard players reset #mhit guikit.tmp scoreboard players reset #lvl guikit.tmp scoreboard players reset #cdleft guikit.tmp scoreboard players reset #pi guikit.tmp +# composite conditions (cond/comp_run, comp_step) +scoreboard players reset #cmode guikit.tmp +scoreboard players reset #cacc guikit.tmp +scoreboard players reset #cn guikit.tmp +scoreboard players reset #ci guikit.tmp +scoreboard players reset #cnot guikit.tmp scoreboard players reset #cd20 guikit.tmp scoreboard players set #ok guikit.const 0 diff --git a/packs/guikit-datapack/data/guikit/function/internal/clear_cond.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/clear_cond.mcfunction index d0252c59..7e118978 100644 --- a/packs/guikit-datapack/data/guikit/function/internal/clear_cond.mcfunction +++ b/packs/guikit-datapack/data/guikit/function/internal/clear_cond.mcfunction @@ -8,6 +8,7 @@ data remove storage guikit:cond min data remove storage guikit:cond mode data remove storage guikit:cond not data remove storage guikit:cond obj +data remove storage guikit:cond of data remove storage guikit:cond pred data remove storage guikit:cond tag data remove storage guikit:cond type diff --git a/packs/guikit-datapack/data/guikit/function/internal/clear_tmp.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/clear_tmp.mcfunction index 6f85207e..d4aea779 100644 --- a/packs/guikit-datapack/data/guikit/function/internal/clear_tmp.mcfunction +++ b/packs/guikit-datapack/data/guikit/function/internal/clear_tmp.mcfunction @@ -11,4 +11,7 @@ data remove storage guikit:ctx cdef data remove storage guikit:ctx uid data remove storage guikit:ctx pad data remove storage guikit:ctx i +data remove storage guikit:cnd items +data remove storage guikit:cnd cur +data remove storage guikit:cnd i data remove storage guikit:p id diff --git a/packs/guikit-datapack/data/guikit/function/internal/containers_builtin.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/containers_builtin.mcfunction index 40e5d13d..ebf90ee4 100644 --- a/packs/guikit-datapack/data/guikit/function/internal/containers_builtin.mcfunction +++ b/packs/guikit-datapack/data/guikit/function/internal/containers_builtin.mcfunction @@ -4,14 +4,12 @@ # slots inventory size (27 chest_minecart/chest_boat, 5 hopper_minecart, 15 donkey/mule) default 27 # pad item id used by widget/pad to fill every slot default minecraft:gray_stained_glass_pane # title optional SNBT text component shown as the container title, e.g. {text:"Barrel"} -# offset first real inventory Slot index for `item replace entity @s container.N`; -# chest_minecart/chest_boat/hopper_minecart are 0. NOT set below for donkey/mule: -# their Items[] is reported (minecraft.wiki) as Slot 2..16 (saddle=0, chest-flag=1), -# but the container.N selector's mapping onto that offset is UNCONFIRMED against a -# live 26.3 client -- see README "Validation status". Until tested, donkey/mule stay -# OUT of data/guikit/tags/entity_type/container.json, so open() can register them by -# name but internal/open_check should reject them (see open_check TODO) rather than -# summon something the framework can't draw into correctly. +# (there is NO `offset` key: every entity used so far addresses its slots as container.0 .. container.slots-1.) +# donkey/mule are registered for later but are deliberately NOT in data/guikit/tags/entity_type/container.json: +# their Items[] is reported (minecraft.wiki) as Slot 2..16 (saddle=0, chest-flag=1) and how `container.N` maps +# onto that is unconfirmed against a live 26.3 client (README "Validation status"). Because they are outside the +# tag, api/open refuses them through internal/open_fail. Supporting them would need an offset in pad_slot and +# widget/draw_on_cart. # Menu packs add or replace entries from #guikit:register (this runs first, so they win). # Every "themed" chest/barrel/etc preset is still a chest_minecart underneath: only entities can # be summoned and filled with `item replace entity`, and Minecraft has no ender chest / barrel @@ -40,8 +38,7 @@ data modify storage guikit:reg containers.mangrove_chest_boat set value {entity: data modify storage guikit:reg containers.cherry_chest_boat set value {entity:"cherry_chest_boat", slots:27, pad:"minecraft:gray_stained_glass_pane"} data modify storage guikit:reg containers.bamboo_chest_raft set value {entity:"bamboo_chest_raft", slots:27, pad:"minecraft:gray_stained_glass_pane"} -# donkey/mule: registered for forward-compat but see the offset TODO above -- deliberately not -# in #guikit:container yet, so api/open must refuse them (internal/open_check TODO) until the -# container.N offset is confirmed live. +# donkey/mule: registered for later, see the note above: not in #guikit:container, so api/open +# refuses them (internal/open_fail) until the container.N mapping is confirmed live. data modify storage guikit:reg containers.donkey set value {entity:"donkey", slots:15, pad:"minecraft:gray_stained_glass_pane"} data modify storage guikit:reg containers.mule set value {entity:"mule", slots:15, pad:"minecraft:gray_stained_glass_pane"} diff --git a/packs/guikit-datapack/data/guikit/function/internal/follow.mcfunction b/packs/guikit-datapack/data/guikit/function/internal/follow.mcfunction index 57d54c8e..2dbfbb49 100644 --- a/packs/guikit-datapack/data/guikit/function/internal/follow.mcfunction +++ b/packs/guikit-datapack/data/guikit/function/internal/follow.mcfunction @@ -2,4 +2,7 @@ # Position context: tick_player runs `at @s` (the player). `execute as ` does NOT # change the position, so `tp @s ~ ~ ~` moves the cart exactly onto its owner. scoreboard players set #found guikit.tmp 1 +# Minecarts follow their owner. Boats/rafts are NOT teleported: the owner rides them (see README +# "Container types", `ride @s mount ...`), teleporting a boat with its rider in every tick fights the ride. tp @s[type=minecraft:chest_minecart] ~ ~1 ~ +tp @s[type=minecraft:hopper_minecart] ~ ~1 ~ diff --git a/packs/guikit-datapack/examples/guikit-demo/data/demo/function/click/open_chest_boat.mcfunction b/packs/guikit-datapack/examples/guikit-demo/data/demo/function/click/open_chest_boat.mcfunction new file mode 100644 index 00000000..962ef365 --- /dev/null +++ b/packs/guikit-datapack/examples/guikit-demo/data/demo/function/click/open_chest_boat.mcfunction @@ -0,0 +1,9 @@ +# api/open already closes the current menu first (see api/open.mcfunction), so no manual close. +function guikit:internal/clear_in +data merge storage guikit:in {menu:"demo:chest_boat_demo", page:0, timer:600} +function guikit:api/open +# mount THIS player's cart only (matching uid), not merely the nearest one -- another player's boat may be closer +scoreboard players operation #uid guikit.tmp = @s guikit.uid +execute as @e[type=#guikit:container,tag=guikit.cart,distance=..3] if score @s guikit.uid = #uid guikit.tmp run tag @s add demo.mount +ride @s mount @e[type=#guikit:container,tag=demo.mount,limit=1] +tag @e[tag=demo.mount] remove demo.mount diff --git a/packs/guikit-datapack/examples/guikit-demo/data/demo/function/main/page2.mcfunction b/packs/guikit-datapack/examples/guikit-demo/data/demo/function/main/page2.mcfunction new file mode 100644 index 00000000..ff821fe8 --- /dev/null +++ b/packs/guikit-datapack/examples/guikit-demo/data/demo/function/main/page2.mcfunction @@ -0,0 +1,83 @@ +# demo :: page 2 -- command buttons (former cmd-demo), radio, meter, links to themed containers + +# --- command buttons (slots 10..14), defs registered in demo:register +function guikit:internal/clear_w +data merge storage guikit:w {slot:10, item:"minecraft:apple", id:"demo:apple", name:{text:"Free apple",color:"green",italic:false}, lore:[]} +function guikit:widget/button +function guikit:internal/clear_w +data merge storage guikit:w {slot:11, item:"minecraft:gold_nugget", id:"demo:coin", name:{text:"+1 coin",color:"yellow",italic:false}, lore:[]} +function guikit:widget/button +function guikit:internal/clear_w +data merge storage guikit:w {slot:22, item:"minecraft:diamond", id:"demo:combo", name:{text:"Diamond (VIP)",color:"aqua",italic:false}, lore:[{text:"Needs tag vip AND XP level 1, costs 3 coins",color:"gray",italic:false}]} +function guikit:widget/button + +function guikit:internal/clear_w +data merge storage guikit:w {slot:12, item:"minecraft:iron_sword", id:"demo:sword", name:{text:"Buy sword",color:"aqua",italic:false}, lore:[{text:"Costs 5 coins (score demo.coins)",color:"gray",italic:false}]} +function guikit:widget/button +function guikit:internal/clear_w +data merge storage guikit:w {slot:13, item:"minecraft:nether_star", id:"demo:vip", name:{text:"VIP only",color:"gold",italic:false}, lore:[{text:"Needs tag vip",color:"gray",italic:false}]} +function guikit:widget/button +function guikit:internal/clear_w +data merge storage guikit:w {slot:14, item:"minecraft:writable_book", id:"demo:link", name:{text:"Open repo link",color:"white",italic:false}, lore:[]} +function guikit:widget/button + +# level-gated button (slot 15): cond type "level", needs XP level 5 +function guikit:internal/clear_w +data merge storage guikit:w {slot:15, item:"minecraft:experience_bottle", id:"demo:lvl", name:{text:"Level 5 only",color:"green",italic:false}, lore:[{text:"Needs XP level 5",color:"gray",italic:false}]} +function guikit:widget/button + +# --- radio (slots 19,20,21): difficulty, direct-assign, unlike cycle's auto-increment on page 0 +execute unless score @s demo.difficulty matches 0.. run scoreboard players set @s demo.difficulty 0 +function guikit:internal/clear_w +data modify storage guikit:w item set value "minecraft:wooden_sword" +data modify storage guikit:w name set value '{"text":"Easy","italic":false}' +execute if score @s demo.difficulty matches 0 run data modify storage guikit:w item set value "minecraft:lime_dye" +execute if score @s demo.difficulty matches 0 run data modify storage guikit:w name set value '{"text":"[x] Easy","color":"green","italic":false}' +data merge storage guikit:w {slot:19, id:"diff_easy", type:"radio", lore:[]} +function guikit:widget/draw +function guikit:internal/clear_w +data modify storage guikit:w item set value "minecraft:iron_sword" +data modify storage guikit:w name set value '{"text":"Normal","italic":false}' +execute if score @s demo.difficulty matches 1 run data modify storage guikit:w item set value "minecraft:lime_dye" +execute if score @s demo.difficulty matches 1 run data modify storage guikit:w name set value '{"text":"[x] Normal","color":"yellow","italic":false}' +data merge storage guikit:w {slot:20, id:"diff_normal", type:"radio", lore:[]} +function guikit:widget/draw +function guikit:internal/clear_w +data modify storage guikit:w item set value "minecraft:netherite_sword" +data modify storage guikit:w name set value '{"text":"Hard","italic":false}' +execute if score @s demo.difficulty matches 2 run data modify storage guikit:w item set value "minecraft:lime_dye" +execute if score @s demo.difficulty matches 2 run data modify storage guikit:w name set value '{"text":"[x] Hard","color":"red","italic":false}' +data merge storage guikit:w {slot:21, id:"diff_hard", type:"radio", lore:[]} +function guikit:widget/draw + +# --- meter (slots 4..8): rating 1..5, click a cell to jump straight to that value +execute unless score @s demo.rating matches 0.. run scoreboard players set @s demo.rating 3 +function guikit:internal/clear_w +data merge storage guikit:w {slot:4, id:"demo:rating"} +function guikit:widget/meter_draw with storage guikit:w + +# --- open a themed sub-menu (ender_chest / barrel, see README "Container types") +function guikit:internal/clear_w +data merge storage guikit:w {slot:24, item:"minecraft:ender_eye", id:"open_ender_chest", type:"nav", name:'{"text":"Open: Ender Chest theme","color":"light_purple","italic":false}', lore:'[]'} +function guikit:widget/draw +function guikit:internal/clear_w +data merge storage guikit:w {slot:25, item:"minecraft:barrel", id:"open_barrel", type:"nav", name:'{"text":"Open: Barrel theme","color":"gold","italic":false}', lore:'[]'} +function guikit:widget/draw + +function guikit:internal/clear_w +data merge storage guikit:w {slot:16, item:"minecraft:hopper", id:"open_hopper", type:"nav", name:{text:"Open: 5-slot hopper",color:"gray",italic:false}, lore:[]} +function guikit:widget/draw +function guikit:internal/clear_w +data merge storage guikit:w {slot:17, item:"minecraft:gold_ingot", id:"open_shop", type:"nav", name:{text:"Open: registered container",color:"aqua",italic:false}, lore:[]} +function guikit:widget/draw +function guikit:internal/clear_w +data merge storage guikit:w {slot:9, item:"minecraft:oak_boat", id:"open_chest_boat", type:"nav", name:{text:"Open: Oak Chest Boat",color:"aqua",italic:false}, lore:[]} +function guikit:widget/draw + +# --- nav back to page 1, close +function guikit:internal/clear_w +data merge storage guikit:w {slot:18, item:"minecraft:arrow", id:"to_page1", type:"nav", name:'{"text":"Back","color":"white","italic":false}', lore:'[]'} +function guikit:widget/draw +function guikit:internal/clear_w +data merge storage guikit:w {slot:26, item:"minecraft:barrier", id:"close", type:"close", name:'{"text":"Close","color":"red","italic":false}', lore:'[]'} +function guikit:widget/draw diff --git a/packs/guikit-datapack/examples/guikit-demo/data/demo/function/main/probe.mcfunction b/packs/guikit-datapack/examples/guikit-demo/data/demo/function/main/probe.mcfunction new file mode 100644 index 00000000..f7071574 --- /dev/null +++ b/packs/guikit-datapack/examples/guikit-demo/data/demo/function/main/probe.mcfunction @@ -0,0 +1,64 @@ +# demo :: main/probe (via demo:probe, as player). ONE line per clickable widget id; +# ONE pair per button (widget/button_probe); ONE line per meter (widget/meter_probe, not per cell). +data merge storage guikit:p {id:"buy_gem", fn:"demo:click/buy_gem"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"sound", fn:"demo:click/sound"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"volume_up", fn:"demo:click/volume_up"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"mode", fn:"demo:click/mode"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"prog_up", fn:"demo:click/prog_up"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"to_page1", fn:"demo:click/to_page1"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"to_page0", fn:"demo:click/to_page0"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"close", fn:"demo:click/close"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"lootbox", fn:"demo:click/lootbox"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"danger", fn:"demo:click/danger"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"to_page2", fn:"demo:click/to_page2"} +function guikit:widget/probe with storage guikit:p + +# --- page 2: command buttons (former cmd-demo) +data merge storage guikit:p {id:"demo:apple"} +function guikit:widget/button_probe with storage guikit:p +data merge storage guikit:p {id:"demo:coin"} +function guikit:widget/button_probe with storage guikit:p +data merge storage guikit:p {id:"demo:sword"} +function guikit:widget/button_probe with storage guikit:p +data merge storage guikit:p {id:"demo:vip"} +function guikit:widget/button_probe with storage guikit:p +data merge storage guikit:p {id:"demo:link"} +function guikit:widget/button_probe with storage guikit:p +data merge storage guikit:p {id:"demo:lvl"} +function guikit:widget/button_probe with storage guikit:p +data merge storage guikit:p {id:"demo:combo"} +function guikit:widget/button_probe with storage guikit:p + +# --- page 2: radio (difficulty, 3 options -- direct-assign, unlike cycle's auto-increment) +data merge storage guikit:p {id:"diff_easy", fn:"demo:click/diff_easy"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"diff_normal", fn:"demo:click/diff_normal"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"diff_hard", fn:"demo:click/diff_hard"} +function guikit:widget/probe with storage guikit:p + +# --- page 2: meter (rating, 5 clickable cells, ONE registration) +data merge storage guikit:p {id:"demo:rating"} +function guikit:widget/meter_probe with storage guikit:p + +# --- page 2: open a themed sub-menu +data merge storage guikit:p {id:"open_ender_chest", fn:"demo:click/open_ender_chest"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"open_barrel", fn:"demo:click/open_barrel"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"open_hopper", fn:"demo:click/open_hopper"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"open_shop", fn:"demo:click/open_shop"} +function guikit:widget/probe with storage guikit:p +data merge storage guikit:p {id:"open_chest_boat", fn:"demo:click/open_chest_boat"} +function guikit:widget/probe with storage guikit:p diff --git a/packs/guikit-datapack/examples/guikit-demo/data/demo/function/register.mcfunction b/packs/guikit-datapack/examples/guikit-demo/data/demo/function/register.mcfunction new file mode 100644 index 00000000..f3c94971 --- /dev/null +++ b/packs/guikit-datapack/examples/guikit-demo/data/demo/function/register.mcfunction @@ -0,0 +1,40 @@ +# demo :: register (called through #guikit:register on every load) +# A menu = { alias (tag-safe), container }. Everything else is code, not config. +# The main demo (chest_minecart) plus one small menu per container flavour, to actually show them +# summoned: ender chest / barrel presets, a 5-slot hopper, and a container registered right here. +data modify storage guikit:reg menus."demo:main" set value {alias:"demo_main", container:"chest_minecart"} +data modify storage guikit:reg menus."demo:ender_chest_demo" set value {alias:"demo_ender_chest", container:"ender_chest"} +data modify storage guikit:reg menus."demo:barrel_demo" set value {alias:"demo_barrel", container:"barrel"} +# oak_chest_boat: added alongside the existing ender_chest/barrel themed sub-menus, same pattern +data modify storage guikit:reg menus."demo:chest_boat_demo" set value {alias:"demo_chest_boat", container:"oak_chest_boat"} +# a container defined by this pack (see README "Container types"): built-ins are registered first, so this is additive +data modify storage guikit:reg containers.demo_shop set value {entity:"chest_minecart", slots:27, pad:"minecraft:cyan_stained_glass_pane", title:{text:"Demo Shop"}} +data modify storage guikit:reg menus."demo:shop_demo" set value {alias:"demo_shop", container:"demo_shop"} +# built-in 5-slot container +data modify storage guikit:reg menus."demo:hopper_demo" set value {alias:"demo_hopper", container:"hopper_minecart"} + +scoreboard objectives add demo.sound_on dummy +scoreboard objectives add demo.volume dummy +scoreboard objectives add demo.mode dummy +scoreboard objectives add demo.coins dummy +scoreboard objectives add demo.progress dummy +scoreboard objectives add demo.difficulty dummy +scoreboard objectives add demo.rating dummy + +# --- button definitions (formerly the separate cmd-demo pack, now page 2 of demo:main). +# plain command +data modify storage guikit:btn defs."demo:apple" set value {cmd:"give @s minecraft:apple 1", timer:1200} +data modify storage guikit:btn defs."demo:coin" set value {cmd:"scoreboard players add @s demo.coins 1", timer:1200} +# score condition, several commands through a function +data modify storage guikit:btn defs."demo:sword" set value {cmd:"function demo:internal/buy_sword", timer:1200, deny:"You need 5 coins.", cond:{type:"score", obj:"demo.coins", min:5}} +# tag condition, JSON inside the command -> single-quoted SNBT string +data modify storage guikit:btn defs."demo:vip" set value {cmd:'tellraw @s {"text":"Welcome, VIP!","color":"gold"}', timer:1200, deny:"VIP only. Try: /tag @s add vip", cond:{type:"tag", tag:"vip"}, locked_item:"minecraft:iron_bars"} +# XP level condition (cond type "level", see README "Conditions") +data modify storage guikit:btn defs."demo:lvl" set value {cmd:'tellraw @s {"text":"Level 5 reached!","color":"green"}', timer:1200, deny:"You need XP level 5.", cond:{type:"level", min:5}, locked_item:"minecraft:iron_bars"} +# composite condition (all of ...) + a score cost: charged only when every element passes, before cmd runs +data modify storage guikit:btn defs."demo:combo" set value {cmd:"give @s minecraft:diamond 1", timer:1200, cost:{obj:"demo.coins", amount:3}, poor:"You need 3 coins.", deny:"VIP with XP level 1+ only.", cond:{type:"all", of:[{type:"tag", tag:"vip"}, {type:"level", min:1}]}, locked_item:"minecraft:iron_bars"} +# link +data modify storage guikit:btn defs."demo:link" set value {url:"https://github.com/runtoolkit/guikit-datapack", close:1b} + +# --- meter definition (see README "Widget: clickable meter / rating bar") +data modify storage guikit:mtr defs."demo:rating" set value {obj:"demo.rating", width:5, max:5, full:"minecraft:lime_dye", empty:"minecraft:gray_dye", name:{text:" "}}