From 1320d07068f25ff23ea27e120983c006f75bec24 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 12 Nov 2011 17:37:14 +0200 Subject: [PATCH] Scripting WIP: dynamic object stuff --- data/scripts/default.lua | 2 + src/content_sao.cpp | 76 ++++++++++++++++++++++++++---------- src/content_sao.h | 19 ++++----- src/inventory.cpp | 29 +++++++------- src/inventory.h | 5 +-- src/player.cpp | 64 +++++++++++++++++++++++++++++++ src/player.h | 14 +++++-- src/scriptapi.cpp | 83 ++++++++++++++++++++++++++++++++++------ src/scriptapi.h | 6 ++- src/server.cpp | 34 ++++++++++------ src/serverobject.h | 37 +++++++++--------- 11 files changed, 274 insertions(+), 95 deletions(-) diff --git a/data/scripts/default.lua b/data/scripts/default.lua index 3ec6f8433..dcc58097b 100644 --- a/data/scripts/default.lua +++ b/data/scripts/default.lua @@ -162,6 +162,8 @@ 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") end -- Called when object is right-clicked diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 0abeb0ef0..eeb17bd30 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -237,14 +237,24 @@ InventoryItem * ItemSAO::createInventoryItem() } } -void ItemSAO::rightClick(Player *player) +void ItemSAO::punch(ServerActiveObject *puncher) +{ + InventoryItem *item = createInventoryItem(); + bool fits = puncher->addToInventory(item); + if(fits) + m_removed = true; + else + delete item; +} + +void ItemSAO::rightClick(ServerActiveObject *clicker) { infostream<<__FUNCTION_NAME<use(m_env, player); + bool to_be_deleted = item->use(m_env, clicker); if(to_be_deleted) m_removed = true; @@ -252,7 +262,7 @@ void ItemSAO::rightClick(Player *player) // Reflect changes to the item here m_inventorystring = item->getItemString(); - delete item; + delete item; // Delete temporary item } /* @@ -435,11 +445,15 @@ std::string RatSAO::getStaticData() return os.str(); } -InventoryItem* RatSAO::createPickedUpItem() +void RatSAO::punch(ServerActiveObject *puncher) { std::istringstream is("CraftItem rat 1", std::ios_base::binary); InventoryItem *item = InventoryItem::deSerialize(is); - return item; + bool fits = puncher->addToInventory(item); + if(fits) + m_removed = true; + else + delete item; } /* @@ -684,9 +698,17 @@ std::string Oerkki1SAO::getStaticData() return os.str(); } -u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir, - const std::string &playername) +void Oerkki1SAO::punch(ServerActiveObject *puncher) { + v3f dir = (getBasePosition() - puncher->getBasePosition()).normalize(); + + std::string toolname = ""; + InventoryItem *item = puncher->getWieldedItem(); + if(item && (std::string)item->getName() == "ToolItem"){ + ToolItem *titem = (ToolItem*)item; + toolname = titem->getToolName(); + } + m_speed_f += dir*12*BS; u16 amount = 5; @@ -704,7 +726,8 @@ u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir, if(toolname == "SteelPick") amount = 7; doDamage(amount); - return 65536/100; + + puncher->damageWieldedItem(65536/100); } void Oerkki1SAO::doDamage(u16 d) @@ -1351,10 +1374,20 @@ void MobV2SAO::step(float dtime, bool send_recommended) } } -u16 MobV2SAO::punch(const std::string &toolname, v3f dir, - const std::string &playername) +void MobV2SAO::punch(ServerActiveObject *puncher) { - assert(m_env); + v3f dir = (getBasePosition() - puncher->getBasePosition()).normalize(); + + std::string toolname = ""; + InventoryItem *item = puncher->getWieldedItem(); + if(item && (std::string)item->getName() == "ToolItem"){ + ToolItem *titem = (ToolItem*)item; + toolname = titem->getToolName(); + } + + // A quick hack; SAO description is player name for player + std::string playername = puncher->getDescription(); + Map *map = &m_env->getMap(); actionstream<damageWieldedItem(65536/100); } bool MobV2SAO::isPeaceful() @@ -1629,18 +1663,20 @@ InventoryItem* LuaEntitySAO::createPickedUpItem() return item; } -u16 LuaEntitySAO::punch(const std::string &toolname, v3f dir, - const std::string &playername) -{ - return 0; -} - -void LuaEntitySAO::rightClick(Player *player) +void LuaEntitySAO::punch(ServerActiveObject *puncher) { if(!m_registered) return; lua_State *L = m_env->getLua(); - scriptapi_luaentity_rightclick_player(L, m_id, player->getName()); + scriptapi_luaentity_punch(L, m_id, puncher); +} + +void LuaEntitySAO::rightClick(ServerActiveObject *clicker) +{ + if(!m_registered) + return; + lua_State *L = m_env->getLua(); + scriptapi_luaentity_rightclick(L, m_id, clicker); } void LuaEntitySAO::setPos(v3f pos) diff --git a/src/content_sao.h b/src/content_sao.h index 1d7239232..51911fe05 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -50,9 +50,8 @@ public: std::string getClientInitializationData(); std::string getStaticData(); InventoryItem* createInventoryItem(); - InventoryItem* createPickedUpItem(){return createInventoryItem();} - void rightClick(Player *player); - + void punch(ServerActiveObject *puncher); + void rightClick(ServerActiveObject *clicker); float getMinimumSavedMovement(){ return 0.1*BS; } private: std::string m_inventorystring; @@ -72,7 +71,7 @@ public: void step(float dtime, bool send_recommended); std::string getClientInitializationData(); std::string getStaticData(); - InventoryItem* createPickedUpItem(); + void punch(ServerActiveObject *puncher); private: bool m_is_active; IntervalLimiter m_inactive_interval; @@ -98,8 +97,7 @@ public: std::string getClientInitializationData(); std::string getStaticData(); InventoryItem* createPickedUpItem(){return NULL;} - u16 punch(const std::string &toolname, v3f dir, - const std::string &playername); + void punch(ServerActiveObject *puncher); bool isPeaceful(){return false;} private: void doDamage(u16 d); @@ -159,8 +157,7 @@ public: std::string getClientInitializationData(); void step(float dtime, bool send_recommended); InventoryItem* createPickedUpItem(){return NULL;} - u16 punch(const std::string &toolname, v3f dir, - const std::string &playername); + void punch(ServerActiveObject *puncher); bool isPeaceful(); private: void sendPosition(); @@ -214,10 +211,8 @@ public: std::string getClientInitializationData(); std::string getStaticData(); InventoryItem* createPickedUpItem(); - u16 punch(const std::string &toolname, v3f dir, - const std::string &playername); - void rightClick(Player *player); - + void punch(ServerActiveObject *puncher); + void rightClick(ServerActiveObject *clicker); void setPos(v3f pos); void moveTo(v3f pos, bool continuous); float getMinimumSavedMovement(); diff --git a/src/inventory.cpp b/src/inventory.cpp index 45646a69a..c9ba9b4e5 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -205,22 +205,23 @@ InventoryItem *CraftItem::createCookResult() const return item_craft_create_cook_result(m_subname); } -bool CraftItem::use(ServerEnvironment *env, Player *player) +bool CraftItem::use(ServerEnvironment *env, ServerActiveObject *user) { - if(item_craft_is_eatable(m_subname)) - { - u16 result_count = getCount() - 1; // Eat one at a time - s16 hp_change = item_craft_eat_hp_change(m_subname); - if(player->hp + hp_change > 20) - player->hp = 20; - else - player->hp += hp_change; + if(!item_craft_is_eatable(m_subname)) + return false; + + u16 result_count = getCount() - 1; // Eat one at a time + s16 hp_change = item_craft_eat_hp_change(m_subname); + s16 hp = user->getHP(); + hp += hp_change; + if(hp < 0) + hp = 0; + user->setHP(hp); + + if(result_count < 1) + return true; - if(result_count < 1) - return true; - else - setCount(result_count); - } + setCount(result_count); return false; } diff --git a/src/inventory.h b/src/inventory.h index 490cab73e..dc5b04ff7 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -36,7 +36,6 @@ with this program; if not, write to the Free Software Foundation, Inc., class ServerActiveObject; class ServerEnvironment; -class Player; class InventoryItem { @@ -117,7 +116,7 @@ public: // Called when item is right-clicked when lying on ground. // If returns true, item shall be deleted. virtual bool use(ServerEnvironment *env, - Player *player){return false;} + ServerActiveObject *user){return false;} protected: u16 m_count; @@ -263,7 +262,7 @@ public: bool isCookable() const; InventoryItem *createCookResult() const; - bool use(ServerEnvironment *env, Player *player); + bool use(ServerEnvironment *env, ServerActiveObject *user); /* Special methods diff --git a/src/player.cpp b/src/player.cpp index 396ce2494..f0a395f49 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -164,6 +164,70 @@ void Player::deSerialize(std::istream &is) inventory.deSerialize(is); } +/* + ServerRemotePlayer +*/ + +/* ServerActiveObject interface */ + +InventoryItem* ServerRemotePlayer::getWieldedItem() +{ + InventoryList *list = inventory.getList("main"); + if (list) + return list->getItem(m_selected_item); + return NULL; +} +void ServerRemotePlayer::damageWieldedItem(u16 amount) +{ + infostream<<"Damaging "<getItem(m_selected_item); + if(item && (std::string)item->getName() == "ToolItem"){ + ToolItem *titem = (ToolItem*)item; + bool weared_out = titem->addWear(amount); + if(weared_out) + list->deleteItem(m_selected_item); + } +} +bool ServerRemotePlayer::addToInventory(InventoryItem *item) +{ + infostream<<"Adding "<getName()<<" into "<getBool("creative_mode")){ + return false; + } + + // Skip if inventory has no free space + if(ilist->roomForItem(item) == false) + { + infostream<<"Player inventory has no free space"<addItem(item); + assert(!leftover); + + return true; +} +void ServerRemotePlayer::setHP(s16 hp_) +{ + hp = hp_; +} +s16 ServerRemotePlayer::getHP() +{ + return hp; +} + /* RemotePlayer */ diff --git a/src/player.h b/src/player.h index c3be07894..e6dfb8199 100644 --- a/src/player.h +++ b/src/player.h @@ -215,12 +215,20 @@ public: Player::setPosition(position); ServerActiveObject::setBasePosition(position); } + + /* ServerActiveObject interface */ - /* - ServerActiveObject interface - */ u8 getType() const {return ACTIVEOBJECT_TYPE_PLAYER;} + virtual std::string getDescription(){return getName();} + // Returns a reference + virtual InventoryItem* getWieldedItem(); + virtual void damageWieldedItem(u16 amount); + // If all fits, eats item and returns true. Otherwise returns false. + virtual bool addToInventory(InventoryItem *item); + virtual void setHP(s16 hp_); + virtual s16 getHP(); + private: }; diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index f8875c0e3..530c1719e 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -368,6 +368,14 @@ private: // Exported functions + // garbage collector + static int gc_object(lua_State *L) { + ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1)); + //infostream<<"ObjectRef::gc_object: o="<addToInventory(item); + // Return + lua_pushboolean(L, fits); + return 1; } public: @@ -502,9 +523,20 @@ const luaL_reg ObjectRef::methods[] = { 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 */ @@ -570,6 +602,7 @@ void scriptapi_add_environment(lua_State *L, ServerEnvironment *env) lua_setfield(L, -2, "env"); } +#if 0 // Dump stack top with the dump2 function static void dump2(lua_State *L, const char *name) { @@ -581,6 +614,7 @@ 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 @@ -815,8 +849,9 @@ 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)); @@ -827,12 +862,36 @@ void scriptapi_luaentity_rightclick_player(lua_State *L, u16 id, 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="<wieldItem(item_i); - // Left click, pick object up (usually) + // Left click, pick/punch if(button == 0) { + actionstream<getName()<<" punches object " + <getId()<punch(srp); + +#if 0 /* Try creating inventory item */ @@ -2371,6 +2384,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) SendInventory(player->peer_id); } } +#endif } // Right click, do something with object if(button == 1) @@ -2378,18 +2392,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) actionstream<getName()<<" right clicks object " <getId()<hp; - // Do stuff - obj->rightClick(player); - - // Send back stuff - if(player->hp != oldhp) - { - SendPlayerHP(player); - } + obj->rightClick(srp); } + + /* + Update player state to client + */ + SendPlayerHP(player); + UpdateCrafting(player->peer_id); + SendInventory(player->peer_id); } else if(command == TOSERVER_GROUND_ACTION) { diff --git a/src/serverobject.h b/src/serverobject.h index 66118cca0..7e767188a 100644 --- a/src/serverobject.h +++ b/src/serverobject.h @@ -71,6 +71,7 @@ public: /* Some more dynamic interface */ + virtual void setPos(v3f pos) { setBasePosition(pos); } // continuous: if true, object does not stop immediately at pos @@ -80,7 +81,11 @@ public: // saving to disk may be omitted virtual float getMinimumSavedMovement() { return 2.0*BS; } + + virtual bool isPeaceful(){return true;} + virtual std::string getDescription(){return "SAO";} + /* Step object in time. Messages added to messages are sent to client over network. @@ -106,26 +111,22 @@ public: */ virtual std::string getStaticData(){return "";} - /* - Item that the player gets when this object is picked up. - If NULL, object cannot be picked up. - */ - virtual InventoryItem* createPickedUpItem(){return NULL;} + virtual void punch(ServerActiveObject *puncher){} + virtual void rightClick(ServerActiveObject *clicker){} - /* - If the object doesn't return an item, this will be called. - Return value is tool wear. - */ - virtual u16 punch(const std::string &toolname, v3f dir, - const std::string &playername) - {return 0;} + // Returns a reference + virtual InventoryItem* getWieldedItem() + { return NULL; } + virtual void damageWieldedItem(u16 amount) + {} + // If all fits, eats item and returns true. Otherwise returns false. + virtual bool addToInventory(InventoryItem *item) + {return false;} + virtual void setHP(s16 hp) + {} + virtual s16 getHP() + {return 0;} - /* - */ - virtual void rightClick(Player *player){} - - virtual bool isPeaceful(){return true;} - /* Number of players which know about this object. Object won't be deleted until this is 0 to keep the id preserved for the right