mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01:00 
			
		
		
		
	Formspec: Show a player inventory using core.show_formspec (#15963)
'core.show_formspec' now shows and updates the inventory formspec as if it was opened using the hotkey on client-side.
This commit is contained in:
		@@ -6872,10 +6872,15 @@ Formspec
 | 
			
		||||
* `core.show_formspec(playername, formname, formspec)`
 | 
			
		||||
    * `playername`: name of player to show formspec
 | 
			
		||||
    * `formname`: name passed to `on_player_receive_fields` callbacks.
 | 
			
		||||
      It should follow the `"modname:<whatever>"` naming convention.
 | 
			
		||||
    * `formname` must not be empty, unless you want to reshow
 | 
			
		||||
      the inventory formspec without updating it for future opens.
 | 
			
		||||
        * It should follow the `"modname:<whatever>"` naming convention.
 | 
			
		||||
        * If empty: Shows a custom, temporary inventory formspec.
 | 
			
		||||
            * An inventory formspec shown this way will also be updated if
 | 
			
		||||
              `ObjectRef:set_inventory_formspec` is called.
 | 
			
		||||
            * Use `ObjectRef:set_inventory_formspec` to change the player's
 | 
			
		||||
              inventory formspec for future opens.
 | 
			
		||||
            * Supported if server AND client are both of version >= 5.13.0.
 | 
			
		||||
    * `formspec`: formspec to display
 | 
			
		||||
    * See also: `core.register_on_player_receive_fields`
 | 
			
		||||
* `core.close_formspec(playername, formname)`
 | 
			
		||||
    * `playername`: name of player to close formspec
 | 
			
		||||
    * `formname`: has to exactly match the one given in `show_formspec`, or the
 | 
			
		||||
@@ -8653,9 +8658,12 @@ child will follow movement and rotation of that bone.
 | 
			
		||||
    * Returns `nil` if no attribute found.
 | 
			
		||||
* `get_meta()`: Returns metadata associated with the player (a PlayerMetaRef).
 | 
			
		||||
* `set_inventory_formspec(formspec)`
 | 
			
		||||
    * Redefine player's inventory form
 | 
			
		||||
    * Should usually be called in `on_joinplayer`
 | 
			
		||||
    * Redefines the player's inventory formspec.
 | 
			
		||||
    * Should usually be called at least once in the `on_joinplayer` callback.
 | 
			
		||||
    * If `formspec` is `""`, the player's inventory is disabled.
 | 
			
		||||
    * If the inventory formspec is currently open on the client, it is
 | 
			
		||||
      updated immediately.
 | 
			
		||||
    * See also: `core.register_on_player_receive_fields`
 | 
			
		||||
* `get_inventory_formspec()`: returns a formspec string
 | 
			
		||||
* `set_formspec_prepend(formspec)`:
 | 
			
		||||
    * the formspec string will be added to every formspec shown to the user,
 | 
			
		||||
 
 | 
			
		||||
@@ -1925,7 +1925,7 @@ void Game::processKeyInput()
 | 
			
		||||
		if (g_settings->getBool("continuous_forward"))
 | 
			
		||||
			toggleAutoforward();
 | 
			
		||||
	} else if (wasKeyDown(KeyType::INVENTORY)) {
 | 
			
		||||
		m_game_formspec.showPlayerInventory();
 | 
			
		||||
		m_game_formspec.showPlayerInventory(nullptr);
 | 
			
		||||
	} else if (input->cancelPressed()) {
 | 
			
		||||
#ifdef __ANDROID__
 | 
			
		||||
		m_android_chat_open = false;
 | 
			
		||||
@@ -2714,11 +2714,16 @@ void Game::handleClientEvent_DeathscreenLegacy(ClientEvent *event, CameraOrienta
 | 
			
		||||
 | 
			
		||||
void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam)
 | 
			
		||||
{
 | 
			
		||||
	m_game_formspec.showFormSpec(*event->show_formspec.formspec,
 | 
			
		||||
		*event->show_formspec.formname);
 | 
			
		||||
	auto &fs = event->show_formspec;
 | 
			
		||||
 | 
			
		||||
	delete event->show_formspec.formspec;
 | 
			
		||||
	delete event->show_formspec.formname;
 | 
			
		||||
	if (fs.formname->empty() && !fs.formspec->empty()) {
 | 
			
		||||
		m_game_formspec.showPlayerInventory(fs.formspec);
 | 
			
		||||
	} else {
 | 
			
		||||
		m_game_formspec.showFormSpec(*fs.formspec, *fs.formname);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	delete fs.formspec;
 | 
			
		||||
	delete fs.formname;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Game::handleClientEvent_ShowCSMFormSpec(ClientEvent *event, CameraOrientation *cam)
 | 
			
		||||
 
 | 
			
		||||
@@ -178,6 +178,10 @@ public:
 | 
			
		||||
	const std::string &getForm() const
 | 
			
		||||
	{
 | 
			
		||||
		LocalPlayer *player = m_client->getEnv().getLocalPlayer();
 | 
			
		||||
 | 
			
		||||
		if (!player->inventory_formspec_override.empty())
 | 
			
		||||
			return player->inventory_formspec_override;
 | 
			
		||||
 | 
			
		||||
		return player->inventory_formspec;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -304,7 +308,7 @@ void GameFormSpec::showNodeFormspec(const std::string &formspec, const v3s16 &no
 | 
			
		||||
	m_formspec->setFormSpec(formspec, inventoryloc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameFormSpec::showPlayerInventory()
 | 
			
		||||
void GameFormSpec::showPlayerInventory(const std::string *fs_override)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * Don't permit to open inventory is CAO or player doesn't exists.
 | 
			
		||||
@@ -317,28 +321,35 @@ void GameFormSpec::showPlayerInventory()
 | 
			
		||||
 | 
			
		||||
	infostream << "Game: Launching inventory" << std::endl;
 | 
			
		||||
 | 
			
		||||
	PlayerInventoryFormSource *fs_src = new PlayerInventoryFormSource(m_client);
 | 
			
		||||
	auto fs_src = std::make_unique<PlayerInventoryFormSource>(m_client);
 | 
			
		||||
 | 
			
		||||
	InventoryLocation inventoryloc;
 | 
			
		||||
	inventoryloc.setCurrentPlayer();
 | 
			
		||||
 | 
			
		||||
	if (m_client->modsLoaded() && m_client->getScript()->on_inventory_open(m_client->getInventory(inventoryloc))) {
 | 
			
		||||
		delete fs_src;
 | 
			
		||||
		return;
 | 
			
		||||
	if (fs_override) {
 | 
			
		||||
		// Temporary overwrite for this specific formspec.
 | 
			
		||||
		player->inventory_formspec_override = *fs_override;
 | 
			
		||||
	} else {
 | 
			
		||||
		// Show the regular inventory formspec
 | 
			
		||||
		player->inventory_formspec_override.clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fs_src->getForm().empty()) {
 | 
			
		||||
		delete fs_src;
 | 
			
		||||
	// If prevented by Client-Side Mods
 | 
			
		||||
	if (m_client->modsLoaded() && m_client->getScript()->on_inventory_open(m_client->getInventory(inventoryloc)))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// Empty formspec -> do not show.
 | 
			
		||||
	if (fs_src->getForm().empty())
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TextDest *txt_dst = new TextDestPlayerInventory(m_client);
 | 
			
		||||
 | 
			
		||||
	GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(),
 | 
			
		||||
		&m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(),
 | 
			
		||||
		&m_input->joystick, fs_src.get(), txt_dst, m_client->getFormspecPrepend(),
 | 
			
		||||
		m_client->getSoundManager());
 | 
			
		||||
 | 
			
		||||
	m_formspec->setFormSpec(fs_src->getForm(), inventoryloc);
 | 
			
		||||
	fs_src.release(); // owned by GUIFormSpecMenu
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define SIZE_TAG "size[11,5.5,true]" // Fixed size (ignored in touchscreen mode)
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,9 @@ struct GameFormSpec
 | 
			
		||||
	// Currently only used for the in-game settings menu.
 | 
			
		||||
	void showPauseMenuFormSpec(const std::string &formspec, const std::string &formname);
 | 
			
		||||
	void showNodeFormspec(const std::string &formspec, const v3s16 &nodepos);
 | 
			
		||||
	void showPlayerInventory();
 | 
			
		||||
	/// If `!fs_override`: Uses `player->inventory_formspec`.
 | 
			
		||||
	/// If ` fs_override`: Uses a temporary formspec until an update is received.
 | 
			
		||||
	void showPlayerInventory(const std::string *fs_override);
 | 
			
		||||
	void showDeathFormspecLegacy();
 | 
			
		||||
	// Shows the hardcoded "main" pause menu.
 | 
			
		||||
	void showPauseMenu();
 | 
			
		||||
 
 | 
			
		||||
@@ -99,6 +99,8 @@ public:
 | 
			
		||||
 | 
			
		||||
	std::string hotbar_image = "";
 | 
			
		||||
	std::string hotbar_selected_image = "";
 | 
			
		||||
	/// Temporary player inventory formspec. Empty value = feature inactive.
 | 
			
		||||
	std::string inventory_formspec_override;
 | 
			
		||||
 | 
			
		||||
	video::SColor light_color = video::SColor(255, 255, 255, 255);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -902,6 +902,7 @@ void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt)
 | 
			
		||||
 | 
			
		||||
	// Store formspec in LocalPlayer
 | 
			
		||||
	player->inventory_formspec = pkt->readLongString();
 | 
			
		||||
	player->inventory_formspec_override.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
 | 
			
		||||
 
 | 
			
		||||
@@ -178,6 +178,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
 | 
			
		||||
	{ "TOCLIENT_STOP_SOUND",               0, true }, // 0x40
 | 
			
		||||
	{ "TOCLIENT_PRIVILEGES",               0, true }, // 0x41
 | 
			
		||||
	{ "TOCLIENT_INVENTORY_FORMSPEC",       0, true }, // 0x42
 | 
			
		||||
	// ^ `channel` MUST be the same as TOCLIENT_SHOW_FORMSPEC
 | 
			
		||||
	{ "TOCLIENT_DETACHED_INVENTORY",       0, true }, // 0x43
 | 
			
		||||
	{ "TOCLIENT_SHOW_FORMSPEC",            0, true }, // 0x44
 | 
			
		||||
	{ "TOCLIENT_MOVEMENT",                 0, true }, // 0x45
 | 
			
		||||
 
 | 
			
		||||
@@ -121,6 +121,8 @@ public:
 | 
			
		||||
	u16 protocol_version = 0;
 | 
			
		||||
	u16 formspec_version = 0;
 | 
			
		||||
 | 
			
		||||
	bool inventory_formspec_overridden = false;
 | 
			
		||||
 | 
			
		||||
	/// returns PEER_ID_INEXISTENT when PlayerSAO is not ready
 | 
			
		||||
	session_t getPeerId() const { return m_peer_id; }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1574,7 +1574,9 @@ int ObjectRef::l_set_inventory_formspec(lua_State *L)
 | 
			
		||||
 | 
			
		||||
	auto formspec = readParam<std::string_view>(L, 2);
 | 
			
		||||
 | 
			
		||||
	if (formspec != player->inventory_formspec) {
 | 
			
		||||
	if (player->inventory_formspec_overridden
 | 
			
		||||
			|| formspec != player->inventory_formspec) {
 | 
			
		||||
		player->inventory_formspec_overridden = false;
 | 
			
		||||
		player->inventory_formspec = formspec;
 | 
			
		||||
		getServer(L)->reportInventoryFormspecModified(player->getName());
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1595,11 +1595,10 @@ void Server::SendShowFormspecMessage(session_t peer_id, const std::string &forms
 | 
			
		||||
				(it->second == formname || formname.empty())) {
 | 
			
		||||
			m_formspec_state_data.erase(peer_id);
 | 
			
		||||
		}
 | 
			
		||||
		pkt.putLongString("");
 | 
			
		||||
	} else {
 | 
			
		||||
		m_formspec_state_data[peer_id] = formname;
 | 
			
		||||
		pkt.putLongString(formspec);
 | 
			
		||||
	}
 | 
			
		||||
	pkt.putLongString(formspec);
 | 
			
		||||
	pkt << formname;
 | 
			
		||||
 | 
			
		||||
	Send(&pkt);
 | 
			
		||||
@@ -3397,6 +3396,9 @@ bool Server::showFormspec(const char *playername, const std::string &formspec,
 | 
			
		||||
	if (!player)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	// To allow re-sending the same inventory formspec.
 | 
			
		||||
	player->inventory_formspec_overridden = formname.empty() && !formspec.empty();
 | 
			
		||||
 | 
			
		||||
	SendShowFormspecMessage(player->getPeerId(), formspec, formname);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user