Skip to content

Pier 26.40.2

Choose a tag to compare

@Maskviva Maskviva released this 14 Sep 03:29
· 9 commits to main since this release

Added

  • A mod that is not a Pier mod can call a Pier mod's services. pier_bridge_call,
    pier_bridge_list and pier_bridge_abi are exported from the host, and
    bindings/bridge/pier-bridge.h is a header-only client that binds them. Until now the
    registry was reachable only with a PierModHandle the loader issues, and the only
    exported symbol pointed the other way, so a permission manager whose value is being the
    backend everyone shares was reachable only by mods that had already adopted Pier.

    The registry is unchanged: api_service_call already accepted a null handle and its
    self-call check was already conditional on one. What a bridge caller lacks is identity,
    which is a real limit and is documented as one -- a provider that grants anything on the
    strength of the caller alone must not be reachable this way. See docs/guide/bridge.md.

  • PlayerEditSignEvent and PlayerOperatedItemFrameEvent are raised. Both were
    declared in ALL_SYNTHETIC and listed as names, and no hook in the tree produced
    either, so a subscription succeeded and never fired. A protection mod gating on them
    reported a refusal its own operator could see while the player edited the sign anyway.
    Sign editing goes through SignBlockActor::_playerCanUpdate, which is the engine's own
    gate and is asked before the text is taken from the packet; the item-frame right click
    goes through ItemFrameBlock::use. Both are in CANCELLABLE now.

  • Every player event with a position carries block, and every one with a player
    carries item.
    Injected by the enricher rather than by each hook, because the events
    that need them are LeviLamina's own and have no hook here to extend. A consumer
    subdividing a permission by what was touched had nowhere to get the answer: the payload
    named the action and never the object. block is the block at the event's coordinates
    and item is what the player held. Both are absent rather than empty when they cannot
    be read, since a name invented here is indistinguishable from a real one and a rule
    keyed on it fires on the wrong block.

  • PlayerOpenContainerEvent carries container and block. The payload had only a
    numeric containerType, so a subscriber wanting to tell a chest from a dropper had to
    carry its own copy of a network enum. container is that enum as a word and block is
    the block's type name, which is empty rather than a placeholder when it cannot be read:
    an invented name is indistinguishable from a real one, and a rule keyed on it fires on
    the wrong block.

Fixed

  • PlayerRequestItemActionEvent is declared observation-only. Nothing raises it and
    there is no point at which it can be cancelled; is_cancellable answered None, which
    a caller reads as "unknown" rather than "no". It now answers Some(false) with where to
    block instead, which is what stops a protection mod from treating a subscription to it
    as a working gate.

Changed

  • Translations are files again, not a generated C++ table.
    packages/pier-support/src/LangShipped.inc, tools/embed-lang.py and
    tools/checks/lang_embedded.py are gone. The host reads plugins/Pier/lang/<code>.lang
    and nothing else is compiled in beyond the built-in English, so a language is a file an
    operator drops in and edits rather than a table only a rebuild can change.

    The packaging half that made the table necessary is handled where it belongs: the
    after_build step in xmake.lua names en_US.lang and zh_CN.lang explicitly and
    fails the build when either is absent, so bin/Pier/lang/ carries both and a release
    cannot ship half-translated. A glob alone still succeeds on one file, which is the
    shape that let the directory go missing before.

  • lang/en_US.lang is added and carries every key. It is what a translator copies and
    what an operator edits; i18n_keys.py now fails when it is missing a key, when either
    shipped file is absent, or when a placeholder count disagrees with the English.

Fixed

  • The lang directory never reached an installed server, so every log was English.
    loadLanguages reads getModDir()/lang, modpacker packages the target and
    manifest.json and nothing else, so lang/ sat in the repository and shipped in no
    archive. Nothing reported it: a missing lang directory is not an error, and the one
    line that would have said so only printed when keys loaded.

    The startup line now prints on every boot rather than only when a file was found, and
    reports how many lines the active locale has rather than how many a file contributed.
    Suppressing it when there is no file would leave exactly the gap this closed.

  • PIER_SRV_PROTOCOL_VERSION reported 2169 for BDS 1.26.40, which speaks 2168. The
    row came from a published metadata table rather than from a server; the banner on a
    real 1.26.40.8 reads ProtocolVersion 2168. A consumer mapped the 2169 back through
    its own table and announced the server as 1.26.45 — a confident wrong answer on a
    clean boot, which is the failure the key was rewritten to stop producing. The 1.21.93
    row went with it: it was taken from a save file's NetworkVersion tag, which is the
    same class of unchecked evidence. An unlisted version fails the key, and failing is
    the correct outcome. 2168 covers 1.26.40 through 1.26.44 and 2169 is 1.26.45, but only
    1.26.40 is listed — a range known second-hand is the evidence that produced the wrong
    row in the first place.

  • tools/checks/i18n_keys.py truncated any English value containing {},. It cut
    the value at the first },, which also matches a placeholder followed by a comma, so
    ... as id {}, registry id {} was read as having one placeholder. A correct
    translation was then reported as having too many. It now collects the C++ string
    literals properly.

Added

  • Seven more log keys: the per-dimension boot lines an operator reads to answer "did my
    world come up the way I wrote it" (dim.height.set, dim.registered, dim.ready,
    dim.terrain.layers, dim.terrain.end), and the host's own ready line
    (host.ready). The grid clause of the layers line is its own key rather than a
    hardcoded tail, because a translation that cannot move that clause has to reorder the
    sentence around it.

Added

  • Three events that used to need iListenAttentively are hooked here.
    PlayerEditSignEvent, PlayerOperatedItemFrameEvent and
    PlayerRequestItemActionEvent moved from ALL_FROM_ILA to ALL_SYNTHETIC.

    Each closes a hole rather than adding a convenience. Placing a sign is a block place
    and was covered; editing the text of one already there was neither a place nor an
    interact. Taking an item out of a frame was covered by PlayerAttackItemFrameEvent;
    rotating it was not. Opening an enchanting table is an interact and was covered;
    everything after that arrives on the item-stack request path and was not.

    Taking them off another mod is deliberate. A protection feature that only works when a
    third-party mod happens to be installed is not a protection feature, and the version
    matrix was already BDS × LeviLamina without adding a third pin that this repository
    cannot fix when it lags a BDS release.

    PlayerRequestItemActionEvent reports only the Craft* action types, as an action
    word (craft / creative / anvil / grindstone / loom) rather than the engine's
    enumerator number, which shifts when Mojang inserts a type. Take, place and swap are
    not reported: several arrive per click, and a cross-mod dispatch on that path would
    cost more than it protects.