App constructor

App({
  1. AccessConflictPolicy accessConflictPolicy = AccessConflictPolicy.warn,
  2. void onDiagnostic(
    1. String message
    )?,
  3. AppDiagnostics diagnostics = const AppDiagnostics(),
})

Creates an app with the built-in schedules registered.

Implementation

App({
  this.accessConflictPolicy = AccessConflictPolicy.warn,
  this.onDiagnostic,
  AppDiagnostics diagnostics = const AppDiagnostics(),
}) : profiler = _buildProfiler(diagnostics, onDiagnostic) {
  for (final label in Schedules.all) {
    _schedules[label] = Schedule(label);
  }
  // Lets systems dispatch a custom schedule through world.runSchedule
  // without reaching the app.
  world.resources.insert<ScheduleRunner>(ScheduleRunner(world, runSchedule));
  // Built-in runtime behavior, like the state-scoped despawn walk: entities
  // carrying DespawnAfter tick down each update and despawn at zero. Games
  // order against it with before/after on DespawnAfterSystem.label. Gated
  // on the store having rows so games that never use the component pay one
  // map lookup per pass and see nothing in system profiles.
  addSystemAdapter(
    DespawnAfterSystem(),
    schedule: Schedules.update,
    label: DespawnAfterSystem.label,
    runIf: (world) => world.ensureObjectStore<DespawnAfter>().length > 0,
  );
  final p = profiler;
  if (p != null) world.resources.insert<SystemProfiler>(p);
  final sink = onDiagnostic;
  if (sink != null) {
    // The accidental O(N×M) shape: a query iterated inside another
    // query's `each` in the same system. Detection runs only in debug
    // mode (the world's tracking sits inside asserts) and reports once
    // per system.
    world.onNestedQuery = sink;
    // Report dropped unread events once per type.
    world.onEventReaderSkip = (type, skipped) {
      if (!_reportedEventSkips.add(type)) return;
      sink(
        'An EventReader<$type> fell behind: $skipped unread event(s) '
        'expired past the channel retention window. This means a reader '
        'went longer than the window without a turn — usually a system '
        'gated by runIf, or a FIXED-step reader at a refresh rate high '
        'enough that render frames carry zero fixed steps. Widen the '
        'window with addEvent<$type>(retainedUpdates: ...) or pass null '
        'to retain events until every reader consumes them. (Reported '
        'once per event type.)',
      );
    };
  }
}