|
6 | 6 | <description> |
7 | 7 | A script implemented in the GDScript programming language. The script extends the functionality of all objects that instance it. |
8 | 8 | [method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes. |
| 9 | + A GDScript object can also be used as standalone, isolated script to safely run code supplied by players (either as mods or part of the game mechanic) if globals are disabled for that particular script. Disabling globals means all classes, engine singletons, project autoload scripts, and even constants which are not defined in that script (such as [code]PI[/code]) will no longer be accessible, and a script with globals disabled attempting to include those will fail to compile and run. (This is set per script, not per instance.) |
| 10 | + Since node classes (such as [Node]) can't be accessed if globals are disabled (and therefore inheritance such as [code]extends Node[/code] is not possible), those scripts can only be created and used from other scripts, not directly as nodes in the [SceneTree]. |
| 11 | + Assuming the following [code]res://user_script.gd[/code]: |
| 12 | + [codeblock] |
| 13 | + var my_var |
| 14 | + |
| 15 | + func my_func(arg): |
| 16 | + print("Hello %s!" % arg) |
| 17 | + [/codeblock] |
| 18 | + A node in the [SceneTree] can safely run this script with globals disabled: |
| 19 | + [codeblock] |
| 20 | + var new_script = load("res://user_script.gd") |
| 21 | + new_script.set_globals_disabled(true) |
| 22 | + if new_script.reload(): |
| 23 | + # Script recompiled successfully |
| 24 | + var new_script_instance = new_script.new() |
| 25 | + # Any method can be called externally, |
| 26 | + # and variables can be externally assigned |
| 27 | + new_script_instance.my_var = 42 |
| 28 | + new_script_instance.my_func("world") # prints "Hello world!" |
| 29 | + else: |
| 30 | + # Pauses with an error if running from the editor, |
| 31 | + # fails silently and continues running in standalone build |
| 32 | + print("Failed to compile script") |
| 33 | + [/codeblock] |
| 34 | + The script doesn't need to be stored as a [code].gd[/code] file. It can be compiled from source code retrieved or generated during gameplay: |
| 35 | + [codeblock] |
| 36 | + var my_source_code = "func main():\n print(\"Hello world!\")\n" |
| 37 | + var new_script = GDScript.new() |
| 38 | + new_script.source_code = my_source_code |
| 39 | + new_script.set_globals_disabled(true) |
| 40 | + if new_script.reload(): |
| 41 | + new_script.new().main() |
| 42 | + else: |
| 43 | + print("Failed to compile script") |
| 44 | + [/codeblock] |
| 45 | + [b]Note:[/b] although global names won't work in the code, a script with globals disabled [i]can access[/i] anything if given [i]explicit[/i] access through method arguments or variable assignments. As example, assuming the [code]res://test_script.gd[/code] script: |
| 46 | + [codeblock] |
| 47 | + var input |
| 48 | + |
| 49 | + func do_something(): |
| 50 | + if input.is_action_pressed("ui_accept"): |
| 51 | + print("Hello world!") |
| 52 | + [/codeblock] |
| 53 | + The [code]input[/code] local variable can be used to give the script access to the [Input] singleton: |
| 54 | + [codeblock] |
| 55 | + var new_script = load("res://test_script.gd") |
| 56 | + new_script.set_globals_disabled(true) |
| 57 | + if new_script.reload(): |
| 58 | + var new_script_instance = new_script.new() |
| 59 | + new_script_instance.set("input", Input) |
| 60 | + new_script_instance.do_something() |
| 61 | + [/codeblock] |
| 62 | + Notice the use of [method Object.set] instead of [code]new_script_instance.input = Input[/code]. If the user script did not declare the [code]input[/code] variable, using [method Object.set] fails silently, and therefore declaring and using the variable becomes optional from the user point of view. |
| 63 | + [b]Warning:[/b] since the scripts with globals disabled can access any properties and methods of objects which are explicitly given to them, critical care must be taken when exposing those objects. As example, if a node in the [SceneTree] is given, methods such as [method Node.get_node] or [method Node.get_tree] would give the script access to a large part or potentially the whole of the project. For cases like game mods (which usually need to expose running game objects and assets), an intermediate interface must be carefully designed to prevent abuse. |
9 | 64 | </description> |
10 | 65 | <tutorials> |
11 | 66 | <link>$DOCS_URL/tutorials/scripting/gdscript/index.html</link> |
|
17 | 72 | Returns byte code for the script source code. |
18 | 73 | </description> |
19 | 74 | </method> |
| 75 | + <method name="is_globals_disabled"> |
| 76 | + <return type="bool" /> |
| 77 | + <description> |
| 78 | + Returns [code]true[/code] if globals are disabled for this script. |
| 79 | + </description> |
| 80 | + </method> |
20 | 81 | <method name="new" qualifiers="vararg"> |
21 | 82 | <return type="Variant" /> |
22 | 83 | <description> |
|
29 | 90 | [/codeblock] |
30 | 91 | </description> |
31 | 92 | </method> |
| 93 | + <method name="set_globals_disabled"> |
| 94 | + <return type="void" /> |
| 95 | + <argument index="0" name="disabled" type="bool" /> |
| 96 | + <description> |
| 97 | + Sets whether access to globals should be disabled for this script, including class names, engine singletons, project autoload scripts, and anything not defined in the script itself or given explicit access externally. |
| 98 | + </description> |
| 99 | + </method> |
32 | 100 | </methods> |
33 | 101 | <constants> |
34 | 102 | </constants> |
|
0 commit comments