Skip to content

Fixed thirdperson animations from third-party addons#1858

Open
mexikoedi wants to merge 7 commits intoTTT-2:masterfrom
mexikoedi:fix-third-party-thirdperson-animation
Open

Fixed thirdperson animations from third-party addons#1858
mexikoedi wants to merge 7 commits intoTTT-2:masterfrom
mexikoedi:fix-third-party-thirdperson-animation

Conversation

@mexikoedi
Copy link
Copy Markdown
Contributor

This PR fixes #1690 .

Third-party addons that create thirdperson animations like Custom Taunt can use gesture slots that conflict with TTT2 gesture handling (for example: GESTURE_SLOT_CUSTOM).
Because of this, the local player’s third-person animation could be visually overridden and not appear correctly.

There was also a second issue with the TTT2 voice chat gesture (ACT_GMOD_IN_CHAT) which interfered with active third-party thirdperson animations.

This fix adds clientside external gesture detection and suppresses the TTT2 ACT_GMOD_IN_CHAT gesture while an external gesture is active.
To make this more robust for all kinds of addons, both AddVCDSequenceToGestureSlot and AnimRestartGesture are tracked, while TTT2 internal gestures are excluded from that detection.

I tested this with the addon mentioned above and can confirm the issue is resolved (thirdperson animation is now visible for the local player).
The voice chat ACT_GMOD_IN_CHAT behavior also works as expected, and I did not encounter errors during testing.

@saibotk
Copy link
Copy Markdown
Member

saibotk commented Feb 23, 2026

Thanks for digging into these issues!

Heads up: The earliest i can review this is probably this weekend or next week!

Copy link
Copy Markdown
Member

@saibotk saibotk left a comment

Choose a reason for hiding this comment

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

