@rezless/vm 0.3.0 → 0.5.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 (155) hide show
  1. package/NOTICE +26 -14
  2. package/dist/builtins/base64.d.ts.map +1 -1
  3. package/dist/builtins/base64.js +29 -2
  4. package/dist/builtins/base64.js.map +1 -1
  5. package/dist/builtins/chat.d.ts +7 -1
  6. package/dist/builtins/chat.d.ts.map +1 -1
  7. package/dist/builtins/chat.js +26 -29
  8. package/dist/builtins/chat.js.map +1 -1
  9. package/dist/builtins/dataserver.d.ts +2 -1
  10. package/dist/builtins/dataserver.d.ts.map +1 -1
  11. package/dist/builtins/dataserver.js +5 -4
  12. package/dist/builtins/dataserver.js.map +1 -1
  13. package/dist/builtins/debug.d.ts +4 -0
  14. package/dist/builtins/debug.d.ts.map +1 -0
  15. package/dist/builtins/debug.js +7 -0
  16. package/dist/builtins/debug.js.map +1 -0
  17. package/dist/builtins/hash.js +1 -1
  18. package/dist/builtins/hash.js.map +1 -1
  19. package/dist/builtins/http.d.ts +8 -1
  20. package/dist/builtins/http.d.ts.map +1 -1
  21. package/dist/builtins/http.js +87 -9
  22. package/dist/builtins/http.js.map +1 -1
  23. package/dist/builtins/identity.d.ts +2 -0
  24. package/dist/builtins/identity.d.ts.map +1 -1
  25. package/dist/builtins/identity.js +9 -1
  26. package/dist/builtins/identity.js.map +1 -1
  27. package/dist/builtins/index.d.ts.map +1 -1
  28. package/dist/builtins/index.js +29 -7
  29. package/dist/builtins/index.js.map +1 -1
  30. package/dist/builtins/inventory.d.ts +13 -2
  31. package/dist/builtins/inventory.d.ts.map +1 -1
  32. package/dist/builtins/inventory.js +82 -43
  33. package/dist/builtins/inventory.js.map +1 -1
  34. package/dist/builtins/json.d.ts.map +1 -1
  35. package/dist/builtins/json.js +11 -36
  36. package/dist/builtins/json.js.map +1 -1
  37. package/dist/builtins/link-info.d.ts +1 -1
  38. package/dist/builtins/link-info.d.ts.map +1 -1
  39. package/dist/builtins/link-info.js +2 -2
  40. package/dist/builtins/link-info.js.map +1 -1
  41. package/dist/builtins/linksetdata.d.ts.map +1 -1
  42. package/dist/builtins/linksetdata.js +298 -31
  43. package/dist/builtins/linksetdata.js.map +1 -1
  44. package/dist/builtins/listen.d.ts +3 -1
  45. package/dist/builtins/listen.d.ts.map +1 -1
  46. package/dist/builtins/listen.js +9 -1
  47. package/dist/builtins/listen.js.map +1 -1
  48. package/dist/builtins/lists.d.ts +21 -0
  49. package/dist/builtins/lists.d.ts.map +1 -1
  50. package/dist/builtins/lists.js +82 -38
  51. package/dist/builtins/lists.js.map +1 -1
  52. package/dist/builtins/math.d.ts +27 -4
  53. package/dist/builtins/math.d.ts.map +1 -1
  54. package/dist/builtins/math.js +118 -41
  55. package/dist/builtins/math.js.map +1 -1
  56. package/dist/builtins/permissions.d.ts +18 -0
  57. package/dist/builtins/permissions.d.ts.map +1 -0
  58. package/dist/builtins/permissions.js +17 -0
  59. package/dist/builtins/permissions.js.map +1 -0
  60. package/dist/builtins/prim-accessors.d.ts +1 -0
  61. package/dist/builtins/prim-accessors.d.ts.map +1 -1
  62. package/dist/builtins/prim-accessors.js +44 -42
  63. package/dist/builtins/prim-accessors.js.map +1 -1
  64. package/dist/builtins/prim-params.d.ts +1 -1
  65. package/dist/builtins/prim-params.d.ts.map +1 -1
  66. package/dist/builtins/prim-params.js +19 -11
  67. package/dist/builtins/prim-params.js.map +1 -1
  68. package/dist/builtins/strings.d.ts.map +1 -1
  69. package/dist/builtins/strings.js +37 -33
  70. package/dist/builtins/strings.js.map +1 -1
  71. package/dist/builtins/time.d.ts +2 -0
  72. package/dist/builtins/time.d.ts.map +1 -1
  73. package/dist/builtins/time.js +2 -0
  74. package/dist/builtins/time.js.map +1 -1
  75. package/dist/clock.d.ts +23 -9
  76. package/dist/clock.d.ts.map +1 -1
  77. package/dist/clock.js +40 -13
  78. package/dist/clock.js.map +1 -1
  79. package/dist/dispatch.d.ts +1 -1
  80. package/dist/dispatch.d.ts.map +1 -1
  81. package/dist/dispatch.js +12 -5
  82. package/dist/dispatch.js.map +1 -1
  83. package/dist/generated/constants.d.ts +130 -18
  84. package/dist/generated/constants.d.ts.map +1 -1
  85. package/dist/generated/constants.js +254 -142
  86. package/dist/generated/constants.js.map +1 -1
  87. package/dist/generated/constants_table.d.ts +1 -1
  88. package/dist/generated/constants_table.d.ts.map +1 -1
  89. package/dist/generated/constants_table.js +247 -135
  90. package/dist/generated/constants_table.js.map +1 -1
  91. package/dist/generated/events.d.ts +22 -22
  92. package/dist/generated/events.d.ts.map +1 -1
  93. package/dist/generated/events.js +10 -10
  94. package/dist/generated/events.js.map +1 -1
  95. package/dist/generated/functions.d.ts +292 -187
  96. package/dist/generated/functions.d.ts.map +1 -1
  97. package/dist/generated/functions.js +149 -140
  98. package/dist/generated/functions.js.map +1 -1
  99. package/dist/index.d.ts +2 -0
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +1 -0
  102. package/dist/index.js.map +1 -1
  103. package/dist/interpreter.d.ts +1 -1
  104. package/dist/interpreter.d.ts.map +1 -1
  105. package/dist/interpreter.js +2 -2
  106. package/dist/interpreter.js.map +1 -1
  107. package/dist/inventory.d.ts +4 -2
  108. package/dist/inventory.d.ts.map +1 -1
  109. package/dist/inventory.js +6 -2
  110. package/dist/inventory.js.map +1 -1
  111. package/dist/keys.d.ts +6 -0
  112. package/dist/keys.d.ts.map +1 -0
  113. package/dist/keys.js +20 -0
  114. package/dist/keys.js.map +1 -0
  115. package/dist/linkset.d.ts +28 -3
  116. package/dist/linkset.d.ts.map +1 -1
  117. package/dist/linkset.js +66 -7
  118. package/dist/linkset.js.map +1 -1
  119. package/dist/prim-params.d.ts +9 -2
  120. package/dist/prim-params.d.ts.map +1 -1
  121. package/dist/prim-params.js +198 -113
  122. package/dist/prim-params.js.map +1 -1
  123. package/dist/prim.d.ts +6 -1
  124. package/dist/prim.d.ts.map +1 -1
  125. package/dist/prim.js +23 -3
  126. package/dist/prim.js.map +1 -1
  127. package/dist/runtime.d.ts +11 -1
  128. package/dist/runtime.d.ts.map +1 -1
  129. package/dist/script.d.ts +30 -5
  130. package/dist/script.d.ts.map +1 -1
  131. package/dist/script.js +94 -32
  132. package/dist/script.js.map +1 -1
  133. package/dist/typecheck.d.ts +1 -1
  134. package/dist/typecheck.js +1 -1
  135. package/dist/values/coerce.d.ts +11 -0
  136. package/dist/values/coerce.d.ts.map +1 -1
  137. package/dist/values/coerce.js +65 -38
  138. package/dist/values/coerce.js.map +1 -1
  139. package/dist/values/format.d.ts +24 -16
  140. package/dist/values/format.d.ts.map +1 -1
  141. package/dist/values/format.js +42 -25
  142. package/dist/values/format.js.map +1 -1
  143. package/dist/values/ops.d.ts +2 -1
  144. package/dist/values/ops.d.ts.map +1 -1
  145. package/dist/values/ops.js +13 -5
  146. package/dist/values/ops.js.map +1 -1
  147. package/dist/values/utf8.d.ts +3 -0
  148. package/dist/values/utf8.d.ts.map +1 -0
  149. package/dist/values/utf8.js +14 -0
  150. package/dist/values/utf8.js.map +1 -0
  151. package/dist/world.d.ts +29 -0
  152. package/dist/world.d.ts.map +1 -0
  153. package/dist/world.js +29 -0
  154. package/dist/world.js.map +1 -0
  155. package/package.json +2 -2
