101f595bac
Add userData players/teams, scene npcTokens with hex-inscribed sizing, session scale synced to presentation, and Playwright e2e coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
import {
|
|
clampNpcTokenSessionScale,
|
|
DEFAULT_NPC_TOKEN_SESSION_SCALE,
|
|
type SceneNpcTokensSessionEvent,
|
|
type SceneNpcTokensSessionState,
|
|
} from '../../shared/types/appPlayers';
|
|
|
|
function emptyState(revision = 1): SceneNpcTokensSessionState {
|
|
return {
|
|
revision,
|
|
byPlacementId: {},
|
|
scale: DEFAULT_NPC_TOKEN_SESSION_SCALE,
|
|
};
|
|
}
|
|
|
|
export class SceneNpcTokensSessionStore {
|
|
private state: SceneNpcTokensSessionState = emptyState();
|
|
|
|
getState(): SceneNpcTokensSessionState {
|
|
return this.state;
|
|
}
|
|
|
|
reset(): SceneNpcTokensSessionState {
|
|
if (
|
|
Object.keys(this.state.byPlacementId).length === 0 &&
|
|
this.state.scale === DEFAULT_NPC_TOKEN_SESSION_SCALE
|
|
) {
|
|
return this.state;
|
|
}
|
|
this.state = emptyState(this.state.revision + 1);
|
|
return this.state;
|
|
}
|
|
|
|
dispatch(event: SceneNpcTokensSessionEvent): SceneNpcTokensSessionState {
|
|
switch (event.kind) {
|
|
case 'clear':
|
|
return this.reset();
|
|
case 'setScale': {
|
|
const scale = clampNpcTokenSessionScale(event.scale);
|
|
if (this.state.scale === scale) return this.state;
|
|
this.state = {
|
|
...this.state,
|
|
revision: this.state.revision + 1,
|
|
scale,
|
|
};
|
|
return this.state;
|
|
}
|
|
case 'move': {
|
|
const placementId = String(event.placementId ?? '');
|
|
if (!placementId) return this.state;
|
|
const nx = Math.max(0, Math.min(1, event.nx));
|
|
const ny = Math.max(0, Math.min(1, event.ny));
|
|
if (!Number.isFinite(nx) || !Number.isFinite(ny)) return this.state;
|
|
const prev = this.state.byPlacementId[placementId];
|
|
if (prev && prev.nx === nx && prev.ny === ny) return this.state;
|
|
this.state = {
|
|
revision: this.state.revision + 1,
|
|
byPlacementId: {
|
|
...this.state.byPlacementId,
|
|
[placementId]: { nx, ny },
|
|
},
|
|
scale: this.state.scale,
|
|
};
|
|
return this.state;
|
|
}
|
|
default: {
|
|
const _exhaustive: never = event;
|
|
void _exhaustive;
|
|
return this.state;
|
|
}
|
|
}
|
|
}
|
|
}
|