diff --git a/src/client/core.ts b/src/client/core.ts index 64306508..20579b2d 100644 --- a/src/client/core.ts +++ b/src/client/core.ts @@ -3,11 +3,17 @@ import { mergeDeep } from "@rbxts/sift/out/Dictionary"; import { ClientDispatcher } from "./dispatcher"; import { DEFAULT_OPTIONS } from "./options"; import { ClientRegistry } from "./registry"; +import { CommanderEvents } from "./types"; export namespace CommanderClient { let started = false; - const registryInstance = new ClientRegistry(); - const dispatcherInstance = new ClientDispatcher(registryInstance); + const events: CommanderEvents = { + historyUpdated: new Instance("BindableEvent"), + commandAdded: new Instance("BindableEvent"), + groupAdded: new Instance("BindableEvent"), + }; + const registryInstance = new ClientRegistry(events); + const dispatcherInstance = new ClientDispatcher(registryInstance, events); let optionsObject = DEFAULT_OPTIONS; const IS_CLIENT = RunService.IsClient(); @@ -42,10 +48,16 @@ export namespace CommanderClient { options.app({ options: optionsObject, execute: (path, text) => dispatcherInstance.run(path, text), - commands: registryInstance.getCommandOptions(), - groups: registryInstance.getGroupOptions(), - history: dispatcherInstance.getHistory(), - onHistoryUpdated: dispatcherInstance.getHistorySignal(), + initialData: { + commands: registryInstance.getCommandOptions(), + groups: registryInstance.getGroupOptions(), + history: dispatcherInstance.getHistory(), + }, + events: { + historyUpdated: events.historyUpdated.Event, + commandAdded: events.commandAdded.Event, + groupAdded: events.groupAdded.Event, + }, }); } } diff --git a/src/client/dispatcher.ts b/src/client/dispatcher.ts index da7856b4..763e2c80 100644 --- a/src/client/dispatcher.ts +++ b/src/client/dispatcher.ts @@ -1,14 +1,20 @@ import { Players } from "@rbxts/services"; -import { CommandPath } from "../shared"; +import { BaseRegistry, CommandPath } from "../shared"; import { BaseDispatcher } from "../shared/core/dispatcher"; import { DEFAULT_HISTORY_LENGTH } from "./options"; -import { ClientOptions, HistoryEntry } from "./types"; +import { ClientOptions, CommanderEvents, HistoryEntry } from "./types"; export class ClientDispatcher extends BaseDispatcher { private readonly history: HistoryEntry[] = []; - private readonly historyEvent = new Instance("BindableEvent"); private maxHistoryLength = DEFAULT_HISTORY_LENGTH; + constructor( + registry: BaseRegistry, + private readonly events: CommanderEvents, + ) { + super(registry); + } + /** * Initialises the client dispatcher. * @@ -60,22 +66,12 @@ export class ClientDispatcher extends BaseDispatcher { return this.history; } - /** - * Gets the history signal, which will be fired each time a new - * {@link HistoryEntry} is added. - * - * @returns The history signal - */ - getHistorySignal() { - return this.historyEvent.Event; - } - private addHistoryEntry(entry: HistoryEntry) { if (this.history.size() >= this.maxHistoryLength) { this.history.remove(0); } this.history.push(entry); - this.historyEvent.Fire(entry); + this.events.historyUpdated.Fire(entry); } } diff --git a/src/client/registry.ts b/src/client/registry.ts index a58a0698..9f6fb9ac 100644 --- a/src/client/registry.ts +++ b/src/client/registry.ts @@ -5,19 +5,22 @@ import { CommandGroup } from "../shared/core/command"; import { BaseRegistry } from "../shared/core/registry"; import { remotes } from "../shared/network"; import { ServerCommand } from "./command"; +import { CommanderEvents } from "./types"; export class ClientRegistry extends BaseRegistry { + private initialSyncReceived = false; + + constructor(private readonly events: CommanderEvents) { + super(); + } + init() { this.registerBuiltInTypes(); } async sync() { - let firstDispatch = false; remotes.sync.dispatch.connect((data) => { - if (!firstDispatch) { - firstDispatch = true; - } - + if (!this.initialSyncReceived) this.initialSyncReceived = true; this.registerServerGroups(data.groups); this.registerServerCommands(data.commands); }); @@ -25,9 +28,7 @@ export class ClientRegistry extends BaseRegistry { return new Promise((resolve) => { // Wait until dispatch has been received - while (!firstDispatch) { - RunService.Heartbeat.Wait(); - } + while (!this.initialSyncReceived) RunService.Heartbeat.Wait(); resolve(undefined); }) .timeout(5) @@ -46,8 +47,8 @@ export class ClientRegistry extends BaseRegistry { getGroupOptions() { const groupMap = new Map(); - for (const [k, v] of this.commands) { - groupMap.set(k, copyDeep(v.options as CommandOptions)); + for (const [k, v] of this.groups) { + groupMap.set(k, copyDeep(v.options as GroupOptions)); } return groupMap; } diff --git a/src/client/types.ts b/src/client/types.ts index 57921d48..9f3bd200 100644 --- a/src/client/types.ts +++ b/src/client/types.ts @@ -3,17 +3,33 @@ import { CommandOptions, CommandPath, GroupOptions } from "../shared"; export interface ClientOptions { historyLength?: number; activationKeys?: Enum.KeyCode[]; - app?: (data: AppData) => void; + app?: (data: AppContext) => void; } -export interface AppData { +export interface CommanderEvents { + historyUpdated: BindableEvent<(entry: HistoryEntry) => void>; + commandAdded: BindableEvent<(command: CommandOptions) => void>; + groupAdded: BindableEvent<(group: GroupOptions) => void>; +} + +export type CommanderEventCallbacks = { + [K in keyof CommanderEvents]: CommanderEvents[K] extends BindableEvent< + infer R + > + ? RBXScriptSignal + : never; +}; + +export type AppContext = { options: ClientOptions; execute: (path: CommandPath, text: string) => Promise; - commands: Map; - groups: Map; - history: HistoryEntry[]; - onHistoryUpdated: RBXScriptSignal<(entry: HistoryEntry) => void>; -} + initialData: { + commands: Map; + groups: Map; + history: HistoryEntry[]; + }; + events: CommanderEventCallbacks; +}; export interface HistoryEntry { text: string;