Skip to content

Commit

Permalink
Add formspec theming using prepended strings
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenwardy committed Mar 28, 2018
1 parent 040b878 commit 2323842
Show file tree
Hide file tree
Showing 16 changed files with 150 additions and 18 deletions.
15 changes: 15 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -2001,6 +2001,10 @@ supported. It is a string, with a somewhat strange format.
Spaces and newlines can be inserted between the blocks, as is used in the
examples.

WARNING: Minetest allows you to add elements to every single formspec instance
using player:set_formspec_prepend(), which may be the reason backgrounds are
appearing when you don't expect them to. See `no_prepend[]`

### Examples

#### Chest
Expand Down Expand Up @@ -2053,6 +2057,10 @@ examples.
* `position` and `anchor` elements need suitable values to avoid a formspec
extending off the game window due to particular game window sizes.

#### `no_prepend[]`
* Must be used after the `size`, `position`, and `anchor` elements (if present).
* Disables player:set_formspec_prepend() from applying to this formspec.

#### `container[<X>,<Y>]`
* Start of a container block, moves all physical elements in the container by
(X, Y).
Expand Down Expand Up @@ -4046,6 +4054,13 @@ This is basically a reference to a C++ `ServerActiveObject`
* Redefine player's inventory form
* Should usually be called in `on_joinplayer`
* `get_inventory_formspec()`: returns a formspec string
* `set_formspec_prepend(formspec)`:
* the formspec string will be added to every formspec shown to the user,
except for those with a no_prepend[] tag.
* This should be used to set style elements such as background[] and
bgcolor[], any non-style elements (eg: label) may result in weird behaviour.
* Only affects formspecs shown after this is called.
* `get_formspec_prepend(formspec)`: returns a formspec string.
* `get_player_control()`: returns table with player pressed keys
* The table consists of fields with boolean value representing the pressed
keys, the fields are jump, right, left, LMB, RMB, sneak, aux1, down, up.
Expand Down
7 changes: 6 additions & 1 deletion src/client.h
Expand Up @@ -224,7 +224,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
void handleCommand_UpdatePlayerList(NetworkPacket* pkt);
void handleCommand_ModChannelMsg(NetworkPacket *pkt);
void handleCommand_ModChannelSignal(NetworkPacket *pkt);
void handleCommand_SrpBytesSandB(NetworkPacket* pkt);
void handleCommand_SrpBytesSandB(NetworkPacket *pkt);
void handleCommand_FormspecPrepend(NetworkPacket *pkt);
void handleCommand_CSMFlavourLimits(NetworkPacket *pkt);

void ProcessData(NetworkPacket *pkt);
Expand Down Expand Up @@ -432,6 +433,10 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
bool sendModChannelMessage(const std::string &channel, const std::string &message);
ModChannel *getModChannel(const std::string &channel);

const std::string &getFormspecPrepend() const
{
return m_env.getLocalPlayer()->formspec_prepend;
}
private:
void loadMods();
bool checkBuiltinIntegrity();
Expand Down
2 changes: 1 addition & 1 deletion src/clientenvironment.h
Expand Up @@ -78,7 +78,7 @@ class ClientEnvironment : public Environment
void step(f32 dtime);

virtual void setLocalPlayer(LocalPlayer *player);
LocalPlayer *getLocalPlayer() { return m_local_player; }
LocalPlayer *getLocalPlayer() const { return m_local_player; }

