Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export class App {
}

/**
* @param {{label: string, delay?: number, repeat?: boolean, errorHandler?: (error: Error, world: World) => void, defaultSystemGroup?: import('../type/index.js').Constructor}} config
* @param {{label: import('../type/index.js').Constructor, delay?: number, repeat?: boolean, errorHandler?: (error: Error, world: World) => void, defaultSystemGroup?: import('../type/index.js').Constructor}} config
*/
createSchedule(config) {
this.scheduler.set(new Executable(config))
Expand Down
4 changes: 2 additions & 2 deletions src/core/core/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ export function defaultRunner(scheduler, world) {
const now = performance.now()

for (const executable of scheduler.values()) {
state.set(executable.label, {
state.set(executable.typeId, {
active: true,
nextRunAt: now + executable.delay
})
}

const update = (/** @type {number} */ time) => {
for (const executable of scheduler.values()) {
const execState = state.get(executable.label)
const execState = state.get(executable.typeId)

if (!execState || !execState.active) continue

Expand Down
23 changes: 13 additions & 10 deletions src/core/core/schedules.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
/**
* The core schedules of an {@link App app}.
*
* @readonly
* @enum {string}
* Core schedule labels used by an {@link App app}.
*/
export const AppSchedule = {
class Startup {}

/**
* Main loop schedule.
*/
class Update {}

export const AppSchedule = Object.freeze({

/**
* The schedule that updates systems it contains every frame.
* The frame rate is determined by the refesh rate of the device.
*
* The frame rate is determined by the refresh rate of the device.
*/
Update: 'mainupdate',
Update,

/**
* Schedule which runs once when the {@link App app} is
* {@link App.run run}.
*/
Startup: 'startup'
}
Startup
})
12 changes: 10 additions & 2 deletions src/schedule/core/executable.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { World } from '../../ecs/index.js'
import { typeid } from '../../type/index.js'
import { Schedule } from './schedule.js'

/**
Expand Down Expand Up @@ -28,7 +29,7 @@ export class Executable {

/**
* @readonly
* @type {string}
* @type {import('../../type/index.js').Constructor}
*/
label

Expand Down Expand Up @@ -63,7 +64,7 @@ export class Executable {
errorHandler

/**
* @param {{label: string, repeat?: boolean, delay?: number, errorHandler?: (error: Error, world: World) => void, defaultSystemGroup?: import('../../type/index.js').Constructor}} config
* @param {{label: import('../../type/index.js').Constructor, repeat?: boolean, delay?: number, errorHandler?: (error: Error, world: World) => void, defaultSystemGroup?: import('../../type/index.js').Constructor}} config
*/
constructor(config) {
this.label = config.label
Expand All @@ -72,4 +73,11 @@ export class Executable {
this.errorHandler = config.errorHandler
this.defaultSystemGroup = config.defaultSystemGroup
}

/**
* @returns {string}
*/
get typeId() {
return typeid(this.label)
}
}
16 changes: 10 additions & 6 deletions src/schedule/core/scheduler.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { Executable } from './executable.js'
import { Schedule } from './schedule.js'
import { typeid } from '../../type/index.js'

/**
* Stores labeled {@link Executable executables}.
*
* @example
* ```ts
* scheduler.set(new Executable({ label: "primary" }))
* scheduler.set(new Executable({ label: "secondary" }))
* class PrimarySchedule {}
* class SecondarySchedule {}
*
* const primarySchedule = scheduler.get("primary")
* scheduler.set(new Executable({ label: PrimarySchedule }))
* scheduler.set(new Executable({ label: SecondarySchedule }))
*
* const primarySchedule = scheduler.get(PrimarySchedule)
* ```
*/
export class Scheduler {
Expand All @@ -23,15 +27,15 @@ export class Scheduler {
* @param {Executable} executable
*/
set(executable) {
this.executables.set(executable.label, executable)
this.executables.set(typeid(executable.label), executable)
}

/**
* @param {string} label
* @param {import('../../type/index.js').Constructor} label
* @returns {Schedule | undefined}
*/
get(label) {
return this.executables.get(label)?.schedule
return this.executables.get(typeid(label))?.schedule
}

/**
Expand Down
51 changes: 26 additions & 25 deletions src/schedule/core/systembuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ export class SchedulerBuilder {
const defaultGroupsBySchedule = new Map()

for (const executable of scheduler.values()) {
defaultGroupsBySchedule.set(executable.label, executable.defaultSystemGroup)
defaultGroupsBySchedule.set(typeid(executable.label), executable.defaultSystemGroup)
}

const schedules = this.createScheduleContexts(defaultGroupsBySchedule)

for (const [scheduleLabel, context] of schedules) {
const schedule = scheduler.get(scheduleLabel)
for (const [, context] of schedules) {
const schedule = scheduler.get(context.label)

assert(schedule, `The schedule label "${scheduleLabel}" is not set in the provided \`Scheduler\`.`)
assert(schedule, `The schedule label "${context.label.name}" is not set in the provided \`Scheduler\`.`)

for (const system of this.sortScheduleSystems(context)) {
schedule.add(system.config.system)
Expand All @@ -74,7 +74,7 @@ export class SchedulerBuilder {
const groupTypeId = typeid(config.label)

if (context.groupIdsByTypeId.has(groupTypeId)) {
throws(`Duplicate system group label "${config.label.name}" on schedule "${config.schedule}".`)
throws(`Duplicate system group label "${config.label.name}" on schedule "${config.schedule.name}".`)
}

/** @type {SystemGroupRegistration} */
Expand All @@ -94,7 +94,7 @@ export class SchedulerBuilder {
const existing = context.nodesByLabel.get(groupLabel)

if (existing) {
throws(`Duplicate system group label "${groupLabel}" on schedule "${config.schedule}". Use a unique label or direct function references in ordering.`)
throws(`Duplicate system group label "${groupLabel}" on schedule "${config.schedule.name}". Use a unique label or direct function references in ordering.`)
}

context.nodesByLabel.set(groupLabel, { kind: ScheduleNodeKind.Group, id: group.id })
Expand All @@ -116,17 +116,17 @@ export class SchedulerBuilder {
const existing = context.nodesByLabel.get(systemLabel)

if (existing) {
throws(`Duplicate system label "${systemLabel}" on schedule "${config.schedule}". Use a unique label or direct function references in ordering.`)
throws(`Duplicate system label "${systemLabel}" on schedule "${config.schedule.name}". Use a unique label or direct function references in ordering.`)
}

context.nodesByLabel.set(systemLabel, { kind: ScheduleNodeKind.System, id: system.id })
}
}

for (const [scheduleLabel, context] of schedules) {
context.defaultSystemGroup = defaultGroupsBySchedule.get(scheduleLabel)
for (const [, context] of schedules) {
context.defaultSystemGroup = defaultGroupsBySchedule.get(typeid(context.label))

this.resolveGroupParents(context, scheduleLabel)
this.resolveGroupParents(context, context.label)

for (let i = 0; i < context.systems.length; i++) {
const system = context.systems[i]
Expand All @@ -137,7 +137,7 @@ export class SchedulerBuilder {
const groupId = context.groupIdsByTypeId.get(typeid(groupLabel))

if (groupId === undefined) {
throws(`The system group "${groupLabel.name}" must be registered explicitly before it can be used on schedule "${scheduleLabel}".`)
throws(`The system group "${groupLabel.name}" must be registered explicitly before it can be used on schedule "${context.label.name}".`)
}

context.groups[groupId].systems.push(system.id)
Expand All @@ -150,7 +150,7 @@ export class SchedulerBuilder {
/**
* @private
* @param {ScheduleContext} context
* @param {string} scheduleLabel
* @param {Constructor} scheduleLabel
*/
resolveGroupParents(context, scheduleLabel) {
for (let i = 0; i < context.groups.length; i++) {
Expand All @@ -162,7 +162,7 @@ export class SchedulerBuilder {
const parentId = context.groupIdsByTypeId.get(typeid(parentLabel))

if (parentId === undefined) {
throws(`The parent system group "${parentLabel.name}" must be registered explicitly before it can be used on schedule "${scheduleLabel}".`)
throws(`The parent system group "${parentLabel.name}" must be registered explicitly before it can be used on schedule "${scheduleLabel.name}".`)
}

group.parentId = parentId
Expand Down Expand Up @@ -197,7 +197,7 @@ export class SchedulerBuilder {
if (visitState === GroupVisitState.Visiting) {
const group = context.groups[groupId]

throws(`Schedule "${context.label}" contains cyclic system group nesting involving "${group.config.label.name}".`)
throws(`Schedule "${context.label.name}" contains cyclic system group nesting involving "${group.config.label.name}".`)
}

if (visitState === GroupVisitState.Visited) return
Expand All @@ -223,7 +223,7 @@ export class SchedulerBuilder {
const sorted = kahnTopologySort(graph)

if (!sorted) {
throws(`Schedule "${context.label}" contains cyclic system ordering constraints.`)
throws(`Schedule "${context.label.name}" contains cyclic system ordering constraints.`)
}

/** @type {SystemRegistration[]} */
Expand Down Expand Up @@ -347,7 +347,7 @@ export class SchedulerBuilder {
const node = context.nodesByLabel.get(stringLabel)

if (!node) {
throws(`Could not resolve the system or system group label "${stringLabel}" on schedule "${context.label}".`)
throws(`Could not resolve the system or system group label "${stringLabel}" on schedule "${context.label.name}".`)
}

return node
Expand All @@ -374,7 +374,7 @@ export class SchedulerBuilder {
const toNodeId = toNodes[j]

if (fromNodeId === toNodeId) {
throws(`The reference "${describeReference(targetLabel)}" creates a self-referential system ordering on schedule "${context.label}".`)
throws(`The reference "${describeReference(targetLabel)}" creates a self-referential system ordering on schedule "${context.label.name}".`)
}

const key = `${fromNodeId}:${toNodeId}`
Expand All @@ -399,7 +399,7 @@ export class SchedulerBuilder {
if (node.kind === ScheduleNodeKind.System) {
const graphId = graphIdsBySystemId.get(node.id)

assert(graphId !== undefined, `Internal error: Could not resolve graph node for system ${node.id} on schedule "${context.label}".`)
assert(graphId !== undefined, `Internal error: Could not resolve graph node for system ${node.id} on schedule "${context.label.name}".`)

return [graphId]
}
Expand All @@ -414,7 +414,7 @@ export class SchedulerBuilder {
for (let i = 0; i < systems.length; i++) {
const graphId = graphIdsBySystemId.get(systems[i])

assert(graphId !== undefined, `Internal error: Could not resolve graph node for system ${systems[i]} on schedule "${context.label}".`)
assert(graphId !== undefined, `Internal error: Could not resolve graph node for system ${systems[i]} on schedule "${context.label.name}".`)
graphIds.push(graphId)
}

Expand All @@ -435,7 +435,7 @@ export class SchedulerBuilder {
expandGroupToGraphNode(context, groupId) {
const graphId = context.graphIdsByGroupId?.get(groupId)

assert(graphId !== undefined, `Internal error: Could not resolve graph node for system group ${groupId} on schedule "${context.label}".`)
assert(graphId !== undefined, `Internal error: Could not resolve graph node for system group ${groupId} on schedule "${context.label.name}".`)

return graphId
}
Expand Down Expand Up @@ -469,7 +469,7 @@ export class SchedulerBuilder {
if (visiting.has(groupId)) {
const group = context.groups[groupId]

throws(`Schedule "${context.label}" contains cyclic system group nesting involving "${group.config.label.name}".`)
throws(`Schedule "${context.label.name}" contains cyclic system group nesting involving "${group.config.label.name}".`)
}

visiting.add(groupId)
Expand Down Expand Up @@ -498,11 +498,12 @@ export class SchedulerBuilder {

/**
* @param {Map<string, ScheduleContext>} schedules
* @param {string} label
* @param {Constructor} label
* @returns {ScheduleContext}
*/
function getOrCreateScheduleContext(schedules, label) {
const existing = schedules.get(label)
const scheduleTypeId = typeid(label)
const existing = schedules.get(scheduleTypeId)

if (existing) return existing

Expand All @@ -516,7 +517,7 @@ function getOrCreateScheduleContext(schedules, label) {
defaultSystemGroup: undefined
})

schedules.set(label, created)
schedules.set(scheduleTypeId, created)

return created
}
Expand All @@ -538,7 +539,7 @@ const ScheduleNodeKind = Object.freeze({

/**
* @typedef ScheduleContext
* @property {string} label
* @property {Constructor} label
* @property {SystemRegistration[]} systems
* @property {SystemGroupRegistration[]} groups
* @property {Map<string, ScheduleNodeRef>} nodesByLabel
Expand Down
4 changes: 2 additions & 2 deletions src/schedule/core/systemconfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/**
* @typedef SystemConfig
* @property {SystemFunc} system
* @property {string} schedule
* @property {Constructor} schedule
* @property {string | undefined} [label]
* @property {Constructor | undefined} [systemGroup]
* @property {SystemOrderReference[] | undefined} [before]
Expand All @@ -18,7 +18,7 @@
/**
* @typedef SystemGroupConfig
* @property {Constructor} label
* @property {string} schedule
* @property {Constructor} schedule
* @property {Constructor | undefined} [parent]
* @property {SystemOrderReference[] | undefined} [before]
* @property {SystemOrderReference[] | undefined} [after]
Expand Down
Loading
Loading