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
IDXA
: The target variable (a GBVM variable) where the retrieved thread-local value will be stored.IDXB
: The index of the thread-local variable to retrieve. Each thread has an array or list of its own local variables, and IDXB
specifies which one to access.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.