airframe.io / src /game /multiplayer /ProjectileSpawner.ts
LATTICEWORKS's picture
feat: integrate Google Earth 3D Tiles and optimize engine hooks
565f6e7
Raw
History Blame Contribute Delete
3.41 kB
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
});
}