diff options
author | Perttu Ahola <celeron55@gmail.com> | 2011-11-21 11:15:15 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2011-11-29 19:13:49 +0200 |
commit | 0ce0c8fcfba655c8db5f53ce8e3ab7adfa59768a (patch) | |
tree | 7491e7b68e0cd4c43a19de54b7352d4d9e0de778 | |
parent | 811ac5ac3ae6de6ee152f724aaf392ac73c3ed40 (diff) | |
download | minetest-0ce0c8fcfba655c8db5f53ce8e3ab7adfa59768a.tar.gz minetest-0ce0c8fcfba655c8db5f53ce8e3ab7adfa59768a.tar.bz2 minetest-0ce0c8fcfba655c8db5f53ce8e3ab7adfa59768a.zip |
Improve LuaEntity velocity/acceleration handling (by kahrl); implement staticdata interface to Lua
-rw-r--r-- | data/mods/default/init.lua | 50 | ||||
-rw-r--r-- | src/content_cao.cpp | 9 | ||||
-rw-r--r-- | src/content_cao.h | 2 | ||||
-rw-r--r-- | src/content_sao.cpp | 24 | ||||
-rw-r--r-- | src/content_sao.h | 4 | ||||
-rw-r--r-- | src/scriptapi.cpp | 192 | ||||
-rw-r--r-- | src/scriptapi.h | 6 | ||||
-rw-r--r-- | src/server.cpp | 26 |
8 files changed, 234 insertions, 79 deletions
diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua index 949816c9e..a8a1d08f4 100644 --- a/data/mods/default/init.lua +++ b/data/mods/default/init.lua @@ -101,6 +101,7 @@ end -- - add_node(pos, node) -- - remove_node(pos) -- - get_node(pos) +-- - add_luaentity(pos, name) -- -- ObjectRef is basically ServerActiveObject. -- ObjectRef methods: @@ -114,6 +115,12 @@ end -- - Functions receive a "luaentity" as self: -- - It has the member .object, which is an ObjectRef pointing to the object -- - The original prototype stuff is visible directly via a metatable +-- - Callbacks: +-- - on_activate(self, staticdata) +-- - on_step(self, dtime) +-- - on_punch(self, hitter) +-- - on_rightclick(self, clicker) +-- - get_staticdata(self): return string -- -- MapNode representation: -- {name="name", param1=num, param2=num} @@ -654,11 +661,20 @@ local TNT = { --textures = {"mese.png^[forcesingle"}, -- Initial value for our timer timer = 0, + -- Number of punches required to defuse + health = 3, -- List names of state variables, for serializing object state -- (NOTE: not implemented and implementation will not be like this) -- state_variables = {"timer"}, } +-- Called when a TNT object is created +function TNT:on_activate(staticdata) + print("TNT:on_activate()") + self.object:setvelocity({x=0, y=1, z=0}) + self.object:setacceleration({x=0, y=-5, z=0}) +end + -- Called periodically function TNT:on_step(dtime) --print("TNT:on_step()") @@ -667,15 +683,18 @@ end -- Called when object is punched function TNT:on_punch(hitter) print("TNT:on_punch()") - self.object:remove() - hitter:add_to_inventory("CraftItem testobject1 1") + self.health = self.health - 1 + if self.health <= 0 then + self.object:remove() + hitter:add_to_inventory("NodeItem TNT 1") + end end -- Called when object is right-clicked function TNT:on_rightclick(clicker) - pos = self.object:getpos() - pos = {x=pos.x, y=pos.y+0.1, z=pos.z} - self.object:moveto(pos, false) + --pos = self.object:getpos() + --pos = {x=pos.x, y=pos.y+0.1, z=pos.z} + --self.object:moveto(pos, false) end print("TNT dump: "..dump(TNT)) @@ -694,16 +713,13 @@ function register_falling_node(nodename, texture) visual = "cube", textures = {texture,texture,texture,texture,texture,texture}, -- State - fallspeed = 0, -- Methods on_step = function(self, dtime) - -- Apply gravity manually - self.fallspeed = self.fallspeed + dtime * 5 - fp = self.object:getpos() - fp.y = fp.y - self.fallspeed * dtime - self.object:moveto(fp, true) + -- Set gravity + self.object:setacceleration({x=0, y=-10, z=0}) -- Turn to actual sand when collides to ground or just move - bcp = {x=fp.x, y=fp.y-0.5, z=fp.z} -- Position of bottom center point + pos = self.object:getpos() + bcp = {x=pos.x, y=pos.y-0.5, z=pos.z} -- Position of bottom center point bcn = minetest.env:get_node(bcp) if bcn.name ~= "air" then -- Turn to a sand node @@ -772,6 +788,16 @@ function on_dignode(p, node) end minetest.register_on_dignode(on_dignode) +function on_punchnode(p, node) + print("on_punchnode") + if node.name == "TNT" then + minetest.env:remove_node(p) + minetest.env:add_luaentity(p, "TNT") + nodeupdate(p) + end +end +minetest.register_on_punchnode(on_punchnode) + -- -- Done, print some random stuff -- diff --git a/src/content_cao.cpp b/src/content_cao.cpp index ca9e22811..f5ef3fb07 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -1278,6 +1278,8 @@ LuaEntityCAO::LuaEntityCAO(IGameDef *gamedef): m_meshnode(NULL), m_spritenode(NULL), m_position(v3f(0,10*BS,0)), + m_velocity(v3f(0,0,0)), + m_acceleration(v3f(0,0,0)), m_yaw(0), m_prop(new LuaEntityProperties) { @@ -1455,6 +1457,9 @@ void LuaEntityCAO::updateNodePos() void LuaEntityCAO::step(float dtime, ClientEnvironment *env) { + m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration; + m_velocity += dtime * m_acceleration; + pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time); pos_translator.translate(dtime); updateNodePos(); } @@ -1471,6 +1476,10 @@ void LuaEntityCAO::processMessage(const std::string &data) bool do_interpolate = readU8(is); // pos m_position = readV3F1000(is); + // velocity + m_velocity = readV3F1000(is); + // acceleration + m_acceleration = readV3F1000(is); // yaw m_yaw = readF1000(is); // is_end_position (for interpolation) diff --git a/src/content_cao.h b/src/content_cao.h index 3a3fbbcda..3f6b9d877 100644 --- a/src/content_cao.h +++ b/src/content_cao.h @@ -428,6 +428,8 @@ private: scene::IMeshSceneNode *m_meshnode; scene::MyBillboardSceneNode *m_spritenode; v3f m_position; + v3f m_velocity; + v3f m_acceleration; float m_yaw; struct LuaEntityProperties *m_prop; SmoothTranslator pos_translator; diff --git a/src/content_sao.cpp b/src/content_sao.cpp index dc112275f..986e3f15f 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -1550,6 +1550,8 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, m_init_state(state), m_registered(false), m_prop(new LuaEntityProperties), + m_velocity(0,0,0), + m_acceleration(0,0,0), m_yaw(0), m_last_sent_yaw(0), m_last_sent_position(0,0,0), @@ -1610,6 +1612,9 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) { m_last_sent_position_timer += dtime; + m_base_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration; + m_velocity += dtime * m_acceleration; + if(m_registered){ lua_State *L = m_env->getLua(); scriptapi_luaentity_step(L, m_id, dtime); @@ -1618,6 +1623,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) if(send_recommended == false) return; + // TODO: force send when velocity/acceleration changes enough float minchange = 0.2*BS; if(m_last_sent_position_timer > 1.0){ minchange = 0.01*BS; @@ -1659,7 +1665,7 @@ std::string LuaEntitySAO::getStaticData() // state if(m_registered){ lua_State *L = m_env->getLua(); - std::string state = scriptapi_luaentity_get_state(L, m_id); + std::string state = scriptapi_luaentity_get_staticdata(L, m_id); os<<serializeLongString(state); } else { os<<serializeLongString(m_init_state); @@ -1709,6 +1715,16 @@ float LuaEntitySAO::getMinimumSavedMovement() return 0.1 * BS; } +void LuaEntitySAO::setVelocity(v3f velocity) +{ + m_velocity = velocity; +} + +void LuaEntitySAO::setAcceleration(v3f acceleration) +{ + m_acceleration = acceleration; +} + void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) { m_last_sent_move_precision = m_base_position.getDistanceFrom( @@ -1716,6 +1732,8 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) m_last_sent_position_timer = 0; m_last_sent_yaw = m_yaw; m_last_sent_position = m_base_position; + //m_last_sent_velocity = m_velocity; + //m_last_sent_acceleration = m_acceleration; float update_interval = m_env->getSendRecommendedInterval(); @@ -1727,6 +1745,10 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) writeU8(os, do_interpolate); // pos writeV3F1000(os, m_base_position); + // velocity + writeV3F1000(os, m_velocity); + // acceleration + writeV3F1000(os, m_acceleration); // yaw writeF1000(os, m_yaw); // is_end_position (for interpolation) diff --git a/src/content_sao.h b/src/content_sao.h index cd7474960..04d33647e 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -216,6 +216,8 @@ public: void setPos(v3f pos); void moveTo(v3f pos, bool continuous); float getMinimumSavedMovement(); + void setVelocity(v3f velocity); + void setAcceleration(v3f acceleration); private: void sendPosition(bool do_interpolate, bool is_movement_end); @@ -224,6 +226,8 @@ private: bool m_registered; struct LuaEntityProperties *m_prop; + v3f m_velocity; + v3f m_acceleration; float m_yaw; float m_last_sent_yaw; v3f m_last_sent_position; diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index a18c144d3..02db2ce02 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -61,6 +61,7 @@ TODO: meta.set("owner", playername) meta.get("owner") - Item definition (actually, only CraftItem) +- (not scripting) Putting items in node metadata (virtual) */ static void stackDump(lua_State *L, std::ostream &o) @@ -424,24 +425,21 @@ static int l_register_craft(lua_State *L) return 0; /* number of results */ } -// Register a global step function -// register_globalstep(function) -static int l_register_globalstep(lua_State *L) +static int register_lua_callback(lua_State *L, const char *tablename) { 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"); + lua_getfield(L, -1, tablename); luaL_checktype(L, -1, LUA_TTABLE); - int registered_globalsteps = lua_gettop(L); + int registered = lua_gettop(L); // table.insert(registered_globalsteps, func) lua_pushvalue(L, table_insert); - lua_pushvalue(L, registered_globalsteps); + lua_pushvalue(L, registered); lua_pushvalue(L, 1); // push function from argument 1 // Call insert if(lua_pcall(L, 2, 0, 0)) @@ -450,54 +448,33 @@ static int l_register_globalstep(lua_State *L) return 0; /* number of results */ } +// Register a global step function +// register_globalstep(function) +static int l_register_globalstep(lua_State *L) +{ + infostream<<"register_globalstep"<<std::endl; + return register_lua_callback(L, "registered_globalsteps"); +} + // register_on_placenode(function) static int l_register_on_placenode(lua_State *L) { - luaL_checktype(L, 1, LUA_TFUNCTION); infostream<<"register_on_placenode"<<std::endl; - - lua_getglobal(L, "table"); - lua_getfield(L, -1, "insert"); - int table_insert = lua_gettop(L); - // Get minetest.registered_on_placenodes - lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "registered_on_placenodes"); - luaL_checktype(L, -1, LUA_TTABLE); - int registered_on_placenodes = lua_gettop(L); - // table.insert(registered_on_placenodes, func) - lua_pushvalue(L, table_insert); - lua_pushvalue(L, registered_on_placenodes); - 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 */ + return register_lua_callback(L, "registered_on_placenodes"); } // register_on_dignode(function) static int l_register_on_dignode(lua_State *L) { - luaL_checktype(L, 1, LUA_TFUNCTION); infostream<<"register_on_dignode"<<std::endl; + return register_lua_callback(L, "registered_on_dignodes"); +} - lua_getglobal(L, "table"); - lua_getfield(L, -1, "insert"); - int table_insert = lua_gettop(L); - // Get minetest.registered_on_dignodes - lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "registered_on_dignodes"); - luaL_checktype(L, -1, LUA_TTABLE); - int registered_on_dignodes = lua_gettop(L); - // table.insert(registered_on_dignodes, func) - lua_pushvalue(L, table_insert); - lua_pushvalue(L, registered_on_dignodes); - 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 */ +// register_on_punchnode(function) +static int l_register_on_punchnode(lua_State *L) +{ + infostream<<"register_on_punchnode"<<std::endl; + return register_lua_callback(L, "registered_on_punchnodes"); } static const struct luaL_Reg minetest_f [] = { @@ -508,6 +485,7 @@ static const struct luaL_Reg minetest_f [] = { {"register_globalstep", l_register_globalstep}, {"register_on_placenode", l_register_on_placenode}, {"register_on_dignode", l_register_on_dignode}, + {"register_on_punchnode", l_register_on_punchnode}, {NULL, NULL} }; @@ -583,8 +561,9 @@ private: // content MapNode n = readnode(L, 3, env->getGameDef()->ndef()); // Do it - env->getMap().addNodeWithEvent(pos, n); - return 0; + bool succeeded = env->getMap().addNodeWithEvent(pos, n); + lua_pushboolean(L, succeeded); + return 1; } // EnvRef:remove_node(pos) @@ -598,8 +577,9 @@ private: // pos v3s16 pos = readpos(L, 2); // Do it - env->getMap().removeNodeWithEvent(pos); - return 0; + bool succeeded = env->getMap().removeNodeWithEvent(pos); + lua_pushboolean(L, succeeded); + return 1; } // EnvRef:get_node(pos) @@ -810,6 +790,32 @@ private: return 0; } + // setvelocity(self, velocity) + static int l_setvelocity(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // pos + v3f pos = readFloatPos(L, 2); + // Do it + co->setVelocity(pos); + return 0; + } + + // setacceleration(self, acceleration) + static int l_setacceleration(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // pos + v3f pos = readFloatPos(L, 2); + // Do it + co->setAcceleration(pos); + return 0; + } + // add_to_inventory(self, itemstring) // returns: true if item was added, false otherwise static int l_add_to_inventory(lua_State *L) @@ -902,6 +908,8 @@ const luaL_reg ObjectRef::methods[] = { method(ObjectRef, getpos), method(ObjectRef, setpos), method(ObjectRef, moveto), + method(ObjectRef, setvelocity), + method(ObjectRef, setacceleration), method(ObjectRef, add_to_inventory), {0,0} }; @@ -958,6 +966,9 @@ void scriptapi_export(lua_State *L, Server *server) lua_setfield(L, -2, "registered_on_dignodes"); lua_newtable(L); + lua_setfield(L, -2, "registered_on_punchnodes"); + + lua_newtable(L); lua_setfield(L, -2, "object_refs"); lua_newtable(L); @@ -1159,12 +1170,45 @@ void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode) } } +void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode oldnode) +{ + realitycheck(L); + assert(lua_checkstack(L, 20)); + //infostream<<"scriptapi_environment_on_punchnode"<<std::endl; + StackUnroller stack_unroller(L); + + // Get server from registry + lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); + Server *server = (Server*)lua_touserdata(L, -1); + // And get the writable node definition manager from the server + IWritableNodeDefManager *ndef = + server->getWritableNodeDefManager(); + + // Get minetest.registered_on_punchnodes + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "registered_on_punchnodes"); + 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 + pushpos(L, p); + pushnode(L, oldnode, ndef); + if(lua_pcall(L, 2, 0, 0)) + script_error(L, "error: %s\n", lua_tostring(L, -1)); + // value removed, keep key for next iteration + } +} + /* luaentity */ bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name, - const char *init_state) + const std::string &staticdata) { realitycheck(L); assert(lua_checkstack(L, 20)); @@ -1172,8 +1216,6 @@ bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name, <<name<<"\""<<std::endl; StackUnroller stack_unroller(L); - // Create object as a dummy string (TODO: Create properly) - // Get minetest.registered_entities[name] lua_getglobal(L, "minetest"); lua_getfield(L, -1, "registered_entities"); @@ -1213,17 +1255,19 @@ bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name, lua_pushvalue(L, object); // Copy object to top of stack lua_settable(L, -3); - // This callback doesn't really make sense - /*// Get on_activate function + // Get on_activate function lua_pushvalue(L, object); lua_getfield(L, -1, "on_activate"); - 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 %s:on_activate: %s\n", - name, lua_tostring(L, -1));*/ - + if(!lua_isnil(L, -1)){ + luaL_checktype(L, -1, LUA_TFUNCTION); + lua_pushvalue(L, object); // self + lua_pushlstring(L, staticdata.c_str(), staticdata.size()); + // Call with 2 arguments, 0 results + if(lua_pcall(L, 2, 0, 0)) + script_error(L, "error running function %s:on_activate: %s\n", + name, lua_tostring(L, -1)); + } + return true; } @@ -1247,13 +1291,33 @@ void scriptapi_luaentity_rm(lua_State *L, u16 id) lua_pop(L, 2); // pop luaentities, minetest } -std::string scriptapi_luaentity_get_state(lua_State *L, u16 id) +std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id) { realitycheck(L); assert(lua_checkstack(L, 20)); - infostream<<"scriptapi_luaentity_get_state: id="<<id<<std::endl; + infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl; + StackUnroller stack_unroller(L); + + // Get minetest.luaentities[id] + luaentity_get(L, id); + int object = lua_gettop(L); + + // Get get_staticdata function + lua_pushvalue(L, object); + lua_getfield(L, -1, "get_staticdata"); + if(lua_isnil(L, -1)) + return ""; + + luaL_checktype(L, -1, LUA_TFUNCTION); + lua_pushvalue(L, object); // self + // Call with 1 arguments, 1 results + if(lua_pcall(L, 1, 1, 0)) + script_error(L, "error running function get_staticdata: %s\n", + lua_tostring(L, -1)); - return ""; + size_t len=0; + const char *s = lua_tolstring(L, -1, &len); + return std::string(s, len); } void scriptapi_luaentity_get_properties(lua_State *L, u16 id, @@ -1344,7 +1408,7 @@ void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime) lua_pushnumber(L, dtime); // dtime // Call with 2 arguments, 0 results if(lua_pcall(L, 2, 0, 0)) - script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1)); + script_error(L, "error running function 'on_step': %s\n", lua_tostring(L, -1)); } // Calls entity:on_punch(ObjectRef puncher) diff --git a/src/scriptapi.h b/src/scriptapi.h index e7ff84039..46bc8233b 100644 --- a/src/scriptapi.h +++ b/src/scriptapi.h @@ -44,13 +44,15 @@ void scriptapi_environment_step(lua_State *L, float dtime); void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode); // After removing node void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode); +// When punching node +void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node); /* luaentity */ // Returns true if succesfully added into Lua; false otherwise. bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name, - const char *init_state); + const std::string &staticdata); void scriptapi_luaentity_rm(lua_State *L, u16 id); -std::string scriptapi_luaentity_get_state(lua_State *L, u16 id); +std::string scriptapi_luaentity_get_staticdata(lua_State *L, u16 id); void scriptapi_luaentity_get_properties(lua_State *L, u16 id, LuaEntityProperties *prop); void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime); diff --git a/src/server.cpp b/src/server.cpp index 467153031..ad80851dd 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2501,6 +2501,32 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) NOTE: This can be used in the future to check if somebody is cheating, by checking the timing. */ + bool cannot_punch_node = false; + + MapNode n(CONTENT_IGNORE); + + try + { + n = m_env->getMap().getNode(p_under); + } + catch(InvalidPositionException &e) + { + infostream<<"Server: Not punching: Node not found." + <<" Adding block to emerge queue." + <<std::endl; + m_emerge_queue.addBlock(peer_id, + getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK); + cannot_punch_node = true; + } + + if(cannot_punch_node) + return; + + /* + Run script hook + */ + scriptapi_environment_on_punchnode(m_lua, p_under, n); + } // action == 0 /* |