├── .editorconfig
├── .github
├── FUNDING.yml
└── workflows
│ ├── build.yml
│ └── test.yml
├── .gitignore
├── .gitmodules
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── build
└── .gdignore
├── config.ld
├── extras
├── .gdignore
├── articles
│ ├── 1-design-en.md
│ ├── 1-design-pt.md
│ ├── 2-create-gdnativelibrary-save.png
│ ├── 2-create-gdnativelibrary.png
│ ├── 2-create-resource.png
│ ├── 2-infrastructure-en.md
│ ├── 2-infrastructure-pt.md
│ ├── 2-pick-so-save.png
│ ├── 2-pick-so.png
│ ├── 2-pluginscript-xmake-lua.png
│ ├── 2-set-singleton.png
│ ├── 2-settings-gdnative-enabled.png
│ ├── 3-luajit-callbacks-en.md
│ ├── 3-luajit-callbacks-pt.md
│ └── 3-script-init-xmake-lua.png
├── docs
│ ├── building.md
│ ├── configuring.md
│ ├── from-gdscript-to-lua.md
│ ├── limitations.md
│ ├── luarocks.md
│ ├── plugin-enabling.png
│ ├── plugin-repl.png
│ └── plugin.md
└── icon.png
├── lib
└── .gdignore
├── lps_coroutine.lua
├── lua_pluginscript.gdnlib
├── plugin
├── export_plugin.lua
├── in_editor_callbacks
│ ├── .gdignore
│ └── init.lua
├── lua_repl.lua
├── lua_repl.tscn
├── luasrcdiet
│ └── .gdignore
├── plugin.cfg
└── plugin.gd
└── src
├── .gdignore
├── cache_lua_libs.lua
├── godot_aabb.lua
├── godot_array.lua
├── godot_array_commons.lua
├── godot_basis.lua
├── godot_class.lua
├── godot_color.lua
├── godot_dictionary.lua
├── godot_enums.lua
├── godot_ffi.lua
├── godot_node_path.lua
├── godot_object.lua
├── godot_plane.lua
├── godot_pool_byte_array.lua
├── godot_pool_color_array.lua
├── godot_pool_int_array.lua
├── godot_pool_real_array.lua
├── godot_pool_string_array.lua
├── godot_pool_vector2_array.lua
├── godot_pool_vector3_array.lua
├── godot_quat.lua
├── godot_rect2.lua
├── godot_rid.lua
├── godot_string.lua
├── godot_string_name.lua
├── godot_transform.lua
├── godot_transform2d.lua
├── godot_variant.lua
├── godot_vector2.lua
├── godot_vector3.lua
├── language_gdnative.c
├── late_globals.lua
├── lua_globals.lua
├── lua_math_extras.lua
├── lua_object_struct.lua
├── lua_object_wrapper.lua
├── lua_package_extras.lua
├── lua_string_extras.lua
├── pluginscript_callbacks.lua
├── pluginscript_instance.lua
├── pluginscript_property.lua
├── pluginscript_script.lua
├── pluginscript_signal.lua
├── register_in_editor_callbacks.lua
├── test
├── array.lua
├── class_wrapper.lua
├── coroutines.lua
├── extras
│ ├── invalid_extends.lua
│ ├── parse_error.lua
│ ├── valid_script.lua
│ └── valid_script_class_wrapper.lua
├── init.lua
├── require_luac.lua
├── script_loading.lua
├── setter_newindex.lua
└── test_cmodule.c
└── tools
├── add_script_c_decl.sed
├── compact_c_ffi.sed
├── embed_to_c.sed
├── project.godot
├── remove_lua_comments.sed
└── squeeze_blank_lines.sed
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | encoding = utf-8
5 | indent_style = tab
6 | indent_size = 4
7 |
8 | [*.{md,yml,yaml}]
9 | indent_style = space
10 | indent_size = 2
11 |
12 | [*.sed]
13 | indent_size = 2
14 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [gilzoide] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: gilzoide # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: gilzoide # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: [ 'https://www.paypal.com/donate/?hosted_button_id=BFFW9Z3DBYHBA', 'https://www.buymeacoffee.com/gilzoide'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | on: [push, pull_request]
3 | defaults:
4 | run:
5 | shell: bash
6 |
7 | env:
8 | DEBUG: 1
9 |
10 | jobs:
11 | build_linux:
12 | name: Build Linux
13 | runs-on: ubuntu-latest
14 | strategy:
15 | matrix:
16 | target:
17 | - linux64
18 | - linux32
19 | steps:
20 | - uses: actions/checkout@v3
21 | with:
22 | submodules: true
23 | - name: Install dependencies
24 | run: |
25 | sudo apt-get update
26 | sudo apt-get install libc6-dev-i386
27 | - name: Build artifact
28 | run: make ${{ matrix.target }}
29 | - name: Upload artifact
30 | uses: actions/upload-artifact@v3
31 | with:
32 | name: linux-x86-x86_64
33 | path: |
34 | build/linux_x86/liblua_pluginscript.so
35 | build/linux_x86_64/liblua_pluginscript.so
36 |
37 | build_windows:
38 | name: Build Windows
39 | runs-on: ubuntu-latest
40 | strategy:
41 | matrix:
42 | target:
43 | - mingw-windows32
44 | - mingw-windows64
45 | steps:
46 | - uses: actions/checkout@v3
47 | with:
48 | submodules: true
49 | - name: Install dependencies
50 | run: |
51 | sudo apt-get update
52 | sudo apt-get install libc6-dev-i386 gcc-mingw-w64
53 | - name: Build artifact
54 | run: make ${{ matrix.target }}
55 | env:
56 | CC: gcc
57 | - name: Upload artifact
58 | uses: actions/upload-artifact@v3
59 | with:
60 | name: windows-x86-x86_64
61 | path: |
62 | build/windows_x86/lua51.dll
63 | build/windows_x86/lua_pluginscript.dll
64 | build/windows_x86_64/lua51.dll
65 | build/windows_x86_64/lua_pluginscript.dll
66 |
67 | build_osx_ios:
68 | name: Build OSX/iOS
69 | runs-on: macos-latest
70 | strategy:
71 | matrix:
72 | target:
73 | - osx64
74 | - ios64
75 | steps:
76 | - uses: actions/checkout@v3
77 | with:
78 | submodules: true
79 | - name: Build artifact
80 | run: make ${{ matrix.target }}
81 | env:
82 | LUA_BIN: lua5.1
83 | - name: Upload artifact
84 | uses: actions/upload-artifact@v3
85 | with:
86 | name: osx-ios-arm64-x86_64
87 | path: |
88 | build/osx_arm64_x86_64/lua_pluginscript.dylib
89 | build/ios_arm64/lua_pluginscript.dylib
90 | build/ios_simulator_arm64_x86_64/lua_pluginscript.dylib
91 |
92 | build_android:
93 | name: Build Android
94 | runs-on: ubuntu-latest
95 | strategy:
96 | matrix:
97 | target:
98 | - android-armv7a
99 | - android-aarch64
100 | - android-x86
101 | - android-x86_64
102 | env:
103 | ANDROID_NDK_VERSION: 21.4.7075529
104 | steps:
105 | - uses: actions/checkout@v3
106 | with:
107 | submodules: true
108 | - name: Install dependencies
109 | run: |
110 | sudo apt-get update
111 | sudo apt-get install libc6-dev-i386
112 | - name: Setup NDK
113 | run: |
114 | $ANDROID_HOME/tools/bin/sdkmanager --install "ndk;$ANDROID_NDK_VERSION"
115 | echo "ANDROID_NDK_ROOT=$ANDROID_HOME/ndk/$ANDROID_NDK_VERSION" >> $GITHUB_ENV
116 | - name: Build artifact
117 | run: make ${{ matrix.target }}
118 | - name: Upload artifact
119 | uses: actions/upload-artifact@v3
120 | with:
121 | name: android-armv7a-aarch64-x86-x86_64
122 | path: |
123 | build/android_armv7a/liblua_pluginscript.so
124 | build/android_aarch64/liblua_pluginscript.so
125 | build/android_x86/liblua_pluginscript.so
126 | build/android_x86_64/liblua_pluginscript.so
127 |
128 | build_distribution_zip:
129 | name: Build distribution zip
130 | needs: [build_linux, build_windows, build_osx_ios, build_android]
131 | runs-on: ubuntu-latest
132 | steps:
133 | - uses: actions/checkout@v3
134 | with:
135 | submodules: true
136 | - name: Download artifacts
137 | id: download
138 | uses: actions/download-artifact@v3
139 | with:
140 | path: artifacts
141 | - name: Copy artifacts to build folder
142 | run: cp -r ${{ steps.download.outputs.download-path }}/*/* build
143 | - name: Make distribution
144 | run: make dist
145 | - name: Upload artifact
146 | uses: actions/upload-artifact@v3
147 | with:
148 | name: lua_pluginscript
149 | path: |
150 | build/LICENSE
151 | build/addons/godot-lua-pluginscript/**
152 |
153 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | on: [push, pull_request]
3 | defaults:
4 | run:
5 | shell: bash
6 |
7 | env:
8 | DEBUG: 1
9 |
10 | jobs:
11 | test_linux:
12 | name: Run tests on Linux
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v3
16 | with:
17 | submodules: true
18 | - name: Install Godot
19 | run: |
20 | curl --location $GODOT_RELEASE_URL --output godot.zip
21 | unzip godot.zip
22 | mv Godot_* godot
23 | touch _sc_
24 | env:
25 | GODOT_RELEASE_URL: https://github.com/godotengine/godot/releases/download/3.5.1-stable/Godot_v3.5.1-stable_linux_headless.64.zip
26 | - name: Build and test
27 | run: make test-linux64
28 | env:
29 | GODOT_BIN: ./godot
30 |
31 | # Windows GitHub runner does not support creating an OpenGL context for running Godot =/
32 | # test_windows:
33 | # name: Run tests on Windows
34 | # runs-on: windows-latest
35 | # steps:
36 | # - uses: actions/checkout@v3
37 | # with:
38 | # submodules: true
39 | # - name: Install Godot
40 | # run: |
41 | # curl --location $GODOT_RELEASE_URL --output godot.zip
42 | # unzip godot.zip
43 | # mv Godot_*.exe godot.exe
44 | # touch _sc_
45 | # env:
46 | # GODOT_RELEASE_URL: https://github.com/godotengine/godot/releases/download/3.5.1-stable/Godot_v3.5.1-stable_win64.exe.zip
47 | # - name: Build and test
48 | # run: make test-windows64
49 | # env:
50 | # CC: gcc
51 | # GODOT_BIN: ./godot.exe
52 |
53 | test_osx:
54 | name: Run tests on OSX
55 | runs-on: macos-latest
56 | steps:
57 | - uses: actions/checkout@v3
58 | with:
59 | submodules: true
60 | - name: Install Godot
61 | run: |
62 | curl --location $GODOT_RELEASE_URL --output godot.zip
63 | unzip godot.zip
64 | env:
65 | GODOT_RELEASE_URL: https://github.com/godotengine/godot/releases/download/3.5.1-stable/Godot_v3.5.1-stable_osx.universal.zip
66 | - name: Build and test
67 | run: make test-osx64
68 | env:
69 | GODOT_BIN: ./Godot.app/Contents/MacOS/Godot
70 |
71 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 | build/
3 | .xmake/
4 | .cache/
5 | /docs/
6 | plugin/luasrcdiet/*
7 | !plugin/luasrcdiet/.gdignore
8 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/godot-headers"]
2 | path = lib/godot-headers
3 | url = https://github.com/godotengine/godot-headers.git
4 | [submodule "lib/high-level-gdnative"]
5 | path = lib/high-level-gdnative
6 | url = https://github.com/gilzoide/high-level-gdnative.git
7 | [submodule "lib/luajit"]
8 | path = lib/luajit
9 | url = https://github.com/LuaJIT/LuaJIT.git
10 | [submodule "lib/luasrcdiet"]
11 | path = lib/luasrcdiet
12 | url = https://github.com/jirutka/luasrcdiet.git
13 | [submodule "lib/luaunit"]
14 | path = lib/luaunit
15 | url = https://github.com/bluebird75/luaunit.git
16 | [submodule "lib/debugger_lua"]
17 | path = lib/debugger_lua
18 | url = https://github.com/slembcke/debugger.lua.git
19 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | ## [Unreleased](https://github.com/gilzoide/godot-lua-pluginscript/compare/0.5.2...HEAD)
3 |
4 |
5 | ## [0.5.2](https://github.com/gilzoide/godot-lua-pluginscript/releases/tag/0.5.2)
6 | ### Fixed
7 |
8 | - Fixed `undefined symbol: lua_*` when requiring Lua/C modules in POSIX systems
9 | ([#41](https://github.com/gilzoide/godot-lua-pluginscript/issues/41))
10 |
11 |
12 | ## [0.5.1](https://github.com/gilzoide/godot-lua-pluginscript/releases/tag/0.5.1)
13 | ### Fixed
14 |
15 | - Plugin initialization on Windows ([#31](https://github.com/gilzoide/godot-lua-pluginscript/issues/31))
16 | - [build] Fixed `make dist` dependencies to include LuaJIT's `jit/*.lua` files
17 | - [build] Fixed `make unzip-to-build` to only copy contents from `build` folder
18 |
19 |
20 | ## [0.5.0](https://github.com/gilzoide/godot-lua-pluginscript/releases/tag/0.5.0)
21 | ### Added
22 |
23 | - `join` method for all `Pool*Array` metatypes with the same implementation as
24 | for `Array` and `PoolStringArray`.
25 | - Possibility for using `ClassWrapper`s as `extends` of a script instead of
26 | their string name. E.g. script: `return { extends = Node }`
27 | - `Object:get_class_wrapper` method that returns the `ClassWrapper` associated
28 | with the Object's class.
29 | - `ClassWrapper:has_property` method that returns whether a class has a property
30 | with the passed name. Properties are considered available if they are found in
31 | the result of `ClassDB:class_get_property_list`.
32 | - Library mapping for `Server` platform pointing to the `linux_x86_64` build.
33 | - `string.quote` function for quoting values.
34 | - [build] Passing `DEBUG=1` to `make docs` adds `--all` flag to `ldoc`, which
35 | adds documentation for locals.
36 | - [build] Passing `DEBUG_INTERACTIVE=1` to `make test*` makes errors trigger
37 | a [debugger.lua](https://github.com/slembcke/debugger.lua) breakpoint, for
38 | debugging tests.
39 |
40 | ### Fixed
41 |
42 | - Return values passed to `lps_coroutine:resume(...)` when calling `GD.yield()`.
43 | - Comparing `Array` and `Pool*Array`s against Lua primitives like `nil` and
44 | numbers now return `false` instead of raising.
45 | - Support for `false` as the default value for a property.
46 |
47 | ### Changed
48 |
49 | - **BREAKING CHANGE**: `Array` and `Pool*Array`'s `__index` and `__newindex`
50 | metamethods now use 1-based indices to match Lua tables.
51 | For 0-based indexing, use `get`/`set` or `safe_get`/`safe_set` instead.
52 | - **BREAKING CHANGE**: property setter functions don't receive property name
53 | anymore ([#5](https://github.com/gilzoide/godot-lua-pluginscript/issues/5#issuecomment-999876834)).
54 | That is, instead of `function(self, property_name, value)`, setters now look
55 | like `function(self, value)`.
56 | - **BREAKING CHANGE**: script instances are now structs instead of tables.
57 | They still have a backing table for storing data, but indexing now calls
58 | getter and setter functions for known properties. Use `rawget` and `rawset`
59 | to bypass getter/setter functions and access the data table directly.
60 | ([#5](https://github.com/gilzoide/godot-lua-pluginscript/issues/5))
61 | - **BREAKING CHANGE**: `Object.call` now raises instead of failing silently.
62 | Use `Object.pcall` to protect from errors.
63 |
64 |
65 | ## [0.4.0](https://github.com/gilzoide/godot-lua-pluginscript/releases/tag/0.4.0)
66 | ### Added
67 |
68 | - Support for running without JIT enabled
69 | - Support for iOS builds
70 | - `export` function, an alias for `property` that always marks the property as
71 | exported
72 |
73 | ### Fixed
74 |
75 | - Quote `CODE_SIGN_IDENTITY` argument passed to `codesign` invocations
76 | - ABI mismatch for math types in Linux x86_64 + Mono ([#4](https://github.com/gilzoide/godot-lua-pluginscript/issues/4#issuecomment-985423759))
77 |
78 | ### Changed
79 |
80 | - **BREAKING CHANGE**: properties are not exported by default. Either pass
81 | a usage with the `PropertyUsage.EDITOR` bit set or call `export` instead of
82 | `property`
83 |
84 |
85 | ## [0.3.1](https://github.com/gilzoide/godot-lua-pluginscript/releases/tag/0.3.1)
86 | ### Added
87 |
88 | - Support for `codesign`ing OSX builds directly from make invocation.
89 | The optional parameters are `CODE_SIGN_IDENTITY` and `OTHER_CODE_SIGN_FLAGS`.
90 | - `LUA_BIN` option for specifying a Lua command other than `lua` when building
91 | - `native-luajit` make target, used by CI
92 | - `unzip-to-build` make target, for unzipping artifacts from CI to build folder
93 |
94 | ### Fixed
95 |
96 | - `strip` invocation on OSX builds
97 | - Update build GitHub Actions workflow with newer build pipeline
98 |
99 | ### Changed
100 |
101 | - Added `build/.gdignore` to distribution, to stop Godot from trying to import
102 | `build/jit/*.lua` files
103 | - Added default values for `MACOSX_DEPLOYMENT_TARGET`, making it an optional
104 | parameter for OSX builds
105 |
106 |
107 | ## [0.3.0](https://github.com/gilzoide/godot-lua-pluginscript/releases/tag/0.3.0)
108 | ### Added
109 |
110 | - `EditorExportPlugin` for minifying Lua scripts with `LuaSrcDiet` on
111 | release exports. Minification may be turned off with the
112 | `lua_pluginscript/export/minify_on_release_export` project setting.
113 |
114 | ### Changed
115 |
116 | - Release builds' init Lua script are minified with `LuaSrcDiet` and libraries
117 | are now `strip`ed, resulting in smaller dynamic libraries
118 | - HGDN functions are now compiled with static visibility and unused GDNative
119 | extensions are excluded, also resulting in smaller dynamic libraries
120 | - Makefile targets for cross-compiling for Windows were renamed from
121 | `cross-windows*` to `mingw-windows*`
122 |
123 | ### Fixed
124 |
125 | - `PoolByteArray.extend` when called with a string argument
126 |
127 |
128 | ## [0.2.0](https://github.com/gilzoide/godot-lua-pluginscript/releases/tag/0.2.0)
129 | ### Added
130 |
131 | - `Array.join` method, similar to `PoolStringArray.join`
132 | - Project Settings for setting up `package.path` and `package.cpath`
133 | - Bundle LuaJIT's `jit/*.lua` modules in build folder
134 |
135 | ### Fixed
136 |
137 | - Error handler now uses `tostring` to stringify the incoming parameter,
138 | avoiding type errors. It also checks for the result of `string.match`, so it
139 | does not errors if the message is not in the format expected.
140 | - Loading of C modules now uses absolute library paths, so that files found in
141 | patterns like `res://*` are correctly loaded.
142 | - Always try loading active library, so that dynamic loader knows about `lua*`
143 | symbols when loading C modules.
144 | - `Pool*Array`s' `__gc` metamethod
145 |
146 |
147 | ## [0.1.0](https://github.com/gilzoide/godot-lua-pluginscript/releases/tag/0.1.0)
148 | ### Added
149 |
150 | - `GD._VERSION`
151 | - `Object.null`
152 | - Call `Object.set` on `Object.__newindex`
153 | - Stack trace to error message when loading script fails
154 | - Initialize known properties when instantiating script
155 | - Unit test infrastructure
156 | - Android ARMv7/ARM64/x86/x86_64 builds
157 | - [plugin] REPL history, with up/down keys choosing previous/next line
158 |
159 | ### Fixed
160 |
161 | - Properties with `nil` as default value not accesible from Lua
162 | - Call `Array.duplicate` using API 1.1 instead of 1.0
163 | - `Array.duplicate` and `Array.slice` return value GC
164 | - Call `Dictionary.duplicate` using API 1.2 instead of 1.0
165 | - `VariantType` used for float properties
166 | - Calling `NodePath()` returns an empty NodePath, rather than one with the path `"nil"`
167 |
168 |
169 | ## [r1](https://github.com/gilzoide/godot-lua-pluginscript/releases/tag/r1)
170 | ### Added
171 |
172 | - Lua PluginScript language
173 | - Embedded LuaJIT
174 | - Metatypes for all Godot basic types
175 | - `yield` function similar to GDScript's
176 | - Script validation and template source code
177 | - Editor plugin with a simple REPL
178 | - Package searcher for Lua and C modules that work with paths relative to
179 | the `res://` folder and/or exported games' executable path
180 | - API documentation
181 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2021 Gil Barbosa Reis.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the “Software”), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Godot Lua PluginScript
2 |
3 |
4 |
5 | [](https://godotengine.org/asset-library/asset/1078)
6 | [](https://discord.gg/rZJbXZXQWe)
7 |
8 | > **WARNING**: This does not work with Godot 4, since it relies on GDNative, a Godot 3 only technology.
9 | >
10 | > To use Lua as a scripting language in Godot 4, use [Lua GDExtension](https://github.com/gilzoide/lua-gdextension) instead.
11 |
12 | GDNative + PluginScript library that adds support for [Lua](https://www.lua.org/)
13 | as a scripting language in [Godot](https://godotengine.org/) 3.
14 |
15 | Being a GDNative library, recompiling the engine is not required, so anyone
16 | with a built release copied to their project can use it.
17 | Being a PluginScript language, Lua can seamlessly communicate with scripts
18 | written in GDScript / C# / Visual Script and vice-versa.
19 | Since the Godot object model is dynamic at runtime, any Godot objects'
20 | properties/methods can be accessed from Lua, including singletons like `OS`,
21 | `ClassDB` and custom singleton nodes.
22 | This way, one can use the language that best suits the implementation for each
23 | script and all of them can understand each other.
24 |
25 | This plugin is available in the Asset Library as [Lua PluginScript](https://godotengine.org/asset-library/asset/1078).
26 |
27 | For some usage examples, check out [plugin/lua\_repl.lua](plugin/lua_repl.lua)
28 | and [plugin/export\_plugin.lua](plugin/export_plugin.lua).
29 |
30 | Currently, only LuaJIT is supported, since the implementation is based on its
31 | [FFI](https://luajit.org/ext_ffi.html) library.
32 |
33 |
34 | ## Installing
35 |
36 | Either:
37 |
38 | - In Godot Editor, open the [Asset Library tab](https://docs.godotengine.org/en/stable/tutorials/assetlib/using_assetlib.html#in-the-editor),
39 | search for the [Lua PluginScript](https://godotengine.org/asset-library/asset/1078)
40 | asset, download and install it.
41 | - Put a built release of the library into the project folder and restart Godot.
42 | Make sure the `lua_pluginscript.gdnlib` file is located at the
43 | `res://addons/godot-lua-pluginscript` folder.
44 | - Clone this repository as the project's `res://addons/godot-lua-pluginscript`
45 | folder and build for the desired platforms.
46 |
47 |
48 | ## Documentation
49 |
50 | - [From GDScript to Lua](extras/docs/from-gdscript-to-lua.md)
51 | - [Lua-specific API reference](https://gilzoide.github.io/godot-lua-pluginscript/topics/README.md.html)
52 | - [Configuring](extras/docs/configuring.md)
53 | - [Editor plugin (REPL and minify on release export)](extras/docs/plugin.md)
54 | - [Using LuaRocks](extras/docs/luarocks.md)
55 | - [Known limitations](extras/docs/limitations.md)
56 | - [Building](extras/docs/building.md)
57 | - [Changelog](CHANGELOG.md)
58 |
59 |
60 | ## Goals
61 |
62 | - Provide support for Lua as a scripting language in Godot in a way that does
63 | not require compiling the engine from scratch
64 | - Be able to seamlessly communicate with any other language supported by Godot,
65 | like GDScript, Visual Script and C#, in an idiomatic way.
66 | This includes being able to dynamically access any Godot object's properties
67 | and methods using Lua's index/method notation
68 | - Have automatic global access to Godot's singleton objects and custom
69 | singleton nodes
70 | - Simple script description interface that doesn't need `require`ing anything
71 | - Support for LuaJIT and Lua 5.2+
72 | - Support paths relative to `res://*` and exported game/app executable path for
73 | `require`ing Lua modules
74 | - Have a simple build process, where anyone with the cloned source code and
75 | installed build system + toolchain can build the project in a single step
76 |
77 |
78 | ## Non-goals
79 |
80 | - Provide calls to core Godot classes' methods via native method bindings
81 | - Support multithreading on the Lua side
82 |
83 |
84 | ## Articles
85 |
86 | 1. [Designing Godot Lua PluginScript](https://github.com/gilzoide/godot-lua-pluginscript/blob/main/extras/articles/1-design-en.md)
87 | 2. [Implementing the library's skeleton](https://github.com/gilzoide/godot-lua-pluginscript/blob/main/extras/articles/2-infrastructure-en.md)
88 | 3. [Integrating LuaJIT and FFI](https://github.com/gilzoide/godot-lua-pluginscript/blob/main/extras/articles/3-luajit-callbacks-en.md)
89 | 4. Initializing and finalizing scripts (TODO)
90 |
91 |
92 | ## Script example
93 |
94 | This is an example of how a Lua script looks like.
95 |
96 | ```lua
97 | -- Class definitions are regular Lua tables, to be returned from the script
98 | local MyClass = {}
99 |
100 | -- Optional: set class as tool, defaults to false
101 | MyClass.is_tool = true
102 |
103 | -- Optional: set base class by name, defaults to 'Reference'
104 | MyClass.extends = Node
105 |
106 | -- Optional: give your class a name
107 | MyClass.class_name = 'MyClass'
108 |
109 | -- Declare signals
110 | MyClass.something_happened = signal()
111 | MyClass.something_happened_with_args = signal("arg1", "arg2")
112 |
113 | -- Values defined in table are registered as properties of the class
114 | -- By default, properties are not exported to the editor
115 | MyClass.some_prop = 42
116 |
117 | -- The `property` function adds metadata to defined properties,
118 | -- like setter and getter functions
119 | MyClass.some_prop_with_details = property {
120 | -- ["default_value"] or ["default"] or [1] = property default value
121 | 5,
122 | -- ["type"] or [2] = variant type, optional, inferred from default value
123 | -- All Godot variant type names are defined globally as written in
124 | -- GDScript, like bool, int, float, String, Array, Vector2, etc...
125 | -- Notice that Lua <= 5.2 does not differentiate integers from float
126 | -- numbers, so we should always specify `int` where appropriate
127 | -- or use `int(5)` in the default value instead
128 | type = int,
129 | -- ["get"] or ["getter"] = getter function or method name, optional
130 | get = function(self)
131 | return self.some_prop_with_details
132 | end,
133 | -- ["set"] or ["setter"] = setter function or method name, optional
134 | set = 'set_some_prop_with_details',
135 | -- ["usage"] = property usage, from `enum godot_property_usage_flags`
136 | -- optional, default to `PropertyUsage.NOEDITOR`
137 | usage = PropertyUsage.NOEDITOR,
138 | -- ["hint"] = property hint, from `enum godot_property_hint`
139 | -- optional, default to `PropertyHint.NONE`
140 | hint = PropertyHint.RANGE,
141 | -- ["hint_string"] = property hint text, only required for some hints
142 | hint_string = '1,10',
143 | -- ["rset_mode"] = property remote set mode, from `enum godot_method_rpc_mode`
144 | -- optional, default to `RPCMode.DISABLED`
145 | rset_mode = RPCMode.MASTER,
146 | }
147 | -- The `export` function is an alias for `property` that always exports
148 | -- properties to the editor
149 | MyClass.exported_prop = export { "This property appears in the editor" }
150 | MyClass.another_exported_prop = export {
151 | [[This one also appears in the editor,
152 | now with a multiline TextArea for edition]],
153 | hint = PropertyHint.MULTILINE_TEXT,
154 | }
155 |
156 | -- Functions defined in table are public methods
157 | function MyClass:_ready() -- `function t:f(...)` is an alias for `function t.f(self, ...)`
158 | -- Singletons are available globally
159 | local os_name = OS:get_name()
160 | print("MyClass instance is ready! Running on a " .. os_name .. " system")
161 |
162 | -- There is no `onready` keyword like in GDScript
163 | -- Just get the needed values on `_ready` method
164 | -- Also, Lua doesn't have the `$child_node` syntax, use `get_node` instead
165 | self.some_grandchild_node = self:get_node("some/grandchild_node")
166 | end
167 |
168 | function MyClass:set_some_prop_with_details(value)
169 | self.some_prop_with_details = value
170 | -- Indexing `self` with keys undefined in script will search base
171 | -- class for methods and properties
172 | self:emit_signal("something_happened_with_args", "some_prop_with_details", value)
173 | end
174 |
175 | function MyClass:get_some_prop_doubled()
176 | return self.some_prop * 2
177 | end
178 |
179 | -- In the end, table with class declaration must be returned from script
180 | return MyClass
181 | ```
182 |
183 |
184 | ## Status
185 |
186 | - [X] LuaJIT support
187 | - [ ] Lua 5.2+ support
188 | - [X] Useful definitions for all GDNative objects, with methods and metamethods
189 | - [X] A `yield` function similar to GDScript's, to resume after a signal is
190 | emitted (`GD.yield`)
191 | - [X] Working PluginScript language definition
192 | - [X] PluginScript script validation and template source code
193 | - [ ] PluginScript code editor callbacks
194 | - [ ] PluginScript debug callbacks
195 | - [ ] PluginScript profiling callbacks
196 | - [X] Package searcher for Lua and C modules that work with paths relative to
197 | the `res://` folder and/or exported games' executable path
198 | - [X] Lua REPL
199 | - [X] API documentation
200 | - [ ] Unit tests
201 | - [ ] Example projects
202 | - [X] Export plugin to minify Lua scripts
203 | - [X] Drop-in binary release in GitHub
204 | - [X] Submit to Asset Library
205 |
206 |
207 | ## Third-party software
208 |
209 | This project uses the following software:
210 |
211 | - [godot-headers](https://github.com/godotengine/godot-headers): headers for
212 | GDNative, distributed under the MIT license
213 | - [LuaJIT](https://luajit.org/luajit.html): Just-In-Time Compiler (JIT) for the
214 | Lua programming language, distributed under the MIT license
215 | - [High Level GDNative (HGDN)](https://github.com/gilzoide/high-level-gdnative):
216 | higher level GDNative API header, released to the Public Domain
217 | - [LuaSrcDiet](https://github.com/jirutka/luasrcdiet): compresses Lua source
218 | code by removing unnecessary characters, distributed under the MIT license
219 | - [LuaUnit](https://github.com/bluebird75/luaunit): unit-testing framework for
220 | Lua, distributed under the BSD license
221 | - [debugger.lua](https://github.com/slembcke/debugger.lua): dependency free,
222 | single file embeddable debugger for Lua, distributed under the MIT license
223 |
224 |
225 | ## Other projects for using Lua in Godot
226 |
227 | - https://github.com/perbone/luascript
228 | - https://github.com/Trey2k/lua
229 | - https://github.com/zozer/godot-lua-module
230 |
--------------------------------------------------------------------------------
/build/.gdignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/build/.gdignore
--------------------------------------------------------------------------------
/config.ld:
--------------------------------------------------------------------------------
1 | project = "Godot Lua PluginScript"
2 | topics = { "CHANGELOG.md", "README.md", "extras/docs" }
3 | format = "markdown"
4 | file = { "src", "lps_coroutine.lua" }
5 | boilerplate = true
6 | sort = true
7 | dir = "docs"
8 | examples = { "lps_coroutine.lua", "plugin/lua_repl.lua" }
9 |
--------------------------------------------------------------------------------
/extras/.gdignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/.gdignore
--------------------------------------------------------------------------------
/extras/articles/1-design-en.md:
--------------------------------------------------------------------------------
1 | # Designing a Godot PluginScript for Lua
2 | 2021-07-28 | `#Godot #Lua #GDNative #PluginScript #languageBindings` | [*Versão em Português*](1-design-pt.md)
3 |
4 | This is the first article in a series about how I'm approaching the development
5 | of a plugin for using the [Lua](https://www.lua.org/) language in
6 | [Godot game engine](https://godotengine.org/).
7 |
8 | Lua is a simple and small, yet powerful and flexible, scripting language.
9 | Although it [isn't fit for every scenario](https://docs.godotengine.org/en/stable/about/faq.html#what-were-the-motivations-behind-creating-gdscript),
10 | it is certainly a great tool for scripting.
11 | Combining that with the power of [LuaJIT](https://luajit.org/),
12 | one of the fastest dynamic language implementations out there, we can also
13 | [call external C functions via the Foreign Function Interface (FFI)](https://luajit.org/ext_ffi.html)!
14 |
15 | With the dynamic nature of scripting in Godot, all supported languages
16 | can seamlessly communicate with each other and thus we can choose to use the
17 | language that best fits the task in hand for each script.
18 | By the means of [signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/signals.html)
19 | and the methods [call](https://docs.godotengine.org/en/stable/classes/class_object.html#class-object-method-call),
20 | [get](https://docs.godotengine.org/en/stable/classes/class_object.html#id1)
21 | and [set](https://docs.godotengine.org/en/stable/classes/class_object.html#id4),
22 | any object can communicate with another one, regardless of the
23 | source language.
24 |
25 | To make Lua be recognized as one of the supported scripting languages for Godot
26 | objects, we will create a PluginScript, which is one of the uses of
27 | [GDNative](https://docs.godotengine.org/en/stable/getting_started/step_by_step/scripting.html#gdnative-c),
28 | the native plugin C API provided by the engine to extend all sorts of
29 | engine systems, such as the scripting one.
30 | One pro of this approach is that only the plugin have to be compiled,
31 | so anyone with a standard prebuilt version of Godot can use it! =D
32 |
33 |
34 | ## Goals
35 | - Provide support for the Lua language in Godot in a way that does not require
36 | compiling the engine from scratch
37 | - Be able to seamlessly communicate with any other language supported by Godot,
38 | like GDScript, Visual Script and C#, in an idiomatic way
39 | - Simple script description interface that doesn't need `require`ing anything
40 | - Support for Lua 5.2+ and LuaJIT
41 | - Have a simple build process, where anyone with the cloned source code and
42 | installed build system + toolchain can build the project in a single step
43 |
44 |
45 | ## Non-goals
46 | - Provide calls to core Godot classes' methods via native method bindings
47 | - Support multithreading on the Lua side
48 |
49 |
50 | ## Script example
51 | This is an example of how a Lua script will look like. There are comments regarding
52 | some design decisions, which may change during development.
53 |
54 | ```lua
55 | -- Class definitions are regular Lua tables, to be returned from the script
56 | local MyClass = {}
57 |
58 | -- Optional: set class as tool, defaults to false
59 | MyClass.is_tool = true
60 |
61 | -- Optional: set base class by name, defaults to 'Reference'
62 | MyClass.extends = 'Node'
63 |
64 | -- Optional: give your class a name
65 | MyClass.class_name = 'MyClass'
66 |
67 | -- Declare signals
68 | MyClass.something_happened = signal()
69 | MyClass.something_happened_with_args = signal("arg1", "arg2")
70 |
71 | -- Values defined in table are registered as properties of the class
72 | MyClass.some_prop = 42
73 |
74 | -- The `property` function adds metadata to defined properties,
75 | -- like setter and getter functions
76 | MyClass.some_prop_with_details = property {
77 | -- [1] or ["default"] or ["default_value"] = property default value
78 | 5,
79 | -- [2] or ["type"] = variant type, optional, inferred from default value
80 | -- All Godot variant type names are defined globally as written in
81 | -- GDScript, like bool, int, float, String, Array, Vector2, etc...
82 | -- Notice that Lua <= 5.2 does not differentiate integers from float
83 | -- numbers, so we should always specify `int` where appropriate
84 | -- or use `int(5)` in the default value instead
85 | type = int,
86 | -- ["set"] or ["setter"] = setter function, optional
87 | set = function(self, value)
88 | self.some_prop_with_details = value
89 | -- Indexing `self` with keys undefined in script will search base
90 | -- class for methods and properties
91 | self:emit_signal("something_happened_with_args", "some_prop_with_details", value)
92 | end,
93 | -- ["get"] or ["getter"] = getter function, optional
94 | get = function(self)
95 | return self.some_prop_with_details
96 | end,
97 | -- ["usage"] = property usage, from enum godot_property_usage_flags
98 | -- optional, default to GD.PROPERTY_USAGE_DEFAULT
99 | usage = GD.PROPERTY_USAGE_DEFAULT,
100 | -- ["hint"] = property hint, from enum godot_property_hint
101 | -- optional, default to GD.PROPERTY_HINT_NONE
102 | hint = GD.PROPERTY_HINT_RANGE,
103 | -- ["hint_string"] = property hint text, only required for some hints
104 | hint_string = '1,10',
105 | -- ["rset_mode"] = property remote set mode, from enum godot_method_rpc_mode
106 | -- optional, default to GD.RPC_MODE_DISABLED
107 | rset_mode = GD.RPC_MODE_MASTER,
108 | }
109 |
110 | -- Functions defined in table are public methods
111 | function MyClass:_init() -- `function t:f(...)` is an alias for `function t.f(self, ...)`
112 | -- Singletons are available globally
113 | local os_name = OS:get_name()
114 | print("MyClass instance initialized! Running on a " .. os_name .. " system")
115 | end
116 |
117 | function MyClass:some_prop_doubled()
118 | return self.some_prop * 2
119 | end
120 |
121 | -- In the end, table with class declaration must be returned from script
122 | return MyClass
123 | ```
124 |
125 |
126 | ## Implementation design details
127 | PluginScripts have three important concepts: the Language Description,
128 | Script Manifest and Instances.
129 |
130 | Let's check out what each layer is and how they will behave from a high
131 | level perspective:
132 |
133 |
134 | ### Language description
135 | The language description tells Godot how to initialize and finalize our
136 | language runtime, as well as how to load script manifests from source
137 | files.
138 |
139 | When initializing the runtime, a new [lua_State](https://www.lua.org/manual/5.4/manual.html#lua_State)
140 | will be created and Godot functionality setup in it.
141 | The Lua Virtual Machine (VM) will use engine memory management routines, so
142 | that memory is tracked by the performance monitors in debug builds of the
143 | game/application.
144 | All scripts will share this same state.
145 |
146 | There will be a global table named `GD` with some Godot specific
147 | functions, such as [load](https://docs.godotengine.org/en/stable/classes/class_%40gdscript.html#class-gdscript-method-load),
148 | [print](https://docs.godotengine.org/en/stable/classes/class_%40gdscript.html#class-gdscript-method-print),
149 | [push_error](https://docs.godotengine.org/en/stable/classes/class_%40gdscript.html#class-gdscript-method-push-error),
150 | [push_warning](https://docs.godotengine.org/en/stable/classes/class_%40gdscript.html#class-gdscript-method-push-warning)
151 | and [yield](https://docs.godotengine.org/en/stable/classes/class_%40gdscript.html#class-gdscript-method-yield).
152 | Lua's global `print` function will be set to `GD.print` and
153 | [Lua 5.4 warning function](https://www.lua.org/manual/5.4/manual.html#lua_WarnFunction)
154 | will behave like a `push_warning` call.
155 |
156 | Functions that expect file names, like [loadfile](https://www.lua.org/manual/5.4/manual.html#pdf-loadfile)
157 | and [io.open](https://www.lua.org/manual/5.4/manual.html#pdf-io.open),
158 | will be patched to accept paths in the format [`res://*`](https://docs.godotengine.org/en/stable/tutorials/io/data_paths.html#resource-path)
159 | and [`user://*`](https://docs.godotengine.org/en/stable/tutorials/io/data_paths.html#user-path-persistent-data).
160 | Also, a [package searcher](https://www.lua.org/manual/5.4/manual.html#pdf-package.searchers)
161 | will be added so that Lua can [require](https://www.lua.org/manual/5.4/manual.html#pdf-require)
162 | modules from paths relative to `res://`.
163 |
164 | Language finalization will simply [lua_close](https://www.lua.org/manual/5.4/manual.html#lua_close) the state.
165 |
166 |
167 | ### Script manifest
168 | Script manifests hold metadata about classes, such as defined signals,
169 | properties and methods, whether class is [tool](https://docs.godotengine.org/en/stable/tutorials/misc/running_code_in_the_editor.html)
170 | and its base class name.
171 |
172 | In Lua, this information will be stored in Lua tables indexed by the
173 | scripts' path.
174 |
175 | When initializing a script, its source code will be loaded and executed.
176 | Scripts must return a table, which defines the class metadata.
177 | Functions declared in the table are registered as class methods and
178 | other variables are declared as properties or signals.
179 |
180 | Script finalization will destroy the manifest table.
181 |
182 |
183 | ### Instances
184 | When a script is attached to an object, the engine will call our
185 | PluginScript to initialize the instance data and when the object gets
186 | destroyed or gets the script removed, we get to finalize the data.
187 |
188 | In Lua, instance data will be stored in Lua tables indexed by the
189 | instance owner object's memory address.
190 |
191 | When instances are indexed with a key that is not present, methods and
192 | property default values will be searched in the script manifest and its
193 | base class, in that order.
194 | This table will be passed to methods as their first argument, as if
195 | using Lua's method call notation: `instance:method(...)`.
196 |
197 | Instance finalization will destroy the data table.
198 |
199 |
200 | ## Wrapping up
201 | With this high level design in place, we can now start implementing the
202 | plugin! I have created a Git repository for it hosted at
203 | [https://github.com/gilzoide/godot-lua-pluginscript](https://github.com/gilzoide/godot-lua-pluginscript).
204 |
205 | In the [next post](2-infrastructure-en.md) I'll discuss how to build the
206 | necessary infrastructure for the PluginScript to work, with stubs to the
207 | necessary callbacks and a build system that compiles the project in a
208 | single step.
209 |
210 | See you there ;D
211 |
--------------------------------------------------------------------------------
/extras/articles/2-create-gdnativelibrary-save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/articles/2-create-gdnativelibrary-save.png
--------------------------------------------------------------------------------
/extras/articles/2-create-gdnativelibrary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/articles/2-create-gdnativelibrary.png
--------------------------------------------------------------------------------
/extras/articles/2-create-resource.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/articles/2-create-resource.png
--------------------------------------------------------------------------------
/extras/articles/2-pick-so-save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/articles/2-pick-so-save.png
--------------------------------------------------------------------------------
/extras/articles/2-pick-so.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/articles/2-pick-so.png
--------------------------------------------------------------------------------
/extras/articles/2-pluginscript-xmake-lua.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/articles/2-pluginscript-xmake-lua.png
--------------------------------------------------------------------------------
/extras/articles/2-set-singleton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/articles/2-set-singleton.png
--------------------------------------------------------------------------------
/extras/articles/2-settings-gdnative-enabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/articles/2-settings-gdnative-enabled.png
--------------------------------------------------------------------------------
/extras/articles/3-script-init-xmake-lua.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/articles/3-script-init-xmake-lua.png
--------------------------------------------------------------------------------
/extras/docs/building.md:
--------------------------------------------------------------------------------
1 | # Building
2 |
3 | ## Submodules
4 |
5 | This project uses git submodules for its dependencies, so be sure to activate
6 | submodules before building.
7 |
8 | ```sh
9 | # clone this repository and activate submodules in a single command
10 | git clone --recurse-submodules https://github.com/gilzoide/godot-lua-pluginscript.git
11 |
12 | # or clone it normally and then activate submodules
13 | git clone https://github.com/gilzoide/godot-lua-pluginscript.git
14 | cd godot-lua-pluginscript
15 | git submodule init
16 | git submodule update
17 | ```
18 |
19 | ## Libraries
20 |
21 | Build the libraries using [make](https://www.gnu.org/software/make/) from
22 | project root, specifying the system as target:
23 |
24 | ```sh
25 | # Choose one of the supported platforms, based on your operating system
26 | make windows64 # x86_64
27 | make windows32 # x86
28 | make linux64 # x86_64
29 | make linux32 # x86
30 | make osx64 \ # multiarch x86_64 + amd64 dylib
31 | # Optional: deployment target. If absent, uses 10.7 for x86_64 and 11.0 for arm64
32 | MACOSX_DEPLOYMENT_TARGET=XX.YY \
33 | # Optional: code sign identity. If absent, `codesign` is not performed
34 | CODE_SIGN_IDENTITY= \
35 | # Optional: additional flags passed to `codesign`
36 | OTHER_CODE_SIGN_FLAGS=
37 |
38 | # Cross-compiling for Windows using MinGW
39 | make mingw-windows64 # x86_64
40 | make mingw-windows32 # x86
41 |
42 | # Cross-compiling for Android using NDK
43 | make android-armv7a \ # Android ARMv7
44 | # Optional: NDK toolchain "bin" folder. Defaults to $ANDROID_NDK_ROOT/toolchains/llvm/prebuild/*/bin
45 | NDK_TOOLCHAIN_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuild/*/bin
46 | make android-aarch64 \ # Android ARM64
47 | NDK_TOOLCHAIN_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuild/*/bin
48 | make android-x86 \ # Android x86
49 | NDK_TOOLCHAIN_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuild/*/bin
50 | make android-x86_64 \ # Android x86_64
51 | NDK_TOOLCHAIN_BIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuild/*/bin
52 |
53 | # Cross-compiling for iOS in a OSX environment
54 | make ios64 \ # Dylibs for iOS arm64 and simulator arm64 + x86_64
55 | # Optional: minimum iOS version to target. If absent, uses 8.0
56 | IOS_VERSION_MIN=X.Y
57 | # Optional: code sign identity. If absent, `codesign` is not performed
58 | CODE_SIGN_IDENTITY= \
59 | # Optional: additional flags passed to `codesign`
60 | OTHER_CODE_SIGN_FLAGS=
61 | ```
62 |
63 | The GDNativeLibrary file `lua_pluginscript.gdnlib` is already configured to use
64 | the built files stored in the `build` folder, so that one can use this
65 | repository directly inside a Godot project under the folder `addons/godot-lua-pluginscript`.
66 |
67 |
68 | ## Export plugin
69 |
70 | If you plan in using the export plugin, the following is also required:
71 |
72 | ```sh
73 | make plugin
74 | ```
75 |
76 |
77 | ## Distribution ZIP
78 |
79 | After building the desired libraries, a distribution zip can be built with:
80 |
81 | ```sh
82 | make dist
83 | ```
84 |
85 |
86 | ## API documentation
87 |
88 | The API is documented using [LDoc](https://stevedonovan.github.io/ldoc/manual/doc.md.html)
89 | and may be generated with the following command:
90 |
91 | ```sh
92 | make docs
93 | ```
94 |
--------------------------------------------------------------------------------
/extras/docs/configuring.md:
--------------------------------------------------------------------------------
1 | # Available configurations
2 |
3 | ## Project Settings
4 | In the `Project -> Project Settings...` window, the following configurations are available:
5 |
6 | - **Lua PluginScript/Package Path/Behavior**: Whether templates will replace
7 | [package.path](https://www.lua.org/manual/5.1/manual.html#pdf-package.path),
8 | be appended to it or prepended to it.
9 | Default behavior: `replace`.
10 | - **Lua PluginScript/Package Path/Templates**: List of templates to be
11 | injected into `package.path`.
12 | Default templates: `res://?.lua` and `res://?/init.lua`.
13 | - **Lua PluginScript/Package C Path/Behavior**: Whether templates will replace
14 | [package.cpath](https://www.lua.org/manual/5.1/manual.html#pdf-package.cpath),
15 | be appended to it or prepended to it.
16 | Default behavior: `replace`.
17 | - **Lua PluginScript/Package C Path/Templates**: List of templates to be
18 | injected into `package.cpath`.
19 | Default templates: `!/?.dll` and `!/loadall.dll` on Windows,
20 | `!/?.so` and `!/loadall.so` elsewhere.
21 | - **Lua PluginScript/Export/Minify On Release Export**: Whether Lua scritps
22 | should be minified on release exports.
23 | Defaults to `true`.
24 |
25 | ## Configuring `package.path` and `package.cpath`
26 | Templates for `package.path` and `package.cpath` accept paths starting with
27 | Godot's Resource path `res://` and User path `user://`.
28 |
29 | Also, the special character `!` represents the executable directory.
30 | When running a standalone build, it will be replaced by the directory of the executable path
31 | ([`OS.get_executable_path().get_base_dir()`](https://docs.godotengine.org/en/stable/classes/class_os.html#class-os-method-get-executable-path)).
32 | When opening the project from the editor, it will be replaced by the project root
33 | ([`ProjectSettings.globalize_path("res://")`](https://docs.godotengine.org/en/stable/classes/class_projectsettings.html#class-projectsettings-method-globalize-path)).
34 |
35 | When the behavior is configured to `replace`, paths coming from the environment
36 | variables `LUA_PATH` and `LUA_CPATH` will also be replaced.
37 |
38 |
--------------------------------------------------------------------------------
/extras/docs/limitations.md:
--------------------------------------------------------------------------------
1 | # Known limitations
2 |
3 | - Calling methods on Lua scripts from background threads without a proper
4 | threading library for Lua will most likely break, since the Lua engine is not
5 | thread-safe.
6 | - Lua scripts cannot inherit other scripts, not even other Lua scripts at the
7 | moment.
8 | - PluginScript instances in editor are not reloaded when a script is edited.
9 | That means that adding/removing/updating an exported property won't show in
10 | the editor and `tool` scripts won't be reloaded until the project is reopened.
11 | This is a limitation of Godot's PluginScript implementation (tested in Godot
12 | 3.4).
13 |
--------------------------------------------------------------------------------
/extras/docs/luarocks.md:
--------------------------------------------------------------------------------
1 | # Using LuaRocks
2 |
3 | Lua modules available at [LuaRocks](https://luarocks.org/) can be installed locally to the project:
4 |
5 | ```sh
6 | luarocks install --lua-version 5.1 --tree
7 | ```
8 |
9 | **TIP**: put an empty `.gdignore` file in the local modules folder, so that
10 | Godot doesn't try importing the installed `*.lua` files as Lua scripts.
11 |
12 | Adjust the package paths using the [Lua PluginScript project settings](configuring.md)
13 | and scripts should be able to `require` the installed modules.
14 |
15 | For example, if the local modules folder is called `localrocks`, add
16 | `res://localrocks/share/lua/5.1/?.lua` and `res://localrocks/share/lua/5.1/?/init.lua`
17 | to **Package Path** and `res://localrocks/lib/lua/5.1/?.so` (change extension
18 | to `.dll` on Windows and possibly `.dylib` on OSX) to **Package C Path**.
19 |
--------------------------------------------------------------------------------
/extras/docs/plugin-enabling.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/docs/plugin-enabling.png
--------------------------------------------------------------------------------
/extras/docs/plugin-repl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/docs/plugin-repl.png
--------------------------------------------------------------------------------
/extras/docs/plugin.md:
--------------------------------------------------------------------------------
1 | # Editor Plugin
2 |
3 | Lua PluginScript comes with an editor plugin that has an interactive Lua
4 | console and an export plugin that minifies Lua scripts.
5 |
6 |
7 | ## Enabling
8 |
9 | The plugin can be enabled in the project's `Project -> Project Settings...`
10 | window, in the `Plugins` tab:
11 |
12 | 
13 |
14 |
15 | ## REPL
16 |
17 | An interactive Lua console is available on the bottom panel, for testing Lua
18 | expressions.
19 | It comes with a basic input history, so that pressing the up/down arrows move
20 | between already given inputs.
21 | Just like Lua/LuaJIT's interactive interpreter, `local` variables do not
22 | persist between expressions, so they should be declared globally if you want to
23 | use their value in a next expression.
24 |
25 | 
26 |
27 |
28 | ## Minify on release export
29 |
30 | If the [**Lua PluginScript/Export/Minify On Release Export**](Configuring.md)
31 | setting is enabled, Lua scripts will get minified when exporting a release
32 | version of the game/application.
33 | Minification uses [LuaSrcDiet](https://github.com/jirutka/luasrcdiet) and its
34 | [maximum settings](https://github.com/jirutka/luasrcdiet/blob/master/doc/features-and-usage.adoc#features).
35 |
36 | Notice that minification messes with the scritps' line numbers and consequently
37 | with stack traces.
38 | That is why minification is not available for debug builds.
39 |
--------------------------------------------------------------------------------
/extras/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/extras/icon.png
--------------------------------------------------------------------------------
/lib/.gdignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/lib/.gdignore
--------------------------------------------------------------------------------
/lps_coroutine.lua:
--------------------------------------------------------------------------------
1 | -- @file lps_coroutine.lua LuaCoroutine script
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Godot Reference script that wraps a Lua coroutine with an API similar to `GDScriptFunctionState`.
25 | -- These are created by `GD.yield` and won't work if created manually.
26 | -- @script lps_coroutine.lua
27 |
28 | local co_resume, co_status = coroutine.resume, coroutine.status
29 |
30 | -- @type LuaCoroutine
31 | local LuaCoroutine = {
32 | --- `signal completed(result)`: signal emitted by `resume` when the coroutine body is completed.
33 | completed = signal('result'),
34 | --- Result of `coroutine.status`
35 | status = property {
36 | type = string,
37 | get = 'get_status',
38 | },
39 | }
40 |
41 | --- Returns the `coroutine.status`.
42 | -- @function get_status
43 | -- @treturn string
44 | -- @see coroutine.status
45 | function LuaCoroutine:get_status()
46 | local co = assert(GD.get_lua_instance(self.__data.__address), "no coroutine attached")
47 | return co_status(co)
48 | end
49 |
50 | --- Returns whether coroutine is valid (`self:get_status() ~= 'dead'`).
51 | -- @function is_valid
52 | -- @treturn bool
53 | function LuaCoroutine:is_valid()
54 | return self:get_status() ~= 'dead'
55 | end
56 |
57 | --- Resume a coroutine, similar to `coroutine.resume`.
58 | -- Emits the `completed` signal if the coroutine body is completed.
59 | -- Differently than `GDScriptFunctionState.resume`, this method accepts
60 | -- multiple arguments.
61 | -- @usage
62 | -- local coro = some_object:method_that_yields()
63 | -- local first_value = coro:resume()
64 | -- local second_value = coro:resume()
65 | -- while coro:is_valid() do
66 | -- local next_value = coro:resume()
67 | -- -- do something
68 | -- end
69 | -- @function resume
70 | -- @param ...
71 | -- @return
72 | -- @raise If `coroutine.resume` returns `false`
73 | function LuaCoroutine:resume(...)
74 | local co = assert(GD.get_lua_instance(self.__data.__address), "no coroutine attached")
75 | local _, result = assert(co_resume(co, ...))
76 | if co_status(co) == 'dead' then
77 | self:emit_signal('completed', result)
78 | end
79 | return result
80 | end
81 |
82 | return LuaCoroutine
83 |
--------------------------------------------------------------------------------
/lua_pluginscript.gdnlib:
--------------------------------------------------------------------------------
1 | [general]
2 |
3 | singleton=true
4 | load_once=true
5 | symbol_prefix="lps_"
6 | reloadable=false
7 |
8 | [entry]
9 |
10 | Android.armeabi-v7a="res://addons/godot-lua-pluginscript/build/android_armv7a/liblua_pluginscript.so"
11 | Android.arm64-v8a="res://addons/godot-lua-pluginscript/build/android_aarch64/liblua_pluginscript.so"
12 | Android.x86="res://addons/godot-lua-pluginscript/build/android_x86/liblua_pluginscript.so"
13 | Android.x86_64="res://addons/godot-lua-pluginscript/build/android_x86_64/liblua_pluginscript.so"
14 | OSX.64="res://addons/godot-lua-pluginscript/build/osx_arm64_x86_64/lua_pluginscript.dylib"
15 | Windows.64="res://addons/godot-lua-pluginscript/build/windows_x86_64/lua_pluginscript.dll"
16 | Windows.32="res://addons/godot-lua-pluginscript/build/windows_x86/lua_pluginscript.dll"
17 | X11.64="res://addons/godot-lua-pluginscript/build/linux_x86_64/liblua_pluginscript.so"
18 | X11.32="res://addons/godot-lua-pluginscript/build/linux_x86/liblua_pluginscript.so"
19 | iOS.arm64="res://addons/godot-lua-pluginscript/build/ios_arm64/lua_pluginscript.dylib"
20 | iOS.x86_64="res://addons/godot-lua-pluginscript/build/ios_simulator_arm64_x86_64/lua_pluginscript.dylib"
21 | Server="res://addons/godot-lua-pluginscript/build/linux_x86_64/liblua_pluginscript.so"
22 |
23 | [dependencies]
24 |
25 | Android.armeabi-v7a=[ ]
26 | Android.arm64-v8a=[ ]
27 | Android.x86=[ ]
28 | Android.x86_64=[ ]
29 | OSX.64=[ ]
30 | Windows.64=[ "res://addons/godot-lua-pluginscript/build/windows_x86_64/lua51.dll" ]
31 | Windows.32=[ "res://addons/godot-lua-pluginscript/build/windows_x86/lua51.dll" ]
32 | X11.64=[ ]
33 | X11.32=[ ]
34 | iOS.arm64=[ ]
35 | iOS.x86_64=[ ]
36 |
--------------------------------------------------------------------------------
/plugin/export_plugin.lua:
--------------------------------------------------------------------------------
1 | -- @file plugin/export_plugin.lua EditorExportPlugin for minifying Lua scripts on release exports
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 | local package_path = package.path
24 | package.path = 'res://addons/godot-lua-pluginscript/plugin/?.lua;res://addons/godot-lua-pluginscript/plugin/?/init.lua;' .. package_path
25 | local luasrcdiet = require 'luasrcdiet'
26 | package.path = package_path
27 |
28 | local LuaExportPlugin = {
29 | is_tool = true,
30 | extends = 'EditorExportPlugin',
31 | }
32 |
33 | local SHOULD_MINIFY_RELEASE_SETTING = 'lua_pluginscript/export/minify_on_release_export'
34 |
35 | local function add_project_setting(name, initial_value)
36 | if not ProjectSettings:has_setting(name) then
37 | ProjectSettings:set_setting(name, initial_value)
38 | end
39 | ProjectSettings:set_initial_value(name, initial_value)
40 | end
41 | add_project_setting(SHOULD_MINIFY_RELEASE_SETTING, true)
42 |
43 | function LuaExportPlugin:_export_begin(features, is_debug, path, flags)
44 | self.ignore_path = self:get_script().resource_path:get_base_dir()
45 | self.should_minify = not is_debug and ProjectSettings:get_setting(SHOULD_MINIFY_RELEASE_SETTING)
46 | self.file = File:new()
47 | end
48 |
49 | function LuaExportPlugin:_export_file(path, type, features)
50 | if path:begins_with(self.ignore_path) then
51 | self:skip()
52 | elseif self.should_minify and path:ends_with('.lua') then
53 | if self.file:open(path, File.READ) == GD.OK then
54 | local source = tostring(self.file:get_as_text())
55 | self.file:close()
56 | local optsource = luasrcdiet.optimize(luasrcdiet.MAXIMUM_OPTS, source)
57 | print(string.format('[LuaPluginScript] Minified %s: %s -> %s (%d%% reduction)',
58 | path,
59 | String.humanize_size(#source),
60 | String.humanize_size(#optsource),
61 | 100 - math.floor(#optsource / #source * 100))
62 | )
63 | self:add_file(path, PoolByteArray.from(optsource), false)
64 | end
65 | end
66 | end
67 |
68 | function LuaExportPlugin:_export_end()
69 | self.ignore_path = nil
70 | self.file = nil
71 | end
72 |
73 | return LuaExportPlugin
74 |
--------------------------------------------------------------------------------
/plugin/in_editor_callbacks/.gdignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/plugin/in_editor_callbacks/.gdignore
--------------------------------------------------------------------------------
/plugin/in_editor_callbacks/init.lua:
--------------------------------------------------------------------------------
1 | -- @file in_editor_callbacks.lua PluginScript Editor + Debug callbacks implementation
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 | local ffi = require 'ffi'
24 |
25 | local pluginscript_callbacks = debug.getregistry().lps_callbacks
26 | local wrap_callback = pluginscript_callbacks.wrap_callback
27 |
28 | -- void (*)(const godot_string *class_name, const godot_string *base_class_name, godot_string *ret)
29 | pluginscript_callbacks.get_template_source_code = wrap_callback(function(class_name, base_class_name, ret)
30 | class_name = ffi.cast('godot_string *', class_name):gsub("[^_%w]", "_")
31 | base_class_name = ffi.cast('godot_string *', base_class_name)
32 | ret = ffi.cast('godot_string *', ret)
33 |
34 | ret[0] = ffi.gc(String('local ' .. class_name .. ' = {\n\textends = "' .. base_class_name .. '",\n}\n\nreturn ' .. class_name), nil)
35 | end)
36 |
37 | -- godot_bool (*)(const godot_string *script, int *line_error, int *col_error, godot_string *test_error, const godot_string *path, godot_pool_string_array *functions)
38 | pluginscript_callbacks.validate = wrap_callback(function(script, line_error, col_error, test_error, path, functions)
39 | script = ffi.cast('godot_string *', script)
40 | line_error = ffi.cast('int *', line_error)
41 | col_error = ffi.cast('int *', col_error)
42 | test_error = ffi.cast('godot_string *', test_error)
43 | path = ffi.cast('godot_string *', path)
44 | functions = ffi.cast('godot_pool_string_array *', functions)
45 |
46 | local f, err = loadstring(tostring(script), tostring(path))
47 | if not f then
48 | local line, msg = string.match(err, ':(%d+):%s*(.*)')
49 | line_error[0] = tonumber(line) or -1
50 | test_error[0] = ffi.gc(String(msg or err), nil)
51 | end
52 | return f ~= nil
53 | end, true)
54 |
55 | -- void (*)(const godot_string *class_name, const godot_string *name, const godot_pool_string_array *args, godot_string *ret)
56 | pluginscript_callbacks.make_function = wrap_callback(function(class_name, name, args, ret)
57 | class_name = ffi.cast('godot_string *', class_name)
58 | name = ffi.cast('godot_string *', name)
59 | args = ffi.cast('godot_pool_string_array *', args)
60 | ret = ffi.cast('godot_string *', ret)
61 |
62 | local code = string.format('function %s:%s(%s)\n\t\nend', tostring(class_name), tostring(name), tostring(args:join(', ')))
63 | ret[0] = ffi.gc(String(code), nil)
64 | end)
65 |
--------------------------------------------------------------------------------
/plugin/lua_repl.lua:
--------------------------------------------------------------------------------
1 | -- @file plugin/lua_repl.lua A tool Node for building a Lua REPL in-editor
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | local LuaREPL = {
25 | is_tool = true,
26 | extends = "Node",
27 | }
28 |
29 | local index_G = { __index = _G }
30 |
31 | local function get_error(text)
32 | text = tostring(text)
33 | return 'Error: ' .. (text:match(":%d+:%s*(.+)") or text)
34 | end
35 |
36 | -- Cache and setup nodes
37 | function LuaREPL:_ready()
38 | self.output = self:get_node("Output")
39 | self.line_edit = self:get_node("Footer/LineEdit")
40 | self.history_button_popup = self:get_node("Header/HistoryButton"):get_popup()
41 | self.history_button_popup:connect("about_to_show", self, "_on_HistoryButton_popup_about_to_show")
42 | self.history_button_popup:connect("id_pressed", self, "_on_HistoryButton_popup_id_pressed")
43 |
44 | self:reset()
45 | end
46 |
47 | -- Resets the Lua environment and REPL history
48 | function LuaREPL:reset()
49 | -- Local environment, to avoid messing up _G
50 | self.env = setmetatable({
51 | print = function(...)
52 | return self:printf('%s\n', string.join('\t', ...))
53 | end,
54 | }, index_G)
55 | self.history = PoolStringArray()
56 | self.current_history = 0
57 |
58 | self:clear()
59 | end
60 |
61 | -- Print content to output
62 | function LuaREPL:print(msg)
63 | self.output:add_text(msg)
64 | end
65 |
66 | function LuaREPL:printn(msg)
67 | self:print(msg)
68 | self:print('\n')
69 | end
70 |
71 | function LuaREPL:printf(fmt, ...)
72 | self:print(string.format(tostring(fmt), ...))
73 | end
74 |
75 | -- Runs a line, printing the results/error
76 | function LuaREPL:dostring(text)
77 | text = text:strip_edges()
78 | if text:empty() then
79 | return
80 | end
81 |
82 | self.history:append(text)
83 | self.current_history = #self.history
84 | self.line_edit:clear()
85 | self:printn(text)
86 |
87 | text = text:gsub('^=', '', 1) -- support for "= value" idiom from Lua 5.1 REPL
88 | local f, err_msg = load('return ' .. text, nil, nil, self.env)
89 | if not f then
90 | f, err_msg = load(text, nil, nil, self.env)
91 | end
92 | if f then
93 | local result = table.pack(pcall(f))
94 | if not result[1] then
95 | self:printn(get_error(result[2]))
96 | elseif result.n > 1 then
97 | local joined_results = string.join('\t', table.unpack(result, 2, result.n))
98 | self:printf('Out[%d]: %s\n', #self.history, joined_results)
99 | end
100 | else
101 | self:printn(get_error(err_msg))
102 | end
103 | self:prompt()
104 | end
105 |
106 | function LuaREPL:prompt()
107 | self:printf('\nIn [%d]: ', #self.history + 1)
108 | end
109 |
110 | -- Clear output text
111 | function LuaREPL:clear()
112 | self.output:clear()
113 | self:prompt()
114 | end
115 |
116 | -- History handlers
117 | function LuaREPL:set_history(index)
118 | if index >= 0 and index <= #self.history then
119 | self.current_history = index
120 | local text = self.history:safe_get(self.current_history) or ""
121 | self.line_edit.text = text
122 | self.line_edit.caret_position = #text
123 | end
124 | end
125 |
126 | function LuaREPL:history_up()
127 | self:set_history(self.current_history - 1)
128 | end
129 |
130 | function LuaREPL:history_down()
131 | self:set_history(self.current_history + 1)
132 | end
133 |
134 | -- Signal handlers
135 | function LuaREPL:_on_LineEdit_text_entered(text)
136 | self:dostring(text)
137 | end
138 |
139 | function LuaREPL:_on_RunButton_pressed()
140 | self:dostring(self.line_edit.text)
141 | end
142 |
143 | function LuaREPL:_on_ClearButton_pressed()
144 | self:clear()
145 | end
146 |
147 | function LuaREPL:_on_ResetButton_pressed()
148 | self:reset()
149 | end
150 |
151 | function LuaREPL:_on_LineEdit_gui_input(event)
152 | if event:is_class("InputEventKey") and event:is_pressed() then
153 | if event.scancode == GD.KEY_UP then
154 | self:history_up()
155 | elseif event.scancode == GD.KEY_DOWN then
156 | self:history_down()
157 | end
158 | end
159 | end
160 |
161 | function LuaREPL:_on_HistoryButton_popup_about_to_show()
162 | self.history_button_popup:clear()
163 | for i, s in ipairs(self.history) do
164 | self.history_button_popup:add_item(s)
165 | end
166 | end
167 |
168 | function LuaREPL:_on_HistoryButton_popup_id_pressed(i)
169 | self:set_history(i)
170 | end
171 |
172 | return LuaREPL
173 |
--------------------------------------------------------------------------------
/plugin/lua_repl.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=2]
2 |
3 | [ext_resource path="res://addons/godot-lua-pluginscript/plugin/lua_repl.lua" type="Script" id=1]
4 |
5 | [node name="LuaREPL" type="VBoxContainer"]
6 | anchor_right = 1.0
7 | anchor_bottom = 1.0
8 | script = ExtResource( 1 )
9 | __meta__ = {
10 | "_edit_use_anchors_": false
11 | }
12 |
13 | [node name="Header" type="HBoxContainer" parent="."]
14 | margin_right = 1024.0
15 | margin_bottom = 20.0
16 |
17 | [node name="Title" type="Label" parent="Header"]
18 | margin_top = 3.0
19 | margin_right = 862.0
20 | margin_bottom = 17.0
21 | size_flags_horizontal = 3
22 | text = "Lua PluginScript REPL:"
23 |
24 | [node name="HistoryButton" type="MenuButton" parent="Header"]
25 | margin_left = 866.0
26 | margin_right = 924.0
27 | margin_bottom = 20.0
28 | text = "History"
29 | flat = false
30 |
31 | [node name="ResetButton" type="Button" parent="Header"]
32 | margin_left = 928.0
33 | margin_right = 976.0
34 | margin_bottom = 20.0
35 | hint_tooltip = "Reset the Lua environment and REPL history "
36 | text = "Reset"
37 |
38 | [node name="ClearButton" type="Button" parent="Header"]
39 | margin_left = 980.0
40 | margin_right = 1024.0
41 | margin_bottom = 20.0
42 | hint_tooltip = "Clear the output text"
43 | text = "Clear"
44 |
45 | [node name="Output" type="RichTextLabel" parent="."]
46 | margin_top = 24.0
47 | margin_right = 1024.0
48 | margin_bottom = 572.0
49 | rect_min_size = Vector2( 0, 100 )
50 | focus_mode = 2
51 | size_flags_vertical = 3
52 | bbcode_enabled = true
53 | scroll_following = true
54 | selection_enabled = true
55 |
56 | [node name="Footer" type="HBoxContainer" parent="."]
57 | margin_top = 576.0
58 | margin_right = 1024.0
59 | margin_bottom = 600.0
60 |
61 | [node name="LineEdit" type="LineEdit" parent="Footer"]
62 | margin_right = 984.0
63 | margin_bottom = 24.0
64 | focus_neighbour_top = NodePath(".")
65 | focus_neighbour_bottom = NodePath(".")
66 | size_flags_horizontal = 3
67 | clear_button_enabled = true
68 |
69 | [node name="RunButton" type="Button" parent="Footer"]
70 | margin_left = 988.0
71 | margin_right = 1024.0
72 | margin_bottom = 24.0
73 | text = "Run"
74 |
75 | [connection signal="pressed" from="Header/ResetButton" to="." method="_on_ResetButton_pressed"]
76 | [connection signal="pressed" from="Header/ClearButton" to="." method="_on_ClearButton_pressed"]
77 | [connection signal="gui_input" from="Footer/LineEdit" to="." method="_on_LineEdit_gui_input"]
78 | [connection signal="text_entered" from="Footer/LineEdit" to="." method="_on_LineEdit_text_entered"]
79 | [connection signal="pressed" from="Footer/RunButton" to="." method="_on_RunButton_pressed"]
80 |
--------------------------------------------------------------------------------
/plugin/luasrcdiet/.gdignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/plugin/luasrcdiet/.gdignore
--------------------------------------------------------------------------------
/plugin/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="Lua PluginScript"
4 | description="Tools for Lua PluginScript: REPL tab and export plugin for minifying scripts"
5 | author="gilzoide"
6 | version="0.5.2"
7 | script="plugin.gd"
8 |
--------------------------------------------------------------------------------
/plugin/plugin.gd:
--------------------------------------------------------------------------------
1 | # @file plugin/plugin.gd EditorPlugin registering REPL
2 | # This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | #
4 | # Copyright (C) 2021 Gil Barbosa Reis.
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the “Software”), to
8 | # deal in the Software without restriction, including without limitation the
9 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | # sell copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in
14 | # all copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | # IN THE SOFTWARE.
23 | tool
24 | extends EditorPlugin
25 |
26 | var _lua_repl
27 | var _lua_export_plugin
28 |
29 | func _enter_tree() -> void:
30 | _lua_repl = preload("lua_repl.tscn").instance()
31 | add_control_to_bottom_panel(_lua_repl, "Lua REPL")
32 |
33 | _lua_export_plugin = preload("export_plugin.lua").new()
34 | add_export_plugin(_lua_export_plugin)
35 |
36 |
37 | func _exit_tree() -> void:
38 | if _lua_repl:
39 | remove_control_from_bottom_panel(_lua_repl)
40 | _lua_repl.free()
41 | _lua_repl = null
42 | if _lua_export_plugin:
43 | remove_export_plugin(_lua_export_plugin)
44 | _lua_export_plugin.unreference()
45 | _lua_export_plugin = null
46 |
--------------------------------------------------------------------------------
/src/.gdignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gilzoide/godot-lua-pluginscript/9bdbf1f4eeb9d256ee7163c7157c341792cc1023/src/.gdignore
--------------------------------------------------------------------------------
/src/cache_lua_libs.lua:
--------------------------------------------------------------------------------
1 | -- @file cache_lua_libs.lua Some Lua globals cached as locals
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | -- Lua globals
25 | local assert, getmetatable, ipairs, pairs, rawget, select, setmetatable, tonumber, tostring, type
26 | = assert, getmetatable, ipairs, pairs, rawget, select, setmetatable, tonumber, tostring, type
27 |
28 | -- Lua globals with fallback for 5.1
29 | local loadstring = loadstring or load
30 | table.unpack = table.unpack or unpack
31 | table.pack = table.pack or function(...)
32 | return { ..., n = select('#', ...) }
33 | end
34 |
35 | -- Bitwise operations for LuaJIT or 5.2 or 5.3+ operators
36 | local bor = bit.bor or bit32.bor or load[[function(a,b)return a|b end]]
37 |
38 | -- Lua library functions
39 | local coroutine_resume, coroutine_running, coroutine_status, coroutine_yield
40 | = coroutine.resume, coroutine.running, coroutine.status, coroutine.yield
41 | local debug_getinfo, debug_traceback
42 | = debug.getinfo, debug.traceback
43 | local package_loadlib
44 | = package.loadlib
45 | local string_byte, string_find, string_format, string_gmatch, string_gsub, string_lower, string_match, string_replace, string_rep, string_reverse, string_sub, string_upper
46 | = string.byte, string.find, string.format, string.gmatch, string.gsub, string.lower, string.match, string.replace, string.rep, string.reverse, string.sub, string.upper
47 | local table_concat, table_insert, table_remove, table_unpack
48 | = table.concat, table.insert, table.remove, table.unpack
49 |
50 | -- custom globals from `src/language_gdnative.c`
51 | local setthreadfunc, touserdata
52 | = setthreadfunc, touserdata
53 |
54 | -- FFI
55 | local ffi_cast, ffi_cdef, ffi_copy, ffi_gc, ffi_istype, ffi_metatype, ffi_new, ffi_sizeof, ffi_string, ffi_typeof
56 | = ffi.cast, ffi.cdef, ffi.copy, ffi.gc, ffi.istype, ffi.metatype, ffi.new, ffi.sizeof, ffi.string, ffi.typeof
57 | local clib = ffi.C
58 |
59 | -- Weak tables
60 | local weak_kv = { __mode = 'kv' }
61 |
62 | -- Forward declarations
63 | local _Object
64 | local LuaScriptInstance
65 |
66 | -- Some useful patterns
67 | local ERROR_LINE_MESSAGE_PATT = ':(%d+):%s*(.*)'
68 | local ERROR_PATH_LINE_MESSAGE_PATT = '"([^"]+)"[^:]*:(%d*):%s*(.*)'
69 |
70 | -- Some useful functions
71 | local function is_not_nil(value)
72 | return type(value) ~= 'nil'
73 | end
74 |
75 | local function first_index_not_nil(obj, ...)
76 | for i = 1, select('#', ...) do
77 | local index = select(i, ...)
78 | local value = obj[index]
79 | if is_not_nil(value) then
80 | return value
81 | end
82 | end
83 | return nil
84 | end
85 |
86 | local function has_length(value)
87 | local t = type(value)
88 | return t == 'table' or t == 'userdata' or t == 'cdata'
89 | end
90 |
--------------------------------------------------------------------------------
/src/godot_aabb.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_aabb.lua Wrapper for GDNative's AABB
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- AABB metatype, wrapper for `godot_aabb`.
25 | -- Constructed using the idiom `AABB(...)`, which calls `__new`.
26 | -- typedef union godot_aabb {
27 | -- uint8_t data[24];
28 | -- float elements[6];
29 | -- struct { Vector3 position, size; };
30 | -- } godot_aabb;
31 | -- @classmod AABB
32 |
33 | local methods = {
34 | fillvariant = api.godot_variant_new_aabb,
35 | varianttype = VariantType.AABB,
36 |
37 | --- Returns the volume of the AABB.
38 | -- @function get_area
39 | -- @treturn number
40 | get_area = api.godot_aabb_get_area,
41 | --- Returns `true` if the AABB is flat or empty.
42 | -- @function has_no_area
43 | -- @treturn bool
44 | has_no_area = api.godot_aabb_has_no_area,
45 | --- Returns `true` if the AABB is empty.
46 | -- @function has_no_surface
47 | -- @treturn bool
48 | has_no_surface = api.godot_aabb_has_no_surface,
49 | --- Returns `true` if the AABB overlaps with another.
50 | -- @function intersects
51 | -- @tparam AABB with
52 | -- @treturn bool
53 | intersects = api.godot_aabb_intersects,
54 | --- Returns `true` if this AABB completely encloses another one.
55 | -- @function encloses
56 | -- @tparam AABB with
57 | -- @treturn bool
58 | encloses = api.godot_aabb_encloses,
59 | --- Returns a larger AABB that contains both this AABB and `with`.
60 | -- @function merge
61 | -- @tparam AABB with
62 | -- @treturn AABB
63 | merge = api.godot_aabb_merge,
64 | --- Returns the intersection between two AABB. An empty AABB (size 0,0,0) is returned on failure.
65 | -- @function intersection
66 | -- @tparam AABB with
67 | -- @treturn AABB
68 | intersection = api.godot_aabb_intersection,
69 | --- Returns `true` if the AABB is on both sides of a plane.
70 | -- @function intersects_plane
71 | -- @tparam Plane plane
72 | -- @treturn bool
73 | intersects_plane = api.godot_aabb_intersects_plane,
74 | --- Returns `true` if the AABB intersects the line segment between `from` and `to`.
75 | -- @function intersects_segment
76 | -- @tparam Vector3 from
77 | -- @tparam Vector3 to
78 | -- @treturn bool
79 | intersects_segment = api.godot_aabb_intersects_segment,
80 | --- Returns `true` if the AABB contains a point.
81 | -- @function has_point
82 | -- @tparam Vector3 point
83 | -- @treturn bool
84 | has_point = api.godot_aabb_has_point,
85 | --- Returns the support point in a given `direction`.
86 | -- This is useful for collision detection algorithms.
87 | -- @function get_support
88 | -- @tparam Vector3 direction
89 | -- @treturn Vector3
90 | get_support = api.godot_aabb_get_support,
91 | --- Returns the normalized longest axis of the AABB.
92 | -- @function get_longest_axis
93 | -- @treturn Vector3
94 | get_longest_axis = api.godot_aabb_get_longest_axis,
95 | --- Returns the index of the longest axis of the AABB (according to Vector3's `AXIS_*` constants).
96 | -- @function get_longest_axis_index
97 | -- @treturn int
98 | get_longest_axis_index = api.godot_aabb_get_longest_axis_index,
99 | --- Returns the scalar length of the longest axis of the AABB.
100 | -- @function get_longest_axis_size
101 | -- @treturn number
102 | get_longest_axis_size = api.godot_aabb_get_longest_axis_size,
103 | --- Returns the normalized shortest axis of the AABB.
104 | -- @function get_shortest_axis
105 | -- @treturn Vector3
106 | get_shortest_axis = api.godot_aabb_get_shortest_axis,
107 | --- Returns the index of the shortest axis of the AABB (according to Vector3's `AXIS_*` constants).
108 | -- @function get_shortest_axis_index
109 | -- @treturn int
110 | get_shortest_axis_index = api.godot_aabb_get_shortest_axis_index,
111 | --- Returns the scalar length of the shortest axis of the AABB.
112 | -- @function get_shortest_axis_size
113 | -- @treturn number
114 | get_shortest_axis_size = api.godot_aabb_get_shortest_axis_size,
115 | --- Returns this AABB expanded to include a given `point`.
116 | -- @function expand
117 | -- @tparam Vector3 point
118 | -- @treturn AABB
119 | expand = api.godot_aabb_expand,
120 | --- Returns a copy of the AABB grown a given amount of units towards all the sides.
121 | -- @function grow
122 | -- @tparam number by
123 | -- @treturn AABB
124 | grow = api.godot_aabb_grow,
125 | --- Gets the position of the 8 endpoints of the AABB in space.
126 | -- @function get_endpoint
127 | -- @tparam int index
128 | -- @treturn Vector3
129 | get_endpoint = api.godot_aabb_get_endpoint,
130 | }
131 |
132 | AABB = ffi_metatype('godot_aabb', {
133 | --- AABB constructor, called by the idiom `AABB(...)`.
134 | --
135 | -- * `AABB()`: all zeros (`AABB() == AABB(Vector3.ZERO, Vector3.ZERO)`)
136 | -- * `AABB(Vector3 position, Vector3 size)`: set position and size
137 | -- * `AABB(AABB other)`: copy values from `other`
138 | -- @function __new
139 | -- @param ...
140 | -- @treturn AABB
141 | __new = function(mt, position, size)
142 | if ffi_istype(mt, position) then
143 | return ffi_new(mt, position)
144 | else
145 | return ffi_new(mt, { position = position, size = size })
146 | end
147 | end,
148 | __index = methods,
149 | --- Returns a Lua string representation of this AABB.
150 | -- @function __tostring
151 | -- @treturn string
152 | __tostring = gd_tostring,
153 | --- Concatenates values.
154 | -- @function __concat
155 | -- @param a First value, stringified with `GD.str`
156 | -- @param b First value, stringified with `GD.str`
157 | -- @treturn String
158 | __concat = concat_gdvalues,
159 | --- Equality operation
160 | -- If either `a` or `b` are not of type `AABB`, always return `false`.
161 | -- @function __eq
162 | -- @tparam AABB a
163 | -- @tparam AABB b
164 | -- @treturn bool
165 | __eq = function(a, b)
166 | return ffi_istype(AABB, a) and ffi_istype(AABB, b) and a.position == b.position and a.size == b.size
167 | end,
168 | })
169 |
170 |
171 |
--------------------------------------------------------------------------------
/src/godot_array_commons.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_array_commons.lua Common functionality between Array and Pool*Arrays
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | local function array_empty(self)
25 | return #self == 0
26 | end
27 |
28 | local function array_safe_get(self, index)
29 | if index >= 0 and index < #self then
30 | return self:get(index)
31 | end
32 | end
33 |
34 | local function array_safe_set(self, index, value)
35 | assert(index >= 0, "Array index must be non-negative")
36 | if index >= #self then
37 | self:resize(index + 1)
38 | end
39 | self:set(index, value)
40 | end
41 |
42 | local function array_join(self, delimiter)
43 | if #self == 0 then
44 | return String()
45 | end
46 | local result = str(self:get(0))
47 | delimiter = str(delimiter or "")
48 | for i = 1, #self - 1 do
49 | result = result .. delimiter .. self:get(i)
50 | end
51 | return result
52 | end
53 |
54 | local function array_next(self, index)
55 | index = index + 1
56 | if index > 0 and index <= #self then
57 | return index, self:get(index - 1)
58 | end
59 | end
60 |
61 | local function array_ipairs(self)
62 | return array_next, self, 0
63 | end
64 |
65 | local function array_generate__index(methods)
66 | return function(self, index)
67 | return methods[index] or array_safe_get(self, index - 1)
68 | end
69 | end
70 |
71 | local function array__newindex(self, index, value)
72 | array_safe_set(self, index - 1, value)
73 | end
74 |
75 | local function array__len(self)
76 | return self:size()
77 | end
78 |
79 | local function array__eq(a, b)
80 | if not has_length(a) or not has_length(b) or #a ~= #b then
81 | return false
82 | end
83 | for i = 1, #a do
84 | if a[i] ~= b[i] then
85 | return false
86 | end
87 | end
88 | return true
89 | end
90 |
91 | local function array_generate_get_buffer(ctype)
92 | local element_size = ffi_sizeof(ctype)
93 | return function(self)
94 | local buffer = PoolByteArray()
95 | local size = #self * element_size
96 | buffer:resize(size)
97 | local src = self:read()
98 | local dst = buffer:write()
99 | ffi_copy(dst:ptr(), src:ptr(), size)
100 | dst:destroy()
101 | src:destroy()
102 | return buffer
103 | end
104 | end
105 |
--------------------------------------------------------------------------------
/src/godot_class.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_class.lua Method Binds and generic Godot Class definitions
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Helper metatables for interfacing with Godot's OOP.
25 | -- None of them are available directly for creation, but are rather returned by
26 | -- the API.
27 | -- @module OOP
28 |
29 | -- Stringification helpers
30 | local function str(value)
31 | if ffi_istype(String, value) then
32 | return value
33 | else
34 | return Variant(value):as_string()
35 | end
36 | end
37 |
38 | local function gd_tostring(value)
39 | return tostring(str(value))
40 | end
41 |
42 | local function concat_gdvalues(a, b)
43 | return ffi_gc(api.godot_string_operator_plus(str(a), str(b)), api.godot_string_destroy)
44 | end
45 |
46 | -- Class/Object definitions
47 | local ClassDB = api.godot_global_get_singleton("ClassDB")
48 |
49 | local Object_call = api.godot_method_bind_get_method('Object', 'call')
50 | local Object_get = api.godot_method_bind_get_method('Object', 'get')
51 | local Object_set = api.godot_method_bind_get_method('Object', 'set')
52 | local Object_has_method = api.godot_method_bind_get_method('Object', 'has_method')
53 | local Object_is_class = api.godot_method_bind_get_method('Object', 'is_class')
54 | local Reference_init_ref = api.godot_method_bind_get_method('Reference', 'init_ref')
55 | local Reference_reference = api.godot_method_bind_get_method('Reference', 'reference')
56 | local Reference_unreference = api.godot_method_bind_get_method('Reference', 'unreference')
57 |
58 | local function Object_gc(obj)
59 | if Reference_unreference(obj) then
60 | api.godot_object_destroy(obj)
61 | end
62 | end
63 |
64 | --- Wrapper for Godot Classes, used to create instances or index constants.
65 | -- These are constructed by `_G:__index` when indexing a known class name, e.g.: `KinematicBody`.
66 | -- @type ClassWrapper
67 | local class_methods = {
68 | --- Creates a new instance of a Class, initializing with the given values.
69 | -- If Class inherits from Reference, the reference is initialized with
70 | -- `init_ref` and object is marked for `unreference`ing at garbage-collection.
71 | -- @function new
72 | -- @param ... Parameters forwarded to a call to `_init`
73 | -- @treturn Object
74 | new = function(self, ...)
75 | local obj = self.constructor()
76 | if Object_is_class(obj, 'Reference') and Reference_init_ref(obj) then
77 | ffi_gc(obj, Object_gc)
78 | end
79 | obj:pcall('_init', ...)
80 | return obj
81 | end,
82 | --- Returns whether this Class inherits a `parent` Class.
83 | -- @function inherits
84 | -- @param other Other class name
85 | -- @treturn bool
86 | inherits = function(self, parent)
87 | return ClassDB:is_parent_class(self.class_name, parent)
88 | end,
89 | --- Returns the parent class.
90 | -- @function get_parent_class
91 | -- @treturn String
92 | get_parent_class = function(self)
93 | return ClassDB:get_parent_class(self.class_name)
94 | end,
95 | --- Returns whether class has a property named `name`.
96 | -- Only properties from `ClassDB:class_get_property_list()` return true.
97 | -- @function has_property
98 | -- @tparam string name Property name
99 | -- @treturn bool
100 | has_property = function(self, name)
101 | local cache = self.known_properties
102 | if not cache then
103 | cache = {}
104 | for _, prop in ipairs(ClassDB:class_get_property_list(self.class_name)) do
105 | cache[tostring(prop.name)] = true
106 | end
107 | self.known_properties = cache
108 | end
109 | return cache[name] ~= nil
110 | end,
111 | }
112 | local ClassWrapper = {
113 | new = function(self, class_name)
114 | return setmetatable({
115 | --- (`string`) Class name
116 | class_name = class_name,
117 | --- (`Object (*)()`) Raw constructor function as returned by GDNative's `godot_get_class_constructor`.
118 | -- This is used by `new` and should probably not be used directly.
119 | -- @see new
120 | constructor = api.godot_get_class_constructor(class_name),
121 | }, self)
122 | end,
123 | --- Returns a `MethodBind` if class has a method with that name, or an integer
124 | -- constant if there is any.
125 | -- @function __index
126 | -- @param key
127 | -- @treturn[1] MethodBind If `ClassDB:class_has_method(self.class_name, key)`
128 | -- @treturn[2] int If `ClassDB:class_has_integer_constant(self.class_name, key)`
129 | -- @treturn[3] nil
130 | __index = function(self, key)
131 | local method = class_methods[key]
132 | if method then return method end
133 | local method_bind = api.godot_method_bind_get_method(self.class_name, key)
134 | if method_bind ~= nil then
135 | rawset(self, key, method_bind)
136 | return method_bind
137 | end
138 | local varkey = Variant(key)
139 | if ClassDB:class_has_integer_constant(self.class_name, varkey) then
140 | local constant = ClassDB:class_get_integer_constant(self.class_name, varkey)
141 | rawset(self, key, constant)
142 | return constant
143 | end
144 | end,
145 | --- Returns `class_name`
146 | -- @function __tostring
147 | -- @treturn string
148 | __tostring = function(self)
149 | return self.class_name
150 | end,
151 | }
152 |
153 | local function is_class_wrapper(v)
154 | return getmetatable(v) == ClassWrapper
155 | end
156 |
157 |
158 | local ClassWrapper_cache = setmetatable({}, {
159 | __index = function(self, class_name)
160 | if not ClassDB:class_exists(class_name) then
161 | return nil
162 | end
163 | class_name = tostring(class_name)
164 | local cls = ClassWrapper:new(class_name)
165 | rawset(self, class_name, cls)
166 | return cls
167 | end,
168 | })
169 |
170 |
171 | --- MethodBind metatype, wrapper for `godot_method_bind`.
172 | -- These are returned by `ClassWrapper:__index` and GDNative's `godot_method_bind_get_method`.
173 | -- @type MethodBind
174 | local MethodBind = ffi_metatype('godot_method_bind', {
175 | --- Calls the method in `object`.
176 | -- @function __call
177 | -- @tparam Object object
178 | -- @param ...
179 | -- @return Method return value
180 | __call = function(self, obj, ...)
181 | local argc = select('#', ...)
182 | local argv = ffi_new('godot_variant *[?]', argc)
183 | for i = 1, argc do
184 | local arg = select(i, ...)
185 | argv[i - 1] = Variant(arg)
186 | end
187 | local r_error = ffi_new('godot_variant_call_error')
188 | local value = ffi_gc(api.godot_method_bind_call(self, _Object(obj), ffi_cast('const godot_variant **', argv), argc, r_error), api.godot_variant_destroy)
189 | if r_error.error == CallError.OK then
190 | return value:unbox()
191 | elseif r_error.error == CallError.ERROR_INVALID_METHOD then
192 | error("Invalid method")
193 | elseif r_error.error == CallError.ERROR_INVALID_ARGUMENT then
194 | error(string_format("Invalid argument #%d, expected %s",
195 | r_error.argument + 1,
196 | VariantType[tonumber(r_error.expected)]
197 | ))
198 | elseif r_error.error == CallError.ERROR_TOO_MANY_ARGUMENTS then
199 | error("Too many arguments")
200 | elseif r_error.error == CallError.ERROR_TOO_FEW_ARGUMENTS then
201 | error("Too few arguments")
202 | elseif r_error.error == CallError.ERROR_INSTANCE_IS_NULL then
203 | error("Instance is null")
204 | end
205 | end,
206 | })
207 |
208 |
209 | --- A method binding object that calls a method by name, as `object:call(method_name, ...)`.
210 | -- These are returned by `Object.__index` if `object:has_method(method_name)` is true.
211 | -- @type MethodBindByName
212 | local MethodBindByName = {
213 | --- Create a new method binding by name.
214 | -- @usage
215 | -- local method_bind = MethodBindByName:new(method_name)
216 | -- method_bind(object, ...)
217 | -- @function new
218 | -- @tparam string method_name
219 | -- @treturn MethodBindByName
220 | new = function(self, method_name)
221 | return setmetatable({
222 | --- (`string`) Method name.
223 | method_name = method_name
224 | }, self)
225 | end,
226 | --- Returns the result of `object:call(self.method_name, ...)`.
227 | -- @function __call
228 | -- @tparam Object|ScriptInstance|Variant object
229 | -- @param ...
230 | __call = function(self, obj, ...)
231 | return obj:call(self.method_name, ...)
232 | end,
233 | }
234 |
235 |
--------------------------------------------------------------------------------
/src/godot_dictionary.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_dictionary.lua Wrapper for GDNative's Dictionary
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Dictionary metatype, wrapper for `godot_dictionary`.
25 | -- Construct using the idiom `Dictionary(from)`, which calls `__new`.
26 | -- @classmod Dictionary
27 |
28 | local Dictionary_erase = api_1_1 ~= nil and api_1_1.godot_dictionary_erase_with_return or api.godot_dictionary_erase
29 |
30 | local methods = {
31 | fillvariant = api.godot_variant_new_dictionary,
32 | varianttype = VariantType.Dictionary,
33 |
34 | --- Returns the number of keys in the Dictionary.
35 | -- @function size
36 | -- @treturn int
37 | size = api.godot_dictionary_size,
38 | --- Returns `true` if the Dictionary is empty.
39 | -- @function empty
40 | -- @treturn bool
41 | empty = api.godot_dictionary_empty,
42 | --- Clear the Dictionary, removing all key/value pairs.
43 | -- @function clear
44 | clear = api.godot_dictionary_clear,
45 | --- Returns `true` if the Dictionary has a given key.
46 | -- @function has
47 | -- @param key
48 | -- @treturn bool
49 | has = function(self, key)
50 | return api.godot_dictionary_has(self, Variant(key))
51 | end,
52 | --- Returns `true` if the dictionary has all the given keys.
53 | -- @function has_all
54 | -- @param ... If only a table or Array value is passed, its values are used as search keys.
55 | -- Otherwise, all passed arguments will be used as search keys.
56 | -- @treturn bool
57 | has_all = function(self, keys, ...)
58 | if select('#', ...) > 0 or not ffi_istype(Array, keys) then
59 | keys = Array(keys, ...)
60 | end
61 | return api.godot_dictionary_has_all(self, keys)
62 | end,
63 | --- Erase a dictionary key/value pair by key.
64 | -- Returns `true` if the given key was present in the Dictionary, `false` otherwise.
65 | -- Does not erase elements while iterating over the dictionary.
66 | -- @function erase
67 | -- @param key Key, boxed with `Variant.__new`
68 | -- @treturn bool
69 | erase = function(self, key)
70 | return Dictionary_erase(self, Variant(key))
71 | end,
72 | --- Returns a hashed integer value representing the Dictionary contents.
73 | -- This can be used to compare Dictionaries by value.
74 | -- Note: Dictionaries with the same keys/values but in a different order will have a different hash.
75 | -- @function hash
76 | -- @treturn int
77 | hash = api.godot_dictionary_hash,
78 | --- Returns the list of keys in the Dictionary.
79 | -- @function keys
80 | -- @treturn Array
81 | keys = function(self)
82 | return ffi_gc(api.godot_dictionary_keys(self), api.godot_array_destroy)
83 | end,
84 | --- Returns the list of values in the Dictionary.
85 | -- @function values
86 | -- @treturn Array
87 | values = function(self)
88 | return ffi_gc(api.godot_dictionary_values(self), api.godot_array_destroy)
89 | end,
90 | --- Returns the current value for the specified `key` in the Dictionary.
91 | -- If the key does not exist, the method returns the value of the optional `default` argument, or `nil` if it is omitted.
92 | -- @function get
93 | -- @param key
94 | -- @param[opt] default Default value to be returned if key doesn't exist in Dictionary
95 | -- @return Unboxed value or `default` or nil
96 | get = function(self, key, default)
97 | if default ~= nil and api_1_1 ~= nil then
98 | return ffi_gc(api_1_1.godot_dictionary_get_with_default(self, Variant(key), Variant(default)), api.godot_variant_destroy):unbox()
99 | else
100 | return ffi_gc(api.godot_dictionary_get(self, Variant(key)), api.godot_variant_destroy):unbox()
101 | end
102 | end,
103 | --- Set a new value for the specified `key` in the Dictionary.
104 | -- @function set
105 | -- @param key
106 | -- @param value
107 | set = function(self, key, value)
108 | api.godot_dictionary_set(self, Variant(key), Variant(value))
109 | end,
110 | --- Returns the next key/value pair Dictionary's, similar to Lua's [next](https://www.lua.org/manual/5.1/manual.html#pdf-next).
111 | -- This is used to iterate over Dictionaries in `__pairs`.
112 | -- @usage
113 | -- local key, value = nil -- First key being `nil`, the iteration begins
114 | -- while true do
115 | -- key, value = dict:next(key)
116 | -- if key == nil then break end
117 | -- -- do something
118 | -- end
119 | -- @function next
120 | -- @param key If `nil`, returns the first key/value pair.
121 | -- Otherwise, returns the next key/value pair.
122 | -- @return[1] Key
123 | -- @return[1] Value
124 | -- @treturn[2] nil If there are no more keys
125 | -- @see __pairs
126 | next = function(self, key)
127 | if key ~= nil then
128 | key = Variant(key)
129 | end
130 | local next_key = api.godot_dictionary_next(self, key)
131 | if next_key ~= nil then
132 | return next_key:unbox(), self:get(next_key)
133 | else
134 | return nil
135 | end
136 | end,
137 | --- Returns a String with JSON representation of the Dictionary's contents.
138 | -- @function to_json
139 | -- @treturn String
140 | to_json = function(self)
141 | return ffi_gc(api.godot_dictionary_to_json(self), api.godot_string_destroy)
142 | end,
143 | }
144 |
145 | if api_1_2 ~= nil then
146 | --- Creates a copy of the dictionary, and returns it.
147 | -- The `deep` parameter causes inner Dictionaries and Arrays to be copied recursively, but does not apply to Objects.
148 | -- @function duplicate
149 | -- @param[opt=false] deep
150 | -- @treturn Dictionary
151 | methods.duplicate = function(self, deep)
152 | return ffi_gc(api_1_2.godot_dictionary_duplicate(self, deep or false), api.godot_dictionary_destroy)
153 | end
154 | end
155 |
156 | if api_1_3 ~= nil then
157 | --- Adds elements from `dictionary` to this Dictionary.
158 | -- By default, duplicate keys will not be copied over, unless `overwrite` is `true`.
159 | -- @function merge
160 | -- @tparam Dictionary dictionary
161 | -- @param[opt=false] overwrite
162 | methods.merge = function(self, dictionary, overwrite)
163 | api_1_3.godot_dictionary_merge(self, dictionary, overwrite or false)
164 | end
165 | end
166 |
167 | Dictionary = ffi_metatype('godot_dictionary', {
168 | --- Dictionary constructor, called by the idiom `Dictionary(value)`.
169 | -- @function __new
170 | -- @param[opt] value If passed, the key/value pairs will be iterated with
171 | -- `pairs` and inserted into the new Dictionary using `set`.
172 | -- Notice that both tables and userdata/cdata with a `__pairs` metamethod
173 | -- are valid, including another Dictionary.
174 | -- @treturn Dictionary
175 | __new = function(mt, value)
176 | local self = ffi_new('godot_dictionary')
177 | api.godot_dictionary_new(self)
178 | if value then
179 | for k, v in pairs(value) do
180 | self[k] = v
181 | end
182 | end
183 | return self
184 | end,
185 | __index = function(self, key)
186 | return methods[key] or methods.get(self, key)
187 | end,
188 | --- Set a value to Dictionary.
189 | -- If `value` is `nil`, the `key` will be `erase`d, similarly to Lua tables.
190 | -- To insert a Nil Variant into Dictionary, use `set` instead.
191 | -- @function __newindex
192 | -- @param key
193 | -- @param value
194 | __newindex = function(self, key, value)
195 | if type(value) == 'nil' then
196 | api.godot_dictionary_erase(self, Variant(key))
197 | else
198 | api.godot_dictionary_set(self, Variant(key), Variant(value))
199 | end
200 | end,
201 | __gc = api.godot_dictionary_destroy,
202 | --- Returns a Lua string representation of this Dictionary.
203 | -- @function __tostring
204 | -- @treturn string
205 | __tostring = gd_tostring,
206 | --- Concatenates values.
207 | -- @function __concat
208 | -- @param a First value, stringified with `GD.str`
209 | -- @param b First value, stringified with `GD.str`
210 | -- @treturn String
211 | __concat = concat_gdvalues,
212 | --- Alias for `size`.
213 | -- @function __len
214 | -- @treturn int
215 | -- @see size
216 | __len = function(self)
217 | return methods.size(self)
218 | end,
219 | --- Returns the `next` iterator and `self`, called by the idiom `pairs(dictionary)`.
220 | -- @usage
221 | -- for k, v in pairs(dictionary) do
222 | -- -- do something
223 | -- end
224 | -- @function __pairs
225 | -- @treturn function
226 | -- @treturn Dictionary self
227 | __pairs = function(self)
228 | return methods.next, self
229 | end,
230 | })
231 |
232 |
--------------------------------------------------------------------------------
/src/godot_node_path.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_node_path.lua Wrapper for GDNative's NodePath
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- NodePath metatype, wrapper for `godot_node_path`.
25 | -- Construct using the idiom `NodePath(path)`, which calls `__new`.
26 | -- @classmod NodePath
27 |
28 | local function is_a_node_path(v)
29 | return is_a_string(v) or ffi_istype(NodePath, v)
30 | end
31 |
32 | local methods = {
33 | fillvariant = api.godot_variant_new_node_path,
34 | varianttype = VariantType.NodePath,
35 |
36 | --- Gets a `String` that represents this NodePath.
37 | -- @function as_string
38 | -- @treturn String
39 | as_string = function(self)
40 | return ffi_gc(api.godot_node_path_as_string(self), api.godot_string_destroy)
41 | end,
42 | --- Returns `true` if the node path is absolute (as opposed to relative), which means that it starts with a slash character (`/`).
43 | -- @function is_absolute
44 | -- @treturn bool
45 | is_absolute = api.godot_node_path_is_absolute,
46 | --- Gets the number of node names which make up the path.
47 | -- Subnames (see `get_subname_count`) are not included.
48 | -- @function get_name_count
49 | -- @treturn int
50 | get_name_count = api.godot_node_path_get_name_count,
51 | --- Gets the node name indicated by `idx`.
52 | -- @function get_name
53 | -- @tparam int idx
54 | -- @treturn String
55 | get_name = function(self, idx)
56 | return ffi_gc(api.godot_node_path_get_name(self, idx), api.godot_string_destroy)
57 | end,
58 | --- Gets the number of resource or property names ("subnames") in the path.
59 | -- Each subname is listed after a colon character (`:`) in the node path.
60 | -- @function get_subname_count
61 | -- @treturn int
62 | get_subname_count = api.godot_node_path_get_subname_count,
63 | --- Gets the resource or property name indicated by `idx`.
64 | -- @function get_subname
65 | -- @tparam int idx
66 | -- @treturn String
67 | get_subname = function(self, idx)
68 | return ffi_gc(api.godot_node_path_get_subname(self, idx), api.godot_string_destroy)
69 | end,
70 | --- Returns all subnames concatenated with a colon character (`:`) as separator, i.e. the right side of the first colon in a node path.
71 | -- @function get_concatenated_subnames
72 | -- @treturn String
73 | get_concatenated_subnames = function(self)
74 | return ffi_gc(api.godot_node_path_get_concatenated_subnames(self), api.godot_string_destroy)
75 | end,
76 | --- Returns `true` if the node path is empty.
77 | -- @function is_empty
78 | -- @treturn bool
79 | is_empty = api.godot_node_path_is_empty,
80 | --- Returns a node path with a colon character (`:`) prepended, transforming it to a pure property path with no node name (defaults to resolving from the current node).
81 | -- @function get_as_property_path
82 | -- @treturn String
83 | get_as_property_path = function(self)
84 | return ffi_gc(api.godot_node_path_get_as_property_path(self), api.godot_node_path_destroy)
85 | end,
86 | }
87 | NodePath = ffi_metatype('godot_node_path', {
88 | --- NodePath constructor, called by the idiom `NodePath(path)`.
89 | --
90 | -- * `NodePath()`: empty NodePath
91 | -- * `NodePath(any path)`: created with `path` stringified with `GD.str`
92 | -- * `NodePath(NodePath other)`: copy from `other`
93 | -- @function __new
94 | -- @param[opt] path
95 | -- @treturn NodePath
96 | __new = function(mt, path)
97 | local self = ffi_new(mt)
98 | if ffi_istype(mt, path) then
99 | api.godot_node_path_new_copy(self, path)
100 | else
101 | api.godot_node_path_new(self, str(path or ''))
102 | end
103 | return self
104 | end,
105 | __gc = api.godot_node_path_destroy,
106 | __index = methods,
107 | --- Returns a Lua string representation of this NodePath.
108 | -- @function __tostring
109 | -- @treturn string
110 | -- @see as_string
111 | __tostring = function(self)
112 | return tostring(methods.as_string(self))
113 | end,
114 | --- Concatenates values.
115 | -- @function __concat
116 | -- @param a First value, stringified with `GD.str`
117 | -- @param b First value, stringified with `GD.str`
118 | -- @treturn String
119 | __concat = concat_gdvalues,
120 | --- Equality comparison (`a == b`).
121 | -- If either `a` or `b` are not of type `NodePath`, `String` or Lua `string`, always return `false`.
122 | -- @function __eq
123 | -- @param a
124 | -- @param b
125 | -- @treturn bool
126 | __eq = function(a, b)
127 | return is_a_node_path(a) and is_a_node_path(b) and api.godot_node_path_operator_equal(NodePath(a), NodePath(b))
128 | end,
129 | })
130 |
--------------------------------------------------------------------------------
/src/godot_plane.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_plane.lua Wrapper for GDNative's Plane
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Plane metatype, wrapper for `godot_plane`.
25 | -- Constructed using the idiom `Plane(...)`, which calls `__new`.
26 | --
27 | -- The components may be accessed through `elements` or individually as
28 | -- `normal/d`:
29 | -- typedef union godot_plane {
30 | -- float elements[4];
31 | -- struct { Vector3 normal; float d; };
32 | -- } godot_plane;
33 | -- @classmod Plane
34 |
35 | local methods = {
36 | fillvariant = api.godot_variant_new_plane,
37 | varianttype = VariantType.Plane,
38 |
39 | --- Returns a copy of the plane, normalized.
40 | -- @function normalized
41 | -- @treturn Plane
42 | normalized = api.godot_plane_normalized,
43 | --- Returns the center of the plane.
44 | -- @function center
45 | -- @treturn Vector3
46 | center = api.godot_plane_center,
47 | --- Returns `true` if `point` is located above the plane.
48 | -- @function is_point_over
49 | -- @tparam Vector2 point
50 | -- @treturn bool
51 | is_point_over = api.godot_plane_is_point_over,
52 | --- Returns the shortest distance from the plane to the position `point`.
53 | -- @function distance_to
54 | -- @tparam Vector3 point
55 | -- @treturn number
56 | distance_to = api.godot_plane_distance_to,
57 | --- Returns `true` if `point` is inside the plane.
58 | -- Comparison uses a custom minimum `epsilon` threshold.
59 | -- @function has_point
60 | -- @tparam Vector3 point
61 | -- @tparam[opt=1e-5] number epsilon
62 | -- @treturn bool
63 | has_point = function(self, point, epsilon)
64 | return api.godot_plane_has_point(self, point, epsilon or 1e-5)
65 | end,
66 | --- Returns the orthogonal projection of `point` into a point in the plane.
67 | -- @function project
68 | -- @tparam Vector3 point
69 | -- @treturn Vector3
70 | project = api.godot_plane_project,
71 | --- Returns the intersection point of the three planes `b`, `c` and this plane.
72 | -- @function intersect_3
73 | -- @tparam Plane b
74 | -- @tparam Plane c
75 | -- @treturn[1] Vector3 Intersection point, if there is any
76 | -- @treturn[2] nil If no intersection is found
77 | intersect_3 = function(self, b, c)
78 | local dest = Vector3()
79 | if api.godot_plane_intersect_3(self, dest, b, c) then
80 | return dest
81 | else
82 | return nil
83 | end
84 | end,
85 | --- Returns the intersection point of a ray consisting of the position `from` and the direction normal `dir` with this plane.
86 | -- @function intersects_ray
87 | -- @tparam Vector3 from
88 | -- @tparam Vector3 dir
89 | -- @treturn[1] Vector3 Intersection point, if there is any
90 | -- @treturn[2] nil If no intersection is found
91 | intersects_ray = function(self, from, dir)
92 | local dest = Vector3()
93 | if api.godot_plane_intersects_ray(self, dest, from, dir) then
94 | return dest
95 | else
96 | return nil
97 | end
98 | end,
99 | --- Returns the intersection point of a segment from position `begin` to position `end` with this plane.
100 | -- @function intersects_segment
101 | -- @tparam Vector3 begin
102 | -- @tparam Vector3 end
103 | -- @treturn[1] Vector3 Intersection point, if there is any
104 | -- @treturn[2] nil If no intersection is found
105 | intersects_segment = function(self, begin, end_)
106 | local dest = Vector3()
107 | if api.godot_plane_intersects_segment(self, dest, begin, end_) then
108 | return dest
109 | else
110 | return nil
111 | end
112 | end,
113 | }
114 |
115 | --- Returns all elements.
116 | -- @function unpack
117 | -- @treturn number normal.x
118 | -- @treturn number normal.y
119 | -- @treturn number normal.z
120 | -- @treturn number d
121 | methods.unpack = function(self)
122 | return self.normal.x, self.normal.y, self.normal.z, self.d
123 | end
124 |
125 | --- Constants
126 | -- @section constants
127 |
128 | --- A plane that extends in the Y and Z axes (normal vector points +X).
129 | -- @field YZ Plane(1, 0, 0, 0)
130 |
131 | --- A plane that extends in the X and Z axes (normal vector points +Y).
132 | -- @field XZ Plane(0, 1, 0, 0)
133 |
134 | --- A plane that extends in the X and Y axes (normal vector points +Z).
135 | -- @field XY Plane(0, 0, 1, 0)
136 |
137 | --- @section end
138 |
139 | methods.YZ = ffi_new('godot_plane', { elements = { 1, 0, 0, 0 } })
140 | methods.XZ = ffi_new('godot_plane', { elements = { 0, 1, 0, 0 } })
141 | methods.XY = ffi_new('godot_plane', { elements = { 0, 0, 1, 0 } })
142 |
143 | --- Metamethods
144 | -- @section metamethods
145 | Plane = ffi_metatype('godot_plane', {
146 | --- Plane constructor, called by the idiom `Plane(...)`.
147 | --
148 | -- * `Plane(Vector3 normal, number d)`: set the normal and the plane's distance to the origin
149 | -- * `Plane(number a, number b, number c, number d)`: normal is set to `Vector3(a, b, c)`, distance is set to `d`
150 | -- * `Plane(Vector3 a, Vector3 b, Vector3 c)`: creates a plane from the three points, given in clockwise order
151 | -- * `Plane(Plane other)`: copy values from `other`
152 | -- @function __new
153 | -- @param ...
154 | -- @treturn Plane
155 | __new = function(mt, a, b, c, d)
156 | if ffi_istype(mt, a) then
157 | return ffi_new(mt, a)
158 | end
159 | local self = ffi_new(mt)
160 | if ffi_istype(Vector3, a) then
161 | if ffi.istype(Vector3, b) then
162 | api.godot_plane_new_with_vectors(self, a, b, c)
163 | else
164 | api.godot_plane_new_with_normal(self, a, b)
165 | end
166 | else
167 | api.godot_plane_new_with_reals(self, a, b, c, d)
168 | end
169 | return self
170 | end,
171 | __index = methods,
172 | --- Returns a Lua string representation of this plane.
173 | -- @function __tostring
174 | -- @treturn string
175 | __tostring = gd_tostring,
176 | --- Concatenates values.
177 | -- @function __concat
178 | -- @param a First value, stringified with `GD.str`
179 | -- @param b First value, stringified with `GD.str`
180 | -- @treturn String
181 | __concat = concat_gdvalues,
182 | --- Unary minus operation
183 | -- @function __unm
184 | -- @treturn Plane
185 | __unm = function(self)
186 | return Plane(-self.normal, -self.d)
187 | end,
188 | --- Equality operation
189 | -- If either `a` or `b` are not of type `Plane`, always return `false`.
190 | -- @function __eq
191 | -- @tparam Plane a
192 | -- @tparam Plane b
193 | -- @treturn bool
194 | __eq = function(a, b)
195 | return a.d == b.d and a.normal == b.normal
196 | end,
197 | })
198 |
199 |
200 |
--------------------------------------------------------------------------------
/src/godot_quat.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_quat.lua Wrapper for GDNative's Quat
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Quat metatype, wrapper for `godot_quat`.
25 | -- Constructed using the idiom `Quat(...)`, which calls `__new`.
26 | --
27 | -- The X, Y, Z and W components may be accessed through `elements` or individually
28 | -- with `x/y/z/w`. `Vector2` with two adjacent components may be get/set with the
29 | -- pairs `xy/yz/zw`. `Vector3` with three adjacent components may be get/set with
30 | -- the triplets `xyz/yzw`:
31 | -- typedef union godot_quat {
32 | -- float elements[4];
33 | -- struct { float x, y, z, w; };
34 | -- struct { Vector2 xy; Vector2 zw; };
35 | -- struct { float _; Vector2 yz; float _; };
36 | -- struct { Vector3 xyz; float _; };
37 | -- struct { float _; Vector3 yzw; };
38 | -- } godot_quat;
39 | -- @classmod Quat
40 |
41 | local methods = {
42 | fillvariant = api.godot_variant_new_quat,
43 | varianttype = VariantType.Quat,
44 |
45 | --- Returns the length of the quaternion.
46 | -- @function length
47 | -- @treturn number
48 | length = api.godot_quat_length,
49 | --- Returns the length of the quaternion, squared.
50 | -- @function length_squared
51 | -- @treturn number
52 | length_squared = api.godot_quat_length_squared,
53 | --- Returns a copy of the quaternion, normalized to unit length.
54 | -- @function normalized
55 | -- @treturn Quat
56 | normalized = api.godot_quat_normalized,
57 | --- Returns whether the quaternion is normalized or not.
58 | -- @function is_normalized
59 | -- @treturn bool
60 | is_normalized = api.godot_quat_is_normalized,
61 | --- Returns the inverse of the quaternion.
62 | -- @function inverse
63 | -- @treturn Quat
64 | inverse = api.godot_quat_inverse,
65 | --- Returns the dot product of two quaternions.
66 | -- @function dot
67 | -- @tparam Quat b
68 | -- @treturn number
69 | dot = api.godot_quat_dot,
70 | --- Returns a vector transformed (multiplied) by this quaternion.
71 | -- @function xform
72 | -- @tparam Vector3 v
73 | -- @treturn Vector3
74 | xform = api.godot_quat_xform,
75 | --- Returns the result of the spherical linear interpolation between this quaternion and `to` by amount `weight`.
76 | -- Note: Both quaternions must be normalized.
77 | -- @function slerp
78 | -- @tparam Quat to
79 | -- @tparam number weight
80 | -- @treturn Quat
81 | -- @see slerpni
82 | slerp = api.godot_quat_slerp,
83 | --- Returns the result of the spherical linear interpolation between this quaternion and `to` by amount `weight`, but without checking if the rotation path is not bigger than 90 degrees.
84 | -- Note: Both quaternions must be normalized.
85 | -- @function slerpni
86 | -- @tparam Quat to
87 | -- @tparam number weight
88 | -- @treturn Quat
89 | -- @see slerp
90 | slerpni = api.godot_quat_slerpni,
91 | --- Performs a cubic spherical interpolation between quaternions `preA`, this vector, `b`, and `postB`, by the given amount `t`.
92 | -- @function cubic_slerp
93 | -- @tparam Quat b
94 | -- @tparam Quat preA
95 | -- @tparam Quat postB
96 | -- @tparam number t
97 | -- @treturn Quat
98 | cubic_slerp = api.godot_quat_cubic_slerp,
99 | }
100 |
101 | --- Returns all elements.
102 | -- @function unpack
103 | -- @treturn number X
104 | -- @treturn number Y
105 | -- @treturn number Z
106 | -- @treturn number W
107 | methods.unpack = function(self)
108 | return self.x, self.y, self.z, self.w
109 | end
110 |
111 | --- Constants
112 | -- @section constants
113 |
114 | --- The identity quaternion, representing no rotation.
115 | -- Equivalent to an identity `Basis` matrix. If a vector is transformed by an identity quaternion, it will not change.
116 | -- @field IDENTITY Quat(0, 0, 0, 1)
117 |
118 | --- @section end
119 |
120 | methods.IDENTITY = ffi_new('godot_quat', { elements = { 0, 0, 0, 1 } })
121 |
122 | --- Metamethods
123 | -- @section metamethods
124 | Quat = ffi_metatype('godot_quat', {
125 | --- Quat constructor, called by the idiom `Quat(...)`.
126 | --
127 | -- * `Quat()`: `IDENTITY` quaternion (`Quat() == Quat(0, 0, 0, 1)`)
128 | -- * `Quat(number x[, number y = 0[, number z = 0[, number w = 1]]])`: set XYZW
129 | -- * `Quat(Basis basis)`: construct from basis
130 | -- * `Quat(Vector3 euler)`: rotation specified by Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last)
131 | -- * `Quat(Vector3 axis, number angle)`: rotates around the given axis by the specified angle. The axis must be a normalized vector.
132 | -- * `Quat(Quat other)`: copy values from `other`
133 | -- @function __new
134 | -- @param ...
135 | -- @treturn Quat
136 | __new = function(mt, x, y, z, w)
137 | if ffi_istype(mt, x) then
138 | return ffi_new(mt, x)
139 | end
140 | local self = ffi_new(mt)
141 | if ffi_istype(Vector3, x) then
142 | if y then
143 | api.godot_quat_new_with_axis_angle(self, x, y)
144 | else
145 | api_1_1.godot_quat_new_with_euler(self, x)
146 | end
147 | elseif ffi_istype(Basis, x) then
148 | api_1_1.godot_quat_new_with_basis(self, x)
149 | else
150 | api.godot_quat_new(self, x or 0, y or 0, z or 0, w or 1)
151 | end
152 | return self
153 | end,
154 | __index = methods,
155 | --- Returns a Lua string representation of this quaternion.
156 | -- @function __tostring
157 | -- @treturn string
158 | __tostring = gd_tostring,
159 | --- Concatenates values.
160 | -- @function __concat
161 | -- @param a First value, stringified with `GD.str`
162 | -- @param b First value, stringified with `GD.str`
163 | -- @treturn String
164 | __concat = concat_gdvalues,
165 | --- Addition operation
166 | -- @function __add
167 | -- @tparam Quat a
168 | -- @tparam Quat b
169 | -- @treturn Quat
170 | __add = function(a, b)
171 | return Quat(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w)
172 | end,
173 | --- Subtraction operation
174 | -- @function __sub
175 | -- @tparam Quat a
176 | -- @tparam Quat b
177 | -- @treturn Quat
178 | __sub = function(a, b)
179 | return Quat(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w)
180 | end,
181 | --- Multiplication operation
182 | -- @function __mul
183 | -- @tparam Quat a
184 | -- @tparam Vector3|number b If a Vector3 is passed, calls `xform`.
185 | -- Otherwise, returns a Quat with each component multiplied by `b`.
186 | -- @treturn Quat|Vector3
187 | __mul = function(self, b)
188 | if ffi_istype(Vector3, b) then
189 | return self:xform(b)
190 | else
191 | return Quat(self.x * b, self.y * b, self.z * b, self.w * b)
192 | end
193 | end,
194 | --- Division operation
195 | -- @function __div
196 | -- @tparam Quat a
197 | -- @tparam number s
198 | -- @treturn Quat
199 | __div = function(self, s)
200 | return self * (1.0 / s)
201 | end,
202 | --- Unary minus operation
203 | -- @function __unm
204 | -- @treturn Quat
205 | __unm = function(self)
206 | return Quat(-self.x, -self.y, -self.z, -self.w)
207 | end,
208 | --- Equality operation
209 | -- If either `a` or `b` are not of type `Quat`, always return `false`.
210 | -- @function __eq
211 | -- @tparam Quat a
212 | -- @tparam Quat b
213 | -- @treturn bool
214 | __eq = function(a, b)
215 | return ffi_istype(Quat, a) and ffi_istype(Quat, b) and a.x == b.x and a.y == b.y and a.z == b.z and a.w == b.w
216 | end,
217 | })
218 |
219 |
220 |
--------------------------------------------------------------------------------
/src/godot_rect2.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_rect2.lua Wrapper for GDNative's Rect2
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Color metatype, wrapper for `godot_rect2`.
25 | -- Construct using the idiom `Rect2(...)`, which calls `__new`.
26 | --
27 | -- Components may be accessed through `elements`, individually using
28 | -- `x/y/width/height` or as `Vector2` `position/size`:
29 | -- typedef union godot_rect2 {
30 | -- uint8_t data[16];
31 | -- float elements[4];
32 | -- struct { float x, y, width, height; };
33 | -- struct { Vector2 position; Vector2 size; };
34 | -- } godot_rect2;
35 | -- @classmod Rect2
36 |
37 | local methods = {
38 | fillvariant = api.godot_variant_new_rect2,
39 | varianttype = VariantType.Rect2,
40 |
41 | --- Returns the area of the Rect2.
42 | -- @function get_area
43 | -- @treturn number
44 | get_area = api.godot_rect2_get_area,
45 | --- Returns `true` if the Rect2 overlaps with `b`. (i.e. they have at least one point in common).
46 | -- @function intersects
47 | -- @tparam Rect2 b
48 | -- @param[opt=false] include_borders If `true`, they will also be considered overlapping if their borders touch, even without intersection.
49 | -- @treturn bool
50 | intersects = function(self, b, include_borders)
51 | return api.godot_rect2_intersects(self, b, include_borders or false)
52 | end,
53 | --- Returns `true` if this Rect2 completely encloses another one.
54 | -- @function encloses
55 | -- @tparam Rect2 b
56 | -- @treturn bool
57 | encloses = api.godot_rect2_encloses,
58 | --- Returns `true` if the Rect2 is flat or empty.
59 | -- @function has_no_area
60 | -- @treturn bool
61 | has_no_area = api.godot_rect2_has_no_area,
62 | --- Returns the intersection of this Rect2 and `b`.
63 | -- @function clip
64 | -- @tparam Rect2 b
65 | -- @treturn Rect2
66 | clip = api.godot_rect2_clip,
67 | --- Returns a larger Rect2 that contains this Rect2 and `b`.
68 | -- @function merge
69 | -- @tparam Rect2 b
70 | -- @treturn Rect2
71 | merge = api.godot_rect2_merge,
72 | --- Returns `true` if the Rect2 contains a point.
73 | -- @function has_point
74 | -- @tparam Vector2 point
75 | -- @treturn bool
76 | has_point = api.godot_rect2_has_point,
77 | --- Returns a copy of the Rect2 grown a given `amount` of units towards all the sides.
78 | -- @function grow
79 | -- @tparam number amount
80 | -- @treturn Rect2
81 | grow = api.godot_rect2_grow,
82 | --- Returns this Rect2 expanded to include a given point.
83 | -- @function expand
84 | -- @tparam Vector2 point
85 | -- @treturn Rect2
86 | expand = api.godot_rect2_expand,
87 | }
88 |
89 | --- Returns all elements.
90 | -- @function unpack
91 | -- @treturn number X
92 | -- @treturn number Y
93 | -- @treturn number width
94 | -- @treturn number height
95 | methods.unpack = function(self)
96 | return self.x, self.y, self.width, self.height
97 | end
98 |
99 | if api_1_1 then
100 | --- Returns a copy of the Rect2 grown a given amount of units towards each direction individually.
101 | -- @function grow_individual
102 | -- @tparam number left
103 | -- @tparam number top
104 | -- @tparam number right
105 | -- @tparam number bottom
106 | -- @treturn Rect2
107 | methods.grow_individual = api_1_1.godot_rect2_grow_individual
108 | --- Returns a copy of the Rect2 grown a given amount of units towards the Margin direction.
109 | -- @function grow_margin
110 | -- @tparam int margin
111 | -- @tparam number amount
112 | -- @treturn Rect2
113 | methods.grow_margin = api_1_1.godot_rect2_grow_margin
114 | --- Returns a Rect2 with equivalent position and area, modified so that the top-left corner is the origin and `width` and `height` are positive.
115 | -- @function abs
116 | -- @treturn Rect2
117 | methods.abs = api_1_1.godot_rect2_abs
118 | end
119 |
120 | Rect2 = ffi_metatype('godot_rect2', {
121 | --- Rect2 constructor, called by the idiom `Rect2(...)`.
122 | --
123 | -- * `Rect2()`: all zeros (`Rect2() == Rect2(0, 0, 0, 0)`)
124 | -- * `Rect2(number x, number y, number width, number height)`: set XY and width/height
125 | -- * `Rect2(Vector2 position, Vector2 size)`: set position and size
126 | -- * `Rect2(Rect2 other)`: copy values from `other`
127 | -- @function __new
128 | -- @param ...
129 | -- @treturn Rect2
130 | __new = function(mt, x, y, width, height)
131 | if ffi_istype(mt, x) then
132 | return ffi_new(mt, x)
133 | elseif ffi_istype(Vector2, x) then
134 | -- (Vector2, Vector2)
135 | if ffi_istype(Vector2, y) then
136 | x, y, width, height = x.x, x.y, y.x, y.y
137 | -- (Vector2, float?, float?)
138 | else
139 | x, y, width, height = x.x, x.y, y, width
140 | end
141 | -- (float, float, Vector2)
142 | elseif ffi_istype(Vector2, width) then
143 | x, y, width, height = x, y, width.x, width.y
144 | end
145 | return ffi_new(mt, { x = x, y = y, width = width, height = height })
146 | end,
147 | __index = methods,
148 | --- Returns a Lua string representation of this rect.
149 | -- @function __tostring
150 | -- @treturn string
151 | __tostring = gd_tostring,
152 | --- Concatenates values.
153 | -- @function __concat
154 | -- @param a First value, stringified with `GD.str`
155 | -- @param b First value, stringified with `GD.str`
156 | -- @treturn String
157 | __concat = concat_gdvalues,
158 | --- Equality operation
159 | -- @function __eq
160 | -- @tparam Rect2 a
161 | -- @tparam Rect2 b
162 | -- @treturn bool
163 | __eq = function(a, b)
164 | return a.x == b.x and a.y == b.y and a.width == b.width and a.height == b.height
165 | end,
166 | })
167 |
168 |
169 |
--------------------------------------------------------------------------------
/src/godot_rid.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_rid.lua Wrapper for GDNative's RID
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- RID metatype, wrapper for `godot_rid`.
25 | -- Construct using the idiom `RID(from)`, which calls `__new`.
26 | -- @classmod RID
27 |
28 | local methods = {
29 | fillvariant = api.godot_variant_new_rid,
30 | varianttype = VariantType.RID,
31 |
32 | --- Returns the ID of the referenced resource.
33 | -- @function get_id
34 | -- @treturn int
35 | get_id = api.godot_rid_get_id,
36 | }
37 | RID = ffi_metatype('godot_rid', {
38 | --- RID constructor, called by the idiom `RID(from)`.
39 | -- @function __new
40 | -- @param[opt] from
41 | -- @treturn RID
42 | __new = function(mt, from)
43 | local self = ffi_new(mt)
44 | if from then
45 | api.godot_rid_new_with_resource(self, from)
46 | else
47 | api.godot_rid_new(self)
48 | end
49 | return self
50 | end,
51 | __index = methods,
52 | --- Returns a Lua string representation of this RID.
53 | -- @function __tostring
54 | -- @treturn string
55 | __tostring = gd_tostring,
56 | --- Concatenates values.
57 | -- @function __concat
58 | -- @param a First value, stringified with `GD.str`
59 | -- @param b First value, stringified with `GD.str`
60 | -- @treturn String
61 | __concat = concat_gdvalues,
62 | --- Equality comparison (`a == b`).
63 | -- If either `a` or `b` are not RIDs, always return `false`.
64 | -- @function __eq
65 | -- @param a
66 | -- @param b
67 | -- @treturn bool
68 | __eq = function(a, b)
69 | return ffi_istype(RID, a) and ffi_istype(RID, b) and api.godot_rid_operator_equal(a, b)
70 | end,
71 | --- Less than comparison (`a < b`).
72 | -- @function __lt
73 | -- @param a
74 | -- @param b
75 | -- @treturn bool
76 | __lt = api.godot_rid_operator_less,
77 | })
78 |
79 |
--------------------------------------------------------------------------------
/src/godot_string_name.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_string_name.lua Wrapper for GDNative's StringName
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- StringName metatype, wrapper for `godot_string_name`.
25 | -- Construct using the idiom `StringName(name)`, which calls `__new`.
26 | -- @classmod StringName
27 |
28 | local methods = {
29 | fillvariant = function(var, self)
30 | api.godot_variant_new_string(var, self:get_name())
31 | end,
32 | varianttype = VariantType.String,
33 |
34 | --- Returns this StringName as a `String`.
35 | -- @function get_name
36 | -- @treturn String
37 | get_name = function(self)
38 | return ffi_gc(api.godot_string_name_get_name(self), api.godot_string_destroy)
39 | end,
40 | --- Returns this StringName's 32-bit hash value.
41 | -- @function get_hash
42 | -- @treturn uint32_t
43 | get_hash = api.godot_string_name_get_hash,
44 | --- Returns this StringName's data pointer (`const void *`)
45 | -- @function get_data_unique_pointer
46 | -- @return[type=const void *]
47 | get_data_unique_pointer = api.godot_string_name_get_data_unique_pointer,
48 | }
49 | StringName = ffi_metatype('godot_string_name', {
50 | --- StringName constructor, called by the idiom `StringName(name)`.
51 | -- @function __new
52 | -- @param[opt=""] name Name, stringified with `GD.str`
53 | -- @treturn StringName
54 | __new = function(mt, name)
55 | local self = ffi_new(mt)
56 | api.godot_string_name_new(self, str(name or ''))
57 | return self
58 | end,
59 | __gc = api.godot_string_name_destroy,
60 | --- Returns a Lua string representation of this StringName.
61 | -- @function __tostring
62 | -- @treturn string
63 | -- @see get_name
64 | __tostring = function(self)
65 | return tostring(self:get_name())
66 | end,
67 | --- Return this StringName's amount of characters.
68 | -- @function __len
69 | -- @treturn int
70 | __len = function(self)
71 | return #self:get_name()
72 | end,
73 | __index = methods,
74 | --- Concatenates values.
75 | -- @function __concat
76 | -- @param a First value, stringified with `GD.str`
77 | -- @param b First value, stringified with `GD.str`
78 | -- @treturn String
79 | __concat = concat_gdvalues,
80 | })
81 |
--------------------------------------------------------------------------------
/src/godot_transform.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_transform.lua Wrapper for GDNative's Transform
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Transform metatype, wrapper for `godot_transform`.
25 | -- Constructed using the idiom `Transform(...)`, which calls `__new`.
26 | -- typedef union godot_transform {
27 | -- uint8_t data[48];
28 | -- float elements[12];
29 | -- struct { Basis basis; Vector3 origin; };
30 | -- } godot_transform;
31 | -- @classmod Transform
32 |
33 | local methods = {
34 | fillvariant = api.godot_variant_new_transform,
35 | varianttype = VariantType.Transform,
36 |
37 | --- Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use `affine_inverse` for transforms with scaling).
38 | -- @function inverse
39 | -- @treturn Transform
40 | inverse = api.godot_transform_inverse,
41 | --- Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.
42 | -- @function affine_inverse
43 | -- @treturn Transform
44 | affine_inverse = api.godot_transform_affine_inverse,
45 | --- Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors.
46 | -- @function orthonormalized
47 | -- @treturn Transform
48 | orthonormalized = api.godot_transform_orthonormalized,
49 | --- Rotates the transform around the given `axis` by the given `angle` (in radians), using matrix multiplication.
50 | -- The axis must be a normalized vector.
51 | -- @function rotated
52 | -- @tparam Vector3 axis
53 | -- @tparam number angle
54 | -- @treturn Transform
55 | rotated = api.godot_transform_rotated,
56 | --- Scales basis and origin of the transform by the given `scale` factor, using matrix multiplication.
57 | -- @function scaled
58 | -- @tparam Vector3 scale
59 | -- @treturn Transform
60 | scaled = api.godot_transform_scaled,
61 | --- Translates the transform by the given `offset`, relative to the transform's basis vectors.
62 | -- Unlike rotated and scaled, this does not use matrix multiplication.
63 | -- @function treturn
64 | -- @tparam Vector3 offset
65 | -- @treturn Transform
66 | translated = api.godot_transform_translated,
67 | --- Returns a copy of the transform rotated such that its -Z axis points towards the `target` position.
68 | -- The transform will first be rotated around the given up vector, and then fully aligned to the `target` by a further rotation around an axis perpendicular to both the `target` and `up` vectors.
69 | -- Operations take place in global space.
70 | -- @function looking_at
71 | -- @tparam Vector3 target
72 | -- @tparam Vector3 up
73 | -- @treturn Transform
74 | looking_at = api.godot_transform_looking_at,
75 | --- Transforms the given Plane
76 | -- @function xform_plane
77 | -- @tparam Plane plane
78 | -- @treturn Plane
79 | -- @see xform
80 | xform_plane = api.godot_transform_xform_plane,
81 | --- Inverse-transforms the given Plane
82 | -- @function xform_inv_plane
83 | -- @tparam Plane plane
84 | -- @treturn Plane
85 | -- @see xform
86 | xform_inv_plane = api.godot_transform_xform_inv_plane,
87 | --- Transforms the given Vector3
88 | -- @function xform_vector3
89 | -- @tparam Vector3 vector
90 | -- @treturn Vector3
91 | -- @see xform
92 | xform_vector3 = api.godot_transform_xform_vector3,
93 | --- Inverse-transforms the given Vector3
94 | -- @function xform_inv_vector3
95 | -- @tparam Vector3 vector
96 | -- @treturn Vector3
97 | -- @see xform
98 | xform_inv_vector3 = api.godot_transform_xform_inv_vector3,
99 | --- Transforms the given AABB
100 | -- @function xform_aabb
101 | -- @tparam AABB aabb
102 | -- @treturn AABB
103 | -- @see xform
104 | xform_aabb = api.godot_transform_xform_aabb,
105 | --- Inverse-transforms the given AABB
106 | -- @function xform_inv_aabb
107 | -- @tparam AABB aabb
108 | -- @treturn AABB
109 | -- @see xform
110 | xform_inv_aabb = api.godot_transform_xform_inv_aabb,
111 | --- Transforms the given `Vector3`, `Plane`, `AABB`, or `PoolVector3Array` by this transform.
112 | -- @function xform
113 | -- @tparam Vector3|Plane|AABB|PoolVector3Array value
114 | -- @treturn Vector3|Plane|AABB|PoolVector3Array Transformed value
115 | xform = function(self, value)
116 | if ffi_istype(Vector3, value) then
117 | return self:xform_vector3(value)
118 | elseif ffi_istype(Plane, value) then
119 | return self:xform_plane(value)
120 | elseif ffi_istype(AABB, value) then
121 | return self:xform_aabb(value)
122 | elseif ffi_istype(PoolVector3Array, value) then
123 | local array = PoolVector3Array()
124 | array:resize(#value)
125 | for i, v in ipairs(value) do
126 | array:set(i, self:xform_vector3(v))
127 | end
128 | return array
129 | end
130 | end,
131 | --- Inverse-transforms the given `Vector3`, `Plane`, `AABB`, or `PoolVector3Array` by this transform.
132 | -- @function xform_inv
133 | -- @tparam Vector3|Plane|AABB|PoolVector3Array value
134 | -- @treturn Vector3|Plane|AABB|PoolVector3Array Transformed value
135 | xform_inv = function(self, value)
136 | if ffi_istype(Vector3, value) then
137 | return self:xform_inv_vector3(value)
138 | elseif ffi_istype(Plane, value) then
139 | return self:xform_inv_plane(value)
140 | elseif ffi_istype(AABB, value) then
141 | return self:xform_inv_aabb(value)
142 | elseif ffi_istype(PoolVector3Array, value) then
143 | local array = PoolVector3Array()
144 | array:resize(#value)
145 | for i, v in ipairs(value) do
146 | array:set(i, self:xform_inv_vector3(v))
147 | end
148 | return array
149 | end
150 | end,
151 | }
152 |
153 | --- Constants
154 | -- @section constants
155 |
156 | --- Transform with no translation, rotation or scaling applied.
157 | -- @field IDENTITY Transform(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
158 |
159 | --- Transform with mirroring applied perpendicular to the YZ plane.
160 | -- @field FLIP_X Transform(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
161 |
162 | --- Transform with mirroring applied perpendicular to the XZ plane.
163 | -- @field FLIP_Y Transform(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0)
164 |
165 | --- Transform with mirroring applied perpendicular to the XY plane.
166 | -- @field FLIP_Z Transform(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0)
167 |
168 | --- @section end
169 |
170 | methods.IDENTITY = ffi_new('godot_transform', { elements = { 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 } })
171 | methods.FLIP_X = ffi_new('godot_transform', { elements = { -1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 } })
172 | methods.FLIP_Y = ffi_new('godot_transform', { elements = { 1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0 } })
173 | methods.FLIP_Z = ffi_new('godot_transform', { elements = { 1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0 } })
174 |
175 | --- Metamethods
176 | -- @section metamethods
177 | Transform = ffi_metatype('godot_transform', {
178 | --- Transform constructor, called by the idiom `Transform(...)`.
179 | --
180 | -- * `Transform()`: `IDENTITY` transform
181 | -- * `Transform(Basis basis[, Vector3 origin = Vector3.ZERO])`: set `basis` and `origin`
182 | -- * `Transform(Quat quat[, Vector3 origin = Vector3.ZERO])`: set `basis` from quaternion and `origin`
183 | -- * `Transform(Vector3 euler[, Vector3 origin = Vector3.ZERO])`: set `basis` from Euler angles and `origin`
184 | -- * `Transform(Vector3 x, Vector3 y, Vector3 z, Vector3 origin)`: constructs the transform from the four column vectors.
185 | -- * `Transform(Transform other)`: returns a copy of `other`
186 | -- @function __new
187 | -- @param ...
188 | -- @treturn Transform
189 | __new = function(mt, x, y, z, origin)
190 | if ffi_istype(mt, x) then
191 | return ffi_new(mt, x)
192 | end
193 | if not x then
194 | return ffi_new(mt, mt.IDENTITY)
195 | elseif ffi_istype(Vector3, x) then
196 | local self = ffi_new(mt)
197 | api.godot_transform_new_with_axis_origin(self, x, y, z, origin)
198 | return self
199 | else
200 | return ffi_new(mt, { basis = Basis(x), origin = y })
201 | end
202 | end,
203 | __index = methods,
204 | --- Returns a Lua string representation of this transform.
205 | -- @function __tostring
206 | -- @treturn string
207 | __tostring = gd_tostring,
208 | --- Concatenates values.
209 | -- @function __concat
210 | -- @param a First value, stringified with `GD.str`
211 | -- @param b First value, stringified with `GD.str`
212 | -- @treturn String
213 | __concat = concat_gdvalues,
214 | --- Multiplication operation.
215 | -- Either multiply another Transform or `xform` value.
216 | -- @tparam Transform self
217 | -- @tparam Transform|Vector3|Plane|AABB|PoolVector3Array b
218 | -- @treturn Transform|Vector3|Plane|AABB|PoolVector3Array Transformed value
219 | __mul = function(self, b)
220 | if ffi_istype(Transform, b) then
221 | return api.godot_transform_operator_multiply(self, b)
222 | else
223 | return self:xform(b)
224 | end
225 | end,
226 | --- Equality operation
227 | -- If either `a` or `b` are not of type `Transform`, always return `false`.
228 | -- @function __eq
229 | -- @tparam Transform a
230 | -- @tparam Transform b
231 | -- @treturn bool
232 | __eq = function(a, b)
233 | return ffi_istype(Transform, a) and ffi_istype(Transform, b) and a.basis == b.basis and a.origin == b.origin
234 | end,
235 | })
236 |
--------------------------------------------------------------------------------
/src/godot_transform2d.lua:
--------------------------------------------------------------------------------
1 | -- @file godot_transform2d.lua Wrapper for GDNative's Transform2D
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Transform2D metatype, wrapper for `godot_transform2d`.
25 | -- Constructed using the idiom `Transform2D(...)`, which calls `__new`.
26 | -- typedef union godot_transform2d {
27 | -- uint8_t data[24];
28 | -- float elements[6];
29 | -- Vector2 columns[3];
30 | -- struct { Vector2 x, y, origin; };
31 | -- } godot_transform2d;
32 | -- @classmod Transform2D
33 |
34 | local methods = {
35 | fillvariant = api.godot_variant_new_transform2d,
36 | varianttype = VariantType.Transform2D,
37 |
38 | --- Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use `affine_inverse` for transforms with scaling).
39 | -- @function inverse
40 | -- @treturn Transform2D
41 | -- @see affine_inverse
42 | inverse = api.godot_transform2d_inverse,
43 | --- Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.
44 | -- @function affine_inverse
45 | -- @treturn Transform2D
46 | affine_inverse = api.godot_transform2d_affine_inverse,
47 | --- Returns the transform's rotation (in radians).
48 | -- @function get_rotation
49 | -- @treturn number
50 | get_rotation = api.godot_transform2d_get_rotation,
51 | --- Returns the transform's origin (translation).
52 | -- @function get_origin
53 | -- @treturn Vector2
54 | get_origin = api.godot_transform2d_get_origin,
55 | --- Returns the scale.
56 | -- @function get_scale
57 | -- @treturn Vector2
58 | get_scale = api.godot_transform2d_get_scale,
59 | --- Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors (scale of 1 or -1).
60 | -- @function orthonormalized
61 | -- @treturn Transform2D
62 | orthonormalized = api.godot_transform2d_orthonormalized,
63 | --- Rotates the transform by the given `angle` (in radians), using matrix multiplication.
64 | -- @function rotated
65 | -- @tparam number angle
66 | -- @treturn Transform2D
67 | rotated = api.godot_transform2d_rotated,
68 | --- Scales the transform by the given `scale` factor, using matrix multiplication.
69 | -- @function scaled
70 | -- @tparam Vector2 scale
71 | -- @treturn Transform2D
72 | scaled = api.godot_transform2d_scaled,
73 | --- Translates the transform by the given `offset`, relative to the transform's basis vectors.
74 | -- Unlike rotated and scaled, this does not use matrix multiplication.
75 | -- @function translated
76 | -- @tparam Vector2 offset
77 | -- @treturn Transform2D
78 | translated = api.godot_transform2d_translated,
79 | --- Transforms the given Vector2.
80 | -- @function xform_vector2
81 | -- @tparam Vector2 vector
82 | -- @treturn Vector2
83 | -- @see xform
84 | xform_vector2 = api.godot_transform2d_xform_vector2,
85 | --- Inverse-transforms the given Vector2.
86 | -- @function xform_inv_vector2
87 | -- @tparam Vector2 vector
88 | -- @treturn Vector2
89 | -- @see xform_inv
90 | xform_inv_vector2 = api.godot_transform2d_xform_inv_vector2,
91 | --- Returns a vector transformed (multiplied) by the basis matrix.
92 | -- This method does not account for translation (the origin vector).
93 | -- @function basis_xform_vector2
94 | -- @tparam Vector2 vector
95 | -- @treturn Vector2
96 | basis_xform = api.godot_transform2d_basis_xform_vector2,
97 | --- Returns a vector transformed (multiplied) by the inverse basis matrix.
98 | -- This method does not account for translation (the origin vector).
99 | -- @function basis_xform_inv
100 | -- @tparam Vector2 vector
101 | -- @treturn Vector2
102 | basis_xform_inv = api.godot_transform2d_basis_xform_inv_vector2,
103 | --- Returns a transform interpolated between this transform and another by a given `weight` (on the range of 0.0 to 1.0).
104 | -- @function interpolate_with
105 | -- @tparam Transform2D transform
106 | -- @tparam number weight
107 | interpolate_with = api.godot_transform2d_interpolate_with,
108 | --- Transforms the given Rect2.
109 | -- @function xform_rect2
110 | -- @tparam Rect2 vector
111 | -- @treturn Rect2
112 | -- @see xform
113 | xform_rect2 = api.godot_transform2d_xform_rect2,
114 | --- Inverse-transforms the given Rect2.
115 | -- @function xform_inv_rect2
116 | -- @tparam Rect2 vector
117 | -- @treturn Rect2
118 | -- @see xform_inv
119 | xform_inv_rect2 = api.godot_transform2d_xform_inv_rect2,
120 | --- Transforms the given `Vector2`, `Rect2`, or `PoolVector2Array` by this transform.
121 | -- @function xform
122 | -- @tparam Vector2|Rect2|PoolVector2Array value
123 | -- @treturn Vector2|Rect2|PoolVector2Array Transformed value
124 | xform = function(self, value)
125 | if ffi_istype(Vector2, value) then
126 | return self:xform_vector2(value)
127 | elseif ffi_istype(Rect2, value) then
128 | return self:xform_rect2(value)
129 | elseif ffi_istype(PoolVector2Array, value) then
130 | local array = PoolVector2Array()
131 | array:resize(#value)
132 | for i, v in ipairs(value) do
133 | array:set(i, self:xform_vector2(v))
134 | end
135 | return array
136 | end
137 | end,
138 | --- Inverse-transforms the given `Vector2`, `Rect2`, or `PoolVector2Array` by this transform.
139 | -- @function xform_inv
140 | -- @tparam Vector2|Rect2|PoolVector2Array value
141 | -- @treturn Vector2|Rect2|PoolVector2Array Transformed value
142 | xform_inv = function(self, value)
143 | if ffi_istype(Vector2, value) then
144 | return self:xform_inv_vector2(value)
145 | elseif ffi_istype(Rect2, value) then
146 | return self:xform_inv_rect2(value)
147 | elseif ffi_istype(PoolVector2Array, value) then
148 | local array = PoolVector2Array()
149 | array:resize(#value)
150 | for i, v in ipairs(value) do
151 | array:set(i, self:xform_inv_vector2(v))
152 | end
153 | return array
154 | end
155 | end,
156 | }
157 |
158 | --- Constants
159 | -- @section constants
160 |
161 | --- The identity Transform2D with no translation, rotation or scaling applied.
162 | -- @field IDENTITY Transform2D(1, 0, 0, 1, 0, 0)
163 |
164 | --- The Transform2D that will flip something along the X axis.
165 | -- @field FLIP_X Transform2D(-1, 0, 0, 1, 0, 0)
166 |
167 | --- The Transform2D that will flip something along the Y axis.
168 | -- @field FLIP_Y Transform2D(1, 0, 0, -1, 0, 0)
169 |
170 | --- @section end
171 |
172 | methods.IDENTITY = ffi_new('godot_transform2d', { elements = { 1, 0, 0, 1, 0, 0 } })
173 | methods.FLIP_X = ffi_new('godot_transform2d', { elements = { -1, 0, 0, 1, 0, 0 } })
174 | methods.FLIP_Y = ffi_new('godot_transform2d', { elements = { 1, 0, 0, -1, 0, 0 } })
175 |
176 | --- Metamethods
177 | -- @section metamethods
178 | Transform2D = ffi_metatype('godot_transform2d', {
179 | --- Transform2D constructor, called by the idiom `Transform2D(...)`.
180 | --
181 | -- * `Transform2D()`: creates an `IDENTITY` transform.
182 | -- * `Transform2D(number angle, Vector2 position)`: constructs the transform from a given angle (in radians) and position.
183 | -- * `Transform2D(Vector2 x, Vector2 y, Vector2 origin)`: constructs the transform from the three column vectors.
184 | -- * `Transform2D(Transform2D other)`: returns a copy of `other`
185 | -- @function __new
186 | -- @param ...
187 | -- @treturn Transform2D
188 | __new = function(mt, x, y, origin)
189 | if ffi_istype(mt, x) then
190 | return ffi_new(mt, x)
191 | end
192 | local self = ffi_new(mt)
193 | if not x then
194 | api.godot_transform2d_new_identity(self)
195 | elseif tonumber(x) then
196 | api.godot_transform2d_new(self, x, y)
197 | else
198 | api.godot_transform2d_new_axis_origin(self, x, y, origin)
199 | end
200 | return self
201 | end,
202 | __index = methods,
203 | --- Returns a Lua string representation of this transform.
204 | -- @function __tostring
205 | -- @treturn string
206 | __tostring = gd_tostring,
207 | --- Concatenates values.
208 | -- @function __concat
209 | -- @param a First value, stringified with `GD.str`
210 | -- @param b First value, stringified with `GD.str`
211 | -- @treturn String
212 | __concat = concat_gdvalues,
213 | --- Multiplication operation.
214 | -- Either multiply another Transform2D or `xform` value.
215 | -- @tparam Transform2D self
216 | -- @tparam Transform2D|Vector2|Rect2|PoolVector2Array b
217 | -- @treturn Transform2D|Vector2|Rect2|PoolVector2Array Transformed value
218 | __mul = function(self, b)
219 | if ffi_istype(Transform2D, b) then
220 | return api.godot_transform2d_operator_multiply(self, b)
221 | else
222 | return self:xform(b)
223 | end
224 | end,
225 | --- Equality operation
226 | -- If either `a` or `b` are not of type `Transform2D`, always return `false`.
227 | -- @function __eq
228 | -- @tparam Transform2D a
229 | -- @tparam Transform2D b
230 | -- @treturn bool
231 | __eq = function(a, b)
232 | return ffi_istype(Transform2D, a) and ffi_istype(Transform2D, b) and a.elements[0] == b.elements[0] and a.elements[1] == b.elements[1] and a.elements[2] == b.elements[2]
233 | end,
234 | })
235 |
236 |
237 |
--------------------------------------------------------------------------------
/src/late_globals.lua:
--------------------------------------------------------------------------------
1 | -- @file late_globals.lua GD table and _G metatable
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Godot enumerations and functions, available globally as the `GD` table.
25 | -- Godot global constants from `godot_get_global_constants` are also available,
26 | -- like `OK`, `ERR_ALREADY_EXISTS`, `TYPE_NIL`, `KEY_A`, `BUTTON_LEFT`,
27 | -- `JOY_START`, `HALIGN_CENTER` and `MIDI_MESSAGE_NOTE_OFF`.
28 | -- @module GD
29 |
30 | GD = {
31 | --- (`const godot_gdnative_core_api_struct *`) GDNative core API 1.0
32 | api = api,
33 | --- (`const godot_gdnative_core_1_1_api_struct *`) GDNative core API 1.1
34 | api_1_1 = api_1_1,
35 | --- (`const godot_gdnative_core_1_2_api_struct *`) GDNative core API 1.2
36 | api_1_2 = api_1_2,
37 | --- (`Object`) [GDNativeLibrary](https://docs.godotengine.org/en/stable/classes/class_gdnativelibrary.html) instance
38 | gdnativelibrary = gdnativelibrary,
39 | --- `Enumerations.Error`
40 | Error = Error,
41 | --- `Enumerations.VariantType`
42 | VariantType = VariantType,
43 | --- `Enumerations.CallError`
44 | CallError = CallError,
45 | --- `Enumerations.RPCMode`
46 | RPCMode = RPCMode,
47 | --- `Enumerations.PropertyHint`
48 | PropertyHint = PropertyHint,
49 | --- `Enumerations.PropertyUsage`
50 | PropertyUsage = PropertyUsage,
51 | --- Project version: 0.5.2
52 | _VERSION = '0.5.2',
53 | }
54 |
55 | local global_constants = api.godot_get_global_constants()
56 | for k, v in pairs(global_constants) do
57 | GD[k:to_ascii()] = v
58 | end
59 | api.godot_dictionary_destroy(global_constants)
60 |
61 | --- Convert any value to a `godot_string`.
62 | -- If `value` is already a `godot_string`, return it unmodified.
63 | -- Otherwise, constructs a Variant and calls `as_string` on it.
64 | -- @function GD.str
65 | -- @param value Value to be stringified
66 | -- @treturn String
67 | GD.str = str
68 |
69 | --- Returns the Lua script instance associated with an `Object`, if it
70 | -- has a Lua Script attached.
71 | -- @function GD.get_lua_instance
72 | -- @tparam Object object
73 | -- @treturn[1] LuaScriptInstance
74 | -- @treturn[2] nil If Object has no Lua Script attached
75 | GD.get_lua_instance = get_lua_instance
76 |
77 | --- Print a message to Godot's Output panel, with values separated by tabs
78 | function GD.print(...)
79 | local message = String(string_join('\t', ...))
80 | api.godot_print(message)
81 | end
82 | _G.print = GD.print
83 |
84 | --- Print a warning to Godot's Output panel, with values separated by tabs
85 | function GD.print_warning(...)
86 | local info = debug_getinfo(2, 'nSl')
87 | local message = string_join('\t', ...)
88 | api.godot_print_warning(message, info.name, info.short_src, info.currentline)
89 | end
90 |
91 | --- Print an error to Godot's Output panel, with values separated by tabs
92 | function GD.print_error(...)
93 | local info = debug_getinfo(2, 'nSl')
94 | local message = string_join('\t', ...)
95 | api.godot_print_error(message, info.name, info.short_src, info.currentline)
96 | end
97 |
98 | local ResourceLoader = api.godot_global_get_singleton("ResourceLoader")
99 | --- Loads a Resource by path, similar to GDScript's [load](https://docs.godotengine.org/en/stable/classes/class_%40gdscript.html#class-gdscript-method-load)
100 | function GD.load(path)
101 | return ResourceLoader:load(path)
102 | end
103 |
104 |
105 | --- Yield the current running Lua thread, returning a wrapper Object with the `lps_coroutine.lua` script attached.
106 | -- If an `object` and `signal_name` are passed, this coroutine will resume automatically when object emits the signal.
107 | -- If the same coroutine yields more than once, the same object will be returned.
108 | -- This is similar to GDScript's [yield](https://docs.godotengine.org/en/stable/classes/class_%40gdscript.html#class-gdscript-method-yield).
109 | -- @usage
110 | -- -- self is a Node
111 | -- GD.yield(self:get_tree():create_timer(2), "timeout")
112 | -- print('2 seconds have passed!')
113 | -- @tparam[opt] Object object
114 | -- @tparam[opt] string|String|StringName signal_name
115 | -- @return Value passed to coroutine object's `resume` call, if any
116 | -- @see lps_coroutine.lua
117 | function GD.yield(object, signal_name)
118 | local co, is_main = coroutine_running()
119 | assert(co and not is_main, "GD.yield can be called only from script methods")
120 | local co_obj = get_script_instance_for_lua_object(co)
121 | if object and signal_name then
122 | object:connect(signal_name, co_obj, "resume", Array(), Object.CONNECT_ONESHOT)
123 | end
124 | return coroutine_yield(co_obj)
125 | end
126 |
127 | local Engine = api.godot_global_get_singleton("Engine")
128 | setmetatable(_G, {
129 | __index = function(self, key)
130 | local gd_key = String(key)
131 | if Engine:has_singleton(gd_key) then
132 | local singleton = api.godot_global_get_singleton(key)
133 | rawset(self, key, singleton)
134 | return singleton
135 | end
136 | local cls = ClassWrapper_cache[key]
137 | if cls then
138 | rawset(self, key, cls)
139 | return cls
140 | end
141 | end,
142 | })
143 |
144 | -- References are already got, just register them globally
145 | _G.Engine = Engine
146 | _G.ClassDB = ClassDB
147 | _G.ResourceLoader = ResourceLoader
148 | -- These classes are registered with a prepending "_" in ClassDB
149 | File = ClassWrapper_cache._File
150 | Directory = ClassWrapper_cache._Directory
151 | Thread = ClassWrapper_cache._Thread
152 | Mutex = ClassWrapper_cache._Mutex
153 | Semaphore = ClassWrapper_cache._Semaphore
154 |
--------------------------------------------------------------------------------
/src/lua_globals.lua:
--------------------------------------------------------------------------------
1 | -- @file lua_globals.lua Extra global Lua functions and basic types
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Extra global Lua functions and basic types
25 | -- @module Globals
26 |
27 | --- Return `value` converted to light userdata with the return of `lua_topointer`
28 | -- @function touserdata
29 | -- @param value Value to be converted
30 | -- @return Light userdata
31 |
32 | --- Create or reuse a Lua thread (coroutine) with the given function/callable object
33 | -- @warning Errorred threads cannot be reused
34 | -- @function setthreadfunc
35 | -- @tparam thread|nil thread Thread to be reused. Pass `nil` to create a new one
36 | -- @tparam function|table|userdata f Function or other callable
37 | -- @treturn thread Reused or created thread
38 |
39 | --- Alias for `GD.print`
40 | -- @function print
41 | -- @param ...
42 |
43 | --- Search for singleton objects with `Engine:has_singleton(key)` and classes with
44 | -- `ClassDB:class_exists(key)`.
45 | -- Cache any values found, to avoid future calls.
46 | -- Called when indexing the global table `_G` with a currently unknown key.
47 | -- @function _G:__index
48 | -- @param key
49 | -- @treturn[1] Object Singleton object, if `Engine:has_singleton(key)`
50 | -- @treturn[2] OOP.ClassWrapper Class wrapper, if `ClassDB:class_exists(key)`
51 | -- @treturn[3] nil
52 |
53 |
54 | --- Scalar types
55 | -- @section scalar_types
56 |
57 | --- Boolean type `godot_bool`
58 | bool = ffi_typeof('godot_bool')
59 | --- Integer type `godot_int`
60 | int = ffi_typeof('godot_int')
61 | --- Float type `godot_real`
62 | float = ffi_typeof('godot_real')
63 |
64 |
--------------------------------------------------------------------------------
/src/lua_math_extras.lua:
--------------------------------------------------------------------------------
1 | -- @file lua_math_extras.lua Extra functionality for the `math` library
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Extra functionality for Lua's `math` library.
25 | -- @module math_extras
26 |
27 | --- Returns the value `x` clamped between an upper (`max`) and lower bounds (`min`).
28 | -- Any values comparable by order, that is, with a less than operator, can be passed in.
29 | -- @tparam Vector2|Vector3|Color|number x
30 | -- @tparam Vector2|Vector3|Color|number min
31 | -- @tparam Vector2|Vector3|Color|number max
32 | -- @treturn Vector2|Vector3|Color|number
33 | function math.clamp(x, min, max)
34 | if x < min then
35 | return min
36 | elseif x > max then
37 | return max
38 | else
39 | return x
40 | end
41 | end
42 |
43 | --- Linearly interpolates values `from` and `to` by `amount`.
44 | -- Equivalent to `from + (amount * (to - from))`.
45 | -- @tparam Vector2|Vector3|Color|Quat|number from
46 | -- @tparam Vector2|Vector3|Color|Quat|number to
47 | -- @tparam number amount
48 | -- @treturn Vector2|Vector3|Color|Quat|number
49 | function math.lerp(from, to, amount)
50 | return from + (amount * (to - from))
51 | end
52 |
--------------------------------------------------------------------------------
/src/lua_object_struct.lua:
--------------------------------------------------------------------------------
1 | -- @file lua_object_struct.lua Helper struct for storing Lua references
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Internal struct to store references to Lua objects, like tables and coroutines.
25 | --
26 | -- References are stored in a global cache table, indexed by their own address,
27 | -- and are only unreferenced when `LuaObject_destroy` is called.
28 | -- Thus this struct must used with care.
29 | --
30 | -- This is used internally for having `LuaScript` and `LuaScriptInstance`
31 | -- be structs that reference tables.
32 | --
33 | -- typedef struct {
34 | -- void *__address;
35 | -- } lps_lua_object;
36 | --
37 | -- @module LuaObject
38 |
39 | ffi_cdef[[
40 | typedef struct {
41 | void *__address;
42 | } lps_lua_object;
43 | ]]
44 |
45 | local lps_lua_objects = {}
46 |
47 | --- Helper function to convert a `void *` to a table index.
48 | local function pointer_to_index(ptr)
49 | return tonumber(ffi_cast('uintptr_t', ptr))
50 | end
51 |
52 | --- Gets the Lua object referenced by a LuaObject
53 | local function LuaObject_get(self)
54 | return lps_lua_objects[pointer_to_index(self.__address)]
55 | end
56 |
57 | --- Sets the Lua object referenced by a LuaObject
58 | -- @tparam LuaObject self
59 | -- @param value
60 | local function LuaObject_set(self, value)
61 | lps_lua_objects[pointer_to_index(self.__address)] = value
62 | end
63 |
64 | --- Unreference the Lua object, removing it from cache.
65 | -- @see lps_lua_objects
66 | local function LuaObject_destroy(self)
67 | LuaObject_set(self, nil)
68 | end
69 |
70 | --- @type LuaObject
71 | local LuaObject = ffi_metatype('lps_lua_object', {
72 | --- Wrapped reference memory address
73 | -- @tfield void* __address
74 |
75 | --- LuaObject constructor, called by the idiom `LuaObject(obj)`.
76 | --
77 | -- This registers the object in the global cache table, indexed by its
78 | -- own address.
79 | -- @function __new
80 | -- @param obj Lua object
81 | -- @local
82 | __new = function(mt, obj)
83 | local self = ffi_new(mt, touserdata(obj))
84 | LuaObject_set(self, obj)
85 | return self
86 | end,
87 | --- Forwards indexing to referenced Lua object
88 | -- @function __index
89 | -- @param index
90 | -- @return value
91 | __index = function(self, index)
92 | return LuaObject_get(self)[index]
93 | end,
94 | --- Forwards indexing to referenced Lua object
95 | -- @function __newindex
96 | -- @param index
97 | -- @param value
98 | __newindex = function(self, index, value)
99 | LuaObject_get(self)[index] = value
100 | end,
101 | --- Forwards length operator to referenced Lua object
102 | -- @function __len
103 | -- @return Object length, if supported
104 | __len = function(self)
105 | return #LuaObject_get(self)
106 | end,
107 | --- Forwards `pairs` to referenced Lua object
108 | -- @function __pairs
109 | __pairs = function(self)
110 | return pairs(LuaObject_get(self))
111 | end,
112 | --- Forwards `ipairs` to referenced Lua object
113 | -- @function __ipairs
114 | __ipairs = function(self)
115 | return ipairs(LuaObject_get(self))
116 | end,
117 | --- Forwards call to referenced Lua object
118 | -- @function __call
119 | -- @param ...
120 | __call = function(self, ...)
121 | return LuaObject_get(self)(...)
122 | end,
123 | })
124 |
--------------------------------------------------------------------------------
/src/lua_object_wrapper.lua:
--------------------------------------------------------------------------------
1 | -- @file lua_object_wrapper.lua Script instances for lua objects
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Helper functions for wrapping a Lua Object in a Godot Object.
25 | -- Currently only coroutines are supported.
26 | -- @module lua_object_wrapper
27 | -- @local
28 |
29 | local library_resource_dir = gdnativelibrary.resource_path:get_base_dir()
30 |
31 | --- Global cache of Lua object wrappers
32 | local lps_lua_object_references = setmetatable({}, weak_kv)
33 |
34 | --- Get or create a Godot Object that wraps `lua_obj`.
35 | -- Currently only coroutines are supported.
36 | local function get_script_instance_for_lua_object(lua_obj)
37 | local ref = lps_lua_object_references[lua_obj]
38 | if ref ~= nil then
39 | return ref
40 | end
41 |
42 | local t = type(lua_obj)
43 | if t == 'thread' then
44 | lps_next_instance_data = lua_obj
45 | local godot_obj = GD.load(library_resource_dir:plus_file('lps_coroutine.lua')):new()
46 | lps_lua_object_references[lua_obj] = godot_obj
47 | return godot_obj
48 | else
49 | error(string_format('Lua object of type %q is not supported yet', t))
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/src/lua_package_extras.lua:
--------------------------------------------------------------------------------
1 | -- @file lua_package_extras.lua Extra functionality for the `package` library
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Extra functionality for Lua's `package` library.
25 | -- Patch the `package.loaders`/`package.searchers` to use `searchpath`,
26 | -- so that `require` can find files relative to the `res://` and
27 | -- executable folder.
28 | -- @module package_extras
29 |
30 | local ProjectSettings, OS = ProjectSettings, OS
31 | local execdir_repl =
32 | OS:has_feature("standalone")
33 | and OS:get_executable_path():get_base_dir()
34 | or ProjectSettings:globalize_path("res://")
35 | execdir_repl = tostring(execdir_repl:trim_suffix('/'))
36 |
37 | -- Supports "res://" and "user://" paths
38 | -- Replaces "!" for executable path on standalone builds or project path otherwise
39 | local function searchpath(name, path, sep, rep)
40 | sep = sep or '.'
41 | rep = rep or '/'
42 | if sep ~= '' then
43 | name = name:replace(sep, rep)
44 | end
45 | local notfound = {}
46 | local f = File:new()
47 | for template in path:gmatch('[^;]+') do
48 | local filename = template:replace('?', name):replace('!', execdir_repl)
49 | if f:open(filename, File.READ) == Error.OK then
50 | return filename, f
51 | else
52 | table_insert(notfound, string_format("\n\tno file %q", filename))
53 | end
54 | end
55 | return nil, table_concat(notfound)
56 | end
57 |
58 | local function lua_searcher(name)
59 | local filename, open_file_or_err = searchpath(name, package.path)
60 | if not filename then
61 | return open_file_or_err
62 | end
63 | local file_len = open_file_or_err:get_len()
64 | local contents = open_file_or_err:get_buffer(file_len):get_string()
65 | open_file_or_err:close()
66 | return assert(loadstring(contents, filename))
67 | end
68 |
69 | local function c_searcher(name, name_override)
70 | local filename, open_file_or_err = searchpath(name, package.cpath)
71 | if not filename then
72 | return open_file_or_err
73 | end
74 | filename = tostring(open_file_or_err:get_path_absolute())
75 | open_file_or_err:close()
76 | local func_suffix = (name_override or name):replace('.', '_')
77 | -- Split module name if a "-" is found
78 | local igmark = string_find(func_suffix, '-', 1, false)
79 | if igmark then
80 | local funcname = 'luaopen_' .. func_suffix:sub(1, igmark - 1)
81 | local f = package_loadlib(filename, funcname)
82 | if f then return f end
83 | func_suffix = func_suffix:sub(igmark + 1)
84 | end
85 | local f, err = package_loadlib(filename, 'luaopen_' .. func_suffix)
86 | return assert(f, string_format('error loading module %q from file %q:\n\t%s', name_override or name, filename, err))
87 | end
88 |
89 | local function c_root_searcher(name)
90 | local root_name = name:match('^([^.]+)%.')
91 | if not root_name then
92 | return nil
93 | end
94 | return c_searcher(root_name, name)
95 | end
96 |
97 | --- Searches for the given `name` in the given path.
98 | -- Similar to Lua 5.2+ [package.searchpath](https://www.lua.org/manual/5.2/manual.html#pdf-package.searchpath),
99 | -- but using Godot Files instead, so that paths like `res://` and `user://` are
100 | -- supported.
101 | --
102 | -- `!` characters in `path` templates are replaced by the directory of the game/app
103 | -- executable when running a standalone build (when `OS:has_feature("standalone")`)
104 | -- or by the project's resource path otherwise (`ProjectSettings:globalize_path("res://")`).
105 | -- @function package.searchpath
106 | -- @param name
107 | -- @param path
108 | -- @param[opt="."] separator
109 | -- @param[opt="/"] replacement
110 | -- @treturn[1] string Found file name
111 | -- @treturn[2] nil
112 | -- @treturn[2] string Error message
113 | function package.searchpath(...)
114 | local filename, open_file_or_err = searchpath(...)
115 | if not filename then
116 | return nil, open_file_or_err
117 | else
118 | open_file_or_err:close()
119 | return filename
120 | end
121 | end
122 |
123 | local searchers = package.searchers or package.loaders
124 | searchers[2] = lua_searcher
125 | searchers[3] = c_searcher
126 | searchers[4] = c_root_searcher
127 |
128 | local LUA_PATH_BEHAVIOR_SETTING = 'lua_pluginscript/package_path/behavior'
129 | local LUA_PATH_SETTING = 'lua_pluginscript/package_path/templates'
130 | local LUA_CPATH_BEHAVIOR_SETTING = 'lua_pluginscript/package_c_path/behavior'
131 | local LUA_CPATH_SETTING = 'lua_pluginscript/package_c_path/templates'
132 |
133 | local function add_project_setting(name, initial_value)
134 | if not ProjectSettings:has_setting(name) then
135 | ProjectSettings:set_setting(name, initial_value)
136 | end
137 | ProjectSettings:set_initial_value(name, initial_value)
138 | end
139 |
140 | local function add_project_setting_enum(name, enum_values)
141 | add_project_setting(name, 0)
142 | ProjectSettings:add_property_info {
143 | name = name,
144 | type = VariantType.Int,
145 | hint = PropertyHint.ENUM,
146 | hint_string = enum_values,
147 | }
148 | end
149 |
150 | add_project_setting_enum(LUA_PATH_BEHAVIOR_SETTING, 'Replace,Append,Prepend')
151 | add_project_setting(LUA_PATH_SETTING, PoolStringArray('res://?.lua', 'res://?/init.lua', 'res://addons/godot-lua-pluginscript/build/?.lua'))
152 | add_project_setting_enum(LUA_CPATH_BEHAVIOR_SETTING, 'Replace,Append,Prepend')
153 | add_project_setting(LUA_CPATH_SETTING, PoolStringArray('!/?.so', '!/loadall.so'))
154 | add_project_setting(LUA_CPATH_SETTING .. '.Windows', PoolStringArray('!/?.dll', '!/loadall.dll'))
155 |
156 | local lua_path = ProjectSettings:get_setting(LUA_PATH_SETTING)
157 | local lua_cpath = ProjectSettings:get_setting(LUA_CPATH_SETTING)
158 | local lua_path_behaviour = ProjectSettings:get_setting(LUA_PATH_BEHAVIOR_SETTING)
159 | local lua_cpath_behaviour = ProjectSettings:get_setting(LUA_CPATH_BEHAVIOR_SETTING)
160 |
161 | if lua_path_behaviour == 1 then
162 | lua_path:insert(0, package.path)
163 | elseif lua_path_behaviour == 2 then
164 | lua_path:append(package.path)
165 | end
166 |
167 | if lua_cpath_behaviour == 1 then
168 | lua_cpath:insert(0, package.cpath)
169 | elseif lua_cpath_behaviour == 2 then
170 | lua_cpath:append(package.cpath)
171 | end
172 |
173 | --- When Lua PluginScript is loaded, `package.path` is either replaced,
174 | -- appended or prepended by the paths in `lua_pluginscript/package_path/templates` project
175 | -- setting.
176 | --
177 | -- The chosen behavior depends on the `lua_pluginscript/package_path/behavior`
178 | -- project setting.
179 | --
180 | -- Default paths are `res://?.lua`, `res://?/init.lua` and 'res://addons/godot-lua-pluginscript/build/?.lua'.
181 | --
182 | -- @see searchpath
183 | package.path = lua_path:join(';')
184 |
185 | --- When Lua PluginScript is loaded, `package.cpath` is either replaced,
186 | -- appended or prepended by the paths in `lua_pluginscript/package_c_path/templates` project
187 | -- setting.
188 | --
189 | -- The chosen behavior depends on the `lua_pluginscript/package_c_path/behavior`
190 | -- project setting.
191 | --
192 | -- Default paths are `!/?.dll` and `!/loadall.dll` on Windows, `!/?.so` and `!/loadall.so` elsewhere.
193 | --
194 | -- @see searchpath
195 | package.cpath = lua_cpath:join(';')
196 |
197 | --- `dlopen`s the PluginScript library with `RTLD_LAZY | RTLD_GLOBAL`.
198 | -- This is necessary for loading Lua/C modules in POSIX systems.
199 | local function dlopen_self()
200 | ffi_cdef[[
201 | void *dlopen(const char *filename, int flags);
202 | int dlclose(void *handle);
203 | ]]
204 |
205 | local RTLD_LAZY = 0x00001
206 | local RTLD_GLOBAL = 0x00100
207 | local currentLibraryPath = tostring(gdnativelibrary:get_current_library_path():replace("res://", execdir_repl .. '/'))
208 | -- Maintain a reference to dlopened library while PluginScript is loaded
209 | -- When the Lua state closes, GC will kick in and the library will get dlclosed
210 | pluginscript_callbacks.__dlopened_self = ffi_gc(ffi.C.dlopen(currentLibraryPath, RTLD_LAZY + RTLD_GLOBAL), ffi.C.dlclose)
211 | end
212 |
213 | if Array("Android", "iOS", "OSX", "Server", "X11"):has(OS:get_name()) then
214 | xpcall(dlopen_self, GD.print_error)
215 | end
216 |
--------------------------------------------------------------------------------
/src/lua_string_extras.lua:
--------------------------------------------------------------------------------
1 | -- @file lua_string_extras.lua Extra functionality for the `string` library
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Extra functionality for Lua's `string` library.
25 | -- @module string_extras
26 |
27 | --- Returns a Lua string with all values joined by `separator`.
28 | -- `tostring` is called to each of the passed values before joining.
29 | -- @usage
30 | -- assert(string.join(',', 1, 2, 'three', Array()) == '1,2,three,[]')
31 | -- @function string.join
32 | -- @tparam string sep
33 | -- @param ... Values to be joined, stringified by `tostring`.
34 | -- @treturn string
35 | local function string_join(sep, ...)
36 | local result = {}
37 | for i = 1, select('#', ...) do
38 | local s = select(i, ...)
39 | table_insert(result, tostring(s))
40 | end
41 | return table_concat(result, sep)
42 | end
43 | string.join = string_join
44 |
45 | --- Quote a value, alias for `string.format("%q", tostring(value))`.
46 | -- @function string.quote
47 | -- @param value
48 | -- @treturn string
49 | local function string_quote(value)
50 | return string_format('%q', tostring(value))
51 | end
52 | string.quote = string_quote
53 |
54 | --- Performs plain substring substitution, with no characters in `pattern` or `replacement` being considered magic.
55 | -- @usage
56 | -- assert(string.replace('Dot.percent.arent.magic', '.', '%') == 'Dot%percent%arent%magic')
57 | -- @function string.replace
58 | -- @tparam string str
59 | -- @tparam string pattern
60 | -- @tparam string replacement
61 | -- @treturn string
62 | -- @see string.gsub
63 |
64 |
--------------------------------------------------------------------------------
/src/pluginscript_instance.lua:
--------------------------------------------------------------------------------
1 | -- @file pluginscript_instance.lua Script instances struct and metatype
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Script instance metatable, the Lua side of a Lua script instance.
25 | -- These are created when a PluginScript is instanced and are only directly
26 | -- accessible in the script's functions as the `self` parameter or gotten from
27 | -- `Object`s using `GD.get_lua_instance`.
28 | --
29 | -- typedef struct {
30 | -- godot_object *__owner;
31 | -- lps_lua_script *__script;
32 | -- lps_lua_object __data;
33 | -- } lps_script_instance;
34 | --
35 | -- @module LuaScriptInstance
36 |
37 | ffi_cdef[[
38 | typedef struct {
39 | godot_object *__owner;
40 | lps_lua_script *__script;
41 | lps_lua_object __data;
42 | } lps_script_instance;
43 | ]]
44 |
45 | --- Allocs and returns a pointer to a `LuaScriptInstance`.
46 | -- @tparam Object owner
47 | -- @tparam table script
48 | -- @param[opt={}] data
49 | local function LuaScriptInstance_new(owner, script, data)
50 | local self = ffi_cast('lps_script_instance *', api.godot_alloc(ffi_sizeof('lps_script_instance')))
51 | self.__owner = owner
52 | self.__script = script
53 | self.__data = LuaObject(data or {})
54 | return self
55 | end
56 |
57 | --- Frees all memory associated with a `LuaScriptInstance`.
58 | -- @tparam LuaScriptInstance self
59 | local function LuaScriptInstance_destroy(self)
60 | LuaObject_destroy(self.__data)
61 | api.godot_free(self)
62 | end
63 |
64 | local methods = {
65 | fillvariant = function(var, self)
66 | api.godot_variant_new_object(var, self.__owner)
67 | end,
68 | varianttype = VariantType.Object,
69 |
70 | --- Get a value from `__data`, bypassing the check for getters.
71 | -- @function rawget
72 | -- @param index
73 | -- @return
74 | rawget = function(self, index)
75 | return self.__data[index]
76 | end,
77 | --- Sets a value on the `__data`, bypassing the check for setters.
78 | -- @function rawset
79 | -- @param index
80 | -- @param value
81 | rawset = function(self, index, value)
82 | self.__data[index] = value
83 | end,
84 | }
85 | LuaScriptInstance = ffi_metatype('lps_script_instance', {
86 | --- `Object` that this script instance is attached to.
87 | -- This is the Godot side of the instance.
88 | -- @tfield Object __owner
89 |
90 | --- `LuaScript` for instance, the one returned by the Lua script when
91 | -- loading it as a PluginScript. Note that calling `Object:get_script` will
92 | -- return an `Object` rather than this wrapper.
93 | -- @tfield LuaScript __script
94 |
95 | --- `LuaObject` that references an internal table for holding arbitrary data.
96 | -- @tfield LuaObject __data
97 |
98 | --- Try indexing `__owner`, then `__data`, then `__script`.
99 | -- @function __index
100 | -- @param key
101 | -- @return
102 | -- @see Object.__index
103 | __index = function(self, key)
104 | local value = methods[key]
105 | if is_not_nil(value) then return value end
106 | local script_value = self.__script[key]
107 | if type(script_value) == 'function' then return script_value end
108 | value = self.__owner[key]
109 | if is_not_nil(value) then return value end
110 | value = self.__data[key]
111 | if is_not_nil(value) then return value end
112 | return script_value
113 | end,
114 | --- Calls `Object:set` if `key` is the name of a property known to base class, `rawset` otherwise.
115 | -- @function __newindex
116 | -- @param key
117 | -- @param value
118 | __newindex = function(self, key, value)
119 | if self.__script:has_property(key) then
120 | Object_set(self.__owner, key, value)
121 | else
122 | self:rawset(key, value)
123 | end
124 | end,
125 | --- Returns a Lua string representation of `__owner`, as per `Object:to_string`.
126 | -- @function __tostring
127 | -- @treturn string
128 | __tostring = function(self)
129 | return tostring(self.__owner)
130 | end,
131 | --- Concatenates values.
132 | -- @function __concat
133 | -- @param a First value, stringified with `GD.str`
134 | -- @param b First value, stringified with `GD.str`
135 | -- @treturn String
136 | __concat = concat_gdvalues,
137 | })
138 |
--------------------------------------------------------------------------------
/src/pluginscript_script.lua:
--------------------------------------------------------------------------------
1 | -- @file pluginscript_script.lua Script metadata struct and metatype
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Internal struct that wrap scripts with metadata.
25 | --
26 | -- typedef struct {
27 | -- godot_string_name __path;
28 | -- godot_string_name __base;
29 | -- lps_lua_object __properties;
30 | -- lps_lua_object __implementation;
31 | -- } lps_lua_script;
32 | --
33 | -- @module LuaScript
34 |
35 | ffi_cdef[[
36 | typedef struct {
37 | godot_string_name __path;
38 | godot_string_name __base;
39 | lps_lua_object __properties;
40 | lps_lua_object __implementation;
41 | } lps_lua_script;
42 | ]]
43 |
44 | --- Allocs and returns a pointer to a `LuaScript`.
45 | -- @param path Script path
46 | -- @tparam string|nil base Base class name. Defaults to "Reference".
47 | -- @tparam table properties Known properties from script
48 | -- @tparam table implementation Script implementation
49 | -- @treturn LuaScript
50 | local function LuaScript_new(path, base, properties, implementation)
51 | local self = ffi_cast('lps_lua_script *', api.godot_alloc(ffi_sizeof('lps_lua_script')))
52 | self.__path = ffi_gc(StringName(path), nil)
53 | self.__base = ffi_gc(StringName(base or 'Reference'), nil)
54 | self.__properties = LuaObject(properties)
55 | self.__implementation = LuaObject(implementation)
56 | return self
57 | end
58 |
59 | --- Frees all memory associated with a `LuaScript`.
60 | -- @tparam LuaScript self
61 | local function LuaScript_destroy(self)
62 | api.godot_string_name_destroy(self.__path)
63 | LuaObject_destroy(self.__properties)
64 | LuaObject_destroy(self.__implementation)
65 | api.godot_free(self)
66 | end
67 |
68 | --- @type LuaScript
69 | local methods = {
70 | --- Returns whether this script or its base class has a property named `name`.
71 | -- @function has_property
72 | -- @tparam string name Property name
73 | -- @treturn bool
74 | has_property = function(self, name)
75 | return self.__properties[name] ~= nil
76 | or ClassWrapper_cache[self.__base]:has_property(name)
77 | end,
78 | }
79 | local LuaScript = ffi_metatype('lps_lua_script', {
80 | --- Script path, usually relative to `res://`
81 | -- @tfield StringName __path
82 |
83 | --- Base class name
84 | -- @tfield StringName __base
85 |
86 | --- Table of known properties
87 | -- @tfield LuaObject __properties
88 |
89 | --- Table returned from script file, holding method implementations
90 | -- @tfield LuaObject __implementation
91 |
92 | --- Forwards indexing to script implementation
93 | -- @function __index
94 | -- @param index
95 | -- @return Value
96 | __index = function(self, index)
97 | return methods[index]
98 | or self.__implementation[index]
99 | end,
100 | })
101 |
--------------------------------------------------------------------------------
/src/pluginscript_signal.lua:
--------------------------------------------------------------------------------
1 | -- @file pluginscript_signal.lua Signal declarations for scripts
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 |
24 | --- Signal declarations for scripts.
25 | -- @module signal
26 |
27 | --- Signal metatable, used only to check if a value is a signal.
28 | local Signal = {}
29 |
30 | --- Checks if `value` is a signal.
31 | local function is_signal(value)
32 | return getmetatable(value) == Signal
33 | end
34 |
35 | --- Transforms a `Signal` into a `Dictionary`, for populating scripts metadata.
36 | local function signal_to_dictionary(sig)
37 | local args = Array()
38 | for i = 1, #sig do
39 | args:append(Dictionary{ name = String(sig[i]) })
40 | end
41 | local dict = Dictionary()
42 | dict.args = args
43 | return dict
44 | end
45 |
46 | --- Create a signal table, only useful for declaring scripts' signals.
47 | -- @usage
48 | -- MyClass.something_happened = signal()
49 | -- MyClass.something_happened_with_args = signal('arg1', 'arg2', 'etc')
50 | -- @param ... Signal argument names
51 | -- @treturn table
52 | -- @see lps_coroutine.lua
53 | function signal(...)
54 | return setmetatable({ ... }, Signal)
55 | end
56 |
--------------------------------------------------------------------------------
/src/register_in_editor_callbacks.lua:
--------------------------------------------------------------------------------
1 | -- @file register_in_editor_callbacks.lua Entrypoint for registering in editor callbacks
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021-2023 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 | if in_editor then
24 | xpcall(require, GD.print_error, 'addons/godot-lua-pluginscript/plugin/in_editor_callbacks')
25 | end
26 |
--------------------------------------------------------------------------------
/src/test/array.lua:
--------------------------------------------------------------------------------
1 | local lu = require "luaunit"
2 |
3 | local Test = {}
4 |
5 | function Test:test_array_index()
6 | local arr = Array(1, 3.14, 'hello!')
7 | lu.assert_nil(arr[0])
8 | lu.assert_equals(1, arr[1])
9 | lu.assert_equals(3.14, arr[2])
10 | lu.assert_equals(String 'hello!', arr[3])
11 | lu.assert_nil(arr[4])
12 | end
13 |
14 | function Test:test_array_newindex()
15 | local arr = Array()
16 | arr[1] = 1
17 | arr[2] = '2'
18 |
19 | lu.assert_equals(1, arr[1])
20 | lu.assert_equals(String '2', arr[2])
21 | lu.assert_equals(2, #arr)
22 |
23 | arr[1] = 2
24 | arr[2] = '3'
25 |
26 | lu.assert_equals(2, arr[1])
27 | lu.assert_equals(String '3', arr[2])
28 | lu.assert_equals(2, #arr)
29 | end
30 |
31 | function Test:sort(a, b)
32 | return a < b
33 | end
34 | function Test:test_sort()
35 | local arr = Array(1, 6, 3, 7, 3)
36 | arr:sort_custom(self, 'sort')
37 | lu.assert_equals(Array(1, 3, 3, 6, 7), arr)
38 | end
39 |
40 | return Test
41 |
--------------------------------------------------------------------------------
/src/test/class_wrapper.lua:
--------------------------------------------------------------------------------
1 | local lu = require "luaunit"
2 |
3 | local Test = {}
4 |
5 | function Test:test_has_property()
6 | lu.assert_true(Node:has_property 'name')
7 | lu.assert_false(Node:has_property 'not_a_property')
8 | end
9 |
10 | function Test:test_inherits()
11 | lu.assert_true(Node:inherits 'Object')
12 | lu.assert_true(Node2D:inherits 'Object')
13 | lu.assert_false(Node:inherits 'not_a_class')
14 | end
15 |
16 | function Test:test_get_parent_class()
17 | lu.assert_equals(String 'Object', Node:get_parent_class())
18 | lu.assert_equals(String 'CanvasItem', Node2D:get_parent_class())
19 | end
20 |
21 | function Test:test_ReturnsConstant()
22 | lu.assert_equals(1, Object.CONNECT_DEFERRED)
23 | lu.assert_equals(1, File.READ)
24 | lu.assert_equals(2, File.WRITE)
25 | end
26 |
27 | return Test
28 |
--------------------------------------------------------------------------------
/src/test/coroutines.lua:
--------------------------------------------------------------------------------
1 | local lu = require "luaunit"
2 |
3 | local Test = {}
4 |
5 | function Test:return_yield()
6 | return GD.yield()
7 | end
8 | function Test:test_yield_results()
9 | local coro = self:call('return_yield')
10 | lu.assert_nil(coro:resume())
11 |
12 | local coro = self:call('return_yield')
13 | lu.assert_equals(coro:resume(42), 42)
14 | end
15 |
16 | function Test:return_yield_numbers(max)
17 | for i = 1, max do
18 | GD.yield()
19 | end
20 | end
21 | function Test:test_yield_more_than_once()
22 | local max = 10
23 | local coro = self:call('return_yield_numbers', max)
24 | local i = 0
25 | while coro:is_valid() do
26 | coro:resume()
27 | i = i + 1
28 | end
29 | lu.assert_equals(i, max)
30 | end
31 |
32 | return Test
33 |
--------------------------------------------------------------------------------
/src/test/extras/invalid_extends.lua:
--------------------------------------------------------------------------------
1 | return {
2 | extends = 'invalid class',
3 | }
4 |
--------------------------------------------------------------------------------
/src/test/extras/parse_error.lua:
--------------------------------------------------------------------------------
1 | hello, this is not a Lua script =O
2 |
--------------------------------------------------------------------------------
/src/test/extras/valid_script.lua:
--------------------------------------------------------------------------------
1 | local Script = {
2 | extends = 'Node'
3 | }
4 |
5 | return Script
6 |
--------------------------------------------------------------------------------
/src/test/extras/valid_script_class_wrapper.lua:
--------------------------------------------------------------------------------
1 | local Script = {
2 | extends = Node
3 | }
4 |
5 | return Script
6 |
7 |
--------------------------------------------------------------------------------
/src/test/init.lua:
--------------------------------------------------------------------------------
1 | -- @file test/init.lua Unit test runner
2 | -- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
3 | --
4 | -- Copyright (C) 2021 Gil Barbosa Reis.
5 | --
6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy
7 | -- of this software and associated documentation files (the “Software”), to
8 | -- deal in the Software without restriction, including without limitation the
9 | -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 | -- sell copies of the Software, and to permit persons to whom the Software is
11 | -- furnished to do so, subject to the following conditions:
12 | --
13 | -- The above copyright notice and this permission notice shall be included in
14 | -- all copies or substantial portions of the Software.
15 | --
16 | -- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 | -- IN THE SOFTWARE.
23 | local TestRunner = {
24 | extends = 'SceneTree',
25 | }
26 |
27 | local function error_handler(msg)
28 | if os.getenv('DEBUG_INTERACTIVE') then
29 | local have_dbg, dbg = pcall(require, 'debugger')
30 | if have_dbg then
31 | return dbg()
32 | end
33 | end
34 | GD.print_error(msg)
35 | end
36 |
37 | function TestRunner:setup_luapath(current_script_base_dir)
38 | local additional_paths = { '../../lib/luaunit', '../../lib/debugger_lua' }
39 | for _, path in ipairs(additional_paths) do
40 | local additional_path = current_script_base_dir:plus_file(path)
41 | package.path = string.format('%s/?.lua;%s/?/init.lua;%s', additional_path, additional_path, package.path)
42 | end
43 | end
44 |
45 | function TestRunner:setup_cpath()
46 | local additional_paths
47 | if OS:get_name() == 'Windows' then
48 | additional_paths = {
49 | '!/addons/godot-lua-pluginscript/build/windows_x86/?.dll',
50 | '!/addons/godot-lua-pluginscript/build/windows_x86_64/?.dll',
51 | }
52 | elseif OS:get_name() == 'OSX' then
53 | additional_paths = {
54 | '!/addons/godot-lua-pluginscript/build/osx_arm64_x86_64/?.dylib',
55 | }
56 | else
57 | additional_paths = {
58 | '!/addons/godot-lua-pluginscript/build/linux_x86/?.so',
59 | '!/addons/godot-lua-pluginscript/build/linux_x86_64/?.so',
60 | }
61 | end
62 |
63 | for _, path in ipairs(additional_paths) do
64 | package.cpath = string.format('%s;%s', path, package.cpath)
65 | end
66 | end
67 |
68 | function TestRunner:_init()
69 | local current_script_path = self:get_script().resource_path
70 | local current_script_filename = current_script_path:get_file()
71 | local current_script_base_dir = current_script_path:get_base_dir()
72 |
73 | self:setup_luapath(current_script_base_dir)
74 | self:setup_cpath()
75 |
76 | local dir, all_passed = Directory:new(), true
77 | assert(dir:open(current_script_base_dir) == GD.OK)
78 | dir:list_dir_begin(true)
79 | repeat
80 | local filename = dir:get_next()
81 | if filename:ends_with('.lua') and filename ~= current_script_filename then
82 | local script = GD.load(current_script_base_dir:plus_file(filename))
83 | local instance = script:new()
84 | if instance:is_class('Node') then
85 | self.root:add_child(instance)
86 | end
87 | local lua_instance = GD.get_lua_instance(instance)
88 | print(string.format('> %s:', filename))
89 | for i, method in ipairs(script:get_script_method_list()) do
90 | if method.name:begins_with("test") then
91 | local success = xpcall(lua_instance[tostring(method.name)], error_handler, lua_instance)
92 | print(string.format(' %s %s: %s', success and '✓' or '🗴', method.name, success and 'passed' or 'failed'))
93 | all_passed = all_passed and success
94 | end
95 | end
96 | instance:pcall('queue_free')
97 | end
98 | until filename == ''
99 | dir:list_dir_end()
100 |
101 | self:quit(all_passed and 0 or 1)
102 | end
103 |
104 | return TestRunner
105 |
--------------------------------------------------------------------------------
/src/test/require_luac.lua:
--------------------------------------------------------------------------------
1 | local lu = require "luaunit"
2 |
3 | local Test = {}
4 |
5 | function Test:test_require_luac_module()
6 | lu.assert_true(pcall(require, 'test_cmodule'))
7 | end
8 |
9 | return Test
10 |
--------------------------------------------------------------------------------
/src/test/script_loading.lua:
--------------------------------------------------------------------------------
1 | local lu = require "luaunit"
2 |
3 | local Test = {}
4 |
5 | function Test:get_extra_script(name)
6 | local script_path = self:get_script().resource_path:get_base_dir():plus_file('extras'):plus_file(name)
7 | return GD.load(script_path)
8 | end
9 |
10 | function Test:test_WhenValidScript_CanInstance()
11 | local script = self:get_extra_script("valid_script.lua")
12 | lu.assert_true(script:can_instance())
13 | end
14 |
15 | function Test:test_WhenExtendsClassWrapper_IsValidAndCanInstance()
16 | local script = self:get_extra_script("valid_script_class_wrapper.lua")
17 | lu.assert_true(script:can_instance())
18 | end
19 |
20 | function Test:test_WhenParseError_CantInstance()
21 | local script = self:get_extra_script("parse_error.lua")
22 | lu.assert_false(script:can_instance())
23 | end
24 |
25 | function Test:test_WhenExtendsIsNotAClassNorScriptPath_CantInstance()
26 | local script = self:get_extra_script("invalid_extends.lua")
27 | lu.assert_false(script:can_instance())
28 | end
29 |
30 | return Test
31 |
--------------------------------------------------------------------------------
/src/test/setter_newindex.lua:
--------------------------------------------------------------------------------
1 | local lu = require "luaunit"
2 |
3 | local Test = {
4 | extends = 'Node'
5 | }
6 |
7 | Test.custom_prop = property {
8 | default = false,
9 | set = function(self, value)
10 | self:rawset('custom_prop', value)
11 | self.custom_prop_setter_called = true
12 | end,
13 | }
14 |
15 | function Test:test_WhenSettingPropertyInClass_SetterIsCalled()
16 | local name = String 'test'
17 | self.name = name
18 | lu.assert_equals(self.name, name)
19 | lu.assert_equals(self:get 'name', name)
20 | lu.assert_nil(self:rawget 'name')
21 | end
22 |
23 | function Test:test_WhenSettingPropertyInScript_SetterIsCalled()
24 | self.custom_prop = true
25 | lu.assert_true(self.custom_prop, true)
26 | lu.assert_true(self.custom_prop_setter_called, true)
27 | end
28 |
29 | return Test
30 |
--------------------------------------------------------------------------------
/src/test/test_cmodule.c:
--------------------------------------------------------------------------------
1 | #include "lua.h"
2 |
3 | int luaopen_test_cmodule(lua_State *L) {
4 | lua_pushboolean(L, 1);
5 | return 1;
6 | }
7 |
--------------------------------------------------------------------------------
/src/tools/add_script_c_decl.sed:
--------------------------------------------------------------------------------
1 | # NOTE: using actual newlines instead of "\n" for BSD/OSX version of sed
2 | # Text before first line
3 | 1 i\
4 | #include\
5 | const char LUA_INIT_SCRIPT[] =
6 | # Text after last line
7 | $ a\
8 | ;\
9 | const size_t LUA_INIT_SCRIPT_SIZE = sizeof(LUA_INIT_SCRIPT);
10 |
--------------------------------------------------------------------------------
/src/tools/compact_c_ffi.sed:
--------------------------------------------------------------------------------
1 | /cdef\[\[/,/\]\]/ {
2 | # Remove C comments
3 | s/[[:space:]]*\/\/.*//
4 | # Minify unused private fields
5 | s/_dont_touch_that/_/
6 | # Remove function parameter names
7 | /\(\*/ {
8 | s/[[:space:]]*[_a-zA-Z0-9]*(,|\);)/\1/g
9 | }
10 | # Remove unused enum/struct/union names when they're typedef'd
11 | s/typedef (enum|struct|union) [_a-zA-Z0-9]*/typedef \1/
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/src/tools/embed_to_c.sed:
--------------------------------------------------------------------------------
1 | # Escape backslashes
2 | s/\\/\\\\/g
3 | # Escape quotes
4 | s/"/\\"/g
5 | # Add starting quote
6 | s/^/"/
7 | # Add ending newline, except on last script line
8 | $! s/$/\\n/
9 | # Add ending quote
10 | s/$/"/
11 |
--------------------------------------------------------------------------------
/src/tools/project.godot:
--------------------------------------------------------------------------------
1 | ; Godot project config file for unit test runner
2 |
3 | config_version=4
4 |
5 | [application]
6 |
7 | config/name="godot-lua-pluginscript-unittest"
8 |
9 | [gdnative]
10 |
11 | singletons=[ "res://addons/godot-lua-pluginscript/lua_pluginscript.gdnlib" ]
12 |
13 | [logging]
14 |
15 | file_logging/enable_file_logging.pc=false
16 | file_logging/log_path="testlogdir"
17 |
18 | [rendering]
19 |
20 | quality/driver/driver_name="GLES2"
21 |
--------------------------------------------------------------------------------
/src/tools/remove_lua_comments.sed:
--------------------------------------------------------------------------------
1 | # Remove all comment lines but the first license notice and "-- @file ..." lines
2 | 25,$ {
3 | # Ensure there is a new line before "-- @file ..." lines
4 | s/(-- @file)/\n\1/
5 | # Skip next command if the previous one substituted anything
6 | # That is, when current line is a "-- @file ..." line, skip everything below
7 | t
8 | # Remove comment lines
9 | /^[[:space:]]*--/d
10 | }
11 |
--------------------------------------------------------------------------------
/src/tools/squeeze_blank_lines.sed:
--------------------------------------------------------------------------------
1 | # On empty lines, do:
2 | /^$/ {
3 | : remove-empty-line
4 | # Load the next input line
5 | N
6 | # Remove last line, if it is empty
7 | s/\n$//
8 | # In case last line was empty, repeat the process to squeeze multiple empty lines into a single one
9 | t remove-empty-line
10 | }
11 |
12 |
--------------------------------------------------------------------------------