Allow defining player's inventory form in Lua
authorPerttu Ahola <celeron55@gmail.com>
Thu, 19 Jul 2012 11:09:16 +0000 (14:09 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Thu, 19 Jul 2012 11:09:16 +0000 (14:09 +0300)
doc/lua_api.txt
games/minimal/mods/experimental/init.lua
src/client.cpp
src/clientserver.h
src/game.cpp
src/player.cpp
src/player.h
src/scriptapi.cpp
src/server.cpp
src/server.h

index 511ec7c8ed5a7699f123b9f4d064b82e00a8dd34..823b4b825eb3c60e8a01840ae9ccb7b74842e3a3 100644 (file)
@@ -759,6 +759,10 @@ minetest.register_on_respawnplayer(func(ObjectRef))
 ^ Called when player is to be respawned
 ^ Called _before_ repositioning of player occurs
 ^ return true in func to disable regular player placement
+minetest.register_on_joinplayer(func(ObjectRef))
+^ Called when a player joins the game
+minetest.register_on_leaveplayer(func(ObjectRef))
+^ Called when a player leaves the game
 minetest.register_on_chat_message(func(name, message))
 
 Other registration functions:
@@ -993,8 +997,8 @@ LuaEntitySAO-only: (no-op for other objects)
 - settexturemod(mod)
 - setsprite(p={x=0,y=0}, num_frames=1, framelength=0.2,
 -           select_horiz_by_yawpitch=false)
-- ^ Select sprite from spritesheet with optional animation and DM-style
--   texture selection based on yaw relative to camera
+  ^ Select sprite from spritesheet with optional animation and DM-style
+    texture selection based on yaw relative to camera
 - get_entity_name() (DEPRECATED: Will be removed in a future version)
 - get_luaentity()
 Player-only: (no-op for other objects)
@@ -1003,6 +1007,10 @@ Player-only: (no-op for other objects)
 - get_look_dir(): get camera direction as a unit vector
 - get_look_pitch(): pitch in radians
 - get_look_yaw(): yaw in radians (wraps around pretty randomly as of now)
+- set_inventory_formspec(formspec)
+  ^ Redefine player's inventory form
+  ^ Should usually be called in on_joinplayer
+- get_inventory_formspec() -> formspec string
 
 InvRef: Reference to an inventory
 methods:
index e8551034f629e1c0252a91c1b4caabbfcd73953c..fb331024606a9afe06567251af5773acd39d2cb6 100644 (file)
@@ -504,6 +504,16 @@ minetest.register_craft({
        }
 })
 
+--[[minetest.register_on_joinplayer(function(player)
+       minetest.after(3, function()
+               player:set_inventory_formspec("invsize[8,7.5;]"..
+                       "image[1,0.6;1,2;player.png]"..
+                       "list[current_player;main;0,3.5;8,4;]"..
+                       "list[current_player;craft;3,0;3,3;]"..
+                       "list[current_player;craftpreview;7,1;1,1;]")
+       end)
+end)]]
+
 minetest.log("experimental modname="..dump(minetest.get_current_modname()))
 minetest.log("experimental modpath="..dump(minetest.get_modpath("experimental")))
 minetest.log("experimental worldpath="..dump(minetest.get_worldpath()))
index 1327feb1f001f910a47cca8e97a57a54e2d6d845..fdfb49c843552c75821d405d8c64a9a8fd817e64 100644 (file)
@@ -1688,6 +1688,16 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                }
                infostream<<std::endl;
        }
