File size: 3,408 Bytes
565f6e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import { Pilot, WeaponType, AmmoBelt } from "../../types";
import { getProjectileReleaseState } from "../projectileSystem";
import { generateId } from "../math";
import { Vector3 } from "three";
import { getTerrainHeight } from "../terrainModel";

const FIXED_DT = 1 / 60;

function getWepBelt(p: Pilot, type: WeaponType): AmmoBelt {
  const wep = p.entity.components.get("weaponized") as any;
  if (!wep || !wep.belts) return AmmoBelt.Universal;
  return wep.belts[type] || AmmoBelt.Universal;
}

export function spawnOrdnance(pilot: Pilot, type: WeaponType, projectiles: any[]) {
  const release = getProjectileReleaseState(pilot, type);
  projectiles.push({
    id: generateId(),
    ownerId: pilot.id,
    ownerTeam: pilot.team,
    type,
    belt: getWepBelt(pilot, type),
    x: release.position.x, y: release.position.y, z: release.position.z,
    vx: release.velocity.x, vy: release.velocity.y, vz: release.velocity.z,
    life: 5.0,
    isRocket: type === WeaponType.ROCKET
  });
}

export function spawnGunProjectile(
  pilot: Pilot, 
  type: WeaponType, 
  clientSeq: number | undefined,
  inputQueueLength: number,
  playerHistory: any[],
  triggerSplashDamage: (pos: Vector3, ownerId: string, team: number, type: WeaponType) => void,
  projectiles: any[],
  mapId: string
) {
  if (clientSeq === undefined) {
    const release = getProjectileReleaseState(pilot, type);
    projectiles.push({
      id: generateId(),
      ownerId: pilot.id,
      ownerTeam: pilot.team,
      type,
      belt: getWepBelt(pilot, type),
      x: release.position.x, y: release.position.y, z: release.position.z,
      vx: release.velocity.x, vy: release.velocity.y, vz: release.velocity.z,
      life: 1.8,
      isRocket: false
    });
    return;
  }

  const oneWayLatencyTicks = Math.min(30, Math.max(0, inputQueueLength)); 
  const historicalTick = (pilot as any).serverTick - oneWayLatencyTicks;
  const history = playerHistory || [];
  const histTransform = history.find(h => h.tick === historicalTick) || history[history.length - 1];

  let release;
  if (histTransform) {
    const tempPilot = new Pilot({
      id: pilot.id,
      aircraftId: pilot.aircraftId,
      specs: pilot.specs,
      x: histTransform.x, y: histTransform.y, z: histTransform.z,
      vx: histTransform.vx, vy: histTransform.vy, vz: histTransform.vz,
      qx: histTransform.qx ?? histTransform.rotX, 
      qy: histTransform.qy ?? histTransform.rotY,
      qz: histTransform.qz ?? histTransform.rotZ,
      qw: histTransform.qw ?? histTransform.rotW,
      ammo: pilot.ammo
    });
    release = getProjectileReleaseState(tempPilot, type);
  } else {
    release = getProjectileReleaseState(pilot, type);
  }

  let px = release.position.x, py = release.position.y, pz = release.position.z;
  const vx = release.velocity.x, vy = release.velocity.y, vz = release.velocity.z;

  const elapsedSec = oneWayLatencyTicks * FIXED_DT;
  for (let s = 0; s < oneWayLatencyTicks; s++) {
    px += vx * FIXED_DT; py += vy * FIXED_DT; pz += vz * FIXED_DT;
    if (py <= getTerrainHeight(px, pz, mapId).height) {
      triggerSplashDamage(new Vector3(px, py, pz), pilot.id, pilot.team as 1 | 2, type);
      return;
    }
  }

  projectiles.push({
    id: generateId(), ownerId: pilot.id, ownerTeam: pilot.team, type,
    belt: getWepBelt(pilot, type),
    x: px, y: py, z: pz, vx, vy, vz,
    life: 1.8 - elapsedSec, isRocket: false
  });
}