Lua HUD
authorJonathon Anderson <anderjon@umail.iu.edu>
Thu, 11 Apr 2013 18:23:38 +0000 (13:23 -0500)
committerkwolekr <kwolekr@minetest.net>
Thu, 18 Apr 2013 06:14:33 +0000 (02:14 -0400)
12 files changed:
doc/lua_api.txt
src/client.cpp
src/client.h
src/clientserver.h
src/game.cpp
src/player.h
src/scriptapi_object.cpp
src/scriptapi_object.h
src/scriptapi_types.cpp
src/scriptapi_types.h
src/server.cpp
src/server.h

index b29c503797a7724cb99a9c6972ef23fc7ab62a99..d4d078e27d11f2089a9ba8d724d47704c39b0532 100644 (file)
@@ -1379,7 +1379,20 @@ Player-only: (no-op for other objects)
     modifies per-player walking speed, jump height, and gravity.
     Values default to 1 and act as offsets to the physics settings 
     in minetest.conf. nil will keep the current setting.
-    
+- hud_add(id, hud definition)
+  ^ id is used for later reference
+  ^ If this id has already been used, it will reset its drawform
+- hud_rm(id): remove an id from the lua hud
+- hud_change(id, stat, value): change a value of a previously added element
+  ^ stat/table key: 0/position, 1/name, 2/scale, 3/text, 4/number,
+  ^ 5/item, 6/dir
+- hud_get_next_id(): get the next available id for a hud element
+- hud_lock_next_bar(right): add a non-conflicting statbar
+  ^ if right, will claim spot on right side, rather then left
+  ^ returns element id on success, false otherwise
+- hud_unlock_bar(id): remove a non-conflicting statbar
+  ^ id is the value returned by calling hud_lock_next_bar()
+
 InvRef: Reference to an inventory
 methods:
 - is_empty(listname): return true if list is empty
@@ -1802,3 +1815,20 @@ Detached inventory callbacks
     ^ No return value
 }
 
+HUD Definition (hud_add)
+{
+    type = "I",           -- One of "I"(image), "S"(statbar),
+    ^ "T"(text), "i"(inv)
+    position = {x=0.5, y=0.5},   -- Left corner position
+    name = "<name>",
+    scale = {x=2, y=2},
+    text = "<text>",
+    ^ Used as texture name for statbars and images, and as list name
+    ^ for inv
+    number = 2,
+    ^ Used as stat for statbar, and as # of items for inv
+    item = 3,      -- Selected item in inv. 0 -> no item selected
+    dir = 0,
+    ^ dir/inv direction: 0/left-right, 1/right-left,
+    ^ 2/top-bottom, 3/bottom-top
+}
index 64b01a5a4cb4a524d503ab58538100d7321f0109..1f8b9cacafb266aaafd1a9947c968a1709d1ed8b 100644 (file)
@@ -2040,6 +2040,73 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
 
                m_client_event_queue.push_back(event);
        }
+       else if(command == TOCLIENT_HUDADD)
+       {
+               std::string datastring((char*)&data[2], datasize-2);
+               std::istringstream is(datastring, std::ios_base::binary);
+
+               u32 id                = readU32(is);
+               u8 type               = readU8(is);
+               core::vector2df pos   = readV2F1000(is);
+               std::string name      = deSerializeString(is);
+               core::vector2df scale = readV2F1000(is);
+               std::string text      = deSerializeString(is);
+               u32 number            = readU32(is);
+               u32 item              = readU32(is);
+               u32 dir               = readU32(is);
+
+               ClientEvent event;
+               event.type = CE_HUDADD;
+               event.hudadd.id = id;
+               event.hudadd.type = type;
+               event.hudadd.pos = new v2f(pos);
+               event.hudadd.name = new std::string(name);
+               event.hudadd.scale = new v2f(scale);
+               event.hudadd.text = new std::string(text);
+               event.hudadd.number = number;
+               event.hudadd.item = item;
+               event.hudadd.dir = dir;
+               m_client_event_queue.push_back(event);
+       }
+       else if(command == TOCLIENT_HUDRM)
+       {
+               std::string datastring((char*)&data[2], datasize-2);
+               std::istringstream is(datastring, std::ios_base::binary);
+
+               u32 id = readU32(is);
+
+               ClientEvent event;
+               event.type = CE_HUDRM;
+               event.hudrm.id = id;
+               m_client_event_queue.push_back(event);
+       }
+       else if(command == TOCLIENT_HUDCHANGE)
+       {
+               std::string datastring((char*)&data[2], datasize-2);
+               std::istringstream is(datastring, std::ios_base::binary);
+
+               u32 id = readU32(is);
+               u8 stat = readU8(is);
+               core::vector2df v2fdata;
+               std::string sdata;
+               u32 data = 0;
+               if(stat == 0 || stat == 2) {
+                       v2fdata = readV2F1000(is);
+               } else if(stat == 1 || stat == 3) {
+                       sdata = deSerializeString(is);
+               } else {
+                       data = readU32(is);
+               }
+
+               ClientEvent event;
+               event.type = CE_HUDCHANGE;
+               event.hudchange.id = id;
+               event.hudchange.stat = stat;
+               event.hudchange.v2fdata = new v2f(v2fdata);
+               event.hudchange.sdata = new std::string(sdata);
+               event.hudchange.data = data;
+               m_client_event_queue.push_back(event);
+       }
        else
        {
                infostream<<"Client: Ignoring unknown command "
index 16cdc237f4bd20e64b7f274090bed8f705132398..696385a9ab6b9f1f9f4e1477e3be62360ab75894 100644 (file)
@@ -160,7 +160,10 @@ enum ClientEventType
        CE_SHOW_FORMSPEC,
        CE_SPAWN_PARTICLE,
        CE_ADD_PARTICLESPAWNER,
-       CE_DELETE_PARTICLESPAWNER
+       CE_DELETE_PARTICLESPAWNER,
+       CE_HUDADD,
+       CE_HUDRM,
+       CE_HUDCHANGE
 };
 
 struct ClientEvent
