Skip to content

[TF2] Fixed Beach Ball going Invisible when shot at#1721

Open
JoeyCheerio wants to merge 2 commits into
ValveSoftware:masterfrom
JoeyCheerio:JoeyCheerio-patch-1
Open

[TF2] Fixed Beach Ball going Invisible when shot at#1721
JoeyCheerio wants to merge 2 commits into
ValveSoftware:masterfrom
JoeyCheerio:JoeyCheerio-patch-1

Conversation

@JoeyCheerio
Copy link
Copy Markdown

@JoeyCheerio JoeyCheerio commented Dec 26, 2025

This patch fixes the beach ball/Smissmas ornament ball from going invisible by preventing invalid numbers from being used in the math. If invalid numbers are used (for example 0) it catches it and changes it to 1

To note: While this issue could technically be fixed by preventing the Ball from using the is_boing property, it would also remove the jiggle effect when interacting with the world. My fix preserves both the visibility of the ball when shot as well as the jiggle effect included in the model's QC

Before

before.fix.mp4

After

after.fix.mp4

This patch fixes the beach ball/Smissmas ornament ball from going invisible by preventing invalid numbers from being used in the math. If invalid numbers are used (for example 0) it catches it and changes it to 1
Comment thread src/public/jigglebones.cpp Outdated
boingSide.NormalizeInPlace();


if (data->boingDir.IsZero()) data->boingDir = Vector(0, 0, 1);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a poor way of fixing it, the source of this issue comes from the normalization of the velocity up above, which returns a non-zero result even if the velocity is zero, and it fails the epsilon check as it happens to be bigger than 0.00001f

Higher up on line 591, this will fix it properly:

		float speed;
		if ( vel.IsZero() )
		{
			vel = Vector( 0, 0, 1.0f );
			speed = 0.0f;
		}
		else
		{
			speed = vel.NormalizeInPlace();
			speed /= deltaT;
		}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an great improvement.

Looking at the Intel platform code, given vel as the zero-vector, NormalizeInPlace looks to theoretically return exactly 0.00001 (the inverse square root of 1.0e-10f (100 000) multiplied by 1.0e-10f).

The result is obviously not less than 0.00001.

Checking early for the zero vector in NormalizeInPlace, and returning 0.0f is better for this specific case, but will just slow things down in every other case.

Included Ficool's better fix
Generalisk added a commit to Generalisk/SourceSDK-Generalisk that referenced this pull request Dec 27, 2025
@FlaminSarge
Copy link
Copy Markdown
Contributor

Someone has already uploaded a fixed model for the ball that handles this the (probably) correct way, by adding a base bone on the model for which the jigglebone can jiggle relative to; see ValveSoftware/Source-1-Games#4208 (comment)

Does this change allow for better handling of jigglebones in general? If not, this probably does not need to go through, in favor of fixing the model itself.

Also should probably revert the whitespace changes.

@ficool2
Copy link
Copy Markdown
Contributor

ficool2 commented Dec 29, 2025

Does this change allow for better handling of jigglebones in general? If not, this probably does not need to go through, in favor of fixing the model itself.

This is likely to fix other assets other than the ball, therefore this PR is still relevant, besides theres clearly a bug in the code as the check for invalid inputs is not correct

@JoeyCheerio
Copy link
Copy Markdown
Author

JoeyCheerio commented Dec 29, 2025

Someone has already uploaded a fixed model for the ball that handles this the (probably) correct way, by adding a base bone on the model for which the jigglebone can jiggle relative to; see ValveSoftware/Source-1-Games#4208 (comment)

This is incorrect. I've tested the fix you linked before (which is what led me to actually investigating what caused the bug in the first place)
The root issue is not related to the model at all, it is entirely related to the is_Boing property.

For example the hat "A Rather Festive Tree" also uses the is_boing property. Turning it into a physics prop and shooting it also turns the jigglebones (The ones that use the is_Boing property) from that hat invisible in base TF2.

The PR fixes that.
You'll notice that only the bones with the Jigglebones are affected.

Before.is_Boing.Fix.mp4
After.is_Boing.Fix.mp4

@FlaminSarge
Copy link
Copy Markdown
Contributor

FlaminSarge commented Dec 30, 2025

The root issue is not related to the model at all, it is entirely related to the is_Boing property.

That's odd; why does the model fix work in that case, then? Why does adding the base bone somehow resolve the issue for that particular model? Is it related to skipping some broken logic here if another bone is present? Would be useful to know why exactly that workaround works even if it's not the 'correct' way to fix it.