/*
ClientSimpleObjects
Expand Down
12 changes: 7 additions & 5 deletions src/game.cpp
Expand Up @@ -2028,7 +2028,7 @@ void Game::openInventory()
|| !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
TextDest *txt_dst = new TextDestPlayerInventory(client);
GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
txt_dst);
txt_dst, client->getFormspecPrepend());
cur_formname = "";
current_formspec->setFormSpec(fs_src->getForm(), inventoryloc);
}
Expand Down Expand Up @@ -2535,7 +2535,7 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
new TextDestPlayerInventory(client, *(event->show_formspec.formname));

GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
fs_src, txt_dst);
fs_src, txt_dst, client->getFormspecPrepend());
cur_formname = *(event->show_formspec.formname);
}

Expand All @@ -2548,7 +2548,8 @@ void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrienta
FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
LocalFormspecHandler *txt_dst =
new LocalFormspecHandler(*event->show_formspec.formname, client);
GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src, txt_dst);
GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend());

delete event->show_formspec.formspec;
delete event->show_formspec.formname;
Expand Down Expand Up @@ -3210,7 +3211,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);

GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
txt_dst);
txt_dst, client->getFormspecPrepend());
cur_formname.clear();

current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
Expand Down Expand Up @@ -4105,7 +4106,8 @@ void Game::showPauseMenu()
FormspecFormSource *fs_src = new FormspecFormSource(os.str());
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");

GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src, txt_dst);
GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend());
current_formspec->setFocus("btn_continue");
current_formspec->doPause = true;
}
Expand Down
1 change: 1 addition & 0 deletions src/gui/guiEngine.cpp
Expand Up @@ -165,6 +165,7 @@ GUIEngine::GUIEngine(JoystickController *joystick,
m_texture_source,
m_formspecgui,
m_buttonhandler,
"",
false);

m_menu->allowClose(false);
Expand Down
36 changes: 29 additions & 7 deletions src/gui/guiFormSpecMenu.cpp
Expand Up @@ -86,11 +86,13 @@ inline u32 clamp_u8(s32 value)
GUIFormSpecMenu::GUIFormSpecMenu(JoystickController *joystick,
gui::IGUIElement *parent, s32 id, IMenuManager *menumgr,
Client *client, ISimpleTextureSource *tsrc, IFormSource *fsrc, TextDest *tdst,
bool remap_dbl_click) :
std::string formspecPrepend,
bool remap_dbl_click):
GUIModalMenu(RenderingEngine::get_gui_env(), parent, id, menumgr),
m_invmgr(client),
m_tsrc(tsrc),
m_client(client),
m_formspec_prepend(formspecPrepend),
m_form_src(fsrc),
m_text_dst(tdst),
m_joystick(joystick),
Expand Down Expand Up @@ -128,11 +130,12 @@ GUIFormSpecMenu::~GUIFormSpecMenu()
}

void GUIFormSpecMenu::create(GUIFormSpecMenu *&cur_formspec, Client *client,
JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest)
JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest,
const std::string &formspecPrepend)
{
if (cur_formspec == nullptr) {
cur_formspec = new GUIFormSpecMenu(joystick, guiroot, -1, &g_menumgr,
client, client->getTextureSource(), fs_src, txt_dest);
client, client->getTextureSource(), fs_src, txt_dest, formspecPrepend);
cur_formspec->doPause = false;

/*
Expand All @@ -144,6 +147,7 @@ void GUIFormSpecMenu::create(GUIFormSpecMenu *&cur_formspec, Client *client,
*/

} else {
cur_formspec->setFormspecPrepend(formspecPrepend);
cur_formspec->setFormSource(fs_src);
cur_formspec->setTextDest(txt_dest);
}
Expand Down Expand Up @@ -2008,7 +2012,6 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
);
}


m_slotbg_n = video::SColor(255,128,128,128);
m_slotbg_h = video::SColor(255,192,192,192);

Expand Down Expand Up @@ -2040,7 +2043,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)

/* try to read version from first element only */
if (!elements.empty()) {
if ( parseVersionDirect(elements[0]) ) {
if (parseVersionDirect(elements[0])) {
i++;
}
}
Expand All @@ -2067,6 +2070,18 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
}
}

/* "no_prepend" element is always after "position" (or "size" element) if it used */
bool enable_prepends = true;
for (; i < elements.size(); i++) {
if (elements[i].empty())
break;

std::vector<std::string> parts = split(elements[i], '[');
if (parts[0] == "no_prepend")
enable_prepends = false;
else
break;
}

if (mydata.explicit_size) {
// compute scaling for specified form size
Expand Down Expand Up @@ -2120,7 +2135,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
// multiplied by gui_scaling, even if this means
// the form doesn't fit the screen.
double prefer_imgsize = mydata.screensize.Y / 15 *
gui_scaling;
gui_scaling;
double fitx_imgsize = mydata.screensize.X /
((5.0/4.0) * (0.5 + mydata.invsize.X));
double fity_imgsize = mydata.screensize.Y /
Expand Down Expand Up @@ -2173,12 +2188,19 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
mydata.basepos = getBasePos();
m_tooltip_element->setOverrideFont(m_font);

gui::IGUISkin* skin = Environment->getSkin();
gui::IGUISkin *skin = Environment->getSkin();
sanity_check(skin);
gui::IGUIFont *old_font = skin->getFont();
skin->setFont(m_font);

pos_offset = v2s32();

if (enable_prepends) {
std::vector<std::string> prepend_elements = split(m_formspec_prepend, ']');
for (const auto &element : prepend_elements)
parseElement(&mydata, element);
}

for (; i< elements.size(); i++) {
parseElement(&mydata, elements[i]);
}
Expand Down
10 changes: 9 additions & 1 deletion src/gui/guiFormSpecMenu.h
Expand Up @@ -287,12 +287,14 @@ class GUIFormSpecMenu : public GUIModalMenu
ISimpleTextureSource *tsrc,
IFormSource* fs_src,
TextDest* txt_dst,
std::string formspecPrepend,
bool remap_dbl_click = true);

~GUIFormSpecMenu();

static void create(GUIFormSpecMenu *&cur_formspec, Client *client,
JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest);
JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest,
const std::string &formspecPrepend);

void setFormSpec(const std::string &formspec_string,
const InventoryLocation &current_inventory_location)
Expand All @@ -302,6 +304,11 @@ class GUIFormSpecMenu : public GUIModalMenu
regenerateGui(m_screensize_old);
}

void setFormspecPrepend(const std::string &formspecPrepend)
{
m_formspec_prepend = formspecPrepend;
}

