-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Something wrong with the Damage System. #2650
Comments
Pretty sure a lot of factors play into account on your issue. To factor those out, you might want to create your own custom sync |
Dedicated Server. And if you read the issue details, the weaponDamageEvent triggers successfully no matter what and it's just a problem to apply the damage. So this is not a network or server related problem it's a Fivem / GTA issue. |
The other client has to accept the damage event for it to be applied to their ped, you can try to use This might be helpful in narrowing down the issue. Do note that this can be inaccurate, there is no way to know in what order the client will reply to messages (if at all), so the caller/target could be wrong. Here is an (over-engineered) example (note this isn't tested): export interface WeaponDamageEvent {
actionResultId: number;
actionResultName: number;
damageFlags: number;
damageTime: Timestamp;
damageType: number;
f104: number;
f112: boolean;
f112_1: number;
f120: number;
f133: boolean;
hasActionResult: boolean;
hasImpactDir: boolean;
hasVehicleData: boolean;
hitComponent: number;
hitEntityWeapon: boolean;
hitGlobalId: number;
hitGlobalIds: number[];
hitWeaponAmmoAttachment: boolean;
impactDirX: number;
impactDirY: number;
impactDirZ: number;
isNetTargetPos: boolean;
localPosX: number;
localPosY: number;
localPosZ: number;
overrideDefaultDamage: boolean;
parentGlobalId: number;
silenced: boolean;
suspensionIndex: number;
tyreIndex: number;
weaponDamage: number;
weaponType: number;
willKill: boolean;
};
type Source = number;
type Timestamp = number;
interface PendingDamageData {
caller: Source,
health: number,
timestamp: Timestamp
}
class DamageHandler {
private static pendingDamages = new Map<Source, PendingDamageData[]>();
static get PendingDamageMap(): Map<Source, PendingDamageData[]> {
return this.pendingDamages;
}
static add(target: Source, damageData: PendingDamageData): void {
const pending = this.get(target);
if (pending) {
pending.push(damageData);
} else {
this.pendingDamages.set(target, [damageData])
}
}
static popFrontForTarget(target: Source): PendingDamageData | null {
const pending = this.get(target);
// don't know how we got here, but we have no pending response!
if (!pending) return null;
const data = pending.shift();
// cleanup data from the map if there are no more fields or if we just
// removed the last one.
if (!data || pending.length === 0) {
this.pendingDamages.delete(target);
}
// kep our return type consistent, null if it doesn't exist
if (!data) return null;
return data;
}
static get(target: Source): PendingDamageData[] | undefined {
return this.pendingDamages.get(target);
}
static delete(target: Source): void {
this.pendingDamages.delete(target);
}
}
on("weaponDamageEvent", (caller: string, event: WeaponDamageEvent) => {
const tgt = event.hitGlobalId;
if (tgt === 0) return;
const ent = NetworkGetEntityFromNetworkId(tgt);
if (!IsPedAPlayer(ent)) return;
const owner = NetworkGetEntityOwner(ent);
DamageHandler.add(owner, {
caller: parseInt(caller),
health: GetEntityHealth(ent),
timestamp: event.damageTime
})
})
interface WeaponDamageReply {
health: number;
time: Timestamp;
f131: boolean; // rejected?
}
on("weaponDamageReply", (caller: string, event: WeaponDamageReply) => {
const src = parseInt(caller);
const pending = DamageHandler.popFrontForTarget(src);
if (!pending) return console.log(`Got damage reply without a pending damage request`);
console.log(`Got damage reply, original health: ${pending.health}, new hp: ${event.health}, was rejected: ${event.f131}, timestamp diff: ${event.time - pending.timestamp}`);
})
setInterval(() => {
const gameTime = GetGameTimer();
for (const [target, callerData] of DamageHandler.PendingDamageMap) {
// if we haven't received a reply after a second then we likely aren't
// going to recieve one at all, clean it up and note that it didn't ever
// get a reply
const deleteForIndicies = [];
for (const [index, data] of callerData.entries()) {
if ((data.timestamp + 1000) < gameTime) {
console.log(`${target} didn't send a reply to ${data.caller} damage event`);
deleteForIndicies.push(index);
}
}
// the indicies should be in order so we'll just reverse it and delete
// from end -> begin so we don't remove the wrong indexs
const reversed = deleteForIndicies.reverse();
for (const index of reversed) {
callerData.splice(index, 1);
}
// if we removed all of the indicies from the array then we want to
// remove it from the damage map
if (callerData.length === 0) {
// i don't remember if this needs to be called when not inside an
// iterator
DamageHandler.delete(target);
}
}
}, 1000) |
What happened?
There is a problem with applying damage. Attacker -> Server -> ??
Attacker sends the request to the server -> Server successfully receives the request. But sometimes it has problems when applying the damage to the victim. Or does the server never send the damage to the victim? I don't know.
As you can see in the video, he shoot 5 bullets at the other player, but only 1 of them was applied to the player.
All damage requests are handled successfully in weaponDamageEvent. However, there is a problem when applying the damage to the target player. Some servers are waiting 50ms after the weaponDamageEvent is triggered and manually applying damage to the player if the damage has not been applied.
So far nothing has been done for PvP Servers. Please pay attention to this issue.
Example video:
KEK.mp4
Expected result
Server should apply every damage to the player without any problem.
Reproduction steps
.
Importancy
Unknown
Area(s)
FiveM
Specific version(s)
FiveM/ Every Artifact
Additional information
No response
The text was updated successfully, but these errors were encountered: