4.7 KiB
EnhancedGameServer
(no submodules)
Purpose
EnhancedGameServer is the top-of-stack integration layer for
@suaveplan/game-server. Waves B and C-1 shipped the engine, plugin
manager, and eight concrete plugins, but consumers still had to wire the
loop, manager, engine, and every plugin by hand on each boot. This module
collapses that boilerplate behind a single bootstrap(options) entry
point and returns a typed handle exposing both the wired GameEngine
and the bundle of installed plugins for direct access.
The integration is deliberately universal — zero browser, React, or
DOM dependencies. The upstream React lobby shell is explicitly deferred
to a future react-game-server package. All collaborators are injected
through the structural contracts in @suaveplan/types
(Clock, IdGenerator, LoggerLike, TimersLike, EventBusLike,
Rng, StorageLike) plus the public APIs of @suaveplan/feature-flags,
@suaveplan/rules, and @suaveplan/workflow.
Features
- Single
bootstrap(options)entry point — no manual wiring. - Pre-installs every built-in plugin (
logging,analytics,persistence,feature-flags,rules,workflow,ab-test) viaPluginManager.installAllso dependency order is honoured. - Enables every plugin after install so callers can opt-out by disabling individual plugins post-bootstrap rather than skipping them entirely.
- Caller-supplied
extraPluginsare installed last and enabled in the same pass. BOOTSTRAP_FAILEDwraps any plugin install failure with the originalcausechain intact.ALREADY_BOOTSTRAPPEDprevents accidental double-wiring.start()/tick()/stop()/dispose()delegate to the underlyingGameEngineso existing engine codes (ENGINE_NOT_STARTED,ENGINE_DISPOSED) propagate unchanged.
Usage: Basic
import { EnhancedGameServer } from "@suaveplan/game-server/integrations/enhanced-server";
const server = new EnhancedGameServer({
clock: () => Date.now(),
timers,
idGenerator,
logger,
events,
emitter,
flagManager,
ruleEngine,
rng,
storage,
analyticsSink: (event) => console.log(event),
});
const { engine, plugins } = await server.bootstrap();
server.start();
await server.tick();
server.stop();
await server.dispose();
Usage: Advanced
Install extra plugins after the canonical seven and configure tick rate:
class TelemetryPlugin extends BasePlugin {
public readonly name = "telemetry";
public readonly version = "1.0.0";
}
const handle = await server.bootstrap({
autoStartLoop: false,
tickRate: 30,
extraPlugins: [new TelemetryPlugin()],
});
// Disable analytics without uninstalling the rest.
await handle.engine.getPlugin("analytics");
// Direct typed access for per-plugin configuration:
handle.plugins.featureFlag.evaluate("dark-mode", "player-1");
API Reference
class EnhancedGameServer(deps: EnhancedGameServerDeps)— constructor.bootstrap(options?: EnhancedServerBootstrapOptions)— returnsPromise<EnhancedServerHandle>. ThrowsALREADY_BOOTSTRAPPEDon the second call and wraps install failures inBOOTSTRAP_FAILED.start()— delegates toGameEngine.start().tick()— delegates toGameEngine.tick().stop()— delegates toGameEngine.stop().dispose()— idempotent; safe before bootstrap.isBootstrapped()— predicate.getHandle()— returns the typed handle; throws if not bootstrapped.
EnhancedServerHandle exposes the wired engine and a strongly-typed
plugins bundle ({ abTest, analytics, featureFlag, logging, persistence, rules, workflow, extras }).
Implementation Notes
- Plugins are installed in an order that satisfies their declared
dependencies. The current canonical set declares none, so the order is determined by the integration: log-first so subsequent installs are recorded, analytics next to capture session events, then persistence, feature-flags, rules, workflow, and finally A/B-test. - Bootstrap calls
PluginManager.installAll(whichtopoSorts its argument) for an atomic batch install. After install, each plugin is individually enabled —PluginManager.enableis idempotent so the second-pass loop is safe. - The shared
EventBusLike<EnhancedServerEventMap>is intersection-typed across the loop, manager, and engine maps so a single bus services all three subsystems without per-subsystem adapters. - All error wrapping preserves the original
causeso consumers can walk the cause chain via@suaveplan/error's utilities. - The class never holds React or DOM references; every concrete dependency is injected through a structural contract, keeping the package universal.