// form_src is deleted by this GUIFormSpecMenu
void setFormSource(IFormSource *form_src)
{
Expand Down Expand Up @@ -378,6 +385,7 @@ class GUIFormSpecMenu : public GUIModalMenu
Client *m_client;

std::string m_formspec_string;
std::string m_formspec_prepend;
InventoryLocation m_current_inventory_location;

std::vector<ListDrawSpec> m_inventorylists;
Expand Down
1 change: 1 addition & 0 deletions src/network/clientopcodes.cpp
Expand Up @@ -121,6 +121,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
null_command_handler,
null_command_handler,
{ "TOCLIENT_SRP_BYTES_S_B", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_SrpBytesSandB }, // 0x60
{ "TOCLIENT_FORMSPEC_PREPEND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FormspecPrepend }, // 0x61,
};

const static ServerCommandFactory null_command_factory = { "TOSERVER_NULL", 0, false };
Expand Down
9 changes: 9 additions & 0 deletions src/network/clientpackethandler.cpp
Expand Up @@ -1324,6 +1324,15 @@ void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
Send(&resp_pkt);
}

void Client::handleCommand_FormspecPrepend(NetworkPacket *pkt)
{
LocalPlayer *player = m_env.getLocalPlayer();
assert(player != NULL);

// Store formspec in LocalPlayer
*pkt >> player->formspec_prepend;
}

void Client::handleCommand_CSMFlavourLimits(NetworkPacket *pkt)
{
*pkt >> m_csm_flavour_limits >> m_csm_noderange_limit;
Expand Down
10 changes: 8 additions & 2 deletions src/network/networkprotocol.h
Expand Up @@ -187,6 +187,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
'zoom_fov'.
Nodebox version 5
Add disconnected nodeboxes
Add TOCLIENT_FORMSPEC_PREPEND
*/

#define LATEST_PROTOCOL_VERSION 36
Expand Down Expand Up @@ -644,7 +645,13 @@ enum ToClientCommand
std::string bytes_B
*/

TOCLIENT_NUM_MSG_TYPES = 0x61,
TOCLIENT_FORMSPEC_PREPEND = 0x61,
/*
u16 len
u8[len] formspec
*/

TOCLIENT_NUM_MSG_TYPES = 0x62,
};

enum ToServerCommand
Expand Down Expand Up @@ -930,4 +937,3 @@ enum CSMFlavourLimit : u64 {
CSM_FL_LOOKUP_NODES = 0x00000010, // Limit node lookups
CSM_FL_ALL = 0xFFFFFFFF,
};

1 change: 1 addition & 0 deletions src/network/serveropcodes.cpp
Expand Up @@ -210,4 +210,5 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
null_command_factory,
null_command_factory,
{ "TOSERVER_SRP_BYTES_S_B", 0, true }, // 0x60
{ "TOCLIENT_FORMSPEC_PREPEND", 0, true }, // 0x61
};
1 change: 1 addition & 0 deletions src/player.h
Expand Up @@ -148,6 +148,7 @@ class Player
float local_animation_speed;

std::string inventory_formspec;
std::string formspec_prepend;

PlayerControl control;
const PlayerControl& getPlayerControl() { return control; }
Expand Down
33 changes: 33 additions & 0 deletions src/script/lua_api/l_object.cpp
Expand Up @@ -1244,6 +1244,37 @@ int ObjectRef::l_get_inventory_formspec(lua_State *L)
return 1;
}

// set_formspec_prepend(self, formspec)
int ObjectRef::l_set_formspec_prepend(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (player == NULL)
return 0;

std::string formspec = luaL_checkstring(L, 2);

player->formspec_prepend = formspec;
getServer(L)->reportFormspecPrependModified(player->getName());
lua_pushboolean(L, true);
return 1;
}

// get_formspec_prepend(self) -> formspec
int ObjectRef::l_get_formspec_prepend(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (player == NULL)
return 0;

std::string formspec = player->formspec_prepend;
lua_pushlstring(L, formspec.c_str(), formspec.size());
return 1;
}

// get_player_control(self)
int ObjectRef::l_get_player_control(lua_State *L)
{
Expand Down Expand Up @@ -1817,6 +1848,8 @@ const luaL_Reg ObjectRef::methods[] = {
luamethod(ObjectRef, set_attribute),
luamethod(ObjectRef, set_inventory_formspec),
luamethod(ObjectRef, get_inventory_formspec),
luamethod(ObjectRef, set_formspec_prepend),
luamethod(ObjectRef, get_formspec_prepend),
luamethod(ObjectRef, get_player_control),
luamethod(ObjectRef, get_player_control_bits),
luamethod(ObjectRef, set_physics_override),
Expand Down
6 changes: 6 additions & 0 deletions src/script/lua_api/l_object.h
Expand Up @@ -253,6 +253,12 @@ class ObjectRef : public ModApiBase {
// get_inventory_formspec(self) -> formspec
static int l_get_inventory_formspec(lua_State *L);

// set_formspec_prepend(self, formspec)
static int l_set_formspec_prepend(lua_State *L);

// get_formspec_prepend(self) -> formspec
static int l_get_formspec_prepend(lua_State *L);

// get_player_control(self)
static int l_get_player_control(lua_State *L);

Expand Down

0 comments on commit 2323842

Please sign in to comment.