From 49f6e347f01f72e8854308d5a54aaae337489555 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Thu, 11 Apr 2013 13:23:38 -0500 Subject: [PATCH] Lua HUD --- doc/lua_api.txt | 32 ++++- src/client.cpp | 67 ++++++++++ src/client.h | 26 +++- src/clientserver.h | 39 +++++- src/game.cpp | 261 ++++++++++++++++++++++++++++++++++++++- src/player.h | 16 +++ src/scriptapi_object.cpp | 209 +++++++++++++++++++++++++++++++ src/scriptapi_object.h | 29 +++++ src/scriptapi_types.cpp | 9 ++ src/scriptapi_types.h | 1 + src/server.cpp | 179 +++++++++++++++++++++++++++ src/server.h | 10 ++ 12 files changed, 873 insertions(+), 5 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index b29c50379..d4d078e27 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -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 = "", + scale = {x=2, y=2}, + 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 +} diff --git a/src/client.cpp b/src/client.cpp index 64b01a5a4..1f8b9caca 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -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 " diff --git a/src/client.h b/src/client.h index 16cdc237f..696385a9a 100644 --- a/src/client.h +++ b/src/client.h @@ -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; }; }; diff --git a/src/clientserver.h b/src/clientserver.h index 8b1e0a7e4..6f7bb4402 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -90,9 +90,13 @@ SharedBuffer 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 diff --git a/src/game.cpp b/src/game.cpp index aae88fe90..046b7bdbf 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -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 barrect(0,0,width,height); + barrect += pos; + video::SColor bgcolor(255,128,128,128); + driver->draw2DRectangle(bgcolor, barrect, NULL);*/ + + core::rect imgrect(0,0,imgsize,imgsize); + + for(s32 i=0; igetItem(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 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( + v2s32(x1 - padding, y1 - padding), + v2s32(x2 + padding, y1) + ), NULL); + driver->draw2DRectangle(c_outside, + core::rect( + v2s32(x1 - padding, y2), + v2s32(x2 + padding, y2 + padding) + ), NULL); + driver->draw2DRectangle(c_outside, + core::rect( + v2s32(x1 - padding, y1), + v2s32(x1, y2) + ), NULL); + driver->draw2DRectangle(c_outside, + core::rect( + v2s32(x2, y1), + v2s32(x2 + padding, y2) + ), NULL); + /*// Light inside borders + driver->draw2DRectangle(c_inside, + core::rect( + v2s32(x1 - padding/2, y1 - padding/2), + v2s32(x2 + padding/2, y1) + ), NULL); + driver->draw2DRectangle(c_inside, + core::rect( + v2s32(x1 - padding/2, y2), + v2s32(x2 + padding/2, y2 + padding/2) + ), NULL); + driver->draw2DRectangle(c_inside, + core::rect( + v2s32(x1 - padding/2, y1), + v2s32(x1, y2) + ), NULL); + driver->draw2DRectangle(c_inside, + core::rect( + 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; igetOriginalSize()); + const video::SColor color(255,255,255,255); + const video::SColor colors[] = {color,color,color,color}; + core::rect rect(0,0,srcd.Width,srcd.Height); + rect += p; + driver->draw2DImage(stat_texture, rect, + core::rect(core::position2d(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 rect(0,0,srcd.Width/2,srcd.Height); + rect += p; + srcd.Width /= 2; + driver->draw2DImage(stat_texture, rect, + core::rect(core::position2d(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"<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 luaguitexts; + if(show_hud) + { + for(std::map::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 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 rect(0, 0, imgsize.Width*e->scale.X, + imgsize.Height*e->scale.X); + rect += pos; + driver->draw2DImage(texture, rect, + core::rect(core::position2d(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(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 "<second<< + "of key "<first<<" due to incorrect command."<drawAll(); + /* + Remove lua-texts + */ + for(std::deque::iterator it = luaguitexts.begin(); + it != luaguitexts.end(); ++it) + (*it)->remove(); + /* End scene */ diff --git a/src/player.h b/src/player.h index d95e535ff..fc80769c2 100644 --- a/src/player.h +++ b/src/player.h @@ -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 hud; + std::map 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 */ diff --git a/src/scriptapi_object.cpp b/src/scriptapi_object.cpp index 05433a598..8f92ca439 100644 --- a/src/scriptapi_object.cpp +++ b/src/scriptapi_object.cpp @@ -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::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::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} }; diff --git a/src/scriptapi_object.h b/src/scriptapi_object.h index a44016933..6df4366bb 100644 --- a/src/scriptapi_object.h +++ b/src/scriptapi_object.h @@ -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); diff --git a/src/scriptapi_types.cpp b/src/scriptapi_types.cpp index 01a9b3bc3..f30451108 100644 --- a/src/scriptapi_types.cpp +++ b/src/scriptapi_types.cpp @@ -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; diff --git a/src/scriptapi_types.h b/src/scriptapi_types.h index 1eeed66df..dd0b125e6 100644 --- a/src/scriptapi_types.h +++ b/src/scriptapi_types.h @@ -81,6 +81,7 @@ std::vector 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); diff --git a/src/server.cpp b/src/server.cpp index b7287c91f..a9632c93c 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -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<name); + writeV2F1000(os, form->scale); + os<text); + writeU32(os, form->number); + writeU32(os, form->item); + writeU32(os, form->dir); + + // Make data buffer + std::string s = os.str(); + SharedBuffer 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 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 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< 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 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::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:"<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:"<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:"<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:"<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:"<peer_id, id, stat, data); + return true; +} + void Server::notifyPlayers(const std::wstring msg) { BroadcastChatMessage(msg); diff --git a/src/server.h b/src/server.h index ea1cb79af..ef0c45a6a 100644 --- a/src/server.h +++ b/src/server.h @@ -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