Skip to content

Commit

Permalink
lua - inherit
Browse files Browse the repository at this point in the history
  • Loading branch information
nem0 committed Nov 15, 2024
1 parent 39e2360 commit 3a3ea53
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 84 deletions.
29 changes: 3 additions & 26 deletions data/maps/demo/button.lua
Original file line number Diff line number Diff line change
@@ -1,35 +1,15 @@
local co = require "scripts/coroutine"
local lumix_math = require "scripts/math"
local interactive = false

label = {}
player = {}
cubeA = {}
cubeB = {}
sphereA = {}
sphereB = {}
sound = -1
local cubeA_pos = {}
local cubeB_pos = {}
local sphereA_pos = {}
local sphereB_pos = {}
local interactive = false

Editor.setPropertyType(this, "label", Editor.ENTITY_PROPERTY)
Editor.setPropertyType(this, "player", Editor.ENTITY_PROPERTY)
Editor.setPropertyType(this, "cubeA", Editor.ENTITY_PROPERTY)
Editor.setPropertyType(this, "cubeB", Editor.ENTITY_PROPERTY)
Editor.setPropertyType(this, "sphereA", Editor.ENTITY_PROPERTY)
Editor.setPropertyType(this, "sphereB", Editor.ENTITY_PROPERTY)
Editor.setPropertyType(this, "sound", Editor.RESOURCE_PROPERTY, "clip")

function start()
-- remember initial positions so we can reset them when button is pressed
cubeA_pos = cubeA.position
cubeB_pos = cubeB.position
sphereA_pos = sphereA.position
sphereB_pos = sphereB.position
end

function playSound(sound)
local path = this.world.lua_script:getResourcePath(sound)
this.world:getModule("audio"):play(this, path, false)
Expand Down Expand Up @@ -77,11 +57,7 @@ function onInputEvent(event : InputEvent)
co.lerpVec3(this, "local_position", {0, 0, 0}, {0, 0, 0.1}, 0.1)
end
)
-- reset objects' positions
cubeA.position = cubeA_pos
cubeB.position = cubeB_pos
sphereA.position = sphereA_pos
sphereB.position = sphereB_pos
buttonPressed()
-- play a sound and wait a bit
playSound(sound)
co.wait(0.1)
Expand All @@ -94,3 +70,4 @@ function onInputEvent(event : InputEvent)
return false
end)
end

8 changes: 0 additions & 8 deletions data/maps/demo/button_press.anp

This file was deleted.

Binary file modified data/maps/demo/demo.unv
Binary file not shown.
32 changes: 32 additions & 0 deletions data/maps/demo/physics_test_button.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
inherit "maps/demo/button"

cubeA = {}
cubeB = {}
sphereA = {}
sphereB = {}

local cubeA_pos = {}
local cubeB_pos = {}
local sphereA_pos = {}
local sphereB_pos = {}

Editor.setPropertyType(this, "cubeA", Editor.ENTITY_PROPERTY)
Editor.setPropertyType(this, "cubeB", Editor.ENTITY_PROPERTY)
Editor.setPropertyType(this, "sphereA", Editor.ENTITY_PROPERTY)
Editor.setPropertyType(this, "sphereB", Editor.ENTITY_PROPERTY)

function buttonPressed()
-- reset objects' positions
cubeA.position = cubeA_pos
cubeB.position = cubeB_pos
sphereA.position = sphereA_pos
sphereB.position = sphereB_pos
end

function start()
-- remember initial positions so we can reset them when button is pressed
cubeA_pos = cubeA.position
cubeB_pos = cubeB.position
sphereA_pos = sphereA.position
sphereB_pos = sphereB.position
end
20 changes: 20 additions & 0 deletions data/maps/demo/spawn_nav_agent_button.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
inherit "maps/demo/button"

spawn_point = {}
Editor.setPropertyType(this, "spawn_point", Editor.ENTITY_PROPERTY)

function buttonPressed()
local e = this.world:createEntityEx {
position = spawn_point.position,
scale = {0.3, 1.5, 0.3},
navmesh_agent = {},
lua_script = {
-- path = "data/scripts/nav_agent.lua"
},
model_instance = {
source = "models/shapes/cylinder.fbx"
}

}

