quake2ts 0.0.299 → 0.0.302

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 (37) hide show
  1. package/package.json +1 -1
  2. package/packages/client/dist/browser/index.global.js +13 -13
  3. package/packages/client/dist/browser/index.global.js.map +1 -1
  4. package/packages/client/dist/cjs/index.cjs +279 -36
  5. package/packages/client/dist/cjs/index.cjs.map +1 -1
  6. package/packages/client/dist/esm/index.js +279 -36
  7. package/packages/client/dist/esm/index.js.map +1 -1
  8. package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
  9. package/packages/client/dist/types/index.d.ts.map +1 -1
  10. package/packages/client/dist/types/ui/demo-controls.d.ts +11 -0
  11. package/packages/client/dist/types/ui/demo-controls.d.ts.map +1 -0
  12. package/packages/engine/dist/browser/index.global.js +9 -9
  13. package/packages/engine/dist/browser/index.global.js.map +1 -1
  14. package/packages/engine/dist/cjs/index.cjs +90 -18
  15. package/packages/engine/dist/cjs/index.cjs.map +1 -1
  16. package/packages/engine/dist/esm/index.js +90 -18
  17. package/packages/engine/dist/esm/index.js.map +1 -1
  18. package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
  19. package/packages/game/dist/browser/index.global.js +4 -4
  20. package/packages/game/dist/browser/index.global.js.map +1 -1
  21. package/packages/game/dist/cjs/index.cjs +107 -28
  22. package/packages/game/dist/cjs/index.cjs.map +1 -1
  23. package/packages/game/dist/esm/index.js +107 -28
  24. package/packages/game/dist/esm/index.js.map +1 -1
  25. package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
  26. package/packages/game/dist/types/entities/gibs.d.ts +1 -1
  27. package/packages/game/dist/types/entities/gibs.d.ts.map +1 -1
  28. package/packages/shared/dist/browser/index.global.js +1 -1
  29. package/packages/shared/dist/browser/index.global.js.map +1 -1
  30. package/packages/shared/dist/cjs/index.cjs +97 -19
  31. package/packages/shared/dist/cjs/index.cjs.map +1 -1
  32. package/packages/shared/dist/esm/index.js +97 -19
  33. package/packages/shared/dist/esm/index.js.map +1 -1
  34. package/packages/shared/dist/tsconfig.tsbuildinfo +1 -1
  35. package/packages/shared/dist/types/net/netchan.d.ts +5 -0
  36. package/packages/shared/dist/types/net/netchan.d.ts.map +1 -1
  37. package/packages/tools/dist/tsconfig.tsbuildinfo +1 -1