@@ -217,6 +220,27 @@ struct ClientEvent
                struct{
                        u32 id;
                } delete_particlespawner;
+               struct{
+                       u32          id;
+                       u8           type;
+                       v2f*         pos;
+                       std::string* name;
+                       v2f*         scale;
+                       std::string* text;
+                       u32          number;
+                       u32          item;
+                       u32          dir;
+               } hudadd;
+               struct{
+                       u32 id;
+               } hudrm;
+               struct{
+                       u32 id;
+                       u8 stat;
+                       v2f* v2fdata;
+                       std::string* sdata;
+                       u32 data;
+               } hudchange;
        };
 };
 
index 8b1e0a7e48483a062571303043d97fbc04f2dd0b..6f7bb4402c109e4e18bd228a35be5e34593ca0bb 100644 (file)
@@ -90,9 +90,13 @@ SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed);
                sound_place added to ItemDefinition
        PROTOCOL_VERSION 19:
                GENERIC_CMD_SET_PHYSICS_OVERRIDE
+       PROTOCOL_VERSION 20:
+               TOCLIENT_HUD_ADD
+               TOCLIENT_HUD_RM
+               TOCLIENT_HUD_CHANGE
 */
 
-#define LATEST_PROTOCOL_VERSION 19
+#define LATEST_PROTOCOL_VERSION 20
 
 // Server's supported network protocol range
 #define SERVER_PROTOCOL_VERSION_MIN 13
@@ -433,6 +437,39 @@ enum ToClientCommand
                u16 command
                u32 id
        */
+
+       TOCLIENT_HUDADD = 0x49,
+       /*
+               u16 command
+               u32 id
+               u8 type
+               v2f1000 pos
+               u32 len
+               u8[len] name
+               v2f1000 scale
+               u32 len2
+               u8[len2] text
+               u32 number
+               u32 item
+               u32 dir
+       */
+
+       TOCLIENT_HUDRM = 0x50,
+       /*
+               u16 command
+               u32 id
+       */
+
+       TOCLIENT_HUDCHANGE = 0x51,
+       /*
+               u16 command
+               u32 id
+               u8 stat
+               [v2f1000 data |
+                u32 len
+                u8[len] data |
+                u32 data]
+       */
 };
 
 enum ToServerCommand
index aae88fe903082cb85ef549de616a6cf8a48ec22c..046b7bdbf9fc6557b56bd8fb41f8205587f97c0f 100644 (file)
@@ -228,6 +228,154 @@ public:
        std::string m_formspec;
        FormspecFormSource** m_game_formspec;
 };
