Перейти до вмісту

ABI reference

Цей контент ще не доступний вашою мовою.

The loader and a mod talk through a C ABI: repr(C) structs, integer enums, extern "system" functions, strings borrowed for the call, and no unwinding across the boundary. Mods normally use the safe layer of enshwick; this chapter is for reading logs and the rare call to the raw table. The exact types and signatures are in the abi module’s rustdoc. The same types for C and other languages are in enshwick.h, see Mods in C.

The layout file abi/layout.txt lists the layout of every ABI type, field by field: offset, size and type, and for a function pointer its signature. Its hash is the ABI version, ABI_VERSION. Any change to the layout is another version, and a loader loads only mods built for its own:

  • A mod exports enshwick_mod_abi, the version it was built for. A loader of another version does not load it and logs <file> skipped: built for another Enshwick: rebuild it for Enshwick 1.0.0-alpha.12, naming its own release.
  • Structs that cross the boundary on their own start with a Header: the struct’s size as its writer knew it and the writer’s ABI version.

Pin enshwick with = in a mod’s Cargo.toml, such as enshwick = "=1.0.0-alpha.12", as cargo enshwick new writes it. A caret requirement lets cargo update move the mod to the next release, whose layout may differ. Releases with the same layout share a version, so a mod keeps loading across them.

CI builds the rolling dev loader from the newest commit of main. To load under it, build the mod against main from git, pinned to a commit:

[dependencies]
enshwick = { git = "https://github.com/enshwick/enshwick", rev = "<commit>" }

The mod loads while that commit has the loader’s abi/layout.txt. Move rev forward when the dev loader moves.

Until 1.0.0 the layout changes whenever the API needs it. From 1.0.0 it is frozen, structs grow only by appending fields, and a loader loads mods built against older releases.

The enshwick crate follows SemVer for its Rust API. Until 1.0.0 the crate is a prerelease: any release may break the API and the ABI, and a break raises the prerelease number of 1.0.0-alpha.N.

The repository checks this in CI:

  • A test fails when the layout of the ABI types differs from abi/layout.txt. Rewriting the file changes ABI_VERSION.
  • CI runs cargo-semver-checks on enshwick against its last release on crates.io, so a release whose version claims less change than its API made fails.

declare_mod! writes five exports:

ExportSignatureWhen the loader calls it
enshwick_mod_abifn() -> u32First: the ABI version the mod was built for.
enshwick_mod_queryfn() -> *const ManifestBefore any of the mod’s code runs; static data.
enshwick_mod_initfn(*const HostApi, ModHandle) -> StatusOnce, in load order; registers hooks and the rest.
enshwick_mod_readyfn(*const HostApi, ModHandle)After every chain is armed, if init returned OK.
enshwick_mod_shutdownfn()Before a development reload unloads it; optional (53).

A DLL in mods/ without the first four is logged as <file> is not an Enshwick mod and unloaded.

Manifest is what manifest! builds:

FieldWhat it holds
headerSize and version of the struct
id<author>.<name>, each of [a-z0-9-], at most 64 characters; names settings and data
versionSemVer
sideSERVER (1), CLIENT (2) or BOTH (3)
flagsJOIN (1): counts in the join check; RELOAD (2): may be reloaded
dependenciesDependency { id, range, relation }; REQUIRES (0), AFTER (1), BREAKS (2), RECOMMENDS (3)
buildsBuildRow { side, fingerprint, symbols, constants }: symbols and constants pinned per game build
nameWhat players read; empty for the id
descriptionOne sentence on what the mod does
authors*const Str and author_count: the authors’ names
licenseAn SPDX licence expression
homepageWhere players read about the mod
pointsThe schemas of the extension points the mod defines, as TOML; also in the .enshpt section

A dependency may also be REPLACES (4), a mod this one takes the place of, with an empty range, or WAS (5), an id this mod had before a rename, which replaces that id as well and carries its settings and data over. HostApi::replaced lists the mods replaced either way, with ModInfo::replaced_by naming the mod that replaces each.

The loader skips a mod whose manifest has another major, an invalid id, the loader’s own id enshwick, a version that is not SemVer, an unknown side, or a dependency range that does not parse; the reason goes to loader.log as <file> skipped: <reason>.

Every call that can fail returns a Status. The safe layer turns a failed status into an Off reason of the form <what>: <why>, such as symbol quest.reward: missing on this game build:

