Spaces:
Sleeping
Sleeping
| import { defineTable } from 'convex/server'; | |
| import { Infer, v } from 'convex/values'; | |
| const input = v.object({ | |
| // Inputs are scoped to a single engine. | |
| engineId: v.id('engines'), | |
| // Monotonically increasing input number within a world starting at 0. | |
| number: v.number(), | |
| // Name of the input handler to run. | |
| name: v.string(), | |
| // Dynamically typed arguments and return value for the input handler. We'll | |
| // provide type safety at a higher layer. | |
| args: v.any(), | |
| returnValue: v.optional( | |
| v.union( | |
| v.object({ | |
| kind: v.literal('ok'), | |
| value: v.any(), | |
| }), | |
| v.object({ | |
| kind: v.literal('error'), | |
| message: v.string(), | |
| }), | |
| ), | |
| ), | |
| // Timestamp when the server received the input. This timestamp is best-effort, | |
| // since we don't guarantee strict monotonicity here. So, an input may not get | |
| // assigned to the engine step whose time interval contains this timestamp. | |
| received: v.number(), | |
| }); | |
| export const engine = v.object({ | |
| // What is the current simulation time for the engine? Monotonically increasing. | |
| currentTime: v.optional(v.number()), | |
| // What was `currentTime` for the preceding step of the engine? | |
| lastStepTs: v.optional(v.number()), | |
| // How far has the engine processed in the input queue? | |
| processedInputNumber: v.optional(v.number()), | |
| running: v.boolean(), | |
| // Monotonically increasing counter that serializes all engine runs. If we ever | |
| // end up with two steps overlapping in time, this counter will force them to | |
| // conflict. | |
| generationNumber: v.number(), | |
| }); | |
| export type Engine = Infer<typeof engine>; | |
| export const engineTables = { | |
| inputs: defineTable(input).index('byInputNumber', ['engineId', 'number']), | |
| engines: defineTable(engine), | |
| }; | |