@underpostnet/cyberia 3.3.73 → 3.3.76
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/.env.example +17 -5
- package/.github/workflows/coverall.cyberia.ci.yml +5 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-server.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +1 -1
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +1 -1
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +1 -1
- package/.github/workflows/publish.cyberia.ci.yml +44 -0
- package/AGENTS.md +61 -12
- package/CHANGELOG.md +126 -41
- package/CLI-HELP.md +19 -12
- package/Dockerfile +1 -1
- package/Dockerfile.dev +1 -1
- package/Dockerfile.test +2 -2
- package/README.md +28 -28
- package/bin/build.js +37 -17
- package/bin/cyberia.js +1247 -1373
- package/bin/index.js +1247 -1373
- package/compose.env +17 -5
- package/conf.js +7 -3
- package/deploy/cyberia-client/deploy.sh +10 -11
- package/deploy/cyberia-client/package.sh +0 -1
- package/deploy/cyberia-client/state.sh +3 -2
- package/deploy/cyberia-server/deploy.sh +10 -11
- package/deploy/cyberia-server/package.sh +0 -1
- package/deploy/cyberia-server/state.sh +3 -2
- package/deploy/dd-cyberia/deploy.sh +5 -5
- package/deploy/dd-cyberia/init.sh +15 -14
- package/deploy/dd-cyberia/package.sh +0 -1
- package/deploy/dd-cyberia/state.sh +2 -2
- package/deploy/dd-cyberia/sync-deploy.sh +139 -75
- package/deploy/lib/config.sh +29 -0
- package/deploy/lib/github-actions-logging.sh +92 -76
- package/deploy/lib/host.sh +27 -18
- package/deploy/lib/state.sh +4 -1
- package/deploy/pwa-microservices-template/deploy.sh +10 -8
- package/deploy/release/deploy.sh +0 -2
- package/deployment.yaml +1 -1
- package/docker-compose.yml +23 -17
- package/hardhat/package-lock.json +2 -2
- package/hardhat/package.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/mongo-express/deployment.yaml +46 -27
- package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
- package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
- package/manifests/deployment/mongo-express/service.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
- package/package.json +19 -17
- package/scripts/test-monitor.sh +3 -3
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +14 -9
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +88 -184
- package/src/api/cyberia-action/cyberia-action.router.js +2 -2
- package/src/api/cyberia-action/cyberia-action.service.js +3 -4
- package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
- package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
- package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
- package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -3
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +12 -34
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +15 -32
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +1 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +16 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +466 -3
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +87 -51
- package/src/api/cyberia-instance/cyberia-fallback-world.js +21 -40
- package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
- package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +34 -141
- package/src/api/cyberia-instance/cyberia-instance.controller.js +1 -4
- package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
- package/src/api/cyberia-instance/cyberia-instance.router.js +3 -16
- package/src/api/cyberia-instance/cyberia-instance.service.js +3 -43
- package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +74 -1
- package/src/api/cyberia-map/cyberia-map.service.js +6 -2
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +3 -3
- package/src/api/cyberia-quest/cyberia-quest.service.js +3 -3
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -188
- package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
- package/src/api/file/file.ref.js +153 -0
- package/src/api/file/file.ref.json +11 -2
- package/src/api/object-layer/object-layer.model.js +47 -12
- package/src/api/object-layer/object-layer.router.js +10 -3
- package/src/api/object-layer/object-layer.service.js +113 -120
- package/src/cli/app.js +12 -1
- package/src/cli/client.js +2 -2
- package/src/cli/cluster.js +7 -0
- package/src/cli/deploy.js +4 -4
- package/src/cli/docker-compose.js +1 -1
- package/src/cli/fs-selection.js +115 -0
- package/src/cli/fs.js +158 -342
- package/src/cli/index.js +22 -10
- package/src/cli/repository.js +28 -0
- package/src/cli/run.js +71 -197
- package/src/cli/test.js +4 -0
- package/src/cli/wireguard.js +32 -31
- package/src/client/components/core/Docs.js +77 -100
- package/src/client/components/core/Modal.js +56 -1
- package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
- package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
- package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
- package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
- package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
- package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +0 -34
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +280 -24
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
- package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
- package/src/client/public/cyberia-docs/CYBERIA.md +28 -28
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
- package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
- package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
- package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
- package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
- package/src/client/services/object-layer/object-layer.management.js +6 -10
- package/src/client/services/object-layer/object-layer.service.js +3 -1
- package/src/client-builder/client-build-docs.js +52 -52
- package/src/client-builder/client-build.js +67 -44
- package/src/client-builder/client-bundle.js +347 -0
- package/src/db/mongo/MongoExpress.js +187 -0
- package/src/grpc/cyberia/grpc-server.js +5 -7
- package/src/index.js +1 -1
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +143 -146
- package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
- package/src/projects/cyberia/besu-genesis-generator.js +5 -14
- package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
- package/src/projects/cyberia/catalog-cyberia.js +3 -2
- package/src/projects/cyberia/gemini-client.js +3 -3
- package/src/projects/cyberia/generate-saga.js +4 -11
- package/src/projects/cyberia/hot-reload-trigger.js +17 -28
- package/src/projects/cyberia/instance-backup.js +210 -0
- package/src/projects/cyberia/instance-data.js +177 -257
- package/src/projects/cyberia/map-preview-generator.js +32 -68
- package/src/projects/cyberia/object-layer.js +152 -319
- package/src/projects/cyberia/seed-audio.js +139 -0
- package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
- package/src/projects/cyberia/semantic-layer-generator.js +2 -18
- package/src/projects/cyberia/stat-balance.js +81 -0
- package/src/projects/cyberia/stat-commands.js +23 -0
- package/src/projects/cyberia/stat-contract-generator.js +101 -0
- package/src/runtime/cyberia-client/Dockerfile +8 -4
- package/src/runtime/cyberia-client/Dockerfile.dev +5 -2
- package/src/runtime/cyberia-server/Dockerfile +9 -2
- package/src/runtime/cyberia-server/Dockerfile.dev +8 -1
- package/src/runtime/engine-cyberia/Dockerfile +1 -1
- package/src/runtime/engine-cyberia/Dockerfile.dev +1 -1
- package/src/runtime/engine-cyberia/Dockerfile.test +2 -2
- package/src/runtime/engine-cyberia/compose.env +17 -5
- package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
- package/src/server/build/coverage.js +113 -42
- package/src/server/build/package.js +55 -12
- package/src/server/build/testing.js +59 -9
- package/src/server/network/middlewares.js +8 -2
- package/src/server/ops/logger.js +70 -35
- package/src/server/runtime/conf.js +4 -2
- package/src/server/storage/data-query.js +16 -0
- package/src/server/storage/downloader.js +62 -14
- package/src/server/storage/zip.js +153 -0
- package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
- package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
- package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +34 -0
- package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
- package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
- package/test/integration/app/cyberia/cyberia-instance-conf-defaults.test.js +16 -22
- package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
- package/test/integration/app/cyberia/cyberia-load.test.js +6 -7
- package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
- package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
- package/test/integration/app/cyberia/fallback-world-capture.test.js +87 -2
- package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
- package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
- package/test/integration/app/cyberia/seed-audio.test.js +275 -0
- package/test/integration/infra/2-network/wireguard-cli.test.js +33 -9
- package/test/integration/infra/2-network/wireguard-edge.test.js +58 -18
- package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
- package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
- package/test/unit/client-build-docs.test.js +97 -70
- package/test/unit/client-bundle.test.js +313 -0
- package/test/unit/conf-resolution.test.js +17 -0
- package/test/unit/coverage-artifact.test.js +120 -29
- package/test/unit/cyberia/instance-backup.test.js +183 -0
- package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
- package/test/unit/cyberia/publish-workflow.test.js +22 -0
- package/test/unit/cyberia/stat-balance.test.js +69 -0
- package/test/unit/deploy-log-table.test.js +76 -5
- package/test/unit/downloader-integrity.test.js +98 -0
- package/test/unit/file-reference-registry.test.js +141 -0
- package/test/unit/fs-storage-paths.test.js +596 -0
- package/test/unit/logger-redaction.test.js +29 -0
- package/test/unit/package.test.js +70 -16
- package/test/unit/prepare-host.test.js +84 -1
- package/test/unit/test-tiers.test.js +27 -0
- package/test/unit/zip-archive.test.js +142 -0
- package/vitest.config.js +11 -3
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
|
@@ -9,142 +9,19 @@ import { DropDown } from '../core/DropDown.js';
|
|
|
9
9
|
import { CyberiaInstanceManagement } from '../../services/cyberia-instance/cyberia-instance.management.js';
|
|
10
10
|
import { CyberiaInstanceService } from '../../services/cyberia-instance/cyberia-instance.service.js';
|
|
11
11
|
import { CyberiaInstanceConfService } from '../../services/cyberia-instance-conf/cyberia-instance-conf.service.js';
|
|
12
|
+
import { CyberiaEntityTypeDefaultService } from '../../services/cyberia-entity-type-default/cyberia-entity-type-default.service.js';
|
|
12
13
|
import { CyberiaMapService } from '../../services/cyberia-map/cyberia-map.service.js';
|
|
13
14
|
import { FileService } from '../../services/file/file.service.js';
|
|
14
15
|
import { DefaultManagement } from '../../services/default/default.management.js';
|
|
15
16
|
import { getApiBaseUrl } from '../../services/core/core.service.js';
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
const dropdownValueKey = (value = '') => String(value).trim().replaceAll(' ', '-');
|
|
19
|
-
const createDropdownOption = (value, onClick = () => {}, display = value, data = value) => ({
|
|
20
|
-
value,
|
|
21
|
-
display,
|
|
22
|
-
data,
|
|
23
|
-
onClick,
|
|
24
|
-
});
|
|
17
|
+
import { getQueryParams, listenQueryParamsChange, setQueryParams } from '../core/Router.js';
|
|
25
18
|
|
|
26
19
|
class InstanceEngineCyberia {
|
|
27
20
|
static currentInstanceId = null;
|
|
21
|
+
static currentInstanceCode = null;
|
|
28
22
|
static currentThumbnailId = null;
|
|
29
23
|
static thumbnailDirty = false;
|
|
30
24
|
static portals = [];
|
|
31
|
-
static itemIdsDropdownId = 'instance-engine-item-ids-dropdown';
|
|
32
|
-
static itemInventoryListId = 'instance-engine-item-inventory-list';
|
|
33
|
-
// itemId → defaultPlayerInventory flag for the currently selected item ids.
|
|
34
|
-
static itemInventoryFlags = {};
|
|
35
|
-
|
|
36
|
-
// Current selection, read from the dropdown's `oncheckvalues` (always live —
|
|
37
|
-
// it is updated before `_renderSelectedBadges` runs, unlike `.value` which
|
|
38
|
-
// lags by one in the option-click path).
|
|
39
|
-
static getSelectedItemIds() {
|
|
40
|
-
const token = DropDown.Tokens[InstanceEngineCyberia.itemIdsDropdownId];
|
|
41
|
-
if (!token) return [];
|
|
42
|
-
const fromChecks = Object.values(token.oncheckvalues || {})
|
|
43
|
-
.map((v) => v.data)
|
|
44
|
-
.filter(Boolean);
|
|
45
|
-
if (fromChecks.length > 0) return fromChecks;
|
|
46
|
-
return Array.isArray(token.value) ? token.value.filter(Boolean) : [];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Render the per-item "Default Player Inventory" toggles for every selected
|
|
50
|
-
// item id. Kept in sync with the dropdown via a MutationObserver on its badge
|
|
51
|
-
// container (see render()).
|
|
52
|
-
static renderItemInventoryList(containerId = InstanceEngineCyberia.itemInventoryListId) {
|
|
53
|
-
const container = s(`.${containerId}`);
|
|
54
|
-
if (!container) return;
|
|
55
|
-
|
|
56
|
-
const selected = InstanceEngineCyberia.getSelectedItemIds();
|
|
57
|
-
|
|
58
|
-
// Drop flags for items no longer selected so the payload never carries them.
|
|
59
|
-
for (const key of Object.keys(InstanceEngineCyberia.itemInventoryFlags)) {
|
|
60
|
-
if (!selected.includes(key)) delete InstanceEngineCyberia.itemInventoryFlags[key];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (selected.length === 0) {
|
|
64
|
-
htmls(`.${containerId}`, html`<div style="color:#888;font-size:12px;">No item IDs selected.</div>`);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
let listHtml = '';
|
|
69
|
-
for (const itemId of selected) {
|
|
70
|
-
const checked = InstanceEngineCyberia.itemInventoryFlags[itemId] ? 'checked' : '';
|
|
71
|
-
listHtml += html`<div class="fl" style="border-bottom:1px solid #444;padding:4px 0;align-items:center;">
|
|
72
|
-
<div class="in fll" style="flex:1;font-size:12px;font-family:monospace;">${itemId}</div>
|
|
73
|
-
<div class="in fll" style="display:flex;align-items:center;justify-content:flex-end;">
|
|
74
|
-
<label style="font-size:11px;cursor:pointer;display:flex;align-items:center;gap:5px;">
|
|
75
|
-
<input
|
|
76
|
-
type="checkbox"
|
|
77
|
-
class="instance-engine-item-inv-checkbox"
|
|
78
|
-
data-item-id="${itemId}"
|
|
79
|
-
${checked}
|
|
80
|
-
style="cursor:pointer;"
|
|
81
|
-
/>
|
|
82
|
-
Default Player Inventory
|
|
83
|
-
</label>
|
|
84
|
-
</div>
|
|
85
|
-
</div>`;
|
|
86
|
-
}
|
|
87
|
-
htmls(`.${containerId}`, listHtml);
|
|
88
|
-
|
|
89
|
-
container.querySelectorAll('.instance-engine-item-inv-checkbox').forEach((cb) => {
|
|
90
|
-
cb.onchange = () => {
|
|
91
|
-
InstanceEngineCyberia.itemInventoryFlags[cb.dataset.itemId] = cb.checked;
|
|
92
|
-
};
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
static syncItemIdsDropdownSelection(itemIds = []) {
|
|
97
|
-
const dropdownId = InstanceEngineCyberia.itemIdsDropdownId;
|
|
98
|
-
if (!DropDown.Tokens[dropdownId]) return;
|
|
99
|
-
|
|
100
|
-
// Accept both the new [{ id, defaultPlayerInventory }] shape and the legacy
|
|
101
|
-
// string[] shape so older instance docs keep loading.
|
|
102
|
-
const normalized = (itemIds || [])
|
|
103
|
-
.map((entry) => (typeof entry === 'string' ? { id: entry, defaultPlayerInventory: false } : entry))
|
|
104
|
-
.filter((entry) => entry && entry.id);
|
|
105
|
-
|
|
106
|
-
DropDown.Tokens[dropdownId].value = [];
|
|
107
|
-
if (s(`.${dropdownId}`)) s(`.${dropdownId}`).value = [];
|
|
108
|
-
DropDown.Tokens[dropdownId].oncheckvalues = {};
|
|
109
|
-
htmls(`.dropdown-current-${dropdownId}`, '');
|
|
110
|
-
htmls(`.${dropdownId}-render-container`, '');
|
|
111
|
-
|
|
112
|
-
InstanceEngineCyberia.itemInventoryFlags = {};
|
|
113
|
-
const ids = [];
|
|
114
|
-
for (const entry of normalized) {
|
|
115
|
-
const key = dropdownValueKey(entry.id);
|
|
116
|
-
DropDown.Tokens[dropdownId].oncheckvalues[key] = {
|
|
117
|
-
data: entry.id,
|
|
118
|
-
display: entry.id,
|
|
119
|
-
value: entry.id,
|
|
120
|
-
};
|
|
121
|
-
InstanceEngineCyberia.itemInventoryFlags[entry.id] = !!entry.defaultPlayerInventory;
|
|
122
|
-
ids.push(entry.id);
|
|
123
|
-
}
|
|
124
|
-
DropDown.Tokens[dropdownId].value = [...ids];
|
|
125
|
-
if (s(`.${dropdownId}`)) s(`.${dropdownId}`).value = [...ids];
|
|
126
|
-
DropDown.Tokens[dropdownId]._renderSelectedBadges?.();
|
|
127
|
-
InstanceEngineCyberia.renderItemInventoryList();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
static async buildItemIdsDropdown() {
|
|
131
|
-
return await DropDown.instance({
|
|
132
|
-
id: InstanceEngineCyberia.itemIdsDropdownId,
|
|
133
|
-
label: html`Object Layer Item IDs`,
|
|
134
|
-
data: [],
|
|
135
|
-
type: 'checkbox',
|
|
136
|
-
containerClass: 'inl',
|
|
137
|
-
excludeSelected: true,
|
|
138
|
-
serviceProvider: async (q) => {
|
|
139
|
-
const result = await ObjectLayerService.searchItemIds({ q });
|
|
140
|
-
if (result.status === 'success' && result.data?.itemIds) {
|
|
141
|
-
return result.data.itemIds.map((itemId) => createDropdownOption(itemId));
|
|
142
|
-
}
|
|
143
|
-
return [];
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
|
|
148
25
|
static renderPortalList(containerId) {
|
|
149
26
|
const container = s(`.${containerId}`);
|
|
150
27
|
if (!container) return;
|
|
@@ -237,7 +114,6 @@ class InstanceEngineCyberia {
|
|
|
237
114
|
const idHotReloadUrl = 'instance-engine-input-hot-reload-url';
|
|
238
115
|
const idThumbnail = 'instance-engine-input-thumbnail';
|
|
239
116
|
const idMapCodesDropdown = 'instance-engine-map-codes-dropdown';
|
|
240
|
-
const idItemIdsDropdown = InstanceEngineCyberia.itemIdsDropdownId;
|
|
241
117
|
const managementId = 'modal-cyberia-instance-engine';
|
|
242
118
|
const portalListId = 'instance-engine-portal-list';
|
|
243
119
|
const idSourceMapCode = 'instance-engine-source-map-code';
|
|
@@ -255,6 +131,7 @@ class InstanceEngineCyberia {
|
|
|
255
131
|
const idAoiRadius = 'instance-engine-aoi-radius';
|
|
256
132
|
|
|
257
133
|
InstanceEngineCyberia.currentInstanceId = null;
|
|
134
|
+
InstanceEngineCyberia.currentInstanceCode = null;
|
|
258
135
|
InstanceEngineCyberia.currentThumbnailId = null;
|
|
259
136
|
InstanceEngineCyberia.thumbnailDirty = false;
|
|
260
137
|
InstanceEngineCyberia.portals = [];
|
|
@@ -268,10 +145,6 @@ class InstanceEngineCyberia {
|
|
|
268
145
|
const cyberiaMapCodes = DropDown.Tokens[idMapCodesDropdown]?.value
|
|
269
146
|
? [...DropDown.Tokens[idMapCodesDropdown].value]
|
|
270
147
|
: [];
|
|
271
|
-
const itemIds = InstanceEngineCyberia.getSelectedItemIds().map((id) => ({
|
|
272
|
-
id,
|
|
273
|
-
defaultPlayerInventory: !!InstanceEngineCyberia.itemInventoryFlags[id],
|
|
274
|
-
}));
|
|
275
148
|
const payload = {
|
|
276
149
|
code: s(`.${idCode}`)?.value || '',
|
|
277
150
|
name: s(`.${idName}`)?.value || '',
|
|
@@ -279,7 +152,6 @@ class InstanceEngineCyberia {
|
|
|
279
152
|
tags,
|
|
280
153
|
status: DropDown.Tokens[idStatus]?.value || 'unlisted',
|
|
281
154
|
cyberiaMapCodes,
|
|
282
|
-
itemIds,
|
|
283
155
|
portals: InstanceEngineCyberia.portals,
|
|
284
156
|
playerSpawn: {
|
|
285
157
|
sourceMapCode: s(`.${idSpawnMapCode}`)?.value?.trim() || '',
|
|
@@ -358,6 +230,9 @@ class InstanceEngineCyberia {
|
|
|
358
230
|
}
|
|
359
231
|
if (result.status === 'success') {
|
|
360
232
|
if (result.data?._id) InstanceEngineCyberia.currentInstanceId = result.data._id;
|
|
233
|
+
// A newly saved instance becomes the one the URL points at.
|
|
234
|
+
InstanceEngineCyberia.currentInstanceCode = body.code || null;
|
|
235
|
+
setQueryParams({ instanceCode: body.code || null }, { replace: true });
|
|
361
236
|
// The conf is auto-upserted on instance save; persist the AOI radius onto
|
|
362
237
|
// it now that we know the instance code resolves to a conf document.
|
|
363
238
|
await persistAoiRadius(body.code);
|
|
@@ -372,6 +247,8 @@ class InstanceEngineCyberia {
|
|
|
372
247
|
|
|
373
248
|
const loadInstance = async (instanceData) => {
|
|
374
249
|
InstanceEngineCyberia.currentInstanceId = instanceData._id || null;
|
|
250
|
+
InstanceEngineCyberia.currentInstanceCode = instanceData.code || null;
|
|
251
|
+
setQueryParams({ instanceCode: instanceData.code || null }, { replace: true });
|
|
375
252
|
if (s(`.${idCode}`)) s(`.${idCode}`).value = instanceData.code || '';
|
|
376
253
|
if (s(`.${idName}`)) s(`.${idName}`).value = instanceData.name || '';
|
|
377
254
|
if (s(`.${idDescription}`)) s(`.${idDescription}`).value = instanceData.description || '';
|
|
@@ -450,7 +327,6 @@ class InstanceEngineCyberia {
|
|
|
450
327
|
}
|
|
451
328
|
}
|
|
452
329
|
|
|
453
|
-
InstanceEngineCyberia.syncItemIdsDropdownSelection(instanceData.itemIds || instanceData.itemsId || []);
|
|
454
330
|
|
|
455
331
|
// Load portals
|
|
456
332
|
InstanceEngineCyberia.portals = (instanceData.portals || []).map((p) => ({
|
|
@@ -478,6 +354,8 @@ class InstanceEngineCyberia {
|
|
|
478
354
|
|
|
479
355
|
const resetForm = () => {
|
|
480
356
|
InstanceEngineCyberia.currentInstanceId = null;
|
|
357
|
+
InstanceEngineCyberia.currentInstanceCode = null;
|
|
358
|
+
setQueryParams({ instanceCode: null }, { replace: true });
|
|
481
359
|
InstanceEngineCyberia.currentThumbnailId = null;
|
|
482
360
|
InstanceEngineCyberia.thumbnailDirty = false;
|
|
483
361
|
if (s(`.${idCode}`)) s(`.${idCode}`).value = '';
|
|
@@ -502,14 +380,6 @@ class InstanceEngineCyberia {
|
|
|
502
380
|
htmls(`.dropdown-current-${idMapCodesDropdown}`, '');
|
|
503
381
|
htmls(`.${idMapCodesDropdown}-render-container`, '');
|
|
504
382
|
}
|
|
505
|
-
if (DropDown.Tokens[idItemIdsDropdown]) {
|
|
506
|
-
DropDown.Tokens[idItemIdsDropdown].oncheckvalues = {};
|
|
507
|
-
DropDown.Tokens[idItemIdsDropdown].value = [];
|
|
508
|
-
htmls(`.dropdown-current-${idItemIdsDropdown}`, '');
|
|
509
|
-
htmls(`.${idItemIdsDropdown}-render-container`, '');
|
|
510
|
-
}
|
|
511
|
-
InstanceEngineCyberia.itemInventoryFlags = {};
|
|
512
|
-
InstanceEngineCyberia.renderItemInventoryList();
|
|
513
383
|
InstanceEngineCyberia.portals = [];
|
|
514
384
|
InstanceEngineCyberia.renderPortalList(portalListId);
|
|
515
385
|
if (s(`.${idSpawnMapCode}`)) s(`.${idSpawnMapCode}`).value = '';
|
|
@@ -519,9 +389,32 @@ class InstanceEngineCyberia {
|
|
|
519
389
|
if (s(`.${idAoiRadius}`)) s(`.${idAoiRadius}`).value = '';
|
|
520
390
|
};
|
|
521
391
|
|
|
522
|
-
|
|
392
|
+
// ?instanceCode=<code> loads that instance into the form on arrival.
|
|
393
|
+
const loadInstanceByCode = async (code) => {
|
|
394
|
+
if (!code || code === InstanceEngineCyberia.currentInstanceCode) return;
|
|
395
|
+
const { status, data } = await CyberiaInstanceService.get({ id: code });
|
|
396
|
+
if (status !== 'success' || !data?._id) {
|
|
397
|
+
NotificationManager.Push({ html: `No instance answers to the code "${code}"`, status: 'error' });
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
await loadInstance(data);
|
|
401
|
+
NotificationManager.Push({ html: `Instance "${data.name || data.code}" loaded`, status: 'success' });
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
listenQueryParamsChange({
|
|
405
|
+
id: 'cyberia-instance-engine-query-listener',
|
|
406
|
+
event: async (queryParams) => {
|
|
407
|
+
if (!s(`.${idCode}`)) return;
|
|
408
|
+
const code = queryParams.instanceCode || null;
|
|
409
|
+
if (code) await loadInstanceByCode(code);
|
|
410
|
+
else if (InstanceEngineCyberia.currentInstanceCode) resetForm();
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
setTimeout(async () => {
|
|
523
415
|
if (s(`.btn-instance-engine-save`)) s(`.btn-instance-engine-save`).onclick = () => saveInstance();
|
|
524
416
|
if (s(`.btn-instance-engine-new`)) s(`.btn-instance-engine-new`).onclick = () => resetForm();
|
|
417
|
+
await loadInstanceByCode(getQueryParams().instanceCode);
|
|
525
418
|
|
|
526
419
|
if (s(`.btn-instance-engine-toggle-thumbnail`))
|
|
527
420
|
s(`.btn-instance-engine-toggle-thumbnail`).onclick = () => {
|
|
@@ -595,6 +488,87 @@ class InstanceEngineCyberia {
|
|
|
595
488
|
}
|
|
596
489
|
};
|
|
597
490
|
|
|
491
|
+
// Syncs against what is on screen: the instance is persisted first so the conf and the map
|
|
492
|
+
// selection agree, then the server matches defaults to the entities those maps place.
|
|
493
|
+
if (s(`.btn-instance-engine-sync-entities`))
|
|
494
|
+
s(`.btn-instance-engine-sync-entities`).onclick = async () => {
|
|
495
|
+
const btn = s(`.btn-instance-engine-sync-entities`);
|
|
496
|
+
const status = s(`.instance-engine-sync-entities-status`);
|
|
497
|
+
const code = s(`.${idCode}`)?.value?.trim();
|
|
498
|
+
if (!code) {
|
|
499
|
+
NotificationManager.Push({ html: 'Instance code is required to sync.', status: 'error' });
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (btn) btn.disabled = true;
|
|
503
|
+
if (status) htmls(`.instance-engine-sync-entities-status`, 'Syncing…');
|
|
504
|
+
try {
|
|
505
|
+
const persisted = await persistInstance({ notify: false });
|
|
506
|
+
if (persisted?.status !== 'success') {
|
|
507
|
+
NotificationManager.Push({ html: persisted?.message || 'Could not save the instance.', status: 'error' });
|
|
508
|
+
if (status) htmls(`.instance-engine-sync-entities-status`, '');
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const mapCodes = DropDown.Tokens[idMapCodesDropdown]?.value
|
|
512
|
+
? [...DropDown.Tokens[idMapCodesDropdown].value]
|
|
513
|
+
: [];
|
|
514
|
+
const result = await CyberiaEntityTypeDefaultService.syncInstance({
|
|
515
|
+
instanceCode: code,
|
|
516
|
+
body: { mapCodes },
|
|
517
|
+
});
|
|
518
|
+
if (result.status === 'error') {
|
|
519
|
+
NotificationManager.Push({ html: result.message, status: 'error' });
|
|
520
|
+
if (status) htmls(`.instance-engine-sync-entities-status`, '');
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
const {
|
|
524
|
+
linked = [],
|
|
525
|
+
skipped = [],
|
|
526
|
+
dropped = [],
|
|
527
|
+
entityDefaults = [],
|
|
528
|
+
skills = [],
|
|
529
|
+
entitiesUpdated = [],
|
|
530
|
+
conflicts = [],
|
|
531
|
+
duplicates = [],
|
|
532
|
+
} = result.data || {};
|
|
533
|
+
const placedRewritten = entitiesUpdated.reduce((sum, { entities }) => sum + entities, 0);
|
|
534
|
+
if (status) {
|
|
535
|
+
htmls(
|
|
536
|
+
`.instance-engine-sync-entities-status`,
|
|
537
|
+
html`${entityDefaults.length} reference${1 === entityDefaults.length ? '' : 's'}${linked.length
|
|
538
|
+
? ` · linked ${linked.length}`
|
|
539
|
+
: ''}${dropped.length ? ` · dropped ${dropped.length}` : ''}${skills.length
|
|
540
|
+
? ` · ${skills.length} skill${1 === skills.length ? '' : 's'}`
|
|
541
|
+
: ''}${placedRewritten
|
|
542
|
+
? ` · placed ${placedRewritten}`
|
|
543
|
+
: ''}${skipped.length
|
|
544
|
+
? html`<div style="margin-top:3px;color:#c90;">
|
|
545
|
+
${skipped.length} match${1 === skipped.length ? '' : 'es'} already referenced by another
|
|
546
|
+
instance — link deliberately in the Entity engine, or clone it there.
|
|
547
|
+
</div>`
|
|
548
|
+
: ''}${conflicts.length
|
|
549
|
+
? html`<div style="margin-top:3px;color:#c90;">
|
|
550
|
+
${conflicts.length} match${1 === conflicts.length ? '' : 'es'} not linked: this instance already
|
|
551
|
+
references a default for the same entity type and live items. Link it in the Entity engine only
|
|
552
|
+
if you mean to replace the one it has.
|
|
553
|
+
</div>`
|
|
554
|
+
: ''}${duplicates.length
|
|
555
|
+
? html`<div style="margin-top:3px;color:#c90;">
|
|
556
|
+
${duplicates.length} reference${1 === duplicates.length ? '' : 's'} answer for a build another
|
|
557
|
+
reference already covers — which one applies depends on list order. Unlink or delete the
|
|
558
|
+
redundant record in the Entity engine.
|
|
559
|
+
</div>`
|
|
560
|
+
: ''}`,
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
NotificationManager.Push({
|
|
564
|
+
html: `Entity type defaults synced — ${entityDefaults.length} referenced`,
|
|
565
|
+
status: 'success',
|
|
566
|
+
});
|
|
567
|
+
} finally {
|
|
568
|
+
if (btn) btn.disabled = false;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
|
|
598
572
|
if (s(`.btn-instance-engine-hot-reload`))
|
|
599
573
|
s(`.btn-instance-engine-hot-reload`).onclick = () => triggerHotReload('full');
|
|
600
574
|
if (s(`.btn-instance-engine-hot-reload-incremental`))
|
|
@@ -695,19 +669,6 @@ class InstanceEngineCyberia {
|
|
|
695
669
|
InstanceEngineCyberia.renderPortalList(portalListId);
|
|
696
670
|
};
|
|
697
671
|
|
|
698
|
-
// Keep the per-item "Default Player Inventory" toggles in sync with the
|
|
699
|
-
// item-ids dropdown. Every add/remove/clear re-renders the dropdown badge
|
|
700
|
-
// container, so observing it is a reliable change hook (the dropdown
|
|
701
|
-
// exposes no onChange callback).
|
|
702
|
-
const itemBadgeContainer = s(`.dropdown-current-${idItemIdsDropdown}`);
|
|
703
|
-
if (itemBadgeContainer) {
|
|
704
|
-
const itemInventoryObserver = new MutationObserver(() => {
|
|
705
|
-
InstanceEngineCyberia.renderItemInventoryList();
|
|
706
|
-
});
|
|
707
|
-
itemInventoryObserver.observe(itemBadgeContainer, { childList: true, subtree: true });
|
|
708
|
-
}
|
|
709
|
-
InstanceEngineCyberia.renderItemInventoryList();
|
|
710
|
-
|
|
711
672
|
ThemeEvents['instance-engine-theme'] = () => {
|
|
712
673
|
InstanceEngineCyberia.renderPortalList(portalListId);
|
|
713
674
|
};
|
|
@@ -858,11 +819,6 @@ class InstanceEngineCyberia {
|
|
|
858
819
|
},
|
|
859
820
|
})}
|
|
860
821
|
</div>
|
|
861
|
-
<div class="in section-mp" style="margin-top: 10px;">${await InstanceEngineCyberia.buildItemIdsDropdown()}</div>
|
|
862
|
-
<div class="in section-mp" style="margin-top: 5px;">
|
|
863
|
-
<div class="in input-label" style="font-size:13px;margin-bottom:5px;">Default Player Inventory</div>
|
|
864
|
-
<div class="in ${InstanceEngineCyberia.itemInventoryListId}" style="max-height:200px;overflow-y:auto;"></div>
|
|
865
|
-
</div>
|
|
866
822
|
<div class="in section-mp" style="margin-top: 10px;">
|
|
867
823
|
<div class="in input-label" style="font-size:14px;margin-bottom:5px;">Portals</div>
|
|
868
824
|
${dynamicCol({ containerSelector: 'instance-engine-container', id: dcPortalSource, type: 'search-inputs' })}
|
|
@@ -1029,6 +985,19 @@ class InstanceEngineCyberia {
|
|
|
1029
985
|
</div>
|
|
1030
986
|
${canMutate
|
|
1031
987
|
? html`<div class="in section-mp" style="margin-top: 10px;">
|
|
988
|
+
<div class="in" style="color:#888;font-size:12px;margin-bottom:6px;">
|
|
989
|
+
Points this instance's conf at every entity-type default the maps selected above actually place —
|
|
990
|
+
matched the way the runtime matches them, by live item ids — and at every skill their items trigger.
|
|
991
|
+
References whose document is gone, and skills nothing carries, are dropped. Saves the instance first,
|
|
992
|
+
so the maps it syncs against are the ones on screen.
|
|
993
|
+
</div>
|
|
994
|
+
${await BtnIcon.instance({
|
|
995
|
+
class: 'wfa btn-instance-engine-sync-entities',
|
|
996
|
+
label: html`<i class="fa-solid fa-diagram-project"></i> Sync Entity Type Defaults`,
|
|
997
|
+
})}
|
|
998
|
+
<div class="in instance-engine-sync-entities-status" style="margin-top:5px;font-size:12px;"></div>
|
|
999
|
+
</div>
|
|
1000
|
+
<div class="in section-mp" style="margin-top: 10px;">
|
|
1032
1001
|
${await BtnIcon.instance({
|
|
1033
1002
|
class: 'wfa btn-instance-engine-toggle-hot-reload',
|
|
1034
1003
|
label: html`<i class="fa-solid fa-caret-right instance-engine-hot-reload-caret"></i> Hot Reload`,
|
|
@@ -162,19 +162,23 @@ const enrichWithLiveStatus = async (instances, opts) => {
|
|
|
162
162
|
// the instance catalogue, then (when `liveStatus`) overlays real Online/Busy/
|
|
163
163
|
// Full/Maintenance/Offline from each world's metrics API. Swap the whole thing
|
|
164
164
|
// via `render({ fetchInstances })` to source instances from anywhere.
|
|
165
|
+
// `limit` keeps only the first N catalogue entries *before* the live overlay so
|
|
166
|
+
// lightweight consumers (the portal landing) don't probe every world's metrics.
|
|
165
167
|
const defaultInstanceProvider = async ({
|
|
166
168
|
clientBaseUrl = DEFAULT_CLIENT_BASE_URL,
|
|
167
169
|
serverBaseUrl = DEFAULT_SERVER_BASE_URL,
|
|
168
170
|
defaultInstanceCode = DEFAULT_INSTANCE_CODE,
|
|
169
171
|
liveStatus = true,
|
|
172
|
+
limit,
|
|
170
173
|
} = {}) => {
|
|
171
174
|
const res = await CyberiaInstanceService.get({ sort: 'createdAt', order: 'asc', limit: 60, fallback: true });
|
|
172
175
|
if (!res || res.status !== 'success') throw new Error(res?.message || 'Could not load instances');
|
|
173
176
|
const raw = res.data;
|
|
174
177
|
const list = Array.isArray(raw) ? raw : Array.isArray(raw?.data) ? raw.data : [];
|
|
175
|
-
|
|
178
|
+
let instances = list
|
|
176
179
|
.filter((doc) => doc && doc.status !== 'archived')
|
|
177
180
|
.map((doc) => normalizeInstance(doc, { clientBaseUrl }));
|
|
181
|
+
if (Number.isInteger(limit) && limit > 0) instances = instances.slice(0, limit);
|
|
178
182
|
if (liveStatus && instances.length > 0) await enrichWithLiveStatus(instances, { serverBaseUrl, defaultInstanceCode });
|
|
179
183
|
return instances;
|
|
180
184
|
};
|
|
@@ -895,6 +899,8 @@ class InstanceSelectionView {
|
|
|
895
899
|
export {
|
|
896
900
|
InstanceSelectionView,
|
|
897
901
|
defaultInstanceProvider,
|
|
902
|
+
placeholderThumbnail,
|
|
903
|
+
DEFAULT_CLIENT_BASE_URL,
|
|
898
904
|
normalizeInstance,
|
|
899
905
|
resolveStatus,
|
|
900
906
|
statusFromMetrics,
|