├── demo ├── .gitignore ├── .gitattributes ├── main.tscn ├── main.gd ├── project.godot ├── icon.svg ├── icon.svg.import └── addons │ └── RobloxToGodotProject │ └── RobloxToGodotProject.gdextension ├── src ├── classes │ ├── roblox │ │ └── core │ │ │ ├── rblx_cross_state_object.cpp │ │ │ ├── rblx_cross_state_object.hpp │ │ │ ├── rblx_instance_new_implementation.cpp │ │ │ ├── rblx_debug.hpp │ │ │ ├── rblx_events.hpp │ │ │ ├── rblx_script.hpp │ │ │ ├── rblx_events.cpp │ │ │ ├── rblx_basic_types.hpp │ │ │ ├── rblx_instance.hpp │ │ │ ├── rblx_script.cpp │ │ │ └── rblx_main.cpp │ ├── luau_function_result.h │ ├── luau_function.h │ ├── luau_function_result.cpp │ ├── luau_function.cpp │ ├── roblox_vm.h │ ├── luau_vm_bindings.cpp │ └── roblox_vm.cpp ├── vector_lib.h ├── utils.h ├── vector_lib.cpp └── utils.cpp ├── .gitmodules ├── register_types.h ├── .github └── workflows │ ├── runner.yml │ ├── static-checks.yml │ ├── android-package.yml │ ├── ios-package.yml │ ├── macos-package.yml │ ├── ios-build.yml │ ├── macos-build.yml │ ├── android-build.yml │ ├── linux.yml │ ├── windows.yml │ └── gdextension.yml ├── README.md ├── LICENSE ├── register_types.cpp ├── SConstruct ├── .gitignore └── tools └── extension_api_viewer.py /demo/.gitignore: -------------------------------------------------------------------------------- 1 | # Godot 4+ specific ignores 2 | .godot/ 3 | -------------------------------------------------------------------------------- /demo/.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize EOL for all files that Git considers text files. 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /src/classes/roblox/core/rblx_cross_state_object.cpp: -------------------------------------------------------------------------------- 1 | #include "rblx_main.hpp" 2 | #include "rblx_cross_state_object.hpp" 3 | 4 | namespace godot { 5 | 6 | }; -------------------------------------------------------------------------------- /src/classes/roblox/core/rblx_cross_state_object.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RBLX_PROXY_OBJECT 2 | #define RBLX_PROXY_OBJECT 3 | 4 | #include "rblx_main.hpp" 5 | 6 | namespace godot { 7 | 8 | } 9 | 10 | 11 | #endif -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "godot-cpp"] 2 | path = godot-cpp 3 | url = https://github.com/godotengine/godot-cpp 4 | branch = master 5 | [submodule "luau"] 6 | path = luau 7 | url = https://github.com/RadiantUwU/luau 8 | -------------------------------------------------------------------------------- /demo/main.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://ba8oxajrv3g3x"] 2 | 3 | [ext_resource type="Script" path="res://main.gd" id="1_fr1je"] 4 | 5 | [node name="Main" type="Node"] 6 | script = ExtResource("1_fr1je") 7 | 8 | [node name="RobloxVM" type="RobloxVM" parent="."] 9 | -------------------------------------------------------------------------------- /src/vector_lib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | #define LUA_VECLIBNAME "vector" 8 | 9 | 10 | int lua_vector_lib_call(lua_State *L); 11 | 12 | int lua_vector_tostring(lua_State *L); 13 | 14 | int lua_vector_index(lua_State *L); 15 | 16 | int luaopen_vector(lua_State *L); 17 | -------------------------------------------------------------------------------- /register_types.h: -------------------------------------------------------------------------------- 1 | #ifndef RobloxToGodotProject_REGISTER_TYPES_H 2 | #define RobloxToGodotProject_REGISTER_TYPES_H 3 | 4 | #include 5 | 6 | using namespace godot; 7 | 8 | void initialize_RobloxToGodotProject_module(ModuleInitializationLevel p_level); 9 | void uninitialize_RobloxToGodotProject_module(ModuleInitializationLevel p_level); 10 | 11 | #endif // RobloxToGodotProject_REGISTER_TYPES_H 12 | -------------------------------------------------------------------------------- /demo/main.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | @onready var vm : RobloxVM = $RobloxVM 5 | 6 | func _ready(): 7 | print("================") 8 | 9 | vm.open_all_libraries() 10 | 11 | vm.lua_pushobject(self) 12 | vm.lua_setfield(vm.LUA_GLOBALSINDEX, "node") 13 | 14 | var success := vm.lua_dostring(""" 15 | node.shit = 3 16 | """) 17 | 18 | if success != vm.LUA_OK: 19 | print(vm.lua_tostring(-1)) 20 | vm.lua_pop() 21 | return 22 | 23 | 24 | func _on_luau_vm_stdout(message): 25 | print(message) 26 | -------------------------------------------------------------------------------- /demo/project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=5 10 | 11 | [application] 12 | 13 | config/name="RobloxToGodotProject Demo" 14 | run/main_scene="res://main.tscn" 15 | config/features=PackedStringArray("4.1", "Forward Plus") 16 | config/icon="res://icon.svg" 17 | -------------------------------------------------------------------------------- /src/classes/luau_function_result.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace godot { 9 | 10 | class LuauFunctionResult : public RefCounted { 11 | GDCLASS(LuauFunctionResult, RefCounted) 12 | 13 | private: 14 | Array tuple; 15 | String error; 16 | bool _is_error = false; 17 | 18 | protected: 19 | static void _bind_methods(); 20 | 21 | public: 22 | LuauFunctionResult() {} 23 | LuauFunctionResult(const Array &tuple); 24 | LuauFunctionResult(const String &error); 25 | ~LuauFunctionResult() {} 26 | 27 | Array get_tuple(); 28 | String get_error(); 29 | bool is_error(); 30 | }; 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /.github/workflows/runner.yml: -------------------------------------------------------------------------------- 1 | name: 🔗 GHA 2 | on: 3 | workflow_dispatch: 4 | 5 | pull_request: 6 | branches: 7 | - "*" 8 | paths-ignore: 9 | - "README.md" 10 | - "LICENSE" 11 | - "**/*.png" 12 | - ".github/ISSUE_TEMPLATE/*" 13 | - ".github/CODEOWNERS" 14 | push: 15 | branches: 16 | - "main" 17 | paths-ignore: 18 | - "**/README.md" 19 | - "**/*.png" 20 | - "**/LICENSE" 21 | - ".github/ISSUE_TEMPLATE/*" 22 | - ".github/CODEOWNERS" 23 | 24 | env: 25 | GODOT_VERSION: 4.1 26 | 27 | jobs: 28 | gdextension-build: 29 | name: ⚙️ GDExtension 30 | uses: ./.github/workflows/gdextension.yml 31 | with: 32 | fullbuild: ${{ github.event_name == 'workflow_dispatch' }} 33 | godot_version: 4.1 34 | -------------------------------------------------------------------------------- /demo/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/classes/luau_function.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | 10 | 11 | namespace godot { 12 | 13 | class LuauFunction : public RefCounted { 14 | GDCLASS(LuauFunction, RefCounted) 15 | 16 | private: 17 | lua_State *L = nullptr; 18 | int ref = LUA_REFNIL; 19 | 20 | protected: 21 | static void _bind_methods(); 22 | 23 | public: 24 | LuauFunction() {} 25 | LuauFunction(lua_State *L, int ref); 26 | ~LuauFunction(); 27 | 28 | Ref pcall(const Variant **args, GDExtensionInt arg_count, GDExtensionCallError &error); 29 | Ref pcallv(const Array &arguments); 30 | 31 | private: 32 | Ref pcall_internal(int arg_count); 33 | }; 34 | 35 | } 36 | 37 | 38 | godot::Ref lua_tofunction(lua_State *L, int idx); 39 | -------------------------------------------------------------------------------- /demo/icon.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://l63om1aoff3g" 6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://icon.svg" 14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # The Roblox To Godot Project 3 | 4 | A GDExtension that adds [Luau](https://luau-lang.org) and creates a `RobloxVMInstance` for Godot to be able to run Roblox games. 5 | *(+ some extras)* 6 | 7 | About 8 | ----- 9 | This project is made for the developers that have gotten sick of using Roblox and want to become indie. Simply convert your game without modifying any scripts and it will all work as expected 10 | 11 | Features 12 | -------- 13 | - Implementation of a Roblox VM that runs Luau and the task scheduler as needed. 14 | - TODO: Implementation of Instances, Roblox data types 15 | - TODO: Implementation of Actors 16 | 17 | Compiling 18 | ------------ 19 | - Clone the repo 20 | - Run `scons platform=` 21 | - [A test project is included in the repo](https://github.com/RadiantUwU/RobloxToGodotProject/tree/master/demo) 22 | (binaries are in `res://addons/gdluau/bin`) 23 | 24 | **Special thanks** 25 | ------ 26 | - https://github.com/Manonox/GDLuau 27 | - https://github.com/WeaselGames/godot_luaAPI 28 | - https://github.com/luau-lang/luau 29 | -------------------------------------------------------------------------------- /src/classes/luau_function_result.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | using namespace godot; 8 | 9 | LuauFunctionResult::LuauFunctionResult(const Array &tuple) { 10 | this->tuple = tuple; 11 | this->_is_error = false; 12 | } 13 | 14 | LuauFunctionResult::LuauFunctionResult(const String &error) { 15 | this->error = error; 16 | this->_is_error = true; 17 | } 18 | 19 | Array LuauFunctionResult::get_tuple() { 20 | if (_is_error) return Variant(); 21 | return this->tuple; 22 | } 23 | 24 | String LuauFunctionResult::get_error() { 25 | if (!_is_error) return Variant(); 26 | return this->error; 27 | } 28 | 29 | bool LuauFunctionResult::is_error() { 30 | return this->_is_error; 31 | } 32 | 33 | 34 | void LuauFunctionResult::_bind_methods() { 35 | ClassDB::bind_method(D_METHOD("get_error"), &LuauFunctionResult::get_error); 36 | ClassDB::bind_method(D_METHOD("get_tuple"), &LuauFunctionResult::get_tuple); 37 | } 38 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | void lua_pushvariant(lua_State *L, const godot::Variant &var); 12 | void lua_pusharray(lua_State *L, const godot::Array &array); 13 | void lua_pushdictionary(lua_State *L, const godot::Dictionary &dict); 14 | 15 | godot::Variant lua_tovariant(lua_State *L, int idx); 16 | godot::Variant lua_toarray(lua_State *L, int idx); 17 | godot::Variant lua_todictionary(lua_State *L, int idx); 18 | 19 | bool luaL_isarray(lua_State *L, int idx); 20 | 21 | void lua_pushcallable(lua_State *L, const godot::Callable &callable); 22 | 23 | 24 | bool luaL_hasmetatable(lua_State *L, int idx, const char *tname); 25 | 26 | void lua_pushobject(lua_State *L, godot::Object *object); 27 | void object_userdata_dtor(lua_State *L, void *data); 28 | godot::Object *lua_toobject(lua_State *L, int idx); 29 | int lua_isobject(lua_State *L, int idx); 30 | godot::Object *luaL_checkobject(lua_State *L, int idx, bool valid); 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Radiant, RobloxToGodotProject 4 | Copyright (c) 2023 Tigran Mamedov, Luau C/C++ Bindings 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 deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | 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 all 14 | 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 FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/classes/roblox/core/rblx_instance_new_implementation.cpp: -------------------------------------------------------------------------------- 1 | #include "rblx_instance.hpp" 2 | #include "rblx_script.hpp" 3 | #include "rblx_main.hpp" 4 | #include "rblx_basic_types.hpp" 5 | #include "rblx_debug.hpp" 6 | #include 7 | 8 | namespace godot { 9 | 10 | int Instance::new_instance(lua_State *L) { 11 | luau_function_context fn = L; 12 | fn.assert_type_argument(1,"ClassName",LUA_TSTRING); 13 | RBXVariant v_temp = fn.as_object(1); 14 | LuaString s = LuaString(v_temp.get_str(),v_temp.get_slen()); 15 | RobloxVMInstance *vm; 16 | fn.rawget(LUA_REGISTRYINDEX,"ROBLOX_VM"); 17 | v_temp = fn.to_object(); 18 | vm = (RobloxVMInstance*)(void*)v_temp; 19 | RBLX_PRINT_VERBOSE((void*)vm); 20 | if (s == "Instance") {// TODO: illegal on roblox lmaooo 21 | fn.new_instance(vm); 22 | return fn.lua_return(1); 23 | } else if (s == "Script") { 24 | fn.new_instance