diff --git a/doc_classes/LuaAPI.xml b/doc_classes/LuaAPI.xml
index be593bdb..892693a0 100644
--- a/doc_classes/LuaAPI.xml
+++ b/doc_classes/LuaAPI.xml
@@ -89,6 +89,11 @@
+
+
+ Set weather an objects lua_fields method should be treated as a blacklist instead of a whitelist.
+
+
Specifies on which events the hook will be called.
diff --git a/project/demo/HelloLua.gd b/project/demo/HelloLua.gd
index 668e9267..06deede2 100644
--- a/project/demo/HelloLua.gd
+++ b/project/demo/HelloLua.gd
@@ -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
diff --git a/project/testing/tests/LuaAPI.call_function.gd b/project/testing/tests/LuaAPI.call_function.gd
index d5985e48..a63d9fb2 100644
--- a/project/testing/tests/LuaAPI.call_function.gd
+++ b/project/testing/tests/LuaAPI.call_function.gd
@@ -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"
diff --git a/project/testing/tests/LuaAPI.expose_constructor.gd b/project/testing/tests/LuaAPI.expose_constructor.gd
index 6be7cafd..20f28070 100644
--- a/project/testing/tests/LuaAPI.expose_constructor.gd
+++ b/project/testing/tests/LuaAPI.expose_constructor.gd
@@ -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)
diff --git a/project/testing/tests/LuaAPI.expose_function.gd b/project/testing/tests/LuaAPI.expose_function.gd
index ab2be7e1..4156fe33 100644
--- a/project/testing/tests/LuaAPI.expose_function.gd
+++ b/project/testing/tests/LuaAPI.expose_function.gd
@@ -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:
diff --git a/project/testing/tests/LuaCoroutine.resume.gd b/project/testing/tests/LuaCoroutine.resume.gd
index de481437..c7b5b50f 100644
--- a/project/testing/tests/LuaCoroutine.resume.gd
+++ b/project/testing/tests/LuaCoroutine.resume.gd
@@ -9,6 +9,7 @@ func _ready():
id = 9500
lua = LuaAPI.new()
+ lua.permissive = true
co = lua.new_coroutine()
co.load_string("
diff --git a/project/testing/tests/LuaCoroutine.yield_await.gd b/project/testing/tests/LuaCoroutine.yield_await.gd
index d483d8d1..5484c239 100644
--- a/project/testing/tests/LuaCoroutine.yield_await.gd
+++ b/project/testing/tests/LuaCoroutine.yield_await.gd
@@ -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)
diff --git a/project/testing/tests/general.base_types.gd b/project/testing/tests/general.base_types.gd
index 0433cda7..7bb82f21 100644
--- a/project/testing/tests/general.base_types.gd
+++ b/project/testing/tests/general.base_types.gd
@@ -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"
diff --git a/project/testing/tests/general.object_metamethods.gd b/project/testing/tests/general.object_metamethods.gd
index ab7015b1..95c8567a 100644
--- a/project/testing/tests/general.object_metamethods.gd
+++ b/project/testing/tests/general.object_metamethods.gd
@@ -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)
diff --git a/project/testing/tests/general.object_push.gd b/project/testing/tests/general.object_push.gd
index b5ee1a74..8bc3af16 100644
--- a/project/testing/tests/general.object_push.gd
+++ b/project/testing/tests/general.object_push.gd
@@ -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)
diff --git a/project/testing/tests/luaAPI.do_file.gd b/project/testing/tests/luaAPI.do_file.gd
index 5a65639e..ac3d5f47 100644
--- a/project/testing/tests/luaAPI.do_file.gd
+++ b/project/testing/tests/luaAPI.do_file.gd
@@ -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()"
diff --git a/project/testing/tests/luaAPI.do_string.gd b/project/testing/tests/luaAPI.do_string.gd
index 145ee018..a7581bd2 100644
--- a/project/testing/tests/luaAPI.do_string.gd
+++ b/project/testing/tests/luaAPI.do_string.gd
@@ -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()"
diff --git a/project/testing/tests/luaAPI.pull_variant.gd b/project/testing/tests/luaAPI.pull_variant.gd
index b9d8f383..288c4ad0 100644
--- a/project/testing/tests/luaAPI.pull_variant.gd
+++ b/project/testing/tests/luaAPI.pull_variant.gd
@@ -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()"
diff --git a/project/testing/tests/luaAPI.push_variant.gd b/project/testing/tests/luaAPI.push_variant.gd
index 0a30021e..92027840 100644
--- a/project/testing/tests/luaAPI.push_variant.gd
+++ b/project/testing/tests/luaAPI.push_variant.gd
@@ -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()"
diff --git a/src/classes/luaAPI.cpp b/src/classes/luaAPI.cpp
index 7b01bb76..0790832f 100644
--- a/src/classes/luaAPI.cpp
+++ b/src/classes/luaAPI.cpp
@@ -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);
diff --git a/src/classes/luaAPI.h b/src/classes/luaAPI.h
index 92cd7479..d8ef5ced 100644
--- a/src/classes/luaAPI.h
+++ b/src/classes/luaAPI.h
@@ -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);
@@ -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;
diff --git a/src/luaState.h b/src/luaState.h
index e188e47d..41c299a9 100644
--- a/src/luaState.h
+++ b/src/luaState.h
@@ -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);
diff --git a/src/metatables.cpp b/src/metatables.cpp
index 22bc5c3d..2eacf373 100644
--- a/src/metatables.cpp
+++ b/src/metatables.cpp
@@ -417,19 +417,44 @@ void LuaState::createObjectMetatable() {
luaL_newmetatable(L, "mt_Object");
LUA_METAMETHOD_TEMPLATE(L, -1, "__index", {
+ Ref lua_api = dynamic_cast(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(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);
@@ -437,7 +462,7 @@ void LuaState::createObjectMetatable() {
}
// 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;
@@ -447,20 +472,30 @@ void LuaState::createObjectMetatable() {
});
LUA_METAMETHOD_TEMPLATE(L, -1, "__newindex", {
+ Ref lua_api = dynamic_cast(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(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;
});