@underpostnet/cyberia 3.3.73 → 3.3.77
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 +10 -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/engine-cyberia.ci.yml +1 -1
- package/.github/workflows/publish.cyberia.ci.yml +44 -0
- package/AGENTS.md +61 -12
- package/CHANGELOG.md +159 -161
- package/CLI-HELP.md +20 -13
- package/Dockerfile +1 -1
- package/Dockerfile.dev +1 -1
- package/Dockerfile.test +2 -2
- package/README.md +28 -28
- package/bin/build.js +96 -21
- package/bin/cyberia.js +1247 -1373
- package/bin/index.js +1247 -1373
- package/compose.env +17 -5
- package/conf.js +7 -4
- 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 +28 -19
- 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/docs/coverage/cyberia/api/cyberia-instance/cyberia-fallback-capture.js.html +1591 -0
- package/docs/coverage/cyberia/api/cyberia-instance/index.html +116 -0
- package/docs/coverage/cyberia/api/cyberia-server-defaults/cyberia-server-defaults.js.html +4138 -0
- package/docs/coverage/cyberia/api/cyberia-server-defaults/index.html +116 -0
- package/docs/coverage/cyberia/api/object-layer/index.html +116 -0
- package/docs/coverage/cyberia/api/object-layer/object-layer.model.js.html +1393 -0
- package/docs/coverage/cyberia/base.css +362 -0
- package/docs/coverage/cyberia/block-navigation.js +82 -0
- package/docs/coverage/cyberia/favicon.png +0 -0
- package/docs/coverage/cyberia/index.html +161 -0
- package/docs/coverage/cyberia/prettify.css +101 -0
- package/docs/coverage/cyberia/prettify.js +937 -0
- package/docs/coverage/cyberia/projects/cyberia/atlas-sprite-sheet-generator.js.html +1315 -0
- package/docs/coverage/cyberia/projects/cyberia/index.html +176 -0
- package/docs/coverage/cyberia/projects/cyberia/instance-backup.js.html +715 -0
- package/docs/coverage/cyberia/projects/cyberia/instance-data.js.html +2182 -0
- package/docs/coverage/cyberia/projects/cyberia/shape-generator.js.html +3265 -0
- package/docs/coverage/cyberia/projects/cyberia/stat-balance.js.html +328 -0
- package/docs/coverage/cyberia/sort-arrow-sprite.png +0 -0
- package/docs/coverage/cyberia/sorter.js +205 -0
- 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 +80 -18
- package/src/cli/deploy.js +215 -34
- 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/release.js +3 -1
- package/src/cli/repository.js +35 -9
- package/src/cli/run.js +80 -199
- package/src/cli/test.js +4 -0
- package/src/cli/wireguard.js +32 -31
- package/src/client/components/core/Badge.js +0 -1
- package/src/client/components/core/CssCore.js +8 -1
- package/src/client/components/core/Docs.js +77 -100
- package/src/client/components/core/Modal.js +77 -23
- package/src/client/components/core/ToolTip.js +15 -0
- package/src/client/components/cryptokoyn/AppShellCryptokoyn.js +0 -2
- 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/RouterCyberiaPortal.js +0 -4
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
- package/src/client/components/default/AppShellDefault.js +1 -4
- package/src/client/components/itemledger/AppShellItemledger.js +0 -2
- package/src/client/components/underpost/AppShellUnderpost.js +1 -1
- 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/ssr/views/Cyberia404.js +3 -3
- 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/network/underpost-gateway.js +113 -14
- package/src/server/ops/logger.js +70 -35
- package/src/server/runtime/conf.js +40 -9
- package/src/server/runtime/start.js +11 -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/integration/infra/4-ingress/underpost-ingress.test.js +1 -1
- package/test/unit/catalog.test.js +13 -2
- 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 +58 -7
- package/test/unit/coverage-artifact.test.js +120 -29
- package/test/unit/cyberia/instance-backup.test.js +183 -0
- package/test/unit/cyberia/instance-data.test.js +314 -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-legacy-gateway-sweep.test.js +63 -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/gateway-pod-fetch.test.js +95 -0
- package/test/unit/letsencrypt-issuer.test.js +101 -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/release-bump.test.js +3 -1
- package/test/unit/start-options.test.js +12 -0
- 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
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
* Instance Map service — strategic-graph REST payloads for the client's
|
|
3
|
-
* expanded Instance Map modal.
|
|
4
|
-
*
|
|
5
|
-
* Serves two lightweight views of an instance, decoupled from the gameplay
|
|
6
|
-
* AOI stream:
|
|
7
|
-
* static — graph topology plus authored map-cell presence, capability
|
|
8
|
-
* membership, and baseline stats for living presence (bots and
|
|
9
|
-
* resources; portals carry none). Fetched once when the modal
|
|
10
|
-
* opens.
|
|
11
|
-
* dynamic — per-player capability activity. Polled while the modal is open.
|
|
12
|
-
*
|
|
13
|
-
* Live player position is intentionally absent: engine-cyberia holds no
|
|
14
|
-
* real-time simulation state (see cyberia-docs/ARCHITECTURE.md). The client
|
|
15
|
-
* overlays its own predicted position on the graph.
|
|
16
|
-
*
|
|
17
|
-
* @module src/api/cyberia-instance/cyberia-instance-map.service.js
|
|
18
|
-
*/
|
|
1
|
+
// The instance map serves authored topology and capabilities. AOI owns live stats.
|
|
19
2
|
|
|
3
|
+
import { CyberiaEntityTypeDefaultService } from '../cyberia-entity-type-default/cyberia-entity-type-default.service.js';
|
|
20
4
|
import { DataBaseProviderService } from '../../db/DataBaseProvider.js';
|
|
21
5
|
import { generateFallbackWorld } from './cyberia-fallback-world.js';
|
|
22
6
|
import {
|
|
@@ -27,10 +11,10 @@ import {
|
|
|
27
11
|
import { FileFactory } from '../file/file.service.js';
|
|
28
12
|
import { loggerFactory } from '../../server/ops/logger.js';
|
|
29
13
|
import {
|
|
30
|
-
CYBERIA_INSTANCE_CONF_DEFAULTS,
|
|
31
14
|
DefaultCyberiaActions,
|
|
32
15
|
DefaultCyberiaQuests,
|
|
33
16
|
ENTITY_TYPE_DEFAULTS,
|
|
17
|
+
resolveEntityDefaultBuild,
|
|
34
18
|
} from '../cyberia-server-defaults/cyberia-server-defaults.js';
|
|
35
19
|
import { DefaultCyberiaItems } from '../../client/components/cyberia/SharedDefaultsCyberia.js';
|
|
36
20
|
|
|
@@ -78,9 +62,6 @@ const entityPresenceStatus = (entity, objectLayerMetadata, behavior) => {
|
|
|
78
62
|
}
|
|
79
63
|
};
|
|
80
64
|
|
|
81
|
-
// Behaviors whose entities never carry the sum-stats readout (mission/action
|
|
82
|
-
// givers and fully static NPCs — mirrors the Go server's behavior semantics).
|
|
83
|
-
const STATLESS_BEHAVIORS = new Set(['provider', 'provider-static', 'static']);
|
|
84
65
|
|
|
85
66
|
const mergeEntityDefaults = (entityDefaults = []) => {
|
|
86
67
|
const merged = entityDefaults.map((entityDefault) => ({
|
|
@@ -101,33 +82,10 @@ const mergeEntityDefaults = (entityDefaults = []) => {
|
|
|
101
82
|
return merged;
|
|
102
83
|
};
|
|
103
84
|
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
let firstTypeDefault;
|
|
109
|
-
let matchedDefault;
|
|
110
|
-
let matchedSize = 0;
|
|
111
|
-
|
|
112
|
-
for (const entityDefault of entityDefaults) {
|
|
113
|
-
if (entityDefault.entityType !== entity.entityType) continue;
|
|
114
|
-
if (!firstTypeDefault) firstTypeDefault = entityDefault;
|
|
115
|
-
const liveItemIds = entityDefault.liveItemIds || [];
|
|
116
|
-
if (0 === itemIds.size || 0 === liveItemIds.length) continue;
|
|
117
|
-
if (!liveItemIds.every((itemId) => itemIds.has(itemId))) continue;
|
|
118
|
-
if (liveItemIds.length > matchedSize) {
|
|
119
|
-
matchedDefault = entityDefault;
|
|
120
|
-
matchedSize = liveItemIds.length;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return (matchedDefault || firstTypeDefault)?.behavior || '';
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const objectLayerStatsSum = (itemIds, objectLayerMetadata, sumStatsLimit) =>
|
|
127
|
-
Math.min(
|
|
128
|
-
(itemIds || []).reduce((sum, itemId) => sum + (objectLayerMetadata[itemId]?.statsSum || 0), 0),
|
|
129
|
-
sumStatsLimit,
|
|
130
|
-
);
|
|
85
|
+
// One resolution rule for the whole platform — see resolveEntityDefaultBuild.
|
|
86
|
+
const entityBehavior = (entity, entityDefaults) =>
|
|
87
|
+
resolveEntityDefaultBuild({ entityType: entity.entityType, itemIds: entity.objectLayerItemIds }, entityDefaults)
|
|
88
|
+
?.behavior || '';
|
|
131
89
|
|
|
132
90
|
const resolveObjectLayerMetadata = async (itemIds, options) => {
|
|
133
91
|
if (!itemIds.length) return {};
|
|
@@ -139,49 +97,28 @@ const resolveObjectLayerMetadata = async (itemIds, options) => {
|
|
|
139
97
|
return {};
|
|
140
98
|
}
|
|
141
99
|
const objectLayers = await ObjectLayer.find({ 'data.item.id': { $in: itemIds } })
|
|
142
|
-
.select('data.item.id data.item.type
|
|
100
|
+
.select('data.item.id data.item.type')
|
|
143
101
|
.lean();
|
|
144
102
|
return Object.fromEntries(
|
|
145
103
|
objectLayers.map((layer) => [
|
|
146
104
|
layer.data.item.id,
|
|
147
105
|
{
|
|
148
|
-
statsSum: Object.values(layer.data.stats || {}).reduce((sum, value) => sum + (Number(value) || 0), 0),
|
|
149
106
|
type: layer.data.item.type,
|
|
150
107
|
},
|
|
151
108
|
]),
|
|
152
109
|
);
|
|
153
110
|
};
|
|
154
111
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
let CyberiaInstanceConf;
|
|
158
|
-
try {
|
|
159
|
-
CyberiaInstanceConf = DataBaseProviderService.getModel('CyberiaInstanceConf', options);
|
|
160
|
-
} catch {
|
|
161
|
-
return fallback;
|
|
162
|
-
}
|
|
163
|
-
const conf = await CyberiaInstanceConf.findOne({ instanceCode: instance.code }).select('sumStatsLimit').lean();
|
|
164
|
-
return Number.isFinite(conf?.sumStatsLimit) && conf.sumStatsLimit > 0 ? conf.sumStatsLimit : fallback;
|
|
165
|
-
};
|
|
166
|
-
|
|
112
|
+
// Only what this instance references: the conf names its entity-type defaults by _id, so a POI
|
|
113
|
+
// never reads behavior out of another world's wiring.
|
|
167
114
|
const resolveEntityDefaults = async (instance, options) => {
|
|
168
|
-
let configDefaults = [];
|
|
169
115
|
try {
|
|
170
116
|
const CyberiaInstanceConf = DataBaseProviderService.getModel('CyberiaInstanceConf', options);
|
|
171
117
|
const conf = await CyberiaInstanceConf.findOne({ instanceCode: instance.code }).select('entityDefaults').lean();
|
|
172
|
-
|
|
118
|
+
return mergeEntityDefaults(await CyberiaEntityTypeDefaultService.resolve(conf?.entityDefaults, options));
|
|
173
119
|
} catch {
|
|
174
|
-
|
|
120
|
+
return mergeEntityDefaults();
|
|
175
121
|
}
|
|
176
|
-
|
|
177
|
-
try {
|
|
178
|
-
const CyberiaEntityTypeDefault = DataBaseProviderService.getModel('CyberiaEntityTypeDefault', options);
|
|
179
|
-
const defaults = await CyberiaEntityTypeDefault.find({}).lean();
|
|
180
|
-
if (defaults.length > 0) return mergeEntityDefaults(defaults);
|
|
181
|
-
} catch {
|
|
182
|
-
// The editable own-model collection is optional for legacy deployments.
|
|
183
|
-
}
|
|
184
|
-
return mergeEntityDefaults(configDefaults);
|
|
185
122
|
};
|
|
186
123
|
|
|
187
124
|
const buildPresencePois = ({
|
|
@@ -191,11 +128,10 @@ const buildPresencePois = ({
|
|
|
191
128
|
actions,
|
|
192
129
|
objectLayerMetadata = {},
|
|
193
130
|
entityDefaults = mergeEntityDefaults(),
|
|
194
|
-
sumStatsLimit = CYBERIA_INSTANCE_CONF_DEFAULTS.sumStatsLimit,
|
|
195
131
|
}) => {
|
|
196
132
|
const pois = new Map();
|
|
197
133
|
|
|
198
|
-
const getPoi = (mapCode, cellX, cellY, presenceStatus, sourcePriority = 0
|
|
134
|
+
const getPoi = (mapCode, cellX, cellY, presenceStatus, sourcePriority = 0) => {
|
|
199
135
|
if (!mapCode || !Number.isFinite(cellX) || !Number.isFinite(cellY) || cellX < 0 || cellY < 0 || !presenceStatus)
|
|
200
136
|
return null;
|
|
201
137
|
const key = `${mapCode}:${cellX}:${cellY}`;
|
|
@@ -207,19 +143,7 @@ const buildPresencePois = ({
|
|
|
207
143
|
presenceStatus,
|
|
208
144
|
capabilities: [],
|
|
209
145
|
sourcePriority,
|
|
210
|
-
statsSum: 0,
|
|
211
|
-
hasStatfulPresence: false,
|
|
212
|
-
hasStatlessPresence: false,
|
|
213
146
|
};
|
|
214
|
-
if (sourcePriority >= 100) {
|
|
215
|
-
if (showStatsValue) {
|
|
216
|
-
poi.hasStatfulPresence = true;
|
|
217
|
-
poi.statsSum += statsSum;
|
|
218
|
-
} else {
|
|
219
|
-
poi.hasStatlessPresence = true;
|
|
220
|
-
poi.statsSum = 0;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
147
|
const priority = sourcePriority + (PRESENCE_PRIORITY[presenceStatus] || 0);
|
|
224
148
|
const currentPriority = poi.sourcePriority + (PRESENCE_PRIORITY[poi.presenceStatus] || 0);
|
|
225
149
|
if (priority > currentPriority) {
|
|
@@ -239,29 +163,14 @@ const buildPresencePois = ({
|
|
|
239
163
|
const behavior = entityBehavior(entity, entityDefaults);
|
|
240
164
|
const presenceStatus = entityPresenceStatus(entity, objectLayerMetadata, behavior);
|
|
241
165
|
if (!presenceStatus) continue;
|
|
242
|
-
|
|
243
|
-
// cells and provider/static-behavior entities never carry the readout.
|
|
244
|
-
const statless =
|
|
245
|
-
presenceStatus === PRESENCE_STATUS.portal ||
|
|
246
|
-
presenceStatus === PRESENCE_STATUS.portalRandom ||
|
|
247
|
-
STATLESS_BEHAVIORS.has(behavior);
|
|
248
|
-
getPoi(
|
|
249
|
-
map.code,
|
|
250
|
-
entity.initCellX ?? 0,
|
|
251
|
-
entity.initCellY ?? 0,
|
|
252
|
-
presenceStatus,
|
|
253
|
-
100,
|
|
254
|
-
statless ? 0 : objectLayerStatsSum(entity.objectLayerItemIds, objectLayerMetadata, sumStatsLimit),
|
|
255
|
-
!statless,
|
|
256
|
-
);
|
|
166
|
+
getPoi(map.code, entity.initCellX ?? 0, entity.initCellY ?? 0, presenceStatus, 100);
|
|
257
167
|
}
|
|
258
168
|
}
|
|
259
169
|
|
|
260
|
-
// Portal-cell presence
|
|
261
|
-
// decides random
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
// any, is stamped by their own outgoing edge.
|
|
170
|
+
// Portal-cell presence follows the AOI: the portal's own outgoing edge
|
|
171
|
+
// decides random against fixed, and priority 200 beats the authored entity
|
|
172
|
+
// class. A fixed-cell target endpoint is only a plain portal POI; its own
|
|
173
|
+
// outgoing edge stamps the mode.
|
|
265
174
|
for (const portal of instance.portals || []) {
|
|
266
175
|
getPoi(
|
|
267
176
|
portal.sourceMapCode,
|
|
@@ -283,14 +192,8 @@ const buildPresencePois = ({
|
|
|
283
192
|
addCapability(poi, CAPABILITY_ACTION);
|
|
284
193
|
}
|
|
285
194
|
|
|
286
|
-
// Display permission is explicit: a statless entity must never become a
|
|
287
|
-
// visible `stats 0` tab due to a numeric fallback or merged POI source.
|
|
288
195
|
return [...pois.values()]
|
|
289
|
-
.map(({ sourcePriority,
|
|
290
|
-
...poi,
|
|
291
|
-
statsSum: hasStatfulPresence && !hasStatlessPresence && poi.capabilities.length === 0 ? poi.statsSum : 0,
|
|
292
|
-
showStatsValue: hasStatfulPresence && !hasStatlessPresence && poi.capabilities.length === 0,
|
|
293
|
-
}))
|
|
196
|
+
.map(({ sourcePriority, ...poi }) => poi)
|
|
294
197
|
.sort(
|
|
295
198
|
(left, right) =>
|
|
296
199
|
left.mapCode.localeCompare(right.mapCode) || left.cellY - right.cellY || left.cellX - right.cellX,
|
|
@@ -310,7 +213,6 @@ const buildStaticPayload = ({
|
|
|
310
213
|
fallback,
|
|
311
214
|
objectLayerMetadata = {},
|
|
312
215
|
entityDefaults = mergeEntityDefaults(),
|
|
313
|
-
sumStatsLimit = CYBERIA_INSTANCE_CONF_DEFAULTS.sumStatsLimit,
|
|
314
216
|
previewCachedMapCodes = new Set(),
|
|
315
217
|
}) => {
|
|
316
218
|
const previewRoute = (mapCode) =>
|
|
@@ -323,11 +225,10 @@ const buildStaticPayload = ({
|
|
|
323
225
|
gridY: m.gridY,
|
|
324
226
|
// File id of the map's auto-captured Object Layer render (persisted maps).
|
|
325
227
|
preview: m.preview ? String(m.preview) : '',
|
|
326
|
-
//
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
// Fallback-world maps only advertise the route once a render succeeded.
|
|
228
|
+
// Path of the node background. A captured File is served directly. Without
|
|
229
|
+
// one the client hits the preview route, which renders on demand and, for a
|
|
230
|
+
// persisted map, stores the result as its `preview` File. A fallback-world
|
|
231
|
+
// map advertises the route only after a render succeeds.
|
|
331
232
|
previewUrl: m.preview
|
|
332
233
|
? `/api/file/blob/${String(m.preview)}`
|
|
333
234
|
: fallback
|
|
@@ -362,7 +263,6 @@ const buildStaticPayload = ({
|
|
|
362
263
|
actions,
|
|
363
264
|
objectLayerMetadata,
|
|
364
265
|
entityDefaults,
|
|
365
|
-
sumStatsLimit,
|
|
366
266
|
}),
|
|
367
267
|
};
|
|
368
268
|
};
|
|
@@ -416,10 +316,9 @@ const classifyActionProviders = (actions, questProviders) => {
|
|
|
416
316
|
|
|
417
317
|
/**
|
|
418
318
|
* Resolve the content-authority view of an instance: its map nodes plus the
|
|
419
|
-
* quests
|
|
420
|
-
* world
|
|
421
|
-
*
|
|
422
|
-
* cyberia-server.
|
|
319
|
+
* quests and actions bound to those maps. An instance that is not persisted
|
|
320
|
+
* falls back to the procedural world and the default quests/actions, the same
|
|
321
|
+
* fallback getFullInstance serves to the simulation.
|
|
423
322
|
*/
|
|
424
323
|
const resolveInstanceWorld = async (instanceCode, options) => {
|
|
425
324
|
const CyberiaInstance = DataBaseProviderService.getModel('CyberiaInstance', options);
|
|
@@ -440,7 +339,7 @@ const resolveInstanceWorld = async (instanceCode, options) => {
|
|
|
440
339
|
const resolved = await resolveObjectLayerMetadata(fallbackItemIds, options);
|
|
441
340
|
const objectLayerMetadata = Object.fromEntries(
|
|
442
341
|
Object.entries(resolved).map(([itemId, meta]) => {
|
|
443
|
-
return [itemId, {
|
|
342
|
+
return [itemId, { type: meta.type }];
|
|
444
343
|
}),
|
|
445
344
|
);
|
|
446
345
|
|
|
@@ -457,11 +356,9 @@ const resolveInstanceWorld = async (instanceCode, options) => {
|
|
|
457
356
|
actions: DefaultCyberiaActions.filter((a) => mapCodes.has(a.sourceMapCode)),
|
|
458
357
|
objectLayerMetadata,
|
|
459
358
|
entityDefaults: mergeEntityDefaults(),
|
|
460
|
-
|
|
461
|
-
//
|
|
462
|
-
|
|
463
|
-
// preview cache (see instanceMapPreview).
|
|
464
|
-
previewCachedMapCodes: new Set(await cacheWorldMapPreviews(instanceCode, world.maps)),
|
|
359
|
+
// The procedural world has no editor pass, so its node backgrounds render
|
|
360
|
+
// here and are served from the in-memory preview cache.
|
|
361
|
+
previewCachedMapCodes: new Set(await cacheWorldMapPreviews(instanceCode, world.maps, { options })),
|
|
465
362
|
fallback: true,
|
|
466
363
|
};
|
|
467
364
|
}
|
|
@@ -483,20 +380,17 @@ const resolveInstanceWorld = async (instanceCode, options) => {
|
|
|
483
380
|
...new Set(maps.flatMap((map) => (map.entities || []).flatMap((entity) => entity.objectLayerItemIds || []))),
|
|
484
381
|
];
|
|
485
382
|
const objectLayerMetadata = await resolveObjectLayerMetadata(itemIds, options);
|
|
486
|
-
const sumStatsLimit = await resolveSumStatsLimit(instance, options);
|
|
487
383
|
const entityDefaults = await resolveEntityDefaults(instance, options);
|
|
488
384
|
|
|
489
385
|
const codeSet = new Set(mapCodes);
|
|
490
386
|
return {
|
|
491
387
|
instance,
|
|
492
388
|
maps,
|
|
493
|
-
// Empty collections fall back to canonical defaults,
|
|
494
|
-
// getByCode behaviour for unseeded databases.
|
|
389
|
+
// Empty collections fall back to the canonical defaults, as getByCode does.
|
|
495
390
|
quests: dbQuests.length > 0 ? dbQuests : DefaultCyberiaQuests.filter((q) => codeSet.has(q.sourceMapCode)),
|
|
496
391
|
actions: dbActions.length > 0 ? dbActions : DefaultCyberiaActions.filter((a) => codeSet.has(a.sourceMapCode)),
|
|
497
392
|
objectLayerMetadata,
|
|
498
393
|
entityDefaults,
|
|
499
|
-
sumStatsLimit,
|
|
500
394
|
fallback: false,
|
|
501
395
|
};
|
|
502
396
|
};
|
|
@@ -532,7 +426,7 @@ class CyberiaInstanceMapService {
|
|
|
532
426
|
if (stored?.data) return stored.data;
|
|
533
427
|
}
|
|
534
428
|
|
|
535
|
-
const rendered = await renderMapPreviewPng(map);
|
|
429
|
+
const rendered = await renderMapPreviewPng(map, { options });
|
|
536
430
|
if (rendered) {
|
|
537
431
|
const file = await new File(FileFactory.create(rendered, `${mapCode}-preview.png`)).save();
|
|
538
432
|
await CyberiaMap.updateOne({ _id: map._id }, { $set: { preview: file._id } });
|
|
@@ -543,10 +437,9 @@ class CyberiaInstanceMapService {
|
|
|
543
437
|
|
|
544
438
|
let png = getCachedMapPreview(instanceCode, mapCode);
|
|
545
439
|
if (!png) {
|
|
546
|
-
// Cold cache
|
|
547
|
-
// regenerate the world so the preview exists, then serve it.
|
|
440
|
+
// Cold cache: regenerate the world so the preview exists, then serve it.
|
|
548
441
|
const { maps } = await resolveInstanceWorld(instanceCode, options);
|
|
549
|
-
await cacheWorldMapPreviews(instanceCode, maps);
|
|
442
|
+
await cacheWorldMapPreviews(instanceCode, maps, { options });
|
|
550
443
|
png = getCachedMapPreview(instanceCode, mapCode);
|
|
551
444
|
}
|
|
552
445
|
if (!png) throw new Error(`No cached preview for map "${mapCode}"`);
|
|
@@ -10,7 +10,7 @@ import { CyberiaInstanceMapService } from './cyberia-instance-map.service.js';
|
|
|
10
10
|
import { CyberiaInstanceBootService } from './cyberia-instance-boot.service.js';
|
|
11
11
|
|
|
12
12
|
const CyberiaInstanceController = buildCrudController(CyberiaInstanceService, {
|
|
13
|
-
// The
|
|
13
|
+
// The game client fetches the instance map cross-origin, as it does quests.
|
|
14
14
|
instanceMapStatic: serviceHandler(CyberiaInstanceMapService.getStatic, { crossOrigin: true, errorStatus: 404 }),
|
|
15
15
|
instanceMapDynamic: serviceHandler(CyberiaInstanceMapService.getDynamic, { crossOrigin: true, errorStatus: 404 }),
|
|
16
16
|
// Node background of a fallback-world map, rendered + cached server-side.
|
|
@@ -30,9 +30,6 @@ const CyberiaInstanceController = buildCrudController(CyberiaInstanceService, {
|
|
|
30
30
|
portalConnect: serviceHandler(CyberiaInstanceService.portalConnect),
|
|
31
31
|
// Moderator/admin-triggered world reload on a running cyberia-server.
|
|
32
32
|
hotReload: serviceHandler(CyberiaInstanceService.hotReload, { errorStatus: 502 }),
|
|
33
|
-
// Fallback-world default items (volatile) + its own reload trigger.
|
|
34
|
-
fallbackDefaultItems: serviceHandler(CyberiaInstanceService.fallbackDefaultItems),
|
|
35
|
-
fallbackHotReload: serviceHandler(CyberiaInstanceService.fallbackHotReload, { errorStatus: 502 }),
|
|
36
33
|
// Boot transport (REST fallback of the gRPC CyberiaDataService).
|
|
37
34
|
bootPing: serviceHandler(CyberiaInstanceBootService.ping),
|
|
38
35
|
bootObjectLayerBatch: serviceHandler(CyberiaInstanceBootService.objectLayerBatch, { errorStatus: 500 }),
|
|
@@ -68,20 +68,6 @@ const CyberiaInstanceSchema = new Schema(
|
|
|
68
68
|
// Vertex set of the graph
|
|
69
69
|
cyberiaMapCodes: { type: [String], default: [] },
|
|
70
70
|
|
|
71
|
-
// Instance-level object layer item IDs. Each entry binds an item id to the
|
|
72
|
-
// instance and flags whether it seeds every player's starting inventory
|
|
73
|
-
// (defaultPlayerInventory → merged into the player entityDefault's
|
|
74
|
-
// defaultObjectLayers when the world is served to cyberia-server).
|
|
75
|
-
itemIds: {
|
|
76
|
-
type: [
|
|
77
|
-
{
|
|
78
|
-
id: { type: String, required: true },
|
|
79
|
-
defaultPlayerInventory: { type: Boolean, default: false },
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
default: [],
|
|
83
|
-
},
|
|
84
|
-
|
|
85
71
|
// Directed edge set of the graph
|
|
86
72
|
portals: { type: [PortalEdgeSchema], default: [] },
|
|
87
73
|
|
|
@@ -12,9 +12,9 @@ class CyberiaInstanceRouter {
|
|
|
12
12
|
const router = express.Router();
|
|
13
13
|
// ── Custom actions (must come before generic /:id routes) ──────────────
|
|
14
14
|
// Boot transport — REST fallback of the gRPC CyberiaDataService, consumed
|
|
15
|
-
// server-to-server by cyberia-server (
|
|
16
|
-
// gRPC server
|
|
17
|
-
//
|
|
15
|
+
// server-to-server by cyberia-server (its --data-server-url) when the engine
|
|
16
|
+
// gRPC server is not enabled for the deploy. Unauthenticated for parity with
|
|
17
|
+
// the internal-network insecure gRPC channel.
|
|
18
18
|
router.get(`/boot/ping`, async (req, res) => await CyberiaInstanceController.bootPing(req, res, options));
|
|
19
19
|
router.get(
|
|
20
20
|
`/boot/object-layers`,
|
|
@@ -38,19 +38,6 @@ class CyberiaInstanceRouter {
|
|
|
38
38
|
async (req, res) => await CyberiaInstanceController.bootFullInstance(req, res, options),
|
|
39
39
|
);
|
|
40
40
|
router.get(`/fallback-world`, async (req, res) => await CyberiaInstanceController.fallbackWorld(req, res, options));
|
|
41
|
-
// Fallback-world default items — volatile, process-local (never persisted).
|
|
42
|
-
// The read is open (same as /fallback-world); staging them and triggering a
|
|
43
|
-
// rebuild is elevated privilege, like every other hot-reload path.
|
|
44
|
-
router.get(
|
|
45
|
-
`/fallback-world/default-items`,
|
|
46
|
-
async (req, res) => await CyberiaInstanceController.fallbackDefaultItems(req, res, options),
|
|
47
|
-
);
|
|
48
|
-
router.post(
|
|
49
|
-
`/fallback-world/hot-reload`,
|
|
50
|
-
options.authMiddleware,
|
|
51
|
-
moderatorGuard,
|
|
52
|
-
async (req, res) => await CyberiaInstanceController.fallbackHotReload(req, res, options),
|
|
53
|
-
);
|
|
54
41
|
// Instance Map — static topology/presence plus dynamic player capability activity.
|
|
55
42
|
router.get(
|
|
56
43
|
`/instance-map/:instanceCode/static`,
|
|
@@ -7,8 +7,6 @@ import {
|
|
|
7
7
|
fallbackListInstance,
|
|
8
8
|
DEFAULT_FALLBACK_INSTANCE_CODE,
|
|
9
9
|
} from './cyberia-fallback-world.js';
|
|
10
|
-
import { getFallbackDefaultItems, setFallbackDefaultItems } from './cyberia-fallback-default-items.js';
|
|
11
|
-
import { CYBERIA_INSTANCE_CONF_DEFAULTS } from '../cyberia-server-defaults/cyberia-server-defaults.js';
|
|
12
10
|
import { triggerHotReload } from '../../projects/cyberia/hot-reload-trigger.js';
|
|
13
11
|
|
|
14
12
|
const logger = loggerFactory(import.meta);
|
|
@@ -45,7 +43,9 @@ class CyberiaInstanceService {
|
|
|
45
43
|
/** @type {import('./cyberia-instance.model.js').CyberiaInstanceModel} */
|
|
46
44
|
const CyberiaInstance = DataBaseProviderService.getModel('CyberiaInstance', options);
|
|
47
45
|
const populateCreator = { path: 'creator', model: 'User', select: '_id username' };
|
|
48
|
-
|
|
46
|
+
// Instances are addressed by code, the key the engine navigates by.
|
|
47
|
+
if (req.params.id)
|
|
48
|
+
return await CyberiaInstance.findOne(DataQuery.naturalKeyFilter('code', req.params.id)).populate(populateCreator);
|
|
49
49
|
|
|
50
50
|
// Parse query parameters using DataQuery helper
|
|
51
51
|
const { query, sort, skip, limit, page } = DataQuery.parse(req.query);
|
|
@@ -185,49 +185,9 @@ class CyberiaInstanceService {
|
|
|
185
185
|
botCount: q.botCount ? parseInt(q.botCount, 10) : undefined,
|
|
186
186
|
obstacleCount: q.obstacleCount ? parseInt(q.obstacleCount, 10) : undefined,
|
|
187
187
|
foregroundCount: q.foregroundCount ? parseInt(q.foregroundCount, 10) : undefined,
|
|
188
|
-
itemIds: getFallbackDefaultItems(),
|
|
189
188
|
});
|
|
190
189
|
};
|
|
191
190
|
|
|
192
|
-
/**
|
|
193
|
-
* Current fallback-world default items — the volatile set the
|
|
194
|
-
* FallbackWorldEngine view last pushed, or `[]` when the engine is running on
|
|
195
|
-
* pure code defaults. Lets the view reopen showing what this process serves.
|
|
196
|
-
*
|
|
197
|
-
* `entityDefaultItemIds` are the ids the code defaults already ship in an
|
|
198
|
-
* entity's `defaultObjectLayers`. Selecting one of them and leaving
|
|
199
|
-
* `defaultPlayerInventory` unchecked REMOVES it (see
|
|
200
|
-
* applyInstanceDefaultPlayerInventory), so the editor needs to be able to warn
|
|
201
|
-
* before an operator silently strips the player's starting skin or weapon.
|
|
202
|
-
*/
|
|
203
|
-
static fallbackDefaultItems = async () => {
|
|
204
|
-
const entityDefaultItemIds = new Set();
|
|
205
|
-
for (const entityDefault of CYBERIA_INSTANCE_CONF_DEFAULTS.entityDefaults || []) {
|
|
206
|
-
for (const layer of entityDefault.defaultObjectLayers || []) {
|
|
207
|
-
if (layer.itemId) entityDefaultItemIds.add(layer.itemId);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return { itemIds: getFallbackDefaultItems(), entityDefaultItemIds: [...entityDefaultItemIds].sort() };
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Stage the fallback world's default items, then ask a running cyberia-server
|
|
215
|
-
* to rebuild. The items are not persisted (see cyberia-fallback-default-items):
|
|
216
|
-
* they are staged here first so the rebuild's `getFullInstance` re-fetch picks
|
|
217
|
-
* them up, which is what makes them reach the server at all.
|
|
218
|
-
*
|
|
219
|
-
* `instanceCode` is intentionally left empty — the target world is addressed by
|
|
220
|
-
* `serverUrl` (origin, or origin + variant sub-path), and naming the synthetic
|
|
221
|
-
* `fallback` code would be rejected by any server serving a real instance code.
|
|
222
|
-
*/
|
|
223
|
-
static fallbackHotReload = async (req) => {
|
|
224
|
-
const { serverUrl, mode, itemIds } = req.body || {};
|
|
225
|
-
if (!serverUrl) throw new Error('serverUrl is required');
|
|
226
|
-
|
|
227
|
-
const staged = setFallbackDefaultItems(itemIds || []);
|
|
228
|
-
const { transport, result, grpcError } = await triggerHotReload({ serverUrl, instanceCode: '', mode });
|
|
229
|
-
return { transport, itemIds: staged, grpcError, ...result };
|
|
230
|
-
};
|
|
231
191
|
}
|
|
232
192
|
|
|
233
193
|
export { CyberiaInstanceService };
|
|
@@ -483,7 +483,6 @@ function generateBots(mapDims, colors, opts = {}) {
|
|
|
483
483
|
cellY = randInt(0, maxY);
|
|
484
484
|
}
|
|
485
485
|
|
|
486
|
-
// const skin = BOT_SKIN_POOL[Math.floor(Math.random() * BOT_SKIN_POOL.length)];
|
|
487
486
|
const skin = 'kishins';
|
|
488
487
|
const hasWeapon = nextRandom() < BOT_WEAPON_CHANCE;
|
|
489
488
|
const itemIds = hasWeapon ? [skin, 'atlas_pistol_mk2'] : [skin];
|
|
@@ -506,16 +505,13 @@ function generateBots(mapDims, colors, opts = {}) {
|
|
|
506
505
|
}
|
|
507
506
|
|
|
508
507
|
/**
|
|
509
|
-
* Action-provider NPC bots
|
|
510
|
-
*
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
* action by these coordinates, so the positions here are the single source
|
|
514
|
-
* of truth shared with `DefaultCyberiaActions`.
|
|
508
|
+
* Action-provider NPC bots, the fixed-position entities behind the mission
|
|
509
|
+
* system. One passive bot per `CyberiaAction` whose `sourceMapCode` matches
|
|
510
|
+
* `mapCode`, at the action's (`sourceCellX`, `sourceCellY`). The server binds
|
|
511
|
+
* a bot to its action by these coordinates.
|
|
515
512
|
*
|
|
516
|
-
* The NPC skin
|
|
517
|
-
*
|
|
518
|
-
* provideItemId; the bot's own active skin is what 'talk' objectives match.
|
|
513
|
+
* The NPC skin comes from the action's first `default-<skin>` dialogue code
|
|
514
|
+
* (`default-wason` → skin `wason`). A 'talk' objective matches that skin.
|
|
519
515
|
*
|
|
520
516
|
* @param {string} mapCode
|
|
521
517
|
* @param {Array<{ key: string, r: number, g: number, b: number, a: number }>} colors
|
|
@@ -546,9 +542,8 @@ function generateActionProviderBots(mapCode, colors, opts = {}) {
|
|
|
546
542
|
|
|
547
543
|
if (opts.grid) opts.grid.block(cellX, cellY, dim, dim);
|
|
548
544
|
|
|
549
|
-
// Passive quest-giver NPC: no aggro
|
|
550
|
-
//
|
|
551
|
-
// it by its spawn-centre (the initial cell), so the bind survives movement.
|
|
545
|
+
// Passive quest-giver NPC: no aggro and a small wander radius. The server
|
|
546
|
+
// binds it by its spawn cell, so the bind survives the drift.
|
|
552
547
|
entities.push({
|
|
553
548
|
entityType: 'bot',
|
|
554
549
|
initCellX: cellX,
|