Loot containers
Цей контент ще не доступний вашою мовою.
enshwick::loot
reads the containers a dead enemy leaves, corpses and loot bags, and other
containers that dissolve once emptied. It reads only; empty a container
through Inventories. To put items into the loot a
container rolls, see Random loot.
Each check of the containers
Section titled “Each check of the containers”The game checks every such container each step in one ECS system,
loot::SYSTEM
(destroy_inventory_on_loot), on a worker thread.
load.on_loot_pass
runs a handler after each run of it in the server’s world, with a LootPass
that walks that run’s containers and reads any entity as one:
use enshwick::world::near;
fn init(load: &mut enshwick::Load<'_>) -> Result<(), enshwick::Off> { load.on_loot_pass(|pass| { let spot = [0.0, 0.0, 0.0]; let mut open = 0; pass.each(|c| { if c.is_open() && near(spot, c.position, 12.0, 4.0) { open += 1; } }); let _ = open; })}each leaves the system’s row where it found it, so the walk does not
disturb vanilla. Keep the handler short; it runs every step. A mod that walks
another system with the same reads uses the unsafe Containers from that
system’s own hook; see ECS inside systems.
Reading one container
Section titled “Reading one container”Container
holds what one container is and holds, read in one go:
| Field | Meaning |
|---|---|
entity | The container. |
position | Where it stands, in metres; y is up. |
is_empty | Whether it holds nothing, as the game last recorded. |
expires | Whether it despawns on its own after a while (LifeTime). |
area_loot | Its AreaLootOverride: Some(true) when area loot may take it, Some(false) when excluded (items a player dropped), None without one. |
offer | Its interaction offer, an InteractionOfferRuntime; None without one. |
An InteractionOfferRuntime names who last opened or looted the container
(guest_id, None before anyone did), when (last_accept_time, in the
game’s nanoseconds, changing with each interaction) and whether the game
offers no interaction now (is_disabled).
Two methods sort containers:
is_enemy_loot(): it expires and is open to area loot. That keeps corpses and enemy loot bags, and leaves out player chests, world chests, quest containers and items a player dropped;is_open(): enemy loot that also holds something and offers its interaction, so a player could take from it now.
Other entities
Section titled “Other entities”From inside any hooked system, with its context:
container(ctx, entity)reads one entity as a loot container;Nonewhen it is not one (noDestroyOnLoot, inventory state or position) or is gone;position(ctx, entity)gives any entity’s position in metres;is_player(ctx, entity)tells whether an entity is a player character, such as an offer’sguest_id.
near(center, at, radius, height)
tells whether at lies within radius metres of center across the
ground and within height metres above or below it:
use enshwick::world::near;
assert!(near([0.0, 0.0, 0.0], [6.0, 3.0, 8.0], 10.0, 4.0));assert!(!near([0.0, 0.0, 0.0], [6.0, 5.0, 8.0], 10.0, 4.0));On a hosting client
Section titled “On a hosting client”A client that hosts a game runs the system in the built-in server’s world
and in its own. on_loot_pass calls its handler for the server’s world only,
checked with
Worlds::is_server(ctx),
so the handler needs no check of its own. Entity ids of the two worlds are
unrelated. See Sides and hosting.
A server-side loot mod declares side: SERVER; the client loads SERVER
mods too, for the games it hosts.
A worked example
Section titled “A worked example”A mod that empties the loot around a container a player just emptied into
the same player puts the pieces of this chapter together. The steps follow
one such mod’s
take.rs:
- At
initit resolvesContainers,InventoriesandWorlds, and hooksloot::SYSTEM. - The hook calls vanilla first, then skips any context for which
is_serveris false, and walks the containers witheach. It catches a panic in its own pass and turns itself off, so the game keeps running vanilla. - A tracker remembers each container’s state between steps. A container
that went empty after a player’s interaction (the offer’s
guest_id, checked withis_player) starts a take. - It gathers the containers around that are
is_open()andnearwithin the configured radius and height, and leaves out any that another player opened or looted in the last 10 seconds, or whose last guest, another player, still stands within 4 metres. - It empties them one at a time with a
MoveAllbatch, nearest first, and goes on to the next only when the batch committed and a read in the callback shows the last one empty. A full inventory stops it. - On
ShutdownStartedit clears the tracker: entity ids belong to one game.