+
+/*
+       Item draw routine
+*/
+void draw_item(video::IVideoDriver *driver, gui::IGUIFont *font, IGameDef *gamedef,
+               v2s32 upperleftpos, s32 imgsize, s32 itemcount,
+               InventoryList *mainlist, u16 selectitem, unsigned short int direction)
+               //NOTE: selectitem = 0 -> no selected; selectitem 1-based
+               //NOTE: direction: 0-> left-right, 1-> right-left, 2->top-bottom, 3->bottom-top
+{
+       s32 padding = imgsize/12;
+       s32 height = imgsize + padding*2;
+       s32 width = itemcount*(imgsize+padding*2);
+       if(direction == 2 or direction == 3){
+               width = imgsize + padding*2;
+               height = itemcount*(imgsize+padding*2);
+       }
+       s32 fullimglen = imgsize + padding*2;
+
+       // Position of upper left corner of bar
+       v2s32 pos = upperleftpos;
+
+       // Draw background color
+       /*core::rect<s32> barrect(0,0,width,height);
+       barrect += pos;
+       video::SColor bgcolor(255,128,128,128);
+       driver->draw2DRectangle(bgcolor, barrect, NULL);*/
+
+       core::rect<s32> imgrect(0,0,imgsize,imgsize);
+
+       for(s32 i=0; i<itemcount; i++)
+       {
+               const ItemStack &item = mainlist->getItem(i);
+
+               v2s32 steppos;
+               if(direction == 1){
+                       steppos = v2s32(-(padding+i*fullimglen), padding);
+               } else if(direction == 2) {
+                       steppos = v2s32(padding, padding+i*fullimglen);
+               } else if(direction == 3) {
+                       steppos = v2s32(padding, -(padding+i*fullimglen));
+               } else {
+                       steppos = v2s32(padding+i*fullimglen, padding);
+               }
+               core::rect<s32> rect = imgrect + pos
+                               + steppos;
+
+               if(selectitem == (i+1))
+               {
+                       video::SColor c_outside(255,255,0,0);
+                       //video::SColor c_outside(255,0,0,0);
+                       //video::SColor c_inside(255,192,192,192);
+                       s32 x1 = rect.UpperLeftCorner.X;
+                       s32 y1 = rect.UpperLeftCorner.Y;
+                       s32 x2 = rect.LowerRightCorner.X;
+                       s32 y2 = rect.LowerRightCorner.Y;
+                       // Black base borders
+                       driver->draw2DRectangle(c_outside,
+                                       core::rect<s32>(
+                                               v2s32(x1 - padding, y1 - padding),
+                                               v2s32(x2 + padding, y1)
+                                       ), NULL);
+                       driver->draw2DRectangle(c_outside,
+                                       core::rect<s32>(
+                                               v2s32(x1 - padding, y2),
+                                               v2s32(x2 + padding, y2 + padding)
+                                       ), NULL);
+                       driver->draw2DRectangle(c_outside,
+                                       core::rect<s32>(
+                                               v2s32(x1 - padding, y1),
+                                               v2s32(x1, y2)
+                                       ), NULL);
+                       driver->draw2DRectangle(c_outside,
+                                       core::rect<s32>(
+                                               v2s32(x2, y1),
+                                               v2s32(x2 + padding, y2)
+                                       ), NULL);
+                       /*// Light inside borders
+                       driver->draw2DRectangle(c_inside,
+                                       core::rect<s32>(
+                                               v2s32(x1 - padding/2, y1 - padding/2),
+                                               v2s32(x2 + padding/2, y1)
+                                       ), NULL);
+                       driver->draw2DRectangle(c_inside,
+                                       core::rect<s32>(
+                                               v2s32(x1 - padding/2, y2),
+                                               v2s32(x2 + padding/2, y2 + padding/2)
+                                       ), NULL);
+                       driver->draw2DRectangle(c_inside,
+                                       core::rect<s32>(
+                                               v2s32(x1 - padding/2, y1),
+                                               v2s32(x1, y2)
+                                       ), NULL);
+                       driver->draw2DRectangle(c_inside,
+                                       core::rect<s32>(
+                                               v2s32(x2, y1),
+                                               v2s32(x2 + padding/2, y2)
+                                       ), NULL);
+                       */
+               }
+
+               video::SColor bgcolor2(128,0,0,0);
+               driver->draw2DRectangle(bgcolor2, rect, NULL);
+               drawItemStack(driver, font, item, rect, NULL, gamedef);
+       }
+}
+
+/*
+       Statbar draw routine
+*/
+void draw_statbar(video::IVideoDriver *driver, gui::IGUIFont *font, IGameDef *gamedef,
+               v2s32 upperleftpos, std::string texture, s32 count)
+               //NOTE: selectitem = 0 -> no selected; selectitem 1-based
+               //NOTE: direction: 0-> left-right, 1-> right-left, 2->top-bottom, 3->bottom-top
+{
+       video::ITexture *stat_texture =
+               gamedef->getTextureSource()->getTextureRaw(texture);
+       if(stat_texture)
+       {
+               v2s32 p = upperleftpos;
+               for(s32 i=0; i<count/2; i++)
+               {
+                       core::dimension2di srcd(stat_texture->getOriginalSize());
+                       const video::SColor color(255,255,255,255);
+                       const video::SColor colors[] = {color,color,color,color};
+                       core::rect<s32> rect(0,0,srcd.Width,srcd.Height);
+                       rect += p;
+                       driver->draw2DImage(stat_texture, rect,
+                               core::rect<s32>(core::position2d<s32>(0,0), srcd),
+                               NULL, colors, true);
+                       p += v2s32(srcd.Width,0);
+               }
+               if(count % 2 == 1)
+               {
+                       core::dimension2di srcd(stat_texture->getOriginalSize());
+                       const video::SColor color(255,255,255,255);
+                       const video::SColor colors[] = {color,color,color,color};
+                       core::rect<s32> rect(0,0,srcd.Width/2,srcd.Height);
+                       rect += p;
+                       srcd.Width /= 2;
+                       driver->draw2DImage(stat_texture, rect,
+                               core::rect<s32>(core::position2d<s32>(0,0), srcd),
+                               NULL, colors, true);
+                       p += v2s32(srcd.Width*2,0);
+               }
+       }
+}
+
 /*
        Hotbar draw routine
 */
@@ -242,7 +390,7 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
                errorstream<<"draw_hotbar(): mainlist == NULL"<<std::endl;
                return;
        }
