@ue-shed/protocol 0.1.0 → 0.3.0

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.
Files changed (45) hide show
  1. package/README.md +2 -1
  2. package/contracts/cameras/map-tile/v1/README.md +44 -0
  3. package/contracts/cameras/map-tile/v1/capture-request.schema.json +68 -0
  4. package/contracts/cameras/map-tile/v1/capture-response.schema.json +115 -0
  5. package/contracts/cameras/map-tile/v1/fixtures/capture-request-valid.json +32 -0
  6. package/contracts/cameras/map-tile/v1/fixtures/capture-response-valid.json +24 -0
  7. package/contracts/cameras/map-tile/v1/fixtures/manifest-invalid-complete.json +41 -0
  8. package/contracts/cameras/map-tile/v1/fixtures/manifest-invalid-grid.json +44 -0
  9. package/contracts/cameras/map-tile/v1/fixtures/manifest-valid.json +60 -0
  10. package/contracts/cameras/map-tile/v1/fixtures/plan-valid.json +27 -0
  11. package/contracts/cameras/map-tile/v1/manifest.schema.json +162 -0
  12. package/contracts/cameras/map-tile/v1/plan.schema.json +176 -0
  13. package/contracts/cameras/provisioning/v1/README.md +5 -3
  14. package/contracts/cameras/provisioning/v1/fixtures/provision-request-valid.json +11 -2
  15. package/contracts/cameras/provisioning/v1/provision-request.schema.json +131 -50
  16. package/contracts/cameras/v1/README.md +6 -3
  17. package/contracts/editor-world/v1/README.md +10 -0
  18. package/contracts/editor-world/v1/request.schema.json +16 -0
  19. package/contracts/editor-world/v1/response.schema.json +93 -0
  20. package/contracts/uasset-io/v1/event.schema.json +110 -60
  21. package/contracts/uasset-io/v1/fixtures/valid/saved-world-result-event.json +20 -4
  22. package/dist/authoring.d.ts +6 -1
  23. package/dist/authoring.d.ts.map +1 -1
  24. package/dist/companion.d.ts +14 -0
  25. package/dist/companion.d.ts.map +1 -1
  26. package/dist/companion.js +7 -0
  27. package/dist/companion.js.map +1 -1
  28. package/dist/editor-play-session.d.ts +4 -1
  29. package/dist/editor-play-session.d.ts.map +1 -1
  30. package/dist/editor-play-session.js.map +1 -1
  31. package/dist/editor-world-control.d.ts +179 -0
  32. package/dist/editor-world-control.d.ts.map +1 -0
  33. package/dist/editor-world-control.js +47 -0
  34. package/dist/editor-world-control.js.map +1 -0
  35. package/dist/index.d.ts +6 -5
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +2 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/saved-world.d.ts +121 -40
  40. package/dist/saved-world.d.ts.map +1 -1
  41. package/dist/saved-world.js +35 -11
  42. package/dist/saved-world.js.map +1 -1
  43. package/dist/uasset-io.d.ts +90 -31
  44. package/dist/uasset-io.d.ts.map +1 -1
  45. package/package.json +1 -1
