Expand description
§bevy_society
Living societies for Bevy: personalities, moods, needs, memories, relationships, opinions,
rumors, reputation and factions; utility-AI daily lives; Rhai-scripted triggers; and dialogue
and barks through bevy_speech_bubbles.
Every model is distilled from social-psychology and game-AI literature (see docs/research/)
and every behaviour is deterministic for a given seed.
§Quick start
use bevy::prelude::*;
use bevy_society::{
Autonomous, Home, Person, Place, PlaceTags, SocietyClock, SocietyDefs, SocietyPlugins,
SocietySettings,
};
let defs = SocietyDefs::starter().expect("the starter pack is valid");
// A headless app has no frame clock, so `Time<Fixed>` never advances on its own. Without this the
// society takes zero ticks however many updates you run.
let step = std::time::Duration::from_secs_f64(1.0 / 64.0);
let mut app = App::new();
app.add_plugins((MinimalPlugins, TransformPlugin))
.insert_resource(bevy::time::TimeUpdateStrategy::ManualDuration(step))
.insert_resource(SocietySettings::default())
.insert_resource(defs);
// `DialoguePlugin` needs a speech-bubbles plugin over a camera, which this snippet has not.
let plugins = SocietyPlugins.build();
#[cfg(feature = "dialogue")]
let plugins = plugins.disable::<bevy_society::DialoguePlugin>();
app.add_plugins(plugins);
let well = app
.world_mut()
.spawn((Name::new("well"), Place { capacity: 6 }, PlaceTags(vec!["gathering".into()]), Transform::default()))
.id();
for name in ["Bram", "Alys", "Corin"] {
app.world_mut()
.spawn((Person, Autonomous, Name::new(name), Home(well), Transform::default()));
}
for _ in 0..600 {
app.update();
}
// The society advanced: this line is what proves the fixed step was pinned.
assert!(app.world().resource::<SocietyClock>().tick > 0);The same code is examples/quickstart.rs, and README.md carries it too — tests/readme.rs
checks the README’s text so the three cannot drift.
Spawn people with Person, give them somewhere to go with Place, hand in the definitions
and read what happens. The example needs no renderer; with the default dialogue feature it
also needs SpeechBubblesPlugin (see the note at the end of the example):
use bevy::prelude::*;
use bevy_society::{
Autonomous, Home, Person, Place, PlaceTags, SocietyDefs, SocietyPlugins, SocietySettings,
};
fn main() {
let defs = SocietyDefs::starter().expect("the starter pack is valid");
let mut app = App::new();
app.add_plugins(MinimalPlugins)
.insert_resource(SocietySettings::default())
.insert_resource(defs)
.add_plugins(SocietyPlugins);
let well = app
.world_mut()
.spawn((Name::new("well"), Place { capacity: 4 }, PlaceTags(vec!["gathering".into()])))
.id();
for name in ["Bram", "Alys"] {
app.world_mut().spawn((
Person,
Autonomous,
Name::new(name),
Home(well),
Transform::default(),
));
}
for _ in 0..600 {
app.update();
}
// With the default `dialogue` feature the host must also add
// `bevy_speech_bubbles::SpeechBubblesPlugin::<YourCamera>`, or `finish()` panics.
// `no_run`: a headless `App::update` never calls `finish()`, so this only compiles.
}§Plugins
SocietyPlugins installs the whole society. Each member also works alone after
SocietyCorePlugin: the mind plugin for emotions, mood, needs and memories, the relationships
plugin for ties, BeliefsPlugin for opinions and rumors, GroupsPlugin for factions and
status, the behaviour plugin for daily life and social exchanges, RulesPlugin for Rhai
triggers, then the feature-gated social-field, steering and dialogue plugins.
§Ticks, snapshots and scripts
The society advances on society ticks: one every SocietySettings::tick_secs of fixed-step
time, with every rate expressed per game-day. The systems run in the order of SocietySystems
— Clock, Perceive, Mind, Decide, Interact, Propagate, Relate, Rules — and only
Clock runs on every fixed step.
Scripts see the society as it stood at the start of the tick, through a snapshot built in
Perceive; a script’s own writes go to a queue. Those writes are applied once per tick, after
Rules, by one exclusive system, so no script can change what another script in the same tick
reads. Game-written input messages (PlantRumor, Interact, FireTrigger) are drained
on every fixed step, not only on society ticks, so a message written between ticks is never
dropped.
§Guides
docs/guide/getting-started.md, concepts.md, authoring.md, scripting.md and dialogue.md;
docs/research/ for the papers behind every formula; docs/DEMOS.md for the capture and GIF.
Modules§
- model
- Engine-free model math: response curves, the personality-to-mood baseline, opinion dynamics, recall and forgetting, rumor spreading, structural balance and the scarcity price on a good. Nothing here names a Bevy type; every function is a pure function of its arguments, so each formula is tested against its paper’s worked values.
Structs§
- Accept
Def - Terms of the acceptance probability (Deffuant et al. 2000 and Byrne 1961 inform the defaults; the plan records the numbers).
- Active
Emotion - One active emotion.
towardnames the person it is about, when there is one. - Activity
Def - Something a person can do, chosen by utility scoring.
- Activity
Ended - A person stopped doing an activity (plan D7).
- Activity
Id - Index of an activity, in definition order.
IDLE_ACTIVITYis alwaysActivityId(0). - Activity
Started - A person began doing an activity (plan D7).
- Appraise
- Asks for an emotion to be felt by
person: the game, a deed, an interaction or a rumor writes it and the mind plugin merges it into the person’sEmotions. Appraisals are applied on every fixed step, not only on society ticks, so a message is never dropped between ticks. - Autonomous
- Marker: this person chooses its own activities. A player-controlled person is a
Personwithout this marker. - Away
- Marker: this person is out of the town and expected back — on an expedition, a voyage, a posting.
- Away
Since - When an
Awayperson left: the game-day, written by the crate whenAwayis inserted (unless the host or a restore already inserted it). Read it for how long someone has been gone; do not insert it withoutAway. - Behavior
Plugin - Runs daily life and social exchanges (plan D7): autonomous people choose activities, travel, arrive, satisfy needs, and exchange with each other.
- Beliefs
Plugin - Runs opinions, rumors and reputation: applies
PlantRumoron every fixed step, then, on society ticks, pulls every person’s opinions toward the group mean it is in contact with. Requirescrate::SocietyCorePlugin. - Bound
Places - The places bound to one person by name, for
ActivityTarget::Bound. - Cell
Frame - An axis-aligned world↔cell mapping: where the grid starts, how wide a cell is, and how many cells there are.
- Channel
Def - Per-channel behaviour. The caller supplies one of these per channel, typically from its own config.
- Chronotype
- How far a person’s body clock runs behind the wall clock, in hours: positive is an owl, negative a lark,
0.0(the default) a person whose body keeps the village’s time. - Clock
Save - The society clock and the tick accumulator, as they stood at capture.
- Commotion
- Raise the commotion field at a point on the society plane.
- Consideration
- One scoring term: an input mapped through a curve.
- Conversation
Rule Def - Chooses the conversation for a
TalkTo. The highest priority matching rule wins. - Deceased
- Marker: this person is dead, and stays dead.
- Decision
- Why one person chose the activity it chose, at one tick.
- Decision
Trace - The decision trace: a fixed-capacity ring of the most recent decisions.
- DeedDef
- A deed a person can do to another. Witnesses judge it by their opinion of
topic. - DeedId
- Index of a deed, in definition order.
- Defs
File - Everything a host hands in, as one RON document. Every list is optional.
- Destination
- Where a travelling person is walking to, on the society plane.
- Dialogue
Plugin - Runs society conversations and barks through
bevy_speech_bubbles. Add it afterSocietyPlugins’ core, and addSpeechBubblesPlugin::<YourCamera>to the app: this plugin checks for it infinish(). - Dialogue
Problem - One definition that names a conversation or node the
DialogueScriptdoes not define. - Doing
- The activity a person is currently performing.
- Doing
Save - The activity a person was performing at capture.
- Dormant
- Marker: this person is out of its daily life for now — posted on a wall, sheltering indoors, away on an expedition, fleeing, or in a conversation with the player.
- Economy
Plugin - Goods, stock and prices.
- Effects
Def - The effects of one interaction outcome.
- Emotion
Save - One active emotion, with the person it is about as a
PersonKey. - Emotions
- The emotions a person currently feels.
- EndActivity
- The host asks for a person’s current activity to end, without dormancy.
- Faction
Def - A faction.
- Faction
Id - Index of a faction, in definition order.
- Faction
Stat - Per-faction aggregates, indexed by
FactionId(plan D6). Recomputed each tick by the groups system. - Faction
Stats - All factions’ aggregates (plan D6). Index
iisFactionId(i). - Fast
Forward - What a
fast_forwarddid. - Fields
Save - Every social grid’s contents: the crowd grid’s channels, then one entry per faction grid.
- Fire
Trigger - A named event the game fires at the society (plan D8): the
Customtriggers with this name run, withactorandtargetbound when the game names them. - GoodDef
- A tradeable quantity. Not a currency: there is no exchange rate and no
Goodis worth another. - GoodId
- Index of a good, in definition order.
- Groups
Plugin - Plugin for factions, standing and faction aggregates (plan D6). Runs in
SocietySystems::Relateafter the tie labels are refreshed, so standing reads settled ties. RequiresSocietyCorePlugin. - Home
- The home of a person, used by the
Homeactivity target. - Host
Clock - The host’s game time, in days. Write it every frame; the crate never inserts it.
- Interact
- Request that
actorperforms the named interaction ontarget. - Interaction
Barks - Bark lines for an interaction. Templates may use
{self},{target},{subject}and{place}. - Interaction
Def - A social exchange between two persons.
- Interaction
Id - Index of an interaction, in definition order.
- Interaction
Resolved - A social exchange finished (plan D7).
- Knowledge
- Everything a person knows about rumors, sorted by
RumorId(plan D5). - Known
- What one person knows about one rumor (plan D5).
- Memberships
- The factions a person belongs to, sorted by
FactionId(plan D6). - Memories
- A bounded list of memories, at most
memory_capacity(default 64). - Memory
- One remembered event.
- Memory
Save - One remembered event.
- Mood
- Pleasure, arousal and dominance, each in
[-1, 1](Russell 1980, DOI 10.1037/h0077714; the Mehrabian 1996 mapping this crate uses is DOI 10.1080/00049539608259510, the onemodel::padimplements). - Mood
Rates - Rates of the mood update, per game-day (plan D3 defaults).
- Names
Save - The names of every definition list, in definition order.
- NeedDef
- A need. Level 1 is satisfied, 0 is desperate.
- NeedId
- Index of a need, in definition order.
- Needs
- Need levels, indexed by
NeedId. Level 1 is satisfied, 0 is desperate. - Next
Person Id - Next
PersonIdto hand out. Ids follow spawn order. - Node
Effect Def - Runs a script when a dialogue node is entered.
- Norm
Violated - Written when a witness judges an actor’s deed harshly enough to count as a norm violation (plan D5): the witness’s approval is below −0.5.
- Obstacle
- Something round and solid that walkers must go around, in metres on the society plane.
- Opinion
- One opinion on one topic (plan D5).
valueis in[-1, 1],stubbornnessin[0, 1]. - Opinions
- A person’s opinions, indexed by
TopicId(plan D5). Sized to the defs bysize_person_state. - Perception
- Per-tick perception: positions and neighbourhoods, indexed by position in
PersonIndex::sorted. Neighbour lists are ascending by index and exclude the person itself. - Person
- Marker of a simulated person. Adding it gives the person every per-person component.
- Person
Def - One authored person.
- Person
Died - A person died: written once, when
Deceasedis inserted. - Person
Id - Stable, deterministic id of a person, assigned in spawn order.
- Person
Index - Persons in spawn order, with lookup by id. Maintained by the add and remove observers only.
- Person
Key - The host’s own stable identity for a person, written by the host before a save is taken.
- Person
Preview - What a preview did to one person.
- Person
Returned - A person came back: written once, when
Awayis removed. - Person
Save - Everything the crate keeps per person, as plain fields.
- Personality
- The five traits, each in
[0, 1]; default 0.5 on every trait. - Personality
Def - A person’s five traits, each in
[0, 1]. A trait left out is0.5. - Place
- A place people can go to.
capacitylimits how many persons may be doing an activity there. - Place
Def - A place: a named spot with a capacity and tags.
- Place
Dependent - One person who depends on a place: it is their home or one of their bound places.
- Place
Key - The host’s own stable identity for a
Place, written by the host before a save is taken. - Place
Tags - Tags that let activities find a place (
ActivityTarget::Place(tag)). - Placed
- What
PlacementFile::spawnmade, in file order. - Placement
File - A list of places and persons, as one RON document. Both lists are optional.
- Plant
Rumor - Game-facing request to start a rumor about
subject’s deed, told byorigin(plan D5). An unknowndeedname is logged and ignored. - Preview
- What
preview_forwardsaw. - Prices
- The price of each good, in definition order.
- Relationships
Plugin - Plugin for the directed-tie model (plan D4). Runs in
SocietySystems::Relate, afterSocietyCorePlugin. - Report
Deed - The host reports a deed the society could not see, naming the people who saw it.
- Restore
Report - What
restoredid beyond the people it restored. - RngSave
- The one RNG’s exact position: its seed, its stream and its offset in words.
- Rules
Plugin - Runs triggers (plan D8). Every other plugin that observes an event pushes a trigger event onto
the trigger queue, and the game fires custom events with
FireTrigger. Requirescrate::SocietyCorePlugin. - Rumor
- One rumor about one person’s deed (plan D5).
valenceis the deed’sharm: negative means damaging to the subject. - Rumor
Book - Every rumor in the society, in creation order (plan D5).
RumorId(i)addressesrumors[i]. - RumorId
- Index of a rumor in the
RumorBook(plan D5). - Rumor
Learned - Written when a person first hears a rumor by gossip (plan D5).
- Rumor
Save - One rumor, with every person reference as a
PersonKey. - Scored
Option - One option a decision weighed: the activity, the score it reached, and why it lost or won.
- Script
Engine - The Rhai engine every runtime script runs on, with the
ctx/fxAPI registered (plan D8). - Script
Error - A script that failed: the authored path that names it and what went wrong (plan D8).
- Script
Event - A named event a script emitted with
fx.emit(plan D8). - Script
Id - Index of a compiled script inside
SocietyDefs, in compile order. - Script
Syntax Error - Where and why a script does not parse, from
check_script. - Signal
Def - A host signal. The crate never changes its value; the host sets it.
- Signal
Id - Index of a host signal, in definition order.
- Signals
- Host-written signal values, indexed by
SignalId. The crate only reads them; a value the host never wrote is0.0. - Skill
Def - A named capability. Level comes from personality, not from stored state.
- SkillId
- Index of a skill, in definition order.
- Social
Field Plugin - Installs the social fields: the crowd presence and commotion grids, plus one presence grid per
faction. They are deposited into and evaporated every tick. Requires
crate::SocietyCorePluginand is included inSocietyPluginswhen thefieldsfeature is on. - Social
Field Settings - Where the fields sit in the world and how they behave. Changing it rebuilds the fields empty.
- Social
Fields - The grids that daily-life options read. Built from
SocialFieldSettingsand the faction count, and rebuilt empty whenever the settings change or the faction count differs. NotReflect, becausebevy_stigmergy’s grids are plain data without it. - Social
Mover - Opt-in walking for a person. Add it to a
Personthat should be steered toward itsDestination; aPersonwithout it is moved by the game. - Social
Velocity - The velocity last computed for a
SocialMover, in metres per second on the plane. - Society
Bark - A line a person says aloud, or thinks, for the game to show.
- Society
Clock - The society clock.
now_daysis the continuous game time in days;dt_daysis the length of one society tick in days. - Society
Core Plugin - Persons, ids, clock, RNG, sets and perception. Add it before every other society plugin, or use
crate::SocietyPlugins, which does. - Society
Defs - Compiled definitions: the resource the simulation reads.
Defaultis the empty set plus the reservedidleactivity. - Society
Plugins - Every society plugin, in dependency order. Add it to an app with
DefaultPluginsand the host’s own systems; disable a member with.disable::<…>()to replace it. - Society
Rng - The only randomness in the crate: a ChaCha8 stream seeded from
SocietySettings::seed. - Society
Save - A whole society, as plain data.
- Society
Settings - Global settings of the society. Insert before adding
SocietyCorePluginto override defaults. - Society
Tick - Accumulates fixed-step time and says whether a society tick is due this step.
- Status
- A person’s standing: the mean respect others hold for them (plan D6). Magee & Galinsky 2008, DOI 10.5465/19416520802211628, on status as conferred respect; Berger et al. 1972, DOI 10.2307/2093465.
- Steering
Plugin - Adds ORCA steering for
SocialMovers. Requirescrate::SocietyCorePlugin(orcrate::SocietyPlugins). - Stock
- Per-person holdings, one level per good in definition order, each in
[0, Tuning::stock_ceiling]. - TalkTo
- Asks the society to start a conversation between two people. The host writes it, or a script
does through
fx.converse(featuredialogue). - Tie
- One directed edge from the owning person to
target(plan D4). - TieChange
- One tie that is not what it was.
- TieDelta
- Tie changes applied by an interaction outcome.
- TieLabel
Changed - Written once per tie whose label changed (plan D4).
fromowns the tie,tois its target. - TieSave
- One directed tie, with its target as a
PersonKey. - TieSpec
- A directed tie from the owning person to another authored person.
- Ties
- A person’s outgoing ties, sorted by
target.to_bits()with at most one entry per target. - Topic
Def - An opinion topic.
- TopicId
- Index of a topic, in definition order.
- Travel
Failed - The host reports that it cannot walk a person to its
Destination. - Trigger
Area - An axis-aligned rectangle on the society plane, edges inclusive: where an area trigger is live.
- Trigger
Def - A rule that fires on a simulation event and runs a script.
- Trigger
Fired - A trigger ran: its event matched, its
areaandifheld and itsthenfinished without error. - Trigger
Test - What
test_triggerfound: whether one trigger would run for the given people, and what itsthenwould write. - Triggers
Save - The trigger bookkeeping: which triggers have fired once, which are cooling, what the clock’s previous instant was, which people have fired a need threshold and not yet recovered, and which (deed, rumor) reach triggers have already fired.
- Tuning
- Every model rate of the crate, one named field each. Rates are per game-day unless the name says otherwise.
- Urgent
Def - A rank an activity takes while one need is low, and only then.
Enums§
- Activity
Target - Where an activity happens.
- Assessment
Norm - How witnesses judge a rule-breaking actor’s trust (see the reputation note).
- Clock
Source - Where the society clock’s time comes from.
- Defs
Error - Why a definitions file was rejected.
- Dialogue
Reference Kind - What kind of definition names a conversation the
DialogueScriptdoes not hold. - Doing
Target - The target of a
Doingactivity. - Doing
Target Save - What a
Doingis directed at, with places and persons as host-stable keys. - Emotion
Kind - The OCC emotion subset (Ortony, Clore & Collins; via Gratch & Marsella 2004, DOI 10.1016/j.cogsys.2004.02.002, and Dias & Paiva 2005, DOI 10.1007/11595014_13).
- Fast
Forward Error - Why a
fast_forwarddid not run. - Feeling
- The feeling a bark carries, mapped from the speaker’s strongest emotion.
- Field
Input - Social fields a consideration or gradient target can read.
- Input
- Signals a consideration can read.
- Locomotion
- Who moves a person’s
Transformtoward itsDestination. - Memory
Kind - What a memory is about.
- Memory
Kind Save - What a memory is about, with every person reference as a
PersonKey. - Preview
Error - Why a
preview_forwarddid not run or could not reset. - Restore
Error - Why a
SocietySavecould not be applied. The world is untouched when one of these returns. - Script
Kind - What a piece of authored script text must be, so
check_scriptparses it the way the definitions compiler will. - Script
Value - One value an
fx.emitcall carries. Any other Rhai type is a runtime error atemittime. - Signal
- A compiled signal, with ids resolved.
- Skill
Group - Which personality axis a skill draws on.
- Society
Plane - Which two world axes the society lives on. Positions are projected onto these axes.
- Society
Systems - System sets of one society tick, chained in this order inside
FixedUpdate. - TieLabel
- The label a tie carries, recomputed each tick from affinity and familiarity (plan D4).
- Trait
- One of the five personality traits (McCrae & John 1992, DOI 10.1111/j.1467-6494.1992.tb00970.x).
- Trigger
On - The events a trigger can listen to.
- Trigger
Test Error - Why
test_triggercould not answer.
Constants§
- IDLE_
ACTIVITY - Name of the reserved activity every compiled
SocietyDefscontains. Persons with no valid option pick it for one game-hour. - STANDING_
FAMILIARITY - Familiarity needed before a respect value counts toward standing (plan D6).
- VERSION
- Version of the
SocietySaveformat this build writes and reads.
Functions§
- belief_
after_ hearing - Belief a listener takes away from hearing a rumor:
teller_belief · (0.5 + 0.5 · trust)(Sommerfeld et al. 2007, DOI 10.1073/pnas.0704598104), re-exported for callers of this module. - capture
- Reads the whole society into a
SocietySave. - check_
script - Parses script text under the same sandbox limits as the definitions compiler and reports the
first syntax error with its line and column, without needing a
DefsFileor a running app. An editor calls this on every edit and refuses to save text that fails. Nothing is evaluated; a script that parses can still fail at run time (an unknown function is found only when it runs). - contest_
win_ chance - Probability that the actor wins a contest (plan D6): logistic of the difference in
(dominance + standing)between actor and target, withsteepnessfromTuning::contest_steepness(Bonabeau et al. 1995, DOI 10.1016/0378-4371(95)00064-e; Hemelrijk 1999, DOI 10.1098/rspb.1999.0646). - dialogue_
problems - Every conversation rule, node effect and node-entered trigger in
defsthat names a conversation or nodescriptdoes not define, in definition order. Empty when the two agree. - fast_
forward - Runs
daysgame-days of society ticks onworldand returns how many ticks ran. - persons_
in_ rect - Persons whose position on the society plane lies inside the rectangle
min..=max, in ascendingPersonIdorder: the selection an editor binds a trigger or a bulk edit to. - place_
dependents - Everyone whose home or bound place is
place, in ascendingPersonIdorder, so an editor can refuse to delete a building that someone lives in or works at and name them. A person holding the place under several roles appears once per role. - preview_
forward - Runs
daysgame-days, reports what changed, and puts the society back as it was. - reload_
defs - Applies an edited definitions file to a running society (see
SocietyDefs::reloadfor what may change) and keeps theonceand cooldown bookkeeping of every trigger that survives the edit, matched by its authoredid. A trigger that was renamed or removed forgets its state; a new one starts clean. A refused file leaves the world untouched. - restore
- Applies a
SocietySaveto a world the host has already spawned its persons and keyed places into. - size_
person_ state - Keeps every person’s
Needs,Signals,OpinionsandStockthe length of the defs (plan D2). A short vector grows with the defs’ starting values; a long one is an error and is truncated.Mutchanges only when a length actually differs. - skill_
level - A skill’s level for a person, in
[0, 1]: the trait its group reads, as it stands. - society_
tick_ due - Run condition: true on fixed steps in which a society tick is due.
- standing_
from - Standing from
(respect, familiarity)pairs, one per person who holds a tie toward this person. Only pairs withfamiliarity >= STANDING_FAMILIARITYcount; 0 when none do (plan D6). - test_
trigger - Dry-runs the trigger authored as
triggeragainst the society as the last tick froze it, as if its event had just happened toactorandtarget, and reports what it would write without writing it. - value_
of - What one unit of a good is worth to a person holding
heldof it:1 / (1 + held).