quake2ts 0.0.7 → 0.0.39

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 (177) hide show
  1. package/README.md +425 -0
  2. package/apps/viewer/dist/browser/index.global.js +1 -1
  3. package/apps/viewer/dist/browser/index.global.js.map +1 -1
  4. package/apps/viewer/dist/cjs/index.cjs +2097 -295
  5. package/apps/viewer/dist/cjs/index.cjs.map +1 -1
  6. package/apps/viewer/dist/esm/index.js +2097 -295
  7. package/apps/viewer/dist/esm/index.js.map +1 -1
  8. package/apps/viewer/dist/tsconfig.tsbuildinfo +1 -1
  9. package/apps/viewer/dist/types/index.d.ts +1 -1
  10. package/package.json +1 -1
  11. package/packages/client/dist/browser/index.global.js +1 -1
  12. package/packages/client/dist/browser/index.global.js.map +1 -1
  13. package/packages/client/dist/cjs/index.cjs +1200 -13
  14. package/packages/client/dist/cjs/index.cjs.map +1 -1
  15. package/packages/client/dist/esm/index.js +1186 -12
  16. package/packages/client/dist/esm/index.js.map +1 -1
  17. package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
  18. package/packages/client/dist/types/index.d.ts +14 -6
  19. package/packages/client/dist/types/index.d.ts.map +1 -1
  20. package/packages/client/dist/types/input/bindings.d.ts +18 -0
  21. package/packages/client/dist/types/input/bindings.d.ts.map +1 -0
  22. package/packages/client/dist/types/input/command-buffer.d.ts +15 -0
  23. package/packages/client/dist/types/input/command-buffer.d.ts.map +1 -0
  24. package/packages/client/dist/types/input/controller.d.ts +125 -0
  25. package/packages/client/dist/types/input/controller.d.ts.map +1 -0
  26. package/packages/client/dist/types/prediction.d.ts +38 -0
  27. package/packages/client/dist/types/prediction.d.ts.map +1 -0
  28. package/packages/client/dist/types/view-effects.d.ts +41 -0
  29. package/packages/client/dist/types/view-effects.d.ts.map +1 -0
  30. package/packages/engine/dist/browser/index.global.js +257 -1
  31. package/packages/engine/dist/browser/index.global.js.map +1 -1
  32. package/packages/engine/dist/cjs/index.cjs +2408 -2
  33. package/packages/engine/dist/cjs/index.cjs.map +1 -1
  34. package/packages/engine/dist/esm/index.js +2340 -2
  35. package/packages/engine/dist/esm/index.js.map +1 -1
  36. package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
  37. package/packages/engine/dist/types/assets/animation.d.ts +33 -0
  38. package/packages/engine/dist/types/assets/animation.d.ts.map +1 -0
  39. package/packages/engine/dist/types/assets/audio.d.ts +21 -0
  40. package/packages/engine/dist/types/assets/audio.d.ts.map +1 -0
  41. package/packages/engine/dist/types/assets/bsp.d.ts +1 -1
  42. package/packages/engine/dist/types/assets/bsp.d.ts.map +1 -1
  43. package/packages/engine/dist/types/assets/ingestion.d.ts +31 -0
  44. package/packages/engine/dist/types/assets/ingestion.d.ts.map +1 -1
  45. package/packages/engine/dist/types/assets/manager.d.ts +43 -0
  46. package/packages/engine/dist/types/assets/manager.d.ts.map +1 -0
  47. package/packages/engine/dist/types/assets/md3.d.ts +69 -0
  48. package/packages/engine/dist/types/assets/md3.d.ts.map +1 -0
  49. package/packages/engine/dist/types/assets/ogg.d.ts +12 -0
  50. package/packages/engine/dist/types/assets/ogg.d.ts.map +1 -0
  51. package/packages/engine/dist/types/assets/pakIndexStore.d.ts +19 -0
  52. package/packages/engine/dist/types/assets/pakIndexStore.d.ts.map +1 -0
  53. package/packages/engine/dist/types/assets/pakValidation.d.ts +28 -0
  54. package/packages/engine/dist/types/assets/pakValidation.d.ts.map +1 -0
  55. package/packages/engine/dist/types/assets/pcx.d.ts +13 -0
  56. package/packages/engine/dist/types/assets/pcx.d.ts.map +1 -0
  57. package/packages/engine/dist/types/assets/texture.d.ts +29 -0
  58. package/packages/engine/dist/types/assets/texture.d.ts.map +1 -0
  59. package/packages/engine/dist/types/assets/wal.d.ts +21 -0
  60. package/packages/engine/dist/types/assets/wal.d.ts.map +1 -0
  61. package/packages/engine/dist/types/assets/wav.d.ts +11 -0
  62. package/packages/engine/dist/types/assets/wav.d.ts.map +1 -0
  63. package/packages/engine/dist/types/audio/api.d.ts +29 -0
  64. package/packages/engine/dist/types/audio/api.d.ts.map +1 -0
  65. package/packages/engine/dist/types/audio/channels.d.ts +15 -0
  66. package/packages/engine/dist/types/audio/channels.d.ts.map +1 -0
  67. package/packages/engine/dist/types/audio/constants.d.ts +24 -0
  68. package/packages/engine/dist/types/audio/constants.d.ts.map +1 -0
  69. package/packages/engine/dist/types/audio/context.d.ts +67 -0
  70. package/packages/engine/dist/types/audio/context.d.ts.map +1 -0
  71. package/packages/engine/dist/types/audio/music.d.ts +42 -0
  72. package/packages/engine/dist/types/audio/music.d.ts.map +1 -0
  73. package/packages/engine/dist/types/audio/precache.d.ts +28 -0
  74. package/packages/engine/dist/types/audio/precache.d.ts.map +1 -0
  75. package/packages/engine/dist/types/audio/registry.d.ts +13 -0
  76. package/packages/engine/dist/types/audio/registry.d.ts.map +1 -0
  77. package/packages/engine/dist/types/audio/spatialization.d.ts +14 -0
  78. package/packages/engine/dist/types/audio/spatialization.d.ts.map +1 -0
  79. package/packages/engine/dist/types/audio/system.d.ts +101 -0
  80. package/packages/engine/dist/types/audio/system.d.ts.map +1 -0
  81. package/packages/engine/dist/types/configstrings.d.ts +1 -0
  82. package/packages/engine/dist/types/configstrings.d.ts.map +1 -1
  83. package/packages/engine/dist/types/index.d.ts +26 -1
  84. package/packages/engine/dist/types/index.d.ts.map +1 -1
  85. package/packages/engine/dist/types/render/bspPipeline.d.ts +42 -0
  86. package/packages/engine/dist/types/render/bspPipeline.d.ts.map +1 -0
  87. package/packages/engine/dist/types/render/bspTraversal.d.ts +11 -0
  88. package/packages/engine/dist/types/render/bspTraversal.d.ts.map +1 -0
  89. package/packages/engine/dist/types/render/culling.d.ts +8 -0
  90. package/packages/engine/dist/types/render/culling.d.ts.map +1 -0
  91. package/packages/engine/dist/types/render/md2Pipeline.d.ts +51 -0
  92. package/packages/engine/dist/types/render/md2Pipeline.d.ts.map +1 -0
  93. package/packages/engine/dist/types/render/resources.d.ts +10 -0
  94. package/packages/engine/dist/types/render/resources.d.ts.map +1 -1
  95. package/packages/engine/dist/types/render/skybox.d.ts +26 -0
  96. package/packages/engine/dist/types/render/skybox.d.ts.map +1 -0
  97. package/packages/game/dist/browser/index.global.js +1 -1
  98. package/packages/game/dist/browser/index.global.js.map +1 -1
  99. package/packages/game/dist/cjs/index.cjs +2926 -116
  100. package/packages/game/dist/cjs/index.cjs.map +1 -1
  101. package/packages/game/dist/esm/index.js +2863 -115
  102. package/packages/game/dist/esm/index.js.map +1 -1
  103. package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
  104. package/packages/game/dist/types/ai/constants.d.ts +13 -0
  105. package/packages/game/dist/types/ai/constants.d.ts.map +1 -0
  106. package/packages/game/dist/types/ai/index.d.ts +4 -0
  107. package/packages/game/dist/types/ai/index.d.ts.map +1 -0
  108. package/packages/game/dist/types/ai/movement.d.ts +20 -0
  109. package/packages/game/dist/types/ai/movement.d.ts.map +1 -0
  110. package/packages/game/dist/types/ai/perception.d.ts +21 -0
  111. package/packages/game/dist/types/ai/perception.d.ts.map +1 -0
  112. package/packages/game/dist/types/checksum.d.ts +3 -0
  113. package/packages/game/dist/types/checksum.d.ts.map +1 -0
  114. package/packages/game/dist/types/combat/armor.d.ts +39 -0
  115. package/packages/game/dist/types/combat/armor.d.ts.map +1 -0
  116. package/packages/game/dist/types/combat/damage.d.ts +52 -0
  117. package/packages/game/dist/types/combat/damage.d.ts.map +1 -0
  118. package/packages/game/dist/types/combat/damageFlags.d.ts +15 -0
  119. package/packages/game/dist/types/combat/damageFlags.d.ts.map +1 -0
  120. package/packages/game/dist/types/combat/damageMods.d.ts +79 -0
  121. package/packages/game/dist/types/combat/damageMods.d.ts.map +1 -0
  122. package/packages/game/dist/types/combat/index.d.ts +6 -0
  123. package/packages/game/dist/types/combat/index.d.ts.map +1 -0
  124. package/packages/game/dist/types/combat/specialDamage.d.ts +88 -0
  125. package/packages/game/dist/types/combat/specialDamage.d.ts.map +1 -0
  126. package/packages/game/dist/types/entities/entity.d.ts +46 -2
  127. package/packages/game/dist/types/entities/entity.d.ts.map +1 -1
  128. package/packages/game/dist/types/entities/index.d.ts +6 -2
  129. package/packages/game/dist/types/entities/index.d.ts.map +1 -1
  130. package/packages/game/dist/types/entities/pool.d.ts +9 -0
  131. package/packages/game/dist/types/entities/pool.d.ts.map +1 -1
  132. package/packages/game/dist/types/entities/spawn.d.ts +27 -0
  133. package/packages/game/dist/types/entities/spawn.d.ts.map +1 -0
  134. package/packages/game/dist/types/entities/system.d.ts +32 -1
  135. package/packages/game/dist/types/entities/system.d.ts.map +1 -1
  136. package/packages/game/dist/types/entities/thinkScheduler.d.ts +6 -0
  137. package/packages/game/dist/types/entities/thinkScheduler.d.ts.map +1 -1
  138. package/packages/game/dist/types/entities/triggers.d.ts +3 -0
  139. package/packages/game/dist/types/entities/triggers.d.ts.map +1 -0
  140. package/packages/game/dist/types/entities/utils.d.ts +4 -0
  141. package/packages/game/dist/types/entities/utils.d.ts.map +1 -0
  142. package/packages/game/dist/types/index.d.ts +5 -0
  143. package/packages/game/dist/types/index.d.ts.map +1 -1
  144. package/packages/game/dist/types/inventory/ammo.d.ts +17 -0
  145. package/packages/game/dist/types/inventory/ammo.d.ts.map +1 -0
  146. package/packages/game/dist/types/inventory/index.d.ts +2 -0
  147. package/packages/game/dist/types/inventory/index.d.ts.map +1 -0
  148. package/packages/game/dist/types/level.d.ts +1 -0
  149. package/packages/game/dist/types/level.d.ts.map +1 -1
  150. package/packages/game/dist/types/save/index.d.ts +4 -0
  151. package/packages/game/dist/types/save/index.d.ts.map +1 -0
  152. package/packages/game/dist/types/save/rerelease.d.ts +25 -0
  153. package/packages/game/dist/types/save/rerelease.d.ts.map +1 -0
  154. package/packages/game/dist/types/save/save.d.ts +49 -0
  155. package/packages/game/dist/types/save/save.d.ts.map +1 -0
  156. package/packages/game/dist/types/save/storage.d.ts +37 -0
  157. package/packages/game/dist/types/save/storage.d.ts.map +1 -0
  158. package/packages/shared/dist/browser/index.global.js +1 -1
  159. package/packages/shared/dist/browser/index.global.js.map +1 -1
  160. package/packages/shared/dist/cjs/index.cjs +638 -9
  161. package/packages/shared/dist/cjs/index.cjs.map +1 -1
  162. package/packages/shared/dist/esm/index.js +616 -9
  163. package/packages/shared/dist/esm/index.js.map +1 -1
  164. package/packages/shared/dist/tsconfig.tsbuildinfo +1 -1
  165. package/packages/shared/dist/types/bsp/collision.d.ts +56 -0
  166. package/packages/shared/dist/types/bsp/collision.d.ts.map +1 -1
  167. package/packages/shared/dist/types/bsp/contents.d.ts +1 -0
  168. package/packages/shared/dist/types/bsp/contents.d.ts.map +1 -1
  169. package/packages/shared/dist/types/index.d.ts +2 -0
  170. package/packages/shared/dist/types/index.d.ts.map +1 -1
  171. package/packages/shared/dist/types/math/random.d.ts +11 -0
  172. package/packages/shared/dist/types/math/random.d.ts.map +1 -1
  173. package/packages/shared/dist/types/protocol/contracts.d.ts +17 -0
  174. package/packages/shared/dist/types/protocol/contracts.d.ts.map +1 -0
  175. package/packages/shared/dist/types/protocol/usercmd.d.ts +30 -0
  176. package/packages/shared/dist/types/protocol/usercmd.d.ts.map +1 -0
  177. package/packages/tools/dist/tsconfig.tsbuildinfo +1 -1
