View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0005331 | The Dark Mod | Physics | public | 22.08.2020 15:09 | 23.08.2020 07:36 |
Reporter | stgatilov | Assigned To | stgatilov | ||
Priority | normal | Severity | major | Reproducibility | sometimes |
Status | resolved | Resolution | fixed | ||
Product Version | TDM 2.08 | ||||
Target Version | TDM 2.09 | Fixed in Version | TDM 2.09 | ||
Summary | 0005331: Doors get stuck sometimes: neither player nor AI can open them | ||||
Description | Sometimes doors get into horribly broken state, where they cannot move at all. Frobbing it has no effect (no movements, no sounds), AI cannot open it and gets stuck. | ||||
Steps To Reproduce | Happens very rarely (I cannot reproduce it yet). See the attached savegame for 2.08 release on "CoS2: A Precarious Position" FM. | ||||
Additional Information | Originally reported by darksilence here: https://forums.thedarkmod.com/index.php?/topic/20529-doors-and-other-handles-like-switches-become-unusable-sometimes/ | ||||
Tags | No tags attached. | ||||
Original savegame by darksilence: https://thedarkmod.blob.core.windows.net/various/bugtracker/darksilence_baddoors.save |
|
The door in question is called: atdm_door_96x48_2hinge_3 It has an entity in m_FrobPeers called: func_static_1130 I assume this entity is the door handle. Here is the state of the handle: m_Open true m_bIntentOpen false m_StateChange true m_bInterruptable false m_ClosedAngles {pitch=0.000000000 yaw=0.000000000 roll=0.000000000 } m_OpenAngles {pitch=-45.0000000 yaw=0.000000000 roll=0.000000000 } m_Rotating true bool m_Translating false bool In idMover: move {stage=ACCELERATION_STAGE (0) acceleration=0 movetime=0 ...} idMover::moveStage_s rot {stage=FINISHED_STAGE (3) acceleration=0 movetime=112 rot.pitch=-401.785736 ...} idMover::rotationState_s dest_angles {pitch=-45.0000000 yaw=0.000000000 roll=0.000000000 } idAngles angle_delta {pitch=-401.785736 yaw=0.000000000 roll=0.000000000 } idAngles And in physics.current: time 17070859 int atRest 17070859 int angles {pitch=-44.9999886 yaw=-90.0000000 roll=0.000000000 } idAngles localAngles {pitch=315.000000 yaw=0.000000000 roll=0.000000000 } idAngles linearExtrapolation {extrapolationType=EXTRAPOLATION_NONE (1) startTime=0.000000000 duration=0.000000000 ...} idExtrapolate<idVec3> angularExtrapolation {extrapolationType=EXTRAPOLATION_LINEAR (2) startTime=17070748.0 duration=112.000000 ...} idExtrapolate<idAngles> Here is angularExtrapolation inside: extrapolationType EXTRAPOLATION_LINEAR (2) extrapolation_t startTime 17070748.0 float duration 112.000000 float startValue {pitch=0.000000000 yaw=0.000000000 roll=0.000000000 } idAngles baseSpeed {pitch=0.000000000 yaw=0.000000000 roll=0.000000000 } idAngles speed {pitch=-401.785736 yaw=0.000000000 roll=0.000000000 } idAngles currentTime -1.00000000 float currentValue {pitch=0.000000000 yaw=0.000000000 roll=0.000000000 } idAngles The current time is: time 17294307 int |
|
The biggest problem that I see is that localAngles.pitch has become 315 instead of -45. Most likely something did not finish because of this. The angle extrapolation seems to be long finished, as seen from rot.stage = FINISHED_STAGE. I think what happens is wrong usage of angle normalization functions, perhaps in presence of numeric errors. For example, this code in idMover::BeginRotation is suspicious, since it can turn -45 into 315: physicsObj.GetLocalAngles( ang ); angle_delta = dest_angles - ang; if ( angle_delta.Compare(ang_zero, VECTOR_EPSILON) ) { // set our final angles so that we get rid of any numerical inaccuracy dest_angles.Normalize360(); physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, dest_angles, ang_zero, ang_zero ); stopRotation = false; DoneRotating(); return; } The code in CBinaryFrobMover::IsAtOpenPosition and CBinaryFrobMover::IsAtClosedPosition is definitely wrong in case of numeric errors: const idAngles& localAngles = physicsObj.GetLocalAngles(); // greebo: Let the check be slightly inaccurate (use the standard epsilon). return (localAngles - m_OpenAngles).Normalize360().Compare(ang_zero, VECTOR_EPSILON) && localOrg.Compare(m_OpenOrigin, VECTOR_EPSILON); Obviously, if different is slightly less than zero, then this condition does not hold. It should be Normalize180 here, not Normalize360. So it might have happened that some rotation did not finish exactly, so the value was slightly less than m_OpenAngles. Then IsAtOpenPosition returned false, hence idMover::BeginRotation was started, which turned the angle into 315. It might also be that uncapped FPS has made this issue trigger, since it has randomized timesteps, leading to randomized numeric errors. |
|
One more interesting fact is that idCurve<type>::GetCurrentValue takes global time as float. So when time is 17294307 (i.e. 5 hours have passed), rounding to float can give 1-2 ms of error! For this reason, the problem can start happening only after very long time in-game... |
|
I found way to reproduce. 1) Set Uncapped FPS to ON. 2) Start FM. 3) noclip & notarget 4) setviewpos -1230 300 90 5) Pause the game in MSVC debugger and change gameLocal.time to 20000000 in watch. 6) Continue game 7) Go to the door and frob it repeatedly. After a few attemps the handle will get stuck. |
|
However, most of my guesses are wrong. Mainly, it is normal for localAngles to become 315. It is normalized to 0..360 interval on every update, so value -45 is impossible. Thus, the code in idMover::BeginRotation is not wrong to do Normalize360. In fact, debugging shows that it is never executed (while doors get broken). |
|
Added commands getGameTime and setGameTime in svn rev 8944. The issue can now be reproduced like this: 1) Start Bakery Job FM. 2) Execute: notarget 3) Come to front door and unlock it. 4) Execute: setGameTime 20000000 5) Open/close the door until it gets stuck. |
|
Added sequence file to reproduce the problem with automation in svn rev 16007. It sets game time to 200M (it's about 55 hours in-game) --- that's ten times worse than what original complaint had. At such time, any door gets stuck from the first try. Fixed the problem in svn rev 8946 by switching idInterpolate and idExtrapolate to double precision. Note that only values which store absolute time are converted: various durations and deltas remain in single precision. These classes control movement of the door, and they gave enough error at high time to break door handling code. With this change, opening and closing the door 100 times at gametime = 200M works properly. I have checked that nothing performance-critical uses these classes (e.g. it is NOT used for particles), so this change won't decrease performance. Also committed a change in svn rev 8945 to make IsAtOpenPosition and IsAtClosedPosition more reliable. |
|
Date Modified | Username | Field | Change |
---|---|---|---|
22.08.2020 15:09 | stgatilov | New Issue | |
22.08.2020 15:09 | stgatilov | Status | new => assigned |
22.08.2020 15:09 | stgatilov | Assigned To | => stgatilov |
22.08.2020 15:13 | stgatilov | Note Added: 0012749 | |
22.08.2020 15:21 | stgatilov | Note Added: 0012750 | |
22.08.2020 15:23 | stgatilov | Note Edited: 0012750 | |
22.08.2020 15:31 | stgatilov | Note Edited: 0012750 | |
22.08.2020 15:43 | stgatilov | Note Added: 0012751 | |
22.08.2020 15:58 | stgatilov | Note Added: 0012752 | |
22.08.2020 16:30 | stgatilov | Note Added: 0012753 | |
22.08.2020 16:40 | stgatilov | Note Added: 0012754 | |
23.08.2020 04:32 | stgatilov | Note Added: 0012755 | |
23.08.2020 07:36 | stgatilov | Note Added: 0012756 | |
23.08.2020 07:36 | stgatilov | Status | assigned => resolved |
23.08.2020 07:36 | stgatilov | Resolution | open => fixed |
23.08.2020 07:36 | stgatilov | Fixed in Version | => TDM 2.09 |