mvbg

VM_GET_TLOCAL

VM_GET_TLOCAL is a GBVM instruction used to retrieve the value of a thread-local variable and store it into a specified GBVM variable.

Purpose: In a multi-threaded environment (where VM_BEGINTHREAD is used), each thread often needs its own independent set of data or state that is not shared with other threads. These are known as “thread-local variables.” VM_GET_TLOCAL allows a thread to access its own unique data without interfering with or being affected by the data of other threads.

This is crucial for:

Syntax:

VM_GET_TLOCAL IDXA, IDXB

Usage Example: Per-NPC Action Counter

Imagine you have multiple NPCs, each running in its own thread, and each needs to perform a specific action (e.g., blinking, waving) a certain number of times. You can use a thread-local variable to keep track of the remaining actions for each NPC independently.

; Define a generic NPC action script that uses a thread-local counter
NPC_ACTION_SCRIPT:
  ; Thread-local variable at index 0 will be our action counter
  ; Assume it was initialized when the thread was created (e.g., via NARGS in VM_BEGINTHREAD)

  VM_GET_TLOCAL VAR_TEMP_COUNTER, 0 ; Get the current value of the thread-local counter (index 0)

  VM_IF_CONST VAR_TEMP_COUNTER > 0
    ; Perform the action (e.g., play a blink animation)
    VM_ACTOR_EMOTE ACTOR_SELF, EMOTE_BLINK
    VM_IDLE 30 ; Wait for half a second

    ; Decrement the thread-local counter
    VM_RPN
      .R_REF_MEM .R_INT8, VAR_TEMP_COUNTER ; Get current counter value
      .R_INT8 1                           ; Push 1
      .R_OPERATOR -                       ; Subtract
      .R_REF_MEM_SET .R_INT8, VAR_TEMP_COUNTER ; Store back into VAR_TEMP_COUNTER
    VM_STOP

    VM_JUMP NPC_ACTION_SCRIPT ; Loop back to check counter again
  VM_ENDIF

  VM_TERMINATE ; End thread when counter reaches 0

; In your main game script, when spawning NPCs:

; Spawn NPC 1 thread, passing initial action count (e.g., 5 blinks)
VM_PUSH_CONST 5 ; Push initial counter value onto stack
VM_BEGINTHREAD BANK(NPC_ACTION_SCRIPT), NPC_ACTION_SCRIPT, VAR_NPC1_THREAD_HANDLE, 1 ; NARGS = 1

; Spawn NPC 2 thread, passing initial action count (e.g., 3 blinks)
VM_PUSH_CONST 3 ; Push initial counter value onto stack
VM_BEGINTHREAD BANK(NPC_ACTION_SCRIPT), NPC_ACTION_SCRIPT, VAR_NPC2_THREAD_HANDLE, 1 ; NARGS = 1

In this example, each NPC_ACTION_SCRIPT instance (running in its own thread) gets its own independent VAR_TEMP_COUNTER via VM_GET_TLOCAL. When NPC 1 blinks and decrements its counter, it doesn’t affect NPC 2’s counter, allowing both to perform their actions independently.

Analogy to other programming languages: This is directly analogous to “Thread-Local Storage” (TLS) or ThreadLocal variables in languages like Java, C++ (thread_local keyword), or Python (threading.local). Each thread gets its own copy of the variable, ensuring data isolation and preventing conflicts when multiple threads execute the same code concurrently.