-       
+#if 0
        s32 padding = imgsize/12;
        //s32 height = imgsize + padding*2;
        s32 width = itemcount*(imgsize+padding*2);
@@ -323,7 +471,14 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
                driver->draw2DRectangle(bgcolor2, rect, NULL);
                drawItemStack(driver, font, item, rect, NULL, gamedef);
        }
-       
+#else
+       s32 padding = imgsize/12;
+       s32 width = itemcount*(imgsize+padding*2);
+       v2s32 pos = centerlowerpos - v2s32(width/2, imgsize+padding*2);
+       draw_item(driver, font, gamedef, pos, imgsize, itemcount,
+                               mainlist, playeritem + 1, 0);
+#endif
+#if 0
        /*
                Draw hearts
        */
@@ -358,6 +513,10 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
                        p += v2s32(16,0);
                }
        }
+#else
+       draw_statbar(driver, font, gamedef, pos + v2s32(0, -20),
+               "heart.png", halfheartcount);
+#endif
 }
 
 /*
@@ -2229,6 +2388,45 @@ void the_game(
                                {
                                        delete_particlespawner (event.delete_particlespawner.id);
                                }
+                               else if (event.type == CE_HUDADD)
+                               {
+                                       HudElement* e = new HudElement;
+                                       e->type   = event.hudadd.type;
+                                       e->pos    = *event.hudadd.pos;
+                                       e->name   = *event.hudadd.name;
+                                       e->scale  = *event.hudadd.scale;
+                                       e->text   = *event.hudadd.text;
+                                       e->number = event.hudadd.number;
+                                       e->item   = event.hudadd.item;
+                                       e->dir    = event.hudadd.dir;
+                                       player->hud[event.hudadd.id] = e;
+                                       delete(event.hudadd.pos);
+                                       delete(event.hudadd.name);
+                                       delete(event.hudadd.scale);
+                                       delete(event.hudadd.text);
+                               }
+                               else if (event.type == CE_HUDRM)
+                               {
+                                       player->hud.erase(event.hudrm.id);
+                               }
+                               else if (event.type == CE_HUDCHANGE)
+                               {
+                                       HudElement* e = player->hud[event.hudchange.id];
+                                       if(event.hudchange.stat == 0)
+                                               e->pos = *event.hudchange.v2fdata;
+                                       else if(event.hudchange.stat == 1)
+                                               e->name = *event.hudchange.sdata;
+                                       else if(event.hudchange.stat == 2)
+                                               e->scale = *event.hudchange.v2fdata;
+                                       else if(event.hudchange.stat == 3)
+                                               e->text = *event.hudchange.sdata;
+                                       else if(event.hudchange.stat == 4)
+                                               e->number = event.hudchange.data;
+                                       else if(event.hudchange.stat == 5)
+                                               e->item = event.hudchange.data;
+                                       else if(event.hudchange.stat == 6)
+                                               e->dir = event.hudchange.data;
+                               }
                        }
                }
                
@@ -3212,12 +3410,71 @@ void the_game(
                                player->hurt_tilt_strength = 0;
                }
 
+               /*
+                       Draw lua hud items
+               */
+               std::deque<gui::IGUIStaticText *> luaguitexts;
+               if(show_hud)
+               {
+                       for(std::map<u32, HudElement*>::iterator it = player->hud.begin();
+                               it != player->hud.end(); ++it)
+                       {
+                               HudElement* e = it->second;
+                               v2f posp(e->pos * v2f(screensize.X, screensize.Y));
+                               core::vector2d<s32> pos(posp.X, posp.Y);
+                               if(e->type == 'I'){         //Img
+                                       video::ITexture *texture =
+                                               gamedef->getTextureSource()->getTextureRaw(e->text);
+                                       const video::SColor color(255,255,255,255);
+                                       const video::SColor colors[] = {color,color,color,color};
+                                       core::dimension2di imgsize(texture->getOriginalSize());
+                                       core::rect<s32> rect(0, 0, imgsize.Width*e->scale.X,
+                                                                                               imgsize.Height*e->scale.X);
+                                       rect += pos;
+                                       driver->draw2DImage(texture, rect,
+                                               core::rect<s32>(core::position2d<s32>(0,0), imgsize),
+                                               NULL, colors, true);
+                               } else if(e->type == 'T') { //Text
+                                       std::wstring t;
+                                       t.assign(e->text.begin(), e->text.end());
+                                       gui::IGUIStaticText *luaguitext = guienv->addStaticText(
+                                                       t.c_str(),
+                                                       core::rect<s32>(0, 0, e->scale.X, text_height*(e->scale.Y))+pos,
+                                                       false, false);
+                                       luaguitexts.push_back(luaguitext);
+                               } else if(e->type == 'S') { //Statbar
+                                       draw_statbar(driver, font, gamedef, pos, e->text, e->number);
+                               } else if(e->type == 's') { //Non-conflict Statbar
+                                       v2s32 p(displaycenter.X - 143, screensize.Y - 76);
+                                       p.X += e->pos.X*173;
+                                       p.Y += e->pos.X*20;
+                                       p.Y -= e->pos.Y*20;
+                                       draw_statbar(driver, font, gamedef, p, e->text, e->number);
+                               } else if(e->type == 'i') { //Inv
+                                       InventoryList* inv = local_inventory.getList(e->text);
+                                       draw_item(driver, font, gamedef, pos, hotbar_imagesize,
+                                                               e->number, inv, e->item, e->dir);
+                               } else {
+                                       actionstream<<"luadraw: ignoring drawform "<<it->second<<
+                                               "of key "<<it->first<<" due to incorrect command."<<std::endl;
+                                       continue;
+                               }
+                       }
+               }
+
                /*
                        Draw gui
                */
                // 0-1ms
                guienv->drawAll();
 
