H3lp Yours3lfDocs
api

S3lf

Lazy caching for attached-object values and bound type methods, exposed as one local/player interface.

Used in the St4sh
  • CHIM 2090: roll/core.lua — Roll manager settings, attached actor access, and randomized roll audio.
  • S3maphore: music/core.lua — A production music loop combining actor state, transitions, cleanup, magic checks, and randomized selection.
  • H4ND: TTTH/hud.lua — A HUD consumer combining attached actor data, settings state, atlas frames, magic calculations, and randomized presentation.
  • T4RG3T5: target/lockOnManager.lua — Lock-on state, attached target access, and onscreen projection for target markers.
require 'openmw.interfaces'.s3.lf → S3lfObject

S3lf is a lazily cached facade over the attached OpenMW object. It resolves type methods, stats, records, object fields, and related helpers on demand, caching values where the configured key behavior allows it so repeated engine-backed lookups become ordinary table access. Bound type methods automatically use the attached object.

For the design reasoning and internal evolution behind this boundary, see Cod3x's I.s3.lf Design Genealogy.

What it actually does

These two forms ask the same OpenMW question:

local types = require 'openmw.types'
local health = types.Actor.stats.dynamic.health(self)
local stance = types.Actor.getStance(self)
local I = require 'openmw.interfaces'

local health = I.s3.lf.health
local stance = I.s3.lf.getStance()

The first S3lf access resolves the engine-backed value and stores cacheable results on the facade. Later reads use ordinary table lookup. The bound method supplies the attached object, so callers do not repeatedly pass self; type methods are wrapped once with the attached object and cached, removing repeated self plumbing and repeated facade resolution.

S3lf caches the engine-backed stat object, not a numeric snapshot of the stat. Caching s3lf.health does not freeze health.current; it retains the DynamicStat view instead of reconstructing that wrapper on every access.

Read the attached actor's health

local core = require 'openmw.core'
local I = require 'openmw.interfaces'

if not core.contentFiles.has 'H3lp Yours3lf.esp' then
    error 'H3 S3lf dependency is missing; enable the H3lp Yours3lf plugin before this script'
end

local function reportHealth()
    local s3lf = I.s3.lf
    local actor = s3lf.asActor()
    if actor then
        print(actor.recordId .. ': ' .. tostring(actor.health.current))
    end
end

return {
    engineHandlers = {
        onInit = reportHealth,
        onLoad = reportHealth,
    },
}

Use the bootstrap's player-script registration. Put H3lp Yours3lf.esp before your content in the load order. The content-file check diagnoses a missing or misconfigured dependency; the lookup still happens when the handler runs rather than assuming the interface is ready during another script's top-level evaluation.

Common members

MemberMeaning
idGame-object instance ID, not record ID.
recordIdRecord identifier shared by instances of that record.
objectUnderlying local game object.
recordRecord data exposed as a field, not a record lookup function.
controlsActor controls when the attached object is an actor.
ATTACK_TYPEAttack-type constants for actor controls.
EQUIPMENT_SLOTActor equipment-slot constants.
STANCEActor stance constants.
actorType0 player, 1 NPC, 2 creature, 3 non-actor.
boundsThe attached object's bounding box.
cellsVisitedPlayer-only map of cell IDs observed by the player's update handler.
consoleLog(...)Lowercase convenience alias for LogMessage.
distance(other)Distance from the attached object's position to another object's position.
sendObjectEvent(name, data?)Sends an event to the attached object.
asActor(), asNPC(), asPlayer(), asCreature(), asNonActor()Same view narrowed to the matching type, or nil. NPC includes player.

Values marked uncacheable are read again; ignored values return nil. The lists below describe the complete H3-provided and inherited facade surface. record may be a creature, NPC, armor, book, clothing, ingredient, light, miscellaneous, potion, weapon, apparatus, lockpick, probe, repair, activator, container, door, static, or levelled-creature record when the attached object has that record type.

Inherited object members

S3lf retains the fields and methods of OpenMW's attached-object (SelfObject) surface. Their availability and mutation rules remain the OpenMW rules; the facade does not make read-only local object fields writable.

MemberMeaning
contentFileLowercase content file defining the object, or nil for a dynamically created object.
positionObject position.
scaleObject scale.
rotationObject rotation.
saveStateWhether the object has been modified for save; local scripts read this value.
startingCellOriginal cell, when available.
startingPosition / startingRotationOriginal position and rotation.
ownerObject ownership information.
cellCurrent cell, or nil during loading or while inside inventory/container storage.
parentContainerContainer or actor holding the object, or nil when it is in a cell.
typeOpenMW type table for the object.
countStack count.
globalVariableAssociated global variable, or nil.
isValid()Whether the object exists and is available.
sendEvent(eventName, eventData)Sends a local event to the object.
getBoundingBox()Returns the object's world-space bounding box.
activateBy(actor)Activates the object using an actor.
isActive()Whether the attached object is in an active cell.
enableAI(value)Enables or disables standard AI for the attached actor.

Forwarded dynamic members

The attached object's type module, record, and OpenMW animation module may expose additional members. S3lf forwards those members using the same key lookup, binding functions to the attached object and caching values according to the configured key behavior. Their names and availability therefore depend on the attached object's type and record; they are not a fixed H3 field list. Use type, record, and the relevant OpenMW API contract to determine what a particular object provides.

