跳到正文

Gui Helper

作者:Hdi

Useful framework for mod developpers

收藏

介绍

中文介绍正在准备中,下面暂时显示原文。

Gui Helper

A Fabric 1.20.6 framework for building Minecraft GUIs from a single Gui object that holds every object and its data.

You describe a screen once, register it under an Identifier, and the server opens it by that id. Values come back the same way.


Quick start

// client — build and register
Gui shop = GuiRegistry.register(GuiHelper.id("shop"), new Gui()
        .setTitle(Text.literal("Shop"))
        .setBackground(new Texture(GuiHelper.id("textures/gui/shop.png"), 0, 0, 176, 166, 256, 256))
        .setDarkBackground(true));

shop.addObject(new TextObject("price", new TextWithDetail(Text.literal("0"), ColorHelper.WHITE, 0.5f),
        8, 20, 60, 10, Align.CENTER));

// server — open it
GuiNetwork.open(player, GuiHelper.id("shop"), new GuiData().set("price", 2000));

Every object takes a String id first. That id is the key for lookup, for server-sent data, and for values sent back — so it must be unique within a Gui (addObject throws otherwise).


Objects

All extend GuiObject. Coordinates are relative to the GUI’s top-left corner.

Object Purpose Value type
TextObject Text, with Align / VerticalAlign inside a box —
TextureObject A texture —
ItemRenderObject An ItemStack with count, optional vanilla item tooltip —
ModelItemRenderObject An item’s 3D model, spinning, with a fixed tilt —
EntityGuiObject A live entity, scaled to fit, optionally cursor-tracking —
ButtonObject Clickable, Runnable onPress —
ToggleObject On/off, two textures boolean
RadioButtonObject One group, exclusive options String
StepperObject Arrows and ticks to pick a step int
DropdownObject Vector-drawn expanding list, wheel or draggable indicator, optional search String
TextFieldObject Text input String
IntegerFieldObject / DecimalFieldObject Validated numeric input, optional setRange(min, max) String (getIntValue() / getNumber())
PercentFieldObject Decimal 0–100, drawn as 65 % String (getNumber())
TextAreaObject Multi-line text input String
BoxObject Container, clips and scrolls its children —
ScrollBarObject Bar owned by a BoxObject —
SlotGridObject Client proxy placing a server slot grid inside a BoxObject —

Shared by every object

object.setLabel(new TextWithDetail(Text.literal("Name"), 0.5f));   // drawn above, left-aligned
object.setTooltip(Text.literal("Line one"), Text.literal("Line two"));
object.setShowWhen(toggle::getValue);                              // re-evaluated every frame
object.setDisabledWhen(() -> !toggle.getValue());                  // 50% opacity, input blocked

setShowWhen / setDisabledWhen return GuiObject, so call them last in a chain.

Dropdown search

dropdown.setSearchable(true).setSearchPlaceholder(Text.literal("Search..."));

A search row filters options by label (case-insensitive contains); Enter picks the first match. Cleared on close.

Reading values

gui.getObject("sound", ToggleObject.class).getValue();
gui.collectValues();   // GuiData of every stateful object, boxes included

getObject recurses into boxes.


State

Values live on the object, not the widget, which decides when they reset:

Event Result
Window resize Preserved — widgets rebuild and re-read the object
Reopening the GUI Reset to defaults

A Gui is a singleton once registered, so resetState() runs from the GuiRenderer constructor — one per screen instance, not per init(). Set your own baseline with setDefaultValue(...).


Data flow

GuiData is a String -> String map with typed accessors, used in both directions.

// server -> client, on open
GuiNetwork.open(player, id, new GuiData().set("price", 2000).set("sound", true));

// client -> server, on demand
ClientPlayNetworking.send(new GuiValuesPayload(id, gui.collectValues()));

An object picks up the entry matching its own id via applyData, and writes it back via collectData. ItemRenderObject and ModelItemRenderObject also read <id>.count.

Defaults are applied first, then server data — so an id absent from the payload leaves the default alone.

Receiving values

GuiValuesRegistry.register(GuiHelper.id("shop"), (player, values) -> {
    // runs on the server thread
});

The receiver rejects a payload unless the player has that GUI open (GuiSessions) and a listener is registered. The wire format is capped at 64 entries, 64-char keys, 256-char values.

GuiData is untrusted. The server cannot validate ids or types — Gui is client-only — so re-check everything against server state.


