@rpgjs/client 5.0.0-beta.7 → 5.0.0-beta.8
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 +14 -0
- package/dist/Game/Map.js +2 -1
- package/dist/Game/Map.js.map +1 -1
- package/dist/Game/Object.d.ts +17 -9
- package/dist/Game/Object.js +1 -12
- package/dist/Game/Object.js.map +1 -1
- package/dist/Gui/Gui.d.ts +17 -4
- package/dist/Gui/Gui.js +63 -33
- package/dist/Gui/Gui.js.map +1 -1
- package/dist/Gui/Gui.spec.d.ts +1 -0
- package/dist/Resource.js +1 -1
- package/dist/Resource.js.map +1 -1
- package/dist/RpgClient.d.ts +35 -2
- package/dist/RpgClientEngine.d.ts +41 -5
- package/dist/RpgClientEngine.js +43 -3
- package/dist/RpgClientEngine.js.map +1 -1
- package/dist/components/character.ce.js +225 -2
- package/dist/components/character.ce.js.map +1 -1
- package/dist/components/dynamics/bar.ce.js +96 -0
- package/dist/components/dynamics/bar.ce.js.map +1 -0
- package/dist/components/dynamics/image.ce.js +23 -0
- package/dist/components/dynamics/image.ce.js.map +1 -0
- package/dist/components/dynamics/parse-value.d.ts +3 -0
- package/dist/components/dynamics/parse-value.js +51 -35
- package/dist/components/dynamics/parse-value.js.map +1 -1
- package/dist/components/dynamics/parse-value.spec.d.ts +1 -0
- package/dist/components/dynamics/shape-utils.d.ts +16 -0
- package/dist/components/dynamics/shape-utils.js +73 -0
- package/dist/components/dynamics/shape-utils.js.map +1 -0
- package/dist/components/dynamics/shape-utils.spec.d.ts +1 -0
- package/dist/components/dynamics/shape.ce.js +83 -0
- package/dist/components/dynamics/shape.ce.js.map +1 -0
- package/dist/components/dynamics/text.ce.js +28 -41
- package/dist/components/dynamics/text.ce.js.map +1 -1
- package/dist/components/player-components-utils.d.ts +67 -0
- package/dist/components/player-components-utils.js +162 -0
- package/dist/components/player-components-utils.js.map +1 -0
- package/dist/components/player-components-utils.spec.d.ts +1 -0
- package/dist/components/player-components.ce.js +188 -0
- package/dist/components/player-components.ce.js.map +1 -0
- package/dist/core/setup.js.map +1 -1
- package/dist/module.js +3 -0
- package/dist/module.js.map +1 -1
- package/dist/node_modules/.pnpm/@signe_reactive@2.10.0/node_modules/@signe/reactive/dist/index.js +197 -3
- package/dist/node_modules/.pnpm/@signe_reactive@2.10.0/node_modules/@signe/reactive/dist/index.js.map +1 -1
- package/dist/node_modules/.pnpm/@signe_room@2.10.0/node_modules/@signe/room/dist/index.js +1 -1
- package/dist/services/loadMap.d.ts +6 -0
- package/dist/services/loadMap.js.map +1 -1
- package/package.json +4 -4
- package/src/Game/Map.ts +12 -2
- package/src/Game/Object.ts +22 -35
- package/src/Gui/Gui.spec.ts +273 -0
- package/src/Gui/Gui.ts +105 -50
- package/src/Resource.ts +1 -2
- package/src/RpgClient.ts +36 -2
- package/src/RpgClientEngine.ts +64 -10
- package/src/components/character.ce +281 -1
- package/src/components/dynamics/bar.ce +87 -0
- package/src/components/dynamics/image.ce +20 -0
- package/src/components/dynamics/parse-value.spec.ts +41 -0
- package/src/components/dynamics/parse-value.ts +102 -37
- package/src/components/dynamics/shape-utils.spec.ts +46 -0
- package/src/components/dynamics/shape-utils.ts +61 -0
- package/src/components/dynamics/shape.ce +89 -0
- package/src/components/dynamics/text.ce +34 -149
- package/src/components/player-components-utils.spec.ts +109 -0
- package/src/components/player-components-utils.ts +205 -0
- package/src/components/player-components.ce +221 -0
- package/src/core/setup.ts +2 -2
- package/src/module.ts +5 -1
- package/src/services/loadMap.ts +2 -0
- package/dist/node_modules/.pnpm/@signe_reactive@2.9.2/node_modules/@signe/reactive/dist/index.js +0 -227
- package/dist/node_modules/.pnpm/@signe_reactive@2.9.2/node_modules/@signe/reactive/dist/index.js.map +0 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
export const DEFAULT_HP_BAR_STYLE = { fillColor: '#ef4444' };
|
|
2
|
+
export const DEFAULT_SP_BAR_STYLE = { fillColor: '#3b82f6' };
|
|
3
|
+
|
|
4
|
+
const DEFAULT_CELL_HEIGHT = 16;
|
|
5
|
+
const DEFAULT_CELL_WIDTH = 32;
|
|
6
|
+
|
|
7
|
+
type NumberResolver = (value: any, fallback?: number) => number;
|
|
8
|
+
|
|
9
|
+
const defaultToNumber: NumberResolver = (value, fallback = 0) => {
|
|
10
|
+
const num = typeof value === 'number' ? value : parseFloat(value);
|
|
11
|
+
return Number.isFinite(num) ? num : fallback;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function getPointBounds(points: any[] = [], toNumber: NumberResolver = defaultToNumber) {
|
|
15
|
+
if (!Array.isArray(points) || points.length < 2) {
|
|
16
|
+
return { width: 1, height: 1 };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let minX = Infinity;
|
|
20
|
+
let minY = Infinity;
|
|
21
|
+
let maxX = -Infinity;
|
|
22
|
+
let maxY = -Infinity;
|
|
23
|
+
|
|
24
|
+
for (let i = 0; i < points.length; i += 2) {
|
|
25
|
+
const x = toNumber(points[i], 0);
|
|
26
|
+
const y = toNumber(points[i + 1], 0);
|
|
27
|
+
minX = Math.min(minX, x);
|
|
28
|
+
minY = Math.min(minY, y);
|
|
29
|
+
maxX = Math.max(maxX, x);
|
|
30
|
+
maxY = Math.max(maxY, y);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
width: Math.max(1, maxX - minX),
|
|
35
|
+
height: Math.max(1, maxY - minY)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getComponentId(definition: any) {
|
|
40
|
+
if (!definition) return undefined;
|
|
41
|
+
if (definition.id) return definition.id;
|
|
42
|
+
if (definition.type === 'text') return 'rpg:text';
|
|
43
|
+
if (definition.type === 'hpBar') return 'rpg:hpBar';
|
|
44
|
+
if (definition.type === 'spBar') return 'rpg:spBar';
|
|
45
|
+
if (definition.type === 'bar') return 'rpg:bar';
|
|
46
|
+
if (definition.type === 'shape') return 'rpg:shape';
|
|
47
|
+
if (definition.type === 'image') return 'rpg:image';
|
|
48
|
+
if (definition.type === 'tile') return 'rpg:tile';
|
|
49
|
+
return definition.type;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function getComponentProps(definition: any) {
|
|
53
|
+
if (definition.props) return definition.props;
|
|
54
|
+
|
|
55
|
+
if (definition.type === 'text') {
|
|
56
|
+
return { value: definition.value, style: definition.style };
|
|
57
|
+
}
|
|
58
|
+
if (definition.type === 'hpBar') {
|
|
59
|
+
return { current: '{hp}', max: '{param.maxHp}', style: { ...DEFAULT_HP_BAR_STYLE, ...definition.style }, text: definition.text };
|
|
60
|
+
}
|
|
61
|
+
if (definition.type === 'spBar') {
|
|
62
|
+
return { current: '{sp}', max: '{param.maxSp}', style: { ...DEFAULT_SP_BAR_STYLE, ...definition.style }, text: definition.text };
|
|
63
|
+
}
|
|
64
|
+
if (definition.type === 'bar') {
|
|
65
|
+
return { current: `{${definition.current}}`, max: `{${definition.max}}`, style: definition.style, text: definition.text };
|
|
66
|
+
}
|
|
67
|
+
if (definition.type === 'shape') {
|
|
68
|
+
return definition.value;
|
|
69
|
+
}
|
|
70
|
+
if (definition.type === 'image' || definition.type === 'tile') {
|
|
71
|
+
return { value: definition.value };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function estimateComponentSize(
|
|
78
|
+
definition: any,
|
|
79
|
+
{
|
|
80
|
+
toNumber = defaultToNumber,
|
|
81
|
+
estimateTextWidth = (value: any) => String(value ?? '').length * 8
|
|
82
|
+
}: {
|
|
83
|
+
toNumber?: NumberResolver;
|
|
84
|
+
estimateTextWidth?: (value: any, style?: any) => number;
|
|
85
|
+
} = {}
|
|
86
|
+
) {
|
|
87
|
+
const props = getComponentProps(definition);
|
|
88
|
+
const style = props?.style ?? definition?.style ?? {};
|
|
89
|
+
|
|
90
|
+
if (definition?.type === 'text' || definition?.id === 'rpg:text') {
|
|
91
|
+
return {
|
|
92
|
+
width: estimateTextWidth(props.value ?? definition.value, style),
|
|
93
|
+
height: toNumber(style.fontSize, 12)
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (definition?.type === 'hpBar' || definition?.type === 'spBar' || definition?.type === 'bar' || definition?.id === 'rpg:hpBar' || definition?.id === 'rpg:spBar' || definition?.id === 'rpg:bar') {
|
|
98
|
+
const barHeight = toNumber(style.height, 8);
|
|
99
|
+
const labelHeight = props.text != null && props.text !== '' ? toNumber(style.fontSize, 10) + 2 : 0;
|
|
100
|
+
return {
|
|
101
|
+
width: toNumber(style.width, 50),
|
|
102
|
+
height: barHeight + labelHeight
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (definition?.type === 'shape' || definition?.id === 'rpg:shape') {
|
|
107
|
+
const shape = props ?? {};
|
|
108
|
+
if (shape.type === 'circle') {
|
|
109
|
+
const radius = toNumber(shape.radius, 8);
|
|
110
|
+
return { width: radius * 2, height: radius * 2 };
|
|
111
|
+
}
|
|
112
|
+
if (shape.type === 'line') {
|
|
113
|
+
return {
|
|
114
|
+
width: Math.max(1, Math.abs(toNumber(shape.x2, 16) - toNumber(shape.x1, 0))),
|
|
115
|
+
height: Math.max(1, Math.abs(toNumber(shape.y2, 0) - toNumber(shape.y1, 0)))
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (shape.type === 'polygon') {
|
|
119
|
+
return getPointBounds(shape.points, toNumber);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
width: toNumber(shape.width, 16),
|
|
123
|
+
height: toNumber(shape.height, 16)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
width: toNumber(definition?.props?.width, DEFAULT_CELL_WIDTH),
|
|
129
|
+
height: toNumber(definition?.props?.height, DEFAULT_CELL_HEIGHT)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function computeBlockSize({
|
|
134
|
+
position,
|
|
135
|
+
layout = {},
|
|
136
|
+
rowMetrics,
|
|
137
|
+
gap = { row: 0, column: 0 },
|
|
138
|
+
graphic,
|
|
139
|
+
hitbox
|
|
140
|
+
}: {
|
|
141
|
+
position: string;
|
|
142
|
+
layout?: any;
|
|
143
|
+
rowMetrics: Array<{ width: number; height: number; cells: any[] }>;
|
|
144
|
+
gap?: { row: number; column: number };
|
|
145
|
+
graphic: { width: number; height: number };
|
|
146
|
+
hitbox: { w: number; h: number };
|
|
147
|
+
}) {
|
|
148
|
+
const rowGapTotal = Math.max(0, rowMetrics.length - 1) * gap.row;
|
|
149
|
+
const maxColumns = rowMetrics.reduce((max, row) => Math.max(max, row.cells.length), 0);
|
|
150
|
+
const columnGapTotal = Math.max(0, maxColumns - 1) * gap.column;
|
|
151
|
+
const contentWidth = rowMetrics.reduce((max, row) => Math.max(max, row.width), 0) + columnGapTotal;
|
|
152
|
+
const contentHeight = rowMetrics.reduce((sum, row) => sum + row.height, 0) + rowGapTotal;
|
|
153
|
+
const width = layout.width ?? Math.max(contentWidth, position === 'bottom' ? hitbox.w : position === 'top' || position === 'center' ? graphic.width : contentWidth);
|
|
154
|
+
const height = layout.height ?? Math.max(contentHeight, position === 'bottom' ? hitbox.h : position === 'left' || position === 'right' || position === 'center' ? graphic.height : contentHeight);
|
|
155
|
+
|
|
156
|
+
return { width, height };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function computeBlockPosition({
|
|
160
|
+
position,
|
|
161
|
+
size,
|
|
162
|
+
layout = {},
|
|
163
|
+
graphic,
|
|
164
|
+
hitbox
|
|
165
|
+
}: {
|
|
166
|
+
position: string;
|
|
167
|
+
size: { width: number; height: number };
|
|
168
|
+
layout?: any;
|
|
169
|
+
graphic: { left: number; top: number; right: number; centerX: number; centerY: number };
|
|
170
|
+
hitbox: { w: number; h: number };
|
|
171
|
+
}) {
|
|
172
|
+
const marginLeft = layout.marginLeft ?? 0;
|
|
173
|
+
const marginRight = layout.marginRight ?? 0;
|
|
174
|
+
const marginTop = layout.marginTop ?? 0;
|
|
175
|
+
const marginBottom = layout.marginBottom ?? 0;
|
|
176
|
+
|
|
177
|
+
switch (position) {
|
|
178
|
+
case 'bottom':
|
|
179
|
+
return {
|
|
180
|
+
x: (hitbox.w / 2) - (size.width / 2) + marginLeft - marginRight,
|
|
181
|
+
y: (hitbox.h / 2) - (size.height / 2) + marginBottom - marginTop
|
|
182
|
+
};
|
|
183
|
+
case 'center':
|
|
184
|
+
return {
|
|
185
|
+
x: graphic.centerX - (size.width / 2) + marginLeft - marginRight,
|
|
186
|
+
y: graphic.centerY - (size.height / 2) + marginTop - marginBottom
|
|
187
|
+
};
|
|
188
|
+
case 'left':
|
|
189
|
+
return {
|
|
190
|
+
x: graphic.left - size.width + marginLeft - marginRight,
|
|
191
|
+
y: graphic.centerY - (size.height / 2) + marginTop - marginBottom
|
|
192
|
+
};
|
|
193
|
+
case 'right':
|
|
194
|
+
return {
|
|
195
|
+
x: graphic.right + marginLeft - marginRight,
|
|
196
|
+
y: graphic.centerY - (size.height / 2) + marginTop - marginBottom
|
|
197
|
+
};
|
|
198
|
+
case 'top':
|
|
199
|
+
default:
|
|
200
|
+
return {
|
|
201
|
+
x: graphic.centerX - (size.width / 2) + marginLeft - marginRight,
|
|
202
|
+
y: graphic.top - size.height + marginTop - marginBottom
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
<Container
|
|
2
|
+
x={blockPosition().x}
|
|
3
|
+
y={blockPosition().y}
|
|
4
|
+
width={blockSize().width}
|
|
5
|
+
height={blockSize().height}
|
|
6
|
+
minWidth={blockSize().width}
|
|
7
|
+
minHeight={blockSize().height}
|
|
8
|
+
display="flex"
|
|
9
|
+
flexDirection="column"
|
|
10
|
+
justifyContent="center"
|
|
11
|
+
alignItems="center"
|
|
12
|
+
rowGap={gap().row}
|
|
13
|
+
>
|
|
14
|
+
@for (row of renderedRows) {
|
|
15
|
+
<Container
|
|
16
|
+
width="100%"
|
|
17
|
+
height={row.height}
|
|
18
|
+
display="flex"
|
|
19
|
+
flexDirection="row"
|
|
20
|
+
justifyContent="center"
|
|
21
|
+
alignItems="center"
|
|
22
|
+
columnGap={gap().column}
|
|
23
|
+
>
|
|
24
|
+
@for (entry of row.entries) {
|
|
25
|
+
<Container
|
|
26
|
+
width={entry.width}
|
|
27
|
+
height={entry.height}
|
|
28
|
+
display="flex"
|
|
29
|
+
justifyContent="center"
|
|
30
|
+
alignItems="center"
|
|
31
|
+
>
|
|
32
|
+
<entry.component object ...entry.props />
|
|
33
|
+
</Container>
|
|
34
|
+
}
|
|
35
|
+
</Container>
|
|
36
|
+
}
|
|
37
|
+
</Container>
|
|
38
|
+
|
|
39
|
+
<script>
|
|
40
|
+
import { computed } from "canvasengine";
|
|
41
|
+
import { RpgClientEngine } from "../RpgClientEngine";
|
|
42
|
+
import { inject } from "../core/inject";
|
|
43
|
+
import { resolveDynamicProps, resolveDynamicValue } from "./dynamics/parse-value";
|
|
44
|
+
import {
|
|
45
|
+
computeBlockPosition,
|
|
46
|
+
computeBlockSize,
|
|
47
|
+
estimateComponentSize,
|
|
48
|
+
getComponentId,
|
|
49
|
+
getComponentProps
|
|
50
|
+
} from "./player-components-utils";
|
|
51
|
+
|
|
52
|
+
const { object, position, graphicBounds } = defineProps({
|
|
53
|
+
position: {
|
|
54
|
+
default: 'top'
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const client = inject(RpgClientEngine);
|
|
59
|
+
const warnedComponents = new Set();
|
|
60
|
+
|
|
61
|
+
const readPosition = computed(() => position?.() ?? 'top');
|
|
62
|
+
|
|
63
|
+
const componentSource = computed(() => {
|
|
64
|
+
switch (readPosition()) {
|
|
65
|
+
case 'bottom':
|
|
66
|
+
return object.componentsBottom?.();
|
|
67
|
+
case 'center':
|
|
68
|
+
return object.componentsCenter?.();
|
|
69
|
+
case 'left':
|
|
70
|
+
return object.componentsLeft?.();
|
|
71
|
+
case 'right':
|
|
72
|
+
return object.componentsRight?.();
|
|
73
|
+
case 'top':
|
|
74
|
+
default:
|
|
75
|
+
return object.componentsTop?.();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const componentData = computed(() => {
|
|
80
|
+
const value = componentSource();
|
|
81
|
+
if (!value) {
|
|
82
|
+
return { components: [], layout: {} };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (typeof value !== 'string') {
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
return JSON.parse(value);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') {
|
|
93
|
+
console.warn('[RPGJS] Invalid server sprite component payload', error);
|
|
94
|
+
}
|
|
95
|
+
return { components: [], layout: {} };
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const layout = computed(() => componentData()?.layout ?? {});
|
|
100
|
+
const rows = computed(() => componentData()?.components ?? []);
|
|
101
|
+
const hitbox = object.hitbox;
|
|
102
|
+
|
|
103
|
+
const toNumber = (value, fallback = 0) => {
|
|
104
|
+
const resolved = resolveDynamicValue(value, object);
|
|
105
|
+
const num = typeof resolved === 'number' ? resolved : parseFloat(resolved);
|
|
106
|
+
return Number.isFinite(num) ? num : fallback;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const estimateTextWidth = (value, style = {}) => {
|
|
110
|
+
const text = String(resolveDynamicValue(value ?? '', object) ?? '');
|
|
111
|
+
const fontSize = toNumber(style.fontSize, 12);
|
|
112
|
+
return Math.max(1, Math.ceil(text.length * fontSize * 0.6));
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const rowMetrics = computed(() => {
|
|
116
|
+
return rows().map((row) => {
|
|
117
|
+
const cells = row.map((definition) => {
|
|
118
|
+
const intrinsic = estimateComponentSize(definition, { toNumber, estimateTextWidth });
|
|
119
|
+
return {
|
|
120
|
+
definition,
|
|
121
|
+
width: intrinsic.width,
|
|
122
|
+
height: intrinsic.height
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
cells,
|
|
128
|
+
width: cells.reduce((sum, cell) => sum + cell.width, 0),
|
|
129
|
+
height: cells.reduce((max, cell) => Math.max(max, cell.height), 0)
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const gap = computed(() => ({
|
|
135
|
+
row: toNumber(layout().rowGap ?? layout().gap, 0),
|
|
136
|
+
column: toNumber(layout().columnGap ?? layout().gap, 0)
|
|
137
|
+
}));
|
|
138
|
+
|
|
139
|
+
const fallbackBounds = computed(() => {
|
|
140
|
+
const box = hitbox();
|
|
141
|
+
const width = box?.w ?? 0;
|
|
142
|
+
const height = box?.h ?? 0;
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
left: 0,
|
|
146
|
+
top: 0,
|
|
147
|
+
right: width,
|
|
148
|
+
bottom: height,
|
|
149
|
+
width,
|
|
150
|
+
height,
|
|
151
|
+
centerX: width / 2,
|
|
152
|
+
centerY: height / 2
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const bounds = computed(() => {
|
|
157
|
+
const resolvedBounds = typeof graphicBounds === 'function' ? graphicBounds() : undefined;
|
|
158
|
+
return resolvedBounds ?? fallbackBounds();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const blockSize = computed(() => {
|
|
162
|
+
const box = hitbox() ?? { w: 0, h: 0 };
|
|
163
|
+
const graphic = bounds();
|
|
164
|
+
return computeBlockSize({
|
|
165
|
+
position: readPosition(),
|
|
166
|
+
layout: layout(),
|
|
167
|
+
rowMetrics: rowMetrics(),
|
|
168
|
+
gap: gap(),
|
|
169
|
+
graphic,
|
|
170
|
+
hitbox: box
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const blockPosition = computed(() => {
|
|
175
|
+
const box = hitbox() ?? { w: 0, h: 0 };
|
|
176
|
+
const graphic = bounds();
|
|
177
|
+
return computeBlockPosition({
|
|
178
|
+
position: readPosition(),
|
|
179
|
+
size: blockSize(),
|
|
180
|
+
layout: layout(),
|
|
181
|
+
graphic,
|
|
182
|
+
hitbox: box
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const warnMissingComponent = (id) => {
|
|
187
|
+
if (!id || warnedComponents.has(id)) return;
|
|
188
|
+
if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') return;
|
|
189
|
+
warnedComponents.add(id);
|
|
190
|
+
console.warn(`[RPGJS] Server sprite component "${id}" is not registered on the client.`);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const renderedRows = computed(() => {
|
|
194
|
+
return rowMetrics().map((row) => {
|
|
195
|
+
const entries = [];
|
|
196
|
+
|
|
197
|
+
row.cells.forEach((cell) => {
|
|
198
|
+
const definition = cell.definition;
|
|
199
|
+
const id = getComponentId(definition);
|
|
200
|
+
const component = client.getSpriteComponent(id);
|
|
201
|
+
|
|
202
|
+
if (!component) {
|
|
203
|
+
warnMissingComponent(id);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
entries.push({
|
|
208
|
+
component,
|
|
209
|
+
props: resolveDynamicProps(getComponentProps(definition), object),
|
|
210
|
+
width: cell.width,
|
|
211
|
+
height: cell.height
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
height: row.height,
|
|
217
|
+
entries
|
|
218
|
+
};
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
</script>
|
package/src/core/setup.ts
CHANGED
|
@@ -14,7 +14,7 @@ export async function startGame(options: SetupOptions) {
|
|
|
14
14
|
|
|
15
15
|
await injector(context, options.providers);
|
|
16
16
|
|
|
17
|
-
const engine = inject(context, RpgClientEngine);
|
|
17
|
+
const engine = inject<RpgClientEngine>(context, RpgClientEngine);
|
|
18
18
|
await engine.start();
|
|
19
19
|
return context;
|
|
20
|
-
}
|
|
20
|
+
}
|
package/src/module.ts
CHANGED
|
@@ -195,6 +195,11 @@ export function provideClientModules(modules: RpgClientModule[]): FactoryProvide
|
|
|
195
195
|
engine.addSpriteComponentInFront(component);
|
|
196
196
|
});
|
|
197
197
|
}
|
|
198
|
+
if (sprite.components) {
|
|
199
|
+
Object.entries(sprite.components).forEach(([id, component]) => {
|
|
200
|
+
engine.registerSpriteComponent(id, component);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
198
203
|
},
|
|
199
204
|
};
|
|
200
205
|
}
|
|
@@ -226,4 +231,3 @@ export function provideClientGlobalConfig(config: any = {}) {
|
|
|
226
231
|
}
|
|
227
232
|
return provideGlobalConfig(config)
|
|
228
233
|
}
|
|
229
|
-
|
package/src/services/loadMap.ts
CHANGED
|
@@ -20,6 +20,8 @@ type MapData = {
|
|
|
20
20
|
height?: number;
|
|
21
21
|
/** Optional map events data (NPCs, interactive objects, etc.) */
|
|
22
22
|
events?: any;
|
|
23
|
+
/** Optional named positions, for example Tiled point objects used by changeMap("map", "name") */
|
|
24
|
+
positions?: Record<string, { x: number; y: number; z?: number }>;
|
|
23
25
|
/** Optional map identifier, defaults to the mapId parameter if not provided */
|
|
24
26
|
id?: string;
|
|
25
27
|
}
|
package/dist/node_modules/.pnpm/@signe_reactive@2.9.2/node_modules/@signe/reactive/dist/index.js
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject, filter } from "rxjs";
|
|
2
|
-
//#region ../../node_modules/.pnpm/@signe+reactive@2.9.2/node_modules/@signe/reactive/dist/index.js
|
|
3
|
-
var ArraySubject = class extends BehaviorSubject {
|
|
4
|
-
constructor(items = []) {
|
|
5
|
-
super({
|
|
6
|
-
type: "init",
|
|
7
|
-
items
|
|
8
|
-
});
|
|
9
|
-
this._items = [];
|
|
10
|
-
this.createProxy(items);
|
|
11
|
-
}
|
|
12
|
-
createProxy(items) {
|
|
13
|
-
this._items = new Proxy(items, {
|
|
14
|
-
get: (target, prop, receiver) => {
|
|
15
|
-
const origMethod = target[prop];
|
|
16
|
-
if (typeof origMethod === "function") return (...args) => {
|
|
17
|
-
let changeType = "update";
|
|
18
|
-
let index = void 0;
|
|
19
|
-
let isMutateFn = false;
|
|
20
|
-
let itemsToEmit = [];
|
|
21
|
-
let changeSplice = true;
|
|
22
|
-
switch (prop) {
|
|
23
|
-
case "push":
|
|
24
|
-
index = target.length;
|
|
25
|
-
changeType = "add";
|
|
26
|
-
isMutateFn = true;
|
|
27
|
-
break;
|
|
28
|
-
case "pop":
|
|
29
|
-
index = target.length - 1;
|
|
30
|
-
changeType = "remove";
|
|
31
|
-
isMutateFn = true;
|
|
32
|
-
break;
|
|
33
|
-
case "unshift":
|
|
34
|
-
index = 0;
|
|
35
|
-
changeType = "add";
|
|
36
|
-
isMutateFn = true;
|
|
37
|
-
break;
|
|
38
|
-
case "shift":
|
|
39
|
-
index = 0;
|
|
40
|
-
changeType = "remove";
|
|
41
|
-
isMutateFn = true;
|
|
42
|
-
break;
|
|
43
|
-
case "splice":
|
|
44
|
-
index = args[0];
|
|
45
|
-
const deleteCount = args[1];
|
|
46
|
-
const newItems = args.slice(2);
|
|
47
|
-
itemsToEmit = newItems;
|
|
48
|
-
if (deleteCount > 0 && newItems.length === 0) changeType = "remove";
|
|
49
|
-
else if (deleteCount === 0 && newItems.length > 0) changeType = "add";
|
|
50
|
-
else if (deleteCount === 0 && newItems.length === 0) changeSplice = false;
|
|
51
|
-
else changeType = "update";
|
|
52
|
-
isMutateFn = true;
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
const result = origMethod.apply(target, args);
|
|
56
|
-
if (isMutateFn && changeSplice) if (prop === "splice") this.next({
|
|
57
|
-
type: changeType,
|
|
58
|
-
index,
|
|
59
|
-
items: itemsToEmit
|
|
60
|
-
});
|
|
61
|
-
else this.next({
|
|
62
|
-
type: changeType,
|
|
63
|
-
index,
|
|
64
|
-
items: args
|
|
65
|
-
});
|
|
66
|
-
return result;
|
|
67
|
-
};
|
|
68
|
-
return Reflect.get(target, prop, receiver);
|
|
69
|
-
},
|
|
70
|
-
set: (target, prop, value) => {
|
|
71
|
-
const index = !isNaN(Number(prop)) ? Number(prop) : void 0;
|
|
72
|
-
target[prop] = value;
|
|
73
|
-
this.next({
|
|
74
|
-
type: "update",
|
|
75
|
-
index,
|
|
76
|
-
items: [value]
|
|
77
|
-
});
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
get items() {
|
|
83
|
-
return this._items;
|
|
84
|
-
}
|
|
85
|
-
set items(newItems) {
|
|
86
|
-
this.createProxy(newItems);
|
|
87
|
-
this.next({
|
|
88
|
-
type: "reset",
|
|
89
|
-
items: newItems
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
var ObjectSubject = class extends BehaviorSubject {
|
|
94
|
-
constructor(obj = {}) {
|
|
95
|
-
super({
|
|
96
|
-
type: "init",
|
|
97
|
-
value: obj
|
|
98
|
-
});
|
|
99
|
-
this.createProxy(obj);
|
|
100
|
-
}
|
|
101
|
-
createProxy(obj) {
|
|
102
|
-
this._obj = new Proxy(obj, {
|
|
103
|
-
get: (target, prop, receiver) => {
|
|
104
|
-
return Reflect.get(target, prop, receiver);
|
|
105
|
-
},
|
|
106
|
-
set: (target, prop, value, receiver) => {
|
|
107
|
-
const key = prop;
|
|
108
|
-
const changeType = key in target ? "update" : "add";
|
|
109
|
-
target[key] = value;
|
|
110
|
-
this.next({
|
|
111
|
-
type: changeType,
|
|
112
|
-
key,
|
|
113
|
-
value
|
|
114
|
-
});
|
|
115
|
-
return true;
|
|
116
|
-
},
|
|
117
|
-
deleteProperty: (target, prop) => {
|
|
118
|
-
const key = prop;
|
|
119
|
-
if (key in target) {
|
|
120
|
-
const value = target[key];
|
|
121
|
-
delete target[key];
|
|
122
|
-
this.next({
|
|
123
|
-
type: "remove",
|
|
124
|
-
key,
|
|
125
|
-
value
|
|
126
|
-
});
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
return false;
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
get obj() {
|
|
134
|
-
return this._obj;
|
|
135
|
-
}
|
|
136
|
-
set obj(newObj) {
|
|
137
|
-
this.createProxy(newObj);
|
|
138
|
-
this.next({
|
|
139
|
-
type: "reset",
|
|
140
|
-
value: newObj
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
var getGlobalReactiveStore = () => {
|
|
145
|
-
const globalKey = "__REACTIVE_STORE__";
|
|
146
|
-
if (typeof globalThis !== "undefined") {
|
|
147
|
-
if (!globalThis[globalKey]) globalThis[globalKey] = {
|
|
148
|
-
currentDependencyTracker: null,
|
|
149
|
-
currentSubscriptionsTracker: null
|
|
150
|
-
};
|
|
151
|
-
return globalThis[globalKey];
|
|
152
|
-
}
|
|
153
|
-
let globalObj;
|
|
154
|
-
if (typeof window !== "undefined") globalObj = window;
|
|
155
|
-
else if (typeof self !== "undefined") globalObj = self;
|
|
156
|
-
else if (typeof Function !== "undefined") globalObj = Function("return this")();
|
|
157
|
-
else {
|
|
158
|
-
console.warn("Unable to find global object, using local instance");
|
|
159
|
-
return {
|
|
160
|
-
currentDependencyTracker: null,
|
|
161
|
-
currentSubscriptionsTracker: null
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
if (!globalObj[globalKey]) globalObj[globalKey] = {
|
|
165
|
-
currentDependencyTracker: null,
|
|
166
|
-
currentSubscriptionsTracker: null
|
|
167
|
-
};
|
|
168
|
-
return globalObj[globalKey];
|
|
169
|
-
};
|
|
170
|
-
var reactiveStore = getGlobalReactiveStore();
|
|
171
|
-
var trackDependency = (signal2) => {
|
|
172
|
-
if (reactiveStore.currentDependencyTracker) reactiveStore.currentDependencyTracker(signal2);
|
|
173
|
-
};
|
|
174
|
-
function signal(defaultValue, options) {
|
|
175
|
-
let subject;
|
|
176
|
-
if (Array.isArray(defaultValue)) subject = new ArraySubject(defaultValue);
|
|
177
|
-
else if (typeof defaultValue === "object" && defaultValue !== null) subject = new ObjectSubject(defaultValue);
|
|
178
|
-
else subject = new BehaviorSubject(defaultValue);
|
|
179
|
-
const getValue = () => {
|
|
180
|
-
if (subject instanceof ArraySubject) return subject.items;
|
|
181
|
-
else if (subject instanceof ObjectSubject) return subject.obj;
|
|
182
|
-
return subject.value;
|
|
183
|
-
};
|
|
184
|
-
const fn = function() {
|
|
185
|
-
trackDependency(fn);
|
|
186
|
-
return getValue();
|
|
187
|
-
};
|
|
188
|
-
fn.set = (value) => {
|
|
189
|
-
const currentValue = getValue();
|
|
190
|
-
let shouldEmit = true;
|
|
191
|
-
if (options?.equal) shouldEmit = !options.equal(currentValue, value);
|
|
192
|
-
else shouldEmit = currentValue !== value;
|
|
193
|
-
if (shouldEmit) if (subject instanceof ArraySubject) subject.items = value;
|
|
194
|
-
else if (subject instanceof ObjectSubject) subject.obj = value;
|
|
195
|
-
else subject.next(value);
|
|
196
|
-
};
|
|
197
|
-
fn._isFrozen = false;
|
|
198
|
-
fn.freeze = () => {
|
|
199
|
-
fn._isFrozen = true;
|
|
200
|
-
};
|
|
201
|
-
fn.unfreeze = () => {
|
|
202
|
-
fn._isFrozen = false;
|
|
203
|
-
if (subject instanceof ArraySubject) subject.next({
|
|
204
|
-
type: "init",
|
|
205
|
-
items: subject.items
|
|
206
|
-
});
|
|
207
|
-
else if (subject instanceof ObjectSubject) subject.next({
|
|
208
|
-
type: "init",
|
|
209
|
-
value: subject.obj
|
|
210
|
-
});
|
|
211
|
-
else subject.next(subject.value);
|
|
212
|
-
};
|
|
213
|
-
fn.mutate = (mutateFn) => {
|
|
214
|
-
mutateFn(getValue());
|
|
215
|
-
};
|
|
216
|
-
fn.update = (updateFn) => {
|
|
217
|
-
const updatedValue = updateFn(getValue());
|
|
218
|
-
fn.set(updatedValue);
|
|
219
|
-
};
|
|
220
|
-
fn.observable = subject.asObservable().pipe(filter(() => !fn._isFrozen));
|
|
221
|
-
fn._subject = subject;
|
|
222
|
-
return fn;
|
|
223
|
-
}
|
|
224
|
-
//#endregion
|
|
225
|
-
export { signal };
|
|
226
|
-
|
|
227
|
-
//# sourceMappingURL=index.js.map
|