@empirica/core
Version:
Empirica Core
298 lines (296 loc) • 7.42 kB
JavaScript
import {
Scope,
Scopes,
Steps
} from "./chunk-IJG2YOZB.js";
import {
Attributes
} from "./chunk-RXGVZSIF.js";
import {
Globals
} from "./chunk-2TT3WJZY.js";
// src/player/classic/classic.ts
import { BehaviorSubject, Subject } from "rxjs";
var endedStatuses = ["ended", "terminated", "failed"];
var Game = class extends Scope {
get hasEnded() {
return endedStatuses.includes(this.get("status"));
}
get stage() {
return this.scopeByKey("stageID");
}
get round() {
return this.stage?.round;
}
};
var Player = class extends Scope {
get game() {
const { game } = this.ctx;
if (!game) {
return;
}
const key = `playerGameID-${game.id}`;
return this.scopeByKey(key);
}
get round() {
const { stage } = this.ctx;
if (!stage) {
return;
}
const { round } = stage;
if (!round) {
return;
}
const key = `playerRoundID-${round.id}`;
return this.scopeByKey(key);
}
get stage() {
const { stage } = this.ctx;
if (!stage) {
return;
}
const key = `playerStageID-${stage.id}`;
return this.scopeByKey(key);
}
hasUpdated() {
if (super.hasUpdated()) {
return true;
}
return Boolean(
this.round?.hasUpdated() || this.stage?.hasUpdated() || this.game?.hasUpdated()
);
}
};
var PlayerGame = class extends Scope {
};
var PlayerRound = class extends Scope {
};
var PlayerStage = class extends Scope {
};
var Round = class extends Scope {
};
var Stage = class extends Scope {
get round() {
return this.scopeByKey("roundID");
}
get timer() {
return this.tickerByKey("timerID");
}
};
var Context = class {
};
var kinds = {
game: Game,
player: Player,
playerGame: PlayerGame,
playerRound: PlayerRound,
playerStage: PlayerStage,
round: Round,
stage: Stage
};
function EmpiricaClassic(participantID, provider) {
const attributesDones = new Subject();
const scopesDones = new Subject();
const ctx = new Context();
const attributes = new Attributes(
provider.attributes,
attributesDones,
provider.setAttributes
);
const steps = new Steps(
provider.steps,
provider.dones
);
const scopes = new Scopes(
provider.scopes,
scopesDones,
ctx,
kinds,
attributes,
steps
);
const participantIDs = /* @__PURE__ */ new Set();
const glob = new Globals(provider.globals);
const ret = {
game: new BehaviorSubject(void 0),
player: new BehaviorSubject(void 0),
players: new BehaviorSubject(void 0),
round: new BehaviorSubject(void 0),
stage: new BehaviorSubject(void 0),
globals: glob.self
};
provider.participants.subscribe({
next: ({ participant, removed }) => {
if (removed) {
if (participantIDs.has(participant.id)) {
participantIDs.delete(participant.id);
}
} else {
if (!participantIDs.has(participant.id)) {
participantIDs.add(participant.id);
}
}
}
});
let scopesUpdated = /* @__PURE__ */ new Set();
provider.attributes.subscribe({
next: (attr) => {
const nodeID = attr.attribute.node?.id || attr.attribute.nodeID;
if (!nodeID) {
return;
}
scopesUpdated.add(nodeID);
}
});
provider.dones.subscribe({
next: () => {
const current = getCurrent(ret);
const updated = getMainObjects(participantID, scopes, attributes);
ctx.game = updated.game;
ctx.stage = updated.stage;
if (scopeChanged(current.game, updated.game)) {
ret.game.next(updated.game);
}
if (scopeChanged(current.player, updated.player)) {
ret.player.next(updated.player);
}
if (scopeChanged(current.round, updated.round)) {
ret.round.next(updated.round);
}
if (scopeChanged(current.stage, updated.stage) || steps.hadUpdates()) {
ret.stage.next(updated.stage);
}
let playersChanged = false;
const players = [];
for (let i = 0; i < (updated.players || []).length; i++) {
let p = updated.players[i];
if (p) {
const partID = attributes.nextAttributeValue(
p.id,
"participantID"
);
if (!participantIDs.has(partID)) {
p = void 0;
}
}
if (!playersChanged && scopeChanged(p, (current.players || [])[i])) {
playersChanged = true;
}
if (!playersChanged && scopeChanged(p?.stage, (current.players || [])[i]?.stage)) {
playersChanged = true;
}
if (!playersChanged && scopeChanged(p?.round, (current.players || [])[i]?.round)) {
playersChanged = true;
}
if (!playersChanged && scopeChanged(p?.game, (current.players || [])[i]?.game)) {
playersChanged = true;
}
if (p) {
players.push(p);
}
}
if (playersChanged) {
ret.players.next(players);
}
const scopeIDs = Array.from(scopesUpdated);
scopesDones.next(scopeIDs);
attributesDones.next(scopeIDs);
scopesUpdated.clear();
}
});
return ret;
}
function scopeChanged(current, updated) {
if (!current && !updated) {
if (current === void 0 && updated === null) {
return true;
}
return false;
}
if (!current || !updated) {
return true;
}
return current.id !== updated.id || updated.hasUpdated();
}
function getCurrent(ctx) {
return {
game: ctx.game.getValue(),
player: ctx.player.getValue(),
round: ctx.round.getValue(),
stage: ctx.stage.getValue(),
players: ctx.players.getValue()
};
}
function getMainObjects(participantID, scopes, attributes) {
const players = Array.from(scopes.byKind("player").values());
players.sort();
const res = {
players,
game: null,
player: null,
round: null,
stage: null
};
if (players.length === 0) {
return res;
}
res.player = players.find((p) => {
const pID = attributes.nextAttributeValue(p.id, "participantID");
return pID === participantID;
});
if (!res.player) {
return res;
}
res.game = nextScopeByKey(scopes, attributes, res.player, "gameID");
if (!res.game) {
return res;
}
for (const player of players || []) {
const key = `playerGameID-${res.game.id}`;
if (!nextScopeByKey(scopes, attributes, player, key)) {
return res;
}
}
res.stage = nextScopeByKey(scopes, attributes, res.game, "stageID");
if (!res.stage) {
return res;
}
for (const player of players || []) {
const key = `playerStageID-${res.stage.id}`;
if (!nextScopeByKey(scopes, attributes, player, key)) {
delete res.stage;
return res;
}
}
res.round = nextScopeByKey(scopes, attributes, res.stage, "roundID");
if (!res.round) {
return res;
}
for (const player of players || []) {
const key = `playerRoundID-${res.round.id}`;
if (!nextScopeByKey(scopes, attributes, player, key)) {
delete res.stage;
delete res.round;
return res;
}
}
return res;
}
function nextScopeByKey(scopes, attributes, scope, key) {
const id = attributes.nextAttributeValue(scope.id, key);
if (!id || typeof id !== "string") {
return null;
}
return scopes.scope(id) || null;
}
export {
Game,
Player,
PlayerGame,
PlayerRound,
PlayerStage,
Round,
Stage,
EmpiricaClassic
};
//# sourceMappingURL=chunk-KV4C4Q27.js.map