Changelog
Цей контент ще не доступний вашою мовою.
The format follows Keep a Changelog, and versions follow Semantic Versioning. Each entry names the pull request that made the change.
[Unreleased]
Section titled “[Unreleased]”-
Ui::map_marker_typeslists the client’s map marker types from the game’s registry, each aMapMarkerTypewith its key, itsMarkerTypeSortinggroup and the game’s flags, andMarker::marker_typeshows a mod’s marker with one of them (HostApi::map_marker_types,MapMarkerTypeInfo;UiMarkertakes the type in place of its reserved field); the fake host serves a registry withFakeHost::map_marker_types(#728). -
developer: trueinmanifest!(ManifestFlags::DEVELOPER) marks a mod as a developer tool. While one runs, or the filemod-data/enshwick/developer-toolsexists, every player reads an upper-case warning in chat at join, on the Mods screen and in the main menu’s line. The loader settingmotdis a message of the day players read in chat at join (#726). -
Load::apply_configreads the settings, hands them to a closure at once and after every change, and returns them (#721). -
A part of the loader that a panic turns off, such as the HUD items, a window or map markers, shows on the Mods screen and in the status summary with its reason; each window and menu entry turns off alone. A player who joins a server gets one chat line naming what is off there (#683).
-
A panic in a mod logs a line at
errorwith its message, place and thread, and the reason of a mod a panic turns off carries the panic’s message; a panickinginitturns the mod off with that reason (#682). -
A world whose save moved to another folder keeps its mods’ data: the loader moves the folders of the world it came from to its new key, or copies them while the old save is still there (#677).
-
A world store whose file does not read shows on the Mods screen as the feature
world store <name>off, with the reason (#675). -
WorldStore::shut_reasonsays why the running world’s file did not read while the store stays shut, and the loader’s status summary shows it under the mod (#668). -
PackManifest::enshwick: a pack’spack.tomlmay name the Enshwick releases it is made for, such asenshwick = "=1.0.0-alpha.12"; a loader of another release skips the pack and logs both versions (#661). -
files:read_if_presentandread_to_string_if_presenttell a missing file from one that does not read, andwrite_atomicallywrites a file whole, flushed to disk, keeping the old one asbackup_path.Store,WorldStoreandHoldwrite through it, so a store keeps<name>.toml.bakbeside its file (#658).
Changed
Section titled “Changed”-
stats::Origin::Modnames its mod by the newmods::ModIndex, its place in load order, whichModIndex::entryandModEntry::indexresolve (#719). -
The fake host refuses the hooks, mid-function hooks, code patches, points and rates the loader refuses, with the loader’s status: a mod’s test now fails where the game would. Both take the rules from one place.
-
The ABI layout file lists each field’s type, and a function pointer’s signature, so a changed signature is another
ABI_VERSION. Every mod needs a rebuild (#681). -
Stats::set_item,Affixes::roll,Load::add_loot_affixes,Load::add_craft_affixes,AffixLootandAffixCraftneed theunstablefeature: they keep their values as item data, which sets aside a value on an item no load finds after a restart (#673). -
item_dataandentity_dataneed theunstablefeature: after a restart, a value on an item no load finds stays aside.ItemInstancemoved toinventory, andstats::SetErrornames the error ofStats::set_item(#665). -
abi::ABI_VERSION, a hash of the committed ABI layout, replacesABI_MAJORandABI_MINOR;Headercarries it asabi_version, and the C header definesENSHWICK_ABI_VERSION. The loader, a mod’s host check andcargo enshwickload only mods built for exactly this version and name the release to rebuild any other for (abi::OTHER_ABI).cargo enshwick newpinsenshwickwith=. Every mod needs a rebuild (#657).
-
Load::world_storerefuses the namessettingsandsave, whose files the loader keeps in the same world folder, so a store no longer writes over the world’s settings (#680). -
Migrations run once per world, all or nothing: each world keeps its own record,
.migrations.toml, and a copy of the files each migration changed under.backup/, put back when a write fails or the game stops part way. A record or store that does not read turns the mod off with the reason instead of being skipped or read as empty (#670). -
StoreandWorldStorefill every key a file lacks fromT::default(), so a store whose type gained a field still reads (#672). -
WorldStorewrites a value again at the next save when its background write failed, instead of dropping the change (#667).
[1.0.0-alpha.11] - 2026-10-28
Section titled “[1.0.0-alpha.11] - 2026-10-28”-
The
unstablefeature also holds what rests on engine facts not yet seen in the running game: the game rates (rates), changes ofField::MaxStackSizeandField::Slotsfrom a mod (refused withOffwithout the feature), the damage filters,events::PlayerDied, thekillerfields ofEntityDiedEvent, andLoad::add_recipe,add_recipe_withandderive_recipes(#649). -
Load::request_base_limitstakes up to 179 bases: the loader grows the game’s bases objects and keeps bases past 16 behind its array, on both sides, andBaseLimit::max_basesreads 179, or 16 on a build where the loader cannot arm every site it needs. A server holds the bases its mods asked for; a joined client with bases past 16 armed groups every base the server does, and one without groups 16.FakeHost::without_base_limitplays a build without the base code,FakeHost::without_bases_past_16a build that raises the zones but keeps 16 bases, andInstalled::requested_base_limitstells the largest request; it replacesbase_limit_raised. The docs ofaltars::groupingandaltars::base_limitname both requests (#647). -
The
unstablefeature holds what may still change in any release, so 1.0 promises only the rest:world,mapwithLoad::fog_of_warand the map markers ofui,actions,console, the script binding (script,#[derive(Script)],#[script]), calls (#[call],Load::serve_call,Load::caller,services::Calland its kin) with the described calls, events and points of script runtimes,Effects::teleportandEffects::ping, the knowledge revokes andLoad::on_knowledge_input,Load::request_base_limits, and the world edit variants ofWorldError. Each item says so in its docs, the Luau definitions markworldandcaller, and the book’s Stability chapter names what is stable and how the ABI versions from 1.0 (#643). -
Load::request_base_limits, behind the newunstablefeature, asks for up to 255 altars a Flame level (ABI 4.1,HostApi::request_base_limits), andBaseLimittells the game’s own bases and the most a mod may ask for, withBaseLimit::past_vanilla(#641). -
abi::DAMAGE_TYPES(ENSHWICK_DAMAGE_TYPESin C), the length of a hit’s damage amounts, andDamageTypeNew::index, a type’s place in them; the loader’s damage and stats code count by them too (#637). -
voxels::PER_METRE, the voxels a metre on every axis, which the loader’s terrain edits now read too (#632). -
RecipeKind::ComfortFurniture(comfort-furniturein a data pack, ABI codeRecipeKind::COMFORT_FURNITURE) for placed props that carry the item tag of the game’s Comfort Furniture crafting group; a prop with the Decorative tag too staysDecorative(#628).
Changed
Section titled “Changed”- Breaking: names the game has take its own.
DamageCause::Impact,FallDamageandSuffocated(DamageCheck::IMPACT,FALL_DAMAGE,SUFFOCATED) replaceHit,FallandDrowning;Rate::FactoryProductionSpeedandResourceDropStackAmount(RateId::FACTORY_PRODUCTION_SPEED,RESOURCE_DROP_STACK_AMOUNT) replaceWorkshopSpeedandResourceDrops;ExperienceGroup::ExplorationQuests(RateId::EXPERIENCE_EXPLORATION_QUESTS) replacesExploration;Teleport::search_best_spawn_positionreplacesbest_spawn, andSpawn::orientationwithorientation_yawreplacesfacingandfacing_yaw. Names that are enshwick’s own say so in their docs (#648). - Breaking:
abi::TickData::elapsed_steps()is gone; read the field of the same name. Its accessors no longer guess for loaders of an older minor, which the ABI never pairs with a mod, and the ABI docs and the C header drop their per-minor history notes (#645). - Breaking:
SkillNodeisabi::SkillNodealone;worldno longer re-exports it (#643). - Breaking:
WorldErrorisenshwick::WorldError, shared by every module that acts on the server’s world, andComponentTypeisecs::ComponentType, resolved withComponentType::resolvein place ofWorld::component_type;WritableType::resolvereplacesWorld::writable_type.ecs::Components::componenttakes aComponentTypein place of its hash. Inventories, loot and the kill credit ofEntityDiedEventno longer need the world’s reads (#642). - Breaking: ABI 4.0. Filter inputs and the death record take the game’s
names.
Load::on_crafthands the game’sCraftRecipeEvent(CraftRequestis gone) andCraftChecknames its fieldscrafting_operator_id,crafting_station_id,recipe_idand au16recipe_amount.PlayerDeathDatahascause_guid,was_deadly_fogand the causesIMPACT,FALL_DAMAGEandFOG.DamageCause::FogandDeadlyFog(DamageCheck::FOG,DEADLY_FOG) replaceShroudandShroudDeath.BedChecknamesnpc_idandbed_id. The zone check isLoad::on_building_zone_checkwithBuildingZoneCheck(HostApi::building_zone_check_filter), and the fake host’sbuilding_zone_check(#635). - A mod whose
initreturnsErr(Off)hands the loader its reason: the Mods screen shows it under the mod and the log names it, anOff::textin the reader’s language (#634). - Breaking:
Entityhas no serde form, since each load of a world numbers its entities anew;Prophas none either, and aCapturekeepsCapturedProp, the item and transform without the entity. Entity data refuses an entity no load finds again, a player’s character, withSetError::NotKept(Status::NOT_KEPT, ABI 3.5) (#631). - Entity and item data keep each value under its entity’s place, the template and position as the save keeps them or the container and slot, and find it again after a load; a value no place names for certain goes aside in the world’s file and never attaches again (#631).
- With the base limit raised, every altar zone the game lists joins its base: the game copied only the first 16 into its bases, so zones past 16 had no comfort, crafting from chests or survivors (#641).
- “Remove water” on a Flame Altar clears every zone of its base, not only the first 16 (#641).
- After a restart that followed any added or removed entity, an entity or item data value could land on another entity of the same template; values now follow their entity’s place. Values of a file written before this stay aside, attached to nothing (#631).
- Item data on a leaving player’s items goes aside in the world’s file instead of being dropped with the items the game removes, and a place keys exactly as the save keeps it, a negative axis included (#640).
[1.0.0-alpha.10] - 2026-10-28
Section titled “[1.0.0-alpha.10] - 2026-10-28”Off::text(key, args)turns a feature off with a text of the mod’s texts: the Mods screen, the status summary and the log show it in the reader’s language. AConfigError::textturned into anOffstays a text (#630).Hold::set_text(reason, key, args)sets a hold whose reason the log shows in the reader’s language while the mod’s texts are loaded, and asreasonwhen they are not; a hold file of one line reads as before (#630).BuffTypeIdandNpcId, the game’s id of a survivor or other NPC, are ABI ids with aShape(ABI 3.4); they print as their number, points and events carry them, and a Luau script reads and answers them asbuff_type_idandnpc_id. Every id the game derives from a GUID hasnamed(#623).loot::LootContainerId, the game’s name for a loot roll’s node and labels (#623).RecipeKind::Decorative(decorativein a data pack, ABI codeRecipeKind::DECORATIVE) for placed props that carry the item tag of the game’s Decorative crafting group, soRecipes::Kind,Rate::RecipeOutputandRecipeView::kindpick decorations by the game’s own grouping (#616).- The title screen shows the loader’s line under the game’s version,
Enshwick 1.0.0-alpha.9 · mods: 6, with the mods off and a warning when the game version leaves features off (#624). Language::OFFERED, the languages the game’s settings offer, andTexts::missing_in(languages), each language’s missing texts, so a mod’s test holds its texts complete for every offered language (#618).- Every id type prints as its number (
Display):Entity,ItemId,PlayerKey,RecipeId,AffixId,SkillNodeandKnowledgeIdgo into a log line as they are (#615). KnowledgeIdnames a knowledge value: a recipe’s, a quest’s or any other the world or a player keeps; aRecipeIdconverts into it (ABI 3.2) (#615).ItemId::from_guid,RecipeId::from_guidandKnowledgeId::from_guidgive the game’s id of a GUID with its type, in a constant too (#615).KnowledgeIdandSkillNodehave aShape, so services, events and points carry them; a Luau script changes an answer of any id type (#619).Load::on_tickruns a tick handler on a period of wall time and returns aTickPeriod, whoseset_everychanges the period while the game runs;Load::on_every_stepruns one on every server step. A step a handler skips never enters the mod (HostApi::subscribe_tick,HostApi::set_tick_every,TickHandle, ABI 3.3) (#614).TickDatacarries the steps and the time since the handler’s last call, the average step interval and, with timed diagnostics, the mod’s recent cost per handler call:elapsed_steps,elapsed,step_intervalandcost, withTickData::newandwith_elapsedfor tests (ABI 3.3) (#614).- The fake host runs steps as the loader does with
Installed::tick(#614). Map::framereturns aMapFrame: where the scene’s map starts, how far it reaches and the size of its cells, in metres, read from the game’s data once per scene like the markers (ABI 3.4,HostApi::map_frameandMapFrameInfo); the fake host serves one withFakeHost::map_frame(#627).
Changed
Section titled “Changed”-
Breaking:
survivors::SurvivorIdisNpcId; the buff and survivor ABI structs,HostApi::remove_buff,summon_itemand the survivor status merge takeBuffTypeIdandNpcId, andBuffTypeId::from_guidtakes aGuid. The fake host’ssummon_itemsandsurvivor_statuscarry the ids (#623). -
Breaking:
Roll::nodeandRoll::labelsareOption<LootContainerId>,Nonewhere the game has none, andSource::nodes,labels,with_nodesandwith_labelstakeLootContainerId(#623). -
Breaking:
Load::on::<Ticked>runs the handler everyTicked::DEFAULT_EVERY(100 ms) instead of on every step; so do Luau’senshwick.on("Ticked", ...)and the scheduler, whosenext_tickruns on its next pass, within that period.Load::on_every_stepkeeps the old timing (#614). -
Breaking:
StepClock::step(instant)isStepClock::advance(elapsed, steps), and the mod’s step clock moves by the time its ticks carry, without reading the clock itself (#614). -
The loader reads the clock once per server step and hands that reading to every part of the step that needs the time (#614).
-
abi::read_headedcopies a struct in one move when the writer’s struct covers all of it, so a larger event struct costs a handler no more (#614). -
Breaking:
MapSnapshotcarries the map’sframe, andMAP_SNAPSHOT_FORMATis 2 (#627). -
Breaking:
Guid::idisGuid::fnv1a, the bare hash, andId::idis gone;ItemId::from_guid(id.guid())and its siblings take their place.World::used_itemreturns anItemId, andmigrations::current_idtakes and returns one (#615). -
Breaking: the knowledge calls,
KnowledgeChanged,QuestCompletedand their ABI structs takeKnowledgeId;Knowledge::questsreturns them.SkillNodeis an ABI type, andabi::SkillCheck::nodeandHostApi::skill_overridetake it (#615). -
Breaking: the fake host’s
survivor_lookuptakes aSurvivorIdandOption<Entity>for no entity and returns the mod’sAnswer;set_knowledge,grants,revokesandaccount_changescarryKnowledgeId, andNonefor the world (#615). -
A text missing in a regional language comes from its main variety before English:
pt-brfrompt,es-mxfromes-419andes,fr-cafromfr,nbfromno(Language::lookup_order) (#618). -
The loader’s own texts sit in a file per language, and every console answer, the status summary, the per-mod costs, the conflict report and the interface demo follow the reader’s language (#618).
-
A player’s game tells the server its language when it joins; the loader’s answers, join notes and mod names to that player follow it, and on a server
i18n::language()is that player’s language while the loader asks a mod about the player. The loader’s settinglanguagesets the language of its console. The join message protocol moved to version 2 (#620). -
ConfigError::text(key, args)refuses settings with a text of the mod’s texts, which each player reads in their own language; thevalidateof theConfigderive takes any error that converts intoConfigError(String,&stror aConfigError) (#620). -
The Mods screen scrolls its lists in the game’s own scroll area instead of paging them, and a text setting takes typed text in the game’s own text field, set on Enter. A game build without either keeps the pages and the read-only line, and the log names what is missing (#625).
Removed
Section titled “Removed”- Breaking:
Load::modify_recipes,RecipeEditandmodify_recipes_in; a data change throughLoad::change_recipesor aRate::RecipeOutputchanges recipe counts by kind (#616).
- The Mods screen shows a secret setting as “(secret)” and never its value (#626).
[1.0.0-alpha.9] - 2026-10-27
Section titled “[1.0.0-alpha.9] - 2026-10-27”code::find_each_uniquefinds many patterns in one pass over the code, each with the resultPattern::find_uniquegives (#598).World::account_actionasks the game to kick, ban or unban an account (AccountAction); a ban of an account that is not online goes straight onto the server’s ban list (HostApi::account_action,AccountActionType). The fake keeps a ban list (Installed::banned,removed) (#586).- With
allowlist = truein the loader’s settings, a dedicated server lets in only the accountsmod-data/enshwick/allowlist.txtlists, and its administrators; the console’senshwick allowlist add|removeandWorld::set_allowlistedchange the list,World::allowlistedreads it (HostApi::allowlist_set,HostApi::allowlist_has, ABI 3.1). The fake keeps the list (Installed::allowlisted) (#602). error_once!andinfo_every!, so every level that has a once or a periodic macro has both (#597).
Changed
Section titled “Changed”World::account_actionrefuses a kick or a ban of a hosted game’s host, succeeds for a ban of an account on the ban list already, and refuses a ban the game’s list does not take instead of answering that the action is missing; the console says so in its own words. The fake takes the host withFakeHost::host_key(#606).- The crate docs say to depend on the crate from crates.io and carry a module map, the feature table and the target; docs.rs builds every feature. The Luau definitions describe events, codes and permission bits in plain words, without Rust paths (#604).
- Breaking: the ABI is 3.0. A mod built for ABI 2 is refused and needs a
rebuild against this release; the C header’s
ENSHWICK_ABI_MAJORis 3 (#599). - Breaking: ids have their own types across the ABI and the safe API.
Entity,ItemId,PlayerKeyandRecipeIdlive in the ABI module, re-exported from the crate root, and the C header declares them asEnshwickEntity,EnshwickItemId,EnshwickPlayerKeyandEnshwickRecipeId;ecs::Entityis nowenshwick::Entity. Account keys (Player::key,Peer::Player, actions’ player lists,Knowledge::grant_account,World::account_actionand the allowlist), item ids (inventory ops and slots, drops, interactions, vetoes, summons,ItemInstance, terrain materials) and recipe ids (CraftRequest,CraftRecipeEvent) take them, and the fake host’s methods do too.affixes::AffixIdnames an affix in this process (Load::define_affix,Affixes::info,Line::affix), andworld::SkillNodea skill node (Skill::node).Summon::ammois anOption. Point and event schemas name the four ABI ids as built-in types, socargo enshwick pointwrites them as the API’s types (#608). - Breaking:
Load::onsubscribes to typed game events too, as Luau’senshwick.ondoes:load.on::<EntityDiedEvent>(..)replacesload.on_game.events::Kindis the one traitontakes; the loader events’EVENTconstant and raw read moved toevents::LoaderEvent, whichFakeHost::raisetakes.game_events::Kindis gone (#597). - Breaking:
Load::event_typeandLoad::event_typesaregame_event_typeandgame_event_types, the names Luau uses;FakeHost::event_typeisgame_event_type(#597). - Breaking:
Load::on_skilltakes theSkilland finds its node itself;Load::skill_nodeandSkillCheck::nodeare gone, andSkillCheckis#[non_exhaustive](#597). - Breaking:
Load::buff_modifiersisadd_buff_modifiers(#597). - Breaking:
mods::all()lists the loaded mods; the crate root’senshwick::mods()andHost::{mods, join_missing, replaced}are gone, so each list has one call:mods::all,mods::join_missing,mods::replaced.mods::labelis hidden:ModEntry::labelnames a mod (#597). - Breaking:
ReadPackError::TooLargenames thelimitthe file broke, andPackFiles::read_dirrefuses a pack with more thanMAX_ICONSicons (ReadPackError::TooManyIcons) or an icon overMAX_ICON_FILE; icon PNGs pasticons::MAX_SIDEpixels do not decode (#596). mods::join_missingleaves out an entry with new text once the loader keeps 64 KiB of text servers advertised (#596).declare_mod!exports the five functions under their C names only outside test builds, so one test binary can declare several mods (#591).
- A server rates the settings queries, setting changes and actions queries of a player who is no administrator, 2 a second in bursts of 8 (#596).
- Settings errors name the key and the expected type, and the line where
the text is at hand, never the value: the settings check’s reason, the
settings read at start, table settings, join values, migrations, and
ConfigErrorandMigrationErrormade from a TOML error. The warning for a value held to its range no longer shows the old value (#594, #595). Schema::parserefuses a field or group key with an empty part, such asauth..token, andLoad::table_configa field with an empty key; the loader refuses such a schema, and the mod’s warning names the key (#593).
Removed
Section titled “Removed”- Breaking: the retired
HostApientriesretired_command,altar_zones_control,set_altar_zonesandaltar_limit, withAltarZoneSizeandAltarLimitFn; every later entry moves up. The ABI docs no longer say in which minor of ABI 2 a field came (#599). - Breaking:
Load::settings, which read the settings file into anyDeserializetype past the stages,syncandsecretchecks: deriveConfigand callLoad::config(#597).
[1.0.0-alpha.8] - 2026-10-27
Section titled “[1.0.0-alpha.8] - 2026-10-27”packs::script_fileslists the scriptsPackFiles::read_dirwould read, without reading them. The loader lists a Luau mod’s scripts each time it looks, so a script added, removed or renamed while the game runs reloads the mod withdev_reloadas an edited one does (#585).- A Luau mod reads and changes inventories through
enshwick.inventory:slots,count,item_info,give,take,destroy_slot,move_slotandmove_all, the done function getting theOutcomeas a table withDoneandOpErrorby name.Inventories::slotsandInventories::countread an inventory on the server’s game thread without aReader(#581). - A Luau mod calls another mod’s call with
enshwick.caller(description), from the modulecargo enshwick call --luauwrites; the input’s fields are numbers, booleans, entities and GUIDs, each checked against its layout hash (#577). - Calls, described services:
#[call]declares one function from arepr(C)input to an answer,Load::serve_callserves it andLoad::callergives aCallerthat runs it from any thread (services::Call,CallError);manifest!(calls: [..])puts its schema into the manifest.DescribedCall,Load::described_callerandLoad::serve_described_calldo the same with bytes, for a runtime that knows a call from its schema. The loader matches callers by name, major, fields and sizes once every mod is initialised (HostApi::serve_call,find_call,call,CallSpec, ABI minor 95). The fake serves and calls them (Installed::serve_call,call,served_calls). A call’s input and answer have no padding, whichShape::PADDING_FREEreports (#574). Load::on_described_mod_eventandLoad::define_described_event(services::DescribedEvent,DescribedEmitter) hear and send a mod event described at run time, its data as bytes in the definer’s layout;manifest!(events: [..])puts the schema of each listed#[event]into the manifest, andModEvent::SCHEMAandDESCRIBEDcarry it (#571).load.fog_of_war()returns the client’sFogOfWar, which the loader copies as the game uncovers it:FogOfWar::state,readandcoverageread what the player has uncovered, as aFogStateandFogImage; thefog_openandfog_readentries andFogInfo(ABI 2.94) (#564).Change::in_tablechanges an item’s count, chance or weight in one fill table alone, after its changes of every table;Vanilla::loot_tablefinds the table a container template rolls, with how many containers share it; a data pack’sloot.tomltakestable = [...]with the containers’ template names.FillTableLayoutandtemplate_tableread a template’s name and table (#570).Hold::for_worldholds the game for one world only (mod-data/<id>/worlds/<key>/hold.txt): the loader stops the game as that world starts to load without the mod, before its save is read, and on a build it leaves vanilla at start;world_holds,held_worldsandWORLDS_DIRread them. A data pack that raised a stack size now holds the worlds saved with it, not the whole data folder (#563).Field::StationandChange::stationmove a vanilla recipe to another workshop (DataField::RECIPE_STATION, ABI minor 93): the loader writes the recipe’s workshop and lists it in the client’s crafting menu at the new station alone, from the next start; a data pack’srecipes.tomltakesstation = "<station item>".menu::move_recipesandrecipe_workshopsdo the same for a mod’s own patches (#567).Items::Backpacksselects every backpack for a change ofField::Slots, which now reaches a backpack’s own inventory too, for backpacks made after it (DataSelect::BACKPACKS, ABI minor 92); a data pack takesitems = "backpacks", andItemTraits::backpack_slotsreads a backpack’s size (#566).Load::extend_described_pointlinks into an extension point described at run time (points::DescribedPoint,DescribedField), the input and the answer as bytes in the owner’s layout, as a script’s schema gives them; the loader checks the layout hashes as for a typed link (#569).Load::change_recipeschanges the output count, cost or time of every vanilla recipe a selection picks:Recipes::Kindby what the recipe makes,Recipes::Workshopby where it is made, read from the game’s data by the loader (DataSelect::RECIPE_KIND,DataSelect::WORKSHOP, ABI minor 91); a data pack’srecipes.tomltakeskind = [...]andworkshop = [...]for the same, andRecipeKind::namegives the names (#562).Map::snapshottakes the map as aMapSnapshotof players, Flame Altars with their bases, and markers, plain data for a process outside the game;MapSnapshot::to_bytesandfrom_byteswrite and read it in a versioned format (MAP_SNAPSHOT_FORMAT) (#560).script::game_eventslists every typed game event for script languages (GameEventKind); the game event structs, masks and values convert for scripts (a mask as its bit names, a value as its name) (#565).load.map()returns theMapof the game server:Map::markersandMap::markers_inlist the world’s map markers, each aMapMarkerwith its position, itsMapMarkerTypeId(the key of the game’s marker type registry) and its label’s text tag;Map::waypointreads the waypoint a player set (#557).- The
world_quietentry answers whether a mod is on the server’s game thread at a quiet moment while a world runs, where it may read live components (ABI 2.90) (#557). Load::table_configreads settings described by aconfig::Schemaat run time, with the file, checks, stages, Mods screen and join values of a typedConfig;config::TableConfig::on_changefollows them, andSchema::templatewrites the file (#561).- A pack’s
pack.tomldeclares settings in[[setting]]tables (PackSetting,PackManifest::settings_schema), checked as it is read (#561). World::can_buildtells whether the server lets a player edit a box:CanEditWorld, andCanEditBaseinside a building zone, as the game’s terrain tools decide, plus two tests from the game’s building cursor, the world’s building area and strict no-build zones; a refusal is aBuildRefusalwith the game’sCursorFlagnames (#547).World::transactionwrites terrain edits as one transaction at the server’s quiet moments, 64 bricks a step, andWorld::undoputs every brick it touched back, refusing when one has changed since;World::transaction_statusfollows it (#548).WorldError::OutsideWorld(Status::OUTSIDE_WORLD): voxel reads, terrain edits and transactions past the world’s edge or above 1,024 metres are refused, where the game would read air (#548).World::props_inlists the props in a box, the things players placed from items, each with itsItemIdandWorldTransform, told apart from the things a world comes with by the template their item places (#550).World::capturetakes a region of up toCAPTURE_TILESreads of 32 metres a side as aCaptureof its voxels and props, counted from its corner;Capture::rotatedturns it by quarter turns about the vertical andCapture::translatedmoves it (#550).ItemId, the game’s number for an item, andWorldTransform, a position in metres with an orientation (#550).Capture,VoxelBox,Voxel,VoxelMaterial,VoxelPos,Entity,ItemId,PropandWorldTransformimplement serde’sSerializeandDeserialize; aVoxelBoxread must hold one voxel per place and end inside the world’s coordinates (#550).ItemData::placed_entity, the GUID of the template a player places from the item, fromHostApi::item_info; ABI minor 88 (#550).Transaction::write_voxels,erase_blockandplace_blockwrite voxels, tear down building voxels and place building blocks inside a transaction, with the same undo; blocks and tear-downs raise the game’sBuildingPlaceEventandBuildingTearDownEvent.VoxelBox::new,setandmoved_tobuild boxes to write (#551).World::transaction_foracts for a player: the loader checks the player’s rights for every change before it writes, and a refusal shows asTransactionStatus::NotAllowed; the op kinds, records andtransaction_commit_forare ABI minor 89 (#551).- The conflict report lists code patches refused over another mod’s
bytes, vanilla values one mod’s set overrides with both values, and
components several mods write; the loader compares the game’s code with
the executable on disk while it starts and names the DLL or mod that
changed it outside the API, after each load,
initandready(#555). - A data pack’s
items.tomlchanges the stack size or container slots of every vanilla item of some categories (category = ["Materials"]), every item that stacks (items = "stackable") or every container (items = "containers"), through the selectionsLoad::change_itemsmakes;Pack::selectionslists them, andItemCategoryMask::NAMESandItemCategoryMask::namedtake the game’s category names (#558). Status::STATIC_HALF(ABI minor 94),WorldError::StaticHalfandFakeHost::static_half: a write to the static half of a component type, the set-up data every entity of a template shares, is refused (#568).Transaction::place_prop,remove_propandremove_prop_discarding_stateplace and remove props inside a transaction, with undo;World::transaction_entitieslists the props a transaction placed. A prop that holds state a player would lose (items, growth, a production queue, assigned survivors, written text, fuel, logic wiring, a logic trigger) is never removed or taken away by an undo unless the mod opts in:WorldError::HoldsState(PropState)names what it holds. The op kinds, records andtransaction_entitiesare ABI minor 96 (#552).World::persiststells whether a save keeps changes in a box: the game saves a world only inside its bases’ zones, so props, blocks and terrain changed elsewhere are gone after a restart, a mod’s as a player’s.HostApi::world_persistsis ABI minor 96 (#552).WorldError::NotAProp(Status::NOT_A_PROP, ABI minor 96): creatures placed from items (animals, pets, survivors) and flame altars are no props; prop removal refuses them in either mode (#552).
Changed
Section titled “Changed”#[point]and#[event]refuse an input, answer or data with padding, as#[call]does, since a described link or listener reads every byte: add the bytes as fields. The example trading post’spricegains acount(#587).Map::markersreads the markers the scene places from the game’s data through the newmap_markersentry andMapMarkerInfo(ABI 2.97), once per scene;MapMarkerno longer names an entity (#573).- An item a mod or pack changes by name keeps that change over its own selection of the same field, so a selection can leave out exceptions (#558).
Terrain::{add,dig,flatten}write nothing and fail withWorldError::NotLoadedunless the whole area the edit can reach is loaded; the game would compute such an edit against air and merge it onto the ground once the area loads (#548).World::entitiestakes the world by value, as the otherWorldcalls do (#550).- Item data (
Inventories::item_info,HostApi::item_info) and the item checks ofWorld::props_inandTransaction::place_blockwork from world start: the loader finds the item registry without waiting for a player to join (#551). World::props_inandWorld::captureleave out creatures placed from items (animals, pets, survivors) and flame altars, which are no props, and answerWorldError::Missingon a game build without their marks (#552).
- A Luau mod’s answer to a point and its mod events take an enum over a
64-bit integer,
usizeandisizeincluded, as a number both ways; before, every such value was refused (#587). - The loader’s profile names the survivors feature
survivors; it showed a mod id (#574). - The loader and the fake leave a mod event subscription idle when it reads more bytes than the definer sends (#571).
Map::markerslisted no marker on a dedicated server, whose marker entities the entity walk does not find (#573).World::componentandWorld::getread the static half of a component type, such asFuelSetup, as the template’s set-up values; they gave the data of its dynamic half,DynamicFuelSetup, before (#568).
[1.0.0-alpha.7] - 2026-10-26
Section titled “[1.0.0-alpha.7] - 2026-10-26”load.voxels()reads up to 64³ voxels of the server’s world withVoxels::readandVoxels::sample, on the game thread at a quiet moment, asVoxelBoxofVoxels;Status::NOT_LOADEDandWorldError::NotLoadedname a part of the world that is not loaded (#541).Load::change_itemschanges a stack size or container slots of every vanilla item a selection picks (Items::Category,Items::Stackable,Items::Containers), read from the game’s data by the loader;ItemCategoryMasknames every item category (#540).Load::declare_changedeclares a change of a vanilla value at init whose value the mod sets any time later through itsChangeHandle(set,reset); the loader merges it with every mod’s and pack’s changes and builds what it reaches again in place, so a stack size or chest size can follow a per-world setting (#542).- The loader keeps every stack size above the game’s that a world was saved
with (
mod-data/enshwick/kept-stacks.toml) and serves at least that size from the start, so lowering a size or removing the mod that raised it never cuts a saved stack; while any size is kept it holds the game on a build it would leave vanilla (#544). scriptdescribes the API for script languages beside the Rust items:#[derive(Script)]for types,#[script(<part>)]for the methods a script may call, a script entry for every loader event, andNAMESPACES(#543).- A data pack folder with a
main.luaureads its scripts:PackFiles::scripts,SCRIPT_MAIN,SCRIPT_EXTENSION,DEFINITIONS_SUFFIX,MAX_SCRIPTS,MAX_SCRIPT_DEPTHandReadPackError::TooManyScripts; scripts count in the pack’s hash (#545).
- Each mod handle has a scheduler queue of its own, so one copy of the API can run tasks for several packs and scripts (#543).
Changed
Section titled “Changed”ItemCategoryMasklives incontent::categories, beside the selections that use it, instead ofaffixes(#540).
[1.0.0-alpha.6] - 2026-10-26
Section titled “[1.0.0-alpha.6] - 2026-10-26”content::loot_tablesreads and changes the random loot table’s stack sizes and every stack of a fill table; a data pack’sloot.tomlchangesstack_size,count,spawn_probabilityandweightunder the game’s own names (#523).altars::base_limitnames the most altar zones and bases the game groups now, and the zones its own grouping takes (#529).ContainerKinds,ItemCategoryMaskand the event masks have aconst fn union, so a combined set can be aconst;|gives the same (#539).
Changed
Section titled “Changed”- The altar limit is a chain any mod joins:
Load::on_altar_limittakes a filter that sees the Flame level, the game’s own count and the count so far in anAltarLimitand changesallowed, in load order. The loader keeps every answer within the zones the game groups, and owns the raised maximum of 32 zones in 16 bases;Load::raise_base_limitputs it in force fromMod::readyon (#529). Worldis one pointer to what the mod resolved once, instead of 320 bytes: a copy is cheap, and passing it by value or moving it into a closure no longer tripsclippy::large_types_passed_by_value. Its methods takeself, so calls read the same (#536).
Removed
Section titled “Removed”VANILLA_ALTARS_PER_FLAME_LEVEL,vanilla_altars,VANILLA_ALTAR_ZONESandRAISED_ALTAR_ZONES: a filter reads the game’s own count fromAltarLimit::vanilla, andaltars::base_limitnames the zones (#529).
[1.0.0-alpha.5] - 2026-10-26
Section titled “[1.0.0-alpha.5] - 2026-10-26”Rate::RecipeOutput(kind)multiplies what the recipes of eachRecipeKindmake, after every mod’s own recipe patch;RecipeEdit::scale_output_byscales by a fraction andRecipeKind::ALLlists the kinds (#501).progress::SkillandLoad::skill_nodegive the node of a skill the platform names on the running game build (#494).game_events::EquipmentSlot, the slotEquipmentChangedcarries, andinventory::OpError, why an inventory operation failed, both named as the game names them (#494).
Changed
Section titled “Changed”- Altar zone sizes are a chain any mod joins:
Load::on_altar_zoneadds a filter that sees each altar’s zone so far, the vanilla one first, in load order, andZoneSizes::changedasks for a new sizing from any thread (#499). - The loader owns the event loop, server loop and task worker hooks:
on_loop_wait,on_server_waitandcap_task_workerskeep their signatures but run through the host, handlers of several mods run in load order and the lowest worker cap wins; a fake host test runs them withInstalled::loop_wait,server_waitandtask_workers, no longer throughmid_hooksorrun_at(#486). - Game settings, hit damage types and attack categories, experience sources, altar actions, equipment slots and inventory error codes resolve through engine ids and the game’s constant names; no engine number is compiled into a mod (#494).
DamageTypesandAttackCategorieskeep their bits private and combine with|;EquipmentChanged::slotis anEquipmentSlotandOpResult::erroranOption<OpError>(#494).World::writable_typeaccepts the copies the game keeps for clients; a write to one is refused withWorldError::Refused(#494).- Names of things the game names itself are the game’s reflected names in Rust casing; the game settings enums read their values by the game’s constant names (#506):
| Old | New |
|---|---|
game_events::DamageTypes | game_events::DamageTypeMask |
DamageTypes::CUT, PIERCE, BLUNT | DamageTypeMask::PHYSICAL_CUT, PHYSICAL_PIERCE, PHYSICAL_BLUNT |
DamageTypes::FIRE, ICE, SHROUD, LIGHTNING | DamageTypeMask::MAGICAL_FIRE, MAGICAL_ICE, MAGICAL_FOG, MAGICAL_LIGHTNING |
game_events::AttackCategories | game_events::AttackCategoryMask |
AttackCategories::AREA | AttackCategoryMask::AOE |
game_events::ExperienceSource | game_events::ExperienceSourceType |
game_events::AltarAction | game_events::FlameAltarActionType |
AltarAction::SetSpawn | FlameAltarActionType::SetAsPreferredSpawnAltar |
game_settings::Preset | game_settings::GameSettingsPreset |
game_settings::Difficulty | game_settings::GenericDifficulty |
game_settings::Amount (random_spawns) | game_settings::RandomSpawnerAmount |
game_settings::Amount (aggro_pool) | game_settings::AggroPoolAmount |
game_settings::StartleRepercussion | game_settings::TamingStartleRepercussion |
Settings::player_health | Settings::player_health_factor |
Settings::player_mana | Settings::player_mana_factor |
Settings::player_stamina | Settings::player_stamina_factor |
Settings::player_body_heat | Settings::player_body_heat_factor |
Settings::player_diving_time | Settings::player_diving_time_factor |
Settings::durability | Settings::enable_durability |
Settings::starving | Settings::enable_starving_debuff |
Settings::food_buff_duration | Settings::food_buff_duration_factor |
Settings::hunger_to_starving | Settings::from_hunger_to_starving |
Settings::shroud_time | Settings::shroud_time_factor |
Settings::tombstone | Settings::tombstone_mode |
Settings::glider_turbulence | Settings::enable_glider_turbulences |
Settings::weather | Settings::weather_frequency |
Settings::fishing | Settings::fishing_difficulty |
Settings::mining_damage | Settings::mining_damage_factor |
Settings::plant_growth | Settings::plant_growth_speed_factor |
Settings::resource_drops | Settings::resource_drop_stack_amount_factor |
Settings::factory_speed | Settings::factory_production_speed_factor |
Settings::perk_recycling | Settings::perk_upgrade_recycling_factor |
Settings::perk_cost | Settings::perk_cost_factor |
Settings::experience_combat | Settings::experience_combat_factor |
Settings::experience_mining | Settings::experience_mining_factor |
Settings::experience_exploration | Settings::experience_exploration_quests_factor |
Settings::random_spawns | Settings::random_spawner_amount |
Settings::aggro_pool | Settings::aggro_pool_amount |
Settings::enemy_damage | Settings::enemy_damage_factor |
Settings::enemy_health | Settings::enemy_health_factor |
Settings::enemy_stamina | Settings::enemy_stamina_factor |
Settings::enemy_perception | Settings::enemy_perception_range_factor |
Settings::boss_damage | Settings::boss_damage_factor |
Settings::boss_health | Settings::boss_health_factor |
Settings::pacify_enemies | Settings::pacify_all_enemies |
Settings::startle | Settings::taming_startle_repercussion |
Settings::day_length | Settings::day_time_duration |
Settings::night_length | Settings::night_time_duration |
Settings::curse | Settings::curse_modifier |
- Typed game events and their fields take the game’s reflected names;
Block,killerandkiller_playerstay enshwick’s (#518):
| Old | New |
|---|---|
game_events::Hit | game_events::HitEvent |
Hit::attacker | HitEvent::root_source_id |
Hit::source | HitEvent::source_id |
Hit::target | HitEvent::target_id |
Hit::root_target | HitEvent::root_target_id |
Hit::weapon | HitEvent::weapon_pide_id |
Hit::attack | HitEvent::attack_category |
game_events::Died | game_events::EntityDiedEvent |
Died::entity | EntityDiedEvent::dead_entity_id |
game_events::LevelGained | game_events::LevelUpEvent |
LevelGained::player | LevelUpEvent::player_entity_id |
game_events::ExperienceGained | game_events::XpGainedEvent |
ExperienceGained::player | XpGainedEvent::player_entity_id |
game_events::CraftRequested | game_events::CraftRecipeEvent |
CraftRequested::player | CraftRecipeEvent::crafting_operator_id |
CraftRequested::station | CraftRecipeEvent::crafting_station_id |
CraftRequested::recipe | CraftRecipeEvent::recipe_id |
CraftRequested::amount | CraftRecipeEvent::recipe_amount |
game_events::Crafted | game_events::CraftRecipeSuccessEvent |
Crafted::workshop | CraftRecipeSuccessEvent::workshop_id |
Crafted::recipe | CraftRecipeSuccessEvent::recipe_id |
game_events::Interacted | game_events::AcceptOfferedInteractionEvent |
Interacted::player | AcceptOfferedInteractionEvent::guest_entity_id |
Interacted::target | AcceptOfferedInteractionEvent::host_entity_id |
Interacted::offer | AcceptOfferedInteractionEvent::offer_id |
game_events::Built | game_events::BuildingPlaceEvent |
Built::item | BuildingPlaceEvent::tracking_item_id |
game_events::TornDown | game_events::BuildingTearDownEvent |
game_events::PickedUp | game_events::BuildingPickUpEvent |
PickedUp::entity | BuildingPickUpEvent::picked_entity_id |
game_events::AltarUsed | game_events::FlameAltarEvent |
AltarUsed::player | FlameAltarEvent::player_entity_id |
AltarUsed::altar | FlameAltarEvent::base_entity_id |
AltarUsed::action | FlameAltarEvent::r#type |
game_events::LootOpened | game_events::LootInteractionEvent |
LootOpened::player | LootInteractionEvent::guest_id |
LootOpened::container | LootInteractionEvent::host_id |
LootOpened::take_all | LootInteractionEvent::loot_all |
game_events::EquipmentChanged | game_events::HandleEquipmentSlotChangedEvent |
EquipmentChanged::player | HandleEquipmentSlotChangedEvent::player_entity_id |
EquipmentChanged::slot | HandleEquipmentSlotChangedEvent::equipment_slot |
game_events::Revived | game_events::RevivedPlayerEvent |
Revived::player | RevivedPlayerEvent::target_entity_id |
Revived::by | RevivedPlayerEvent::source_entity_id |
Block::player | Block::owner_id |
- The other types, fields and constants the game names take the game’s reflected names; the ones enshwick computes say so in their docs (#525):
| Old | New |
|---|---|
damage::DamageType | damage::DamageTypeNew |
DamageType::Cut, Pierce, Blunt | DamageTypeNew::PhysicalCut, PhysicalPierce, PhysicalBlunt |
DamageType::Fire, Ice, Shroud, Lightning | DamageTypeNew::MagicalFire, MagicalIce, MagicalFog, MagicalLightning |
buffs::BuffKind | buffs::BuffSlotType |
BuffKind::Terrain | BuffSlotType::TerrainDebuff |
buffs::BuffId | buffs::BuffTypeId |
BuffType::id, kind, duration, saved, hidden | BuffType::buff_type_id, slot, default_life_time, is_saved, hide_in_ui |
Buff::id, entity, kind, duration | Buff::type_id, buff_entity_id, slot, life_time |
knowledge::KnowledgeKind | knowledge::KnowledgeType |
Known::kind, expected | Known::r#type, expected_flags |
weather::FrontKind | weather::WeatherPhenomenonEffect |
FrontKind::Clouds | WeatherPhenomenonEffect::None |
affixes::Rarity | affixes::ItemRarity |
affixes::Categories | affixes::ItemCategoryMask |
Categories::INSTRUMENTS, FISHING_RODS | ItemCategoryMask::INSTRUMENT, FISHING_ROD |
inventory::Category | inventory::InventoryCategory |
Category::UNKNOWN | InventoryCategory::INVALID |
ItemInfo::max_stack | ItemInfo::max_stack_size |
content::types::ITEM_REGISTRY, RECIPE_REGISTRY, WORKSHOP_REGISTRY | content::types::ITEM_REGISTRY_RESOURCE, RECIPE_REGISTRY_RESOURCE, WORKSHOP_REGISTRY_RESOURCE |
content::types::TEMPLATE, TEMPLATE_COLLECTION | content::types::TEMPLATE_RESOURCE, TEMPLATE_COLLECTION_RESOURCE |
content::types::UI_IMAGE, UI_BUNDLE | content::types::UI_TEXTURE_RESOURCE, FB_UI_BUNDLE |
content::items::Stat | content::items::ImpactUiValue |
Stat::label, format | ImpactUiValue::loca_id, value_format |
content::items::Meter | content::items::FuelSetup |
Meter::max | FuelSetup::max_fuel_charges |
changes::Field::MaxStack, Time | changes::Field::MaxStackSize, CraftingDuration |
terrain::Material | terrain::TerrainTerraformingConfig |
Material::id, item, health, flattens | TerrainTerraformingConfig::terrain_material, terrain_item, health_points, can_be_flattened |
loot::Offer | loot::InteractionOfferRuntime |
Offer::guest, accepted_at, disabled | InteractionOfferRuntime::guest_id, last_accept_time, is_disabled |
Container::empty | Container::is_empty |
effects::NpcOrder | effects::NpcCommandType |
NpcOrder::GoTo | NpcCommandType::GoToPosition |
TimeOfDay::day_length, night_length | TimeOfDay::day_time_duration, night_time_duration |
Removed
Section titled “Removed”control_altar_zones,ZoneControl,ZoneSizeandSetSizesError(#499).progress::AIRBORNE_ARCHITECT,OpResult::TOO_LARGE,OpResult::NO_ROOM,ExperienceSource::from_rawandAltarAction::from_raw(#494).- The game settings enums’
from_valueandvalue(#506).
[1.0.0-alpha.4] - 2026-10-26
Section titled “[1.0.0-alpha.4] - 2026-10-26”rates: a mod declares aRatewithLoad::rateand sets its factor; the loader scales experience by group, workshop speed, resource drops, comfort, skill points per level and loot stacks by the product of every mod’s factor (#445).Load::event_types()lists every game event type the running game build has (#461).RecipeView::kind()andRecipeKindtell a building block, a roof, overgrowth or terrain from other recipes by the output item’s data (#469).i18n::MOD_NAMEandi18n::MOD_DESCRIPTION: a mod’s texts give its name and description in the player’s language on the Mods screen, in join notes, the console and the status summary (#470).- A dedicated server runs lines typed into its console window or appended to
mod-data/enshwick/commands.txt, asenshwick ...tools or as<mod id> <action>(#440, #452). The tools includeenshwick mods,world,entity,placed,reload,kick,banandunban(#455). - A DLL in
mods/without the Enshwick interface stays loaded as a native mod and is listed on the Mods screen and instatus.log(#415). logs/enshwick/report.md, one file a player attaches to an issue (#418).
Changed
Section titled “Changed”-
enshwickandenshwick-gamedatarequire the exact version of the crates they are released with, so an olderenshwicknever resolves a newerenshwick-macros(#484). -
A mod id without an author part is refused whatever ABI minor the mod was built for. Rebuild a mod built for ABI minor 69 or older with an
<author>.<name>id (#436). -
Game events, content layouts and content types resolve through engine ids the loader maps to the running build;
content::typesareResourceTypehandles (#460, #461). -
rename_settingandremove_settingtake dotted keys and move a setting into or out of a table (#464).
Removed
Section titled “Removed”game_events::EVENT_TYPE_NAMESandKind::TYPE_NAME(#461).
[1.0.0-alpha.3] - 2026-10-26
Section titled “[1.0.0-alpha.3] - 2026-10-26”- Mod ids have an author part,
<author>.<name>, each part of[a-z0-9-], at most 64 characters;abi::is_valid_idchecks one, andcargo enshwick newtakes the new form (#378). was: [...]inmanifest!for a renamed mod: it replaces its old ids, answers requirements and extension points named by them, and on its first start takes over the old id’s settings file, texts andmod-datafolder.replaces: [...]andabi::is_valid_former_idaccept ids of the old form (#369, #378, #424).Migration::take_settingfor a mod that folds another one in and takes its settings (#369).points: [Type, ...]inmanifest!: a mod lists the extension points it defines, and their schemas go into its DLL.cargo enshwick pointwrites another mod’s point definition from that DLL (#394).#[config(group)]: a setting that is aConfigof its own becomes a table of the settings file, keyedgroup.fieldon the Mods screen and the console (#399).- A list of up to 16 numbers with a range shows a slider per element on the
Mods screen and takes
key[i]on the console;#[config(first = n)]and the text<key>.elementlabel the elements (#403, #425). DamageCause::NAMEDlists every damage cause the API names (#400).Texts::languages()andTexts::untranslated()for a test that a mod’s texts have no gaps (#397).- The stub loads every DLL in
mods/chain/before the loader, so another mod’s own proxy DLL runs beside Enshwick (#414).
Changed
Section titled “Changed”- Game memory is read only as types valid for any bytes, through
enshwick::raw::read_atandread_ptr_at.abi::Headedis anunsafe traitthat requiresZeroable(#380). loot::nearmoved toworld::near(#401).- The fake host’s builder is split by domain;
Installed::check_settingsreturnsSettingsRefused(#368). - A number outside its range in a settings file is held to the range with a warning instead of refusing the whole file (#425).
- Of two files that declare one mod id, the highest version runs (#365).
Removed
Section titled “Removed”points::safes,points::survivors_per_altar,points::flame_altar_countandpoints::area_loot: the API declares no mod’s points. A mod that extended one writes its definition withcargo enshwick point(#394).- The
enshwick-reflectcrate; its reader isenshwick_gamedata::reflect(#421). - The probe and research mods moved to devtools-mods (#363).
[1.0.0-alpha.2] - 2026-10-26
Section titled “[1.0.0-alpha.2] - 2026-10-26”- A mod’s actions run from the server’s console as
<mod id> <action> <values>, throughActionCall::CONSOLE(#336).
Removed
Section titled “Removed”- Chat commands:
commands,Reply,CommandContext,Load::add_command,Action::verbsandActions::set_language. Players and administrators use actions on the Mods screen, and servers the console (#336).
[1.0.0-alpha.1] - 2026-10-26
Section titled “[1.0.0-alpha.1] - 2026-10-26”The first version on crates.io, as enshwick, with enshwick-macros,
enshwick-gamedata and cargo-enshwick (#347).