mirror of
https://github.com/YuzuZensai/VRC-Circle.git
synced 2026-09-13 10:58:59 +00:00
69 lines
1.9 KiB
TypeScript
69 lines
1.9 KiB
TypeScript
import type { World, WorldSnapshot } from "../../shared/types/world";
|
|||
|
|
import type { FieldSource } from "../../shared/types/repository";
|
||
|
|
import { repos } from "./repository/manager";
|
||
|
|
|
||
|
|
export type { WorldSnapshot };
|
||
|
|
|
||
|
|
type Change = { type: "seed"; snapshot: WorldSnapshot } | { type: "upsert"; world: World };
|
||
|
|
type Listener = (change: Change) => void;
|
||
|
|
|
||
|
|
class WorldStore {
|
||
|
|
private readonly listeners = new Set<Listener>();
|
||
|
|
private byAuthor = new Map<string, Set<string>>();
|
||
|
|
private wired = false;
|
||
|
|
|
||
|
|
onChange(fn: Listener): () => void {
|
||
|
|
this.wire();
|
||
|
|
this.listeners.add(fn);
|
||
|
|
return () => this.listeners.delete(fn);
|
||
|
|
}
|
||
|
|
|
||
|
|
private wire(): void {
|
||
|
|
if (this.wired || !repos.hasActive) return;
|
||
|
|
this.wired = true;
|
||
|
|
repos.active.worlds.onChange((c) => {
|
||
|
|
this.emit({ type: "upsert", world: c.entity });
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
setAuthorWorlds(authorId: string, worlds: World[]): void {
|
||
|
|
this.byAuthor.set(authorId, new Set(worlds.map((w) => w.id)));
|
||
|
|
repos.active.worlds.upsertMany(worlds, "rest:list");
|
||
|
|
this.emit({ type: "seed", snapshot: this.snapshot() });
|
||
|
|
}
|
||
|
|
|
||
|
|
addWorld(world: World, src: FieldSource = world.detailed ? "rest:detail" : "rest:list"): void {
|
||
|
|
repos.active.worlds.upsert(world, src);
|
||
|
|
}
|
||
|
|
|
||
|
|
authorWorlds(authorId: string): World[] {
|
||
|
|
const ids = this.byAuthor.get(authorId);
|
||
|
|
if (!ids) return [];
|
||
|
|
return repos.active.worlds.getMany([...ids]);
|
||
|
|
}
|
||
|
|
|
||
|
|
get(worldId: string): World | undefined {
|
||
|
|
return repos.active.worlds.get(worldId);
|
||
|
|
}
|
||
|
|
|
||
|
|
snapshot(): WorldSnapshot {
|
||
|
|
return {
|
||
|
|
worlds: repos.hasActive ? repos.active.worlds.all() : [],
|
||
|
|
byAuthor: Object.fromEntries([...this.byAuthor].map(([k, v]) => [k, [...v]])),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
reset(): void {
|
||
|
|
this.byAuthor.clear();
|
||
|
|
this.wired = false;
|
||
|
|
this.wire();
|
||
|
|
this.emit({ type: "seed", snapshot: this.snapshot() });
|
||
|
|
}
|
||
|
|
|
||
|
|
private emit(change: Change): void {
|
||
|
|
for (const fn of this.listeners) fn(change);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export const worldStore = new WorldStore();
|