@homie-rocks/studio 0.14.4 → 0.16.0
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 +43 -6
- package/bin/homie-studio.mjs +59 -3
- package/lib/build.mjs +48 -0
- package/lib/office.mjs +7 -6
- package/lib/scaffold.mjs +50 -3
- package/lib/servers.mjs +133 -0
- package/lib/template-history.json +55 -0
- package/netplay/NETPLAY.md +317 -21
- package/netplay/netplay.ts +649 -33
- package/package.json +1 -1
- package/port/bots.ts +25 -2
- package/port/hud.ts +10 -7
- package/port/index.ts +5 -2
- package/port/room.ts +48 -10
- package/port/skill.ts +28 -0
- package/port/touch.ts +4 -1
- package/site/SITE.md +71 -0
- package/starters/ember-vale/src/main.ts +58 -12
- package/starters/gem-rush/src/main.ts +128 -33
- package/worker/account-page.mjs +26 -0
- package/worker/agents.mjs +238 -0
- package/worker/index.mjs +353 -68
- package/worker/office-page.mjs +178 -10
- package/worker/office.mjs +294 -25
- package/worker/pages.mjs +622 -18
- package/worker/players.mjs +11 -3
- package/worker/room.mjs +547 -41
- package/worker/saves.mjs +4 -0
- package/worker/servers.mjs +445 -0
- package/worker/site.mjs +166 -10
- package/worker/stats.mjs +9 -3
- package/worker/version.mjs +1 -1
package/worker/players.mjs
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* A player sees, downloads (/api/player/export) and deletes (/api/player/delete) everything of theirs.
|
|
26
26
|
*/
|
|
27
27
|
import { handleFor } from './room.mjs';
|
|
28
|
+
import { isAiName } from './agents.mjs';
|
|
28
29
|
import { cookieValue } from './stats.mjs';
|
|
29
30
|
import { adoptStatements, bumpPlayerStats, dropPlayerData, fall, fallenList, getSave, listSaves, playerData, readPlayerStats, SAVE_LIMITS, savesSummary, wipeSaves, writeSaves } from './saves.mjs';
|
|
30
31
|
import { bytesToB64url, randomToken, sha256Hex, verifyAssertion, verifyRegistration } from './webauthn.mjs';
|
|
@@ -147,8 +148,9 @@ const ROLE_WORDS = /^(?:the\s+)?(?:admin|administrator|mod|moderator|owner|staff
|
|
|
147
148
|
/**
|
|
148
149
|
* A display name, by the same rules as a room's typed names and handles: one line of at most 24 characters,
|
|
149
150
|
* whitespace collapsed, no control, format or invisible characters (no zero-width or bidi tricks), at least one
|
|
150
|
-
* letter or digit; never a role (admin, moderator, owner…) or the studio's own name, except for the owner
|
|
151
|
-
*
|
|
151
|
+
* letter or digit; never a role (admin, moderator, owner…) or the studio's own name, except for the owner; and never
|
|
152
|
+
* ending in an AI or bot mark ("· AI", "(bot)"…), for anyone: only an agent's name says AI (0.16.0). It is always
|
|
153
|
+
* shown as text (escaped), never as markup. `max` lets a character's name run to 32.
|
|
152
154
|
*/
|
|
153
155
|
export function cleanName(raw, { studio = '', owner = false, max = 24 } = {}) {
|
|
154
156
|
const text = String(raw ?? '').normalize('NFKC')
|
|
@@ -161,6 +163,7 @@ export function cleanName(raw, { studio = '', owner = false, max = 24 } = {}) {
|
|
|
161
163
|
if (!owner && (ROLE_WORDS.test(name) || (studio && name.toLowerCase() === String(studio).trim().toLowerCase()))) {
|
|
162
164
|
return { ok: false, error: 'name-taken', message: 'that name belongs to the studio; pick another' };
|
|
163
165
|
}
|
|
166
|
+
if (isAiName(name)) return { ok: false, error: 'name-ai', message: 'a person\'s name cannot end in "AI" or "bot": only an AI player is marked AI' };
|
|
164
167
|
return { ok: true, name, cut: chars.length > max };
|
|
165
168
|
}
|
|
166
169
|
|
|
@@ -299,7 +302,10 @@ async function meOf(env, player) {
|
|
|
299
302
|
const e = await env.DB.prepare('SELECT email, verified_at FROM player_emails WHERE player = ?1').bind(player.id).first();
|
|
300
303
|
if (e) email = { address: e.email, verified: Boolean(e.verified_at) };
|
|
301
304
|
}
|
|
302
|
-
|
|
305
|
+
// The servers this player belongs to (0.16.0; none before migration 0006).
|
|
306
|
+
let servers = [];
|
|
307
|
+
try { servers = ((await env.DB.prepare('SELECT game, server, role, home FROM server_members WHERE player = ?1 ORDER BY home DESC, seen_at DESC LIMIT 50').bind(player.id).all()).results ?? []).map((r) => ({ game: r.game, server: r.server, role: r.role, home: Number(r.home) === 1 })); } catch { servers = []; }
|
|
308
|
+
return { id: player.id, name: player.name, named: Boolean(player.named), guest: Boolean(player.guest), owner: Boolean(player.owner), since: new Date(player.since).toISOString(), passkeys: Number(keys?.n) || 0, email, servers };
|
|
303
309
|
}
|
|
304
310
|
|
|
305
311
|
const features = (env) => ({ accounts: Boolean(env.DB) && env.HOMIE_PREVIEW !== '1', email: Boolean(env.PLAYER_MAIL && env.PLAYER_MAIL_FROM) });
|
|
@@ -315,6 +321,8 @@ async function removePlayer(env, id) {
|
|
|
315
321
|
env.DB.prepare('DELETE FROM player_emails WHERE player = ?1').bind(id),
|
|
316
322
|
env.DB.prepare('DELETE FROM players WHERE id = ?1').bind(id),
|
|
317
323
|
]);
|
|
324
|
+
// Their servers' memberships too (0.16.0); a studio before migration 0006 has none to delete.
|
|
325
|
+
try { await env.DB.prepare('DELETE FROM server_members WHERE player = ?1').bind(id).run(); } catch { /* not migrated */ }
|
|
318
326
|
await data.after();
|
|
319
327
|
}
|
|
320
328
|
|