@@ -1,10 +1,12 @@
1
- import { ALL_SIDES, CLICK_ACTION_TOUCH, PRIM_ALPHA_MODE, PRIM_ALPHA_MODE_NONE, PRIM_ALLOW_UNSIT, PRIM_BUMP_NONE, PRIM_BUMP_SHINY, PRIM_CAST_SHADOWS, PRIM_CLICK_ACTION, PRIM_COLOR, PRIM_DAMAGE, PRIM_DESC, PRIM_FLEXIBLE, PRIM_FULLBRIGHT, PRIM_GLOW, PRIM_GLTF_ALPHA_MODE_OPAQUE, PRIM_GLTF_BASE_COLOR, PRIM_GLTF_EMISSIVE, PRIM_GLTF_METALLIC_ROUGHNESS, PRIM_GLTF_NORMAL, PRIM_HEALTH, PRIM_HOLE_DEFAULT, PRIM_LINK_TARGET, PRIM_MATERIAL, PRIM_MATERIAL_STONE, PRIM_NAME, PRIM_NORMAL, PRIM_OMEGA, PRIM_PHANTOM, PRIM_PHYSICS, PRIM_PHYSICS_SHAPE_PRIM, PRIM_PHYSICS_SHAPE_TYPE, PRIM_POINT_LIGHT, PRIM_POSITION, PRIM_POS_LOCAL, PRIM_PROJECTOR, PRIM_REFLECTION_PROBE, PRIM_RENDER_MATERIAL, PRIM_ROTATION, PRIM_ROT_LOCAL, PRIM_SCRIPTED_SIT_ONLY, PRIM_SCULPT_TYPE_SPHERE, PRIM_SHINY_NONE, PRIM_SIT_FLAGS, PRIM_SIT_TARGET, PRIM_SIZE, PRIM_SLICE, PRIM_SPECULAR, PRIM_TEMP_ON_REZ, PRIM_TEXGEN, PRIM_TEXGEN_DEFAULT, PRIM_TEXT, PRIM_TEXTURE, PRIM_TYPE, PRIM_TYPE_BOX, PRIM_TYPE_CYLINDER, PRIM_TYPE_PRISM, PRIM_TYPE_RING, PRIM_TYPE_SCULPT, PRIM_TYPE_SPHERE, PRIM_TYPE_TORUS, PRIM_TYPE_TUBE, STATUS_PHANTOM, STATUS_PHYSICS, TEXTURE_DEFAULT, } from './generated/constants.js';
2
- import { NULL_KEY } from './values/types.js';
1
+ import { ALL_SIDES, CLICK_ACTION_TOUCH, PRIM_ALPHA_MODE, PRIM_ALPHA_MODE_NONE, PRIM_ALLOW_UNSIT, PRIM_BUMP_NONE, PRIM_BUMP_SHINY, PRIM_CAST_SHADOWS, PRIM_CLICK_ACTION, PRIM_COLOR, PRIM_DAMAGE, PRIM_DESC, PRIM_FLEXIBLE, PRIM_FULLBRIGHT, PRIM_GLOW, PRIM_GLTF_ALPHA_MODE_OPAQUE, PRIM_GLTF_BASE_COLOR, PRIM_GLTF_EMISSIVE, PRIM_GLTF_METALLIC_ROUGHNESS, PRIM_GLTF_NORMAL, PRIM_HEALTH, PRIM_HOLE_DEFAULT, PRIM_LINK_TARGET, PRIM_MATERIAL, PRIM_MATERIAL_WOOD, PRIM_NAME, PRIM_NORMAL, PRIM_OMEGA, PRIM_PHANTOM, PRIM_PHYSICS, PRIM_PHYSICS_SHAPE_PRIM, PRIM_PHYSICS_SHAPE_TYPE, PRIM_POINT_LIGHT, PRIM_POSITION, PRIM_POS_LOCAL, PRIM_PROJECTOR, PRIM_REFLECTION_PROBE, PRIM_RENDER_MATERIAL, PRIM_ROTATION, PRIM_ROT_LOCAL, PRIM_SCRIPTED_SIT_ONLY, PRIM_SCULPT_TYPE_SPHERE, PRIM_SHINY_NONE, PRIM_SIT_FLAGS, PRIM_SIT_TARGET, PRIM_SIZE, PRIM_SLICE, PRIM_SPECULAR, PRIM_TEMP_ON_REZ, PRIM_TEXGEN, PRIM_TEXGEN_DEFAULT, PRIM_TEXT, PRIM_TEXTURE, PRIM_TYPE, PRIM_TYPE_BOX, PRIM_TYPE_CYLINDER, PRIM_TYPE_PRISM, PRIM_TYPE_RING, PRIM_TYPE_SCULPT, PRIM_TYPE_SPHERE, PRIM_TYPE_TORUS, PRIM_TYPE_TUBE, STATUS_PHANTOM, STATUS_PHYSICS, TEXTURE_DEFAULT, } from './generated/constants.js';
2
+ import { NULL_KEY, isRotation, isVector } from './values/types.js';
3
+ import { listElementType } from './values/list-types.js';
4
+ import { truncateUtf8 } from './values/utf8.js';
3
5
  /**
4
- * Typed-literal aliases for the kwdb PRIM_TYPE_* constants. The
6
+ * Typed-literal aliases for the PRIM_TYPE_* constants. The
5
7
  * generated module exports them as `: number` so TS can't narrow on
6
8
  * them; we re-pin them to their literal values here. The `as` assertions
7
- * are runtime-asserted below so a future kwdb renumber would surface as
9
+ * are runtime-asserted below so a future upstream renumber would surface as
8
10
  * a load-time failure rather than silent corruption.
9
11
  */