Also it's looking like the ball model should get that base bone anyways in addition to this PR fix, just as a 'correctness' measure, since it seems like without a base bone if another bug crops up with jigglebones this can happen again (based on your video of the Xmas hat folding in on itself instead of outright disappearing, since it has the base bone).

This is likely to fix other assets other than the ball, therefore this PR is still relevant, besides theres clearly a bug in the code as the check for invalid inputs is not correct

Agreed that this PR should go through then.

Should still fix the whitespace, though.
Screenshot 2025-12-29 at 7 31 02 PM

@bulkmoerls
Copy link
Copy Markdown

Let this PR slide
it will change history

@Thornskade
Copy link
Copy Markdown

Thornskade commented Apr 8, 2026

EDIT: I've been testing this in-game today and it seems I've been wrong about the cause of this issue all these years.

I assumed it was related to network settings, but upon further inspection I realized that once I set my interpolation to 0.1 and back, the ball would continue to not disappear. Which shouldn't be the case, obviously.

I think I've found the actual cause of it and hence the confusion on my end: Changing my network settings causes my game to stutter shortly, enough for it to recognize my framerate has dipped below 20 fps which is also the the default for cl_jiggle_bone_framerate_cutoff.

Interestingly, this will cause the ball to stay visible for the entire game even if your framerate stays high. Although, I hadn't realized it also causes the jiggle to look, uh, a little broken when you look more closely.

So I guess back in 2011 or so when I changed my network settings to default and realized the ball would stay visible it was a case of false correlation. I can't believe I've been mistaken about this for all these years. I apologize for the confusion.

I now assume people who've never seen the ball go invisible have a lot more unstable framerates that frequently dip below 20, have a different cut-off value or they disabled jigglebones entirely for whatever reason.

  • ORIGINAL REPLY BELOW -

Hey, I just watched the video.

This bug is as old as 2011 at least because this has always been an issue for me.

You should also know that setting your network settings back to default fixes it, too. So if you have cl_interp 0.1, the ball will work fine even without this fix.

I'm not a programmer either, I don't really understand what you guys changed, but network settings have always been the culprit for me. I just accepted these minor issues for lower interpolation.

The ball isn't the only thing affected by cl_interp being different from 0.1. It also causes Sentries and NPC bosses to animate at low framerates.

Comment on lines +591 to +592
float speed;
if ( vel.IsZero() )
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the whitespace

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not to be rude at all, just because the author is not a developer, I would recommend to "suggest" changes directly on the comment, so the author only has to "accept" the change and that's it! Github has the suggestion usage on the markdown code and comment formatting section, and it is awesome!

Suggested change
float speed;
if ( vel.IsZero() )
float speed;
if ( vel.IsZero() )

}
boingSide.NormalizeInPlace();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the whitespace/unrelated change

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

@bjorn-martinsson
Copy link
Copy Markdown

bjorn-martinsson commented Apr 9, 2026

I have a sneaking suspicion that the culprit is the if ( speed < 0.00001f ) if-check triggering on line 592. My guess is that when it triggers, the ball turns invisible.

        float speed = vel.NormalizeInPlace();
        if ( speed < 0.00001f )   <------------ This line
        {
            vel = Vector( 0, 0, 1.0f );
            speed = 0.0f;
        }
        else
        {
            speed /= deltaT;
        }

Has anyone tried simply removing the ( speed < 0.00001f ) check completely? Ending up with

        float speed = vel.NormalizeInPlace();
        speed /= deltaT;

This theory would also explain why @ficool2’s suggested fix works. My guess is that the change from if (speed < 0.00001f) to if (vel.IsZero()) results in the if-statement never triggering, effectively removing the if-statement.

EDIT: After testing I've come to the conclusion that my theory is wrong. I also realized that if (vel.IsZero()) is more lenient than if (speed < 0.00001f). So I was wrong about that too.

mastercoms added a commit to mastercomfig/tc2 that referenced this pull request Apr 12, 2026
@robotboy655
Copy link
Copy Markdown

Seems to work in my testing, I will try to include this in Garry's Mod as well, since it also has the same issue with the same props. I feel like I have seen the issue with the xmas tree model reported before on our side.

As a side note, models/props_gameplay/ball001.mdl seems to have its collision model misaligned, which can be seen with vcollide_wireframe 1, so the model is not without its issues after all.

image

@BDMCGaming
Copy link
Copy Markdown

Just saying this as a heads up. This pull request made it onto Hackaday news, so it might get a lot more attention soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.