@@ -409,6 +409,19 @@ var MersenneTwister19937 = class {
409
409
  }
410
410
  this.index = 0;
411
411
  }
412
+ getState() {
413
+ return {
414
+ index: this.index,
415
+ state: Array.from(this.state)
416
+ };
417
+ }
418
+ setState(snapshot) {
419
+ if (snapshot.state.length !== STATE_SIZE) {
420
+ throw new Error(`Expected ${STATE_SIZE} MT state values, received ${snapshot.state.length}`);
421
+ }
422
+ this.index = snapshot.index;
423
+ this.state = Uint32Array.from(snapshot.state, (value) => value >>> 0);
424
+ }
412
425
  };
413
426
  var RandomGenerator = class {
414
427
  constructor(options = {}) {
@@ -473,6 +486,12 @@ var RandomGenerator = class {
473
486
  randomIndex(container) {
474
487
  return this.irandom(container.length);
475
488
  }
489
+ getState() {
490
+ return { mt: this.mt.getState() };
491
+ }
492
+ setState(snapshot) {
493
+ this.mt.setState(snapshot.mt);
494
+ }
476
495
  };
477
496
  function createRandomGenerator(options) {
478
497
  return new RandomGenerator(options);
@@ -487,6 +506,7 @@ var CONTENTS_LAVA = 1 << 3;
487
506
  var CONTENTS_SLIME = 1 << 4;
488
507
  var CONTENTS_WATER = 1 << 5;
489
508
  var CONTENTS_MIST = 1 << 6;
509
+ var CONTENTS_TRIGGER = 1073741824;
490
510
  var CONTENTS_NO_WATERJUMP = 1 << 13;
491
511
  var CONTENTS_PROJECTILECLIP = 1 << 14;
492
512
  var CONTENTS_AREAPORTAL = 1 << 15;
@@ -566,6 +586,8 @@ var PlaneSide = /* @__PURE__ */ ((PlaneSide2) => {
566
586
  return PlaneSide2;
567
587
  })(PlaneSide || {});
568
588
  var DIST_EPSILON = 0.03125;
589
+ var MAX_CHECKCOUNT = Number.MAX_SAFE_INTEGER - 1;
590
+ var globalBrushCheckCount = 1;
569
591
  function buildCollisionModel(lumps) {
570
592
  const planes = lumps.planes.map((plane) => ({
571
593
  ...plane,
@@ -605,7 +627,8 @@ function buildCollisionModel(lumps) {
605
627
  leaves,
606
628
  brushes,
607
629
  leafBrushes: lumps.leafBrushes,
608
- bmodels
630
+ bmodels,
631
+ visibility: lumps.visibility
609
632
  };
610
633
  }
611
634
  function computePlaneSignBits(normal) {
@@ -752,6 +775,420 @@ function createDefaultTrace() {
752
775
  allsolid: false
753
776
  };
754
777
  }
778
+ function findLeafIndex(point, model, headnode) {
779
+ let nodeIndex = headnode;
780
+ while (nodeIndex >= 0) {
781
+ const node = model.nodes[nodeIndex];
782
+ const dist = planeDistanceToPoint(node.plane, point);
783
+ nodeIndex = dist >= 0 ? node.children[0] : node.children[1];
784
+ }
785
+ return -1 - nodeIndex;
786
+ }
787
+ function computeLeafContents(model, leafIndex, point) {
788
+ const leaf = model.leaves[leafIndex];
789
+ let contents = leaf.contents;
790
+ const brushCheckCount = nextBrushCheckCount();
791
+ const start = leaf.firstLeafBrush;
792
+ const end = start + leaf.numLeafBrushes;
793
+ for (let i = start; i < end; i += 1) {
794
+ const brushIndex = model.leafBrushes[i];
795
+ const brush = model.brushes[brushIndex];
796
+ if (brush.checkcount === brushCheckCount) continue;
797
+ brush.checkcount = brushCheckCount;
798
+ if (brush.sides.length === 0) continue;
799
+ if (pointInsideBrush(point, brush)) {
800
+ contents |= brush.contents;
801
+ }
802
+ }
803
+ return contents;
804
+ }
805
+ function nextBrushCheckCount() {
806
+ const count = globalBrushCheckCount;
807
+ globalBrushCheckCount += 1;
808
+ if (globalBrushCheckCount >= MAX_CHECKCOUNT) {
809
+ globalBrushCheckCount = 1;
810
+ }
811
+ return count;
812
+ }
813
+ function isPointBounds(mins, maxs) {
814
+ return mins.x === 0 && mins.y === 0 && mins.z === 0 && maxs.x === 0 && maxs.y === 0 && maxs.z === 0;
815
+ }
816
+ function planeOffsetForBounds(plane, mins, maxs) {
817
+ if (isPointBounds(mins, maxs)) return 0;
818
+ const offset = plane.normal.x * (plane.normal.x < 0 ? maxs.x : mins.x) + plane.normal.y * (plane.normal.y < 0 ? maxs.y : mins.y) + plane.normal.z * (plane.normal.z < 0 ? maxs.z : mins.z);
819
+ return offset;
820
+ }
821
+ function planeOffsetMagnitude(plane, mins, maxs) {
822
+ return Math.abs(planeOffsetForBounds(plane, mins, maxs));
823
+ }
824
+ function lerpPoint(start, end, t) {
825
+ return addVec3(start, scaleVec3(subtractVec3(end, start), t));
826
+ }
827
+ function finalizeTrace(trace, start, end) {
828
+ const clampedFraction = trace.allsolid ? 0 : trace.fraction;
829
+ const endpos = lerpPoint(start, end, clampedFraction);
830
+ return {
831
+ fraction: clampedFraction,
832
+ endpos,
833
+ plane: trace.plane,
834
+ planeNormal: trace.startsolid ? void 0 : trace.plane?.normal,
835
+ contents: trace.contents,
836
+ surfaceFlags: trace.surfaceFlags,
837
+ startsolid: trace.startsolid,
838
+ allsolid: trace.allsolid
839
+ };
840
+ }
841
+ function clusterForPoint(point, model, headnode) {
842
+ const leafIndex = findLeafIndex(point, model, headnode);
843
+ return model.leaves[leafIndex]?.cluster ?? -1;
844
+ }
845
+ function clusterVisible(visibility, from, to, usePhs) {
846
+ if (!visibility || visibility.numClusters === 0) return true;
847
+ if (from < 0 || to < 0) return false;
848
+ if (from >= visibility.clusters.length || to >= visibility.numClusters) return false;
849
+ const cluster = visibility.clusters[from];
850
+ const set = usePhs ? cluster.phs : cluster.pvs;
851
+ const byte = set[to >> 3];
852
+ if (byte === void 0) return false;
853
+ return (byte & 1 << (to & 7)) !== 0;
854
+ }
855
+ function recursiveHullCheck(params) {
856
+ const {
857
+ model,
858
+ nodeIndex,
859
+ startFraction,
860
+ endFraction,
861
+ start,
862
+ end,
863
+ traceStart,
864
+ traceEnd,
865
+ mins,
866
+ maxs,
867
+ contentMask,
868
+ trace,
869
+ brushCheckCount
870
+ } = params;
871
+ if (trace.fraction <= startFraction) {
872
+ return;
873
+ }
874
+ if (nodeIndex < 0) {
875
+ const leafIndex = -1 - nodeIndex;
876
+ const leaf = model.leaves[leafIndex];
877
+ const brushStart = leaf.firstLeafBrush;
878
+ const brushEnd = brushStart + leaf.numLeafBrushes;
879
+ for (let i = brushStart; i < brushEnd; i += 1) {
880
+ const brushIndex = model.leafBrushes[i];
881
+ const brush = model.brushes[brushIndex];
882
+ if ((brush.contents & contentMask) === 0) continue;
883
+ if (!brush.sides.length) continue;
884
+ if (brush.checkcount === brushCheckCount) continue;
885
+ brush.checkcount = brushCheckCount;
886
+ clipBoxToBrush({ start: traceStart, end: traceEnd, mins, maxs, brush, trace });
887
+ if (trace.allsolid) {
888
+ return;
889
+ }
890
+ }
891
+ return;
892
+ }
893
+ const node = model.nodes[nodeIndex];
894
+ const plane = node.plane;
895
+ const offset = planeOffsetForBounds(plane, mins, maxs);
896
+ const startDist = planeDistanceToPoint(plane, start) + offset;
897
+ const endDist = planeDistanceToPoint(plane, end) + offset;
898
+ if (startDist >= 0 && endDist >= 0) {
899
+ recursiveHullCheck({
900
+ model,
901
+ nodeIndex: node.children[0],
902
+ startFraction,
903
+ endFraction,
904
+ start,
905
+ end,
906
+ traceStart,
907
+ traceEnd,
908
+ mins,
909
+ maxs,
910
+ contentMask,
911
+ trace,
912
+ brushCheckCount
913
+ });
914
+ return;
915
+ }
916
+ if (startDist < 0 && endDist < 0) {
917
+ recursiveHullCheck({
918
+ model,
919
+ nodeIndex: node.children[1],
920
+ startFraction,
921
+ endFraction,
922
+ start,
923
+ end,
924
+ traceStart,
925
+ traceEnd,
926
+ mins,
927
+ maxs,
928
+ contentMask,
929
+ trace,
930
+ brushCheckCount
931
+ });
932
+ return;
933
+ }
934
+ let side = 0;
935
+ let idist = 1 / (startDist - endDist);
936
+ let fraction1 = (startDist - DIST_EPSILON) * idist;
937
+ let fraction2 = (startDist + DIST_EPSILON) * idist;
938
+ if (startDist < endDist) {
939
+ side = 1;
940
+ fraction1 = (startDist + DIST_EPSILON) * idist;
941
+ fraction2 = (startDist - DIST_EPSILON) * idist;
942
+ }
943
+ if (fraction1 < 0) fraction1 = 0;
944
+ else if (fraction1 > 1) fraction1 = 1;
945
+ if (fraction2 < 0) fraction2 = 0;
946
+ else if (fraction2 > 1) fraction2 = 1;
947
+ const midFraction = startFraction + (endFraction - startFraction) * fraction1;
948
+ const midPoint = lerpPoint(start, end, fraction1);
949
+ recursiveHullCheck({
950
+ model,
951
+ nodeIndex: node.children[side],
952
+ startFraction,
953
+ endFraction: midFraction,
954
+ start,
955
+ end: midPoint,
956
+ traceStart,
957
+ traceEnd,
958
+ mins,
959
+ maxs,
960
+ contentMask,
961
+ trace,
962
+ brushCheckCount
963
+ });
964
+ const updatedFraction = trace.fraction;
965
+ if (updatedFraction <= midFraction) {
966
+ return;
967
+ }
968
+ const midFraction2 = startFraction + (endFraction - startFraction) * fraction2;
969
+ const midPoint2 = lerpPoint(start, end, fraction2);
970
+ recursiveHullCheck({
971
+ model,
972
+ nodeIndex: node.children[1 - side],
973
+ startFraction: midFraction2,
974
+ endFraction,
975
+ start: midPoint2,
976
+ end,
977
+ traceStart,
978
+ traceEnd,
979
+ mins,
980
+ maxs,
981
+ contentMask,
982
+ trace,
983
+ brushCheckCount
984
+ });
985
+ }
986
+ function traceBox(params) {
987
+ const { model, start, end } = params;
988
+ const mins = params.mins ?? ZERO_VEC3;
989
+ const maxs = params.maxs ?? ZERO_VEC3;
990
+ const contentMask = params.contentMask ?? 4294967295;
991
+ const headnode = params.headnode ?? 0;
992
+ const trace = createDefaultTrace();
993
+ const brushCheckCount = nextBrushCheckCount();
994
+ recursiveHullCheck({
995
+ model,
996
+ nodeIndex: headnode,
997
+ startFraction: 0,
998
+ endFraction: 1,
999
+ start,
1000
+ end,
1001
+ traceStart: start,
1002
+ traceEnd: end,
1003
+ mins,
1004
+ maxs,
1005
+ contentMask,
1006
+ trace,
1007
+ brushCheckCount
1008
+ });
1009
+ return finalizeTrace(trace, start, end);
1010
+ }
1011
+ function pointContents(point, model, headnode = 0) {
1012
+ const leafIndex = findLeafIndex(point, model, headnode);
1013
+ return computeLeafContents(model, leafIndex, point);
1014
+ }
1015
+ function pointContentsMany(points, model, headnode = 0) {
1016
+ const leafCache = /* @__PURE__ */ new Map();
1017
+ return points.map((point) => {
1018
+ const leafIndex = findLeafIndex(point, model, headnode);
1019
+ const leaf = model.leaves[leafIndex];
1020
+ if (leaf.numLeafBrushes === 0) {
1021
+ const cached = leafCache.get(leafIndex);
1022
+ if (cached !== void 0) {
1023
+ return cached;
1024
+ }
1025
+ leafCache.set(leafIndex, leaf.contents);
1026
+ return leaf.contents;
1027
+ }
1028
+ return computeLeafContents(model, leafIndex, point);
1029
+ });
1030
+ }
1031
+ function boxContents(origin, mins, maxs, model, headnode = 0) {
1032
+ const brushCheckCount = nextBrushCheckCount();
1033
+ let contents = 0;
1034
+ function traverse(nodeIndex) {
1035
+ if (nodeIndex < 0) {
1036
+ const leafIndex = -1 - nodeIndex;
1037
+ const leaf = model.leaves[leafIndex];
1038
+ contents |= leaf.contents;
1039
+ const brushStart = leaf.firstLeafBrush;
1040
+ const brushEnd = brushStart + leaf.numLeafBrushes;
1041
+ for (let i = brushStart; i < brushEnd; i += 1) {
1042
+ const brushIndex = model.leafBrushes[i];
1043
+ const brush = model.brushes[brushIndex];
1044
+ if (brush.checkcount === brushCheckCount) continue;
1045
+ brush.checkcount = brushCheckCount;
1046
+ if (brush.sides.length === 0) continue;
1047
+ const result = testBoxInBrush(origin, mins, maxs, brush);
1048
+ if (result.startsolid) {
1049
+ contents |= result.contents;
1050
+ }
1051
+ }
1052
+ return;
1053
+ }
1054
+ const node = model.nodes[nodeIndex];
1055
+ const plane = node.plane;
1056
+ const offset = planeOffsetMagnitude(plane, mins, maxs);
1057
+ const dist = planeDistanceToPoint(plane, origin);
1058
+ if (offset === 0) {
1059
+ traverse(dist >= 0 ? node.children[0] : node.children[1]);
1060
+ return;
1061
+ }
1062
+ if (dist > offset) {
1063
+ traverse(node.children[0]);
1064
+ return;
1065
+ }
1066
+ if (dist < -offset) {
1067
+ traverse(node.children[1]);
1068
+ return;
1069
+ }
1070
+ traverse(node.children[0]);
1071
+ traverse(node.children[1]);
1072
+ }
1073
+ traverse(headnode);
1074
+ return contents;
1075
+ }
1076
+ function inPVS(p1, p2, model, headnode = 0) {
1077
+ const { visibility } = model;
1078
+ if (!visibility) return true;
1079
+ const cluster1 = clusterForPoint(p1, model, headnode);
1080
+ const cluster2 = clusterForPoint(p2, model, headnode);
1081
+ return clusterVisible(visibility, cluster1, cluster2, false);
1082
+ }
1083
+ function inPHS(p1, p2, model, headnode = 0) {
1084
+ const { visibility } = model;
1085
+ if (!visibility) return true;
1086
+ const cluster1 = clusterForPoint(p1, model, headnode);
1087
+ const cluster2 = clusterForPoint(p2, model, headnode);
1088
+ return clusterVisible(visibility, cluster1, cluster2, true);
1089
+ }
1090
+ function axisAlignedPlane(normal, dist, type) {
1091
+ return { normal, dist, type, signbits: computePlaneSignBits(normal) };
1092
+ }
1093
+ function makeEntityBrush(link) {
1094
+ const sx = link.surfaceFlags ?? 0;
1095
+ const xMax = link.origin.x + link.maxs.x;
1096
+ const xMin = link.origin.x + link.mins.x;
1097
+ const yMax = link.origin.y + link.maxs.y;
1098
+ const yMin = link.origin.y + link.mins.y;
1099
+ const zMax = link.origin.z + link.maxs.z;
1100
+ const zMin = link.origin.z + link.mins.z;
1101
+ const planes = [
1102
+ axisAlignedPlane({ x: 1, y: 0, z: 0 }, xMax, 0),
1103
+ axisAlignedPlane({ x: -1, y: 0, z: 0 }, -xMin, 0),
1104
+ axisAlignedPlane({ x: 0, y: 1, z: 0 }, yMax, 1),
1105
+ axisAlignedPlane({ x: 0, y: -1, z: 0 }, -yMin, 1),
1106
+ axisAlignedPlane({ x: 0, y: 0, z: 1 }, zMax, 2),
1107
+ axisAlignedPlane({ x: 0, y: 0, z: -1 }, -zMin, 2)
1108
+ ];
1109
+ const sides = planes.map((plane) => ({ plane, surfaceFlags: sx }));
1110
+ return { contents: link.contents, sides, checkcount: 0 };
1111
+ }
1112
+ function makeEntityState(link) {
1113
+ const brush = makeEntityBrush(link);
1114
+ return {
1115
+ ...link,
1116
+ brush,
1117
+ bounds: {
1118
+ mins: {
1119
+ x: link.origin.x + link.mins.x,
1120
+ y: link.origin.y + link.mins.y,
1121
+ z: link.origin.z + link.mins.z
1122
+ },
1123
+ maxs: {
1124
+ x: link.origin.x + link.maxs.x,
1125
+ y: link.origin.y + link.maxs.y,
1126
+ z: link.origin.z + link.maxs.z
1127
+ }
1128
+ }
1129
+ };
1130
+ }
1131
+ function boundsIntersect(a, b) {
1132
+ return !(a.mins.x > b.maxs.x || a.maxs.x < b.mins.x || a.mins.y > b.maxs.y || a.maxs.y < b.mins.y || a.mins.z > b.maxs.z || a.maxs.z < b.mins.z);
1133
+ }
1134
+ function pickBetterTrace(best, candidate) {
1135
+ if (candidate.allsolid && !best.allsolid) return true;
1136
+ if (candidate.startsolid && !best.startsolid) return true;
1137
+ return candidate.fraction < best.fraction;
1138
+ }
1139
+ var CollisionEntityIndex = class {
1140
+ constructor() {
1141
+ this.entities = /* @__PURE__ */ new Map();
1142
+ }
1143
+ link(entity) {
1144
+ this.entities.set(entity.id, makeEntityState(entity));
1145
+ }
1146
+ unlink(entityId) {
1147
+ this.entities.delete(entityId);
1148
+ }
1149
+ trace(params) {
1150
+ const { passId } = params;
1151
+ const mins = params.mins ?? ZERO_VEC3;
1152
+ const maxs = params.maxs ?? ZERO_VEC3;
1153
+ const contentMask = params.contentMask ?? 4294967295;
1154
+ let bestTrace;
1155
+ let bestEntity = null;
1156
+ if (params.model) {
1157
+ bestTrace = traceBox(params);
1158
+ } else {
1159
+ bestTrace = finalizeTrace(createDefaultTrace(), params.start, params.end);
1160
+ }
1161
+ for (const entity of this.entities.values()) {
1162
+ if (entity.id === passId) continue;
1163
+ if ((entity.contents & contentMask) === 0) continue;
1164
+ const trace = createDefaultTrace();
1165
+ clipBoxToBrush({ start: params.start, end: params.end, mins, maxs, brush: entity.brush, trace });
1166
+ if (trace.contents === 0) {
1167
+ trace.contents = entity.contents;
1168
+ }
1169
+ const candidate = finalizeTrace(trace, params.start, params.end);
1170
+ if (pickBetterTrace(bestTrace, candidate)) {
1171
+ bestTrace = candidate;
1172
+ bestEntity = entity.id;
1173
+ }
1174
+ }
1175
+ return { ...bestTrace, entityId: bestEntity };
1176
+ }
1177
+ gatherTriggerTouches(origin, mins, maxs, mask = CONTENTS_TRIGGER) {
1178
+ const results = [];
1179
+ const queryBounds = {
1180
+ mins: addVec3(origin, mins),
1181
+ maxs: addVec3(origin, maxs)
1182
+ };
1183
+ for (const entity of this.entities.values()) {
1184
+ if ((entity.contents & mask) === 0) continue;
1185
+ if (boundsIntersect(queryBounds, entity.bounds)) {
1186
+ results.push(entity.id);
1187
+ }
1188
+ }
1189
+ return results;
1190
+ }
1191
+ };
755
1192
 
756
1193
  // src/protocol/cvar.ts
757
1194
  var CvarFlags = /* @__PURE__ */ ((CvarFlags2) => {
@@ -819,6 +1256,124 @@ function configStringSize(index) {
819
1256
  return CS_MAX_STRING_LENGTH;
820
1257
  }
821
1258
 
1259
+ // src/protocol/contracts.ts
1260
+ function normalize(object) {
1261
+ return object ?? {};
1262
+ }
1263
+ function validateContract(table, requiredKeys, options = {}) {
1264
+ const normalized = normalize(table);
1265
+ const missing = [];
1266
+ const nonFunctions = [];
1267
+ for (const key of requiredKeys) {
1268
+ if (!(key in normalized)) {
1269
+ missing.push(key);
1270
+ continue;
1271
+ }
1272
+ if (typeof normalized[key] !== "function") {
1273
+ nonFunctions.push(key);
1274
+ }
1275
+ }
1276
+ const extras = options.allowExtra === false ? Object.keys(normalized).filter((key) => !requiredKeys.includes(key)) : [];
1277
+ return { missing, nonFunctions, extras };
1278
+ }
1279
+ function assertContract(table, requiredKeys, options = {}) {
1280
+ const { missing, nonFunctions, extras } = validateContract(table, requiredKeys, options);
1281
+ if (missing.length === 0 && nonFunctions.length === 0 && extras.length === 0) {
1282
+ return;
1283
+ }
1284
+ const pieces = [];
1285
+ if (missing.length > 0) {
1286
+ pieces.push(`missing: ${missing.join(", ")}`);
1287
+ }
1288
+ if (nonFunctions.length > 0) {
1289
+ pieces.push(`non-functions: ${nonFunctions.join(", ")}`);
1290
+ }
1291
+ if (extras.length > 0) {
1292
+ pieces.push(`extras: ${extras.join(", ")}`);
1293
+ }
1294
+ const label = options.name ?? "contract";
1295
+ throw new Error(`${label} validation failed (${pieces.join("; ")})`);
1296
+ }
1297
+ var GAME_IMPORT_KEYS = [
1298
+ "Broadcast_Print",
1299
+ "Com_Print",
1300
+ "Client_Print",
1301
+ "Center_Print",
1302
+ "sound",
1303
+ "positioned_sound",
1304
+ "local_sound",
1305
+ "configstring",
1306
+ "get_configstring",
1307
+ "Com_Error",
1308
+ "modelindex",
1309
+ "soundindex",
1310
+ "imageindex",
1311
+ "setmodel",
1312
+ "trace",
1313
+ "clip",
1314
+ "pointcontents",
1315
+ "inPVS",
1316
+ "inPHS",
1317
+ "SetAreaPortalState",
1318
+ "AreasConnected",
1319
+ "linkentity",
1320
+ "unlinkentity",
1321
+ "BoxEdicts",
1322
+ "multicast",
1323
+ "unicast"
1324
+ ];
1325
+ var GAME_EXPORT_KEYS = [
1326
+ "PreInit",
1327
+ "Init",
1328
+ "Shutdown",
1329
+ "SpawnEntities",
1330
+ "WriteGameJson",
1331
+ "ReadGameJson",
1332
+ "WriteLevelJson",
1333
+ "ReadLevelJson",
1334
+ "CanSave",
1335
+ "ClientConnect",
1336
+ "ClientThink",
1337
+ "RunFrame",
1338
+ "Pmove"
1339
+ ];
1340
+ var CGAME_IMPORT_KEYS = [
1341
+ "Com_Print",
1342
+ "get_configstring",
1343
+ "Com_Error",
1344
+ "TagMalloc",
1345
+ "TagFree",
1346
+ "AddCommandString",
1347
+ "CL_FrameValid",
1348
+ "CL_FrameTime",
1349
+ "CL_ClientTime",
1350
+ "CL_ServerFrame",
1351
+ "Draw_RegisterPic",
1352
+ "Draw_GetPicSize",
1353
+ "SCR_DrawChar",
1354
+ "SCR_DrawPic",
1355
+ "SCR_DrawColorPic"
1356
+ ];
1357
+ var CGAME_EXPORT_KEYS = [
1358
+ "Init",
1359
+ "Shutdown",
1360
+ "DrawHUD",
1361
+ "TouchPics",
1362
+ "LayoutFlags",
1363
+ "GetActiveWeaponWheelWeapon",
1364
+ "GetOwnedWeaponWheelWeapons",
1365
+ "GetWeaponWheelAmmoCount",
1366
+ "GetPowerupWheelCount",
1367
+ "GetHitMarkerDamage",
1368
+ "Pmove",
1369
+ "ParseConfigString",
1370
+ "ParseCenterPrint",
1371
+ "ClearNotify",
1372
+ "ClearCenterprint",
1373
+ "NotifyMessage",
1374
+ "GetMonsterFlashOffset"
1375
+ ];
1376
+
822
1377
  // src/pmove/constants.ts
823
1378
  var WaterLevel = /* @__PURE__ */ ((WaterLevel3) => {
824
1379
  WaterLevel3[WaterLevel3["None"] = 0] = "None";
@@ -1634,7 +2189,7 @@ function buildFlyWishVelocity(params) {
1634
2189
 
1635
2190
  // src/pmove/water.ts
1636
2191
  function getWaterLevel(params) {
1637
- const { origin, mins, viewheight, pointContents } = params;
2192
+ const { origin, mins, viewheight, pointContents: pointContents2 } = params;
1638
2193
  const sample2 = viewheight - mins.z;
1639
2194
  const sample1 = sample2 / 2;
1640
2195
  const point = {
@@ -1642,18 +2197,18 @@ function getWaterLevel(params) {
1642
2197
  y: origin.y,
1643
2198
  z: origin.z + mins.z + 1
1644
2199
  };
1645
- let contents = pointContents(point);
2200
+ let contents = pointContents2(point);
1646
2201
  if ((contents & MASK_WATER) === 0) {
1647
2202
  return { waterlevel: 0 /* None */, watertype: CONTENTS_NONE };
1648
2203
  }
1649
2204
  const watertype = contents;
1650
2205
  let waterlevel = 1 /* Feet */;
1651
2206
  let point2 = { x: point.x, y: point.y, z: origin.z + mins.z + sample1 };
1652
- contents = pointContents(point2);
2207
+ contents = pointContents2(point2);
1653
2208
  if ((contents & MASK_WATER) !== 0) {
1654
2209
  waterlevel = 2 /* Waist */;
1655
2210
  let point3 = { x: point.x, y: point.y, z: origin.z + mins.z + sample2 };
1656
- contents = pointContents(point3);
2211
+ contents = pointContents2(point3);
1657
2212
  if ((contents & MASK_WATER) !== 0) {
1658
2213
  waterlevel = 3 /* Under */;
1659
2214
  }
@@ -1843,7 +2398,7 @@ function categorizePosition(params) {
1843
2398
  maxs,
1844
2399
  viewheight,
1845
2400
  trace,
1846
- pointContents
2401
+ pointContents: pointContents2
1847
2402
  } = params;
1848
2403
  let pmFlags = params.pmFlags;
1849
2404
  let pmTime = params.pmTime;
@@ -1898,7 +2453,7 @@ function categorizePosition(params) {
1898
2453
  origin,
1899
2454
  mins,
1900
2455
  viewheight,
1901
- pointContents
2456
+ pointContents: pointContents2
1902
2457
  });
1903
2458
  return {
1904
2459
  pmFlags,
@@ -2240,7 +2795,7 @@ function checkSpecialMovement(params) {
2240
2795
  maxs,
2241
2796
  viewheight,
2242
2797
  trace,
2243
- pointContents,
2798
+ pointContents: pointContents2,
2244
2799
  onGround,
2245
2800
  overbounce = DEFAULT_OVERBOUNCE2,
2246
2801
  stepSize = WATERJUMP_STEP_TOLERANCE,
@@ -2320,7 +2875,7 @@ function checkSpecialMovement(params) {
2320
2875
  if (onGround && Math.abs(origin.z - downTrace.endpos.z) <= stepSize) {
2321
2876
  return { pmFlags, pmTime, velocity, performedWaterJump: false };
2322
2877
  }
2323
- const landingWater = getWaterLevel({ origin: downTrace.endpos, mins, viewheight, pointContents });
2878
+ const landingWater = getWaterLevel({ origin: downTrace.endpos, mins, viewheight, pointContents: pointContents2 });
2324
2879
  if (landingWater.waterlevel >= 2 /* Waist */) {
2325
2880
  return { pmFlags, pmTime, velocity, performedWaterJump: false };
2326
2881
  }
@@ -2416,7 +2971,39 @@ function clampViewAngles(params) {
2416
2971
  const vectors = angleVectors(viewangles);
2417
2972
  return { viewangles, ...vectors };
2418
2973
  }
2974
+
2975
+ // src/protocol/usercmd.ts
2976
+ var DEFAULT_FORWARD_SPEED = 200;
2977
+ var DEFAULT_SIDE_SPEED = 200;
2978
+ var DEFAULT_UP_SPEED = 200;
2979
+ var DEFAULT_YAW_SPEED = 140;
2980
+ var DEFAULT_PITCH_SPEED = 150;
2981
+ var DEFAULT_MOUSE_SENSITIVITY = 3;
2982
+ function clampPitch2(pitch) {
2983
+ const normalized = angleMod(pitch);
2984
+ if (normalized > 89 && normalized < 180) return 89;
2985
+ if (normalized < 271 && normalized >= 180) return 271;
2986
+ return normalized;
2987
+ }
2988
+ function addViewAngles(current, delta) {
2989
+ return {
2990
+ x: clampPitch2(current.x + delta.x),
2991
+ y: angleMod(current.y + delta.y),
2992
+ z: angleMod(current.z + delta.z)
2993
+ };
2994
+ }
2995
+ function mouseDeltaToViewDelta(delta, options) {
2996
+ const yawScale = options.sensitivityX ?? options.sensitivity;
2997
+ const pitchScale = (options.sensitivityY ?? options.sensitivity) * (options.invertY ? -1 : 1);
2998
+ return {
2999
+ x: delta.deltaY * pitchScale,
3000
+ y: delta.deltaX * yawScale,
3001
+ z: 0
3002
+ };
3003
+ }
2419
3004
  export {
3005
+ CGAME_EXPORT_KEYS,
3006
+ CGAME_IMPORT_KEYS,
2420
3007
  CONTENTS_AREAPORTAL,
2421
3008
  CONTENTS_AUX,
2422
3009
  CONTENTS_CURRENT_0,
@@ -2442,13 +3029,23 @@ export {
2442
3029
  CONTENTS_SLIME,
2443
3030
  CONTENTS_SOLID,
2444
3031
  CONTENTS_TRANSLUCENT,
3032
+ CONTENTS_TRIGGER,
2445
3033
  CONTENTS_WATER,
2446
3034
  CONTENTS_WINDOW,
2447
3035
  CS_MAX_STRING_LENGTH,
2448
3036
  CS_MAX_STRING_LENGTH_OLD,
3037
+ CollisionEntityIndex,
2449
3038
  ConfigStringIndex,
2450
3039
  CvarFlags,
3040
+ DEFAULT_FORWARD_SPEED,
3041
+ DEFAULT_MOUSE_SENSITIVITY,
3042
+ DEFAULT_PITCH_SPEED,
3043
+ DEFAULT_SIDE_SPEED,
3044
+ DEFAULT_UP_SPEED,
3045
+ DEFAULT_YAW_SPEED,
2451
3046
  DIST_EPSILON,
3047
+ GAME_EXPORT_KEYS,
3048
+ GAME_IMPORT_KEYS,
2452
3049
  LAST_VISIBLE_CONTENTS,
2453
3050
  MASK_ALL,
2454
3051
  MASK_BLOCK_SIGHT,
@@ -2513,6 +3110,7 @@ export {
2513
3110
  addPmFlag,
2514
3111
  addPointToBounds,
2515
3112
  addVec3,
3113
+ addViewAngles,
2516
3114
  angleMod,
2517
3115
  angleVectors,
2518
3116
  applyPmoveAccelerate,
@@ -2522,6 +3120,8 @@ export {
2522
3120
  applyPmoveFlyMove,
2523
3121
  applyPmoveFriction,
2524
3122
  applyPmoveWaterMove,
3123
+ assertContract,
3124
+ boxContents,
2525
3125
  boxOnPlaneSide,
2526
3126
  boxesIntersect,
2527
3127
  buildAirGroundWish,
@@ -2557,18 +3157,23 @@ export {
2557
3157
  hasAnyContents,
2558
3158
  hasPmFlag,
2559
3159
  hasSurfaceFlags,
3160
+ inPHS,
3161
+ inPVS,
2560
3162
  initialSnapPosition,
2561
3163
  isAtLeastWaistDeep,
2562
3164
  isUnderwater,
2563
3165
  lengthSquaredVec3,
2564
3166
  lengthVec3,
2565
3167
  lerpAngle,
3168
+ mouseDeltaToViewDelta,
2566
3169
  multiplyVec3,
2567
3170
  negateVec3,
2568
3171
  normalizeVec3,
2569
3172
  perpendicularVec3,
2570
3173
  planeDistanceToPoint,
2571
3174
  pmoveCmdScale,
3175
+ pointContents,
3176
+ pointContentsMany,
2572
3177
  pointInsideBrush,
2573
3178
  pointOnPlaneSide,
2574
3179
  projectPointOnPlane,
@@ -2587,6 +3192,8 @@ export {
2587
3192
  stepSlideMove,
2588
3193
  subtractVec3,
2589
3194
  testBoxInBrush,
3195
+ traceBox,
3196
+ validateContract,
2590
3197
  vectorToAngles,
2591
3198
  vectorToYaw,
2592
3199
  waterCurrentVelocity