10
12
  const SHAPE_BOX = PRIM_TYPE_BOX;
@@ -15,11 +17,16 @@ const SHAPE_TORUS = PRIM_TYPE_TORUS;
15
17
  const SHAPE_TUBE = PRIM_TYPE_TUBE;
16
18
  const SHAPE_RING = PRIM_TYPE_RING;
17
19
  const SHAPE_SCULPT = PRIM_TYPE_SCULPT;
18
- if (SHAPE_BOX !== 0 || SHAPE_CYLINDER !== 1 || SHAPE_PRISM !== 2 ||
19
- SHAPE_SPHERE !== 3 || SHAPE_TORUS !== 4 || SHAPE_TUBE !== 5 ||
20
- SHAPE_RING !== 6 || SHAPE_SCULPT !== 7) {
21
- throw new Error('kwdb PRIM_TYPE_* constants disagree with PrimShape literal aliases');
20
+ /** Throws unless `shapes` lists PRIM_TYPE_BOX..PRIM_TYPE_SCULPT as 0..7 in order. */
21
+ export function assertShapeAliases(shapes) {
22
+ if (shapes.length !== 8 || shapes.some((v, i) => v !== i)) {
23
+ throw new Error('PRIM_TYPE_* constants disagree with PrimShape literal aliases');
24
+ }
22
25
  }
26
+ assertShapeAliases([
27
+ SHAPE_BOX, SHAPE_CYLINDER, SHAPE_PRISM, SHAPE_SPHERE,
28
+ SHAPE_TORUS, SHAPE_TUBE, SHAPE_RING, SHAPE_SCULPT,
29
+ ]);
23
30
  const zero = () => ({ x: 0, y: 0, z: 0 });
24
31
  const one = () => ({ x: 1, y: 1, z: 1 });
25
32
  const identityRot = () => ({ x: 0, y: 0, z: 0, s: 1 });
@@ -75,7 +82,7 @@ export function defaultPrimParams() {
75
82
  sculpt: { textureKey: '', type: PRIM_SCULPT_TYPE_SPHERE },
76
83
  slice: { x: 0, y: 1, z: 0 },
77
84
  shape: defaultShape(),
78
- material: PRIM_MATERIAL_STONE,
85
+ material: PRIM_MATERIAL_WOOD,
79
86
  tempOnRez: false,
80
87
  castShadows: false,
81
88
  allowUnsit: true,
@@ -87,7 +94,7 @@ export function defaultPrimParams() {
87
94
  damage: { amount: 0, type: 0 },
88
95
  health: 1,
89
96
  reflectionProbe: { enabled: false, ambiance: 0, clipDistance: 0, flags: 0 },
90
- physicsMaterial: { gravityMultiplier: 1, restitution: 0, friction: 0, density: 1000 },
97
+ physicsMaterial: { gravityMultiplier: 1, restitution: 0.5, friction: Math.fround(0.6), density: 1000 },
91
98
  textureAnim: { mode: 0, face: 0, sizex: 0, sizey: 0, start: 0, length: 0, rate: 0 },
92
99
  passCollisions: 0,
93
100
  passTouches: 0,
@@ -113,15 +120,21 @@ const asRot = (v) => {
113
120
  return identityRot();
114
121
  };
115
122
  const toByteChannel = (c) => Math.floor(Math.min(1, Math.max(0, c)) * 255) / 255;
116
- function facesOf(faceArg) {
117
- const f = num(faceArg, 0) | 0;
118
- if (f === ALL_SIDES)
119
- return [0, 1, 2, 3, 4, 5];
120
- return [f];
123
+ const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
124
+ const clampVec = (v, lo, hi) => ({ x: clamp(v.x, lo, hi), y: clamp(v.y, lo, hi), z: clamp(v.z, lo, hi) });
125
+ function normalizeRot(r) {
126
+ const mag = Math.hypot(r.x, r.y, r.z, r.s);
127
+ if (mag === 0)
128
+ return identityRot();
129
+ return { x: r.x / mag, y: r.y / mag, z: r.z / mag, s: r.s / mag };
121
130
  }
122
- function inRange(face) {
123
- return face >= 0 && face <= 5;
131
+ /** Face indexes a face argument names: every face for ALL_SIDES, none past the shape's face count. */
132
+ export function faceIndices(p, face) {
133
+ if (face === ALL_SIDES)
134
+ return p.faces.map((_, i) => i);
135
+ return face >= 0 && face < p.faces.length ? [face] : [];
124
136
  }
137
+ const facesOf = (p, faceArg) => faceIndices(p, num(faceArg, 0) | 0);
125
138
  /**
126
139
  * Slot count for a PRIM_* rule's *write* form, given the rule constant
127
140
  * and (for variable-shape rules like PRIM_TYPE) the rules list + cursor
@@ -205,14 +218,14 @@ export function writePrimParam(prim, param, rules, cursor) {
205
218
  const p = prim.params;
206
219
  switch (param) {
207
220
  case PRIM_NAME:
208
- prim.name = str(rules[cursor]);
221
+ prim.name = truncateUtf8(str(rules[cursor]), 63);
209
222
  return 1;
210
223
  case PRIM_DESC:
211
- prim.description = str(rules[cursor]);
224
+ prim.description = truncateUtf8(str(rules[cursor]), 127);
212
225
  prim.appearance.description = prim.description;
213
226
  return 1;
214
227
  case PRIM_TEXT: {
215
- const text = str(rules[cursor]);
228
+ const text = truncateUtf8(str(rules[cursor]), 254);
216
229
  const color = asVec(rules[cursor + 1]);
217
230
  const alpha = num(rules[cursor + 2], 1);
218
231
  prim.appearance.text = { text, color, alpha };
@@ -224,10 +237,10 @@ export function writePrimParam(prim, param, rules, cursor) {
224
237
  return 1;
225
238
  case PRIM_ROTATION:
226
239
  case PRIM_ROT_LOCAL:
227
- p.rotation = asRot(rules[cursor]);
240
+ p.rotation = normalizeRot(asRot(rules[cursor]));
228
241
  return 1;
229
242
  case PRIM_SIZE:
230
- p.size = asVec(rules[cursor]);
243
+ p.size = clampVec(asVec(rules[cursor]), 0.01, 64);
231
244
  return 1;
232
245
  case PRIM_SLICE:
233
246
  p.slice = asVec(rules[cursor]);
@@ -317,27 +330,22 @@ export function writePrimParam(prim, param, rules, cursor) {
317
330
  case PRIM_TYPE:
318
331
  return writePrimType(p, rules, cursor);
319
332
  case PRIM_COLOR: {
320
- const faces = facesOf(rules[cursor]);
333
+ const faces = facesOf(p, rules[cursor]);
321
334
  const color = asVec(rules[cursor + 1]);
322
- const alpha = num(rules[cursor + 2], 1);
335
+ const alpha = clamp(num(rules[cursor + 2], 1), 0, 1);
323
336
  for (const f of faces) {
324
- if (!inRange(f))
325
- continue;
326
- // Clone so faces don't alias the same vector instance.
327
- p.faces[f].color = { x: color.x, y: color.y, z: color.z };
337
+ p.faces[f].color = clampVec(color, 0, 1);
328
338
  p.faces[f].alpha = alpha;
329
339
  }
330
340
  return 3;
331
341
  }
332
342
  case PRIM_TEXTURE: {
333
- const faces = facesOf(rules[cursor]);
343
+ const faces = facesOf(p, rules[cursor]);
334
344
  const tex = str(rules[cursor + 1]);
335
345
  const repeats = asVec(rules[cursor + 2]);
336
346
  const offsets = asVec(rules[cursor + 3]);
337
347
  const rot = num(rules[cursor + 4]);
338
348
  for (const f of faces) {
339
- if (!inRange(f))
340
- continue;
341
349
  p.faces[f].texture = tex;
342
350
  p.faces[f].textureRepeats = { x: repeats.x, y: repeats.y, z: repeats.z };
343
351
  p.faces[f].textureOffsets = { x: offsets.x, y: offsets.y, z: offsets.z };
@@ -346,66 +354,54 @@ export function writePrimParam(prim, param, rules, cursor) {
346
354
  return 5;
347
355
  }
348
356
  case PRIM_RENDER_MATERIAL: {
349
- const faces = facesOf(rules[cursor]);
357
+ const faces = facesOf(p, rules[cursor]);
350
358
  const m = str(rules[cursor + 1]);
351
359
  for (const f of faces) {
352
- if (!inRange(f))
353
- continue;
354
360
  p.faces[f].renderMaterial = m;
355
361
  }
356
362
  return 2;
357
363
  }
358
364
  case PRIM_FULLBRIGHT: {
359
- const faces = facesOf(rules[cursor]);
365
+ const faces = facesOf(p, rules[cursor]);
360
366
  const v = num(rules[cursor + 1]) !== 0;
361
367
  for (const f of faces) {
362
- if (!inRange(f))
363
- continue;
364
368
  p.faces[f].fullBright = v;
365
369
  }
366
370
  return 2;
367
371
  }
368
372
  case PRIM_GLOW: {
369
- const faces = facesOf(rules[cursor]);
373
+ const faces = facesOf(p, rules[cursor]);
370
374
  const v = num(rules[cursor + 1]);
371
375
  for (const f of faces) {
372
- if (!inRange(f))
373
- continue;
374
376
  p.faces[f].glow = v;
375
377
  p.glow[f] = v;
376
378
  }
377
379
  return 2;
378
380
  }
379
381
  case PRIM_BUMP_SHINY: {
380
- const faces = facesOf(rules[cursor]);
382
+ const faces = facesOf(p, rules[cursor]);
381
383
  const shiny = num(rules[cursor + 1]) | 0;
382
384
  const bump = num(rules[cursor + 2]) | 0;
383
385
  for (const f of faces) {
384
- if (!inRange(f))
385
- continue;
386
386
  p.faces[f].bumpShiny = { shiny, bump };
387
387
  }
388
388
  return 3;
389
389
  }
390
390
  case PRIM_TEXGEN: {
391
- const faces = facesOf(rules[cursor]);
391
+ const faces = facesOf(p, rules[cursor]);
392
392
  const mode = num(rules[cursor + 1]) | 0;
393
393
  for (const f of faces) {
394
- if (!inRange(f))
395
- continue;
396
394
  p.faces[f].texgen = mode;
397
395
  }
398
396
  return 2;
399
397
  }
400
398
  case PRIM_NORMAL: {
401
- const faces = facesOf(rules[cursor]);
399
+ const faces = facesOf(p, rules[cursor]);
402
400
  const tex = str(rules[cursor + 1]);
403
401
  const repeats = asVec(rules[cursor + 2]);
404
402
  const offsets = asVec(rules[cursor + 3]);
405
403
  const rot = num(rules[cursor + 4]);
406
404
  for (const f of faces) {
407
- if (!inRange(f))
408
- continue;
409
405
  p.faces[f].normal = {
410
406
  texture: tex,
411
407
  textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
@@ -416,7 +412,7 @@ export function writePrimParam(prim, param, rules, cursor) {
416
412
  return 5;
417
413
  }
418
414
  case PRIM_SPECULAR: {
419
- const faces = facesOf(rules[cursor]);
415
+ const faces = facesOf(p, rules[cursor]);
420
416
  const tex = str(rules[cursor + 1]);
421
417
  const repeats = asVec(rules[cursor + 2]);
422
418
  const offsets = asVec(rules[cursor + 3]);
@@ -425,8 +421,6 @@ export function writePrimParam(prim, param, rules, cursor) {
425
421
  const gloss = num(rules[cursor + 6]) | 0;
426
422
  const env = num(rules[cursor + 7]) | 0;
427
423
  for (const f of faces) {
428
- if (!inRange(f))
429
- continue;
430
424
  p.faces[f].specular = {
431
425
  texture: tex,
432
426
  textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
@@ -441,18 +435,16 @@ export function writePrimParam(prim, param, rules, cursor) {
441
435
  return 8;
442
436
  }
443
437
  case PRIM_ALPHA_MODE: {
444
- const faces = facesOf(rules[cursor]);
438
+ const faces = facesOf(p, rules[cursor]);
445
439
  const mode = num(rules[cursor + 1]) | 0;
446
440
  const cutoff = num(rules[cursor + 2]) | 0;
447
441
  for (const f of faces) {
448
- if (!inRange(f))
449
- continue;
450
442
  p.faces[f].alphaMode = { mode, cutoff };
451
443
  }
452
444
  return 3;
453
445
  }
454
446
  case PRIM_GLTF_BASE_COLOR: {
455
- const faces = facesOf(rules[cursor]);
447
+ const faces = facesOf(p, rules[cursor]);
456
448
  const tex = str(rules[cursor + 1]);
457
449
  const repeats = asVec(rules[cursor + 2]);
458
450
  const offsets = asVec(rules[cursor + 3]);
@@ -463,8 +455,6 @@ export function writePrimParam(prim, param, rules, cursor) {
463
455
  const aCut = num(rules[cursor + 8]);
464
456
  const dbl = num(rules[cursor + 9]) | 0;
465
457
  for (const f of faces) {
466
- if (!inRange(f))
467
- continue;
468
458
  p.faces[f].gltf.baseColor = {
469
459
  texture: tex,
470
460
  textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
@@ -480,14 +470,12 @@ export function writePrimParam(prim, param, rules, cursor) {
480
470
  return 10;
481
471
  }
482
472
  case PRIM_GLTF_NORMAL: {
483
- const faces = facesOf(rules[cursor]);
473
+ const faces = facesOf(p, rules[cursor]);
484
474
  const tex = str(rules[cursor + 1]);
485
475
  const repeats = asVec(rules[cursor + 2]);
486
476
  const offsets = asVec(rules[cursor + 3]);
487
477
  const rot = num(rules[cursor + 4]);
488
478
  for (const f of faces) {
489
- if (!inRange(f))
490
- continue;
491
479
  p.faces[f].gltf.normal = {
492
480
  texture: tex,
493
481
  textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
@@ -498,7 +486,7 @@ export function writePrimParam(prim, param, rules, cursor) {
498
486
  return 5;
499
487
  }
500
488
  case PRIM_GLTF_METALLIC_ROUGHNESS: {
501
- const faces = facesOf(rules[cursor]);
489
+ const faces = facesOf(p, rules[cursor]);
502
490
  const tex = str(rules[cursor + 1]);
503
491
  const repeats = asVec(rules[cursor + 2]);
504
492
  const offsets = asVec(rules[cursor + 3]);
@@ -506,8 +494,6 @@ export function writePrimParam(prim, param, rules, cursor) {
506
494
  const metallic = num(rules[cursor + 5]);
507
495
  const rough = num(rules[cursor + 6]);
508
496
  for (const f of faces) {
509
- if (!inRange(f))
510
- continue;
511
497
  p.faces[f].gltf.metallicRoughness = {
512
498
  texture: tex,
513
499
  textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
@@ -520,15 +506,13 @@ export function writePrimParam(prim, param, rules, cursor) {
520
506
  return 7;
521
507
  }
522
508
  case PRIM_GLTF_EMISSIVE: {
523
- const faces = facesOf(rules[cursor]);
509
+ const faces = facesOf(p, rules[cursor]);
524
510
  const tex = str(rules[cursor + 1]);
525
511
  const repeats = asVec(rules[cursor + 2]);
526
512
  const offsets = asVec(rules[cursor + 3]);
527
513
  const rot = num(rules[cursor + 4]);
528
514
  const tint = asVec(rules[cursor + 5]);
529
515
  for (const f of faces) {
530
- if (!inRange(f))
531
- continue;
532
516
  p.faces[f].gltf.emissive = {
533
517
  texture: tex,
534
518
  textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
@@ -547,6 +531,7 @@ export function writePrimParam(prim, param, rules, cursor) {
547
531
  }
548
532
  function writePrimType(p, rules, cursor) {
549
533
  const kind = (num(rules[cursor]) | 0);
534
+ const old = p.shape;
550
535
  switch (kind) {
551
536
  case SHAPE_BOX:
552
537
  case SHAPE_CYLINDER:
@@ -560,7 +545,7 @@ function writePrimType(p, rules, cursor) {
560
545
  topSize: asVec(rules[cursor + 5]),
561
546
  topShear: asVec(rules[cursor + 6]),
562
547
  };
563
- return 7;
548
+ break;
564
549
  case SHAPE_SPHERE:
565
550
  p.shape = {
566
551
  kind: SHAPE_SPHERE,
@@ -570,7 +555,7 @@ function writePrimType(p, rules, cursor) {
570
555
  twist: asVec(rules[cursor + 4]),
571
556
  dimple: asVec(rules[cursor + 5]),
572
557
  };
573
- return 6;
558
+ break;
574
559
  case SHAPE_TORUS:
575
560
  case SHAPE_TUBE:
576
561
  case SHAPE_RING:
@@ -588,14 +573,14 @@ function writePrimType(p, rules, cursor) {
588
573
  radiusOffset: num(rules[cursor + 10]),
589
574
  skew: num(rules[cursor + 11]),
590
575
  };
591
- return 12;
576
+ break;
592
577
  case SHAPE_SCULPT:
593
578
  p.shape = {
594
579
  kind: SHAPE_SCULPT,
595
580
  map: str(rules[cursor + 1]),
596
581
  type: num(rules[cursor + 2]) | 0,
597
582
  };
598
- return 3;
583
+ break;
599
584
  default:
600
585
  // Unknown PRIM_TYPE_* kind: terminate the walk rather than guessing
601
586
  // a slot count. Matches writePrimParamSlots' default behavior so
@@ -603,6 +588,8 @@ function writePrimType(p, rules, cursor) {
603
588
  // same way.
604
589
  return null;
605
590
  }
591
+ remapFaces(p, old);
592
+ return writePrimParamSlots(PRIM_TYPE, rules, cursor);
606
593
  }
607
594
  /**
608
595
  * Read a single PRIM_* rule, returning the flat values it expands to and
@@ -622,6 +609,7 @@ export function readPrimParam(prim, param, rules, cursor) {
622
609
  return { values: t ? [t.text, t.color, t.alpha] : ['', zero(), 0], consumed: 0 };
623
610
  }
624
611
  case PRIM_POSITION:
612
+ return { values: [prim.regionPosition()], consumed: 0 };
625
613
  case PRIM_POS_LOCAL:
626
614
  return { values: [p.position], consumed: 0 };
627
615
  case PRIM_ROTATION:
@@ -683,147 +671,119 @@ export function readPrimParam(prim, param, rules, cursor) {
683
671
  case PRIM_TYPE:
684
672
  return { values: readPrimType(p), consumed: 0 };
685
673
  case PRIM_COLOR: {
686
- const faces = facesOf(rules[cursor]);
674
+ const faces = facesOf(p, rules[cursor]);
687
675
  const out = [];
688
676
  for (const f of faces) {
689
- if (!inRange(f))
690
- continue;
691
677
  out.push(p.faces[f].color, p.faces[f].alpha);
692
678
  }
693
679
  return { values: out, consumed: 1 };
694
680
  }
695
681
  case PRIM_TEXTURE: {
696
- const faces = facesOf(rules[cursor]);
682
+ const faces = facesOf(p, rules[cursor]);
697
683
  const out = [];
698
684
  for (const f of faces) {
699
- if (!inRange(f))
700
- continue;
701
685
  const fa = p.faces[f];
702
686
  out.push(fa.texture, fa.textureRepeats, fa.textureOffsets, fa.textureRotation);
703
687
  }
704
688
  return { values: out, consumed: 1 };
705
689
  }
706
690
  case PRIM_RENDER_MATERIAL: {
707
- const faces = facesOf(rules[cursor]);
691
+ const faces = facesOf(p, rules[cursor]);
708
692
  const out = [];
709
693
  for (const f of faces) {
710
- if (!inRange(f))
711
- continue;
712
694
  out.push(p.faces[f].renderMaterial);
713
695
  }
714
696
  return { values: out, consumed: 1 };
715
697
  }
716
698
  case PRIM_FULLBRIGHT: {
717
- const faces = facesOf(rules[cursor]);
699
+ const faces = facesOf(p, rules[cursor]);
718
700
  const out = [];
719
701
  for (const f of faces) {
720
- if (!inRange(f))
721
- continue;
722
702
  out.push(p.faces[f].fullBright ? 1 : 0);
723
703
  }
724
704
  return { values: out, consumed: 1 };
725
705
  }
726
706
  case PRIM_GLOW: {
727
- const faces = facesOf(rules[cursor]);
707
+ const faces = facesOf(p, rules[cursor]);
728
708
  const out = [];
729
709
  for (const f of faces) {
730
- if (!inRange(f))
731
- continue;
732
710
  out.push(p.faces[f].glow);
733
711
  }
734
712
  return { values: out, consumed: 1 };
735
713
  }
736
714
  case PRIM_BUMP_SHINY: {
737
- const faces = facesOf(rules[cursor]);
715
+ const faces = facesOf(p, rules[cursor]);
738
716
  const out = [];
739
717
  for (const f of faces) {
740
- if (!inRange(f))
741
- continue;
742
718
  out.push(p.faces[f].bumpShiny.shiny, p.faces[f].bumpShiny.bump);
743
719
  }
744
720
  return { values: out, consumed: 1 };
745
721
  }
746
722
  case PRIM_TEXGEN: {
747
- const faces = facesOf(rules[cursor]);
723
+ const faces = facesOf(p, rules[cursor]);
748
724
  const out = [];
749
725
  for (const f of faces) {
750
- if (!inRange(f))
751
- continue;
752
726
  out.push(p.faces[f].texgen);
753
727
  }
754
728
  return { values: out, consumed: 1 };
755
729
  }
756
730
  case PRIM_NORMAL: {
757
- const faces = facesOf(rules[cursor]);
731
+ const faces = facesOf(p, rules[cursor]);
758
732
  const out = [];
759
733
  for (const f of faces) {
760
- if (!inRange(f))
761
- continue;
762
734
  const n = p.faces[f].normal;
763
735
  out.push(n.texture, n.textureRepeats, n.textureOffsets, n.textureRotation);
764
736
  }
765
737
  return { values: out, consumed: 1 };
766
738
  }
767
739
  case PRIM_SPECULAR: {
768
- const faces = facesOf(rules[cursor]);
740
+ const faces = facesOf(p, rules[cursor]);
769
741
  const out = [];
770
742
  for (const f of faces) {
771
- if (!inRange(f))
772
- continue;
773
743
  const s = p.faces[f].specular;
774
744
  out.push(s.texture, s.textureRepeats, s.textureOffsets, s.textureRotation, s.color, s.glossiness, s.environment);
775
745
  }
776
746
  return { values: out, consumed: 1 };
777
747
  }
778
748
  case PRIM_ALPHA_MODE: {
779
- const faces = facesOf(rules[cursor]);
749
+ const faces = facesOf(p, rules[cursor]);
780
750
  const out = [];
781
751
  for (const f of faces) {
782
- if (!inRange(f))
783
- continue;
784
752
  out.push(p.faces[f].alphaMode.mode, p.faces[f].alphaMode.cutoff);
785
753
  }
786
754
  return { values: out, consumed: 1 };
787
755
  }
788
756
  case PRIM_GLTF_BASE_COLOR: {
789
- const faces = facesOf(rules[cursor]);
757
+ const faces = facesOf(p, rules[cursor]);
790
758
  const out = [];
791
759
  for (const f of faces) {
792
- if (!inRange(f))
793
- continue;
794
760
  const g = p.faces[f].gltf.baseColor;
795
761
  out.push(g.texture, g.textureRepeats, g.textureOffsets, g.textureRotation, g.color, g.alpha, g.alphaMode, g.alphaCutoff, g.doubleSided);
796
762
  }
797
763
  return { values: out, consumed: 1 };
798
764
  }
799
765
  case PRIM_GLTF_NORMAL: {
800
- const faces = facesOf(rules[cursor]);
766
+ const faces = facesOf(p, rules[cursor]);
801
767
  const out = [];
802
768
  for (const f of faces) {
803
- if (!inRange(f))
804
- continue;
805
769
  const g = p.faces[f].gltf.normal;
806
770
  out.push(g.texture, g.textureRepeats, g.textureOffsets, g.textureRotation);
807
771
  }
808
772
  return { values: out, consumed: 1 };
809
773
  }
810
774
  case PRIM_GLTF_METALLIC_ROUGHNESS: {
811
- const faces = facesOf(rules[cursor]);
775
+ const faces = facesOf(p, rules[cursor]);
812
776
  const out = [];
813
777
  for (const f of faces) {
814
- if (!inRange(f))
815
- continue;
816
778
  const g = p.faces[f].gltf.metallicRoughness;
817
779
  out.push(g.texture, g.textureRepeats, g.textureOffsets, g.textureRotation, g.metallic, g.roughness);
818
780
  }
819
781
  return { values: out, consumed: 1 };
820
782
  }
821
783
  case PRIM_GLTF_EMISSIVE: {
822
- const faces = facesOf(rules[cursor]);
784
+ const faces = facesOf(p, rules[cursor]);
823
785
  const out = [];
824
786
  for (const f of faces) {
825
- if (!inRange(f))
826
- continue;
827
787
  const g = p.faces[f].gltf.emissive;
828
788
  out.push(g.texture, g.textureRepeats, g.textureOffsets, g.textureRotation, g.tint);
829
789
  }
@@ -916,4 +876,129 @@ export function primParamTypes(param, values) {
916
876
  const pattern = param === PRIM_TYPE ? primTypeTypes(values[0]) : (PRIM_PARAM_TYPES[param] ?? []);
917
877
  return values.map((_, i) => pattern[i % pattern.length]);
918
878
  }
879
+ const PER_FACE_RULES = new Set([
880
+ PRIM_COLOR, PRIM_TEXTURE, PRIM_RENDER_MATERIAL, PRIM_FULLBRIGHT, PRIM_GLOW, PRIM_BUMP_SHINY,
881
+ PRIM_TEXGEN, PRIM_NORMAL, PRIM_SPECULAR, PRIM_ALPHA_MODE, PRIM_GLTF_BASE_COLOR,
882
+ PRIM_GLTF_NORMAL, PRIM_GLTF_METALLIC_ROUGHNESS, PRIM_GLTF_EMISSIVE,
883
+ ]);
884
+ const RULE_CONSTANTS = {
885
+ PRIM_NAME, PRIM_DESC, PRIM_TEXT, PRIM_POSITION, PRIM_POS_LOCAL, PRIM_ROTATION, PRIM_ROT_LOCAL,
886
+ PRIM_SIZE, PRIM_SLICE, PRIM_MATERIAL, PRIM_PHYSICS, PRIM_PHANTOM, PRIM_TEMP_ON_REZ,
887
+ PRIM_PHYSICS_SHAPE_TYPE, PRIM_CAST_SHADOWS, PRIM_ALLOW_UNSIT, PRIM_SCRIPTED_SIT_ONLY,
888
+ PRIM_SIT_FLAGS, PRIM_CLICK_ACTION, PRIM_HEALTH, PRIM_DAMAGE, PRIM_OMEGA, PRIM_POINT_LIGHT,
889
+ PRIM_REFLECTION_PROBE, PRIM_PROJECTOR, PRIM_FLEXIBLE, PRIM_SIT_TARGET, PRIM_TYPE, PRIM_COLOR,
890
+ PRIM_TEXTURE, PRIM_RENDER_MATERIAL, PRIM_FULLBRIGHT, PRIM_GLOW, PRIM_BUMP_SHINY, PRIM_TEXGEN,
891
+ PRIM_NORMAL, PRIM_SPECULAR, PRIM_ALPHA_MODE, PRIM_GLTF_BASE_COLOR, PRIM_GLTF_NORMAL,
892
+ PRIM_GLTF_METALLIC_ROUGHNESS, PRIM_GLTF_EMISSIVE,
893
+ };
894
+ const RULE_NAMES = new Map(Object.entries(RULE_CONSTANTS).map(([name, value]) => [value, name]));
895
+ function givenType(rules, index) {
896
+ const known = listElementType(rules, index);
897
+ if (known)
898
+ return known;
899
+ const v = rules[index];
900
+ if (typeof v === 'string')
901
+ return 'string';
902
+ if (typeof v === 'number')
903
+ return Number.isInteger(v) ? 'integer' : 'float';
904
+ if (isRotation(v))
905
+ return 'rotation';
906
+ if (isVector(v))
907
+ return 'vector';
908
+ return 'list';
909
+ }
910
+ function typeAccepts(expected, given) {
911
+ if (expected === given)
912
+ return true;
913
+ const numeric = (t) => t === 'integer' || t === 'float';
914
+ const text = (t) => t === 'string' || t === 'key';
915
+ return (numeric(expected) && numeric(given)) || (text(expected) && text(given));
916
+ }
917
+ /** `%g`-style number text, as the simulator prints it in error messages. */
918
+ const formatG = (v) => String(Number(v.toPrecision(6)));
919
+ /**
920
+ * Check one PRIM_* rule of a set call before it is applied. Returns null if
921
+ * the rule can run, otherwise the error text that follows "rule #N" in the
922
+ * simulator's message (e.g. " (PRIM_SIZE): arg #1 vector expected but string given").
923
+ */
924
+ /** GLTF override rules take "" in any slot after the face to mean "no override". */
925
+ const GLTF_RULES = new Set([PRIM_GLTF_BASE_COLOR, PRIM_GLTF_NORMAL, PRIM_GLTF_METALLIC_ROUGHNESS, PRIM_GLTF_EMISSIVE]);
926
+ export function checkPrimRule(param, rules, cursor) {
927
+ const name = RULE_NAMES.get(param);
928
+ if (name === undefined || writePrimParamSlots(param, rules, cursor) === null)
929
+ return ': unknown rule';
930
+ const pattern = param === PRIM_TYPE ? primTypeTypes(rules[cursor]) : PRIM_PARAM_TYPES[param];
931
+ const expected = PER_FACE_RULES.has(param) ? ['integer', ...pattern] : pattern;
932
+ for (let i = 0; i < expected.length; i++) {
933
+ if (cursor + i >= rules.length)
934
+ break;
935
+ if (i > 0 && GLTF_RULES.has(param) && rules[cursor + i] === '')
936
+ continue;
937
+ const given = givenType(rules, cursor + i);
938
+ if (!typeAccepts(expected[i], given)) {
939
+ return ` (${name}): arg #${i + 1} ${expected[i]} expected but ${given} given`;
940
+ }
941
+ }
942
+ if (param === PRIM_GLOW) {
943
+ const glow = num(rules[cursor + 1]);
944
+ if (glow < 0 || glow > 1)
945
+ return ` (${name}): bounds error; ${formatG(glow)} is not in (0, 1)`;
946
+ }
947
+ return null;
948
+ }
949
+ const PROFILE_SIDES = {
950
+ [SHAPE_BOX]: 4, [SHAPE_CYLINDER]: 1, [SHAPE_PRISM]: 3, [SHAPE_SPHERE]: 1,
951
+ [SHAPE_TORUS]: 1, [SHAPE_TUBE]: 4, [SHAPE_RING]: 3,
952
+ };
953
+ const isCut = (range) => range.x > 0 || range.y < 1;
954
+ function faceRoles(shape) {
955
+ if (shape.kind === SHAPE_SCULPT)
956
+ return [{ from: 0, to: 1 }];
957
+ const looped = shape.kind === SHAPE_TORUS || shape.kind === SHAPE_TUBE || shape.kind === SHAPE_RING;
958
+ const profileCut = looped ? shape.advancedCut : shape.cut;
959
+ const pathEnds = shape.kind === SHAPE_SPHERE
960
+ ? isCut(shape.dimple) || shape.hollow > 0
961
+ : !looped || isCut(shape.cut);
962
+ const sides = PROFILE_SIDES[shape.kind];
963
+ const roles = pathEnds ? ['top'] : [];
964
+ for (let i = 0; i < sides; i++) {
965
+ const from = i / sides, to = (i + 1) / sides;
966
+ if (from < profileCut.y && to > profileCut.x)
967
+ roles.push({ from, to });
968
+ }
969
+ if (shape.hollow > 0)
970
+ roles.push('inner');
971
+ if (pathEnds)
972
+ roles.push('bottom');
973
+ if (isCut(profileCut))
974
+ roles.push('cutStart', 'cutEnd');
975
+ return roles;
976
+ }
977
+ /**
978
+ * Rebuild the face slots for a new shape. A face keeps the values of the old
979
+ * face with the same role; an outer side takes the first old outer side it
980
+ * overlaps, else the nearest one; any other new face copies the old last face.
981
+ */
982
+ function remapFaces(p, oldShape) {
983
+ const oldRoles = faceRoles(oldShape);
984
+ const old = p.faces;
985
+ const last = old[old.length - 1];
986
+ const oldOuter = oldRoles.flatMap((r, i) => (typeof r === 'string' ? [] : [{ ...r, face: old[i] }]));
987
+ const source = (role) => {
988
+ if (typeof role === 'string')
989
+ return old[oldRoles.indexOf(role)] ?? last;
990
+ const gap = (o) => Math.max(o.from - role.to, role.from - o.to);
991
+ const overlap = oldOuter.find((o) => gap(o) < 0);
992
+ if (overlap)
993
+ return overlap.face;
994
+ const nearest = oldOuter.reduce((a, o) => (!a || gap(o) < gap(a) ? o : a), undefined);
995
+ return nearest?.face ?? last;
996
+ };
997
+ p.faces = faceRoles(p.shape).map((role) => structuredClone(source(role)));
998
+ p.glow = p.faces.map((f) => f.glow);
999
+ }
1000
+ /** Face count of a prim shape, as llGetNumberOfSides reports it. */
1001
+ export function numberOfSides(shape) {
1002
+ return faceRoles(shape).length;
1003
+ }
919
1004
  //# sourceMappingURL=prim-params.js.map