+               /*
+                       Remove lua-texts
+               */
+               for(std::deque<gui::IGUIStaticText *>::iterator it = luaguitexts.begin();
+                       it != luaguitexts.end(); ++it)
+                       (*it)->remove();
+
                /*
                        End scene
                */
index d95e535ffda63d91c5cf67cab8571d9c08f464f8..fc80769c2cfeb233740a3a4369dadefac537c386 100644 (file)
@@ -87,6 +87,7 @@ class Map;
 class IGameDef;
 struct CollisionInfo;
 class PlayerSAO;
+struct HudElement;
 
 class Player
 {
@@ -243,6 +244,9 @@ public:
        
        u32 keyPressed;
 
+       std::map<u32, HudElement*> hud;
+       std::map<u8, u32> hud_bars;
+
 protected:
        IGameDef *m_gamedef;
 
@@ -253,6 +257,18 @@ protected:
        v3f m_position;
 };
 
+struct HudElement {
+       u8 type;
+       core::vector2df pos;
+       std::string name;
+
+       core::vector2df scale;
+       std::string text;
+       u32 number;
+       u32 item;
+       u32 dir;
+};
+
 /*
        Player on the server
 */
index 05433a598fae6433773dfc2c525f2f6389c97e20..8f92ca439ccd2bf64adb9d49724f30c71459b6a0 100644 (file)
@@ -700,6 +700,209 @@ int ObjectRef::l_get_player_control_bits(lua_State *L)
        return 1;
 }
 