I looked over the changes and got some concerns and questions we need to discuss and i would prefer not to merge those in their current state.

  • Not to shame you, but if this code was written with AI, I'd prefer if you'd disclose so (if not, I'm sorry its just hard to tell in todays world)
  • Can you elaborate on the exact problem that was fixed here? The issue is rather old and lacks some information on how this behaves in the current version and what you expect it to do
  • Can you elaborate how the Custom Taunts addon uses these functions or GMOD functions to handle animations, so we can understand why and what we need to adjust here?
  • I'd prefer not to introduce additional public methods, especially since GMOD also has functions like IsPlayingTaunt already. This will be very confusing and we need to check if we handle all cases correctly

Let's first collect more information on this and then we can discuss a potential solution together. This way you don't waste time iterating too much on a potential solution.

Thanks for your understanding!

and isnumber(activity)
and activity >= 0
then
local sequence = self:SelectWeightedSequence(activity)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I could not find how this is handled internally within GMOD, but this can be wrong, when the sequence here is different from the one that GMOD chooses when playing ACT gestures that hold multiple sequences.

This is because you select one sequence at random here, you would need to pass this exact sequence to the AnimRestartGesture call, as far as i can see.

Copy link
Copy Markdown
Contributor Author

@mexikoedi mexikoedi Mar 10, 2026

Choose a reason for hiding this comment

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

That makes sense.
Since Custom Taunt uses AddVCDSequenceToGestureSlot directly, the whole AnimRestartGesture part is not required for the fix so I could even remove that part entirely if you want? But I don't know if maybe other gesture/... addons might use it and if/how they are affected.

Comment on lines +11 to +12
-- use a dedicated slot if available to reduce collisions with third-party gesture addons
local ttt2GestureSlot = GESTURE_SLOT_VCD or GESTURE_SLOT_CUSTOM
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I cannot really understand the reasoning here. What is the intention of using the VCD slot?
GMOD and sandbox gamemode both default to the GESTUR_SLOT_CUSTOM.

Besides, those two slot variables are always defined, so i'd assume this or statement to not be effective at all.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This was from my first iteration where I just tried a different slot and noticed that it began working again but not ideal because of the voice chat for example but I never changed it afterwards.
So yes, that can be changed again.

Comment on lines +132 to +136
-- prevent voice chat ear grab gesture from interfering with active third-party gestures
if ply:HasExternalGestureActive() then
return 0
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What about all the other native gestures listed below in the gestTbl?
Are they non-problematic and is this only an issue because of the automatic activation?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I forgot about them first and only did it for the voicechat because it was enabled by default and caused visual interference with the Custom Taunt gestures.
It also could be activated/deactivated all the time via a button click.
But then I also noticed the other gestures and tested it again.
They do not affect the dancing when I use them while using Custom Taunt gestures.
So there is no change needed for them.

Comment on lines +54 to +55
-- depth > 0 means this call originates from TTT2's AnimApplyGesture and should not count as external
if (self._ttt2InternalGestureWriteDepth or 0) <= 0 then
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is never called from the AnimApplyGesture function, so we do not need to check this here afaik

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried to make it similar to AnimRestartGesture which is called from AnimApplyGesture.
But yes, I can remove that from here.

self:AnimRestartGesture(GESTURE_SLOT_CUSTOM, act, true) -- true = autokill
self:AnimSetGestureWeight(GESTURE_SLOT_CUSTOM, weight)
-- prevent our own gesture writes from being treated as external
self._ttt2InternalGestureWriteDepth = (self._ttt2InternalGestureWriteDepth or 0) + 1
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This does not have to be a counter and can be a simple boolean flag.
This code is executed instantly and sequentially and should never reach any concurrency situations afaik how gmod works.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed, that can be simplified.

@mexikoedi
Copy link
Copy Markdown
Contributor Author

I looked over the changes and got some concerns and questions we need to discuss and i would prefer not to merge those in their current state.

  • Not to shame you, but if this code was written with AI, I'd prefer if you'd disclose so (if not, I'm sorry its just hard to tell in todays world)
  • Can you elaborate on the exact problem that was fixed here? The issue is rather old and lacks some information on how this behaves in the current version and what you expect it to do
  • Can you elaborate how the Custom Taunts addon uses these functions or GMOD functions to handle animations, so we can understand why and what we need to adjust here?
  • I'd prefer not to introduce additional public methods, especially since GMOD also has functions like IsPlayingTaunt already. This will be very confusing and we need to check if we handle all cases correctly

Let's first collect more information on this and then we can discuss a potential solution together. This way you don't waste time iterating too much on a potential solution.

Thanks for your understanding!

  • I use autocompletion for example for code comments/variables and I also had multiple iterations until I was happy with the results from testing so there are some not needed and confusing code parts. After reading through your comments it makes sense and I should have looked more at the code than the ingame testing results.

  • The bug is a local visibility conflict in thirdperson when gesture layers overlap. Custom Taunt plays emote sequences via AddVCDSequenceToGestureSlot on GESTURE_SLOT_CUSTOM. TTT2 also starts its own player gestures (for example voicechat). This overlaps with the Custom Taunt gestures on the same gesture layer and overrides (visually) the local thirdperson taunt while other players can still see it. (see issue description to see when it worked, when it stopped working, ...) I want to see the Custom Taunt gestures in thirdperson too and I don't want other gestures (voicechat) to cause visual interferences with it.

  • The client selects a gesture via the dance menu. Then the duration is calculated (LookupSequence+ SequenceDuration), then the client sends a mmddance net message, the server receives it and broadcasts playmmd, then the client plays the animation with ply:AddVCDSequenceToGestureSlot(GESTURE_SLOT_CUSTOM, ply:LookupSequence(mmdDance), 0, true). If the client wants to stop the gesture he can also do that via the menu and then ply:AddVCDSequenceToGestureSlot(GESTURE_SLOT_CUSTOM, ply:LookupSequence("gesture_bow_base_layer"), 0, true) will be run and the gesture is finished afterwards. AnimRestartGesture or other functions are not used. It's just over net messages, AddVCDSequenceToGestureSlot with LookupSequence and SequenceDuration.

  • Yes that would be better, I didn't know about the existence of IsPlayingTaunt. I can try that instead of HasExternalGestureActive.

So I could implement your comments:

  • Remove HasExternalGestureActive and try to use something like IsPlayingTaunt instead
  • Remove the whole AnimRestartGesture part if wanted or instead try to implement your suggestion there
  • Remove GESTURE_SLOT_VCD and use GESTURE_SLOT_CUSTOM entirely again
  • Remove the check (in AddVCDSequenceToGestureSlot)
  • Make a boolean instead of a counter (in AnimApplyGesture) or try to remove it entirely if AnimRestartGesture is not needed
  • And maybe clean up/reduce code parts if possible

What do you think?
Thanks for your detailed review and your time.

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.

Issue with thirdperson animation from third-party addon

2 participants