CodeConstantMeaning<why> in the Off reason
0OKSuccess
1MISSINGWhat was asked for does not exist on this game buildmissing on this game build
2AMBIGUOUSMore than one candidate answers a lookupambiguous on this game build
3REFUSEDConflicts with another mod or with the loader’s rulesrefused by the loader
4BAD_ARGSAn argument is malformedmalformed
5TOO_LATECalled in a phase where it is not allowed, such as a hook after armingasked for too late
6FAULTEDThe mod has faulted and is offunavailable: the mod has faulted
7WRONG_THREADCalled from a thread the function does not servecalled off the thread it serves
8NOT_LOADEDThe part of the world asked about is not loaded yet; try again in a secondnot loaded yet
9OUTSIDE_WORLDThe box asked about leaves the world, past its edge or above its heightoutside the world
10STATIC_HALFThe static half of a component type: template data, never writtentemplate data, never written
11NOT_A_PROPThe entity is no prop: a creature, a flame altar or not placednot a prop
12NOT_KEPTNothing finds the entity after a load: a player, or no place in the worldnot found again after a load

enshwick_mod_init itself returns OK, REFUSED when Mod::init returned Err(Off), or FAULTED when it panicked; the loader logs off: init returned 3 or off: init returned 6 under the mod’s id.

Every host function answers a mod that is off with FAULTED, and a handle the loader never gave out with BAD_ARGS. A panic in the loader’s own code behind a host function never reaches the mod: the call returns REFUSED (or zero for a function that returns a value) and the loader logs the fault.

Struct fields and host function arguments that name a thing of the game take an id type, the same size and alignment as its integer. The header declares each as a typedef:

RustCIntegerNames
EntityEnshwickEntityu32an entity of the world; 0 for none
ItemIdEnshwickItemIdu32an item, by the number its item data gives
PlayerKeyEnshwickPlayerKeyu64a player’s account, the same every session
RecipeIdEnshwickRecipeIdu32a crafting recipe

HostApi::recipe_kind answers a RecipeKind code, and a recipe selection of change_data and a recipe output RateId take one. A mod reads a code it does not know as OTHER.

CodeConstantThe item a recipe makes
0OTHERnone of the kinds below
1BUILDING_BLOCKequipment slot BlueprintMaterial_Default
2ROOFequipment slot BlueprintMaterial_Roof
3OVERGROWTHequipment slot OvergrowthMaterial
4TERRAINequipment slot TerrainMaterial
5DECORATIVEslot BuildTool with the Decorative menu group’s item tag
6COMFORT_FURNITUREslot BuildTool with the Comfort Furniture menu group’s item tag and not the Decorative one

A mod subscribes with Load::on and the types in events, or with a raw Event id through Load::on_raw_event. See Events and the scheduler.

IdConstantTyped eventDataRaised onSide
1SETTINGS_CHANGEDSettingsChangednonenot fixedboth
2LOADER_SETTINGS_CHANGEDLoaderSettingsChangednonea loader threadboth
3TICKEDTickedTickDatathe game threadserver
4WORLD_LOADEDWorldLoadednonethe game threadserver
5WORLD_SAVEDWorldSavednonethe game threadserver
6PLAYER_JOINEDPlayerJoinedPlayerDatathe game threadserver
7PLAYER_LEFTPlayerLeftPlayerDatathe game threadserver
8SHUTDOWN_STARTEDShutdownStartednonethe game threadserver
9BUILDING_PLACEDBuildingPlacedBuildingDatathe game threadserver
10BUILDING_REMOVEDBuildingRemovedBuildingDatathe game threadserver
11JOIN_REFUSEDJoinRefusednonethe game threadclient
12ALTARS_CHANGEDAltarsChangednonethe game threadserver
13DAY_STARTEDDayStartednonethe game threadserver
14NIGHT_STARTEDNightStartednonethe game threadserver
15KNOWLEDGE_CHANGEDKnowledgeChangedKnowledgeDatathe game threadserver
16QUEST_COMPLETEDQuestCompletedQuestDatathe game threadserver
17CHUNK_LOADEDChunkLoadedChunkDatathe game threadserver
18CHUNK_UNLOADEDChunkUnloadedChunkDatathe game threadserver
19SETTINGS_REPLACEDSettingsReplacednonethe game threadserver
20PLAYER_DIEDPlayerDiedPlayerDeathDatathe game threadserver

