Difference between revisions of "User:DavidJCobb/Stack dumping"

3,115 bytes added ,  19:31, 2 March 2015
→‎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>
Anonymous user