+// hud_add(self, form)
+int ObjectRef::l_hud_add(lua_State *L)
+{
+       ObjectRef *ref = checkobject(L, 1);
+       Player *player = getplayer(ref);
+       if(player == NULL) return 0;
+
+       u32 id = hud_get_next_id(L);
+       HudElement* form = new HudElement;
+       std::string SS = getstringfield_default(L, 3, "type", "I");
+       form->type = SS[0];
+       lua_getfield(L, 3, "position");
+       if(lua_istable(L, -1))
+               form->pos = read_v2f(L, -1);
+       else
+               form->pos = v2f();
+       lua_pop(L, 1);
+       form->name = getstringfield_default(L, 3, "name", "");
+
+       lua_getfield(L, 3, "scale");
+       if(lua_istable(L, -1))
+               form->scale = read_v2f(L, -1);
+       else
+               form->scale = v2f();
+       lua_pop(L, 1);
+
+       form->text = getstringfield_default(L, 3, "text", "");
+       form->number = getintfield_default(L, 3, "number", 0);
+       form->item = getintfield_default(L, 3, "item", 0);
+       form->dir = getintfield_default(L, 3, "dir", 0);
+
+       get_server(L)->hudadd(player->getName(), id, form);
+       player->hud[id] = form;
+       lua_pushnumber(L, id);
+       return 1;
+}
+
+// hud_rm(self, id)
+int ObjectRef::l_hud_rm(lua_State *L)
+{
+       ObjectRef *ref = checkobject(L, 1);
+       Player *player = getplayer(ref);
+       if(player == NULL) return 0;
+
+       u32 id = -1;
+       if(!lua_isnil(L, 2))
+               id = lua_tonumber(L, 2);
+       get_server(L)->hudrm(player->getName(), id);
+       player->hud.at(id)->type = (u8)NULL;
+       lua_pushboolean(L, true);
+       return 1;
+}
+
+
+// hud_change(self, id, stat, data)
+int ObjectRef::l_hud_change(lua_State *L)
+{
+       ObjectRef *ref = checkobject(L, 1);
+       Player *player = getplayer(ref);
+       if(player == NULL) return 0;
+
+       u32 id = -1;
+       if(!lua_isnil(L, 2))
+               id = lua_tonumber(L, 2);
+       u8 stat = -1;
+       if(!lua_isnil(L, 3))
+               stat = lua_tonumber(L, 3);
+       if(stat == 0 || stat == 2) {
+               get_server(L)->hudchange(player->getName(), id, stat, read_v2f(L, 4));
+       } else if(stat == 1 || stat == 3) {
+               get_server(L)->hudchange(player->getName(), id, stat, lua_tostring(L, 4));
+       } else {
+               get_server(L)->hudchange(player->getName(), id, stat, lua_tonumber(L, 4));
+       }
+
+       HudElement* e = player->hud[id];
+       switch(stat) {
+               case HUD_STAT_POS:    e->pos = read_v2f(L, 4);
+               case HUD_STAT_NAME:   e->name = lua_tostring(L, 4);
+               case HUD_STAT_SCALE:  e->scale = read_v2f(L, 4);
+               case HUD_STAT_TEXT:   e->text = lua_tostring(L, 4);
+               case HUD_STAT_NUMBER: e->number = lua_tonumber(L, 4);
+               case HUD_STAT_ITEM:   e->item = lua_tonumber(L, 4);
+               case HUD_STAT_DIR:    e->dir = lua_tonumber(L, 4);
+       }
+
+       lua_pushboolean(L, true);
+       return 1;
+}
+
+u32 ObjectRef::hud_get_next_id(lua_State *L)
+{
+       ObjectRef *ref = checkobject(L, 1);
+       Player *player = getplayer(ref);
+
+       for(std::map<u32, HudElement*>::iterator it=player->hud.begin();
+               it!=player->hud.end();it++) {
+               if(it->second->type == (u8)NULL) {
+                       return it->first;
+               }
+       }
+       return player->hud.size();
+}
+
+// hud_get(self, id)
+int ObjectRef::l_hud_get(lua_State *L)
+{
+       ObjectRef *ref = checkobject(L, 1);
+       Player *player = getplayer(ref);
+       if(player == NULL) return 0;
+
+       HudElement* e = player->hud.at(lua_tonumber(L, -1));
+       lua_newtable(L);
+       lua_pushstring(L, std::string(1, e->type).c_str());
+       lua_setfield(L, -2, "type");
+       push_v2f(L, e->pos);
+       lua_setfield(L, -2, "position");
+       lua_pushstring(L, e->name.c_str());
+       lua_setfield(L, -2, "name");
+       push_v2f(L, e->scale);
+       lua_setfield(L, -2, "scale");
+       lua_pushstring(L, e->text.c_str());
+       lua_setfield(L, -2, "text");
+       lua_pushnumber(L, e->number);
+       lua_setfield(L, -2, "number");
+       lua_pushnumber(L, e->item);
+       lua_setfield(L, -2, "item");
+       lua_pushnumber(L, e->dir);
+       lua_setfield(L, -2, "dir");
+
+       return 1;
+}
+
+// hud_lock_next_bar(self, texture, right)
+// return id on success, false otherwise
+int ObjectRef::l_hud_lock_next_bar(lua_State *L)
+{
+       ObjectRef *ref = checkobject(L, 1);
+       Player *player = getplayer(ref);
+       if(player == NULL) return 0;
+
+       bool right = false;
+       if(!lua_isnil(L, 2))
+               right = lua_toboolean(L, 2);
+       v2f pos(0, 0);
+       u8 i = 0;
+       if(right)
+               pos.X = 1;
+               i += 3;
+       for(u8 it = 0; it < 4; it++) {
+               if(player->hud_bars.count(i+it) == 1) {
+                       if(it == 3) {
+                               lua_pushboolean(L, false);
+                               return 1;
+                       }
+               } else {
+                       i += it;
+                       pos.Y = it;
+                       break;
+               }
+       }
+       HudElement* form = new HudElement;
+       form->type = 's';
+       form->pos = pos;
+       form->name = "";
+       form->scale = v2f();
+       form->text = "";
+       form->number = 0;
+       form->item = 0;
+       form->dir = 0;
+
+       u32 id = hud_get_next_id(L);
+       get_server(L)->hudadd(player->getName(), id, form);
+       player->hud[id] = form;
+       player->hud_bars[i] = id;
+       lua_pushnumber(L, id);
+       return 1;
+}
+
+// hud_unlock_bar(self, id)
+int ObjectRef::l_hud_unlock_bar(lua_State *L)
+{
+       ObjectRef *ref = checkobject(L, 1);
+       Player *player = getplayer(ref);
+       if(player == NULL) return 0;
+
+       u32 id = 0;
+       if(!lua_isnil(L, 2))
+               id = lua_tonumber(L, 2);
+
+       for(std::map<u8, u32>::iterator it=player->hud_bars.begin();
+               it!=player->hud_bars.end();it++) {
+               if(it->second == id) {
+                       player->hud_bars.erase(it->first);
+                       get_server(L)->hudrm(player->getName(), id);
+                       player->hud.at(id)->type = (u8)NULL;
+                       lua_pushboolean(L, true);
+                       return 1;
+               }
+       }
+       lua_pushboolean(L, false);
+       return 1;
+}
 
 ObjectRef::ObjectRef(ServerActiveObject *object):
        m_object(object)
@@ -807,6 +1010,12 @@ const luaL_reg ObjectRef::methods[] = {
        luamethod(ObjectRef, get_inventory_formspec),
        luamethod(ObjectRef, get_player_control),
        luamethod(ObjectRef, get_player_control_bits),
+       luamethod(ObjectRef, hud_add),
+       luamethod(ObjectRef, hud_rm),
+       luamethod(ObjectRef, hud_change),
+       luamethod(ObjectRef, hud_get),
+       luamethod(ObjectRef, hud_lock_next_bar),
+       luamethod(ObjectRef, hud_unlock_bar),
        {0,0}
 };
 
