Последняя активность 2 weeks ago

Версия f097c21ba0943bcfe04573c793427a5fec2456ec

gistfile1.txt Исходник
1/**
2 * CharacterRegistry — central lookup for Character objects.
3 *
4 * Usage:
5 * import { CharacterRegistry } from "@registry/CharacterRegistry";
6 *
7 * const char = CharacterRegistry.find("«Flash»");
8 * const chars = CharacterRegistry.forUser("flash");
9 * const active = CharacterRegistry.getActive("flash");
10 */
11
12 import fs from "fs";
13 import path from "path";
14 import { Character, UserKey, CharName } from "@types";
15 import { Paths } from "@helpers/paths";
16
17 const CHARS_PATH = Paths.data("characters.json");
18
19 let _cache: Record<string, { characters: Character[] }> | null = null;
20
21 function loadChars(): Record<string, { characters: Character[] }> {
22 if (!_cache) {
23 try {
24 _cache = JSON.parse(fs.readFileSync(CHARS_PATH, "utf8"));
25 console.log("[CharacterRegistry] cache miss — loading from disk");
26 }
27 catch { _cache = {}; }
28 }
29
30 return _cache!;
31 }
32
33 export const CharacterRegistry = {
34 /**
35 * Find a character by name across all users.
36 * Character names are unique across users (enforced by conflict system).
37 */
38 find(charName: CharName): Character | null {
39 const chars = loadChars();
40 for (const data of Object.values(chars)) {
41 const found = data.characters?.find(
42 (c) => c.name.toLowerCase() === charName.toLowerCase()
43 );
44 if (found) return found;
45 }
46 return null;
47 },
48
49 all(): Character[] {
50 const chars = loadChars();
51 return Object.values(chars).flatMap((data: any) => data.characters ?? []);
52 },
53
54 /**
55 * Find a character by name for a specific user.
56 */
57 findForUser(userKey: UserKey, charName: CharName): Character | null {
58 const chars = loadChars();
59 return chars[userKey]?.characters?.find(
60 (c) => c.name.toLowerCase() === charName.toLowerCase()
61 ) ?? null;
62 },
63
64 /**
65 * Get all characters for a user.
66 */
67 forUser(userKey: UserKey): Character[] {
68 const chars = loadChars();
69 return chars[userKey]?.characters ?? [];
70 },
71
72 /**
73 * Get the active character for a user (from characters.json only, no borrow).
74 * For effective char (including borrows), use getEffectiveCharacter from borrow.ts.
75 */
76 getActive(userKey: UserKey): Character | null {
77 return CharacterRegistry.forUser(userKey).find((c) => c.active) ?? null;
78 },
79
80 /**
81 * Get all characters shared with a given user across all owners.
82 */
83 sharedWith(userKey: UserKey): { char: Character; ownerKey: UserKey }[] {
84 const chars = loadChars();
85 const result: { char: Character; ownerKey: UserKey }[] = [];
86 for (const [ownerKey, data] of Object.entries(chars)) {
87 if (ownerKey === userKey) continue;
88 for (const char of data.characters ?? []) {
89 if (char.sharedWith?.includes(userKey)) {
90 result.push({ char, ownerKey });
91 }
92 }
93 }
94 return result;
95 },
96
97 invalidateCache(): void {
98 _cache = null;
99 },
100 };