Fix misplaced func_breakable_surf when damaged#1906
Open
Masterkatze wants to merge 1 commit intoNeotokyoRebuild:masterfrom
Open
Fix misplaced func_breakable_surf when damaged#1906Masterkatze wants to merge 1 commit intoNeotokyoRebuild:masterfrom
Masterkatze wants to merge 1 commit intoNeotokyoRebuild:masterfrom
Conversation
sunzenshen
reviewed
Mar 31, 2026
| // the geometric height edge. Unlike the non-NEO path we do NOT scale by | ||
| // flDir here: in NEO we never shift the vertices, so flDir has no bearing | ||
| // on the edge vectors themselves. | ||
| float flWDist = DotProduct( vWidthDir, vWidth ); |
Contributor
There was a problem hiding this comment.
It may be a good idea to normalize wWidth since wWidthDir already seems normalized by this point. That way the dot product would be done with both normalized parameters. Something like this:
Vector vWidthNorm = vWidth;
VectorNormalize( vWidthNorm );
float flWDist = DotProduct( vWidthDir, vWidthNorm );
bool bSwapped = ( fabs(flWDist) < 0.5f ); // < 0.5 ≡ angle > 60° from canonical width| Vector m_vCorner; | ||
| #ifdef NEO | ||
| Vector m_vWidthDir; | ||
| Vector m_vHeightDir; |
Contributor
There was a problem hiding this comment.
Would it make sense to zero initialize these new members in
void C_BreakableSurface::InitMaterial(WinEdge_t nEdgeType, int nEdgeStyle, char const* pMaterialName)? (or some other initialization function)
e.g. put what you have in other places into one place in an initialization function like this:
Vector vWidth = m_vLLVertex - m_vLRVertex;
Vector vHeight = m_vLLVertex - m_vULVertex;
m_vWidthDir = vWidth; VectorNormalize( m_vWidthDir.GetForModify() );
m_vHeightDir = vHeight; VectorNormalize( m_vHeightDir.GetForModify() );
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
When a
func_breakable_surfwindow is broken, the client renders a crack overlay by placing a panel grid starting fromm_vCornerand stepping alongvWidthStep/vHeightStep. On windows with non-trivial rotation, the crack overlay was displaced from the glass, sometimes by a large amount.Three independent bugs caused this:
The server computed
m_vCornerusing vertex positions, but the client independently re-derived the stepping directions viaVectorAngles(-m_vNormal) + AngleVectors. For rotated windows, the server's vertex-based axes and the client's trig-based axes diverge due to floating-point representation, causing the panel grid to drift from the surface.Fix: Add two new networked vectors
m_vWidthDirandm_vHeightDir, sent at full float precision (SPROP_NOSCALE). The server computes these from actual vertex positions; the client uses them directly. All three rendering functions and all server-side panel position calculations use the stored vectors instead of re-deriving them.m_vCorner1 unit off the glassWhen
DotProduct(m_vNormal, vAttackDir) < 0(attack from behind), the original code shifted all four corner vertices 1 unit along the normal before selectingm_vCorner. This placed the crack origin 1 unit away from the glass surface.Fix: Skip the vertex shift in the NEO path. Instead, the normal is computed from vertex positions before the flip check so the dot product test remains valid, and
m_vNormalis simply negated (not accompanied by a vertex shift) when needed.When the BSP compiler's "width" edge (LLV to LRV) is more aligned with the canonical height axis than the width axis (e.g., a window whose width edge is vertical), the server swaps
vWidth/vHeightbefore corner selection. Two mistakes in this swap path:flDirscaling: The original code multiplied by flDir during the swap to cancel the effect of the vertex shift it had just applied. Since NEO skips the vertex shift, this scaling incorrectly negated the edge vectors for flDir = 1 (back-face attack), producing wrong bLeft/bLower values.Transposed corner table: After the swap,
vWidthspans what was the BSP height axis (LLV-ULV) andvHeightspans the BSP width axis (LLV-LRV). ThebLeft/bLowervertex-label mapping is only valid in the unswapped frame. In the swapped frame the table must be transposed:bLeftindexes into LLV, LRV andbLowerindexes into LLV, ULV.Fix: Remove
flDirfrom the swap and add abSwappedflag that selects the correct corner table.Toolchain