Players¶
Section notes in abi.h
Appended
§B player management
§I NBT binary, KvDb (thread-safe), system & server info
Player: equipment, cooldown, network (dedicated fns)
Titles
PACT_SET_TITLE (player_action opcode 6) reaches the client by running the console command title "<name>" title <text>. Three things are wrong with that and none of them are theoretical:
This slot builds a real SetTitlePacket instead. No wire format crosses the FFI (the packet is constructed field-by-field on this side), so it survives protocol bumps the way spawn_particle_for does.
type is SetTitlePacketPayload::TitleType:
| Text Only | |
|---|---|
The TextObject variants (6..8) need a ResolvedTextObject and are refused. text is ignored for Clear/Reset/Times.
Durations are in TICKS. For 2/3/4, when all three are >= 0 a Times packet is sent first so the timing is deterministic rather than inherited from whatever the client last stored; pass -1 for all three to keep the client's current timing. Mixing (-1 with >=0) is refused rather than guessed at — a half-specified duration set has no sane meaning. Server thread only.
Same-toolchain fast lane, appended and struct_size-gated.
Five slots appended without touching PIER_ABI_VERSION: a pure append is not a version change, and struct_size is the precise gate.
Both directions hold. A new loader running an old mod: the old table is a byte-identical prefix of the new one, the mod cannot reach these five slots, and it works unchanged. A new mod on an old loader: SDK runtime init compares struct_size, finds the loader's table shorter than the one it was compiled against, and refuses to load. That is the right outcome, since a mod that reads the lane_publish cell on a loader without it would read out of bounds.
In short: the version number tracks "semantics changed", struct_size tracks "the table grew". This change is only the latter.
See the long comment at PierLaneDesc above. In one line: service is the cross-language (name, JSON) -> JSON channel, while this is a direct function-table call that holds only when both sides were built by the same toolchain; a fingerprint mismatch yields no pointer and the consumer falls back to service.
Server thread only.
Slots¶
get_player_position¶
| C | |
|---|---|
Look up a connected player's feet position and dimension by name. Used to pick selection corners from where the player is standing. Server thread only.
- Call:
api->get_player_position(name) - Parameters:
- name :
PierStr
- name :
- Return type:
PierPlayerPos - Section of abi.h: Appended
- Position in the table: slot 14, counting from 0
- Callers in each binding:
- Rust:
Player::position - Go:
Raw.GetPlayerPosition
- Rust:
list_players¶
| C | |
|---|---|
One SNBT per online player: {name,xuid,uuid,dim,x,y,z}.
- Call:
api->list_players(ctx, snbt_sink) - Parameters:
- ctx :
void* - snbt_sink :
PierStrSink
- ctx :
- Section of abi.h: §B player management
- Position in the table: slot 21, counting from 0
- Callers in each binding:
- Rust:
Player::list,Player::list - Go:
ListPlayers,Raw.ListPlayers
- Rust:
player_resolve¶
| C | |
|---|---|
Resolve a player selector to their ActorUniqueID (bridges into the actor_* API).
- Call:
api->player_resolve(sel, out) - Parameters:
- sel :
PierPlayerSel - out :
PierActorId*
- sel :
- Return type:
bool - Section of abi.h: §B player management
- Position in the table: slot 22, counting from 0
- Callers in each binding:
player_send_message¶
| C | |
|---|---|
- Call:
api->player_send_message(sel, msg) - Parameters:
- sel :
PierPlayerSel - msg :
PierStr
- sel :
- Return type:
bool - Section of abi.h: §B player management
- Position in the table: slot 23, counting from 0
- Callers in each binding:
player_disconnect¶
| C | |
|---|---|
- Call:
api->player_disconnect(sel, reason) - Parameters:
- sel :
PierPlayerSel - reason :
PierStr
- sel :
- Return type:
bool - Section of abi.h: §B player management
- Position in the table: slot 24, counting from 0
- Callers in each binding:
broadcast_message¶
| C | |
|---|---|
sendMessage to every online player.
- Call:
api->broadcast_message(msg) - Parameters:
- msg :
PierStr
- msg :
- Section of abi.h: §B player management
- Position in the table: slot 25, counting from 0
- Callers in each binding:
- Rust:
Player::broadcast - Go:
Broadcast,Raw.BroadcastMessage
- Rust:
player_set_gamemode¶
| C | |
|---|---|
0=survival 1=creative 2=adventure 6=spectator, native (Player::setPlayerGameType).
- Call:
api->player_set_gamemode(sel, mode) - Parameters:
- sel :
PierPlayerSel - mode :
int32_t
- sel :
- Return type:
bool - Section of abi.h: §B player management
- Position in the table: slot 26, counting from 0
- Callers in each binding:
player_teleport¶
| C | |
|---|---|
Teleport natively (Actor::teleport). Custom dimensions (id >= 3) are allowed; the dimension bridge must produce an engine instance whose id matches, or the call fails instead of sending the player into a mismatched dimension.
- Call:
api->player_teleport(sel, dim, x, y, z) - Parameters:
- sel :
PierPlayerSel - dim :
int32_t - x :
double - y :
double - z :
double
- sel :
- Return type:
bool - Section of abi.h: §B player management
- Position in the table: slot 27, counting from 0
- Callers in each binding:
- Rust:
Player::teleport - Go:
Player.Teleport,Raw.PlayerTeleport
- Rust:
player_get_num¶
| C | |
|---|---|
The four *_get_num slots share one convention. The return is whether the host has an answer, and *out is the answer; a false leaves *out untouched.
False and "the value is zero" are different results and a caller must not collapse them (contract §5.2). False has two causes it does not distinguish: the subject was not found, and the property is one this engine version does not expose. Neither is an error the host logs, because a caller polling a property it cannot read would fill the log with it; the list of properties that always answer false on a given version is in CHANGELOG.md under the release.
- Call:
api->player_get_num(sel, prop, out) - Parameters:
- sel :
PierPlayerSel - prop :
int32_t - out :
double*
- sel :
- Return type:
bool - Section of abi.h: §B player management
- Position in the table: slot 28, counting from 0
- Callers in each binding:
- Rust:
Player::num,Player::game_type,Player::permission_level,Player::dimension,Player::level,Player::experienceand more, 36 in all - Go:
Player.GameType,Player.Level,Player.Experience,Player.Hunger,Player.Saturation,Player.Exhaustionand more, 37 in all - Zig:
Player.gameType,Player.level,Player.experience,Player.hunger,Player.saturation,Player.exhaustionand more, 36 in all
- Rust:
player_get_str¶
| C | |
|---|---|
- Call:
api->player_get_str(sel, prop, ctx, sink) - Parameters:
- sel :
PierPlayerSel - prop :
int32_t - ctx :
void* - sink :
PierStrSink
- sel :
- Return type:
bool - Section of abi.h: §B player management
- Position in the table: slot 29, counting from 0
- Callers in each binding:
- Rust:
Player::text,Player::last_death_pos,Player::position,Player::real_name,Player::uuid,Player::xuidand more, 11 in all - Go:
Player.RealName,Player.Uuid,Player.Xuid,Player.IpAndPort,Player.LocaleCode,Player.NameTagand more, 12 in all - Zig:
Player.realName,Player.uuid,Player.xuid,Player.ipAndPort,Player.localeCode,Player.nameTagand more, 11 in all
- Rust:
player_set_num¶
| C | |
|---|---|
- Call:
api->player_set_num(sel, prop, v) - Parameters:
- sel :
PierPlayerSel - prop :
int32_t - v :
double
- sel :
- Return type:
bool - Section of abi.h: §B player management
- Position in the table: slot 30, counting from 0
- Callers in each binding:
- Rust:
Player::set_num,Player::set_level,Player::set_experience,Player::set_hunger,Player::set_saturation,Player::set_exhaustion - Go:
Player.SetLevel,Player.SetExperience,Player.SetHunger,Player.SetSaturation,Player.SetExhaustion,Raw.PlayerSetNum - Zig:
Player.setLevel,Player.setExperience,Player.setHunger,Player.setSaturation,Player.setExhaustion
- Rust:
player_action¶
| C | |
|---|---|
- Call:
api->player_action(sel, action, sarg, a, b, c, ctx, out) - Parameters:
- sel :
PierPlayerSel - action :
int32_t - sarg :
PierStr - a :
double - b :
double - c :
double - ctx :
void* - out :
PierStrSink
- sel :
- Return type:
bool - Section of abi.h: §B player management
- Position in the table: slot 31, counting from 0
- Callers in each binding:
- Rust:
Player::act,Player::set_ability,Player::set_ability_raw,Player::can_use_ability,Player::set_permission_level,Player::set_selected_slotand more, 22 in all - Go:
Player.SetAbility,Player.CanUseAbilityAction,Player.SetSelectedSlot,Player.GiveItem,Player.SetSpawnPoint,Player.ClearTitleand more, 28 in all - Zig:
Player.setAbility,Player.canUseAbilityAction,Player.setSelectedSlot,Player.giveItem,Player.setSpawnPoint,Player.clearTitleand more, 27 in all
- Rust:
player_send_message_typed¶
| C | |
|---|---|
Group note
Send a message of a specific TextPacketType to one player (additive, gated by struct_size). type is a TextPacketType value:
| Text Only | |
|---|---|
Out-of-range falls back to Raw. Single-string body (like LSE tell): the author/param kinds (Chat/Whisper/Translate) arrive as plain text. plain player_send_message remains the Raw/Chat convenience path.
- Call:
api->player_send_message_typed(sel, msg, type) - Parameters:
- sel :
PierPlayerSel - msg :
PierStr - type :
int32_t
- sel :
- Return type:
bool - Section of abi.h: §I NBT binary, KvDb (thread-safe), system & server info
- Position in the table: slot 91, counting from 0
- Callers in each binding:
player_get_carried_item¶
| C | |
|---|---|
- Call:
api->player_get_carried_item(sel, ctx, sink) - Parameters:
- sel :
PierPlayerSel - ctx :
void* - sink :
PierStrSink
- sel :
- Return type:
bool - Section of abi.h: Player: equipment, cooldown, network (dedicated fns)
- Position in the table: slot 102, counting from 0
- Callers in each binding:
player_get_item¶
| C | |
|---|---|
- Call:
api->player_get_item(sel, slot, ctx, sink) - Parameters:
- sel :
PierPlayerSel - slot :
int32_t - ctx :
void* - sink :
PierStrSink
- sel :
- Return type:
bool - Section of abi.h: Player: equipment, cooldown, network (dedicated fns)
- Position in the table: slot 103, counting from 0
- Callers in each binding:
- Rust:
Player::item - Go:
Player.InventoryItem,Raw.PlayerGetItem
- Rust:
player_set_item¶
| C | |
|---|---|
- Call:
api->player_set_item(sel, slot, item_snbt) - Parameters:
- sel :
PierPlayerSel - slot :
int32_t - item_snbt :
PierStr
- sel :
- Return type:
bool - Section of abi.h: Player: equipment, cooldown, network (dedicated fns)
- Position in the table: slot 104, counting from 0
- Callers in each binding:
player_get_equipment¶
| C | |
|---|---|
All equipment as SNBT: [{slot, item_snbt},…] slot: 0=mainhand 1=offhand 2-5=armor
- Call:
api->player_get_equipment(sel, ctx, sink) - Parameters:
- sel :
PierPlayerSel - ctx :
void* - sink :
PierStrSink
- sel :
- Return type:
bool - Section of abi.h: Player: equipment, cooldown, network (dedicated fns)
- Position in the table: slot 105, counting from 0
- Callers in each binding:
- Rust:
Player::equipment - Go:
Raw.PlayerGetEquipment
- Rust:
player_get_cooldown¶
| C | |
|---|---|
Ticks remaining for an item cooldown (-1 if not on cooldown / player offline).
- Call:
api->player_get_cooldown(sel, item_name) - Parameters:
- sel :
PierPlayerSel - item_name :
PierStr
- sel :
- Return type:
int32_t - Section of abi.h: Player: equipment, cooldown, network (dedicated fns)
- Position in the table: slot 106, counting from 0
- Callers in each binding:
- Rust:
Player::cooldown - Go:
Raw.PlayerGetCooldown
- Rust:
player_start_cooldown¶
| C | |
|---|---|
- Call:
api->player_start_cooldown(sel, item_name, ticks) - Parameters:
- sel :
PierPlayerSel - item_name :
PierStr - ticks :
int32_t
- sel :
- Return type:
bool - Section of abi.h: Player: equipment, cooldown, network (dedicated fns)
- Position in the table: slot 107, counting from 0
- Callers in each binding:
player_get_network_status¶
| C | |
|---|---|
- Call:
api->player_get_network_status(sel, ctx, sink) - Parameters:
- sel :
PierPlayerSel - ctx :
void* - sink :
PierStrSink
- sel :
- Return type:
bool - Section of abi.h: Player: equipment, cooldown, network (dedicated fns)
- Position in the table: slot 108, counting from 0
- Callers in each binding:
player_send_title¶
| C | |
|---|---|
- Call:
api->player_send_title(sel, type, text, fade_in_ticks, stay_ticks, fade_out_ticks) - Parameters:
- sel :
PierPlayerSel - type :
int32_t - text :
PierStr - fade_in_ticks :
int32_t - stay_ticks :
int32_t - fade_out_ticks :
int32_t
- sel :
- Return type:
bool - Section of abi.h: Titles
- Position in the table: slot 156, counting from 0
- Callers in each binding:
player_conn_id¶
| C | |
|---|---|
This player's connection id — the same number packet interceptors see in the packet context.
A packet callback has only conn_id, not a player, so per-player rewriting of outbound packets is impossible without this: locking the sky color needs the dimension of the person on that connection, which needs to know who they are.
The alternative is to periodically send packets that override the server's, and that is wrong: the server sends real time while the mod sends locked time, the two kinds interleave, and the client's sky flickers between them. Rewriting is correct, and rewriting needs this slot.
@return the connection id; 0 if the player is offline or their network
| Text Only | |
|---|---|
Pure append: PIER_ABI_VERSION is unchanged, struct_size is the gate.
- Call:
api->player_conn_id(who) - Parameters:
- who :
PierPlayerSel
- who :
- Return type:
uint64_t - Section of abi.h: Same-toolchain fast lane, appended and struct_size-gated.
- Position in the table: slot 180, counting from 0
- Callers in each binding:
- Rust:
Player::conn_id - Go:
Player.ConnID,Raw.PlayerConnId
- Rust:
PierPlayerNumProp¶
player_get_num / player_set_num keys. (G)=get-only, (S)=settable.
| Name | Value | Description |
|---|---|---|
PIER_PPROP_GAME_TYPE |
0 |
(G) Player::getPlayerGameType; write via player_set_gamemode |
PIER_PPROP_LEVEL |
1 |
(S) attribute Player::LEVEL() |
PIER_PPROP_EXPERIENCE |
2 |
(S) attribute Player::EXPERIENCE() (progress 0..1) |
PIER_PPROP_HUNGER |
3 |
(S) attribute Player::HUNGER() |
PIER_PPROP_SATURATION |
4 |
(S) attribute Player::SATURATION() |
PIER_PPROP_EXHAUSTION |
5 |
(S) attribute Player::EXHAUSTION() |
PIER_PPROP_XP_NEEDED_NEXT_LEVEL |
6 |
(G) Player::getXpNeededForNextLevel |
PIER_PPROP_LUCK |
7 |
(G) Player::getLuck |
PIER_PPROP_SELECTED_SLOT |
8 |
(G) Player::getSelectedItemSlot; set via PIER_PACT_SET_SELECTED_SLOT |
PIER_PPROP_IS_OPERATOR |
9 |
(G) Player::isOperator |
PIER_PPROP_CAN_USE_OPERATOR_BLOCKS |
10 |
(G) Player::canUseOperatorBlocks |
PIER_PPROP_IS_FLYING |
11 |
(G) Player::isFlying |
PIER_PPROP_CAN_JUMP |
12 |
(G) Player::canJump |
PIER_PPROP_IS_EMOTING |
13 |
(G) Player::isEmoting |
PIER_PPROP_IS_IN_RAID |
14 |
(G) Player::isInRaid |
PIER_PPROP_IS_HURT |
15 |
(G) Player::isHurt |
PIER_PPROP_IS_SCOPING |
16 |
(G) Player::isScoping |
PIER_PPROP_CAN_SLEEP |
17 |
(G) Player::canSleep |
PIER_PPROP_HAS_RESPAWN_POSITION |
18 |
(G) Player::hasRespawnPosition |
PIER_PPROP_CLIENT_SUB_ID |
19 |
(G) Player::getClientSubId |
PIER_PPROP_CAN_USE_ABILITY |
20 |
(G) Player::canUseAbility; the ability index is passed through the player_action GET path, see PIER_PACT_CAN_USE_ABILITY |
PIER_PPROP_DIRECTION |
21 |
(G) Player::getDirection (0=S,1=W,2=N,3=E) |
PIER_PPROP_CHUNK_RADIUS |
22 |
(G) Player::getChunkRadius |
PIER_PPROP_NETWORK_RTT |
23 |
(G) getNetworkStatus().mPing (ms) |
PIER_PPROP_PLATFORM |
24 |
(G) Player::getPlatform |
PIER_PPROP_ENCHANTMENT_SEED |
25 |
(G) Player::getEnchantmentSeed |
PIER_PPROP_IS_USING_ITEM |
26 |
(G) Player::isUsingItem |
PIER_PPROP_IS_BLOCKING |
27 |
(G) Player::isBlocking |
PIER_PPROP_IS_GLIDING |
28 |
(G) Player::isGliding |
PIER_PPROP_IS_SWIMMING |
29 |
(G) Player::isSwimming |
PIER_PPROP_PERMISSION_LEVEL |
30 |
(G) Player::getPlayerPermissionLevel |
PIER_PPROP_SCORE |
31 |
(G) Player::getScore |
PIER_PPROP_FALL_DISTANCE |
32 |
(G) Actor::getFallDistance |
PIER_PPROP_IS_DEAD |
33 |
(G) Actor::isDead |
PIER_PPROP_HAS_DIED_BEFORE |
34 |
(G) Player::hasDiedBefore |
PIER_PPROP_DIMENSION |
35 |
(G) Actor::getDimensionId |
PierPlayerStrProp¶
player_get_str keys.
| Name | Value | Description |
|---|---|---|
PIER_PSTR_REAL_NAME |
0 |
Player::getRealName |
PIER_PSTR_UUID |
1 |
Player::getUuid().asString() |
PIER_PSTR_XUID |
2 |
Player::getXuid |
PIER_PSTR_IP_AND_PORT |
3 |
Player::getIPAndPort |
PIER_PSTR_LOCALE_CODE |
4 |
Player::getLocaleCode |
PIER_PSTR_NAME_TAG |
5 |
Actor::getNameTag (display name) |
PIER_PSTR_LAST_DEATH_POS |
6 |
SNBT {x,y,z} or "" if none |
PIER_PSTR_LAST_DEATH_DIMENSION |
7 |
dimension id as string |
PIER_PSTR_NETWORK_STATUS |
8 |
SNBT {ping,avg_ping,packet_loss,max_ping} |
PIER_PSTR_PLATFORM_ONLINE_ID |
9 |
Player::getPlatformOnlineId |
PIER_PSTR_RESPAWN_POS |
10 |
SNBT {x,y,z,dim}: where this player would respawn. Never empty; a player with no bed reports the world spawn, and the two are not distinguishable. |
PierPlayerAction¶
player_action verbs. Args are (sarg, a, b, c); unused args are ignored. out (when non-NULL) receives a result string where noted.
| Name | Value | Description |
|---|---|---|
PIER_PACT_SET_ABILITY |
0 |
a=AbilitiesIndex, b=0/1 (bool slots) or float (FlySpeed etc.). Restores PlayerPermissionLevel to its pre-write value afterwards: the engine's LayeredAbilities::setAbility is the "switch to custom permissions" path and pushes the player to Custom, and that level ships to the client inside UpdateAbilitiesPacket together with the ability layer. To change the level, use PIER_PACT_SET_PERMISSION_LEVEL. Refused (false) until the player has finished joining (Player::isPlayerInitialized): an ability written while the client is still loading desynchronizes until the player rejoins. Simulated players are exempt. |
PIER_PACT_CAN_USE_ABILITY |
1 |
a=AbilitiesIndex → out "0"/"1" Player::canUseAbility |
PIER_PACT_SET_SELECTED_SLOT |
2 |
a=slot Player::setSelectedSlot |
PIER_PACT_GIVE_ITEM |
3 |
sarg=item SNBT ItemStack::fromTag + Player::addAndRefresh |
PIER_PACT_SET_SPAWN_POINT |
4 |
a,b,c=pos, sarg=dim id (any registered dim); native Player::setRespawnPosition |
PIER_PACT_CLEAR_TITLE |
5 |
native SetTitlePacket(Clear) |
PIER_PACT_SET_TITLE |
6 |
sarg=text, a=slot(0 title,1 subtitle,2 actionbar); native SetTitlePacket, text sent verbatim |
PIER_PACT_ADD_EXPERIENCE |
7 |
a=xp Player::addExperience |
PIER_PACT_ADD_LEVELS |
8 |
a=levels Player::addLevels |
PIER_PACT_START_COOLDOWN |
9 |
sarg=item name, a=ticks Player::startItemCooldown |
PIER_PACT_START_RIDING |
10 |
a=vehicle ActorUniqueID (lower 64b) Player::startRiding |
PIER_PACT_STOP_RIDING |
11 |
Player::stopRiding |
PIER_PACT_ATTACK |
12 |
a=target ActorUniqueID (lower 64b) Player::attack |
PIER_PACT_DROP |
13 |
sarg=item SNBT, a=random(0/1) Player::drop |
PIER_PACT_INTERACT |
14 |
a=target ActorUniqueID Player::interact |
PIER_PACT_START_USING_ITEM |
15 |
sarg=item SNBT, a=duration Player::startUsingItem |
PIER_PACT_STOP_USING_ITEM |
16 |
Player::stopUsingItem |
PIER_PACT_SET_CHUNK_RADIUS |
17 |
a=radius Player::setChunkRadius |
PIER_PACT_SET_ENCHANTMENT_SEED |
18 |
a=seed Player::setEnchantmentSeed |
PIER_PACT_REGISTER_TRACKED_BOSS |
19 |
a=boss ActorUniqueID Player::registerTrackedBoss |
PIER_PACT_UNREGISTER_TRACKED_BOSS |
20 |
a=boss ActorUniqueID Player::unRegisterTrackedBoss |
PIER_PACT_PLAY_EMOTE |
21 |
sarg=piece id Player::playEmote |
PIER_PACT_RESEND_ALL_CHUNKS |
22 |
Player::resendAllChunks |
PIER_PACT_OPEN_INVENTORY |
23 |
Player::openInventory |
PIER_PACT_SIDEBAR_SET |
24 |
sarg="obj\ntitle\nline…" per-player sidebar |
PIER_PACT_SIDEBAR_CLEAR |
25 |
sarg=objective RemoveObjectivePacket |
PIER_PACT_SET_PERMISSION_LEVEL |
26 |
a=PlayerPermissionLevel (0 Visitor, 1 Member, 2 Operator, 3 Custom). LayeredAbilities::setPlayerPermissions plus UpdateAbilitiesPacket. The read side is PIER_PPROP_PERMISSION_LEVEL. Refused until the player has finished joining, like PIER_PACT_SET_ABILITY. |