Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions Code/Game/Weapon/BaseBulletWeapon/BaseBulletWeapon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ protected void ShootBullet( float fireRate, in BulletConfiguration config )
.UseHitboxes()
.Run();

ShootEffects( tr.EndPosition, tr.Hit, tr.Normal, tr.GameObject, tr.Surface );
// Extract bone index from hitbox if available for accurate decal parenting
int boneIndex = -1;
if ( tr.Hitbox != null && tr.Hitbox.Bone != null )
boneIndex = tr.Hitbox.Bone.Index;

ShootEffects( tr.EndPosition, tr.Hit, tr.Normal, tr.GameObject, tr.Surface, boneIndex );
TraceAttack( TraceAttackInfo.From( tr, config.Damage ) );
TimeSinceShoot = 0;

Expand Down Expand Up @@ -115,7 +120,7 @@ protected void ShootBullet( float fireRate, in BulletConfiguration config )
}

[Rpc.Broadcast]
public void ShootEffects( Vector3 hitpoint, bool hit, Vector3 normal, GameObject hitObject, Surface hitSurface, Vector3? origin = null, bool noEvents = false )
public void ShootEffects( Vector3 hitpoint, bool hit, Vector3 normal, GameObject hitObject, Surface hitSurface, int boneIndex = -1, Vector3? origin = null, bool noEvents = false )
{
if ( Application.IsDedicatedServer ) return;
if ( !hitSurface.IsValid() ) return;
Expand Down Expand Up @@ -168,21 +173,35 @@ public void ShootEffects( Vector3 hitpoint, bool hit, Vector3 normal, GameObject
if ( hitObject.GetComponentInChildren<SkinnedModelRenderer>() is not { CreateBoneObjects: true } skinned )
return;

// find closest bone
var bones = skinned.GetBoneTransforms( true );
// Note this does require bone objects to be enabled on the skinned model renderer
GameObject closestBone = null;

var closestDist = float.MaxValue;
// If we have a valid bone index from the hitbox, use that for accurate decal placement
if ( boneIndex >= 0 )
{
closestBone = skinned.GetBoneObject( boneIndex );
}

for ( var i = 0; i < bones.Length; i++ )
// Else we use the closest bone to the hit point which is less accurate
if ( !closestBone.IsValid() )
{
var bone = bones[i];
var dist = bone.Position.Distance( hitpoint );
if ( dist < closestDist )
var bones = skinned.GetBoneTransforms( true );
var closestDist = float.MaxValue;

for ( var i = 0; i < bones.Length; i++ )
{
closestDist = dist;
impact.SetParent( skinned.GetBoneObject( i ), true );
var bone = bones[i];
var dist = bone.Position.Distance( hitpoint );
if ( dist < closestDist )
{
closestDist = dist;
closestBone = skinned.GetBoneObject( i );
}
}
}

if ( closestBone.IsValid() )
impact.SetParent( closestBone, true );
}

public record struct BulletConfiguration
Expand Down