What happened to OC? - CLOSED Carnage?!
PiRate

Useless Information You Didn't Need to Know About sleep_until

Tiddy-bits:

Definitely interesting. I have always understood the "period" to be how many times per second it checks, rather than an interval of ticks, if I am remembering correctly from the documentation; and that it defaults to once per second if no argument is given. In my experience putting "30" as the period gives much faster results (from stimulus to advancement, theoretically checking every tick) than leaving it default.

Edited by TCK

Umh7x1l.gif

Share this post


Link to post
Share on other sites

I am unsure how to explain your experience with sleep_until's second parameter. Preliminary testing indicates that omitting the second parameter and setting it to 30 yield the same result. Additionally, evaluating (sleep_until false 1 90) produces 90 evaluations of the condition in 3 seconds, as expected.

Investigation into the code also corroborates this.

 

CPU Disasm
Address       Command                                              Comments
004898F3  |.  MOV EAX,DWORD PTR SS:[LOCAL.2]
004898F7  |.  MOV BYTE PTR DS:[EAX],0                              ; condition value, default 0 (false)
004898FA  |.  MOV EAX,DWORD PTR DS:[Globals::lpGameTimeGlobals]
004898FF  |.  MOV EAX,DWORD PTR DS:[EAX+0C]
00489902  |.  MOV DWORD PTR DS:[EDX],EAX                           ; sets call_time = lpGameTimeGlobals->game_ticks
00489904  |.  MOV EAX,DWORD PTR SS:[LOCAL.3]
00489908  |.  MOV WORD PTR DS:[EDI],0                              ; bool that is set when 2nd and 3rd args are evaluated/defaulted
0048990D  |.  MOV WORD PTR DS:[EBX],1E                             ; period, default 0x1E (30 decimal) ticks
00489912  |.  MOV DWORD PTR DS:[EAX],-1                            ; timeout, default -1

This snippet sets up the period to the value to 30, later taking on the value of the second argument when and if it is evaluated, and remains unchanged if the second argument is omitted.

 

As to how that argument is used:

CPU Disasm
Address       Command                                              Comments
004899BF  |.  MOV EAX,DWORD PTR SS:[LOCAL.1]                       ; EAX <- &period
004899C3  |.  MOV AX,WORD PTR DS:[EAX]                             ; AX <- period
004899C6  |.  CMP AX,1                                             ; AX <- max(period, (short)1)
004899CA  |.  JGE SHORT 004899D3                                   ; ^     ^
004899CC  |.  MOV EAX,1                                            ; ^     ^
004899D1  |.  JMP SHORT 004899D6                                   ; ^     ^
004899D3  |>  MOVSX EAX,AX                                         ; (long)max(period, (short)1)
004899D6  |>  MOV ECX,DWORD PTR DS:[Globals::lpGameTimeGlobals]
004899DC  |.  MOV EDX,DWORD PTR DS:[ECX+0C]                        ; lpGameTimeGlobals->game_ticks
004899DF  |.  MOV ECX,DWORD PTR SS:[LOCAL.3]
004899E3  |.  ADD EAX,EDX                                          ; EAX <- game_ticks + max(period, (short)1)
004899E5  |.  MOV DWORD PTR SS:[EBP+8],EAX                         ; lpThread->wake_tick = game_ticks + max(period, (short)1)

sleep_until's mechanism is implemented by setting a value that indicates to the script engine on what tick the script thread can be updated again, as shown here in the thread update function:

Address      Command                                              Comments
0048A410  |>  /MOV ECX,DWORD PTR DS:[ESI+8]                        ; ECX <- lpScriptThread->wake_tick
0048A413  |.  |TEST ECX,ECX
0048A415  |.  |JL 0048A4FC                                         ; stops thread update if lpThread->wake_tick < 0
0048A41B  |.  |MOV EAX,DWORD PTR DS:[Globals::lpGameTimeGlobals]
0048A420  |.  |CMP BYTE PTR DS:[EAX],0
0048A423  |.  |JE SHORT 0048A43C                                   ; skips time check if game is not ready
0048A425  |.  |MOV DL,BYTE PTR DS:[EAX+1]
0048A428  |.  |TEST DL,DL
0048A42A  |.  |JNZ SHORT 0048A433                                  ; skips time check if game is not running
0048A42C  |.  |MOV DL,BYTE PTR DS:[EAX+2]
0048A42F  |.  |TEST DL,DL
0048A431  |.  |JZ SHORT 0048A43C                                   ; skips time check if game is paused
0048A433  |>  |CMP ECX,DWORD PTR DS:[EAX+0C]                       ; cmp lpThread->wake_tick, lpGameTimeGlobals->game_ticks
0048A436  |.  |JG 0048A4FC                                         ; stops thread update if lpThread->wake_tick > lpGameTimeGlobals->game_ticks

Then, upon waking, the thread will check the condition again. If the condition evaluates to false, the thread is set to sleep another period ticks as indicated in the second snippet. Otherwise, if the condition evaluates to true, the script thread returns from the sleep_until call.

Edited by PiRate
silly dereference

Share this post


Link to post
Share on other sites

Hm I guess it's possible it was placebo. I could have sworn the original description I read of it specifically said, "checks <short> times per second if specified," but the Halo Scripting Bible doesn't say that so maybe I imagined it.

Edited by TCK

Umh7x1l.gif

Share this post


Link to post
Share on other sites

I had to do a workaround that accomplished this same result a few times for one of my scripts and hated it. Wasted variables and extra scripts to track the time. Very cool that this function exists. Nice work.

Share this post


Link to post
Share on other sites
  • Recently Browsing   0 members

    No registered users viewing this page.