updated
This commit is contained in:
parent
4e0acf9e7c
commit
02fc0aa4ee
109
server.js
109
server.js
@ -101,6 +101,81 @@ function parseVec3(str) {
|
||||
return { x, y, z };
|
||||
}
|
||||
|
||||
function pickVec3Any(pos) {
|
||||
if (!pos) return { x: 0, y: 0, z: 0 };
|
||||
if (Array.isArray(pos)) return { x: +pos[0]||0, y: +pos[1]||0, z: +pos[2]||0 };
|
||||
if (typeof pos === 'string') return parseVec3(pos);
|
||||
return { x: +pos.x||0, y: +pos.y||0, z: +pos.z||0 };
|
||||
}
|
||||
|
||||
const NADE_DEFAULTS = {
|
||||
smoke: { radius: 150, lifetimeMs: 18_000 },
|
||||
molotov:{ radius: 120, lifetimeMs: 7_000 },
|
||||
he: { radius: 40, lifetimeMs: 300 },
|
||||
flash: { radius: 36, lifetimeMs: 300 },
|
||||
decoy: { radius: 80, lifetimeMs: 15_000 },
|
||||
};
|
||||
|
||||
function normalizeGrenadesFromGSI(raw, now) {
|
||||
if (!raw || typeof raw !== 'object') return [];
|
||||
|
||||
// Dr. Weissbrot Format: buckets (smokes, infernos, hegrenades, flashes, decoys, ...),
|
||||
// evtl. auch *_projectile – beides unterstützen.
|
||||
const mapKind = (k) => {
|
||||
const s = k.toLowerCase();
|
||||
if (s.includes('smoke')) return 'smoke';
|
||||
if (s.includes('inferno') || s.includes('molotov') || s.includes('incendiary')) return 'molotov';
|
||||
if (s.includes('flash')) return 'flash';
|
||||
if (s.includes('decoy')) return 'decoy';
|
||||
if (s.includes('he')) return 'he';
|
||||
return 'unknown';
|
||||
};
|
||||
|
||||
const pushList = (acc, kind, list) => {
|
||||
if (!list) return;
|
||||
const arr = Array.isArray(list) ? list : Object.values(list);
|
||||
let i = 0;
|
||||
for (const g of arr) {
|
||||
const pos = pickVec3Any(g?.position || g?.pos || g?.location || g);
|
||||
const id =
|
||||
String(g?.id ?? g?.entityid ?? g?.entindex ??
|
||||
`${kind}#${Math.round(pos.x)}:${Math.round(pos.y)}:${i++}`);
|
||||
|
||||
const ownerTeam = (g?.owner?.team || g?.team || '').toString().toUpperCase();
|
||||
const team = ownerTeam === 'T' || ownerTeam === 'CT' ? ownerTeam : null;
|
||||
|
||||
const def = NADE_DEFAULTS[kind] || { radius: 60, lifetimeMs: 2_000 };
|
||||
const bornAt =
|
||||
Number.isFinite(+g?.lifetime) ? (now - Math.max(0, +g.lifetime * 1000))
|
||||
: Number.isFinite(+g?.spawn_time) ? +g.spawn_time
|
||||
: now;
|
||||
|
||||
// Für aktive Effekte (z.B. smoke/inferno) gibt es teils direkte "expire"-Infos.
|
||||
const radius = Number.isFinite(+g?.radius) ? +g.radius : def.radius;
|
||||
const expiresAt = Number.isFinite(+g?.expiresAt)
|
||||
? +g.expiresAt
|
||||
: bornAt + def.lifetimeMs;
|
||||
|
||||
acc.push({
|
||||
id,
|
||||
kind,
|
||||
x: pos.x, y: pos.y, z: pos.z,
|
||||
radius,
|
||||
expiresAt,
|
||||
team,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const out = [];
|
||||
for (const [k, v] of Object.entries(raw)) {
|
||||
// z.B. "smokes", "smokegrenade_projectile", "inferno", "hegrenade_projectile" ...
|
||||
const kind = mapKind(k);
|
||||
pushList(out, kind, v);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function forwardToYawPitch(fwd) {
|
||||
const yaw = Math.atan2(fwd.y || 0, fwd.x || 0) * 180 / Math.PI;
|
||||
const z = Math.max(-1, Math.min(1, fwd.z || 0));
|
||||
@ -141,13 +216,19 @@ function normalizeBombFromGSI(body) {
|
||||
: { x: Number(b?.x) || 0, y: Number(b?.y) || 0, z: Number(b?.z) || 0 };
|
||||
|
||||
let raw = String(b?.state || b?.status || "").toLowerCase();
|
||||
let status = "unknown"; // 'planted'|'dropped'|'carried'|'unknown'
|
||||
if (raw.includes("plant")) status = "planted";
|
||||
else if (raw.includes("drop")) status = "dropped";
|
||||
else if (raw.includes("carry")) status = "carried";
|
||||
let status = "unknown";
|
||||
|
||||
if (raw.includes("planted")) status = "planted";
|
||||
else if (raw.includes("defusing")) status = "defusing";
|
||||
else if (raw.includes("defused")) status = "defused";
|
||||
else if (raw.includes("dropped")) status = "dropped";
|
||||
else if (raw.includes("carried")) status = "carried";
|
||||
// "planting" bewusst NICHT als planted behandeln
|
||||
|
||||
// bool-Fallbacks
|
||||
if (b?.planted === true) status = "planted";
|
||||
if (b?.defusing === true) status = "defusing";
|
||||
if (b?.defused === true) status = "defused";
|
||||
if (b?.dropped === true) status = "dropped";
|
||||
if (b?.carried === true) status = "carried";
|
||||
|
||||
@ -155,6 +236,7 @@ function normalizeBombFromGSI(body) {
|
||||
return { x: pos.x, y: pos.y, z: pos.z, status };
|
||||
}
|
||||
|
||||
|
||||
function sameBomb(a, b) {
|
||||
if (!a && !b) return true;
|
||||
if (!a || !b) return false;
|
||||
@ -253,17 +335,29 @@ app.post(GSI_PATH, (req, res) => {
|
||||
}
|
||||
|
||||
// 4) Grenades roh (du kannst bei Bedarf normalisieren)
|
||||
const grenades = body?.grenades || {};
|
||||
const grenades = normalizeGrenadesFromGSI(body?.grenades || {}, Date.now());
|
||||
|
||||
// 5) Bombe normalisieren + Events bei Statuswechsel
|
||||
const bomb = normalizeBombFromGSI(body);
|
||||
if (!sameBomb(bomb, lastBomb)) {
|
||||
if (bomb) {
|
||||
if (bomb.status === "planted" && (!lastBomb || lastBomb.status !== "planted")) {
|
||||
const prev = lastBomb;
|
||||
// echte Plant-Transition
|
||||
if (bomb.status === "planted" && (!prev || prev.status !== "planted")) {
|
||||
broadcast({ type: "bomb_planted", bomb });
|
||||
// Defuse begonnen
|
||||
} else if (bomb.status === "defusing" && (!prev || prev.status !== "defusing")) {
|
||||
broadcast({ type: "bomb_begindefuse", bomb });
|
||||
// Defuse abgebrochen (zurück zu planted)
|
||||
} else if (prev && prev.status === "defusing" && bomb.status === "planted") {
|
||||
broadcast({ type: "bomb_abortdefuse", bomb });
|
||||
// Erfolgreich entschärft
|
||||
} else if (bomb.status === "defused" && (!prev || prev.status !== "defused")) {
|
||||
broadcast({ type: "bomb_defused", bomb });
|
||||
// Drop / Pickup
|
||||
} else if (bomb.status === "dropped") {
|
||||
broadcast({ type: "bomb_dropped", bomb });
|
||||
} else if (bomb.status === "carried" && lastBomb && lastBomb.status === "dropped") {
|
||||
} else if (bomb.status === "carried" && prev && prev.status === "dropped") {
|
||||
broadcast({ type: "bomb_pickup", bomb });
|
||||
} else {
|
||||
broadcast({ type: "bomb", bomb });
|
||||
@ -274,6 +368,7 @@ app.post(GSI_PATH, (req, res) => {
|
||||
lastBomb = bomb || null;
|
||||
}
|
||||
|
||||
|
||||
// 6) Tick mit kompletter Momentaufnahme (inkl. bomb)
|
||||
broadcast({
|
||||
type: "tick",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user