-
Hey guys, Is there an easy way to get an event of a SUCCESSFUL friendly player hit with mp_friendlyfire 0? I have checked most of the events, but I MIGHT missed something. Thanks in advance! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments
-
Hi - do you have a GOTV demo available where I can test this? Thanks |
Beta Was this translation helpful? Give feedback.
-
Hey @saul, |
Beta Was this translation helpful? Give feedback.
-
I've spent a few hours coming up with a solution. It works by tracking when the Unfortunately it is quite difficult to calculate who the attacker was, because the player positions are affected by lag compensation. To workaround this, the solution below works when just one player shoots in a given tick. Two or more players shooting on the exact same tick is uncommon, but it does happen, so this solution won't work 100% of the time. With that said it should get you most of the way there.
Let me know how you get on :) import {
CTEEffectDispatch,
CTEFireBullets,
DemoFile,
IStringTable,
Player
} from "demofile";
import * as fs from "fs";
function parseDemoFile(path: string) {
const stream = fs.createReadStream(path);
const demoFile = new DemoFile();
// This code entirely depends on the server sending an 'Impact' effect
// for every player hit by a bullet. This is the default behaviour.
demoFile.conVars.on("change", e => {
if (e.name === "sv_server_verify_blood_on_player" && e.value === "0") {
console.error(
"Can only detect friendly fire attacks when 'sv_server_verify_blood_on_player' is enabled."
);
process.exit(1);
}
});
let victimsThisTick: Set<Player> = new Set<Player>();
let attackersThisTick: Player[] = [];
let effectTable: IStringTable<any> = null!;
demoFile.stringTables.on("create", table => {
if (table.name === "EffectDispatch") {
effectTable = table;
}
});
demoFile.entities.on("tempent", e => {
if (e.serverClass.name === "CTEFireBullets") {
const bulletData = ((e.props as unknown) as CTEFireBullets)
.DT_TEFireBullets;
// m_iPlayer is the client slot, need +1 for the entity
const attacker = (demoFile.entities.entities.get(
bulletData.m_iPlayer + 1
) as unknown) as Player;
attackersThisTick.push(attacker);
} else if (e.serverClass.name === "CTEEffectDispatch") {
const effect = ((e.props as unknown) as CTEEffectDispatch).DT_EffectData;
// m_iEffectName is an index into the 'EffectDispatch' string table
const effectName = effectTable.entries[effect.m_iEffectName]?.entry;
// We only care about impact effects
if (effectName !== "Impact") return;
const victim = (demoFile.entities.entities.get(
effect.entindex
) as unknown) as Player;
victimsThisTick.add(victim);
}
});
demoFile.on("tickend", tick => {
if (attackersThisTick.length === 1) {
const attacker = attackersThisTick[0]!;
for (const victim of victimsThisTick) {
// We only care about friendly fire
if (attacker.teamNumber !== victim.teamNumber) continue;
console.log(
`${tick} 🔫 ${attacker.name} team attacked ${victim.name}`
);
}
}
attackersThisTick = [];
victimsThisTick.clear();
});
demoFile.on("end", e => {
if (e.error) {
console.error("Error during parsing:", e.error);
process.exitCode = 1;
}
console.log("Finished.");
});
// Start parsing the stream now that we've added our event listeners
demoFile.parseStream(stream);
}
parseDemoFile(process.argv[2]!); |
Beta Was this translation helpful? Give feedback.
I've spent a few hours coming up with a solution. It works by tracking when the
Impact
effect is dispatched. This effect is dispatched when players are hit, even if they are hit by teammates whenmp_friendlyfire = 0
. It is responsible for adding the blood decal to player models when they've been shot.Unfortunately it is quite difficult to calculate who the attacker was, because the player positions are affected by lag compensation. To workaround this, the solution below works when just one player shoots in a given tick. Two or more players shooting on the exact same tick is uncommon, but it does happen, so this solution won't work 100% of the time. With that said it should get you most o…