cubeforge 0.7.0 → 0.8.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/dist/index.d.ts +1 -0
- package/dist/index.js +591 -4
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export { AudioAnalyserControls, AudioAnalyserOptions, AudioGroup, AudioScheduler
|
|
|
17
17
|
export { DevToolsHandle } from '@cubeforge/devtools';
|
|
18
18
|
import { Room } from '@cubeforge/net';
|
|
19
19
|
export { BinaryNetTransport, ClientPrediction, InterpolationBuffer, InterpolationBufferConfig, InterpolationState, NetMessage, NetTransport, NetworkInputConfig, PredictionConfig, Room, RoomConfig, SyncConfig, WebRTCTransport, WebRTCTransportConfig, WebSocketTransportOptions, createWebRTCTransport, createWebSocketTransport, isBinaryTransport, syncEntity, useNetworkInput } from '@cubeforge/net';
|
|
20
|
+
export { BoolField, ColorField, EditorShell, EditorShellProps, EditorState, EntityInfo, EntityInspector, EntityInspectorProps, NumberField, SceneHierarchy, SceneHierarchyProps, TextField, Vec2Field, useEditorState } from '@cubeforge/editor';
|
|
20
21
|
|
|
21
22
|
interface GameControls {
|
|
22
23
|
pause(): void;
|
package/dist/index.js
CHANGED
|
@@ -83,6 +83,20 @@ function applyDeltaSnapshot(baseline, delta) {
|
|
|
83
83
|
}
|
|
84
84
|
return { nextId: delta.nextId, rngState: delta.rngState, entities };
|
|
85
85
|
}
|
|
86
|
+
function _componentsChanged(a, b) {
|
|
87
|
+
if (a.length !== b.length) return true;
|
|
88
|
+
for (let i = 0; i < a.length; i++) {
|
|
89
|
+
const ca = a[i];
|
|
90
|
+
const cb = b[i];
|
|
91
|
+
if (ca["type"] !== cb["type"]) return true;
|
|
92
|
+
const keysA = Object.keys(ca);
|
|
93
|
+
if (keysA.length !== Object.keys(cb).length) return true;
|
|
94
|
+
for (const k of keysA) {
|
|
95
|
+
if (ca[k] !== cb[k]) return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
86
100
|
var ECSWorld = class {
|
|
87
101
|
nextId = 0;
|
|
88
102
|
// Secondary index: O(1) single-entity component lookup
|
|
@@ -201,6 +215,23 @@ var ECSWorld = class {
|
|
|
201
215
|
hasComponent(id, type) {
|
|
202
216
|
return this.componentIndex.get(id)?.has(type) ?? false;
|
|
203
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Returns live references to all components on an entity.
|
|
220
|
+
* Useful for editor / inspector tooling. Returns an empty array if the
|
|
221
|
+
* entity does not exist.
|
|
222
|
+
*
|
|
223
|
+
* **Do not mutate structural fields** (e.g. `type`) — doing so will
|
|
224
|
+
* desync the archetype index. Mutating value fields (x, y, color …) is safe.
|
|
225
|
+
*/
|
|
226
|
+
getEntityComponents(id) {
|
|
227
|
+
const map = this.componentIndex.get(id);
|
|
228
|
+
if (!map) return [];
|
|
229
|
+
return [...map.values()];
|
|
230
|
+
}
|
|
231
|
+
/** Returns all live entity IDs currently in the world. */
|
|
232
|
+
getAllEntityIds() {
|
|
233
|
+
return [...this.componentIndex.keys()];
|
|
234
|
+
}
|
|
204
235
|
// Flush pending dirty flags into the query cache immediately.
|
|
205
236
|
// Called inline at the top of query() so any mid-frame mutation
|
|
206
237
|
// (destroyEntity, addComponent, removeComponent) is reflected before
|
|
@@ -437,7 +468,7 @@ var ECSWorld = class {
|
|
|
437
468
|
const removed = [];
|
|
438
469
|
for (const entity of current.entities) {
|
|
439
470
|
const base = baseMap.get(entity.id);
|
|
440
|
-
if (!base ||
|
|
471
|
+
if (!base || _componentsChanged(entity.components, base.components)) {
|
|
441
472
|
changed.push(entity);
|
|
442
473
|
}
|
|
443
474
|
}
|
|
@@ -8597,7 +8628,6 @@ function Checkpoint({
|
|
|
8597
8628
|
// src/components/Tilemap.tsx
|
|
8598
8629
|
import { useEffect as useEffect30, useState as useState6, useContext as useContext20 } from "react";
|
|
8599
8630
|
import { Fragment as Fragment5, jsx as jsx10 } from "react/jsx-runtime";
|
|
8600
|
-
var animatedTiles = /* @__PURE__ */ new Map();
|
|
8601
8631
|
function getProperty(props, name) {
|
|
8602
8632
|
return props?.find((p) => p.name === name)?.value;
|
|
8603
8633
|
}
|
|
@@ -8629,6 +8659,7 @@ function Tilemap({
|
|
|
8629
8659
|
useEffect30(() => {
|
|
8630
8660
|
if (!engine) return;
|
|
8631
8661
|
const createdEntities = [];
|
|
8662
|
+
const animatedTiles = /* @__PURE__ */ new Map();
|
|
8632
8663
|
async function load() {
|
|
8633
8664
|
let mapData;
|
|
8634
8665
|
try {
|
|
@@ -8764,6 +8795,7 @@ function Tilemap({
|
|
|
8764
8795
|
if (frame) {
|
|
8765
8796
|
sprite.frame = { sx: frame.sx, sy: frame.sy, sw: frame.sw, sh: frame.sh };
|
|
8766
8797
|
engine.assets.loadImage(frame.imageSrc).then((img) => {
|
|
8798
|
+
if (!engine.ecs.hasEntity(eid)) return;
|
|
8767
8799
|
const s2 = engine.ecs.getComponent(eid, "Sprite");
|
|
8768
8800
|
if (s2) s2.image = img;
|
|
8769
8801
|
}).catch(() => {
|
|
@@ -8779,6 +8811,7 @@ function Tilemap({
|
|
|
8779
8811
|
animatedTiles.set(eid, state);
|
|
8780
8812
|
const firstFrameRegion = getFrameForLocalId(resolved.tileset, frames[0]);
|
|
8781
8813
|
engine.assets.loadImage(firstFrameRegion.imageSrc).then((img) => {
|
|
8814
|
+
if (!engine.ecs.hasEntity(eid)) return;
|
|
8782
8815
|
const s2 = engine.ecs.getComponent(eid, "Sprite");
|
|
8783
8816
|
if (s2) {
|
|
8784
8817
|
s2.image = img;
|
|
@@ -14610,7 +14643,7 @@ function HUDBar({
|
|
|
14610
14643
|
display: "flex",
|
|
14611
14644
|
flexDirection: rtl ? "row-reverse" : "row"
|
|
14612
14645
|
};
|
|
14613
|
-
const
|
|
14646
|
+
const labelStyle2 = {
|
|
14614
14647
|
fontFamily: "system-ui, sans-serif",
|
|
14615
14648
|
fontSize: 11,
|
|
14616
14649
|
letterSpacing: 0.5,
|
|
@@ -14622,7 +14655,7 @@ function HUDBar({
|
|
|
14622
14655
|
marginBottom: 4
|
|
14623
14656
|
};
|
|
14624
14657
|
return /* @__PURE__ */ jsxs11("div", { style: { display: "flex", flexDirection: "column", ...style }, "aria-label": label, children: [
|
|
14625
|
-
(label || showValue) && /* @__PURE__ */ jsxs11("div", { style:
|
|
14658
|
+
(label || showValue) && /* @__PURE__ */ jsxs11("div", { style: labelStyle2, children: [
|
|
14626
14659
|
label && /* @__PURE__ */ jsx22("span", { children: label }),
|
|
14627
14660
|
showValue && /* @__PURE__ */ jsxs11("span", { style: { fontVariantNumeric: "tabular-nums" }, children: [
|
|
14628
14661
|
Math.round(value),
|
|
@@ -15330,12 +15363,558 @@ function useRemotePlayer(config) {
|
|
|
15330
15363
|
}, [room, world]);
|
|
15331
15364
|
return { players };
|
|
15332
15365
|
}
|
|
15366
|
+
|
|
15367
|
+
// ../editor/src/components/SceneHierarchy.tsx
|
|
15368
|
+
import { jsx as jsx23, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
15369
|
+
var panelStyle = {
|
|
15370
|
+
background: "#0d1520",
|
|
15371
|
+
borderRight: "1px solid #1a2a3a",
|
|
15372
|
+
color: "#c0d0e0",
|
|
15373
|
+
fontFamily: "system-ui, sans-serif",
|
|
15374
|
+
fontSize: 12,
|
|
15375
|
+
display: "flex",
|
|
15376
|
+
flexDirection: "column",
|
|
15377
|
+
overflow: "hidden",
|
|
15378
|
+
userSelect: "none"
|
|
15379
|
+
};
|
|
15380
|
+
var headerStyle = {
|
|
15381
|
+
padding: "6px 10px",
|
|
15382
|
+
fontSize: 10,
|
|
15383
|
+
fontWeight: 700,
|
|
15384
|
+
textTransform: "uppercase",
|
|
15385
|
+
letterSpacing: 1,
|
|
15386
|
+
color: "#4fc3f7",
|
|
15387
|
+
borderBottom: "1px solid #1a2a3a",
|
|
15388
|
+
flexShrink: 0
|
|
15389
|
+
};
|
|
15390
|
+
var listStyle = {
|
|
15391
|
+
flex: 1,
|
|
15392
|
+
overflowY: "auto",
|
|
15393
|
+
padding: "4px 0"
|
|
15394
|
+
};
|
|
15395
|
+
function entityRowStyle(selected) {
|
|
15396
|
+
return {
|
|
15397
|
+
display: "flex",
|
|
15398
|
+
alignItems: "center",
|
|
15399
|
+
gap: 6,
|
|
15400
|
+
padding: "3px 10px",
|
|
15401
|
+
cursor: "pointer",
|
|
15402
|
+
background: selected ? "#1a3050" : "transparent",
|
|
15403
|
+
borderLeft: selected ? "2px solid #4fc3f7" : "2px solid transparent",
|
|
15404
|
+
color: selected ? "#e0f0ff" : "#a0b4c8",
|
|
15405
|
+
transition: "background 80ms"
|
|
15406
|
+
};
|
|
15407
|
+
}
|
|
15408
|
+
var componentBadgeStyle = {
|
|
15409
|
+
fontSize: 9,
|
|
15410
|
+
background: "#1a2a3a",
|
|
15411
|
+
color: "#607080",
|
|
15412
|
+
borderRadius: 3,
|
|
15413
|
+
padding: "1px 4px",
|
|
15414
|
+
maxWidth: 60,
|
|
15415
|
+
overflow: "hidden",
|
|
15416
|
+
textOverflow: "ellipsis",
|
|
15417
|
+
whiteSpace: "nowrap"
|
|
15418
|
+
};
|
|
15419
|
+
function SceneHierarchy({ entities, selectedId, onSelect, width = 220, style }) {
|
|
15420
|
+
return /* @__PURE__ */ jsxs12("div", { style: { ...panelStyle, width, ...style }, children: [
|
|
15421
|
+
/* @__PURE__ */ jsx23("div", { style: headerStyle, children: "Scene Hierarchy" }),
|
|
15422
|
+
/* @__PURE__ */ jsxs12("div", { style: { padding: "4px 10px", borderBottom: "1px solid #1a2a3a", color: "#4a5a6a", fontSize: 10 }, children: [
|
|
15423
|
+
entities.length,
|
|
15424
|
+
" ",
|
|
15425
|
+
entities.length === 1 ? "entity" : "entities"
|
|
15426
|
+
] }),
|
|
15427
|
+
/* @__PURE__ */ jsxs12("div", { style: listStyle, children: [
|
|
15428
|
+
entities.map((e) => /* @__PURE__ */ jsx23(
|
|
15429
|
+
"div",
|
|
15430
|
+
{
|
|
15431
|
+
style: entityRowStyle(e.id === selectedId),
|
|
15432
|
+
onClick: () => onSelect(e.id === selectedId ? null : e.id),
|
|
15433
|
+
children: /* @__PURE__ */ jsxs12("div", { style: { flex: 1, overflow: "hidden" }, children: [
|
|
15434
|
+
/* @__PURE__ */ jsx23("div", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: e.name }),
|
|
15435
|
+
/* @__PURE__ */ jsxs12("div", { style: { display: "flex", gap: 3, marginTop: 2, flexWrap: "wrap" }, children: [
|
|
15436
|
+
e.componentTypes.slice(0, 3).map((t) => /* @__PURE__ */ jsx23("span", { style: componentBadgeStyle, children: t }, t)),
|
|
15437
|
+
e.componentTypes.length > 3 && /* @__PURE__ */ jsxs12("span", { style: componentBadgeStyle, children: [
|
|
15438
|
+
"+",
|
|
15439
|
+
e.componentTypes.length - 3
|
|
15440
|
+
] })
|
|
15441
|
+
] })
|
|
15442
|
+
] })
|
|
15443
|
+
},
|
|
15444
|
+
e.id
|
|
15445
|
+
)),
|
|
15446
|
+
entities.length === 0 && /* @__PURE__ */ jsx23("div", { style: { padding: "10px", color: "#3a5060", fontSize: 11, textAlign: "center" }, children: "No entities" })
|
|
15447
|
+
] })
|
|
15448
|
+
] });
|
|
15449
|
+
}
|
|
15450
|
+
|
|
15451
|
+
// ../editor/src/components/PropertyField.tsx
|
|
15452
|
+
import { jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
15453
|
+
var fieldRow = {
|
|
15454
|
+
display: "flex",
|
|
15455
|
+
alignItems: "center",
|
|
15456
|
+
gap: 6,
|
|
15457
|
+
marginBottom: 4,
|
|
15458
|
+
minHeight: 24
|
|
15459
|
+
};
|
|
15460
|
+
var labelStyle = {
|
|
15461
|
+
flex: "0 0 90px",
|
|
15462
|
+
fontSize: 11,
|
|
15463
|
+
color: "#8899aa",
|
|
15464
|
+
overflow: "hidden",
|
|
15465
|
+
textOverflow: "ellipsis",
|
|
15466
|
+
whiteSpace: "nowrap",
|
|
15467
|
+
fontFamily: "system-ui, sans-serif",
|
|
15468
|
+
textTransform: "uppercase",
|
|
15469
|
+
letterSpacing: 0.5
|
|
15470
|
+
};
|
|
15471
|
+
var inputBase = {
|
|
15472
|
+
flex: 1,
|
|
15473
|
+
background: "#1a2030",
|
|
15474
|
+
border: "1px solid #2a3a50",
|
|
15475
|
+
borderRadius: 3,
|
|
15476
|
+
color: "#d0e0f0",
|
|
15477
|
+
padding: "2px 6px",
|
|
15478
|
+
fontSize: 11,
|
|
15479
|
+
fontFamily: "monospace",
|
|
15480
|
+
outline: "none",
|
|
15481
|
+
minWidth: 0
|
|
15482
|
+
};
|
|
15483
|
+
function NumberField({ label, value, onChange, step = 1 }) {
|
|
15484
|
+
return /* @__PURE__ */ jsxs13("div", { style: fieldRow, children: [
|
|
15485
|
+
/* @__PURE__ */ jsx24("span", { style: labelStyle, title: label, children: label }),
|
|
15486
|
+
/* @__PURE__ */ jsx24(
|
|
15487
|
+
"input",
|
|
15488
|
+
{
|
|
15489
|
+
type: "number",
|
|
15490
|
+
style: inputBase,
|
|
15491
|
+
value: isNaN(value) ? "" : value,
|
|
15492
|
+
step,
|
|
15493
|
+
onChange: (e) => {
|
|
15494
|
+
const v = parseFloat(e.target.value);
|
|
15495
|
+
if (!isNaN(v)) onChange(v);
|
|
15496
|
+
}
|
|
15497
|
+
}
|
|
15498
|
+
)
|
|
15499
|
+
] });
|
|
15500
|
+
}
|
|
15501
|
+
function TextField({ label, value, onChange }) {
|
|
15502
|
+
return /* @__PURE__ */ jsxs13("div", { style: fieldRow, children: [
|
|
15503
|
+
/* @__PURE__ */ jsx24("span", { style: labelStyle, title: label, children: label }),
|
|
15504
|
+
/* @__PURE__ */ jsx24("input", { type: "text", style: inputBase, value, onChange: (e) => onChange(e.target.value) })
|
|
15505
|
+
] });
|
|
15506
|
+
}
|
|
15507
|
+
function BoolField({ label, value, onChange }) {
|
|
15508
|
+
return /* @__PURE__ */ jsxs13("div", { style: fieldRow, children: [
|
|
15509
|
+
/* @__PURE__ */ jsx24("span", { style: labelStyle, title: label, children: label }),
|
|
15510
|
+
/* @__PURE__ */ jsx24(
|
|
15511
|
+
"input",
|
|
15512
|
+
{
|
|
15513
|
+
type: "checkbox",
|
|
15514
|
+
checked: value,
|
|
15515
|
+
style: { accentColor: "#4fc3f7", cursor: "pointer" },
|
|
15516
|
+
onChange: (e) => onChange(e.target.checked)
|
|
15517
|
+
}
|
|
15518
|
+
)
|
|
15519
|
+
] });
|
|
15520
|
+
}
|
|
15521
|
+
function ColorField({ label, value, onChange }) {
|
|
15522
|
+
return /* @__PURE__ */ jsxs13("div", { style: fieldRow, children: [
|
|
15523
|
+
/* @__PURE__ */ jsx24("span", { style: labelStyle, title: label, children: label }),
|
|
15524
|
+
/* @__PURE__ */ jsxs13("div", { style: { display: "flex", gap: 4, flex: 1 }, children: [
|
|
15525
|
+
/* @__PURE__ */ jsx24(
|
|
15526
|
+
"input",
|
|
15527
|
+
{
|
|
15528
|
+
type: "color",
|
|
15529
|
+
value: value.startsWith("#") ? value.slice(0, 7) : "#ffffff",
|
|
15530
|
+
style: { width: 28, height: 22, padding: 1, border: "1px solid #2a3a50", borderRadius: 3, cursor: "pointer" },
|
|
15531
|
+
onChange: (e) => onChange(e.target.value)
|
|
15532
|
+
}
|
|
15533
|
+
),
|
|
15534
|
+
/* @__PURE__ */ jsx24("input", { type: "text", style: { ...inputBase, flex: 1 }, value, onChange: (e) => onChange(e.target.value) })
|
|
15535
|
+
] })
|
|
15536
|
+
] });
|
|
15537
|
+
}
|
|
15538
|
+
function Vec2Field({ label, x, y, onChangeX, onChangeY, step = 1 }) {
|
|
15539
|
+
return /* @__PURE__ */ jsxs13("div", { style: fieldRow, children: [
|
|
15540
|
+
/* @__PURE__ */ jsx24("span", { style: labelStyle, title: label, children: label }),
|
|
15541
|
+
/* @__PURE__ */ jsxs13("div", { style: { display: "flex", gap: 4, flex: 1 }, children: [
|
|
15542
|
+
/* @__PURE__ */ jsx24(
|
|
15543
|
+
"input",
|
|
15544
|
+
{
|
|
15545
|
+
type: "number",
|
|
15546
|
+
style: { ...inputBase, flex: 1 },
|
|
15547
|
+
value: isNaN(x) ? "" : x,
|
|
15548
|
+
step,
|
|
15549
|
+
onChange: (e) => {
|
|
15550
|
+
const v = parseFloat(e.target.value);
|
|
15551
|
+
if (!isNaN(v)) onChangeX(v);
|
|
15552
|
+
}
|
|
15553
|
+
}
|
|
15554
|
+
),
|
|
15555
|
+
/* @__PURE__ */ jsx24(
|
|
15556
|
+
"input",
|
|
15557
|
+
{
|
|
15558
|
+
type: "number",
|
|
15559
|
+
style: { ...inputBase, flex: 1 },
|
|
15560
|
+
value: isNaN(y) ? "" : y,
|
|
15561
|
+
step,
|
|
15562
|
+
onChange: (e) => {
|
|
15563
|
+
const v = parseFloat(e.target.value);
|
|
15564
|
+
if (!isNaN(v)) onChangeY(v);
|
|
15565
|
+
}
|
|
15566
|
+
}
|
|
15567
|
+
)
|
|
15568
|
+
] })
|
|
15569
|
+
] });
|
|
15570
|
+
}
|
|
15571
|
+
|
|
15572
|
+
// ../editor/src/components/EntityInspector.tsx
|
|
15573
|
+
import { Fragment as Fragment10, jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
15574
|
+
var panelStyle2 = {
|
|
15575
|
+
background: "#0d1520",
|
|
15576
|
+
borderLeft: "1px solid #1a2a3a",
|
|
15577
|
+
color: "#c0d0e0",
|
|
15578
|
+
fontFamily: "system-ui, sans-serif",
|
|
15579
|
+
fontSize: 12,
|
|
15580
|
+
display: "flex",
|
|
15581
|
+
flexDirection: "column",
|
|
15582
|
+
overflow: "hidden",
|
|
15583
|
+
userSelect: "none"
|
|
15584
|
+
};
|
|
15585
|
+
var headerStyle2 = {
|
|
15586
|
+
padding: "6px 10px",
|
|
15587
|
+
fontSize: 10,
|
|
15588
|
+
fontWeight: 700,
|
|
15589
|
+
textTransform: "uppercase",
|
|
15590
|
+
letterSpacing: 1,
|
|
15591
|
+
color: "#4fc3f7",
|
|
15592
|
+
borderBottom: "1px solid #1a2a3a",
|
|
15593
|
+
flexShrink: 0
|
|
15594
|
+
};
|
|
15595
|
+
var scrollStyle = {
|
|
15596
|
+
flex: 1,
|
|
15597
|
+
overflowY: "auto",
|
|
15598
|
+
padding: "6px 0"
|
|
15599
|
+
};
|
|
15600
|
+
var componentSectionStyle = {
|
|
15601
|
+
marginBottom: 2,
|
|
15602
|
+
borderBottom: "1px solid #131d2a"
|
|
15603
|
+
};
|
|
15604
|
+
var componentHeaderStyle = {
|
|
15605
|
+
display: "flex",
|
|
15606
|
+
alignItems: "center",
|
|
15607
|
+
padding: "4px 10px",
|
|
15608
|
+
fontSize: 10,
|
|
15609
|
+
fontWeight: 700,
|
|
15610
|
+
textTransform: "uppercase",
|
|
15611
|
+
letterSpacing: 0.8,
|
|
15612
|
+
color: "#80a8c0",
|
|
15613
|
+
cursor: "default",
|
|
15614
|
+
background: "#0f1a28"
|
|
15615
|
+
};
|
|
15616
|
+
var fieldsStyle = {
|
|
15617
|
+
padding: "4px 10px 6px"
|
|
15618
|
+
};
|
|
15619
|
+
function isColorKey(key) {
|
|
15620
|
+
const lower = key.toLowerCase();
|
|
15621
|
+
return lower === "color" || lower === "background" || lower === "fill" || lower === "stroke" || lower.includes("color");
|
|
15622
|
+
}
|
|
15623
|
+
function ComponentSection({ comp }) {
|
|
15624
|
+
const compRecord = comp;
|
|
15625
|
+
const entries = Object.entries(comp).filter(([k]) => k !== "type");
|
|
15626
|
+
const rendered = /* @__PURE__ */ new Set();
|
|
15627
|
+
return /* @__PURE__ */ jsxs14("div", { style: componentSectionStyle, children: [
|
|
15628
|
+
/* @__PURE__ */ jsx25("div", { style: componentHeaderStyle, children: comp.type }),
|
|
15629
|
+
/* @__PURE__ */ jsxs14("div", { style: fieldsStyle, children: [
|
|
15630
|
+
entries.map(([key, val]) => {
|
|
15631
|
+
if (rendered.has(key)) return null;
|
|
15632
|
+
if (key === "x" && typeof val === "number" && typeof compRecord["y"] === "number") {
|
|
15633
|
+
rendered.add("x");
|
|
15634
|
+
rendered.add("y");
|
|
15635
|
+
return /* @__PURE__ */ jsx25(
|
|
15636
|
+
Vec2Field,
|
|
15637
|
+
{
|
|
15638
|
+
label: "pos",
|
|
15639
|
+
x: val,
|
|
15640
|
+
y: compRecord["y"],
|
|
15641
|
+
step: 0.5,
|
|
15642
|
+
onChangeX: (v) => {
|
|
15643
|
+
compRecord["x"] = v;
|
|
15644
|
+
},
|
|
15645
|
+
onChangeY: (v) => {
|
|
15646
|
+
compRecord["y"] = v;
|
|
15647
|
+
}
|
|
15648
|
+
},
|
|
15649
|
+
"xy"
|
|
15650
|
+
);
|
|
15651
|
+
}
|
|
15652
|
+
if (key === "followOffsetX" && typeof val === "number") {
|
|
15653
|
+
const oy = compRecord["followOffsetY"];
|
|
15654
|
+
if (typeof oy === "number") {
|
|
15655
|
+
rendered.add("followOffsetX");
|
|
15656
|
+
rendered.add("followOffsetY");
|
|
15657
|
+
return /* @__PURE__ */ jsx25(
|
|
15658
|
+
Vec2Field,
|
|
15659
|
+
{
|
|
15660
|
+
label: "offset",
|
|
15661
|
+
x: val,
|
|
15662
|
+
y: oy,
|
|
15663
|
+
step: 1,
|
|
15664
|
+
onChangeX: (v) => {
|
|
15665
|
+
compRecord["followOffsetX"] = v;
|
|
15666
|
+
},
|
|
15667
|
+
onChangeY: (v) => {
|
|
15668
|
+
compRecord["followOffsetY"] = v;
|
|
15669
|
+
}
|
|
15670
|
+
},
|
|
15671
|
+
"followOffset"
|
|
15672
|
+
);
|
|
15673
|
+
}
|
|
15674
|
+
}
|
|
15675
|
+
if (typeof val === "number") {
|
|
15676
|
+
rendered.add(key);
|
|
15677
|
+
return /* @__PURE__ */ jsx25(
|
|
15678
|
+
NumberField,
|
|
15679
|
+
{
|
|
15680
|
+
label: key,
|
|
15681
|
+
value: val,
|
|
15682
|
+
step: Math.abs(val) < 2 ? 0.01 : 1,
|
|
15683
|
+
onChange: (v) => {
|
|
15684
|
+
compRecord[key] = v;
|
|
15685
|
+
}
|
|
15686
|
+
},
|
|
15687
|
+
key
|
|
15688
|
+
);
|
|
15689
|
+
}
|
|
15690
|
+
if (typeof val === "string" && isColorKey(key)) {
|
|
15691
|
+
rendered.add(key);
|
|
15692
|
+
return /* @__PURE__ */ jsx25(
|
|
15693
|
+
ColorField,
|
|
15694
|
+
{
|
|
15695
|
+
label: key,
|
|
15696
|
+
value: val,
|
|
15697
|
+
onChange: (v) => {
|
|
15698
|
+
compRecord[key] = v;
|
|
15699
|
+
}
|
|
15700
|
+
},
|
|
15701
|
+
key
|
|
15702
|
+
);
|
|
15703
|
+
}
|
|
15704
|
+
if (typeof val === "string") {
|
|
15705
|
+
rendered.add(key);
|
|
15706
|
+
return /* @__PURE__ */ jsx25(
|
|
15707
|
+
TextField,
|
|
15708
|
+
{
|
|
15709
|
+
label: key,
|
|
15710
|
+
value: val,
|
|
15711
|
+
onChange: (v) => {
|
|
15712
|
+
compRecord[key] = v;
|
|
15713
|
+
}
|
|
15714
|
+
},
|
|
15715
|
+
key
|
|
15716
|
+
);
|
|
15717
|
+
}
|
|
15718
|
+
if (typeof val === "boolean") {
|
|
15719
|
+
rendered.add(key);
|
|
15720
|
+
return /* @__PURE__ */ jsx25(
|
|
15721
|
+
BoolField,
|
|
15722
|
+
{
|
|
15723
|
+
label: key,
|
|
15724
|
+
value: val,
|
|
15725
|
+
onChange: (v) => {
|
|
15726
|
+
compRecord[key] = v;
|
|
15727
|
+
}
|
|
15728
|
+
},
|
|
15729
|
+
key
|
|
15730
|
+
);
|
|
15731
|
+
}
|
|
15732
|
+
if (val !== null && val !== void 0 && typeof val !== "function") {
|
|
15733
|
+
rendered.add(key);
|
|
15734
|
+
const preview = typeof val === "object" ? JSON.stringify(val).slice(0, 60) : String(val);
|
|
15735
|
+
return /* @__PURE__ */ jsxs14(
|
|
15736
|
+
"div",
|
|
15737
|
+
{
|
|
15738
|
+
style: {
|
|
15739
|
+
display: "flex",
|
|
15740
|
+
gap: 6,
|
|
15741
|
+
marginBottom: 4,
|
|
15742
|
+
fontSize: 11,
|
|
15743
|
+
alignItems: "flex-start"
|
|
15744
|
+
},
|
|
15745
|
+
children: [
|
|
15746
|
+
/* @__PURE__ */ jsx25(
|
|
15747
|
+
"span",
|
|
15748
|
+
{
|
|
15749
|
+
style: {
|
|
15750
|
+
flex: "0 0 90px",
|
|
15751
|
+
color: "#6a7a8a",
|
|
15752
|
+
textTransform: "uppercase",
|
|
15753
|
+
fontSize: 10,
|
|
15754
|
+
letterSpacing: 0.5,
|
|
15755
|
+
paddingTop: 2
|
|
15756
|
+
},
|
|
15757
|
+
children: key
|
|
15758
|
+
}
|
|
15759
|
+
),
|
|
15760
|
+
/* @__PURE__ */ jsx25(
|
|
15761
|
+
"span",
|
|
15762
|
+
{
|
|
15763
|
+
style: { flex: 1, color: "#506070", fontFamily: "monospace", wordBreak: "break-all", fontSize: 10 },
|
|
15764
|
+
children: preview
|
|
15765
|
+
}
|
|
15766
|
+
)
|
|
15767
|
+
]
|
|
15768
|
+
},
|
|
15769
|
+
key
|
|
15770
|
+
);
|
|
15771
|
+
}
|
|
15772
|
+
return null;
|
|
15773
|
+
}),
|
|
15774
|
+
entries.length === 0 && /* @__PURE__ */ jsx25("div", { style: { color: "#3a5060", fontSize: 10 }, children: "No fields" })
|
|
15775
|
+
] })
|
|
15776
|
+
] });
|
|
15777
|
+
}
|
|
15778
|
+
function EntityInspector({ entity, components, width = 260, style }) {
|
|
15779
|
+
return /* @__PURE__ */ jsxs14("div", { style: { ...panelStyle2, width, ...style }, children: [
|
|
15780
|
+
/* @__PURE__ */ jsx25("div", { style: headerStyle2, children: "Inspector" }),
|
|
15781
|
+
entity ? /* @__PURE__ */ jsxs14(Fragment10, { children: [
|
|
15782
|
+
/* @__PURE__ */ jsxs14(
|
|
15783
|
+
"div",
|
|
15784
|
+
{
|
|
15785
|
+
style: {
|
|
15786
|
+
padding: "6px 10px",
|
|
15787
|
+
borderBottom: "1px solid #1a2a3a",
|
|
15788
|
+
color: "#d0e0f0",
|
|
15789
|
+
fontSize: 12,
|
|
15790
|
+
fontWeight: 600
|
|
15791
|
+
},
|
|
15792
|
+
children: [
|
|
15793
|
+
entity.name,
|
|
15794
|
+
/* @__PURE__ */ jsxs14("span", { style: { color: "#4a6070", fontSize: 10, marginLeft: 6 }, children: [
|
|
15795
|
+
"#",
|
|
15796
|
+
entity.id
|
|
15797
|
+
] })
|
|
15798
|
+
]
|
|
15799
|
+
}
|
|
15800
|
+
),
|
|
15801
|
+
/* @__PURE__ */ jsxs14("div", { style: scrollStyle, children: [
|
|
15802
|
+
components.map((comp) => /* @__PURE__ */ jsx25(ComponentSection, { comp }, comp.type)),
|
|
15803
|
+
components.length === 0 && /* @__PURE__ */ jsx25("div", { style: { padding: "10px", color: "#3a5060", fontSize: 11, textAlign: "center" }, children: "No components" })
|
|
15804
|
+
] })
|
|
15805
|
+
] }) : /* @__PURE__ */ jsx25(
|
|
15806
|
+
"div",
|
|
15807
|
+
{
|
|
15808
|
+
style: {
|
|
15809
|
+
flex: 1,
|
|
15810
|
+
display: "flex",
|
|
15811
|
+
alignItems: "center",
|
|
15812
|
+
justifyContent: "center",
|
|
15813
|
+
color: "#2a4050",
|
|
15814
|
+
fontSize: 11
|
|
15815
|
+
},
|
|
15816
|
+
children: "Select an entity"
|
|
15817
|
+
}
|
|
15818
|
+
)
|
|
15819
|
+
] });
|
|
15820
|
+
}
|
|
15821
|
+
|
|
15822
|
+
// ../editor/src/hooks/useEditorState.ts
|
|
15823
|
+
import { useState as useState34, useCallback as useCallback37, useContext as useContext81, useEffect as useEffect86, useRef as useRef54 } from "react";
|
|
15824
|
+
function buildEntityInfo(engine) {
|
|
15825
|
+
const nameMap = /* @__PURE__ */ new Map();
|
|
15826
|
+
engine.entityIds.forEach((eid, name) => nameMap.set(eid, name));
|
|
15827
|
+
const ids = engine.ecs.getAllEntityIds();
|
|
15828
|
+
return ids.map((id) => {
|
|
15829
|
+
const comps = engine.ecs.getEntityComponents(id);
|
|
15830
|
+
return {
|
|
15831
|
+
id,
|
|
15832
|
+
name: nameMap.get(id) ?? `Entity #${id}`,
|
|
15833
|
+
componentTypes: comps.map((c) => c.type)
|
|
15834
|
+
};
|
|
15835
|
+
});
|
|
15836
|
+
}
|
|
15837
|
+
function useEditorState(refreshHz = 4) {
|
|
15838
|
+
const engine = useContext81(EngineContext);
|
|
15839
|
+
const [entities, setEntities] = useState34([]);
|
|
15840
|
+
const [selectedId, setSelectedId] = useState34(null);
|
|
15841
|
+
const intervalRef = useRef54(null);
|
|
15842
|
+
const refresh = useCallback37(() => {
|
|
15843
|
+
setEntities(buildEntityInfo(engine));
|
|
15844
|
+
}, [engine]);
|
|
15845
|
+
useEffect86(() => {
|
|
15846
|
+
refresh();
|
|
15847
|
+
intervalRef.current = setInterval(refresh, 1e3 / refreshHz);
|
|
15848
|
+
return () => {
|
|
15849
|
+
if (intervalRef.current !== null) clearInterval(intervalRef.current);
|
|
15850
|
+
};
|
|
15851
|
+
}, [refresh, refreshHz]);
|
|
15852
|
+
const select = useCallback37((id) => {
|
|
15853
|
+
setSelectedId(id);
|
|
15854
|
+
}, []);
|
|
15855
|
+
const selectedComponents = selectedId !== null ? engine.ecs.getEntityComponents(selectedId) : [];
|
|
15856
|
+
return { entities, selectedId, selectedComponents, select, refresh };
|
|
15857
|
+
}
|
|
15858
|
+
|
|
15859
|
+
// ../editor/src/components/EditorShell.tsx
|
|
15860
|
+
import { Fragment as Fragment11, jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
15861
|
+
function EditorShell({
|
|
15862
|
+
children,
|
|
15863
|
+
active = true,
|
|
15864
|
+
hierarchyWidth = 220,
|
|
15865
|
+
inspectorWidth = 260,
|
|
15866
|
+
style
|
|
15867
|
+
}) {
|
|
15868
|
+
const state = useEditorState();
|
|
15869
|
+
const selectedEntity = state.entities.find((e) => e.id === state.selectedId) ?? null;
|
|
15870
|
+
if (!active) {
|
|
15871
|
+
return /* @__PURE__ */ jsx26(Fragment11, { children });
|
|
15872
|
+
}
|
|
15873
|
+
const shellStyle = {
|
|
15874
|
+
position: "absolute",
|
|
15875
|
+
inset: 0,
|
|
15876
|
+
display: "flex",
|
|
15877
|
+
flexDirection: "row",
|
|
15878
|
+
pointerEvents: "none",
|
|
15879
|
+
zIndex: 200,
|
|
15880
|
+
...style
|
|
15881
|
+
};
|
|
15882
|
+
const sideStyle = {
|
|
15883
|
+
pointerEvents: "auto",
|
|
15884
|
+
flexShrink: 0,
|
|
15885
|
+
height: "100%",
|
|
15886
|
+
overflow: "hidden"
|
|
15887
|
+
};
|
|
15888
|
+
return /* @__PURE__ */ jsxs15("div", { style: shellStyle, children: [
|
|
15889
|
+
/* @__PURE__ */ jsx26("div", { style: sideStyle, children: /* @__PURE__ */ jsx26(
|
|
15890
|
+
SceneHierarchy,
|
|
15891
|
+
{
|
|
15892
|
+
entities: state.entities,
|
|
15893
|
+
selectedId: state.selectedId,
|
|
15894
|
+
onSelect: state.select,
|
|
15895
|
+
width: hierarchyWidth,
|
|
15896
|
+
style: { height: "100%" }
|
|
15897
|
+
}
|
|
15898
|
+
) }),
|
|
15899
|
+
/* @__PURE__ */ jsx26("div", { style: { flex: 1, pointerEvents: "none" }, children }),
|
|
15900
|
+
/* @__PURE__ */ jsx26("div", { style: sideStyle, children: /* @__PURE__ */ jsx26(
|
|
15901
|
+
EntityInspector,
|
|
15902
|
+
{
|
|
15903
|
+
entity: selectedEntity,
|
|
15904
|
+
components: state.selectedComponents,
|
|
15905
|
+
width: inspectorWidth,
|
|
15906
|
+
style: { height: "100%" }
|
|
15907
|
+
}
|
|
15908
|
+
) })
|
|
15909
|
+
] });
|
|
15910
|
+
}
|
|
15333
15911
|
export {
|
|
15334
15912
|
A11yNode,
|
|
15335
15913
|
AnimatedSprite,
|
|
15336
15914
|
Animation,
|
|
15337
15915
|
Animator,
|
|
15338
15916
|
AssetLoader,
|
|
15917
|
+
BoolField,
|
|
15339
15918
|
BoxCollider,
|
|
15340
15919
|
COLLISION_DYNAMIC_DYNAMIC,
|
|
15341
15920
|
COLLISION_DYNAMIC_KINEMATIC,
|
|
@@ -15351,6 +15930,7 @@ export {
|
|
|
15351
15930
|
CircleCollider,
|
|
15352
15931
|
ClientPrediction,
|
|
15353
15932
|
CollisionPipeline,
|
|
15933
|
+
ColorField,
|
|
15354
15934
|
ComboDetector,
|
|
15355
15935
|
CompoundCollider,
|
|
15356
15936
|
ConvexCollider,
|
|
@@ -15359,7 +15939,9 @@ export {
|
|
|
15359
15939
|
DialogueBox,
|
|
15360
15940
|
Ease,
|
|
15361
15941
|
EditableText,
|
|
15942
|
+
EditorShell,
|
|
15362
15943
|
Entity,
|
|
15944
|
+
EntityInspector,
|
|
15363
15945
|
FocusRing,
|
|
15364
15946
|
Game,
|
|
15365
15947
|
Gradient,
|
|
@@ -15377,6 +15959,7 @@ export {
|
|
|
15377
15959
|
Mask,
|
|
15378
15960
|
MovingPlatform,
|
|
15379
15961
|
NineSlice,
|
|
15962
|
+
NumberField,
|
|
15380
15963
|
PARTICLE_PRESETS,
|
|
15381
15964
|
ParallaxLayer,
|
|
15382
15965
|
ParticleEmitter,
|
|
@@ -15384,6 +15967,7 @@ export {
|
|
|
15384
15967
|
RenderSystem,
|
|
15385
15968
|
RigidBody,
|
|
15386
15969
|
Room,
|
|
15970
|
+
SceneHierarchy,
|
|
15387
15971
|
SceneTransitionOverlay,
|
|
15388
15972
|
ScreenFlash,
|
|
15389
15973
|
Script,
|
|
@@ -15394,6 +15978,7 @@ export {
|
|
|
15394
15978
|
SquashStretch,
|
|
15395
15979
|
Stage,
|
|
15396
15980
|
Text,
|
|
15981
|
+
TextField,
|
|
15397
15982
|
TextureFilter,
|
|
15398
15983
|
Tilemap,
|
|
15399
15984
|
Trail,
|
|
@@ -15401,6 +15986,7 @@ export {
|
|
|
15401
15986
|
TransformHandles,
|
|
15402
15987
|
TriMeshCollider,
|
|
15403
15988
|
TriangleCollider,
|
|
15989
|
+
Vec2Field,
|
|
15404
15990
|
VectorPath,
|
|
15405
15991
|
VirtualCamera,
|
|
15406
15992
|
VirtualJoystick,
|
|
@@ -15578,6 +16164,7 @@ export {
|
|
|
15578
16164
|
useDraggable,
|
|
15579
16165
|
useDropThrough,
|
|
15580
16166
|
useDroppable,
|
|
16167
|
+
useEditorState,
|
|
15581
16168
|
useEntity,
|
|
15582
16169
|
useEvent,
|
|
15583
16170
|
useEvents,
|