+       else if(command == TOCLIENT_INVENTORY_FORMSPEC)
+       {
+               std::string datastring((char*)&data[2], datasize-2);
+               std::istringstream is(datastring, std::ios_base::binary);
+
+               // Store formspec in LocalPlayer
+               Player *player = m_env.getLocalPlayer();
+               assert(player != NULL);
+               player->inventory_formspec = deSerializeLongString(is);
+       }
        else
        {
                infostream<<"Client: Ignoring unknown command "
index 559fb5b15526e7643ffd887d445e3578643e8584..07e7b831d4b62388860aea3091e1490e2dd94449 100644 (file)
@@ -58,6 +58,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
        PROTOCOL_VERSION 11:
                TileDef in ContentFeatures
                Nodebox drawtype
+               Added after a release: TOCLIENT_INVENTORY_FORMSPEC
 */
 
 #define PROTOCOL_VERSION 11
@@ -308,6 +309,13 @@ enum ToClientCommand
                        u16 len
                        u8[len] privilege
        */
+
+       TOCLIENT_INVENTORY_FORMSPEC = 0x42,
+       /*
+               u16 command
+               u32 len
+               u8[len] formspec
+       */
 };
 
 enum ToServerCommand
index 98ffac3d56a30c94855cd6857a26eb453852edfc..b29d2d646693db0e3eed9d2cd20cd9ae029f64a3 100644 (file)
@@ -144,6 +144,22 @@ public:
        v3s16 m_p;
 };
 
+class PlayerInventoryFormSource: public IFormSource
+{
+public:
+       PlayerInventoryFormSource(Client *client):
+               m_client(client)
+       {
+       }
+       std::string getForm()
+       {
+               LocalPlayer* player = m_client->getEnv().getLocalPlayer();
+               return player->inventory_formspec;
+       }
+
+       Client *m_client;
+};
+
 /*
        Hotbar draw routine
 */
@@ -1463,14 +1479,10 @@ void the_game(
                        InventoryLocation inventoryloc;
                        inventoryloc.setCurrentPlayer();
 
-                       menu->setFormSpec(
-                               "invsize[8,7.5;]"
-                               //"image[1,0.6;1,2;player.png]"
-                               "list[current_player;main;0,3.5;8,4;]"
-                               "list[current_player;craft;3,0;3,3;]"
-                               "list[current_player;craftpreview;7,1;1,1;]"
-                               , inventoryloc);
-
+                       PlayerInventoryFormSource *src = new PlayerInventoryFormSource(&client);
+                       assert(src);
+                       menu->setFormSpec(src->getForm(), inventoryloc);
+                       menu->setFormSource(new PlayerInventoryFormSource(&client));
                        menu->drop();
                }
                else if(input->wasKeyDown(EscapeKey))
index 999d842fa9dc37e6f6e9037002da285152c44d4f..6dd90e9577b37e12c03c4f197c4a6b6c5997114f 100644 (file)
@@ -48,6 +48,13 @@ Player::Player(IGameDef *gamedef):
        inventory.addList("craft", 9);
        inventory.addList("craftpreview", 1);
        inventory.addList("craftresult", 1);
+
+       // Can be redefined via Lua
+       inventory_formspec =  "invsize[8,7.5;]"
+               //"image[1,0.6;1,2;player.png]"
+               "list[current_player;main;0,3.5;8,4;]"
+               "list[current_player;craft;3,0;3,3;]"
+               "list[current_player;craftpreview;7,1;1,1;]";
 }
 
 Player::~Player()
index c3ccc960dfb0ec1e41a714707b92983398fdb6a6..352b93e88eb77d02c917f8785a62e425fa908f57 100644 (file)
@@ -157,6 +157,8 @@ public:
 
        u16 peer_id;
 
+       std::string inventory_formspec;
+
 protected:
        IGameDef *m_gamedef;
 
index f0648545881c0a39f39621fa542c44d73790c1d5..25af2d105b347b21f3bca9fc2fe754b71ac6ee94 100644 (file)
@@ -2864,6 +2864,32 @@ private:
                return 1;
        }
 
