From 666aae359310483b7ad0f2bba1f4c31d8a58c737 Mon Sep 17 00:00:00 2001 From: kwolekr Date: Sat, 13 Apr 2013 18:20:22 -0400 Subject: [PATCH] Split HUD code off to hud.cpp, make into a class, extensive Lua HUD modification --- doc/lua_api.txt | 73 ++++-- src/CMakeLists.txt | 1 + src/client.cpp | 73 +++--- src/client.h | 28 +-- src/game.cpp | 516 +++++++-------------------------------- src/hud.cpp | 291 ++++++++++++++++++++++ src/hud.h | 116 +++++++++ src/player.h | 18 +- src/scriptapi_object.cpp | 266 ++++++++++---------- src/scriptapi_object.h | 19 +- src/server.cpp | 188 +++++--------- src/server.h | 20 +- 12 files changed, 793 insertions(+), 816 deletions(-) create mode 100644 src/hud.cpp create mode 100644 src/hud.h diff --git a/doc/lua_api.txt b/doc/lua_api.txt index d4d078e27..44b2a0b63 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -401,6 +401,43 @@ Currently supported flags: absheight Also produce this same ore between the height range of -height_max and -height_min. Useful for having ore in sky realms without having to duplicate ore entries. +HUD element types +------------------- +The position field is used for all element types. +To account for differing resolutions, the position coordinates are the percentage of the screen, +ranging in value from 0 to 1. +The name field is not yet used, but should contain a description of what the HUD element represents. +Below are the specific uses for fields in each type; fields not listed for that type are ignored. + +Note: Future revisions to the HUD API may be incompatible; the HUD API is still in the experimental stages. + +- image + Displays an image on the HUD. + - scale: The scale of the image, with 1 being the original texture size. + Only the X coordinate scale is used. + - text: The name of the texture that is displayed. +- text + Displays text on the HUD. + - scale: Defines the bounding rectangle of the text. + A value such as {x=100, y=100} should work. + - text: The text to be displayed in the HUD element. + - number: An integer containing the RGB value of the color used to draw the text. + Specify 0xFFFFFF for white text, 0xFF0000 for red, and so on. +- statbar + Displays a horizontal bar made up of half-images. + - text: The name of the texture that is used. + - number: The number of half-textures that are displayed. + If odd, will end with a vertically center-split texture. +- inventory + - text: The name of the inventory list to be displayed. + - number: Number of items in the inventory to be displayed. + - item: Position of item that is selected. + - direction: Direction in which the inventory list is drawn. + 0 draws from left to right, + 1 draws from right to left, + 2 draws from top to bottom, and + 3 draws from bottom to top. + Representations of simple things -------------------------------- Position/vector: @@ -1379,19 +1416,11 @@ 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() +- hud_add(hud definition): add a HUD element described by HUD def, returns ID number on success +- hud_remove(id): remove the HUD element of the specified id +- hud_change(id, stat, value): change a value of a previously added HUD element + ^ element stat values: position, name, scale, text, number, item, dir +- hud_get(id): gets the HUD element definition structure of the specified ID InvRef: Reference to an inventory methods: @@ -1815,20 +1844,18 @@ Detached inventory callbacks ^ No return value } -HUD Definition (hud_add) +HUD Definition (hud_add, hud_get) { - type = "I", -- One of "I"(image), "S"(statbar), - ^ "T"(text), "i"(inv) - position = {x=0.5, y=0.5}, -- Left corner position + type = "image", + ^ type of HUD element, can be either of "image", "text", "statbar", or "inventory" + position = {x=0.5, y=0.5}, + ^ Left corner position of element 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 + item = 3, + ^ Selected item in inventory. 0 for no item selected. dir = 0, - ^ dir/inv direction: 0/left-right, 1/right-left, - ^ 2/top-bottom, 3/bottom-top + ^ Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 62bb42b9e..7ddeeb02e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -327,6 +327,7 @@ set(minetest_SRCS particles.cpp clientobject.cpp chat.cpp + hud.cpp guiMainMenu.cpp guiKeyChangeMenu.cpp guiMessageMenu.cpp diff --git a/src/client.cpp b/src/client.cpp index 1f8b9caca..03a710599 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -2042,35 +2042,35 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) } else if(command == TOCLIENT_HUDADD) { - std::string datastring((char*)&data[2], datasize-2); + 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); + u32 id = readU32(is); + u8 type = readU8(is); + v2f pos = readV2F1000(is); + std::string name = deSerializeString(is); + v2f 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.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; + 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::string datastring((char *)&data[2], datasize - 2); std::istringstream is(datastring, std::ios_base::binary); u32 id = readU32(is); @@ -2081,30 +2081,31 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) m_client_event_queue.push_back(event); } else if(command == TOCLIENT_HUDCHANGE) - { - std::string datastring((char*)&data[2], datasize-2); + { + std::string sdata; + v2f v2fdata; + u32 intdata = 0; + + 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) { + u32 id = readU32(is); + u8 stat = (HudElementStat)readU8(is); + + if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE) v2fdata = readV2F1000(is); - } else if(stat == 1 || stat == 3) { + else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT) sdata = deSerializeString(is); - } else { - data = readU32(is); - } - + else + intdata = readU32(is); + ClientEvent event; event.type = CE_HUDCHANGE; - event.hudchange.id = id; - event.hudchange.stat = stat; + event.hudchange.id = id; + event.hudchange.stat = (HudElementStat)stat; event.hudchange.v2fdata = new v2f(v2fdata); - event.hudchange.sdata = new std::string(sdata); - event.hudchange.data = data; + event.hudchange.sdata = new std::string(sdata); + event.hudchange.data = intdata; m_client_event_queue.push_back(event); } else diff --git a/src/client.h b/src/client.h index 696385a9a..f59588680 100644 --- a/src/client.h +++ b/src/client.h @@ -186,8 +186,8 @@ struct ClientEvent f32 camera_point_target_z; } deathscreen; struct{ - std::string* formspec; - std::string* formname; + std::string *formspec; + std::string *formname; } show_formspec; struct{ } textures_updated; @@ -221,24 +221,24 @@ struct ClientEvent 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; + 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; + HudElementStat stat; + v2f *v2fdata; + std::string *sdata; u32 data; } hudchange; }; diff --git a/src/game.cpp b/src/game.cpp index 046b7bdbf..a2d94ac0a 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -59,6 +59,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "subgame.h" #include "quicktune_shortcutter.h" #include "clientmap.h" +#include "hud.h" #include "sky.h" #include "sound.h" #if USE_SOUND @@ -229,296 +230,6 @@ public: 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 -*/ -void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font, - IGameDef *gamedef, - v2s32 centerlowerpos, s32 imgsize, s32 itemcount, - Inventory *inventory, s32 halfheartcount, u16 playeritem) -{ - InventoryList *mainlist = inventory->getList("main"); - if(mainlist == NULL) - { - errorstream<<"draw_hotbar(): mainlist == NULL"< 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); - - core::rect rect = imgrect + pos - + v2s32(padding+i*(imgsize+padding*2), padding); - - if(playeritem == i) - { - 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); - } -#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 - */ - video::ITexture *heart_texture = - gamedef->getTextureSource()->getTextureRaw("heart.png"); - if(heart_texture) - { - v2s32 p = pos + v2s32(0, -20); - for(s32 i=0; i rect(0,0,16,16); - rect += p; - driver->draw2DImage(heart_texture, rect, - core::rect(core::position2d(0,0), - core::dimension2di(heart_texture->getOriginalSize())), - NULL, colors, true); - p += v2s32(16,0); - } - if(halfheartcount % 2 == 1) - { - const video::SColor color(255,255,255,255); - const video::SColor colors[] = {color,color,color,color}; - core::rect rect(0,0,16/2,16); - rect += p; - core::dimension2di srcd(heart_texture->getOriginalSize()); - srcd.Width /= 2; - driver->draw2DImage(heart_texture, rect, - core::rect(core::position2d(0,0), srcd), - NULL, colors, true); - p += v2s32(16,0); - } - } -#else - draw_statbar(driver, font, gamedef, pos + v2s32(0, -20), - "heart.png", halfheartcount); -#endif -} - /* Check if a node is pointable */ @@ -1103,14 +814,8 @@ void the_game( // Calculate text height using the font u32 text_height = font->getDimension(L"Random test string").Height; - v2u32 screensize(0,0); v2u32 last_screensize(0,0); - screensize = driver->getScreenSize(); - - const s32 hotbar_itemcount = 8; - //const s32 hotbar_imagesize = 36; - //const s32 hotbar_imagesize = 64; - s32 hotbar_imagesize = 48; + v2u32 screensize = driver->getScreenSize(); /* Draw "Loading" screen @@ -1534,6 +1239,12 @@ void the_game( LocalPlayer* player = client.getEnv().getLocalPlayer(); player->hurt_tilt_timer = 0; player->hurt_tilt_strength = 0; + + /* + HUD object + */ + Hud hud(driver, guienv, font, text_height, + gamedef, player, &local_inventory); for(;;) { @@ -1707,13 +1418,11 @@ void the_game( v2s32 displaycenter(screensize.X/2,screensize.Y/2); //bool screensize_changed = screensize != last_screensize; - // Resize hotbar - if(screensize.Y <= 800) - hotbar_imagesize = 32; - else if(screensize.Y <= 1280) - hotbar_imagesize = 48; - else - hotbar_imagesize = 64; + + // Update HUD values + hud.screensize = screensize; + hud.displaycenter = displaycenter; + hud.resizeHotbar(); // Hilight boxes collected during the loop and displayed std::vector hilightboxes; @@ -2077,7 +1786,7 @@ void the_game( { s32 wheel = input->getMouseWheel(); u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1, - hotbar_itemcount-1); + hud.hotbar_itemcount-1); if(wheel < 0) { @@ -2101,7 +1810,7 @@ void the_game( const KeyPress *kp = NumberKey + (i + 1) % 10; if(input->wasKeyDown(*kp)) { - if(i < PLAYER_INVENTORY_SIZE && i < hotbar_itemcount) + if(i < PLAYER_INVENTORY_SIZE && i < hud.hotbar_itemcount) { new_playeritem = i; @@ -2390,8 +2099,18 @@ void the_game( } else if (event.type == CE_HUDADD) { - HudElement* e = new HudElement; - e->type = event.hudadd.type; + u32 id = event.hudadd.id; + size_t nhudelem = player->hud.size(); + if (id > nhudelem || (id < nhudelem && player->hud[id])) { + delete event.hudadd.pos; + delete event.hudadd.name; + delete event.hudadd.scale; + delete event.hudadd.text; + continue; + } + + HudElement *e = new HudElement; + e->type = (HudElementType)event.hudadd.type; e->pos = *event.hudadd.pos; e->name = *event.hudadd.name; e->scale = *event.hudadd.scale; @@ -2399,33 +2118,61 @@ void the_game( 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); + + if (id == nhudelem) + player->hud.push_back(e); + else + player->hud[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); + u32 id = event.hudrm.id; + if (id < player->hud.size() && player->hud[id]) { + delete player->hud[id]; + player->hud[id] = NULL; + } } 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; + u32 id = event.hudchange.id; + if (id >= player->hud.size() || !player->hud[id]) { + delete event.hudchange.v2fdata; + delete event.hudchange.sdata; + continue; + } + + HudElement* e = player->hud[id]; + switch (event.hudchange.stat) { + case HUD_STAT_POS: + e->pos = *event.hudchange.v2fdata; + break; + case HUD_STAT_NAME: + e->name = *event.hudchange.sdata; + break; + case HUD_STAT_SCALE: + e->scale = *event.hudchange.v2fdata; + break; + case HUD_STAT_TEXT: + e->text = *event.hudchange.sdata; + break; + case HUD_STAT_NUMBER: + e->number = event.hudchange.data; + break; + case HUD_STAT_ITEM: + e->item = event.hudchange.data; + break; + case HUD_STAT_DIR: + e->dir = event.hudchange.data; + break; + } + + delete event.hudchange.v2fdata; + delete event.hudchange.sdata; } } } @@ -3203,7 +2950,6 @@ void the_game( */ TimeTaker tt_draw("mainloop: draw"); - { TimeTaker timer("beginScene"); @@ -3307,26 +3053,8 @@ void the_game( driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); - if(show_hud) - { - v3f selectionbox_color = g_settings->getV3F("selectionbox_color"); - u32 selectionbox_color_r = rangelim(myround(selectionbox_color.X), 0, 255); - u32 selectionbox_color_g = rangelim(myround(selectionbox_color.Y), 0, 255); - u32 selectionbox_color_b = rangelim(myround(selectionbox_color.Z), 0, 255); - - for(std::vector::const_iterator - i = hilightboxes.begin(); - i != hilightboxes.end(); i++) - { - /*infostream<<"hilightbox min=" - <<"("<MinEdge.X<<","<MinEdge.Y<<","<MinEdge.Z<<")" - <<" max=" - <<"("<MaxEdge.X<<","<MaxEdge.Y<<","<MaxEdge.Z<<")" - <draw3DBox(*i, video::SColor(255,selectionbox_color_r,selectionbox_color_g,selectionbox_color_b)); - } - } - + if (show_hud) + hud.drawSelectionBoxes(hilightboxes); /* Wielded tool */ @@ -3354,22 +3082,9 @@ void the_game( /* Draw crosshair */ - if(show_hud) - { - v3f crosshair_color = g_settings->getV3F("crosshair_color"); - u32 crosshair_color_r = rangelim(myround(crosshair_color.X), 0, 255); - u32 crosshair_color_g = rangelim(myround(crosshair_color.Y), 0, 255); - u32 crosshair_color_b = rangelim(myround(crosshair_color.Z), 0, 255); - u32 crosshair_alpha = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255); - - driver->draw2DLine(displaycenter - core::vector2d(10,0), - displaycenter + core::vector2d(10,0), - video::SColor(crosshair_alpha,crosshair_color_r,crosshair_color_g,crosshair_color_b)); - driver->draw2DLine(displaycenter - core::vector2d(0,10), - displaycenter + core::vector2d(0,10), - video::SColor(crosshair_alpha,crosshair_color_r,crosshair_color_g,crosshair_color_b)); - } - + if (show_hud) + hud.drawCrosshair(); + } // timer //timer10.stop(); @@ -3379,11 +3094,9 @@ void the_game( /* Draw hotbar */ - if(show_hud) + if (show_hud) { - draw_hotbar(driver, font, gamedef, - v2s32(displaycenter.X, screensize.Y), - hotbar_imagesize, hotbar_itemcount, &local_inventory, + hud.drawHotbar(v2s32(displaycenter.X, screensize.Y), client.getHP(), client.getPlayerItem()); } @@ -3413,54 +3126,8 @@ void the_game( /* 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 */ @@ -3517,11 +3177,11 @@ void the_game( /* Drop stuff */ - if(clouds) + if (clouds) clouds->drop(); - if(gui_chat_console) + if (gui_chat_console) gui_chat_console->drop(); - clear_particles (); + clear_particles(); /* Draw a "shutting down" screen, which will be shown while the map diff --git a/src/hud.cpp b/src/hud.cpp new file mode 100644 index 000000000..349c55add --- /dev/null +++ b/src/hud.cpp @@ -0,0 +1,291 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2010-2013 blue42u, Jonathon Anderson +Copyright (C) 2010-2013 kwolekr, Ryan Kwolek + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include + +#include "guiFormSpecMenu.h" +#include "main.h" +#include "util/numeric.h" +#include "log.h" +#include "client.h" +#include "hud.h" + + +Hud::Hud(video::IVideoDriver *driver, gui::IGUIEnvironment* guienv, + gui::IGUIFont *font, u32 text_height, IGameDef *gamedef, + LocalPlayer *player, Inventory *inventory) { + this->driver = driver; + this->guienv = guienv; + this->font = font; + this->text_height = text_height; + this->gamedef = gamedef; + this->player = player; + this->inventory = inventory; + + screensize = v2u32(0, 0); + displaycenter = v2s32(0, 0); + hotbar_imagesize = 48; + hotbar_itemcount = 8; + + v3f crosshair_color = g_settings->getV3F("crosshair_color"); + u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255); + u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255); + u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255); + u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255); + crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b); + + v3f selectionbox_color = g_settings->getV3F("selectionbox_color"); + u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255); + u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255); + u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255); + selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b); +} + + +//NOTE: selectitem = 0 -> no selected; selectitem 1-based +void Hud::drawItem(v2s32 upperleftpos, s32 imgsize, s32 itemcount, + InventoryList *mainlist, u16 selectitem, u16 direction) +{ + s32 padding = imgsize / 12; + s32 height = imgsize + padding * 2; + s32 width = itemcount * (imgsize + padding * 2); + if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) { + 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; i < itemcount; i++) + { + const ItemStack &item = mainlist->getItem(i); + + v2s32 steppos; + switch (direction) { + case HUD_DIR_RIGHT_LEFT: + steppos = v2s32(-(padding + i * fullimglen), padding); + break; + case HUD_DIR_TOP_BOTTOM: + steppos = v2s32(padding, padding + i * fullimglen); + break; + case HUD_DIR_BOTTOM_TOP: + steppos = v2s32(padding, -(padding + i * fullimglen)); + break; + default: + 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); + } +} + + +void Hud::drawLuaElements() { + for (size_t i = 0; i != player->hud.size(); i++) { + HudElement *e = player->hud[i]; + if (!e) + continue; + + v2s32 pos(e->pos.X * screensize.X, e->pos.Y * screensize.Y); + switch (e->type) { + case HUD_ELEM_IMAGE: { + video::ITexture *texture = + gamedef->getTextureSource()->getTextureRaw(e->text); + if (!texture) + continue; + + 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); + break; } + case HUD_ELEM_TEXT: { + video::SColor color(255, (e->number >> 16) & 0xFF, + (e->number >> 8) & 0xFF, + (e->number >> 0) & 0xFF); + core::rect size(0, 0, e->scale.X, text_height * e->scale.Y); + font->draw(narrow_to_wide(e->text).c_str(), size + pos, color); + break; } + case HUD_ELEM_STATBAR: + drawStatbar(pos, e->text, e->number); + break; + case HUD_ELEM_INVENTORY: { + InventoryList *inv = inventory->getList(e->text); + drawItem(pos, hotbar_imagesize, e->number, inv, e->item, e->dir); + break; } + default: + infostream << "Hud::drawLuaElements: ignoring drawform " << e->type << + "of hud element ID " << i << " due to unrecognized type" << std::endl; + } + } +} + + +void Hud::drawStatbar(v2s32 upperleftpos, std::string texture, s32 count) { + video::ITexture *stat_texture = + gamedef->getTextureSource()->getTextureRaw(texture); + if (!stat_texture) + return; + + 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 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); + } +} + + +void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem) { + InventoryList *mainlist = inventory->getList("main"); + if (mainlist == NULL) { + errorstream << "draw_hotbar(): mainlist == NULL" << std::endl; + return; + } + + s32 padding = hotbar_imagesize / 12; + s32 width = hotbar_itemcount * (hotbar_imagesize + padding * 2); + v2s32 pos = centerlowerpos - v2s32(width / 2, hotbar_imagesize + padding * 2); + + drawItem(pos, hotbar_imagesize, hotbar_itemcount, mainlist, playeritem + 1, 0); + drawStatbar(pos + v2s32(0, -20), "heart.png", halfheartcount); +} + + +void Hud::drawCrosshair() { + driver->draw2DLine(displaycenter - v2s32(10,0), + displaycenter + v2s32(10, 0), crosshair_argb); + driver->draw2DLine(displaycenter - v2s32(0,10), + displaycenter + v2s32(0, 10), crosshair_argb); +} + + +void Hud::drawSelectionBoxes(std::vector &hilightboxes) { + for (std::vector::const_iterator + i = hilightboxes.begin(); + i != hilightboxes.end(); i++) { + driver->draw3DBox(*i, selectionbox_argb); + } +} + + +void Hud::resizeHotbar() { + if (screensize.Y <= 800) + hotbar_imagesize = 32; + else if (screensize.Y <= 1280) + hotbar_imagesize = 48; + else + hotbar_imagesize = 64; +} diff --git a/src/hud.h b/src/hud.h new file mode 100644 index 000000000..7e00a94e3 --- /dev/null +++ b/src/hud.h @@ -0,0 +1,116 @@ +/* +Minetest +Copyright (C) 2010-2013 kwolekr, Ryan Kwolek + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef HUD_HEADER +#define HUD_HEADER + +#include "irrlichttypes_extrabloated.h" + +#define HUD_DIR_LEFT_RIGHT 0 +#define HUD_DIR_RIGHT_LEFT 1 +#define HUD_DIR_TOP_BOTTOM 2 +#define HUD_DIR_BOTTOM_TOP 3 + +class Player; + +enum HudElementType { + HUD_ELEM_IMAGE = 0, + HUD_ELEM_TEXT = 1, + HUD_ELEM_STATBAR = 2, + HUD_ELEM_INVENTORY = 3 +}; + +enum HudElementStat { + HUD_STAT_POS, + HUD_STAT_NAME, + HUD_STAT_SCALE, + HUD_STAT_TEXT, + HUD_STAT_NUMBER, + HUD_STAT_ITEM, + HUD_STAT_DIR +}; + +struct HudElement { + HudElementType type; + v2f pos; + std::string name; + v2f scale; + std::string text; + u32 number; + u32 item; + u32 dir; +}; + + +inline u32 hud_get_free_id(Player *player) { + size_t size = player->hud.size(); + for (size_t i = 0; i != size; i++) { + if (!player->hud[i]) + return i; + } + return size; +} + +#ifndef SERVER + +#include + +#include + +#include "gamedef.h" +#include "inventory.h" +#include "localplayer.h" + +class Hud { +public: + video::IVideoDriver *driver; + gui::IGUIEnvironment *guienv; + gui::IGUIFont *font; + u32 text_height; + IGameDef *gamedef; + LocalPlayer *player; + Inventory *inventory; + + v2u32 screensize; + v2s32 displaycenter; + s32 hotbar_imagesize; + s32 hotbar_itemcount; + + video::SColor crosshair_argb; + video::SColor selectionbox_argb; + + Hud(video::IVideoDriver *driver, gui::IGUIEnvironment* guienv, + gui::IGUIFont *font, u32 text_height, IGameDef *gamedef, + LocalPlayer *player, Inventory *inventory); + + void drawItem(v2s32 upperleftpos, s32 imgsize, s32 itemcount, + InventoryList *mainlist, u16 selectitem, u16 direction); + void drawLuaElements(); + void drawStatbar(v2s32 upperleftpos, std::string texture, s32 count); + + void drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem); + void resizeHotbar(); + + void drawCrosshair(); + void drawSelectionBoxes(std::vector &hilightboxes); +}; + +#endif + +#endif diff --git a/src/player.h b/src/player.h index fc80769c2..d0e50d2c3 100644 --- a/src/player.h +++ b/src/player.h @@ -87,7 +87,7 @@ class Map; class IGameDef; struct CollisionInfo; class PlayerSAO; -struct HudElement; +class HudElement; class Player { @@ -243,9 +243,8 @@ public: } u32 keyPressed; - - std::map hud; - std::map hud_bars; + + std::vector hud; protected: IGameDef *m_gamedef; @@ -257,17 +256,6 @@ 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 8f92ca439..531bb7a58 100644 --- a/src/scriptapi_object.cpp +++ b/src/scriptapi_object.cpp @@ -26,6 +26,30 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "scriptapi_item.h" #include "scriptapi_entity.h" #include "scriptapi_common.h" +#include "hud.h" + + +struct EnumString es_HudElementType[] = +{ + {HUD_ELEM_IMAGE, "image"}, + {HUD_ELEM_TEXT, "text"}, + {HUD_ELEM_STATBAR, "statbar"}, + {HUD_ELEM_INVENTORY, "inventory"}, + {0, NULL}, +}; + +struct EnumString es_HudElementStat[] = +{ + {HUD_STAT_POS, "pos"}, + {HUD_STAT_NAME, "name"}, + {HUD_STAT_SCALE, "scale"}, + {HUD_STAT_TEXT, "text"}, + {HUD_STAT_NUMBER, "number"}, + {HUD_STAT_ITEM, "item"}, + {HUD_STAT_DIR, "direction"}, + {0, NULL}, +}; + /* ObjectRef @@ -705,205 +729,161 @@ int ObjectRef::l_hud_add(lua_State *L) { ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); - if(player == NULL) return 0; + 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(); + HudElement *elem = new HudElement; + + elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type", + es_HudElementType, HUD_ELEM_TEXT); + + lua_getfield(L, 2, "position"); + elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : 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_getfield(L, 2, "scale"); + elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); + + elem->name = getstringfield_default(L, 2, "name", ""); + elem->text = getstringfield_default(L, 2, "text", ""); + elem->number = getintfield_default(L, 2, "number", 0); + elem->item = getintfield_default(L, 2, "item", 0); + elem->dir = getintfield_default(L, 2, "dir", 0); - 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); + u32 id = get_server(L)->hudAdd(player, elem); + if (id == (u32)-1) { + delete elem; + return 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) +// hud_remove(self, id) +int ObjectRef::l_hud_remove(lua_State *L) { ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); - if(player == NULL) return 0; + if (player == NULL) + return 0; u32 id = -1; - if(!lua_isnil(L, 2)) + if (!lua_isnil(L, 2)) id = lua_tonumber(L, 2); - get_server(L)->hudrm(player->getName(), id); - player->hud.at(id)->type = (u8)NULL; + + if (!get_server(L)->hudRemove(player, id)) + return 0; + 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; + if (player == NULL) + return 0; u32 id = -1; - if(!lua_isnil(L, 2)) + 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); + + HudElementStat stat = (HudElementStat)getenumfield(L, 3, "stat", + es_HudElementStat, HUD_STAT_NUMBER); + + if (id >= player->hud.size()) + return 0; + + void *value = NULL; + HudElement *e = player->hud[id]; + if (!e) + return 0; + + switch (stat) { + case HUD_STAT_POS: + e->pos = read_v2f(L, 4); + value = &e->pos; + break; + case HUD_STAT_NAME: + e->name = lua_tostring(L, 4); + value = &e->name; + break; + case HUD_STAT_SCALE: + e->scale = read_v2f(L, 4); + value = &e->scale; + break; + case HUD_STAT_TEXT: + e->text = lua_tostring(L, 4); + value = &e->text; + break; + case HUD_STAT_NUMBER: + e->number = lua_tonumber(L, 4); + value = &e->number; + break; + case HUD_STAT_ITEM: + e->item = lua_tonumber(L, 4); + value = &e->item; + break; + case HUD_STAT_DIR: + e->dir = lua_tonumber(L, 4); + value = &e->dir; } + + get_server(L)->hudChange(player, id, stat, value); 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; + if (player == NULL) + return 0; - HudElement* e = player->hud.at(lua_tonumber(L, -1)); + u32 id = lua_tonumber(L, -1); + if (id >= player->hud.size()) + return 0; + + HudElement *e = player->hud[id]; + if (!e) + return 0; + lua_newtable(L); - lua_pushstring(L, std::string(1, e->type).c_str()); + + lua_pushstring(L, es_HudElementType[(u8)e->type].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) { @@ -1011,11 +991,11 @@ const luaL_reg ObjectRef::methods[] = { luamethod(ObjectRef, get_player_control), luamethod(ObjectRef, get_player_control_bits), luamethod(ObjectRef, hud_add), - luamethod(ObjectRef, hud_rm), + luamethod(ObjectRef, hud_remove), luamethod(ObjectRef, hud_change), luamethod(ObjectRef, hud_get), - luamethod(ObjectRef, hud_lock_next_bar), - luamethod(ObjectRef, hud_unlock_bar), + //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 6df4366bb..fd46f2cf6 100644 --- a/src/scriptapi_object.h +++ b/src/scriptapi_object.h @@ -29,14 +29,6 @@ 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 */ @@ -202,23 +194,14 @@ private: static int l_hud_add(lua_State *L); // hud_rm(self, id) - static int l_hud_rm(lua_State *L); + static int l_hud_remove(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/server.cpp b/src/server.cpp index a9632c93c..241826ba2 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3449,7 +3449,9 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message) // Send as reliable m_con.Send(peer_id, 0, data, true); } -void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname) + +void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, + const std::string formname) { DSTACK(__FUNCTION_NAME); @@ -3470,7 +3472,9 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, co } // Spawns a particle on peer with peer_id -void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture) +void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, + float expirationtime, float size, bool collisiondetection, + std::string texture) { DSTACK(__FUNCTION_NAME); @@ -3492,7 +3496,9 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat } // Spawns a particle on all peers -void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture) +void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration, + float expirationtime, float size, bool collisiondetection, + std::string texture) { for(std::map::iterator i = m_clients.begin(); @@ -3595,22 +3601,18 @@ void Server::SendDeleteParticleSpawnerAll(u32 id) } } -void Server::SendHUDAdd(u16 peer_id, const u32 id, HudElement* form) +void Server::SendHUDAdd(u16 peer_id, 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); + writeU16(os, TOCLIENT_HUDADD); writeU32(os, id); - writeU8(os, form->type); + writeU8(os, (u8)form->type); writeV2F1000(os, form->pos); - os<name); + os << serializeString(form->name); writeV2F1000(os, form->scale); - os<text); + os << serializeString(form->text); writeU32(os, form->number); writeU32(os, form->item); writeU32(os, form->dir); @@ -3622,16 +3624,12 @@ void Server::SendHUDAdd(u16 peer_id, const u32 id, HudElement* form) m_con.Send(peer_id, 0, data, true); } -void Server::SendHUDRm(u16 peer_id, const u32 id) +void Server::SendHUDRemove(u16 peer_id, 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); + writeU16(os, TOCLIENT_HUDRM); writeU32(os, id); // Make data buffer @@ -3641,67 +3639,36 @@ void Server::SendHUDRm(u16 peer_id, const u32 id) m_con.Send(peer_id, 0, data, true); } -void Server::SendHUDChange(u16 peer_id, const u32 id, const u8 stat, v2f data) +void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value) { - DSTACK(__FUNCTION_NAME); - std::ostringstream os(std::ios_base::binary); - u8 buf[12]; // Write command - writeU16(buf, TOCLIENT_HUDCHANGE); - os.write((char*)buf, 2); + writeU16(os, TOCLIENT_HUDCHANGE); writeU32(os, id); - writeU8(os, stat); - writeV2F1000(os, data); + writeU8(os, (u8)stat); + switch (stat) { + case HUD_STAT_POS: + case HUD_STAT_SCALE: + writeV2F1000(os, *(v2f *)value); + break; + case HUD_STAT_NAME: + case HUD_STAT_TEXT: + os << serializeString(*(std::string *)value); + break; + case HUD_STAT_NUMBER: + case HUD_STAT_ITEM: + case HUD_STAT_DIR: + default: + writeU32(os, *(u32 *)value); + break; + } // Make data buffer std::string s = os.str(); - SharedBuffer ddata((u8*)s.c_str(), s.size()); + SharedBuffer data((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); + m_con.Send(peer_id, 0, data, true); } void Server::BroadcastChatMessage(const std::wstring &message) @@ -4657,71 +4624,34 @@ 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:"<hud.size()) + player->hud[id] = form; + else + player->hud.push_back(form); + SendHUDAdd(player->peer_id, id, form); + return id; +} + +bool Server::hudRemove(Player *player, u32 id) { + if (!player || id >= player->hud.size() || !player->hud[id]) + return false; + + delete player->hud[id]; + player->hud[id] = NULL; + + SendHUDRemove(player->peer_id, id); 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; diff --git a/src/server.h b/src/server.h index ef0c45a6a..52606b0cb 100644 --- a/src/server.h +++ b/src/server.h @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "map.h" #include "inventory.h" #include "ban.h" +#include "hud.h" #include "gamedef.h" #include "serialization.h" // For SER_FMT_VER_INVALID #include "mods.h" @@ -51,6 +52,7 @@ class EventManager; class PlayerSAO; class IRollbackManager; class EmergeManager; +//struct HudElement; class ServerError : public std::exception { @@ -534,11 +536,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); + + u32 hudAdd(Player *player, HudElement *element); + bool hudRemove(Player *player, u32 id); + bool hudChange(Player *player, u32 id, HudElementStat stat, void *value); + private: // con::PeerHandler implementation. @@ -578,11 +580,9 @@ 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); + void SendHUDAdd(u16 peer_id, u32 id, HudElement *form); + void SendHUDRemove(u16 peer_id, u32 id); + void SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value); /* Send a node removal/addition event to all clients except ignore_id. Additionally, if far_players!=NULL, players further away than