Repository navigation
Unit scripts: no double scheduling, completions sent once, COB UNIT_TEAM, failed LUS Killed, COB woken threads in saves - #3479
Open
moss-orbit-9f339e wants to merge 2 commits into
Conversation
…_TEAM, failed Killed, COB waiting threads in saves - CUnitScriptEngine::AddInstance did not check that the script was already in animating. In the single-threaded part of Tick, a completion callback of script A can start an animation on script B after B's last animation ended in this tick but before B was removed from animating; B then had two entries, and the next tick ran TickAllAnims for B twice, on two worker threads at the same time. Pass checkIfUnique = true. - TickAnimFinished sent the completions in doneAnims again each time it ran. doneAnims is cleared only in TickAllAnims, so a script that was added again in the same tick (see above) sent its old completions a second time and could wake a thread that waits on a new animation of the same piece and axis. A completion is now sent once (hasWaiting is cleared); the records stay for DumpState. - COB GetUnitVal(UNIT_TEAM, id) returned the team of the calling unit, not of unit id. - LUS Killed: when the callin raised an error, inKilled stayed true and KilledScriptFinished was never called, so the dead unit was never removed. Finish with the default wreck level, as for a bad return value. - CCobEngine: waitingThreadIDs was not saved (CR_IGNORED, "always empty when saving"). It is not empty at the end of a frame: a COB thread that is woken after TickRunningThreads (for example when its animation ends in CUnitScriptEngine::Tick) waits there for the next frame. After a load, such a thread was in no list and never ran again. Found by a Codex audit and checked by a second review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Five fixes in the unit script engine. They change synced behaviour only in the cases that they describe.
animatingtwo times.CUnitScriptEngine::AddInstancecalledVectorInsertUniquewithoutcheckIfUnique(thetruewas commented out). In the single-threaded part ofTick, a completion callback of script A can start an animation on script B after B's last animation ended in this tick (inTickAllAnims) but before B's turn in the loop removed it.HaveAnimations()is then false, so B was added a second time. In the next tickfor_mtranTickAllAnimsfor B on two threads at the same time.TickAnimFinishedsends the completions indoneAnims, which is cleared only inTickAllAnims. A script that is added again in the same tick (see above) sent its old completions a second time, which could wake a thread that waits on a new animation of the same piece and axis. A completion is now sent once (hasWaitingis cleared); the records stay forDumpState.UNIT_TEAM:GetUnitVal(UNIT_TEAM, id)returned the team of the calling unit, not the team of unitid.Killederror: when the callin raised an error,inKilledstayed true andKilledScriptFinishedwas never called, so the dead unit was never removed. It now finishes with the default wreck level, as the code already does for a bad return value.waitingThreadIDswasCR_IGNORED("always empty when saving"), but a COB thread that is woken afterTickRunningThreads(for example when its animation ends inCUnitScriptEngine::Tick) waits there for the next frame. After a load it was in no list and never ran again. It is now saved.Sync: changes only in the cases above. The replay below gives the same checksums as master, so it does not reach them.
Testing (Windows, RTX 3080; master
01efdf4312and this branch, each with thespringcontent.sdzof its own build; a Zero-K replay on Nuclear Winter, 29 players and about 1,000 units, many LUS units):UNIT_TEAMquery, aKillederror or a save with a woken COB thread. These are checked by reading the code.AI disclosure: OpenAI Codex (GPT-6 Astra and GPT-6.1 Sol) found these bugs in code audits and drafted the fixes; a second Codex review checked the branch. Claude Code checked each finding against the code, reviewed and edited every change, and ran the tests.
🤖 Generated with Claude Code