Handler GUIs (inventories)

Slots are the sync protocol: index, order and count must match on both sides. So the layout is common (src/main) and the look is client (src/client), keyed by the same Identifier.

// common — onInitialize, both sides
GuiHandlerRegistry.register(GuiHelper.id("forge"), new GuiHandler()
        .setTitle(Text.literal("Forge"))
        .addSlotGrid("input", 0, 8, 18, 3, 3)     // idPrefix, startIndex, x, y, columns, rows
        .addSlot(new SlotObject("output", 9, 120, 35))
        .setPlayerInventory(8, 84));

// client — a Gui under the same id
GuiRegistry.register(GuiHelper.id("forge"), buildForgeGui());

// server
GuiNetwork.openHandler(player, GuiHelper.id("forge"), data, inventory);

getInventorySize() is derived from the highest slot index, so size is never declared twice. To decorate slots, read their positions back rather than repeating them:

for (SlotObject slot : GuiHandlerRegistry.get(id).getSlots()) {
    gui.addObject(new TextureObject(slot.getId(), Textures.TEXTURE_SLOT,
            slot.getObjectStartX() - 1, slot.getObjectStartY() - 1));
}

Slots inside a box

// common: the grid's coordinates only define its shape
new GuiHandler().addSlotGrid("storage", 9, 0, 0, 3, 6);

// client: id = the grid prefix
box.addObject(new SlotGridObject("storage", GuiHelper.id("forge"), 0, 0));

The server keeps the slots and the sync; the client places them. Scrolling is smooth — partly visible slots are clipped and only their visible part takes hover and clicks (HandledScreenMixin + an access widener making Slot.x/y mutable). box.setScrollSnap(18) scrolls row by row instead.

One ExtendedScreenHandlerType<CustomScreenHandler, GuiOpenData> carries the id and data in the vanilla open packet, so handlers can be registered at any time.


Textures

new Texture(id, drawStartX, drawStartY, drawSizeX, drawSizeY, textureSizeX, textureSizeY)

drawStart + drawSize select a region of a sheet; textureSize is the file’s dimensions. The region stretches to whatever size the object declares.

Nine-slice keeps corners crisp at any size — it works on sub-regions, unlike vanilla’s GUI sprite atlas:

new Texture(...).setNineSlice(3);                 // all sides
new Texture(...).setNineSlice(6, 3, 6, 3);        // left, top, right, bottom

Scaling

gui.setSizeMultiplicator(2) renders everything twice as big. Mouse coordinates are divided to match, and slot hit-testing follows. Tooltips stay at normal size at the real cursor.


Overlays

A DropdownObject‘s open list floats above everything and takes input first — clicks, wheel and ESC — so a widget underneath can’t steal a click or show its tooltip. Implement OverlayRenderer for anything else that needs to escape draw order and clipping; BoxWidget forwards all five members with its scroll offset, so overlays work inside boxes.


Debug

GuiHelper.DEBUG follows FabricLoader.isDevelopmentEnvironment(), so these exist under runClient and not in a built jar:

Command Opens
/testGui [id] a registered Gui as a plain screen (default debug)
/testHandler [id] a registered GuiHandler (default debug_handler, tab-completes)

Known limits

  • A registered Gui is a shared instance — one screen at a time on the client, which is fine, but it is not re-entrant.
  • SlotObject.backgroundSprite goes through GuiSlot, so the identifier must be a sprite stitched into the block atlas, not a loose textures/gui/*.png.
  • Shift-click can insert into slots scrolled out of a box; setDisabledWhen on a SlotGridObject only dims it — lock slots server-side.
  • SlotGridObject only works in a handler GUI, and only claims slots named <id>_<digits>.
  • The dropdown search text uses the first labelled option’s style and needs rows at least 9px tall.
  • GuiObject still carries texture / text / onPress fields that most subclasses leave null.

常见问题

Gui Helper 支持哪些 Minecraft 版本?

Gui Helper 支持 Minecraft Java 版 1.20.6,可用的加载器:Fabric。下载时注意选择和你游戏版本一致的文件。

Gui Helper 怎么安装?

先用 PCL2 或 HMCL 启动器安装对应版本的 Fabric,再把下载的 .jar 文件放进游戏目录的 mods 文件夹,重新启动游戏即可。开启了版本隔离的,mods 文件夹在 versions/版本名 下面。

评论

登录后评论和评分

Hdi 的其他作品

查看全部 →