@@ -0,0 +1,176 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://ue-shed.dev/contracts/cameras/map-tile/v1/plan.schema.json",
4
+ "title": "UE Shed Map Capture Plan v1.0",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "capture",
9
+ "contract",
10
+ "gutterPixels",
11
+ "id",
12
+ "levels",
13
+ "output",
14
+ "project",
15
+ "requestedBounds",
16
+ "tilePixelSize"
17
+ ],
18
+ "properties": {
19
+ "capture": { "$ref": "#/$defs/capturePolicy" },
20
+ "contract": {
21
+ "type": "object",
22
+ "additionalProperties": false,
23
+ "required": ["name", "version"],
24
+ "properties": {
25
+ "name": { "const": "ue-shed-map-capture-plan" },
26
+ "version": { "$ref": "#/$defs/version" }
27
+ }
28
+ },
29
+ "gutterPixels": { "type": "integer", "minimum": 0, "maximum": 32 },
30
+ "id": { "$ref": "#/$defs/id" },
31
+ "levels": {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "required": ["coarsestUnitsPerPixel", "count"],
35
+ "properties": {
36
+ "coarsestUnitsPerPixel": { "type": "number", "exclusiveMinimum": 0 },
37
+ "count": { "type": "integer", "minimum": 1, "maximum": 24 }
38
+ }
39
+ },
40
+ "output": {
41
+ "type": "object",
42
+ "additionalProperties": false,
43
+ "required": ["imageFormat", "publication"],
44
+ "properties": {
45
+ "imageFormat": { "const": "png" },
46
+ "publication": { "const": "local_immutable" }
47
+ }
48
+ },
49
+ "project": { "$ref": "#/$defs/project" },
50
+ "requestedBounds": { "$ref": "#/$defs/bounds" },
51
+ "tilePixelSize": { "type": "integer", "minimum": 64, "maximum": 4096 }
52
+ },
53
+ "$defs": {
54
+ "id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$" },
55
+ "version": {
56
+ "type": "object",
57
+ "additionalProperties": false,
58
+ "required": ["major", "minor"],
59
+ "properties": { "major": { "const": 1 }, "minor": { "const": 0 } }
60
+ },
61
+ "bounds": {
62
+ "type": "object",
63
+ "additionalProperties": false,
64
+ "required": ["minX", "minY", "maxX", "maxY"],
65
+ "properties": {
66
+ "minX": { "type": "number" },
67
+ "minY": { "type": "number" },
68
+ "maxX": { "type": "number" },
69
+ "maxY": { "type": "number" }
70
+ }
71
+ },
72
+ "project": {
73
+ "type": "object",
74
+ "additionalProperties": false,
75
+ "required": ["id", "mapPath"],
76
+ "properties": {
77
+ "id": { "$ref": "#/$defs/id" },
78
+ "mapPath": { "type": "string", "pattern": "^/[A-Za-z0-9_./-]+$" }
79
+ }
80
+ },
81
+ "dataLayers": {
82
+ "oneOf": [
83
+ {
84
+ "type": "object",
85
+ "additionalProperties": false,
86
+ "required": ["mode"],
87
+ "properties": { "mode": { "const": "unchanged" } }
88
+ },
89
+ {
90
+ "type": "object",
91
+ "additionalProperties": false,
92
+ "required": ["mode", "states"],
93
+ "properties": {
94
+ "mode": { "const": "explicit" },
95
+ "states": {
96
+ "type": "array",
97
+ "maxItems": 64,
98
+ "items": {
99
+ "type": "object",
100
+ "additionalProperties": false,
101
+ "required": ["name", "state"],
102
+ "properties": {
103
+ "name": { "type": "string", "minLength": 1, "maxLength": 1024 },
104
+ "state": { "enum": ["unloaded", "loaded", "activated"] }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+ ]
111
+ },
112
+ "capturePolicy": {
113
+ "type": "object",
114
+ "additionalProperties": false,
115
+ "required": ["dataLayers", "orientation", "render", "z"],
116
+ "properties": {
117
+ "dataLayers": { "$ref": "#/$defs/dataLayers" },
118
+ "orientation": {
119
+ "type": "object",
120
+ "additionalProperties": false,
121
+ "required": ["pitch", "roll", "yaw"],
122
+ "properties": {
123
+ "pitch": { "const": -90 },
124
+ "roll": { "const": 0 },
125
+ "yaw": { "const": 0 }
126
+ }
127
+ },
128
+ "render": {
129
+ "type": "object",
130
+ "additionalProperties": false,
131
+ "required": ["effects", "lodPolicy", "profile"],
132
+ "properties": {
133
+ "effects": {
134
+ "type": "object",
135
+ "additionalProperties": false,
136
+ "required": ["fog", "volumetricFog"],
137
+ "properties": {
138
+ "fog": { "type": "boolean" },
139
+ "volumetricFog": { "type": "boolean" }
140
+ }
141
+ },
142
+ "lodDistanceScaleByZoom": {
143
+ "type": "array",
144
+ "minItems": 1,
145
+ "maxItems": 24,
146
+ "items": { "type": "number", "minimum": 0.1, "maximum": 100 }
147
+ },
148
+ "lodPolicy": {
149
+ "enum": ["natural", "fixed_lod_zero", "per_level_distance_scale"]
150
+ },
151
+ "profile": {
152
+ "enum": [
153
+ "full_fidelity",
154
+ "seam_stable",
155
+ "scene_capture_defaults",
156
+ "observation"
157
+ ]
158
+ }
159
+ },
160
+ "allOf": [
161
+ {
162
+ "if": {
163
+ "properties": {
164
+ "lodPolicy": { "const": "per_level_distance_scale" }
165
+ }
166
+ },
167
+ "then": { "required": ["lodDistanceScaleByZoom"] },
168
+ "else": { "not": { "required": ["lodDistanceScaleByZoom"] } }
169
+ }
170
+ ]
171
+ },
172
+ "z": { "type": "number" }
173
+ }
174
+ }
175
+ }
176
+ }
@@ -4,9 +4,11 @@
4
4
  camera is a transient runtime realization, identified by a generated `ProvisionedCameraId`; it is
5
5
  never a durable Map Review camera record.
6
6
 
7
- Each request carries an explicit correlation to either a framing candidate or a durable Review View.
8
- The compatibility decoder accepts the former candidate-only request shape for already-installed
9
- clients, but new clients emit only `schemaVersion: 2` and the `correlation` union.
7
+ Each request carries an expected map and an explicit correlation to a framing candidate, a durable
8
+ Review View, or a Map Capture Plan. A camera selects either perspective field of view or
9
+ orthographic width through a discriminated projection. The compatibility decoder accepts the
10
+ candidate-only and `schemaVersion: 2` perspective request shapes for already-installed clients, but
11
+ new clients emit only `schemaVersion: 3`.
10
12
 
11
13
  The editor returns the same correlation for every provisioned camera. Array index remains a live
12
14
  frame transport position, never durable identity.
@@ -1,14 +1,23 @@
1
1
  {
2
- "schemaVersion": 2,
2
+ "schemaVersion": 3,
3
+ "expectedMapPath": "/Game/Fixture/Cameras/L_CameraLoad",
3
4
  "previewFps": 5,
4
5
  "cameras": [
5
6
  {
6
7
  "correlation": { "type": "framing_candidate", "candidateId": "context_three_quarter" },
7
- "fieldOfViewDegrees": 60,
8
+ "projection": { "type": "perspective", "fieldOfViewDegrees": 60 },
8
9
  "location": { "x": 1200, "y": -1400, "z": 700 },
9
10
  "rotation": { "pitch": -12, "yaw": 135, "roll": 0 },
10
11
  "width": 320,
11
12
  "height": 180
13
+ },
14
+ {
15
+ "correlation": { "type": "map_capture_plan", "mapCapturePlanId": "fixture-overview" },
16
+ "projection": { "type": "orthographic", "orthoWidth": 4096 },
17
+ "location": { "x": 0, "y": 0, "z": 5000 },
18
+ "rotation": { "pitch": -90, "yaw": 0, "roll": 0 },
19
+ "width": 640,
20
+ "height": 360
12
21
  }
13
22
  ]
14
23
  }
@@ -4,68 +4,149 @@
4
4
  "title": "UE Shed provisioned camera request v1",
5
5
  "type": "object",
6
6
  "additionalProperties": false,
7
- "required": ["schemaVersion", "previewFps", "cameras"],
7
+ "required": ["schemaVersion", "expectedMapPath", "previewFps", "cameras"],
8
8
  "properties": {
9
- "schemaVersion": { "const": 2 },
9
+ "schemaVersion": { "const": 3 },
10
+ "expectedMapPath": {
11
+ "type": "string",
12
+ "minLength": 1,
13
+ "maxLength": 1024,
14
+ "pattern": "^/[A-Za-z0-9_./-]+$"
15
+ },
10
16
  "previewFps": { "type": "integer", "minimum": 1, "maximum": 10 },
11
17
  "cameras": {
12
18
  "type": "array",
13
19
  "minItems": 1,
14
20
  "maxItems": 32,
15
21
  "items": {
16
- "type": "object",
17
- "additionalProperties": false,
18
- "required": [
19
- "correlation",
20
- "fieldOfViewDegrees",
21
- "location",
22
- "rotation",
23
- "width",
24
- "height"
25
- ],
26
- "properties": {
27
- "correlation": {
28
- "oneOf": [
29
- {
30
- "type": "object",
31
- "additionalProperties": false,
32
- "required": ["type", "candidateId"],
33
- "properties": {
34
- "type": { "const": "framing_candidate" },
35
- "candidateId": {
36
- "type": "string",
37
- "minLength": 1,
38
- "maxLength": 128,
39
- "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"
40
- }
41
- }
42
- },
43
- {
44
- "type": "object",
45
- "additionalProperties": false,
46
- "required": ["type", "reviewViewId"],
47
- "properties": {
48
- "type": { "const": "review_view" },
49
- "reviewViewId": {
50
- "type": "string",
51
- "minLength": 1,
52
- "maxLength": 128,
53
- "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"
54
- }
55
- }
56
- }
57
- ]
22
+ "oneOf": [
23
+ {
24
+ "$ref": "#/$defs/perspectiveCamera"
58
25
  },
59
- "fieldOfViewDegrees": { "type": "number", "minimum": 5, "maximum": 170 },
60
- "location": { "$ref": "#/$defs/vector" },
61
- "rotation": { "$ref": "#/$defs/rotation" },
62
- "width": { "type": "integer", "minimum": 64, "maximum": 2560 },
63
- "height": { "type": "integer", "minimum": 64, "maximum": 1440 }
64
- }
26
+ {
27
+ "$ref": "#/$defs/orthographicCamera"
28
+ }
29
+ ]
65
30
  }
66
31
  }
67
32
  },
68
33
  "$defs": {
34
+ "cameraFields": {
35
+ "type": "object",
36
+ "required": ["correlation", "projection", "location", "rotation", "width", "height"],
37
+ "properties": {
38
+ "correlation": { "$ref": "#/$defs/correlation" },
39
+ "location": { "$ref": "#/$defs/vector" },
40
+ "rotation": { "$ref": "#/$defs/rotation" },
41
+ "width": { "type": "integer", "minimum": 64, "maximum": 2560 },
42
+ "height": { "type": "integer", "minimum": 64, "maximum": 1440 }
43
+ }
44
+ },
45
+ "perspectiveCamera": {
46
+ "allOf": [
47
+ { "$ref": "#/$defs/cameraFields" },
48
+ {
49
+ "type": "object",
50
+ "additionalProperties": false,
51
+ "required": [
52
+ "correlation",
53
+ "projection",
54
+ "location",
55
+ "rotation",
56
+ "width",
57
+ "height"
58
+ ],
59
+ "properties": {
60
+ "correlation": { "$ref": "#/$defs/correlation" },
61
+ "projection": { "$ref": "#/$defs/perspectiveProjection" },
62
+ "location": { "$ref": "#/$defs/vector" },
63
+ "rotation": { "$ref": "#/$defs/rotation" },
64
+ "width": { "type": "integer", "minimum": 64, "maximum": 2560 },
65
+ "height": { "type": "integer", "minimum": 64, "maximum": 1440 }
66
+ }
67
+ }
68
+ ]
69
+ },
70
+ "orthographicCamera": {
71
+ "allOf": [
72
+ { "$ref": "#/$defs/cameraFields" },
73
+ {
74
+ "type": "object",
75
+ "additionalProperties": false,
76
+ "required": [
77
+ "correlation",
78
+ "projection",
79
+ "location",
80
+ "rotation",
81
+ "width",
82
+ "height"
83
+ ],
84
+ "properties": {
85
+ "correlation": { "$ref": "#/$defs/correlation" },
86
+ "projection": { "$ref": "#/$defs/orthographicProjection" },
87
+ "location": { "$ref": "#/$defs/vector" },
88
+ "rotation": { "$ref": "#/$defs/rotation" },
89
+ "width": { "type": "integer", "minimum": 64, "maximum": 2560 },
90
+ "height": { "type": "integer", "minimum": 64, "maximum": 1440 }
91
+ }
92
+ }
93
+ ]
94
+ },
95
+ "perspectiveProjection": {
96
+ "type": "object",
97
+ "additionalProperties": false,
98
+ "required": ["type", "fieldOfViewDegrees"],
99
+ "properties": {
100
+ "type": { "const": "perspective" },
101
+ "fieldOfViewDegrees": { "type": "number", "minimum": 5, "maximum": 170 }
102
+ }
103
+ },
104
+ "orthographicProjection": {
105
+ "type": "object",
106
+ "additionalProperties": false,
107
+ "required": ["type", "orthoWidth"],
108
+ "properties": {
109
+ "type": { "const": "orthographic" },
110
+ "orthoWidth": { "type": "number", "exclusiveMinimum": 0 }
111
+ }
112
+ },
113
+ "correlation": {
114
+ "oneOf": [
115
+ {
116
+ "type": "object",
117
+ "additionalProperties": false,
118
+ "required": ["type", "candidateId"],
119
+ "properties": {
120
+ "type": { "const": "framing_candidate" },
121
+ "candidateId": { "$ref": "#/$defs/identifier" }
122
+ }
123
+ },
124
+ {
125
+ "type": "object",
126
+ "additionalProperties": false,
127
+ "required": ["type", "reviewViewId"],
128
+ "properties": {
129
+ "type": { "const": "review_view" },
130
+ "reviewViewId": { "$ref": "#/$defs/identifier" }
131
+ }
132
+ },
133
+ {
134
+ "type": "object",
135
+ "additionalProperties": false,
136
+ "required": ["type", "mapCapturePlanId"],
137
+ "properties": {
138
+ "type": { "const": "map_capture_plan" },
139
+ "mapCapturePlanId": { "$ref": "#/$defs/identifier" }
140
+ }
141
+ }
142
+ ]
143
+ },
144
+ "identifier": {
145
+ "type": "string",
146
+ "minLength": 1,
147
+ "maxLength": 128,
148
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"
149
+ },
69
150
  "vector": {
70
151
  "type": "object",
71
152
  "additionalProperties": false,
@@ -20,9 +20,9 @@ frames from an old session are disposable.
20
20
  | 40 | f64 | Unreal world seconds at capture request |
21
21
  | 48 | f64 | producer monotonic milliseconds at capture request |
22
22
  | 56 | f64 | GPU readback latency in milliseconds |
23
- | 64 | u8[16] | producer ID |
24
- | 80 | u8[16] | session ID |
25
- | 96 | u8[16] | camera ID |
23
+ | 64 | u32[4] | producer FGuid words, each little-endian |
24
+ | 80 | u32[4] | session FGuid words, each little-endian |
25
+ | 96 | u32[4] | camera FGuid words, each little-endian |
26
26
  | 112 | u32 | cumulative readback/staging drops |
27
27
  | 116 | u32 | cumulative latest-frame transport replacements |
28
28
  | 120 | u32 | reserved, zero |
@@ -31,3 +31,6 @@ frames from an old session are disposable.
31
31
  The payload is top-to-bottom, tightly packed BGRA8. Live buffers are bounded and latest-frame-wins;
32
32
  sequence gaps are expected and observable. The control plane owns camera listing, schedule tuning,
33
33
  pause/focus, and health. This binary stream never carries durable evidence.
34
+
35
+ To compare an ID with Unreal's `FGuid::ToString(EGuidFormats::Digits)` output, read the four
36
+ little-endian `u32` words and concatenate them as four zero-padded, eight-digit hexadecimal values.
@@ -0,0 +1,10 @@
1
+ # Unreal editor world-control contract v1
2
+
3
+ This contract lets a trusted external client open one explicit `/Game/` map in Unreal Editor
4
+ without player input. The operation never saves, discards, or prompts over dirty work. It returns
5
+ `already_open` when the target is current and otherwise rejects active play sessions, dirty world
6
+ packages, missing maps, and failed loads as typed outcomes.
7
+
8
+ `request.schema.json` and `response.schema.json` are the language-neutral authority shared by
9
+ `@ue-shed/protocol` and `UEShedCoreEditor`. The companion advertises
10
+ `editor.world-control.v1` and its reflected object path before clients may invoke the operation.
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://ue-shed.dev/contracts/editor-world/v1/request.schema.json",
4
+ "title": "UE Shed editor world open request v1.0",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["contract", "operationId", "targetMapPath"],
8
+ "properties": {
9
+ "contract": { "$ref": "response.schema.json#/$defs/contract" },
10
+ "operationId": {
11
+ "type": "string",
12
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"
13
+ },
14
+ "targetMapPath": { "$ref": "response.schema.json#/$defs/gameMapPath" }
15
+ }
16
+ }
@@ -0,0 +1,93 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://ue-shed.dev/contracts/editor-world/v1/response.schema.json",
4
+ "title": "UE Shed editor world open response v1.0",
5
+ "oneOf": [
6
+ {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "required": ["after", "before", "contract", "operationId", "outcome", "targetMapPath"],
10
+ "properties": {
11
+ "after": { "$ref": "#/$defs/snapshot" },
12
+ "before": { "$ref": "#/$defs/snapshot" },
13
+ "contract": { "$ref": "#/$defs/contract" },
14
+ "operationId": { "$ref": "#/$defs/operationId" },
15
+ "outcome": { "enum": ["opened", "already_open"] },
16
+ "targetMapPath": { "$ref": "#/$defs/gameMapPath" }
17
+ }
18
+ },
19
+ {
20
+ "type": "object",
21
+ "additionalProperties": false,
22
+ "required": [
23
+ "after",
24
+ "before",
25
+ "code",
26
+ "contract",
27
+ "message",
28
+ "operationId",
29
+ "outcome",
30
+ "recovery",
31
+ "retrySafe",
32
+ "targetMapPath"
33
+ ],
34
+ "properties": {
35
+ "after": { "$ref": "#/$defs/snapshot" },
36
+ "before": { "$ref": "#/$defs/snapshot" },
37
+ "code": {
38
+ "enum": [
39
+ "dirty_world",
40
+ "invalid_request",
41
+ "map_not_found",
42
+ "open_failed",
43
+ "play_session_active",
44
+ "unavailable"
45
+ ]
46
+ },
47
+ "contract": { "$ref": "#/$defs/contract" },
48
+ "message": { "type": "string" },
49
+ "operationId": { "$ref": "#/$defs/operationId" },
50
+ "outcome": { "const": "rejected" },
51
+ "recovery": { "type": "string" },
52
+ "retrySafe": { "type": "boolean" },
53
+ "targetMapPath": { "$ref": "#/$defs/gameMapPath" }
54
+ }
55
+ }
56
+ ],
57
+ "$defs": {
58
+ "contract": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["name", "version"],
62
+ "properties": {
63
+ "name": { "const": "unreal-editor-world-control" },
64
+ "version": {
65
+ "type": "object",
66
+ "additionalProperties": false,
67
+ "required": ["major", "minor"],
68
+ "properties": { "major": { "const": 1 }, "minor": { "const": 0 } }
69
+ }
70
+ }
71
+ },
72
+ "mapPath": { "type": "string", "pattern": "^/[A-Za-z0-9_./-]+$" },
73
+ "gameMapPath": { "type": "string", "pattern": "^/Game/[A-Za-z0-9_./-]+$" },
74
+ "operationId": {
75
+ "type": "string",
76
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"
77
+ },
78
+ "snapshot": {
79
+ "type": "object",
80
+ "additionalProperties": false,
81
+ "required": ["dirtyWorldPackages", "playSessionActive"],
82
+ "properties": {
83
+ "dirtyWorldPackages": {
84
+ "type": "array",
85
+ "maxItems": 256,
86
+ "items": { "$ref": "#/$defs/mapPath" }
87
+ },
88
+ "mapPath": { "$ref": "#/$defs/mapPath" },
89
+ "playSessionActive": { "type": "boolean" }
90
+ }
91
+ }
92
+ }
93
+ }