#include "script.h"
//#include "luna.h"
#include "luaentity_common.h"
+#include "content_sao.h" // For LuaEntitySAO
/*
TODO:
-- Global environment step function
+- Node type definition
- Random node triggers
-- Object network and client-side stuff
-- Named node types and dynamic id allocation
+- Object visual client-side stuff
+ - Blink effect
+ - Spritesheets and animation
+- Named node types and dynamic id allocation per MapBlock
- LuaNodeMetadata
blockdef.has_metadata = true/false
- Stores an inventory and stuff in a Settings object
}
};
+v3f readFloatPos(lua_State *L, int index)
+{
+ v3f pos;
+ lua_pushvalue(L, index); // Push pos
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, "x");
+ pos.X = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "y");
+ pos.Y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "z");
+ pos.Z = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_pop(L, 1); // Pop pos
+ pos *= BS; // Scale to internal format
+ return pos;
+}
+
+/*
+ Global functions
+*/
+
// Register new object prototype
// register_entity(name, prototype)
static int l_register_entity(lua_State *L)
return 0; /* number of results */
}
+// Register a global step function
+// register_globalstep(function)
+static int l_register_globalstep(lua_State *L)
+{
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ infostream<<"register_globalstep"<<std::endl;
+
+ lua_getglobal(L, "table");
+ lua_getfield(L, -1, "insert");
+ int table_insert = lua_gettop(L);
+ // Get minetest.registered_globalsteps
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_globalsteps");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int registered_globalsteps = lua_gettop(L);
+ // table.insert(registered_globalsteps, func)
+ lua_pushvalue(L, table_insert);
+ lua_pushvalue(L, registered_globalsteps);
+ lua_pushvalue(L, 1); // push function from argument 1
+ // Call insert
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s\n", lua_tostring(L, -1));
+
+ return 0; /* number of results */
+}
+
static const struct luaL_Reg minetest_f [] = {
{"register_entity", l_register_entity},
+ {"register_globalstep", l_register_globalstep},
{NULL, NULL}
};
-static int l_entity_set_deleted(lua_State *L)
-{
- return 0;
-}
+/*
+ LuaEntity functions
+*/
static const struct luaL_Reg minetest_entity_m [] = {
- {"set_deleted", l_entity_set_deleted},
{NULL, NULL}
};
+/*
+ Getters for stuff in main tables
+*/
+
static void objectref_get(lua_State *L, u16 id)
{
// Get minetest.object_refs[i]
return *(ObjectRef**)ud; // unbox pointer
}
+ static ServerActiveObject* getobject(ObjectRef *ref)
+ {
+ ServerActiveObject *co = ref->m_object;
+ return co;
+ }
+
+ static LuaEntitySAO* getluaobject(ObjectRef *ref)
+ {
+ ServerActiveObject *obj = getobject(ref);
+ if(obj == NULL)
+ return NULL;
+ if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
+ return NULL;
+ return (LuaEntitySAO*)obj;
+ }
+
// Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L) {
+ ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
+ //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
+ delete o;
+ return 0;
+ }
+ // remove(self)
static int l_remove(lua_State *L)
{
- ObjectRef *o = checkobject(L, 1);
- ServerActiveObject *co = o->m_object;
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
infostream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
co->m_removed = true;
return 0;
}
-
+
+ // getpos(self)
+ // returns: {x=num, y=num, z=num}
static int l_getpos(lua_State *L)
{
- ObjectRef *o = checkobject(L, 1);
- ServerActiveObject *co = o->m_object;
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
- infostream<<"ObjectRef::l_getpos(): id="<<co->getId()<<std::endl;
v3f pos = co->getBasePosition() / BS;
lua_newtable(L);
lua_pushnumber(L, pos.X);
lua_setfield(L, -2, "z");
return 1;
}
-
- static int gc_object(lua_State *L) {
- //ObjectRef *o = checkobject(L, 1);
- ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
- //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
- delete o;
+
+ // setpos(self, pos)
+ static int l_setpos(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ //LuaEntitySAO *co = getluaobject(ref);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // pos
+ v3f pos = readFloatPos(L, 2);
+ // Do it
+ co->setPos(pos);
+ return 0;
+ }
+
+ // moveto(self, pos, continuous=false)
+ static int l_moveto(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ //LuaEntitySAO *co = getluaobject(ref);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // pos
+ v3f pos = readFloatPos(L, 2);
+ // continuous
+ bool continuous = lua_toboolean(L, 3);
+ // Do it
+ co->moveTo(pos, continuous);
return 0;
}
+ // add_to_inventory(self, itemstring)
+ // returns: true if item was added, false otherwise
+ static int l_add_to_inventory(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ luaL_checkstring(L, 2);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // itemstring
+ const char *itemstring = lua_tostring(L, 2);
+ infostream<<"ObjectRef::l_add_to_inventory(): id="<<co->getId()
+ <<" itemstring=\""<<itemstring<<"\""<<std::endl;
+ // Do it
+ std::istringstream is(itemstring, std::ios::binary);
+ InventoryItem *item = InventoryItem::deSerialize(is);
+ bool fits = co->addToInventory(item);
+ // Return
+ lua_pushboolean(L, fits);
+ return 1;
+ }
+
public:
ObjectRef(ServerActiveObject *object):
m_object(object)
const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, remove),
method(ObjectRef, getpos),
+ method(ObjectRef, setpos),
+ method(ObjectRef, moveto),
+ method(ObjectRef, add_to_inventory),
{0,0}
};
+// Creates a new anonymous reference if id=0
+static void objectref_get_or_create(lua_State *L, ServerActiveObject *cobj)
+{
+ if(cobj->getId() == 0){
+ ObjectRef::create(L, cobj);
+ } else {
+ objectref_get(L, cobj->getId());
+ }
+}
+
/*
Main export function
*/
realitycheck(L);
assert(lua_checkstack(L, 20));
infostream<<"scriptapi_export"<<std::endl;
+ StackUnroller stack_unroller(L);
// Register global functions in table minetest
lua_newtable(L);
// Get the main minetest table
lua_getglobal(L, "minetest");
- // Add registered_entities table in minetest
+ // Add tables to minetest
+
+ /*lua_newtable(L);
+ lua_setfield(L, -2, "registered_blocks");*/
+
lua_newtable(L);
lua_setfield(L, -2, "registered_entities");
- // Add object_refs table in minetest
+ lua_newtable(L);
+ lua_setfield(L, -2, "registered_globalsteps");
+
lua_newtable(L);
lua_setfield(L, -2, "object_refs");
- // Add luaentities table in minetest
lua_newtable(L);
lua_setfield(L, -2, "luaentities");
- // Load and run some base Lua stuff
- /*script_load(L, (porting::path_data + DIR_DELIM + "scripts"
- + DIR_DELIM + "base.lua").c_str());*/
-
- // Create entity reference metatable
- //luaL_newmetatable(L, "minetest.entity_reference");
- //lua_pop(L, 1);
-
// Create entity prototype
luaL_newmetatable(L, "minetest.entity");
// metatable.__index = metatable
realitycheck(L);
assert(lua_checkstack(L, 20));
infostream<<"scriptapi_add_environment"<<std::endl;
+ StackUnroller stack_unroller(L);
// Create EnvRef on stack
EnvRef::create(L, env);
luaL_checktype(L, -1, LUA_TTABLE);
lua_pushvalue(L, envref);
lua_setfield(L, -2, "env");
-
- // pop minetest and envref
- lua_pop(L, 2);
}
+#if 0
// Dump stack top with the dump2 function
static void dump2(lua_State *L, const char *name)
{
if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s\n", lua_tostring(L, -1));
}
+#endif
/*
object_reference
realitycheck(L);
assert(lua_checkstack(L, 20));
infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
+ StackUnroller stack_unroller(L);
// Create object on stack
ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
lua_pushnumber(L, cobj->getId()); // Push id
lua_pushvalue(L, object); // Copy object to top of stack
lua_settable(L, objectstable);
-
- // pop object_refs, minetest and the object
- lua_pop(L, 3);
}
void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
realitycheck(L);
assert(lua_checkstack(L, 20));
infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
+ StackUnroller stack_unroller(L);
// Get minetest.object_refs table
lua_getglobal(L, "minetest");
lua_pushnumber(L, cobj->getId()); // Push id
lua_pushnil(L);
lua_settable(L, objectstable);
-
- // pop object_refs, minetest
- lua_pop(L, 2);
+}
+
+/*
+ environment
+*/
+
+void scriptapi_environment_step(lua_State *L, float dtime)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.registered_globalsteps
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_globalsteps");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int table = lua_gettop(L);
+ // Foreach
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ // Call function
+ lua_pushnumber(L, dtime);
+ if(lua_pcall(L, 1, 0, 0))
+ script_error(L, "error: %s\n", lua_tostring(L, -1));
+ // value removed, keep key for next iteration
+ }
}
/*
luaentity
*/
-void scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
+bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
const char *init_state)
{
realitycheck(L);
lua_pushstring(L, name);
lua_gettable(L, -2);
// Should be a table, which we will use as a prototype
- luaL_checktype(L, -1, LUA_TTABLE);
+ //luaL_checktype(L, -1, LUA_TTABLE);
+ if(lua_type(L, -1) != LUA_TTABLE){
+ errorstream<<"LuaEntity name \""<<name<<"\" not defined"<<std::endl;
+ return false;
+ }
int prototype_table = lua_gettop(L);
//dump2(L, "prototype_table");
if(lua_pcall(L, 1, 0, 0))
script_error(L, "error running function %s:on_activate: %s\n",
name, lua_tostring(L, -1));*/
+
+ return true;
}
void scriptapi_luaentity_rm(lua_State *L, u16 id)
}
}
lua_pop(L, 1);
+
}
void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1));
}
-void scriptapi_luaentity_rightclick_player(lua_State *L, u16 id,
- const char *playername)
+// Calls entity:on_punch(ObjectRef puncher)
+void scriptapi_luaentity_punch(lua_State *L, u16 id,
+ ServerActiveObject *puncher)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
luaentity_get(L, id);
int object = lua_gettop(L);
// State: object is at top of stack
- // Get step function
+ // Get function
+ lua_getfield(L, -1, "on_punch");
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, object); // self
+ objectref_get_or_create(L, puncher); // Clicker reference
+ // Call with 2 arguments, 0 results
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
+}
+
+// Calls entity:on_rightclick(ObjectRef clicker)
+void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
+ ServerActiveObject *clicker)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.luaentities[id]
+ luaentity_get(L, id);
+ int object = lua_gettop(L);
+ // State: object is at top of stack
+ // Get function
lua_getfield(L, -1, "on_rightclick");
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
- // Call with 1 arguments, 0 results
- if(lua_pcall(L, 1, 0, 0))
- script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1));
+ objectref_get_or_create(L, clicker); // Clicker reference
+ // Call with 2 arguments, 0 results
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error running function 'on_rightclick': %s\n", lua_tostring(L, -1));
}