end
12 changes: 9 additions & 3 deletions src/lua/editor/lua_script_plugins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,8 @@ static bool gatherRequires(Span<const u8> src, Lumix::Array<Path>& dependencies,
const char* path = LuaWrapper::checkArg<const char*>(L, 1);
Path lua_path(path, ".lua");
deps->push(lua_path);
return 0;
lua_newtable(L);
return 1;
};

auto index_fn = [](lua_State* L) -> int {
Expand All @@ -618,10 +619,13 @@ static bool gatherRequires(Span<const u8> src, Lumix::Array<Path>& dependencies,
return 1;
};

lua_pushcclosure(L, reg_dep, "require", 0);
lua_pushcfunction(L, reg_dep, "inherit");
lua_setfield(L, LUA_GLOBALSINDEX, "inherit");

lua_pushcfunction(L, reg_dep, "require");
lua_setfield(L, LUA_GLOBALSINDEX, "require");

lua_pushcclosure(L, reg_dep, "dofile", 0);
lua_pushcfunction(L, reg_dep, "dofile");
lua_setfield(L, LUA_GLOBALSINDEX, "dofile");

lua_pushlightuserdata(L, &dependencies);
Expand All @@ -639,6 +643,8 @@ static bool gatherRequires(Span<const u8> src, Lumix::Array<Path>& dependencies,
lua_setfield(L, -2, "require"); // metatable, new_g
lua_getglobal(L, "dofile"); // metatable, new_g, require
lua_setfield(L, -2, "dofile"); // metatable, new_g
lua_getglobal(L, "inherit"); // metatable, new_g, require
lua_setfield(L, -2, "inherit"); // metatable, new_g

lua_insert(L, -2); // new_g, meta
lua_setmetatable(L, -2); //new_g
Expand Down
2 changes: 2 additions & 0 deletions src/lua/lua_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1205,6 +1205,8 @@ void registerEngineAPI(lua_State* L, Engine* engine)
ent.position = v
elseif k == "rotation" then
ent.position = v
elseif k == "scale" then
ent.scale = v
else
local c = ent:createComponent(k)
for k2, v2 in pairs(v) do
Expand Down
132 changes: 85 additions & 47 deletions src/lua/lua_script_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3051,26 +3051,60 @@ struct LuaProperties : reflection::DynamicProperties {

static int finishrequire(lua_State* L)
{
if (lua_isstring(L, -1))
lua_error(L);
if (lua_isstring(L, -1))
lua_error(L);

return 1;
}

static int LUA_inherit(lua_State* L) {
LuaWrapper::DebugGuard guard(L);
const char* name = luaL_checkstring(L, 1);
Engine* engine = LuaWrapper::getClosureObject<Engine>(L);
Path path(name, ".lua");
LuaScript* dep = engine->getResourceManager().load<LuaScript>(path);
if (!dep->isReady()) {
ASSERT(false); // inherited-d files should be registered as dependencies, so it should be impossible to get here
luaL_argerrorL(L, 1, "failed to inherit file, it's not ready");
}

const StringView src = dep->getSourceCode();
bool errors = LuaWrapper::luaL_loadbuffer(L, src.begin, src.size(), name);
if (errors) {
lua_error(L);
return 0;
}

// set the environment of the inherited file to the environment of the calling function
lua_Debug ar;
lua_getinfo(L, 1, "f", &ar); // fn, cur fn
lua_getfenv(L, -1); // fn, cur fn, env
lua_setfenv(L, -3); // fn, cur fn
lua_pop(L, 1); // fn

errors = lua_pcall(L, 0, 0, 0) != 0;
if (errors) {
lua_error(L);
return 0;
}

return 1;
return 0;
}

static int LUA_require(lua_State* L) {
const char* name = luaL_checkstring(L, 1);
const char* name = luaL_checkstring(L, 1);

luaL_findtable(L, LUA_REGISTRYINDEX, "_MODULES", 1);
luaL_findtable(L, LUA_REGISTRYINDEX, "_MODULES", 1);

// return the module from the cache
lua_getfield(L, -1, name);
if (!lua_isnil(L, -1))
{
// L stack: _MODULES result
return finishrequire(L);
}
// return the module from the cache
lua_getfield(L, -1, name);
if (!lua_isnil(L, -1))
{
// L stack: _MODULES result
return finishrequire(L);
}

lua_pop(L, 1);
lua_pop(L, 1);

Engine* engine = LuaWrapper::getClosureObject<Engine>(L);
Path path(name, ".lua");
Expand All @@ -3080,16 +3114,16 @@ static int LUA_require(lua_State* L) {
luaL_argerrorL(L, 1, "error loading module");
}

// module needs to run in a new thread, isolated from the rest
// note: we create ML on main thread so that it doesn't inherit environment of L
lua_State* GL = lua_mainthread(L);
lua_State* ML = lua_newthread(GL);
lua_xmove(GL, L, 1);
// module needs to run in a new thread, isolated from the rest
// note: we create ML on main thread so that it doesn't inherit environment of L
lua_State* GL = lua_mainthread(L);
lua_State* ML = lua_newthread(GL);
lua_xmove(GL, L, 1);

// new thread needs to have the globals sandboxed
luaL_sandboxthread(ML);
// new thread needs to have the globals sandboxed
luaL_sandboxthread(ML);

// now we can compile & run module on the new thread
// now we can compile & run module on the new thread
size_t bytecode_size;
char* bytecode = luau_compile((const char*)dep->getSourceCode().begin, dep->getSourceCode().size(), nullptr, &bytecode_size);
if (bytecode_size == 0) {
Expand All @@ -3098,35 +3132,35 @@ static int LUA_require(lua_State* L) {
lua_error(L);
}

if (luau_load(ML, name, bytecode, bytecode_size, 0) == 0)
{
int status = lua_resume(ML, L, 0);

if (status == 0)
{
if (lua_gettop(ML) == 0)
lua_pushstring(ML, "module must return a value");
else if (!lua_istable(ML, -1) && !lua_isfunction(ML, -1))
lua_pushstring(ML, "module must return a table or function");
}
else if (status == LUA_YIELD)
{
lua_pushstring(ML, "module can not yield");
}
else if (!lua_isstring(ML, -1))
{
lua_pushstring(ML, "unknown error while running module");
}
}
if (luau_load(ML, name, bytecode, bytecode_size, 0) == 0)
{
int status = lua_resume(ML, L, 0);

if (status == 0)
{
if (lua_gettop(ML) == 0)
lua_pushstring(ML, "module must return a value");
else if (!lua_istable(ML, -1) && !lua_isfunction(ML, -1))
lua_pushstring(ML, "module must return a table or function");
}
else if (status == LUA_YIELD)
{
lua_pushstring(ML, "module can not yield");
}
else if (!lua_isstring(ML, -1))
{
lua_pushstring(ML, "unknown error while running module");
}
}
free(bytecode);

// there's now a return value on top of ML; L stack: _MODULES ML
lua_xmove(ML, L, 1);
lua_pushvalue(L, -1);
lua_setfield(L, -4, name);
// there's now a return value on top of ML; L stack: _MODULES ML
lua_xmove(ML, L, 1);
lua_pushvalue(L, -1);
lua_setfield(L, -4, name);

// L stack: _MODULES ML result
return finishrequire(L);
// L stack: _MODULES ML result
return finishrequire(L);
}

static int LUA_dofile(lua_State* L) {
Expand Down Expand Up @@ -3218,6 +3252,10 @@ LuaScriptSystemImpl::LuaScriptSystemImpl(Engine& engine)
lua_pushcclosure(L, &LUA_require, "require", 1);
lua_setglobal(L, "require");

lua_pushlightuserdata(L, &engine);
lua_pushcclosure(L, &LUA_inherit, "inherit", 1);
lua_setglobal(L, "inherit");

lua_pushlightuserdata(L, &engine);
lua_pushcclosure(L, &LUA_dofile, "dofile", 1);
lua_setglobal(L, "dofile");
Expand Down

0 comments on commit 3a3ea53

Please sign in to comment.