Difference between revisions of "User:DavidJCobb/Stack dumping"
→Code snippets: More snippets, and explanations for all snippets.
imported>DavidJCobb |
imported>DavidJCobb (→Code snippets: More snippets, and explanations for all snippets.) |
||
Line 43: | Line 43: | ||
=== Process a task OnHit, and don't re-process for X seconds === | === Process a task OnHit, and don't re-process for X seconds === | ||
This code blocks concurrent OnHit calls, so we don't try to process multiple hits on the same actor at the same time. It also blocks calls for X seconds after we've finished processing a hit. | |||
<source lang="Papyrus"> | <source lang="Papyrus"> | ||
Bool Property pbBusy = False Auto Hidden | Bool Property pbBusy = False Auto Hidden ; prevents concurrent execution | ||
Bool Property pbProcessed = False Auto Hidden | Bool Property pbProcessed = False Auto Hidden ; prevents re-processing | ||
Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) | Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) | ||
Line 63: | Line 65: | ||
pbProcessed = False | pbProcessed = False | ||
EndEvent | EndEvent | ||
</source> | |||
=== Process a task OnHit, and wait for X seconds during the task === | |||
This simple example blocks concurrent calls, and replaces a Utility.Wait(X) call with a RegisterForSingleUpdate(X) call. If we used Utility.Wait(X), we'd suspend our stack for X seconds; by using RegisterForSingleUpdate and OnUpdate, we get rid of the stack entirely during those X seconds, and create a new stack to continue processing after the delay. | |||
<source lang="Papyrus"> | |||
Bool Property pbBusy = False Auto Hidden ; prevents concurrent execution | |||
Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) | |||
If pbBusy || pbProcessed | |||
Return | |||
EndIf | |||
pbBusy = True | |||
; | |||
; Do your processing here. | |||
; | |||
RegisterForSingleUpdate(x) ; replace "X" with the seconds you want to spend waiting | |||
EndEvent | |||
Event OnUpdate() | |||
; | |||
; Continue processing here. | |||
; | |||
pbBusy = False ; We're done! | |||
EndEvent | |||
</source> | |||
=== Process a task OnHit, without outright discarding concurrent calls === | |||
We want to avoid doing processing during concurrent calls, but we may not want to outright discard concurrent calls. If an enemy is hit four times in rapid succession, we'll want to process all four hits, but we'll want to do so in just one stack, if possible. To accomplish this, we block concurrent calls, but we keep track of how many such calls we've blocked; and in a loop, we run our task that number of times. | |||
<source lang="Papyrus"> | |||
Bool Property pbBusy = False Auto Hidden ; prevents concurrent execution | |||
Int Property piBlocked = 0 Auto Hidden ; tracks how many concurrent calls were prevented | |||
Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) | |||
DoProcess() | |||
EndEvent | |||
Event OnUpdate() | |||
DoProcess() | |||
EndEvent | |||
Function DoProcess() | |||
If pbBusy ; This is a concurrent call. | |||
piBlocked += 1 ; Keep track of it and we'll get to it later. | |||
Return | |||
EndIf | |||
pbBusy = True ; Block concurrent calls. | |||
Int iTasksToProcess = piBlocked ; This is how many times we plan to process our task. | |||
piBlocked = 0 ; Reset the concurrent call counter, so we can handle calls that happen while we process. | |||
Int iIterator = 0 | |||
While iIterator < iTasksToProcess | |||
; | |||
; Do your processing here. | |||
; | |||
iIterator += 1 | |||
EndWhile | |||
pbBusy = False ; Stop blocking concurrent calls. | |||
If piBlocked | |||
; | |||
; If this runs, it's because another event fired while we were processing. | |||
; We need to re-process. Doing that in an update creates a new call stack, | |||
; which will hopefully prevent issues caused by too much recursion. | |||
; | |||
RegisterForSingleUpdate(0.1) | |||
EndIf | |||
EndFunction | |||
</source> | </source> |