index a44016933517c8d3f71a2d0042bec8cb52fe980e..6df4366bbd5429c01b957eeae7349ec25be2f332 100644 (file)
@@ -29,6 +29,14 @@ extern "C" {
 #include "content_sao.h"
 #include "player.h"
 
+#define HUD_STAT_POS    0
+#define HUD_STAT_NAME   1
+#define HUD_STAT_SCALE  2
+#define HUD_STAT_TEXT   3
+#define HUD_STAT_NUMBER 4
+#define HUD_STAT_ITEM   5
+#define HUD_STAT_DIR    6
+
 /*
        ObjectRef
 */
@@ -190,6 +198,27 @@ private:
        // get_player_control_bits(self)
        static int l_get_player_control_bits(lua_State *L);
 
+       // hud_add(self, id, form)
+       static int l_hud_add(lua_State *L);
+
+       // hud_rm(self, id)
+       static int l_hud_rm(lua_State *L);
+
+       // hud_change(self, id, stat, data)
+       static int l_hud_change(lua_State *L);
+
+       // hud_get_next_id(self)
+       static u32 hud_get_next_id(lua_State *L);
+
+       // hud_get(self, id)
+       static int l_hud_get(lua_State *L);
+
+       // hud_lock_next_bar(self, right)
+       static int l_hud_lock_next_bar(lua_State *L);
+
+       // hud_unlock_bar(self, id)
+       static int l_hud_unlock_bar(lua_State *L);
+
 public:
        ObjectRef(ServerActiveObject *object);
 
index 01a9b3bc3bc9c8d2219151afad83ec5b1719cff5..f304511080c57c2fda5b7e504a84cf15da265bf0 100644 (file)
@@ -42,6 +42,15 @@ void push_v3f(lua_State *L, v3f p)
        lua_setfield(L, -2, "z");
 }
 
+void push_v2f(lua_State *L, v2f p)
+{
+       lua_newtable(L);
+       lua_pushnumber(L, p.X);
+       lua_setfield(L, -2, "x");
+       lua_pushnumber(L, p.Y);
+       lua_setfield(L, -2, "y");
+}
+
 v2s16 read_v2s16(lua_State *L, int index)
 {
        v2s16 p;
index 1eeed66df67fc078b45f250b0ed327085cb4e634..dd0b125e6920ad18a3af4064be1fbffd77751e88 100644 (file)
@@ -81,6 +81,7 @@ std::vector<aabb3f>
 void          push_v3s16                    (lua_State *L, v3s16 p);
 void          pushFloatPos                  (lua_State *L, v3f p);
 void          push_v3f                      (lua_State *L, v3f p);
+void          push_v2f                      (lua_State *L, v2f p);
 
 
 MapNode readnode(lua_State *L, int index, INodeDefManager *ndef);
index b7287c91f0f47cb01bc46e9c0424a18133b688bd..a9632c93c6ce0fa23a5a9e8e64f7c53daacf7a85 100644 (file)
@@ -3595,6 +3595,115 @@ void Server::SendDeleteParticleSpawnerAll(u32 id)
        }
 }
 
