FERRETGame engine over Babylon.js
Ferret

@ferret/accounts

The player's account in the game's own process: sign-in, session, balances, a gateway for net.

8 exports · source in packages/accounts/src

Classes

AccountService class

class AccountService implements Service

The player's account in the game's own process: what a local helper app (SquirrelCraft's arbiter) used to do for the original. Sign-in (user:verify), keeping and checking the session, signing out, the rewards balances. A guest is a player nobody is signed in as; the game plays on, and a later sign-in upgrades it. The Camerlengo calls all go through @ferret/net's client. Events: account:login { user }, account:logout, account:guest, account:expired, account:balance { currency, balance }.

readonly name: "account"
constructor(readonly opts: AccountOptions)
init(world: World)
dispose()
get signedIn(): boolean
session(): string | nullthe session token for calls that need one (voice); null for a guest
user(): AccountUser | null
async signIn(user: string, password: string): Promise<void>
signOut()
async valid(session = this.tok): Promise<boolean>Is a session still good? (user:getSessionUser.) A backend that cannot be reached is "not known to be bad": true.
async autoLoginOrGuest(): Promise<boolean>At the start: take the session that was given or stored if it is still good, else play as a guest. Resolves with whether the player is signed in. Never throws: a backend that is down leaves a stored session in place (checked again later) or a guest.
async check(): Promise<void>One session check now; an expired session is renewed with the kept password, else the player is a guest again.
async rewards(query: string, params: Record<string, unknown> = {}): Promise<Record<string, any>>One rewards query for the signed-in player: plugin:call with the scoped key and the session.
async balance(currency = 'PIA'): Promise<number>
async balances(): Promise<Record<string, number>>every currency the account holds, as plain numbers
async adjust(delta: number, reason: string, currency = 'PIA'): Promise<number>earn (positive) or spend (negative); resolves with the new balance
gateway(currency = 'PIA'): AccountGatewayThe @ferret/net account gateway over this service: a guest has no name and 0 balance; spending needs a sign-in.

packages/accounts/src/account.ts:32

HelperStubs class

class HelperStubs implements Service

The two calls the original's local helper app (SquirrelCraft's arbiter) accepted and only wrote to its log, because the thing behind them was never built: the shared "AI teacher" bot of a voice room, and a player coming near to or leaving an artifact. They are kept as calls with the same names and arguments, so a game that makes them does not change when the real thing exists; for now each is logged (log) and announced as an event, which a game or a backend adapter can listen to:

  `teacher:start` / `teacher:stop` { room, identity }     identity is "npc:<Name>"; one bot per room serves everybody in it
  `artifact:near` / `artifact:far` { artifactId }
readonly name: "helper-stubs"
readonly log: string[]what was asked, in order (<event> <json>), for tests and for looking at what a game does
constructor(private opts: { sink?: (line: string) => void } = {})
init(world: World)
teacherAgent(action: 'start' | 'stop', room: string, identity: string)Ask for the shared teacher bot of a voice room to start or stop (not a voice join: that is for a player's own presence).
artifactNear(artifactId: string)
artifactFar(artifactId: string)

packages/accounts/src/helper-stubs.ts:11

Functions

signInCard function

function signInCard(account: AccountService, opts: { document?: Document; strings?: Partial<SignInStrings> } = {}): Promise<boolean>

A card over the game that asks for the account (the helper app's login dialog, in the page). Resolves when the player has signed in (true) or chose to play as a guest or closed the card (false); the level keeps running underneath either way.

packages/accounts/src/sign-in.ts:32

Interfaces

AccountOptions interface

interface AccountOptions
client: CamerlengoClientthe backend client; its appKey is the key for user:verify / user:getSessionUser
path?: stringthe user namespace of the sign-in (default "/users")
rewardsKey?: stringa key scoped to plugin:call on the rewards plugin only; without it there are no balances
rewardsPlugin?: stringthe rewards plugin (default "GameRewards")
checkMinutes?: numberminutes between session checks while signed in (default 30); an expired session is renewed with the password kept in memory
store?: KeyValueStore
storeKey?: string
session?: stringa session obtained elsewhere (a launcher, a link); checked like a stored one

packages/accounts/src/account.ts:7

AccountUser interface

interface AccountUser
id: string
name: string

packages/accounts/src/account.ts:24

KeyValueStore interface

interface KeyValueStore

Where the session is kept between page loads (a Storage: localStorage; tests pass a Map-backed stand-in).

getItem(k: string): string | null
setItem(k: string, v: string): void
removeItem(k: string): void

packages/accounts/src/account.ts:5

SignInStrings interface

interface SignInStrings

Text of the sign-in card; a game can translate it.

title: string
email: string
password: string
signIn: string
guest: string
close: string
busy: string
wrong: string
down: string

packages/accounts/src/sign-in.ts:4

Constants

defaultStrings const

const defaultStrings: SignInStrings

packages/accounts/src/sign-in.ts:5