import { ObjectType, v } from 'convex/values'; import { Conversation, serializedConversation } from './conversation'; import { Player, serializedPlayer } from './player'; import { Agent, serializedAgent } from './agent'; import { GameId, parseGameId, playerId } from './ids'; import { parseMap } from '../util/object'; import { GameCycle, gameCycleSchema } from './gameCycle'; import { Votes, VotesSchema } from './voting'; export const historicalLocations = v.array( v.object({ playerId, location: v.bytes(), }), ); export const serializedWorld = { nextId: v.number(), conversations: v.array(v.object(serializedConversation)), players: v.array(v.object(serializedPlayer)), playersInit: v.array(v.object(serializedPlayer)), agents: v.array(v.object(serializedAgent)), historicalLocations: v.optional(historicalLocations), gameCycle: v.object(gameCycleSchema), gameVotes: v.array(v.object(VotesSchema)), llmVotes: v.array(v.object(VotesSchema)), winner: v.optional(v.union(v.literal('werewolves'), v.literal('villagers'))) }; export type SerializedWorld = ObjectType; export class World { nextId: number; conversations: Map, Conversation>; players: Map, Player>; playersInit: Map, Player>; // kept for voting purpose agents: Map, Agent>; historicalLocations?: Map, ArrayBuffer>; gameCycle: GameCycle; gameVotes: Votes[]; llmVotes: Votes[]; winner?: 'werewolves' | 'villagers' | undefined constructor(serialized: SerializedWorld) { const { nextId, historicalLocations } = serialized; this.nextId = nextId; this.conversations = parseMap(serialized.conversations, Conversation, (c) => c.id); this.players = parseMap(serialized.players, Player, (p) => p.id); this.playersInit = parseMap(serialized.playersInit, Player, (p) => p.id); this.agents = parseMap(serialized.agents, Agent, (a) => a.id); this.gameCycle = new GameCycle(serialized.gameCycle); this.gameVotes = serialized.gameVotes.map((v) => new Votes(v)); this.llmVotes = serialized.llmVotes.map((v) => new Votes(v)); this.winner = serialized.winner; if (historicalLocations) { this.historicalLocations = new Map(); for (const { playerId, location } of historicalLocations) { this.historicalLocations.set(parseGameId('players', playerId), location); } } } playerConversation(player: Player): Conversation | undefined { return [...this.conversations.values()].find((c) => c.participants.has(player.id)); } serialize(): SerializedWorld { return { nextId: this.nextId, conversations: [...this.conversations.values()].map((c) => c.serialize()), players: [...this.players.values()].map((p) => p.serialize()), playersInit: [...this.playersInit.values()].map((p) => p.serialize()), agents: [...this.agents.values()].map((a) => a.serialize()), historicalLocations: this.historicalLocations && [...this.historicalLocations.entries()].map(([playerId, location]) => ({ playerId, location, })), gameCycle: this.gameCycle.serialize(), gameVotes: this.gameVotes.map((v) => v.serialize()), llmVotes: this.llmVotes.map((v) => v.serialize()), winner: this.winner, }; } }