+void Server::SendHUDAdd(u16 peer_id, const u32 id, HudElement* form)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       std::ostringstream os(std::ios_base::binary);
+       u8 buf[12];
+
+       // Write command
+       writeU16(buf, TOCLIENT_HUDADD);
+       os.write((char*)buf, 2);
+       writeU32(os, id);
+       writeU8(os, form->type);
+       writeV2F1000(os, form->pos);
+       os<<serializeString(form->name);
+       writeV2F1000(os, form->scale);
+       os<<serializeString(form->text);
+       writeU32(os, form->number);
+       writeU32(os, form->item);
+       writeU32(os, form->dir);
+
+       // 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);
+}
+
+void Server::SendHUDRm(u16 peer_id, const u32 id)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       std::ostringstream os(std::ios_base::binary);
+       u8 buf[12];
+
+       // Write command
+       writeU16(buf, TOCLIENT_HUDRM);
+       os.write((char*)buf, 2);
+       writeU32(os, id);
+
+       // 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);
+}
+
+void Server::SendHUDChange(u16 peer_id, const u32 id, const u8 stat, v2f data)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       std::ostringstream os(std::ios_base::binary);
+       u8 buf[12];
+
+       // Write command
+       writeU16(buf, TOCLIENT_HUDCHANGE);
+       os.write((char*)buf, 2);
+       writeU32(os, id);
+       writeU8(os, stat);
+       writeV2F1000(os, data);
+
+       // Make data buffer
+       std::string s = os.str();
+       SharedBuffer<u8> ddata((u8*)s.c_str(), s.size());
+       // Send as reliable
+       m_con.Send(peer_id, 0, ddata, true);
+}
+
+void Server::SendHUDChange(u16 peer_id, const u32 id, const u8 stat, std::string data)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       std::ostringstream os(std::ios_base::binary);
+       u8 buf[12];
+
+       // Write command
+       writeU16(buf, TOCLIENT_HUDCHANGE);
+       os.write((char*)buf, 2);
+       writeU32(os, id);
+       writeU8(os, stat);
+       os<<serializeString(data);
+
+       // Make data buffer
+       std::string s = os.str();
+       SharedBuffer<u8> ddata((u8*)s.c_str(), s.size());
+       // Send as reliable
+       m_con.Send(peer_id, 0, ddata, true);
+}
+
+void Server::SendHUDChange(u16 peer_id, const u32 id, const u8 stat, u32 data)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       std::ostringstream os(std::ios_base::binary);
+       u8 buf[12];
+
+       // Write command
+       writeU16(buf, TOCLIENT_HUDCHANGE);
+       os.write((char*)buf, 2);
+       writeU32(os, id);
+       writeU8(os, stat);
+       writeU32(os, data);
+
+       // Make data buffer
+       std::string s = os.str();
+       SharedBuffer<u8> ddata((u8*)s.c_str(), s.size());
+       // Send as reliable
+       m_con.Send(peer_id, 0, ddata, true);
+}
+
 void Server::BroadcastChatMessage(const std::wstring &message)
 {
        for(std::map<u16, RemoteClient*>::iterator
@@ -4548,6 +4657,76 @@ bool Server::showFormspec(const char *playername, const std::string &formspec, c
        return true;
 }
 
+bool Server::hudadd(const char *playername, const u32 &id, HudElement* form)
+{
+       Player *player = m_env->getPlayer(playername);
+
+       if(!player)
+       {
+               infostream<<"hudadd: couldn't find player:"<<playername<<std::endl;
+               return false;
+       }
+
+       SendHUDAdd(player->peer_id, id, form);
+       return true;
+}
+
+bool Server::hudrm(const char *playername, const u32 &id)
+{
+       Player *player = m_env->getPlayer(playername);
+
+       if(!player)
+       {
+               infostream<<"hudrm: couldn't find player:"<<playername<<std::endl;
+               return false;
+       }
+
+       SendHUDRm(player->peer_id, id);
+       return true;
+}
+
+bool Server::hudchange(const char *playername, const u32 &id, const u8 &stat, v2f data)
+{
+       Player *player = m_env->getPlayer(playername);
+
+       if(!player)
+       {
+               infostream<<"hudchange: couldn't find player:"<<playername<<std::endl;
+               return false;
+       }
+
+       SendHUDChange(player->peer_id, id, stat, data);
+       return true;
+}
+
+bool Server::hudchange(const char *playername, const u32 &id, const u8 &stat, std::string data)
+{
+       Player *player = m_env->getPlayer(playername);
+
+       if(!player)
+       {
+               infostream<<"hudchange: couldn't find player:"<<playername<<std::endl;
+               return false;
+       }
+
+       SendHUDChange(player->peer_id, id, stat, data);
+       return true;
+}
+
+bool Server::hudchange(const char *playername, const u32 &id, const u8 &stat, u32 data)
+{
+       Player *player = m_env->getPlayer(playername);
+
+       if(!player)
+       {
+               infostream<<"hudchange: couldn't find player:"<<playername<<std::endl;
+               return false;
+       }
+
+       SendHUDChange(player->peer_id, id, stat, data);
+       return true;
+}
+
 void Server::notifyPlayers(const std::wstring msg)
 {
        BroadcastChatMessage(msg);
index ea1cb79af529aef55fc09de91c2c583abdd1dac9..ef0c45a6ae0a096f62e4bdbf74191700afe8e4aa 100644 (file)
@@ -534,6 +534,11 @@ public:
        }
 
        bool showFormspec(const char *name, const std::string &formspec, const std::string &formname);
+       bool hudadd(const char *pname, const u32 &id, HudElement *element);
+       bool hudrm(const char *pname, const u32 &id);
+       bool hudchange(const char *pname, const u32 &id, const u8 &stat, v2f data);
+       bool hudchange(const char *pname, const u32 &id, const u8 &stat, std::string data);
+       bool hudchange(const char *pname, const u32 &id, const u8 &stat, u32 data);
 private:
 
        // con::PeerHandler implementation.
@@ -573,6 +578,11 @@ private:
        void SendPlayerPrivileges(u16 peer_id);
        void SendPlayerInventoryFormspec(u16 peer_id);
        void SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname);
+       void SendHUDAdd(u16 peer_id, const u32 id, HudElement* form);
+       void SendHUDRm(u16 peer_id, const u32 id);
+       void SendHUDChange(u16 peer_id, const u32 id, const u8 stat, v2f data);
+       void SendHUDChange(u16 peer_id, const u32 id, const u8 stat, std::string data);
+       void SendHUDChange(u16 peer_id, const u32 id, const u8 stat, u32 data);
        /*
                Send a node removal/addition event to all clients except ignore_id.
                Additionally, if far_players!=NULL, players further away than