Actor methods

These methods exist on actor views. They omit the object argument because S3lf supplies the attached object.

MemberMeaning
getEncumbrance()Current actor encumbrance.
getCapacity()Current actor inventory capacity.
getBarterGold() / setBarterGold(amount)Read or set barter gold.
isDead() / isDeathFinished()Death and finished-death state.
getPathfindingAgentBounds()Actor pathfinding bounds.
isInActorsProcessingRange()Whether the actor is in processing range.
inventory()Actor inventory.
canMove()Whether the actor can move.
getRunSpeed() / getWalkSpeed() / getCurrentSpeed()Actor movement speeds.
isOnGround() / isSwimming()Current movement state.
getStance() / setStance(stance)Read or set actor stance.
hasEquipped(item)Whether the actor has the object equipped.
getEquipment(slot?) / setEquipment(equipment)Read or set equipment.
getSelectedSpell() / setSelectedSpell(spell)Read or set the selected spell.
clearSelectedCastable()Clear the selected castable.
getSelectedEnchantedItem() / setSelectedEnchantedItem(item)Read or set the selected enchanted item.
activeEffects()Active actor effects.
activeSpells()Active actor spells.
spells()Actor spell list.

Actor stats

These fields are engine stat objects, not copied plain tables. Dynamic stats, AI stats, attributes, and level apply to actor views as supported by the underlying type. Skills are available on NPC and player views.

CategoryFields
Dynamic statshealth, magicka, fatigue
AI statsalarm, fight, flee, hello
Attributesstrength, intelligence, willpower, agility, speed, endurance, personality, luck
Levellevel
Skillsblock, armorer, mediumarmor, heavyarmor, bluntweapon, longblade, axe, spear, athletics, enchant, destruction, alteration, illusion, conjuration, mysticism, restoration, alchemy, unarmored, security, sneak, acrobatics, lightarmor, shortblade, marksman, mercantile, speechcraft, handtohand

NPC methods

These methods exist on NPC views. OpenMW's NPC type includes the player, so asNPC() also exposes them for a player view.

MemberMeaning
getFactions()Factions joined by the NPC.
getFactionRank(faction) / setFactionRank(faction, value)Read or set faction rank.
modifyFactionRank(faction, value)Adjust faction rank.
joinFaction(faction) / leaveFaction(faction)Join or leave a faction.
getFactionReputation(faction) / setFactionReputation(faction, value)Read or set faction reputation.
modifyFactionReputation(faction, value)Adjust faction reputation.
expel(faction) / clearExpelled(faction)Set or clear faction expulsion.
isExpelled(faction)Whether the NPC is expelled from a faction.
getDisposition(player) / getBaseDisposition(player)Read current or base disposition.
setBaseDisposition(player, value) / modifyBaseDisposition(player, value)Set or adjust base disposition.
isWerewolf() / setWerewolf(werewolf)Read or set werewolf state.

Player methods

These methods exist only on a player view.

MemberMeaning
getCrimeLevel() / setCrimeLevel(crimeLevel)Read or set crime level.
isCharGenFinished()Whether character generation is finished.
isTeleportingEnabled() / setTeleportingEnabled(state)Read or set teleporting permission.
quests()Player quest data.
addTopic(topicId)Add a topic to the player's journal topics.
journal()Player journal.
getControlSwitch(key) / setControlSwitch(key, value)Read or set a player control switch.
getBirthSign()Player birth sign.
sendMenuEvent(eventName, eventData?)Sends an event to the player's menu context.

Record-derived fields

When the attached record provides them, S3lf resolves these fields from the record:

FieldMeaning
isCreatureWhether the attached record is a creature record.
combatSkillCreature combat skill.
nameRecord display name.
modelRecord model path.
baseGoldRecord base gold value.

Bound type methods omit the object argument. For example, actor.getStance() and actor.getEquipment(slot) operate on the attached actor. Use dot calls: adding a colon would supply an extra argument. Availability still depends on the object type and underlying OpenMW API.

Diagnostics and player-specific tracking

MemberMeaning
isInCombat()Whether tracked target data is nonempty and engine AI is enabled.
targetData()Read-only map of tracked actor IDs to actor objects.
displayBuilds and sends a diagnostic description of the view to nearby players, then returns that description; available on local and player views.

Combat tracking consumes OMWMusicCombatTargetsChanged; it is not an independent scan of every fight in the world. Incoming reports produce S3CombatTargetAdded or S3CombatTargetRemoved, with the reporting actor as payload. Do not interpret repeated reports as a unique kill count or guaranteed deduplicated transition history.

S3LFCellChanged carries the previous cell ID when the player moves between known cells. The player provider saves its tracked target data and visited cells. Consumers should use the interface, not reach into that provider's save payload.

Caching and lifetime

Most resolved members are cached; selected openmw.self keys are explicitly ignored or left uncached through H3's key-behavior table. Type values, type methods, stats, record values, object values, and animation values then follow their own lazy-cache paths. This is not a deep snapshot: cached engine stat objects can still expose current values. Do not infer that every cached scalar is refreshed each frame or that every field exists on every object. Retain the interface only for its valid script/object lifetime and read changing data when needed.

See State and Context for the distinction between wrappers, permissions, and persistent data.