dsh-offwork 1.0.1 → 1.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/CHANGELOG.md +19 -0
- package/README.md +38 -20
- package/assets/animations/NOTICE.md +15 -0
- package/assets/animations/alpha-probe.webm +0 -0
- package/assets/animations/ornate-drink.webm +0 -0
- package/assets/animations/ornate-greet.webm +0 -0
- package/assets/animations/ornate-idle.webm +0 -0
- package/assets/animations/whale-drink.webm +0 -0
- package/assets/animations/whale-greet.webm +0 -0
- package/assets/characters/NOTICE.md +11 -0
- package/assets/characters/whale-actions.webp +0 -0
- package/assets/characters/whale-dress.webp +0 -0
- package/assets/characters/whale-ornate-actions.webp +0 -0
- package/assets/characters/whale-ornate.webp +0 -0
- package/client.js +4033 -188
- package/client.source.js +2449 -214
- package/companion.js +185 -0
- package/hydration-store.js +101 -0
- package/hydration.js +303 -0
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +13 -2
- package/pet-interactions.js +138 -0
- package/pet-motion.js +110 -0
- package/pet-surfaces.js +194 -0
- package/pet-video.js +231 -0
- package/pet-view.js +323 -0
- package/tests/companion.test.mjs +86 -0
- package/tests/hydration-extras.test.mjs +226 -0
- package/tests/hydration-store.test.mjs +287 -0
- package/tests/hydration.test.mjs +211 -0
- package/tests/pet-character.test.mjs +62 -0
- package/tests/pet-interactions.test.mjs +88 -0
- package/tests/pet-motion.test.mjs +139 -0
- package/tests/pet-surfaces.test.mjs +128 -0
- package/tests/pet-video.test.mjs +337 -0
- package/tests/pet-view.test.mjs +48 -0
- package/tests/ui.test.mjs +22 -2
- package/tools/build.mjs +62 -6
- package/tools/check-package.mjs +20 -0
- package/ui-utils.js +22 -4
package/tools/build.mjs
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
|
|
3
3
|
const root = new URL('../', import.meta.url);
|
|
4
|
-
const moduleNames = [
|
|
4
|
+
const moduleNames = [
|
|
5
|
+
'client.source.js',
|
|
6
|
+
'clock.js',
|
|
7
|
+
'ui-utils.js',
|
|
8
|
+
'companion.js',
|
|
9
|
+
'pet-view.js',
|
|
10
|
+
'pet-motion.js',
|
|
11
|
+
'pet-video.js',
|
|
12
|
+
'pet-interactions.js',
|
|
13
|
+
'pet-surfaces.js',
|
|
14
|
+
'hydration.js',
|
|
15
|
+
'hydration-store.js',
|
|
16
|
+
];
|
|
5
17
|
const [entry, ...modules] = await Promise.all(
|
|
6
18
|
moduleNames.map((name) => readFile(new URL(name, root), 'utf8')),
|
|
7
19
|
);
|
|
@@ -10,11 +22,55 @@ if (entry.split(marker).length !== 2) {
|
|
|
10
22
|
throw new Error('Expected exactly one pure-module marker in client.source.js');
|
|
11
23
|
}
|
|
12
24
|
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
const pure = modules
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
// Embed the tested modules, removing only their internal module wiring.
|
|
26
|
+
// The browser and Node.js tests execute the same calculation and store code.
|
|
27
|
+
const pure = modules
|
|
28
|
+
.map((source) =>
|
|
29
|
+
source.replace(/^import .* from '\.\/hydration\.js';\n/gm, '').replace(/^export /gm, ''),
|
|
30
|
+
)
|
|
31
|
+
.join('\n');
|
|
32
|
+
const banner = '// Generated by tools/build.mjs; edit the source modules, not this file.\n';
|
|
33
|
+
const spriteMarker = '/* PET_SPRITES */';
|
|
34
|
+
if (entry.split(spriteMarker).length !== 2) throw new Error('Expected one sprite marker');
|
|
35
|
+
const sprites = Object.fromEntries(
|
|
36
|
+
await Promise.all(
|
|
37
|
+
['whale-dress', 'whale-ornate', 'whale-actions', 'whale-ornate-actions'].map(async (id) => {
|
|
38
|
+
const bytes = await readFile(new URL(`assets/characters/${id}.webp`, root));
|
|
39
|
+
if (bytes.toString('ascii', 8, 12) !== 'WEBP' || bytes.length > 200000)
|
|
40
|
+
throw new Error(`Invalid sprite: ${id}`);
|
|
41
|
+
return [id, 'data:image/webp;base64,' + bytes.toString('base64')];
|
|
42
|
+
}),
|
|
43
|
+
),
|
|
44
|
+
);
|
|
45
|
+
const clipMarker = '/* PET_CLIPS */';
|
|
46
|
+
if (entry.split(clipMarker).length !== 2) throw new Error('Expected one clip marker');
|
|
47
|
+
async function clip(name, maximum) {
|
|
48
|
+
const bytes = await readFile(new URL(`assets/animations/${name}.webm`, root));
|
|
49
|
+
if (bytes.readUInt32BE(0) !== 0x1a45dfa3 || bytes.length > maximum)
|
|
50
|
+
throw new Error(`Invalid or oversized WebM: ${name}`);
|
|
51
|
+
return 'data:video/webm;base64,' + bytes.toString('base64');
|
|
52
|
+
}
|
|
53
|
+
const [probe, greet, celebrate, ornateIdle, ornateGreet, ornateDrink] = await Promise.all([
|
|
54
|
+
clip('alpha-probe', 10000),
|
|
55
|
+
clip('whale-greet', 2000000),
|
|
56
|
+
clip('whale-drink', 2000000),
|
|
57
|
+
clip('ornate-idle', 2000000),
|
|
58
|
+
clip('ornate-greet', 2000000),
|
|
59
|
+
clip('ornate-drink', 2000000),
|
|
60
|
+
]);
|
|
61
|
+
const clips = {
|
|
62
|
+
probe,
|
|
63
|
+
models: {
|
|
64
|
+
'whale-actions': { greet, celebrate },
|
|
65
|
+
'whale-ornate-actions': { idle: ornateIdle, greet: ornateGreet, celebrate: ornateDrink },
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
const result =
|
|
69
|
+
banner +
|
|
70
|
+
entry
|
|
71
|
+
.replace(marker, pure)
|
|
72
|
+
.replace(spriteMarker, () => `const PET_SPRITES = ${JSON.stringify(sprites)};`)
|
|
73
|
+
.replace(clipMarker, () => `const PET_CLIPS = ${JSON.stringify(clips)};`);
|
|
18
74
|
const output = new URL('client.js', root);
|
|
19
75
|
|
|
20
76
|
if (process.argv.includes('--check')) {
|
package/tools/check-package.mjs
CHANGED
|
@@ -68,8 +68,28 @@ for (const path of [
|
|
|
68
68
|
'package.json',
|
|
69
69
|
'index.js',
|
|
70
70
|
'client.js',
|
|
71
|
+
'companion.js',
|
|
72
|
+
'pet-view.js',
|
|
73
|
+
'pet-motion.js',
|
|
74
|
+
'pet-video.js',
|
|
75
|
+
'pet-interactions.js',
|
|
76
|
+
'pet-surfaces.js',
|
|
77
|
+
'hydration.js',
|
|
78
|
+
'hydration-store.js',
|
|
71
79
|
'cordis.patch.yml',
|
|
72
80
|
'icon.svg',
|
|
81
|
+
'assets/characters/whale-dress.webp',
|
|
82
|
+
'assets/characters/whale-ornate.webp',
|
|
83
|
+
'assets/characters/whale-actions.webp',
|
|
84
|
+
'assets/characters/whale-ornate-actions.webp',
|
|
85
|
+
'assets/animations/ornate-idle.webm',
|
|
86
|
+
'assets/animations/ornate-greet.webm',
|
|
87
|
+
'assets/animations/ornate-drink.webm',
|
|
88
|
+
'assets/animations/whale-greet.webm',
|
|
89
|
+
'assets/animations/whale-drink.webm',
|
|
90
|
+
'assets/animations/alpha-probe.webm',
|
|
91
|
+
'assets/animations/NOTICE.md',
|
|
92
|
+
'assets/characters/NOTICE.md',
|
|
73
93
|
'locale/zh.json',
|
|
74
94
|
'locale/en.json',
|
|
75
95
|
'README.md',
|
package/ui-utils.js
CHANGED
|
@@ -11,11 +11,13 @@ export function clampPosition(position, viewport, size) {
|
|
|
11
11
|
const width = Math.max(0, viewport.width),
|
|
12
12
|
height = Math.max(0, viewport.height);
|
|
13
13
|
const edge = Math.min(12, width / 2, height / 2);
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const left = viewport.left ?? 0,
|
|
15
|
+
top = viewport.top ?? 0;
|
|
16
|
+
const maxX = Math.max(left + edge, left + width - size.width - edge);
|
|
17
|
+
const maxY = Math.max(top + edge, top + height - size.height - edge);
|
|
16
18
|
return {
|
|
17
|
-
x: Math.max(edge, Math.min(Number.isFinite(position?.x) ? position.x : maxX, maxX)),
|
|
18
|
-
y: Math.max(edge, Math.min(Number.isFinite(position?.y) ? position.y : 88, maxY)),
|
|
19
|
+
x: Math.max(left + edge, Math.min(Number.isFinite(position?.x) ? position.x : maxX, maxX)),
|
|
20
|
+
y: Math.max(top + edge, Math.min(Number.isFinite(position?.y) ? position.y : top + 88, maxY)),
|
|
19
21
|
};
|
|
20
22
|
}
|
|
21
23
|
|
|
@@ -29,6 +31,22 @@ export function normalizeView(value) {
|
|
|
29
31
|
return {
|
|
30
32
|
mini: value?.mini !== false,
|
|
31
33
|
masked: value?.masked !== false,
|
|
34
|
+
companion: value?.companion !== false,
|
|
35
|
+
companionMotion: value?.companionMotion !== false,
|
|
36
|
+
petModel: [
|
|
37
|
+
'whale-dress',
|
|
38
|
+
'whale-ornate',
|
|
39
|
+
'whale-actions',
|
|
40
|
+
'whale-ornate-actions',
|
|
41
|
+
'xiaoxie-original',
|
|
42
|
+
].includes(value?.petModel)
|
|
43
|
+
? value.petModel
|
|
44
|
+
: 'whale-dress',
|
|
45
|
+
petSize: Math.min(180, Math.max(80, Number.isFinite(value?.petSize) ? value.petSize : 132)),
|
|
46
|
+
petPosition:
|
|
47
|
+
Number.isFinite(value?.petPosition?.x) && Number.isFinite(value?.petPosition?.y)
|
|
48
|
+
? { x: value.petPosition.x, y: value.petPosition.y }
|
|
49
|
+
: null,
|
|
32
50
|
opacity: clampOpacity(value?.opacity),
|
|
33
51
|
position:
|
|
34
52
|
Number.isFinite(value?.position?.x) && Number.isFinite(value?.position?.y)
|