+       // set_inventory_formspec(self, formspec)
+       static int l_set_inventory_formspec(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               Player *player = getplayer(ref);
+               if(player == NULL) return 0;
+               std::string formspec = luaL_checkstring(L, 2);
+
+               player->inventory_formspec = formspec;
+               get_server(L)->reportInventoryFormspecModified(player->getName());
+               lua_pushboolean(L, true);
+               return 1;
+       }
+
+       // get_inventory_formspec(self) -> formspec
+       static int l_get_inventory_formspec(lua_State *L)
+       {
+               ObjectRef *ref = checkobject(L, 1);
+               Player *player = getplayer(ref);
+               if(player == NULL) return 0;
+
+               std::string formspec = player->inventory_formspec;
+               lua_pushlstring(L, formspec.c_str(), formspec.size());
+               return 1;
+       }
+
 public:
        ObjectRef(ServerActiveObject *object):
                m_object(object)
@@ -2960,6 +2986,8 @@ const luaL_reg ObjectRef::methods[] = {
        method(ObjectRef, get_look_dir),
        method(ObjectRef, get_look_pitch),
        method(ObjectRef, get_look_yaw),
+       method(ObjectRef, set_inventory_formspec),
+       method(ObjectRef, get_inventory_formspec),
        {0,0}
 };
 
index f8eaaf9c3952d8f6e69f8c4d74d19a856ff55ae4..d703f7d9b5525b8c02556be18ee3d562a580ce48 100644 (file)
@@ -2243,6 +2243,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                // Send privileges
                SendPlayerPrivileges(peer_id);
                
+               // Send inventory formspec
+               SendPlayerInventoryFormspec(peer_id);
+
                // Send inventory
                UpdateCrafting(peer_id);
                SendInventory(peer_id);
@@ -3573,6 +3576,9 @@ void Server::SendPlayerPrivileges(u16 peer_id)
 {
        Player *player = m_env->getPlayer(peer_id);
        assert(player);
+       if(player->peer_id == PEER_ID_INEXISTENT)
+               return;
+
        std::set<std::string> privs;
        scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
        
@@ -3591,6 +3597,24 @@ void Server::SendPlayerPrivileges(u16 peer_id)
        m_con.Send(peer_id, 0, data, true);
 }
 
+void Server::SendPlayerInventoryFormspec(u16 peer_id)
+{
+       Player *player = m_env->getPlayer(peer_id);
+       assert(player);
+       if(player->peer_id == PEER_ID_INEXISTENT)
+               return;
+
+       std::ostringstream os(std::ios_base::binary);
+       writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
+       os<<serializeLongString(player->inventory_formspec);
+
+       // Make data buffer
+       std::string s = os.str();
+       SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+       // Send as reliable
+       m_con.Send(peer_id, 0, data, true);
+}
+
 s32 Server::playSound(const SimpleSoundSpec &spec,
                const ServerSoundParams &params)
 {
@@ -4357,6 +4381,14 @@ void Server::reportPrivsModified(const std::string &name)
        }
 }
 
+void Server::reportInventoryFormspecModified(const std::string &name)
+{
+       Player *player = m_env->getPlayer(name.c_str());
+       if(!player)
+               return;
+       SendPlayerInventoryFormspec(player->peer_id);
+}
+
 // Saves g_settings to configpath given at initialization
 void Server::saveConfig()
 {
index 4d93ae6f35a49844c73c09b929b4ce3187cd07eb..36c243ccdcf968b767a280b4dfd3280722652c01 100644 (file)
@@ -505,6 +505,7 @@ public:
        std::set<std::string> getPlayerEffectivePrivs(const std::string &name);
        bool checkPriv(const std::string &name, const std::string &priv);
        void reportPrivsModified(const std::string &name=""); // ""=all
+       void reportInventoryFormspecModified(const std::string &name);
 
        // Saves g_settings to configpath given at initialization
        void saveConfig();
@@ -602,6 +603,7 @@ private:
        void SendPlayerHP(u16 peer_id);
        void SendMovePlayer(u16 peer_id);
        void SendPlayerPrivileges(u16 peer_id);
+       void SendPlayerInventoryFormspec(u16 peer_id);
        /*
                Send a node removal/addition event to all clients except ignore_id.
                Additionally, if far_players!=NULL, players further away than