Skip to content

SnLib v1.25.0

Choose a tag to compare

@ValentinTarnovsky ValentinTarnovsky released this 11 Aug 16:46
· 6 commits to main since this release

Placeholders that need no player.

Not every placeholder describes a player. A leaderboard row, a server-wide counter, an event countdown - that is global data that merely happens to be exposed through PlaceholderAPI's per-player surface. And the callers that ask for it routinely supply no player at all: a global hologram, a Discord bridge, a console task, /papi parse --null.

BuiltExpansion.onRequest rejected a null requester before it had even looked at which resolver was being asked for, so a token that needed no player was dropped along with the ones that did. The consumer could not opt out: sn.papi().expansion(...) is the only registration path, and taking the raw PlaceholderExpansion back would take back registration, persistence and unregistration with it.

  • ExpansionBuilder.global(String param, Supplier<String>) and globalPrefixed(String prefix, Function<String, String>) - bind a resolver that takes NO OfflinePlayer, so it cannot dereference one and it answers a null requester like any other. Same keyspace and precedence as placeholder / prefixed; the later declaration for one key wins outright.
  • onRequest now locates the resolver FIRST and rejects the null requester SECOND. Everything bound through placeholder / prefixed keeps the short-circuit exactly as before, so a resolver written against the non-null contract its binder documents never starts seeing nulls.
  • LeaderboardCache.exposePlaceholders(id) binds its top_ tokens global, so every board exposed through it renders in a global hologram without the consumer changing a line. pos_<id> asks about the requester by definition and stays player-bound.
sn.papi().expansion("shop")
        .placeholder("balance", player -> money(player))   // needs a player
        .global("open_shops", () -> String.valueOf(registry.openCount()))
        .globalPrefixed("top_", position -> topSellerAt(position))
        .register();

Strictly additive: two new public methods, zero public signatures changed, and the only behaviour change on an existing path is exposePlaceholders, which answers strictly more than it did. SnApi.LEVEL 16 -> 17.