ALTARS_CHANGED is raised for mods that opened altars. “Server” events also reach a client while it hosts a game, solo play included. The typed events hand a handler the fields the loader knows, with fields added after the event zero; they skip the handler only when the data lacks a field the event came with.

HostApi is the table of functions the loader passes to enshwick_mod_init. Fields marked “init only” are allowed during enshwick_mod_init only.

FieldWhat it does
headerSize and version of the table
host_versionThe loader’s own version
buildWrites the running game’s side, image base, build fingerprint and where its build table is from
symbolResolves a symbolic id for the running build: the mod’s own rows first, then the loader’s table
systemResolves an ECS system’s update function by its reflected name
field_offsetResolves a field’s offset in a reflected type
type_sizeResolves a reflected type’s size
hookLinks a detour into a function’s chain; init only
caller_frameWrites the game caller’s context at entry of the current chain, for HookFlags::CALLER_FRAME
faultReports a run-time failure; the loader unlinks the mod and turns it off
logWrites a line to the log under the mod’s id
settingsThe text of the mod’s settings file, written from the defaults when missing
publishPublishes a service table with its layout for other mods; init only
serviceFinds a published service and checks its layout starts with the wanted one
constantResolves an engine constant of the running build by its symbolic id
data_dirThe mod’s data folder, mod-data/<id>, created on first use
log_levelThe most detailed level kept for the mod’s lines
subscribeCalls a handler on every occurrence of an event; init only
type_hashThe ECS type hash of a reflected component type
componentA read-only pointer to an entity’s component; server game thread only
entity_templateThe template GUID of an entity; server game thread only
playerThe connected player whose character is an entity; server game thread only
playersThe connected players with characters in the world; server game thread only
serve_resourceServes a resource built from a base resource by a patch function; init only, one mod per key
add_textAdds the text of a LocaTag in a language; init only
modsThe loaded mods, the loader first
syncReports the mod’s join values and returns the joined server’s values to run with
code_rangeWhere the game’s code section is loaded and its length
patch_codeReplaces bytes of game code that must read as expected at arming; init only
workshop_recipesThe most recipes one workshop takes: 512, or u32::MAX once the loader lifted the limit
hosting1 while this process runs a game server
server_worldThe entity world of the game server this process runs; 0 for none
chatSends a chat line to one player or everyone, from any thread
set_labelGives an entity a name, as a player’s rename does; server game thread only
rename_filterCalls a filter before the server applies a player’s rename; init only
join_missingThe server’s join mods the last refused join found missing on this client
hook_atRuns a handler before an instruction inside a game function; init only
inventory_openAsks for inventory transactions and item data; init only; MISSING on a build that lacks them
item_infoWrites an item’s static data with the template it places; any thread
inventory_submitQueues an inventory transaction, from any thread; the result comes on the game thread
statusAdds a source of lines for the loader’s status summary
run_consoleRuns a console line as the server’s console, an action’s text form included; server game thread only
altars_openAsks the loader to follow the Flame Altars of the server’s world; init only
altarsThe altars with their levels and zones; any thread; REFUSED for a mod that did not open them
building_zone_check_filterCalls a filter when the game refuses a placement outside a single building zone; init only
survivor_lookupAnswers the game’s survivor lookups, one mod at a time; init only
survivor_bed_checkCalls a filter after a survivor’s own bed check kept its bed; init only
summon_filterCalls a filter before a summoning staff spawns or moves a survivor; init only
summon_itemFiles an item as a survivor’s summoning staff; init only
survivor_statusMerges the client’s survivor menu statuses, one mod at a time; init only
interaction_filterCalls a filter before a player’s interaction with an entity, in the server’s world; init only
skill_overrideAnswers the game’s checks of one skill node; init only
comfort_filterChanges the comfort each provider registers in a base; init only
experience_filterChanges the characters’ gained experience before the server applies it; init only
raise_base_limitLets the game group altar zones up to the loader’s maximum; init only; MISSING on an unknown build
base_zonesThe zones and bases of the last grouping, while the raised limit is in force
game_eventCalls a handler on every game event of a reflected type, or of all; init only
entitiesThe entities with a component and a place in the world; server game thread only
destroyAsks the server to destroy an entity after the next step; server game thread only
save_worldAsks the server to save the world now; server game thread only
world_keyThe key of the world the server runs: its save file’s name and a folder hash
component_writeA component to write, marked changed; refuses client copies; server game thread only
emitRaises a game event of an allowed type; server game thread only
teleportMoves an entity as the admin teleport does, after the next step; server game thread only
spawnSpawns an entity from a template as the admin spawn does; server game thread only
craft_filterCalls a filter on each player’s craft request in the server’s world; init only
build_filterCalls a filter after the cursor check allows a placement, on both sides; init only
net_channelOpens a join mod’s channel between its server and client parts; init only
net_sendSends a message on the mod’s channel to the server or a player’s client; any thread
net_readyWhether a peer takes messages now; any thread
notifyShows a line on a player’s screen through the client’s loader; server game thread only
time_of_dayThe clock of the server’s world; server game thread only
set_time_of_daySets the time of day; clients follow after the next step; server game thread only
time_speed_controlLets the mod set a factor on the clock’s speed; init only
set_time_speedSets the mod’s factor on the clock’s speed, 0 to 1000; server game thread only
game_settingsCopies the server’s live game settings and their preset; server game thread only
set_game_settingsReplaces the live game settings as the admin command does, until the server stops
damage_filterCalls a filter on damage before the game applies it, on worker threads; init only
buff_typesThe buff and debuff types of the running game; server game thread only
buffsThe buffs an entity has; server game thread only
apply_buffGives an entity a buff, or renews it, as the game restores saved buffs; server game thread only
remove_buffRemoves a buff type from an entity, as the game cleanses one; server game thread only
knowledgeA knowledge value of a player or the world; server game thread only
grant_knowledgeGrants knowledge as the game does, applied the next step; server game thread only
questsThe quest ids of the running game; server game thread only
weather_atHow clear, rainy, snowy and stormy it is at a place; server game thread only
weather_frontsThe current weather fronts of the server’s world; server game thread only
set_weatherStarts new weather in every layer, or lets the game choose; server game thread only
terrain_materialsThe terrain materials of the running game; server game thread only
terrain_editAdds, digs or flattens ground as the game’s terraforming does; server game thread only
config_schemaHands the loader the mod’s settings schema as TOML text; any time
summonedCalls a handler after a summoning staff’s use spawned or moved a survivor; init only
item_data_openOpens an item data kind by id; init only
item_data_getCopies an item’s value of a kind; any thread
item_data_setSets or removes an item’s value of a kind and sends it to clients; server, any thread
ui_frameCalls a callback each frame of the client’s interface; init only
ui_widgetDraws a window, label, button, row, bar or sound in the mod’s frame callback
ui_dialogQueues a dialog in the game’s style, answered on the thread that draws
ui_hudCalls a callback each frame the game draws its HUD; init only
ui_markersReplaces the mod’s markers on the client’s map; any thread
config_checkThe mod’s check of a new settings text before the loader writes it; init only
textsHands the loader the mod’s texts, for the labels of its settings on the Mods screen
content_serveServes bytes as game content, a served texture’s pixels, and gives their hash; any thread
content_readCopies the game’s own content from its archive files; any thread
icons_readyWhether this client shows the UI images mods serve; any thread
stat_openDefines or opens a stat kind by id; init only
stat_infoA stat kind’s definition and id; any thread
stat_valueA stat’s value on an entity, without locks; any thread
stat_modifySets or removes a mod’s modifier on an entity; server, any thread
stat_buffGives a buff type modifiers; init only
stats_changedCalls a handler for every stat value that changed; init only
stat_sourcesThe modifiers that count toward an entity’s stat; server game thread only
stat_watchWatches an entity for its worn items and buffs; any thread
define_eventDefines a mod event named after the mod, with its layout; init only
subscribe_eventCalls a handler on every mod event of a name whose layout serves the handler’s; init only
send_eventHands a mod event the mod defined to its subscribers on this thread; any thread
affix_openDefines an affix in the mod’s namespace; init only
affix_rollRolls affixes onto an item and keeps them; server game thread only
item_linesThe lines of what an item gives, own modifiers then affixes; any thread
affix_infoAn affix’s text key and rarity; any thread
migrateRegisters the mod’s migrations and runs them on its settings file; init only
declare_contentDeclares a content id in the mod’s namespace and returns its GUID; init only
entity_data_openOpens an entity data kind, sent to clients or not; init only
replacedThe mods a present mod replaces, never started; any thread
knowledge_input_filterA filter on the knowledge clients ask for in their input; server worker threads
languageThe game language the client last asked a text in; 0 on a server; any thread
keep_game_settingsChanges the game settings and keeps the marked fields with the world; server game thread only
forget_game_settingsForgets the world’s kept game settings and puts back its loaded values; server game thread only
revoke_knowledgeTakes knowledge back and has the clients sent it again; server game thread only
account_knowledgeGrants or takes back an account’s knowledge now or once its character loads; server game thread only
resource_readCopies a vanilla resource from the game’s archive files; any thread
game_textThe game’s own text of a tag in a language, from its archive; client only, any thread
rebuild_resourceBuilds a served resource again from its kept base with every mod’s patches; any thread
recipe_ruleAdds or takes back the mod’s rule that disables recipes by recipe, item or workshop; any thread
recipe_disabledWhether a recipe is disabled in this process now; any thread
define_pointDefines an extension point named after the mod, with its layouts and mode; init only
attach_pointAttaches a link to another mod’s extension point, with its order; init only
run_pointRuns the live links of the mod’s own extension point over its answer; any thread
actionsRegisters the mod’s player actions, asked for sheets, runs and hints; init only
event_typesEvery game event type the running build reflects, with hash and size; any thread
recipe_kindThe kind of the recipes that make an item, from its loaded slot and tags; any thread
rateDeclares a game rate the mod multiplies; init only
set_ratePuts the mod’s factor for a declared rate in force, 0 to 100; any thread
change_dataDeclares a change of a vanilla value, or of each item or recipe a selection picks; init only
featureReports one of the mod’s features on or off for the log, status summary and Mods screen
loop_waitRuns a handler before every wait of the engine’s event loop; init only
server_waitRuns a handler where the server loop picks its wait, which it may change; init only
task_workersCaps the task groups’ worker threads, the lowest cap winning; init only
altar_zone_filterAdds a filter to the chain that sizes altar zones; init only
altar_zones_changedHas the altar zones sized again on the server’s next step; any thread
altar_limit_filterAdds a filter to the chain that decides how many altars a Flame level allows; init only
base_limitThe most altar zones and bases the game groups now, and its own grouping’s zones; any thread
voxel_readReads a box of up to 64³ voxels at full detail, decoded; server game thread, quiet moment only
declare_changeDeclares a change of a vanilla value whose value the mod sets later; init only
set_changePuts the mod’s value of a declared change in force, or takes it out; any thread
build_rightsWhether the server lets a player edit a box; game thread, quiet moment only, refused inside a step
transaction_commitQueues terrain, voxels, erases, blocks and props as one transaction, with undo; any thread
transaction_undoQueues the undo of one of the mod’s transactions, refused once its bricks changed; any thread
transaction_statusWhere one of the mod’s transactions stands: queued, applied, undone, failed and why; any thread
transaction_commit_forAs transaction_commit, for a player whose rights the loader checks first; any thread
world_quietWhether live components may be read now: server game thread, quiet moment, world running
fog_openHas the loader copy the client’s fog of war for the mod; client, init only
fog_readCopies a box of the client’s fog of war and its size and version; any thread
serve_callServes a call, a described service named after the mod, with its input and answer; init only
find_callAsks for another mod’s call by name and major, matched field by field after init; init only
callRuns an asked call on this thread: the server’s handler reads the input and writes the answer
transaction_entitiesThe props one of the mod’s transactions placed and still holds; any thread
world_persistsWhether a save keeps changes in a box: inside one base’s zone; game thread
map_markersThe markers the scene places, read from the game’s data once per scene; game thread, quiet
account_actionKicks, bans or unbans an account; a ban of an account not online goes onto the list; game thread
allowlist_setLists an account on the loader’s allowlist or takes it off; dedicated server, any thread
allowlist_hasWhether the loader’s allowlist lists an account; dedicated server, any thread
subscribe_tickCalls a tick handler on the game thread about every period of wall time, every step for 0; init only
set_tick_everyChanges a periodic tick handler’s period from the next step; any thread
map_frameThe map’s origin, size and cell size in metres, read once per scene; game thread, quiet
request_base_limitsAsks for up to the given altar zones and bases, the largest request holding; init only
map_marker_typesThe client’s map marker types from the game’s registry, read once; any thread