@agent-os-lab/agent-game-sdk 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -0
- package/package.json +38 -0
- package/src/core/agent-game-store.ts +110 -0
- package/src/core/agent-service-event-adapter.ts +20 -0
- package/src/core/assets.ts +119 -0
- package/src/core/commands.ts +42 -0
- package/src/core/errors.ts +19 -0
- package/src/core/event-adapter.ts +40 -0
- package/src/core/index.ts +23 -0
- package/src/core/life-presets.ts +54 -0
- package/src/core/movement.ts +50 -0
- package/src/core/office-building-layout.ts +376 -0
- package/src/core/office-layout.ts +152 -0
- package/src/core/pixel-character-avatar.ts +87 -0
- package/src/core/pixel-character.ts +684 -0
- package/src/core/realtime-events.ts +44 -0
- package/src/core/realtime-transport.ts +39 -0
- package/src/core/reducer.ts +105 -0
- package/src/core/scene.ts +144 -0
- package/src/core/schedule.ts +20 -0
- package/src/core/sequence.ts +48 -0
- package/src/core/state.ts +26 -0
- package/src/core/svg-pixel-avatar.ts +372 -0
- package/src/core/town-office-assets.ts +109 -0
- package/src/core/town-office-room-presets.ts +455 -0
- package/src/core/town-office-seat-layout.ts +238 -0
- package/src/graph.ts +112 -0
- package/src/index.ts +2 -0
- package/src/office/core/projection.ts +89 -0
- package/src/office/core/source.ts +46 -0
- package/src/office/core/types.ts +110 -0
- package/src/office/index.ts +4 -0
- package/src/office/mount.ts +104 -0
- package/src/office/react/AgentGameOfficeView.ts +58 -0
- package/src/office/react/index.ts +1 -0
- package/src/office/renderers/three/agent-activity-effects.ts +161 -0
- package/src/office/renderers/three/agent-animation.ts +205 -0
- package/src/office/renderers/three/agent-body-instancing.ts +119 -0
- package/src/office/renderers/three/agent-label.ts +82 -0
- package/src/office/renderers/three/agent-layout.ts +72 -0
- package/src/office/renderers/three/agent-mesh.ts +145 -0
- package/src/office/renderers/three/mount.ts +253 -0
- package/src/office/renderers/three/scene.ts +790 -0
- package/src/phaser/agent-game-scene.ts +87 -0
- package/src/phaser/anchor-debug.ts +22 -0
- package/src/phaser/avatar-registry.ts +46 -0
- package/src/phaser/camera-controls.ts +419 -0
- package/src/phaser/camera-model.ts +81 -0
- package/src/phaser/create-agent-game.ts +242 -0
- package/src/phaser/debug-overlay.ts +21 -0
- package/src/phaser/index.ts +13 -0
- package/src/phaser/movement-tween.ts +59 -0
- package/src/phaser/office-background.ts +48 -0
- package/src/phaser/office-building-renderer.ts +87 -0
- package/src/phaser/office-layout-renderer.ts +58 -0
- package/src/phaser/render-layers.ts +30 -0
- package/src/phaser/scene-reconciler.ts +614 -0
- package/src/phaser/scene-renderer.ts +138 -0
- package/src/phaser/text-style.ts +8 -0
- package/src/phaser/town-office-business-props.ts +256 -0
- package/src/phaser/town-office-environment.ts +89 -0
- package/src/phaser/town-office-furniture.ts +182 -0
- package/src/phaser/town-office-primitives.ts +53 -0
- package/src/phaser/town-office-renderer.ts +429 -0
- package/src/phaser/types.ts +67 -0
- package/src/phaser/viewport.ts +88 -0
- package/src/runtime-client.ts +435 -0
- package/src/types.ts +80 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import type { AgentAvatarDefinition } from "./assets.js";
|
|
2
|
+
|
|
3
|
+
export const SVG_PIXEL_AVATAR_FRAME_NAMES = [
|
|
4
|
+
"idle-down-0",
|
|
5
|
+
"idle-up-0",
|
|
6
|
+
"idle-left-0",
|
|
7
|
+
"idle-right-0",
|
|
8
|
+
"walk-down-0",
|
|
9
|
+
"walk-down-1",
|
|
10
|
+
"walk-down-2",
|
|
11
|
+
"walk-down-3",
|
|
12
|
+
"walk-up-0",
|
|
13
|
+
"walk-up-1",
|
|
14
|
+
"walk-up-2",
|
|
15
|
+
"walk-up-3",
|
|
16
|
+
"walk-left-0",
|
|
17
|
+
"walk-left-1",
|
|
18
|
+
"walk-left-2",
|
|
19
|
+
"walk-left-3",
|
|
20
|
+
"walk-right-0",
|
|
21
|
+
"walk-right-1",
|
|
22
|
+
"walk-right-2",
|
|
23
|
+
"walk-right-3",
|
|
24
|
+
"work-typing-0",
|
|
25
|
+
"work-typing-1",
|
|
26
|
+
"think-down-0",
|
|
27
|
+
"think-down-1",
|
|
28
|
+
"talk-down-0",
|
|
29
|
+
"talk-down-1",
|
|
30
|
+
] as const;
|
|
31
|
+
|
|
32
|
+
export type SvgPixelAvatarFrameName = (typeof SVG_PIXEL_AVATAR_FRAME_NAMES)[number];
|
|
33
|
+
|
|
34
|
+
export type SvgPixelAgentColors = {
|
|
35
|
+
hair: string;
|
|
36
|
+
skin: string;
|
|
37
|
+
shirt: string;
|
|
38
|
+
pants: string;
|
|
39
|
+
shoes: string;
|
|
40
|
+
cap: string;
|
|
41
|
+
shadow: string;
|
|
42
|
+
eye: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type SvgPixelAgentAvatarOptions = {
|
|
46
|
+
id: string;
|
|
47
|
+
seed: string | number;
|
|
48
|
+
department?: string;
|
|
49
|
+
pixelSize?: number;
|
|
50
|
+
templateIndex?: number;
|
|
51
|
+
colors?: Partial<SvgPixelAgentColors>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type SvgPixelAgentAtlas = {
|
|
55
|
+
frames: Record<SvgPixelAvatarFrameName, { frame: { x: number; y: number; w: number; h: number } }>;
|
|
56
|
+
meta: {
|
|
57
|
+
app: string;
|
|
58
|
+
image: string;
|
|
59
|
+
format: "RGBA8888";
|
|
60
|
+
size: { w: number; h: number };
|
|
61
|
+
scale: "1";
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type SvgPixelAgentSpriteSheet = {
|
|
66
|
+
avatar: AgentAvatarDefinition;
|
|
67
|
+
atlas: SvgPixelAgentAtlas;
|
|
68
|
+
svg: string;
|
|
69
|
+
frameWidth: number;
|
|
70
|
+
frameHeight: number;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const SPRITE_WIDTH = 8;
|
|
74
|
+
const SPRITE_HEIGHT = 11;
|
|
75
|
+
const DEFAULT_PIXEL_SIZE = 3;
|
|
76
|
+
|
|
77
|
+
const SPRITE_TEMPLATES: number[][][] = [
|
|
78
|
+
[
|
|
79
|
+
[0, 0, 1, 1, 1, 1, 0, 0],
|
|
80
|
+
[0, 1, 1, 1, 1, 1, 1, 0],
|
|
81
|
+
[0, 2, 2, 2, 2, 2, 2, 0],
|
|
82
|
+
[0, 2, 9, 2, 2, 9, 2, 0],
|
|
83
|
+
[0, 2, 2, 8, 8, 2, 2, 0],
|
|
84
|
+
[0, 3, 3, 3, 3, 3, 3, 0],
|
|
85
|
+
[3, 2, 3, 3, 3, 3, 2, 3],
|
|
86
|
+
[0, 0, 3, 3, 3, 3, 0, 0],
|
|
87
|
+
[0, 0, 4, 4, 4, 4, 0, 0],
|
|
88
|
+
[0, 0, 4, 0, 0, 4, 0, 0],
|
|
89
|
+
[0, 0, 5, 0, 0, 5, 0, 0],
|
|
90
|
+
],
|
|
91
|
+
[
|
|
92
|
+
[0, 1, 0, 1, 0, 1, 0, 0],
|
|
93
|
+
[0, 1, 1, 1, 1, 1, 1, 0],
|
|
94
|
+
[0, 2, 2, 2, 2, 2, 2, 0],
|
|
95
|
+
[0, 2, 9, 2, 2, 9, 2, 0],
|
|
96
|
+
[0, 2, 2, 8, 8, 2, 2, 0],
|
|
97
|
+
[0, 3, 3, 3, 3, 3, 3, 0],
|
|
98
|
+
[3, 2, 3, 3, 3, 3, 2, 3],
|
|
99
|
+
[0, 0, 3, 3, 3, 3, 0, 0],
|
|
100
|
+
[0, 0, 4, 4, 4, 4, 0, 0],
|
|
101
|
+
[0, 0, 4, 0, 0, 4, 0, 0],
|
|
102
|
+
[0, 0, 5, 0, 0, 5, 0, 0],
|
|
103
|
+
],
|
|
104
|
+
[
|
|
105
|
+
[0, 6, 6, 6, 6, 6, 6, 0],
|
|
106
|
+
[6, 6, 6, 6, 6, 6, 6, 6],
|
|
107
|
+
[0, 2, 2, 2, 2, 2, 2, 0],
|
|
108
|
+
[0, 2, 9, 2, 2, 9, 2, 0],
|
|
109
|
+
[0, 2, 2, 8, 8, 2, 2, 0],
|
|
110
|
+
[0, 3, 3, 3, 3, 3, 3, 0],
|
|
111
|
+
[3, 2, 3, 3, 3, 3, 2, 3],
|
|
112
|
+
[0, 0, 3, 3, 3, 3, 0, 0],
|
|
113
|
+
[0, 0, 4, 4, 4, 4, 0, 0],
|
|
114
|
+
[0, 0, 4, 0, 0, 4, 0, 0],
|
|
115
|
+
[0, 0, 5, 0, 0, 5, 0, 0],
|
|
116
|
+
],
|
|
117
|
+
[
|
|
118
|
+
[0, 0, 1, 1, 1, 1, 0, 0],
|
|
119
|
+
[0, 1, 1, 1, 1, 1, 1, 0],
|
|
120
|
+
[1, 2, 2, 2, 2, 2, 2, 1],
|
|
121
|
+
[1, 2, 9, 2, 2, 9, 2, 1],
|
|
122
|
+
[1, 2, 2, 8, 8, 2, 2, 1],
|
|
123
|
+
[0, 3, 3, 3, 3, 3, 3, 0],
|
|
124
|
+
[3, 2, 3, 3, 3, 3, 2, 3],
|
|
125
|
+
[0, 0, 3, 3, 3, 3, 0, 0],
|
|
126
|
+
[0, 0, 4, 4, 4, 4, 0, 0],
|
|
127
|
+
[0, 0, 4, 0, 0, 4, 0, 0],
|
|
128
|
+
[0, 0, 5, 0, 0, 5, 0, 0],
|
|
129
|
+
],
|
|
130
|
+
[
|
|
131
|
+
[0, 0, 1, 1, 1, 1, 0, 0],
|
|
132
|
+
[0, 1, 1, 1, 1, 1, 1, 0],
|
|
133
|
+
[0, 1, 2, 2, 2, 2, 1, 0],
|
|
134
|
+
[0, 2, 9, 2, 2, 9, 2, 0],
|
|
135
|
+
[0, 2, 2, 8, 8, 2, 2, 0],
|
|
136
|
+
[0, 3, 3, 3, 3, 3, 3, 0],
|
|
137
|
+
[3, 2, 3, 3, 3, 3, 2, 3],
|
|
138
|
+
[0, 0, 3, 3, 3, 3, 0, 0],
|
|
139
|
+
[0, 0, 4, 4, 4, 4, 0, 0],
|
|
140
|
+
[0, 0, 4, 0, 0, 4, 0, 0],
|
|
141
|
+
[0, 0, 5, 0, 0, 5, 0, 0],
|
|
142
|
+
],
|
|
143
|
+
[
|
|
144
|
+
[0, 0, 1, 1, 1, 1, 1, 0],
|
|
145
|
+
[0, 1, 1, 1, 1, 1, 0, 1],
|
|
146
|
+
[0, 2, 2, 2, 2, 2, 0, 1],
|
|
147
|
+
[0, 2, 9, 2, 2, 9, 2, 0],
|
|
148
|
+
[0, 2, 2, 8, 8, 2, 2, 0],
|
|
149
|
+
[0, 3, 3, 3, 3, 3, 3, 0],
|
|
150
|
+
[3, 2, 3, 3, 3, 3, 2, 3],
|
|
151
|
+
[0, 0, 3, 3, 3, 3, 0, 0],
|
|
152
|
+
[0, 0, 4, 4, 4, 4, 0, 0],
|
|
153
|
+
[0, 0, 4, 0, 0, 4, 0, 0],
|
|
154
|
+
[0, 0, 5, 0, 0, 5, 0, 0],
|
|
155
|
+
],
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
const HAIR_COLORS = ["#2c1810", "#4a3728", "#8b6914", "#1a1a2e", "#6b3a2a", "#c0392b", "#d4a574", "#3d2b1f"];
|
|
159
|
+
const SKIN_COLORS = ["#ffdbb4", "#f0c8a0", "#d4a574", "#c49060", "#8d5524"];
|
|
160
|
+
const PANTS_COLORS = ["#2e3a5c", "#3d3d50", "#5c4033", "#2a2a35", "#3b4252"];
|
|
161
|
+
const SHIRT_COLORS = ["#4a7dbc", "#8b5fb0", "#d97a3a", "#29a693", "#d4527c", "#c9a832", "#7a8a99", "#3a9d5c"];
|
|
162
|
+
const DEPARTMENT_SHIRT_COLORS: Record<string, string> = {
|
|
163
|
+
"交易部": "#4a7dbc",
|
|
164
|
+
"研发部": "#8b5fb0",
|
|
165
|
+
"市场部": "#d97a3a",
|
|
166
|
+
"人力资源部": "#29a693",
|
|
167
|
+
"法务部": "#d4527c",
|
|
168
|
+
"财务部": "#c9a832",
|
|
169
|
+
"行政部": "#7a8a99",
|
|
170
|
+
"项目管理部": "#3a9d5c",
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export function createSvgPixelAgentAvatar(options: SvgPixelAgentAvatarOptions): AgentAvatarDefinition {
|
|
174
|
+
return createSvgPixelAgentSpriteSheet(options).avatar;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function createSvgPixelAgentSpriteSheet(options: SvgPixelAgentAvatarOptions): SvgPixelAgentSpriteSheet {
|
|
178
|
+
const pixelSize = options.pixelSize ?? DEFAULT_PIXEL_SIZE;
|
|
179
|
+
const frameWidth = SPRITE_WIDTH * pixelSize;
|
|
180
|
+
const frameHeight = SPRITE_HEIGHT * pixelSize;
|
|
181
|
+
const sheetWidth = frameWidth * SVG_PIXEL_AVATAR_FRAME_NAMES.length;
|
|
182
|
+
const hash = hashSeed(`${options.seed}:${options.department ?? ""}`);
|
|
183
|
+
const template = SPRITE_TEMPLATES[options.templateIndex ?? hash % SPRITE_TEMPLATES.length];
|
|
184
|
+
const colors = createColors(hash, options.department, options.colors);
|
|
185
|
+
const svg = createSpriteSheetSvg(template, colors, pixelSize, frameWidth, frameHeight, sheetWidth);
|
|
186
|
+
const atlas = createAtlas(options.id, frameWidth, frameHeight, sheetWidth);
|
|
187
|
+
const avatar: AgentAvatarDefinition = {
|
|
188
|
+
id: options.id,
|
|
189
|
+
imageUrl: `data:image/svg+xml;base64,${encodeBase64(svg)}`,
|
|
190
|
+
atlasUrl: `data:application/json;base64,${encodeBase64(JSON.stringify(atlas))}`,
|
|
191
|
+
animations: {
|
|
192
|
+
"idle.down": ["idle-down-0"],
|
|
193
|
+
"idle.up": ["idle-up-0"],
|
|
194
|
+
"idle.left": ["idle-left-0"],
|
|
195
|
+
"idle.right": ["idle-right-0"],
|
|
196
|
+
"walk.down": ["walk-down-0", "walk-down-1", "walk-down-2", "walk-down-3"],
|
|
197
|
+
"walk.up": ["walk-up-0", "walk-up-1", "walk-up-2", "walk-up-3"],
|
|
198
|
+
"walk.left": ["walk-left-0", "walk-left-1", "walk-left-2", "walk-left-3"],
|
|
199
|
+
"walk.right": ["walk-right-0", "walk-right-1", "walk-right-2", "walk-right-3"],
|
|
200
|
+
"work.typing": ["work-typing-0", "work-typing-1"],
|
|
201
|
+
"emote.think": ["think-down-0", "think-down-1"],
|
|
202
|
+
"emote.talk": ["talk-down-0", "talk-down-1"],
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
avatar,
|
|
208
|
+
atlas,
|
|
209
|
+
svg,
|
|
210
|
+
frameWidth,
|
|
211
|
+
frameHeight,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function createColors(
|
|
216
|
+
hash: number,
|
|
217
|
+
department: string | undefined,
|
|
218
|
+
overrides: Partial<SvgPixelAgentColors> | undefined,
|
|
219
|
+
): SvgPixelAgentColors {
|
|
220
|
+
const skin = pick(SKIN_COLORS, hash >>> 8);
|
|
221
|
+
const shirt = department
|
|
222
|
+
? DEPARTMENT_SHIRT_COLORS[department] ?? pick(SHIRT_COLORS, hashSeed(department))
|
|
223
|
+
: pick(SHIRT_COLORS, hash >>> 16);
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
hair: pick(HAIR_COLORS, hash >>> 4),
|
|
227
|
+
skin,
|
|
228
|
+
shirt,
|
|
229
|
+
pants: pick(PANTS_COLORS, hash >>> 12),
|
|
230
|
+
shoes: "#2c1810",
|
|
231
|
+
cap: shirt,
|
|
232
|
+
shadow: skin === "#ffdbb4" ? "#e8b898" : skin === "#8d5524" ? "#6b3a2a" : "#c49060",
|
|
233
|
+
eye: "#1a1a2e",
|
|
234
|
+
...overrides,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function createSpriteSheetSvg(
|
|
239
|
+
template: number[][],
|
|
240
|
+
colors: SvgPixelAgentColors,
|
|
241
|
+
pixelSize: number,
|
|
242
|
+
frameWidth: number,
|
|
243
|
+
frameHeight: number,
|
|
244
|
+
sheetWidth: number,
|
|
245
|
+
): string {
|
|
246
|
+
const frames = SVG_PIXEL_AVATAR_FRAME_NAMES
|
|
247
|
+
.map((frame, index) => {
|
|
248
|
+
const frameX = index * frameWidth;
|
|
249
|
+
const rects = createFrameRects(template, colors, pixelSize, frameX, frame);
|
|
250
|
+
return `<g id="${frame}">${rects}</g>`;
|
|
251
|
+
})
|
|
252
|
+
.join("");
|
|
253
|
+
|
|
254
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${sheetWidth}" height="${frameHeight}" viewBox="0 0 ${sheetWidth} ${frameHeight}" shape-rendering="crispEdges">${frames}</svg>`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function createFrameRects(
|
|
258
|
+
template: number[][],
|
|
259
|
+
colors: SvgPixelAgentColors,
|
|
260
|
+
pixelSize: number,
|
|
261
|
+
frameX: number,
|
|
262
|
+
frame: SvgPixelAvatarFrameName,
|
|
263
|
+
): string {
|
|
264
|
+
const colorMap: Record<number, string> = {
|
|
265
|
+
1: colors.hair,
|
|
266
|
+
2: colors.skin,
|
|
267
|
+
3: colors.shirt,
|
|
268
|
+
4: colors.pants,
|
|
269
|
+
5: colors.shoes,
|
|
270
|
+
6: colors.cap,
|
|
271
|
+
8: colors.shadow,
|
|
272
|
+
9: colors.eye,
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
let rects = "";
|
|
276
|
+
const animatedTemplate = createAnimatedFrameTemplate(template, frame);
|
|
277
|
+
for (let y = 0; y < template.length; y++) {
|
|
278
|
+
for (let x = 0; x < animatedTemplate[y].length; x++) {
|
|
279
|
+
const token = animatedTemplate[y][x];
|
|
280
|
+
const fill = colorMap[token];
|
|
281
|
+
if (fill) {
|
|
282
|
+
rects += `<rect x="${frameX + x * pixelSize}" y="${y * pixelSize}" width="${pixelSize}" height="${pixelSize}" fill="${fill}"/>`;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return rects;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function createAnimatedFrameTemplate(template: number[][], frame: SvgPixelAvatarFrameName): number[][] {
|
|
290
|
+
if (!frame.startsWith("walk-")) {
|
|
291
|
+
return template;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const phase = Number(frame.at(-1));
|
|
295
|
+
if (phase !== 1 && phase !== 3) {
|
|
296
|
+
return template;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const next = template.map((row) => [...row]);
|
|
300
|
+
if (phase === 1) {
|
|
301
|
+
next[9][1] = 4;
|
|
302
|
+
next[10][1] = 5;
|
|
303
|
+
next[9][2] = 0;
|
|
304
|
+
next[10][2] = 0;
|
|
305
|
+
next[6][0] = 0;
|
|
306
|
+
next[6][1] = 0;
|
|
307
|
+
next[7][0] = 3;
|
|
308
|
+
next[7][1] = 2;
|
|
309
|
+
return next;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
next[9][6] = 4;
|
|
313
|
+
next[10][6] = 5;
|
|
314
|
+
next[9][5] = 0;
|
|
315
|
+
next[10][5] = 0;
|
|
316
|
+
next[6][6] = 0;
|
|
317
|
+
next[6][7] = 0;
|
|
318
|
+
next[7][6] = 2;
|
|
319
|
+
next[7][7] = 3;
|
|
320
|
+
return next;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function createAtlas(id: string, frameWidth: number, frameHeight: number, sheetWidth: number): SvgPixelAgentAtlas {
|
|
324
|
+
const frames = {} as SvgPixelAgentAtlas["frames"];
|
|
325
|
+
SVG_PIXEL_AVATAR_FRAME_NAMES.forEach((frame, index) => {
|
|
326
|
+
frames[frame] = {
|
|
327
|
+
frame: {
|
|
328
|
+
x: index * frameWidth,
|
|
329
|
+
y: 0,
|
|
330
|
+
w: frameWidth,
|
|
331
|
+
h: frameHeight,
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
frames,
|
|
338
|
+
meta: {
|
|
339
|
+
app: "agent-game-sdk/svg-pixel-avatar",
|
|
340
|
+
image: `${id}.svg`,
|
|
341
|
+
format: "RGBA8888",
|
|
342
|
+
size: {
|
|
343
|
+
w: sheetWidth,
|
|
344
|
+
h: frameHeight,
|
|
345
|
+
},
|
|
346
|
+
scale: "1",
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function hashSeed(seed: string | number): number {
|
|
352
|
+
const input = String(seed);
|
|
353
|
+
let hash = 2166136261;
|
|
354
|
+
for (let index = 0; index < input.length; index++) {
|
|
355
|
+
hash ^= input.charCodeAt(index);
|
|
356
|
+
hash = Math.imul(hash, 16777619);
|
|
357
|
+
}
|
|
358
|
+
return hash >>> 0;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function pick<T>(items: readonly T[], hash: number): T {
|
|
362
|
+
return items[hash % items.length];
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function encodeBase64(value: string): string {
|
|
366
|
+
const bytes = new TextEncoder().encode(value);
|
|
367
|
+
let binary = "";
|
|
368
|
+
for (let index = 0; index < bytes.length; index++) {
|
|
369
|
+
binary += String.fromCharCode(bytes[index]);
|
|
370
|
+
}
|
|
371
|
+
return btoa(binary);
|
|
372
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export const TOWN_OFFICE_OBJECT_FRAMES = [
|
|
2
|
+
"desk-single",
|
|
3
|
+
"desk-long",
|
|
4
|
+
"chair-office",
|
|
5
|
+
"whiteboard",
|
|
6
|
+
"wall-art",
|
|
7
|
+
"plant-small",
|
|
8
|
+
"plant-large",
|
|
9
|
+
"monitor",
|
|
10
|
+
"sofa-long",
|
|
11
|
+
"laptop",
|
|
12
|
+
"bookshelf",
|
|
13
|
+
"filing-cabinet",
|
|
14
|
+
"meeting-table",
|
|
15
|
+
"coffee-machine",
|
|
16
|
+
"water-dispenser",
|
|
17
|
+
"locker",
|
|
18
|
+
"vending-machine",
|
|
19
|
+
"phone",
|
|
20
|
+
"schedule-board",
|
|
21
|
+
"trash-can",
|
|
22
|
+
"bench",
|
|
23
|
+
"flower-pot",
|
|
24
|
+
"clock",
|
|
25
|
+
"bulletin-board",
|
|
26
|
+
"fire-extinguisher",
|
|
27
|
+
"rug-mat",
|
|
28
|
+
"window",
|
|
29
|
+
"air-conditioner",
|
|
30
|
+
"exit-sign",
|
|
31
|
+
"picture",
|
|
32
|
+
"printer",
|
|
33
|
+
"door",
|
|
34
|
+
"light-switch",
|
|
35
|
+
"socket",
|
|
36
|
+
"server-rack",
|
|
37
|
+
"tv",
|
|
38
|
+
"monitor-wall",
|
|
39
|
+
"ticker-board",
|
|
40
|
+
"test-rack",
|
|
41
|
+
"cert-badge",
|
|
42
|
+
"henan-map",
|
|
43
|
+
"battery",
|
|
44
|
+
"solar-panel",
|
|
45
|
+
"ev-charger",
|
|
46
|
+
"megaphone",
|
|
47
|
+
"chart-board",
|
|
48
|
+
"red-banner",
|
|
49
|
+
"beaker",
|
|
50
|
+
"ping-pong-table",
|
|
51
|
+
"podium",
|
|
52
|
+
"party-flag",
|
|
53
|
+
"wind-turbine",
|
|
54
|
+
"transmission-tower",
|
|
55
|
+
"tree",
|
|
56
|
+
"gazebo",
|
|
57
|
+
"bicycle-rack",
|
|
58
|
+
"big-screen",
|
|
59
|
+
"kpi-card",
|
|
60
|
+
"seal",
|
|
61
|
+
] as const;
|
|
62
|
+
|
|
63
|
+
export type TownOfficeObjectFrame = (typeof TOWN_OFFICE_OBJECT_FRAMES)[number];
|
|
64
|
+
|
|
65
|
+
export const TOWN_OFFICE_ROOM_TYPES = [
|
|
66
|
+
"trading",
|
|
67
|
+
"meeting",
|
|
68
|
+
"lab",
|
|
69
|
+
"admin",
|
|
70
|
+
"meeting_small",
|
|
71
|
+
"innovation",
|
|
72
|
+
"infrastructure",
|
|
73
|
+
"legal",
|
|
74
|
+
"training",
|
|
75
|
+
"research",
|
|
76
|
+
"business",
|
|
77
|
+
"cafeteria",
|
|
78
|
+
"lounge",
|
|
79
|
+
"fitness",
|
|
80
|
+
"outdoor",
|
|
81
|
+
"executive",
|
|
82
|
+
"party_building",
|
|
83
|
+
"library",
|
|
84
|
+
"honor_hall",
|
|
85
|
+
"employee_home",
|
|
86
|
+
"interest_class",
|
|
87
|
+
"club",
|
|
88
|
+
"counseling",
|
|
89
|
+
"mental_health",
|
|
90
|
+
"testing_room",
|
|
91
|
+
"regional_office",
|
|
92
|
+
"dispatch",
|
|
93
|
+
"testing",
|
|
94
|
+
"resource",
|
|
95
|
+
"archive",
|
|
96
|
+
] as const;
|
|
97
|
+
|
|
98
|
+
export type TownOfficeRoomType = (typeof TOWN_OFFICE_ROOM_TYPES)[number];
|
|
99
|
+
|
|
100
|
+
const TOWN_OFFICE_OBJECT_FRAME_SET = new Set<string>(TOWN_OFFICE_OBJECT_FRAMES);
|
|
101
|
+
const TOWN_OFFICE_ROOM_TYPE_SET = new Set<string>(TOWN_OFFICE_ROOM_TYPES);
|
|
102
|
+
|
|
103
|
+
export function isTownOfficeObjectFrame(value: string): value is TownOfficeObjectFrame {
|
|
104
|
+
return TOWN_OFFICE_OBJECT_FRAME_SET.has(value);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function isTownOfficeRoomType(value: string): value is TownOfficeRoomType {
|
|
108
|
+
return TOWN_OFFICE_ROOM_TYPE_SET.has(value);
|
|
109
|
+
}
|