@@ -2442,10 +2442,14 @@ var _NetChan = class _NetChan2 {
2442
2442
  this.incomingReliableSequence = 0;
2443
2443
  this.outgoingReliableSequence = 0;
2444
2444
  this.reliableLength = 0;
2445
+ this.fragmentSendOffset = 0;
2446
+ this.fragmentBuffer = null;
2447
+ this.fragmentLength = 0;
2448
+ this.fragmentReceived = 0;
2445
2449
  this.lastReceived = 0;
2446
2450
  this.lastSent = 0;
2447
2451
  this.remoteAddress = null;
2448
- this.reliableMessage = new BinaryWriter(_NetChan2.MAX_MSGLEN);
2452
+ this.reliableMessage = new BinaryWriter(_NetChan2.MAX_RELIABLE_BUFFER);
2449
2453
  const now = Date.now();
2450
2454
  this.lastReceived = now;
2451
2455
  this.lastSent = now;
@@ -2471,6 +2475,10 @@ var _NetChan = class _NetChan2 {
2471
2475
  this.outgoingReliableSequence = 0;
2472
2476
  this.reliableLength = 0;
2473
2477
  this.reliableMessage.reset();
2478
+ this.fragmentSendOffset = 0;
2479
+ this.fragmentBuffer = null;
2480
+ this.fragmentLength = 0;
2481
+ this.fragmentReceived = 0;
2474
2482
  this.lastReceived = Date.now();
2475
2483
  this.lastSent = Date.now();
2476
2484
  }
@@ -2480,18 +2488,38 @@ var _NetChan = class _NetChan2 {
2480
2488
  transmit(unreliableData) {
2481
2489
  this.outgoingSequence++;
2482
2490
  this.lastSent = Date.now();
2491
+ let sendReliableLength = 0;
2492
+ let isFragment = false;
2493
+ let fragmentStart = 0;
2494
+ if (this.reliableLength > 0) {
2495
+ if (this.reliableLength > _NetChan2.FRAGMENT_SIZE) {
2496
+ isFragment = true;
2497
+ if (this.fragmentSendOffset >= this.reliableLength) {
2498
+ this.fragmentSendOffset = 0;
2499
+ }
2500
+ const remaining = this.reliableLength - this.fragmentSendOffset;
2501
+ sendReliableLength = remaining;
2502
+ if (sendReliableLength > _NetChan2.FRAGMENT_SIZE) {
2503
+ sendReliableLength = _NetChan2.FRAGMENT_SIZE;
2504
+ }
2505
+ fragmentStart = this.fragmentSendOffset;
2506
+ this.fragmentSendOffset += sendReliableLength;
2507
+ } else {
2508
+ sendReliableLength = this.reliableLength;
2509
+ }
2510
+ }
2483
2511
  const headerSize = _NetChan2.PACKET_HEADER;
2484
- const reliableSize = this.reliableLength > 0 ? this.reliableLength + 2 : 0;
2512
+ const reliableHeaderSize = sendReliableLength > 0 ? 2 + (isFragment ? 8 : 0) : 0;
2485
2513
  let unreliableSize = unreliableData ? unreliableData.length : 0;
2486
- if (headerSize + reliableSize + unreliableSize > _NetChan2.MAX_MSGLEN) {
2487
- unreliableSize = _NetChan2.MAX_MSGLEN - headerSize - reliableSize;
2514
+ if (headerSize + reliableHeaderSize + sendReliableLength + unreliableSize > _NetChan2.MAX_MSGLEN) {
2515
+ unreliableSize = _NetChan2.MAX_MSGLEN - headerSize - reliableHeaderSize - sendReliableLength;
2488
2516
  if (unreliableSize < 0) unreliableSize = 0;
2489
2517
  }
2490
- const buffer = new ArrayBuffer(headerSize + reliableSize + unreliableSize);
2518
+ const buffer = new ArrayBuffer(headerSize + reliableHeaderSize + sendReliableLength + unreliableSize);
2491
2519
  const view = new DataView(buffer);
2492
2520
  const result = new Uint8Array(buffer);
2493
2521
  let sequence = this.outgoingSequence;
2494
- if (this.reliableLength > 0) {
2522
+ if (sendReliableLength > 0) {
2495
2523
  sequence |= 2147483648;
2496
2524
  if ((this.outgoingReliableSequence & 1) !== 0) {
2497
2525
  sequence |= 1073741824;
@@ -2505,13 +2533,23 @@ var _NetChan = class _NetChan2 {
2505
2533
  view.setUint32(4, ack, true);
2506
2534
  view.setUint16(8, this.qport, true);
2507
2535
  let offset = headerSize;
2508
- if (this.reliableLength > 0) {
2509
- view.setUint16(offset, this.reliableLength, true);
2536
+ if (sendReliableLength > 0) {
2537
+ let lengthField = sendReliableLength;
2538
+ if (isFragment) {
2539
+ lengthField |= 32768;
2540
+ }
2541
+ view.setUint16(offset, lengthField, true);
2510
2542
  offset += 2;
2543
+ if (isFragment) {
2544
+ view.setUint32(offset, fragmentStart, true);
2545
+ offset += 4;
2546
+ view.setUint32(offset, this.reliableLength, true);
2547
+ offset += 4;
2548
+ }
2511
2549
  const reliableBuffer = this.reliableMessage.getBuffer();
2512
- const reliableBytes = reliableBuffer.subarray(0, this.reliableLength);
2550
+ const reliableBytes = reliableBuffer.subarray(fragmentStart, fragmentStart + sendReliableLength);
2513
2551
  result.set(reliableBytes, offset);
2514
- offset += this.reliableLength;
2552
+ offset += sendReliableLength;
2515
2553
  }
2516
2554
  if (unreliableData && unreliableSize > 0) {
2517
2555
  const chunk = unreliableData.slice(0, unreliableSize);
@@ -2552,6 +2590,7 @@ var _NetChan = class _NetChan2 {
2552
2590
  this.reliableLength = 0;
2553
2591
  this.reliableMessage.reset();
2554
2592
  this.outgoingReliableSequence ^= 1;
2593
+ this.fragmentSendOffset = 0;
2555
2594
  }
2556
2595
  }
2557
2596
  const hasReliableData = (sequence & 2147483648) !== 0;
@@ -2560,13 +2599,45 @@ var _NetChan = class _NetChan2 {
2560
2599
  let reliableData = null;
2561
2600
  if (hasReliableData) {
2562
2601
  if (payloadOffset + 2 > packet.byteLength) return null;
2563
- const reliableLen = view.getUint16(payloadOffset, true);
2602
+ let reliableLen = view.getUint16(payloadOffset, true);
2564
2603
  payloadOffset += 2;
2604
+ const isFragment = (reliableLen & 32768) !== 0;
2605
+ reliableLen &= 32767;
2565
2606
  const expectedBit = this.incomingReliableSequence & 1;
2566
2607
  if (reliableSeqBit === expectedBit) {
2567
- this.incomingReliableSequence++;
2568
- if (payloadOffset + reliableLen > packet.byteLength) return null;
2569
- reliableData = packet.slice(payloadOffset, payloadOffset + reliableLen);
2608
+ if (isFragment) {
2609
+ if (payloadOffset + 8 > packet.byteLength) return null;
2610
+ const fragStart = view.getUint32(payloadOffset, true);
2611
+ payloadOffset += 4;
2612
+ const fragTotal = view.getUint32(payloadOffset, true);
2613
+ payloadOffset += 4;
2614
+ if (fragTotal > _NetChan2.MAX_RELIABLE_BUFFER) {
2615
+ console.warn(`NetChan: received invalid fragment total ${fragTotal} > ${_NetChan2.MAX_RELIABLE_BUFFER}`);
2616
+ return null;
2617
+ }
2618
+ if (!this.fragmentBuffer || this.fragmentBuffer.length !== fragTotal) {
2619
+ this.fragmentBuffer = new Uint8Array(fragTotal);
2620
+ this.fragmentLength = fragTotal;
2621
+ this.fragmentReceived = 0;
2622
+ }
2623
+ if (payloadOffset + reliableLen > packet.byteLength) return null;
2624
+ const data = packet.subarray(payloadOffset, payloadOffset + reliableLen);
2625
+ if (fragStart === this.fragmentReceived && fragStart + reliableLen <= fragTotal) {
2626
+ this.fragmentBuffer.set(data, fragStart);
2627
+ this.fragmentReceived += reliableLen;
2628
+ if (this.fragmentReceived >= fragTotal) {
2629
+ reliableData = this.fragmentBuffer;
2630
+ this.incomingReliableSequence++;
2631
+ this.fragmentBuffer = null;
2632
+ this.fragmentLength = 0;
2633
+ this.fragmentReceived = 0;
2634
+ }
2635
+ }
2636
+ } else {
2637
+ this.incomingReliableSequence++;
2638
+ if (payloadOffset + reliableLen > packet.byteLength) return null;
2639
+ reliableData = packet.slice(payloadOffset, payloadOffset + reliableLen);
2640
+ }
2570
2641
  }
2571
2642
  payloadOffset += reliableLen;
2572
2643
  }
@@ -2593,7 +2664,7 @@ var _NetChan = class _NetChan2 {
2593
2664
  * Writes a byte to the reliable message buffer
2594
2665
  */
2595
2666
  writeReliableByte(value) {
2596
- if (this.reliableLength + 1 > _NetChan2.MAX_MSGLEN - _NetChan2.HEADER_OVERHEAD) {
2667
+ if (this.reliableLength + 1 > _NetChan2.MAX_RELIABLE_BUFFER) {
2597
2668
  throw new Error("NetChan reliable buffer overflow");
2598
2669
  }
2599
2670
  this.reliableMessage.writeByte(value);
@@ -2603,7 +2674,7 @@ var _NetChan = class _NetChan2 {
2603
2674
  * Writes a short to the reliable message buffer
2604
2675
  */
2605
2676
  writeReliableShort(value) {
2606
- if (this.reliableLength + 2 > _NetChan2.MAX_MSGLEN - _NetChan2.HEADER_OVERHEAD) {
2677
+ if (this.reliableLength + 2 > _NetChan2.MAX_RELIABLE_BUFFER) {
2607
2678
  throw new Error("NetChan reliable buffer overflow");
2608
2679
  }
2609
2680
  this.reliableMessage.writeShort(value);
@@ -2613,7 +2684,7 @@ var _NetChan = class _NetChan2 {
2613
2684
  * Writes a long to the reliable message buffer
2614
2685
  */
2615
2686
  writeReliableLong(value) {
2616
- if (this.reliableLength + 4 > _NetChan2.MAX_MSGLEN - _NetChan2.HEADER_OVERHEAD) {
2687
+ if (this.reliableLength + 4 > _NetChan2.MAX_RELIABLE_BUFFER) {
2617
2688
  throw new Error("NetChan reliable buffer overflow");
2618
2689
  }
2619
2690
  this.reliableMessage.writeLong(value);
@@ -2624,7 +2695,7 @@ var _NetChan = class _NetChan2 {
2624
2695
  */
2625
2696
  writeReliableString(value) {
2626
2697
  const len2 = value.length + 1;
2627
- if (this.reliableLength + len2 > _NetChan2.MAX_MSGLEN - _NetChan2.HEADER_OVERHEAD) {
2698
+ if (this.reliableLength + len2 > _NetChan2.MAX_RELIABLE_BUFFER) {
2628
2699
  throw new Error("NetChan reliable buffer overflow");
2629
2700
  }
2630
2701
  this.reliableMessage.writeString(value);
@@ -2657,6 +2728,7 @@ _NetChan.MAX_MSGLEN = 1400;
2657
2728
  _NetChan.FRAGMENT_SIZE = 1024;
2658
2729
  _NetChan.PACKET_HEADER = 10;
2659
2730
  _NetChan.HEADER_OVERHEAD = _NetChan.PACKET_HEADER + 2;
2731
+ _NetChan.MAX_RELIABLE_BUFFER = 262144;
2660
2732
  var AmmoType = /* @__PURE__ */ ((AmmoType22) => {
2661
2733
  AmmoType22[AmmoType22["Bullets"] = 0] = "Bullets";
2662
2734
  AmmoType22[AmmoType22["Shells"] = 1] = "Shells";
@@ -8341,6 +8413,13 @@ var NetworkMessageParser = class _NetworkMessageParser {
8341
8413
  if (bitsHigh & U_OLD_FRAME_HIGH) to.oldFrame = this.stream.readShort();
8342
8414
  }
8343
8415
  };
8416
+ var PlaybackState = /* @__PURE__ */ ((PlaybackState22) => {
8417
+ PlaybackState22[PlaybackState22["Stopped"] = 0] = "Stopped";
8418
+ PlaybackState22[PlaybackState22["Playing"] = 1] = "Playing";
8419
+ PlaybackState22[PlaybackState22["Paused"] = 2] = "Paused";
8420
+ PlaybackState22[PlaybackState22["Finished"] = 3] = "Finished";
8421
+ return PlaybackState22;
8422
+ })(PlaybackState || {});
8344
8423
  var DemoPlaybackController = class {
8345
8424
  // ms (10Hz default)
8346
8425
  constructor() {
@@ -9419,10 +9498,14 @@ var _NetChan3 = class _NetChan4 {
9419
9498
  this.incomingReliableSequence = 0;
9420
9499
  this.outgoingReliableSequence = 0;
9421
9500
  this.reliableLength = 0;
9501
+ this.fragmentSendOffset = 0;
9502
+ this.fragmentBuffer = null;
9503
+ this.fragmentLength = 0;
9504
+ this.fragmentReceived = 0;
9422
9505
  this.lastReceived = 0;
9423
9506
  this.lastSent = 0;
9424
9507
  this.remoteAddress = null;
9425
- this.reliableMessage = new BinaryWriter2(_NetChan4.MAX_MSGLEN);
9508
+ this.reliableMessage = new BinaryWriter2(_NetChan4.MAX_RELIABLE_BUFFER);
9426
9509
  const now = Date.now();
9427
9510
  this.lastReceived = now;
9428
9511
  this.lastSent = now;
@@ -9448,6 +9531,10 @@ var _NetChan3 = class _NetChan4 {
9448
9531
  this.outgoingReliableSequence = 0;
9449
9532
  this.reliableLength = 0;
9450
9533
  this.reliableMessage.reset();
9534
+ this.fragmentSendOffset = 0;
9535
+ this.fragmentBuffer = null;
9536
+ this.fragmentLength = 0;
9537
+ this.fragmentReceived = 0;
9451
9538
  this.lastReceived = Date.now();
9452
9539
  this.lastSent = Date.now();
9453
9540
  }
@@ -9457,18 +9544,38 @@ var _NetChan3 = class _NetChan4 {
9457
9544
  transmit(unreliableData) {
9458
9545
  this.outgoingSequence++;
9459
9546
  this.lastSent = Date.now();
9547
+ let sendReliableLength = 0;
9548
+ let isFragment = false;
9549
+ let fragmentStart = 0;
9550
+ if (this.reliableLength > 0) {
9551
+ if (this.reliableLength > _NetChan4.FRAGMENT_SIZE) {
9552
+ isFragment = true;
9553
+ if (this.fragmentSendOffset >= this.reliableLength) {
9554
+ this.fragmentSendOffset = 0;
9555
+ }
9556
+ const remaining = this.reliableLength - this.fragmentSendOffset;
9557
+ sendReliableLength = remaining;
9558
+ if (sendReliableLength > _NetChan4.FRAGMENT_SIZE) {
9559
+ sendReliableLength = _NetChan4.FRAGMENT_SIZE;
9560
+ }
9561
+ fragmentStart = this.fragmentSendOffset;
9562
+ this.fragmentSendOffset += sendReliableLength;
9563
+ } else {
9564
+ sendReliableLength = this.reliableLength;
9565
+ }
9566
+ }
9460
9567
  const headerSize = _NetChan4.PACKET_HEADER;
9461
- const reliableSize = this.reliableLength > 0 ? this.reliableLength + 2 : 0;
9568
+ const reliableHeaderSize = sendReliableLength > 0 ? 2 + (isFragment ? 8 : 0) : 0;
9462
9569
  let unreliableSize = unreliableData ? unreliableData.length : 0;
9463
- if (headerSize + reliableSize + unreliableSize > _NetChan4.MAX_MSGLEN) {
9464
- unreliableSize = _NetChan4.MAX_MSGLEN - headerSize - reliableSize;
9570
+ if (headerSize + reliableHeaderSize + sendReliableLength + unreliableSize > _NetChan4.MAX_MSGLEN) {
9571
+ unreliableSize = _NetChan4.MAX_MSGLEN - headerSize - reliableHeaderSize - sendReliableLength;
9465
9572
  if (unreliableSize < 0) unreliableSize = 0;
9466
9573
  }
9467
- const buffer = new ArrayBuffer(headerSize + reliableSize + unreliableSize);
9574
+ const buffer = new ArrayBuffer(headerSize + reliableHeaderSize + sendReliableLength + unreliableSize);
9468
9575
  const view = new DataView(buffer);
9469
9576
  const result = new Uint8Array(buffer);
9470
9577
  let sequence = this.outgoingSequence;
9471
- if (this.reliableLength > 0) {
9578
+ if (sendReliableLength > 0) {
9472
9579
  sequence |= 2147483648;
9473
9580
  if ((this.outgoingReliableSequence & 1) !== 0) {
9474
9581
  sequence |= 1073741824;
@@ -9482,13 +9589,23 @@ var _NetChan3 = class _NetChan4 {
9482
9589
  view.setUint32(4, ack, true);
9483
9590
  view.setUint16(8, this.qport, true);
9484
9591
  let offset = headerSize;
9485
- if (this.reliableLength > 0) {
9486
- view.setUint16(offset, this.reliableLength, true);
9592
+ if (sendReliableLength > 0) {
9593
+ let lengthField = sendReliableLength;
9594
+ if (isFragment) {
9595
+ lengthField |= 32768;
9596
+ }
9597
+ view.setUint16(offset, lengthField, true);
9487
9598
  offset += 2;
9599
+ if (isFragment) {
9600
+ view.setUint32(offset, fragmentStart, true);
9601
+ offset += 4;
9602
+ view.setUint32(offset, this.reliableLength, true);
9603
+ offset += 4;
9604
+ }
9488
9605
  const reliableBuffer = this.reliableMessage.getBuffer();
9489
- const reliableBytes = reliableBuffer.subarray(0, this.reliableLength);
9606
+ const reliableBytes = reliableBuffer.subarray(fragmentStart, fragmentStart + sendReliableLength);
9490
9607
  result.set(reliableBytes, offset);
9491
- offset += this.reliableLength;
9608
+ offset += sendReliableLength;
9492
9609
  }
9493
9610
  if (unreliableData && unreliableSize > 0) {
9494
9611
  const chunk = unreliableData.slice(0, unreliableSize);
@@ -9529,6 +9646,7 @@ var _NetChan3 = class _NetChan4 {
9529
9646
  this.reliableLength = 0;
9530
9647
  this.reliableMessage.reset();
9531
9648
  this.outgoingReliableSequence ^= 1;
9649
+ this.fragmentSendOffset = 0;
9532
9650
  }
9533
9651
  }
9534
9652
  const hasReliableData = (sequence & 2147483648) !== 0;
@@ -9537,13 +9655,45 @@ var _NetChan3 = class _NetChan4 {
9537
9655
  let reliableData = null;
9538
9656
  if (hasReliableData) {
9539
9657
  if (payloadOffset + 2 > packet.byteLength) return null;
9540
- const reliableLen = view.getUint16(payloadOffset, true);
9658
+ let reliableLen = view.getUint16(payloadOffset, true);
9541
9659
  payloadOffset += 2;
9660
+ const isFragment = (reliableLen & 32768) !== 0;
9661
+ reliableLen &= 32767;
9542
9662
  const expectedBit = this.incomingReliableSequence & 1;
9543
9663
  if (reliableSeqBit === expectedBit) {
9544
- this.incomingReliableSequence++;
9545
- if (payloadOffset + reliableLen > packet.byteLength) return null;
9546
- reliableData = packet.slice(payloadOffset, payloadOffset + reliableLen);
9664
+ if (isFragment) {
9665
+ if (payloadOffset + 8 > packet.byteLength) return null;
9666
+ const fragStart = view.getUint32(payloadOffset, true);
9667
+ payloadOffset += 4;
9668
+ const fragTotal = view.getUint32(payloadOffset, true);
9669
+ payloadOffset += 4;
9670
+ if (fragTotal > _NetChan4.MAX_RELIABLE_BUFFER) {
9671
+ console.warn(`NetChan: received invalid fragment total ${fragTotal} > ${_NetChan4.MAX_RELIABLE_BUFFER}`);
9672
+ return null;
9673
+ }
9674
+ if (!this.fragmentBuffer || this.fragmentBuffer.length !== fragTotal) {
9675
+ this.fragmentBuffer = new Uint8Array(fragTotal);
9676
+ this.fragmentLength = fragTotal;
9677
+ this.fragmentReceived = 0;
9678
+ }
9679
+ if (payloadOffset + reliableLen > packet.byteLength) return null;
9680
+ const data = packet.subarray(payloadOffset, payloadOffset + reliableLen);
9681
+ if (fragStart === this.fragmentReceived && fragStart + reliableLen <= fragTotal) {
9682
+ this.fragmentBuffer.set(data, fragStart);
9683
+ this.fragmentReceived += reliableLen;
9684
+ if (this.fragmentReceived >= fragTotal) {
9685
+ reliableData = this.fragmentBuffer;
9686
+ this.incomingReliableSequence++;
9687
+ this.fragmentBuffer = null;
9688
+ this.fragmentLength = 0;
9689
+ this.fragmentReceived = 0;
9690
+ }
9691
+ }
9692
+ } else {
9693
+ this.incomingReliableSequence++;
9694
+ if (payloadOffset + reliableLen > packet.byteLength) return null;
9695
+ reliableData = packet.slice(payloadOffset, payloadOffset + reliableLen);
9696
+ }
9547
9697
  }
9548
9698
  payloadOffset += reliableLen;
9549
9699
  }
@@ -9570,7 +9720,7 @@ var _NetChan3 = class _NetChan4 {
9570
9720
  * Writes a byte to the reliable message buffer
9571
9721
  */
9572
9722
  writeReliableByte(value) {
9573
- if (this.reliableLength + 1 > _NetChan4.MAX_MSGLEN - _NetChan4.HEADER_OVERHEAD) {
9723
+ if (this.reliableLength + 1 > _NetChan4.MAX_RELIABLE_BUFFER) {
9574
9724
  throw new Error("NetChan reliable buffer overflow");
9575
9725
  }
9576
9726
  this.reliableMessage.writeByte(value);
@@ -9580,7 +9730,7 @@ var _NetChan3 = class _NetChan4 {
9580
9730
  * Writes a short to the reliable message buffer
9581
9731
  */
9582
9732
  writeReliableShort(value) {
9583
- if (this.reliableLength + 2 > _NetChan4.MAX_MSGLEN - _NetChan4.HEADER_OVERHEAD) {
9733
+ if (this.reliableLength + 2 > _NetChan4.MAX_RELIABLE_BUFFER) {
9584
9734
  throw new Error("NetChan reliable buffer overflow");
9585
9735
  }
9586
9736
  this.reliableMessage.writeShort(value);
@@ -9590,7 +9740,7 @@ var _NetChan3 = class _NetChan4 {
9590
9740
  * Writes a long to the reliable message buffer
9591
9741
  */
9592
9742
  writeReliableLong(value) {
9593
- if (this.reliableLength + 4 > _NetChan4.MAX_MSGLEN - _NetChan4.HEADER_OVERHEAD) {
9743
+ if (this.reliableLength + 4 > _NetChan4.MAX_RELIABLE_BUFFER) {
9594
9744
  throw new Error("NetChan reliable buffer overflow");
9595
9745
  }
9596
9746
  this.reliableMessage.writeLong(value);
@@ -9601,7 +9751,7 @@ var _NetChan3 = class _NetChan4 {
9601
9751
  */
9602
9752
  writeReliableString(value) {
9603
9753
  const len2 = value.length + 1;
9604
- if (this.reliableLength + len2 > _NetChan4.MAX_MSGLEN - _NetChan4.HEADER_OVERHEAD) {
9754
+ if (this.reliableLength + len2 > _NetChan4.MAX_RELIABLE_BUFFER) {
9605
9755
  throw new Error("NetChan reliable buffer overflow");
9606
9756
  }
9607
9757
  this.reliableMessage.writeString(value);
@@ -9634,6 +9784,7 @@ _NetChan3.MAX_MSGLEN = 1400;
9634
9784
  _NetChan3.FRAGMENT_SIZE = 1024;
9635
9785
  _NetChan3.PACKET_HEADER = 10;
9636
9786
  _NetChan3.HEADER_OVERHEAD = _NetChan3.PACKET_HEADER + 2;
9787
+ _NetChan3.MAX_RELIABLE_BUFFER = 262144;
9637
9788
  var NetChan = _NetChan3;
9638
9789
  var AmmoType2 = /* @__PURE__ */ ((AmmoType22) => {
9639
9790
  AmmoType22[AmmoType22["Bullets"] = 0] = "Bullets";
@@ -11880,6 +12031,89 @@ var MultiplayerConnection = class {
11880
12031
  }
11881
12032
  };
11882
12033
 
12034
+ // src/ui/demo-controls.ts
12035
+ var DemoControls = class {
12036
+ constructor(playback) {
12037
+ this.isVisible = true;
12038
+ this.playback = playback;
12039
+ }
12040
+ render(renderer, width, height) {
12041
+ if (!this.isVisible) return;
12042
+ const state = this.playback.getState();
12043
+ const isPlaying = state === PlaybackState.Playing;
12044
+ const overlayHeight = 60;
12045
+ const y = height - overlayHeight;
12046
+ renderer.drawfillRect(0, y, width, overlayHeight, [0, 0, 0, 0.5]);
12047
+ const iconSize = 24;
12048
+ const iconY = y + (overlayHeight - iconSize) / 2;
12049
+ const iconX = 20;
12050
+ const statusText = isPlaying ? "PAUSE" : "PLAY";
12051
+ renderer.drawString(iconX, iconY, statusText);
12052
+ const speed = this.playback.getSpeed();
12053
+ const speedText = `Speed: ${speed}x`;
12054
+ renderer.drawCenterString(iconY, speedText);
12055
+ const currentTime = this.playback.getCurrentTime();
12056
+ const currentFormatted = this.formatTime(currentTime);
12057
+ const totalFormatted = "--:--";
12058
+ const timeText = `${currentFormatted} / ${totalFormatted}`;
12059
+ const timeX = width - 150;
12060
+ renderer.drawString(timeX, iconY, timeText);
12061
+ const timelineY = y + 5;
12062
+ const timelineHeight = 4;
12063
+ const timelineWidth = width - 40;
12064
+ const timelineX = 20;
12065
+ renderer.drawfillRect(timelineX, timelineY, timelineWidth, timelineHeight, [0.3, 0.3, 0.3, 1]);
12066
+ const progress = 0;
12067
+ const progressWidth = timelineWidth * progress;
12068
+ renderer.drawfillRect(timelineX, timelineY, progressWidth, timelineHeight, [1, 1, 1, 1]);
12069
+ const markerX = timelineX + progressWidth;
12070
+ renderer.drawfillRect(markerX - 2, timelineY - 2, 4, timelineHeight + 4, [1, 0, 0, 1]);
12071
+ const helpText = "[Space] Toggle [< >] Step [ [ ] ] Speed [Esc] Stop";
12072
+ renderer.drawCenterString(y + 35, helpText);
12073
+ }
12074
+ handleInput(key, down) {
12075
+ if (!down) return false;
12076
+ switch (key.toLowerCase()) {
12077
+ case " ":
12078
+ if (this.playback.getState() === PlaybackState.Playing) {
12079
+ this.playback.pause();
12080
+ } else if (this.playback.getState() === PlaybackState.Paused) {
12081
+ this.playback.play();
12082
+ }
12083
+ return true;
12084
+ case "arrowright":
12085
+ this.playback.stepForward();
12086
+ return true;
12087
+ case "arrowleft":
12088
+ this.playback.stepBackward();
12089
+ return true;
12090
+ case "]":
12091
+ this.changeSpeed(2);
12092
+ return true;
12093
+ case "[":
12094
+ this.changeSpeed(0.5);
12095
+ return true;
12096
+ case "escape":
12097
+ this.playback.stop();
12098
+ return true;
12099
+ }
12100
+ return false;
12101
+ }
12102
+ changeSpeed(factor) {
12103
+ const current = this.playback.getSpeed();
12104
+ let newSpeed = current * factor;
12105
+ if (newSpeed < 0.1) newSpeed = 0.1;
12106
+ if (newSpeed > 16) newSpeed = 16;
12107
+ this.playback.setSpeed(newSpeed);
12108
+ }
12109
+ formatTime(ms) {
12110
+ const totalSeconds = Math.floor(ms / 1e3);
12111
+ const minutes = Math.floor(totalSeconds / 60);
12112
+ const seconds = totalSeconds % 60;
12113
+ return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
12114
+ }
12115
+ };
12116
+
11883
12117
  // src/input/bindings.ts
11884
12118
  var DEFAULT_BINDINGS = [
11885
12119
  { code: "KeyW", command: "+forward" },
@@ -12392,6 +12626,7 @@ function createClient(imports) {
12392
12626
  const prediction = new import_cgame3.ClientPrediction(imports.engine.trace, pointContents);
12393
12627
  const view = new import_cgame4.ViewEffects();
12394
12628
  const demoPlayback = new DemoPlaybackController();
12629
+ const demoControls = new DemoControls(demoPlayback);
12395
12630
  const demoHandler = new ClientNetworkHandler(imports);
12396
12631
  demoHandler.setView(view);
12397
12632
  let isDemoPlaying = false;
@@ -12586,6 +12821,11 @@ function createClient(imports) {
12586
12821
  return prediction.enqueueCommand(command);
12587
12822
  },
12588
12823
  handleInput(key, down) {
12824
+ if (isDemoPlaying) {
12825
+ if (demoControls.handleInput(key, down)) {
12826
+ return true;
12827
+ }
12828
+ }
12589
12829
  if (!menuSystem.isActive()) return false;
12590
12830
  if (!down) return true;
12591
12831
  const lowerKey = key.toLowerCase();
@@ -12805,6 +13045,9 @@ function createClient(imports) {
12805
13045
  if (menuSystem.isActive()) {
12806
13046
  Draw_Menu(imports.engine.renderer, menuSystem.getState(), imports.engine.renderer.width, imports.engine.renderer.height);
12807
13047
  }
13048
+ if (isDemoPlaying) {
13049
+ demoControls.render(imports.engine.renderer, imports.engine.renderer.width, imports.engine.renderer.height);
13050
+ }
12808
13051
  if (lastRendered && lastRendered.client) {
12809
13052
  wheelMenuSystem.render(imports.engine.renderer, imports.engine.renderer.width, imports.engine.renderer.height, lastRendered.client);
12810
13053
  }