Skip to content
This repository was archived by the owner on Dec 29, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc_classes/LuaAPI.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@
</description>
</method>
</methods>
<members>
<member name="permissive" type="bool" setter="set_permissive" getter="get_permissive" default="false">
Set weather an objects lua_fields method should be treated as a blacklist instead of a whitelist.
</member>
</members>
<constants>
<constant name="HOOK_MASK_CALL" value="1" enum="HookMask">
Specifies on which events the hook will be called.
Expand Down
6 changes: 3 additions & 3 deletions project/demo/HelloLua.gd
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ func _lua_print(message: String):
return LuaError.new_error("test", LuaError.ERR_RUNTIME)

func _ready():
# All builtin libraries are available to bind with. Use Debug, OS and IO at your own risk.
lua.bind_libraries(["base", "table", "string"])

lua.push_variant("print", _lua_print)
lua.push_variant("message", "Hello lua!")

# All builtin libraries are available to bind with. Use OS and IO at your own risk.
lua.bind_libraries(["base", "table", "string"])

# Most methods return a LuaError in case of an error
var err: LuaError = lua.do_string("""
for i=1,10,1 do
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/LuaAPI.call_function.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ func _ready():
id = 9970

lua = LuaAPI.new()
lua.permissive = true

# testName and testDescription are for any needed context about the test.
testName = "LuaAPI.call_function"
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/LuaAPI.expose_constructor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ func _ready():
id = 9950

lua = LuaAPI.new()
lua.permissive = true
var err = lua.expose_constructor("TestObj", TestObject)
if err is LuaError:
errors.append(err)
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/LuaAPI.expose_function.gd
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func _ready():
id = 9940

lua = LuaAPI.new()
lua.permissive = true
lua.set_meta("isValid", true)
var err = lua.push_variant("test1", LuaCallableExtra.with_tuple(testFuncTuple, 2))
if err is LuaError:
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/LuaCoroutine.resume.gd
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ func _ready():
id = 9500

lua = LuaAPI.new()
lua.permissive = true
co = lua.new_coroutine()

co.load_string("
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/LuaCoroutine.yield_await.gd
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func _ready():
id = 9490

lua = LuaAPI.new()
lua.permissive = true
co = lua.new_coroutine()
co.push_variant("test_yield_await", _test_yield_await)

Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/general.base_types.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ func _ready():
id = 9825

lua = LuaAPI.new()
lua.permissive = true

# testName and testDescription are for any needed context about the test.
testName = "General.base_types"
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/general.object_metamethods.gd
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func _ready():
id = 9850

lua = LuaAPI.new()
lua.permissive = true
lua.set_meta("isValid", true)
testObj = TestObject.new()
lua.push_variant("testObj", testObj)
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/general.object_push.gd
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func _ready():

testObj = TestObject.new()
lua = LuaAPI.new()
lua.permissive = true
var err = lua.push_variant("testObj", testObj)
if err is LuaError:
errors.append(err)
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/luaAPI.do_file.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ func _ready():
id = 9990

lua = LuaAPI.new()
lua.permissive = true

# testName and testDescription are for any needed context about the test.
testName = "LuaAPI.do_file()"
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/luaAPI.do_string.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ func _ready():
id = 10000

lua = LuaAPI.new()
lua.permissive = true

# testName and testDescription are for any needed context about the test.
testName = "LuaAPI.do_string()"
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/luaAPI.pull_variant.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ func _ready():
id = 9980

lua = LuaAPI.new()
lua.permissive = true

# testName and testDescription are for any needed context about the test.
testName = "LuaAPI.pull_variant()"
Expand Down
1 change: 1 addition & 0 deletions project/testing/tests/luaAPI.push_variant.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ func _ready():
id = 9960

lua = LuaAPI.new()
lua.permissive = true

# testName and testDescription are for any needed context about the test.
testName = "LuaAPI.push_variant()"
Expand Down
5 changes: 5 additions & 0 deletions src/classes/luaAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ void LuaAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("new_coroutine"), &LuaAPI::newCoroutine);
ClassDB::bind_method(D_METHOD("get_running_coroutine"), &LuaAPI::getRunningCoroutine);

ClassDB::bind_method(D_METHOD("set_permissive", "value"), &LuaAPI::setPermissive);
ClassDB::bind_method(D_METHOD("get_permissive"), &LuaAPI::getPermissive);

ADD_PROPERTY(PropertyInfo(Variant::INT, "permissive"), "set_permissive", "get_permissive");

BIND_ENUM_CONSTANT(HOOK_MASK_CALL);
BIND_ENUM_CONSTANT(HOOK_MASK_RETURN);
BIND_ENUM_CONSTANT(HOOK_MASK_LINE);
Expand Down
12 changes: 11 additions & 1 deletion src/classes/luaAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ class LuaAPI : public RefCounted {
void bindLibraries(Array libs);
void setHook(Callable hook, int mask, int count);

inline void setPermissive(bool permissive) {
this->permissive = permissive;
}

inline bool getPermissive() const {
return permissive;
}

bool luaFunctionExists(String functionName);

Variant pullVariant(String name);
Expand Down Expand Up @@ -68,7 +76,9 @@ class LuaAPI : public RefCounted {

private:
LuaState state;
lua_State *lState;
lua_State *lState = nullptr;

bool permissive = false;

// Temp. Looking for better method. Maybe?
Array refs;
Expand Down
1 change: 0 additions & 1 deletion src/luaState.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ class LuaState {
public:
void setState(lua_State *state, RefCounted *obj, bool bindAPI);
void bindLibraries(Array libs);

void setHook(Callable hook, int mask, int count);

bool luaFunctionExists(String functionName);
Expand Down
45 changes: 40 additions & 5 deletions src/metatables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,27 +417,52 @@ void LuaState::createObjectMetatable() {
luaL_newmetatable(L, "mt_Object");

LUA_METAMETHOD_TEMPLATE(L, -1, "__index", {
Ref<LuaAPI> lua_api = dynamic_cast<LuaAPI *>(OBJ);
if (lua_api == nullptr) {
LuaError *err = LuaError::newError("Object not found!", LuaError::ERR_RUNTIME);
LuaState::pushVariant(inner_state, err);
return 0;
}

// If object overrides
if (arg1.has_method("__index")) {
LuaState::pushVariant(inner_state, arg1.call("__index", Ref<LuaAPI>(OBJ), arg2));
LuaState::pushVariant(inner_state, arg1.call("__index", lua_api, arg2));
return 1;
}

bool permissive = lua_api->getPermissive();
Array allowedFields = Array();
if (arg1.has_method("lua_fields")) {
allowedFields = arg1.call("lua_fields");
}

// In permissive mode, allowedFields beomces a blacklist.
if (permissive) {
if (!allowedFields.has(arg2) && arg1.has_method(arg2.operator String())) {
lua_pushlightuserdata(inner_state, lua_touserdata(inner_state, 1));
LuaState::pushVariant(inner_state, arg2);
lua_pushcclosure(inner_state, luaUserdataFuncCall, 2);
return 1;
}

if (!allowedFields.has(arg2)) {
Variant var = arg1.get(arg2);
LuaState::pushVariant(inner_state, var);
return 1;
}
return 0;
}

// If the functions is allowed and exists
if ((allowedFields.is_empty() || allowedFields.has(arg2)) && arg1.has_method(arg2.operator String())) {
if (allowedFields.has(arg2) && arg1.has_method(arg2.operator String())) {
lua_pushlightuserdata(inner_state, lua_touserdata(inner_state, 1));
LuaState::pushVariant(inner_state, arg2);
lua_pushcclosure(inner_state, luaUserdataFuncCall, 2);
return 1;
}

// If the field is allowed
if (allowedFields.is_empty() || allowedFields.has(arg2)) {
if (allowedFields.has(arg2)) {
Variant var = arg1.get(arg2);
LuaState::pushVariant(inner_state, var);
return 1;
Expand All @@ -447,20 +472,30 @@ void LuaState::createObjectMetatable() {
});

LUA_METAMETHOD_TEMPLATE(L, -1, "__newindex", {
Ref<LuaAPI> lua_api = dynamic_cast<LuaAPI *>(OBJ);
if (lua_api == nullptr) {
LuaError *err = LuaError::newError("Object not found!", LuaError::ERR_RUNTIME);
LuaState::pushVariant(inner_state, err);
return 0;
}

// If object overrides
if (arg1.has_method("__newindex")) {
LuaState::pushVariant(inner_state, arg1.call("__newindex", Ref<LuaAPI>(OBJ), arg2, arg3));
LuaState::pushVariant(inner_state, arg1.call("__newindex", lua_api, arg2, arg3));
return 1;
}

bool permissive = lua_api->getPermissive();
Array allowedFields = Array();
if (arg1.has_method("lua_fields")) {
allowedFields = arg1.call("lua_fields");
}

if (allowedFields.is_empty() || allowedFields.has(arg2)) {
if (!permissive && allowedFields.has(arg2)) {
// We can't use arg1 here because we need to reference the userdata
((Variant *)lua_touserdata(inner_state, 1))->set(arg2, arg3);
} else if (permissive && !allowedFields.has(arg2)) { // In permissive mode, allowedFields beomces a blacklist.
((Variant *)lua_touserdata(inner_state, 1))->set(arg2, arg3);
}
return 0;
});
Expand Down