mirror of
https://github.com/luanti-org/luanti.git
synced 2025-07-22 17:18:39 +00:00
Merge 929f9f2736
into 535d757563
This commit is contained in:
commit
2419bde120
15 changed files with 551 additions and 5 deletions
|
@ -9,7 +9,7 @@ serverlistmgr = {
|
|||
-- list of locally favorites servers
|
||||
favorites = nil,
|
||||
|
||||
-- list of servers fetched from public list
|
||||
-- list of servers fetched from public list and local servers
|
||||
servers = nil,
|
||||
}
|
||||
|
||||
|
@ -140,6 +140,14 @@ local function fetch_geoip()
|
|||
end
|
||||
|
||||
function serverlistmgr.sync()
|
||||
if minetest.settings:get("serverlist_lan") then
|
||||
if core.ask_lan_servers then --This checks if the function exists before running it.
|
||||
core.ask_lan_servers();
|
||||
else
|
||||
print("core.ask_lan_servers isn't defined.")
|
||||
end
|
||||
end
|
||||
|
||||
if not serverlistmgr.servers then
|
||||
serverlistmgr.servers = {{
|
||||
name = fgettext("Loading..."),
|
||||
|
|
|
@ -4,14 +4,27 @@
|
|||
|
||||
local function get_sorted_servers()
|
||||
local servers = {
|
||||
lan = {},
|
||||
fav = {},
|
||||
public = {},
|
||||
incompatible = {}
|
||||
}
|
||||
|
||||
local serverlist = table.copy(serverlistmgr.servers)
|
||||
|
||||
if minetest.settings:get_bool("serverlist_lan") then
|
||||
local lan_servers = core.get_lan_servers()
|
||||
|
||||
for _, server in ipairs(lan_servers) do
|
||||
server.is_compatible = is_server_protocol_compat(server.proto_min, server.proto_max)
|
||||
server.is_local = true
|
||||
table.insert(serverlist, server)
|
||||
end
|
||||
end
|
||||
|
||||
local favs = serverlistmgr.get_favorites()
|
||||
local taken_favs = {}
|
||||
local result = menudata.search_result or serverlistmgr.servers
|
||||
local result = menudata.search_result or serverlist
|
||||
for _, server in ipairs(result) do
|
||||
server.is_favorite = false
|
||||
for index, fav in ipairs(favs) do
|
||||
|
@ -25,7 +38,11 @@ local function get_sorted_servers()
|
|||
if server.is_favorite then
|
||||
table.insert(servers.fav, server)
|
||||
elseif server.is_compatible then
|
||||
table.insert(servers.public, server)
|
||||
if server.is_local then
|
||||
table.insert(servers.lan, server)
|
||||
else
|
||||
table.insert(servers.public, server)
|
||||
end
|
||||
else
|
||||
table.insert(servers.incompatible, server)
|
||||
end
|
||||
|
@ -249,11 +266,12 @@ local function get_formspec(tabview, name, tabdata)
|
|||
local servers = get_sorted_servers()
|
||||
|
||||
local dividers = {
|
||||
lan = "1,#00ff00," .. fgettext("Lan") .. ",,,0,0,,",
|
||||
fav = "5,#ffff00," .. fgettext("Favorites") .. ",,,0,0,,",
|
||||
public = "6,#4bdd42," .. fgettext("Public Servers") .. ",,,0,0,,",
|
||||
incompatible = "7,"..mt_color_grey.."," .. fgettext("Incompatible Servers") .. ",,,0,0,,"
|
||||
}
|
||||
local order = {"fav", "public", "incompatible"}
|
||||
local order = {"lan", "fav", "public", "incompatible"}
|
||||
|
||||
tabdata.lookup = {} -- maps row number to server
|
||||
local rows = {}
|
||||
|
|
|
@ -1044,6 +1044,9 @@ server_announce (Announce server) bool false
|
|||
# Send names of online players to the serverlist. If disabled only the player count is revealed.
|
||||
server_announce_send_players (Send player names to the server list) bool true
|
||||
|
||||
# Make local servers visible to local clients.
|
||||
serverlist_lan (Show local servers) bool true
|
||||
|
||||
# Announce to this serverlist.
|
||||
serverlist_url (Serverlist URL) [common] string https://servers.luanti.org
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <IGUISpriteBank.h>
|
||||
#include <ICameraSceneNode.h>
|
||||
#include <unordered_map>
|
||||
#include "server/serverlist.h"
|
||||
|
||||
#if USE_SOUND
|
||||
#include "sound/sound_openal.h"
|
||||
|
@ -540,6 +541,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
|
|||
|
||||
void ClientLauncher::main_menu(MainMenuData *menudata)
|
||||
{
|
||||
ServerList::lan_get();
|
||||
bool *kill = porting::signal_handler_killstatus();
|
||||
video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
|
||||
auto *device = m_rendering_engine->get_raw_device();
|
||||
|
|
|
@ -533,6 +533,7 @@ void set_default_settings()
|
|||
Mapgen::setDefaultSettings(settings);
|
||||
|
||||
// Server list announcing
|
||||
settings->setDefault("serverlist_lan", "true");
|
||||
settings->setDefault("server_announce", "false");
|
||||
settings->setDefault("server_url", "");
|
||||
settings->setDefault("server_address", "");
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
set(common_network_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/address.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/connection.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lan.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mtp/impl.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mtp/threads.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/networkpacket.cpp
|
||||
|
|
|
@ -31,6 +31,9 @@ public:
|
|||
Address(u32 address, u16 port);
|
||||
Address(u8 a, u8 b, u8 c, u8 d, u16 port);
|
||||
Address(const IPv6AddressBytes *ipv6_bytes, u16 port);
|
||||
Address(const in6_addr & addr, u16 port) { setAddress(addr); setPort(port); };
|
||||
Address(const sockaddr_in6 & sai) { m_address.ipv6 = sai.sin6_addr; m_addr_family = sai.sin6_family; m_port = ntohs(sai.sin6_port); };
|
||||
Address(const sockaddr_in & sai) { m_address.ipv4 = sai.sin_addr; m_addr_family = sai.sin_family; m_port = ntohs(sai.sin_port); };
|
||||
|
||||
bool operator==(const Address &address) const;
|
||||
bool operator!=(const Address &address) const { return !(*this == address); }
|
||||
|
@ -59,6 +62,7 @@ public:
|
|||
void setAddress(u32 address);
|
||||
void setAddress(u8 a, u8 b, u8 c, u8 d);
|
||||
void setAddress(const IPv6AddressBytes *ipv6_bytes);
|
||||
void setAddress(const in6_addr & addr) { m_address.ipv6 = addr; m_addr_family = AF_INET6;}
|
||||
void setPort(u16 port);
|
||||
|
||||
private:
|
||||
|
|
355
src/network/lan.cpp
Normal file
355
src/network/lan.cpp
Normal file
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
Luanti
|
||||
Copyright (C) 2024 proller <proler@gmail.com> and contributors.
|
||||
|
||||
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 "network/lan.h"
|
||||
#include <cstdint>
|
||||
#include "convert_json.h"
|
||||
#include "socket.h"
|
||||
#include "log.h"
|
||||
#include "settings.h"
|
||||
#include "version.h"
|
||||
#include "networkprotocol.h"
|
||||
#include "server/serverlist.h"
|
||||
#include "debug.h"
|
||||
#include "json/json.h"
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include "porting.h"
|
||||
#include "threading/thread.h"
|
||||
#include "network/address.h"
|
||||
|
||||
//copypaste from ../socket.cpp
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
// Without this some of the network functions are not found on mingw
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define LAST_SOCKET_ERR() WSAGetLastError()
|
||||
typedef SOCKET socket_t;
|
||||
typedef int socklen_t;
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifndef __ANDROID__
|
||||
#include <ifaddrs.h>
|
||||
#define HAVE_IFADDRS 1
|
||||
#endif
|
||||
|
||||
#define LAST_SOCKET_ERR() (errno)
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
|
||||
const char* adv_multicast_addr = "224.1.1.1";
|
||||
const static unsigned short int adv_port = 29998;
|
||||
const std::string proto = "lanti";
|
||||
static std::string ask_str;
|
||||
|
||||
bool use_ipv6 = true;
|
||||
|
||||
lan_adv::lan_adv() : Thread("lan_adv")
|
||||
{
|
||||
}
|
||||
|
||||
void lan_adv::ask()
|
||||
{
|
||||
if (!isRunning()) start();
|
||||
|
||||
if (ask_str.empty()) {
|
||||
Json::Value j;
|
||||
j["cmd"] = "ask";
|
||||
j["proto"] = proto;
|
||||
ask_str = fastWriteJson(j);
|
||||
}
|
||||
|
||||
send_string(ask_str);
|
||||
}
|
||||
|
||||
void lan_adv::send_string(const std::string &str)
|
||||
{
|
||||
if (g_settings->getBool("ipv6_server")) {
|
||||
std::vector<uint32_t> scopes;
|
||||
// todo: windows and android
|
||||
|
||||
#if HAVE_IFADDRS
|
||||
struct ifaddrs *ifaddr = nullptr, *ifa = nullptr;
|
||||
if (getifaddrs(&ifaddr) < 0) {
|
||||
} else {
|
||||
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
if (!ifa->ifa_addr)
|
||||
continue;
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
auto sa = *((struct sockaddr_in6 *)ifa->ifa_addr);
|
||||
if (sa.sin6_scope_id)
|
||||
scopes.push_back(sa.sin6_scope_id);
|
||||
|
||||
/*errorstream<<"in=" << ifa->ifa_name << " a="<<Address(*((struct sockaddr_in6*)ifa->ifa_addr)).serializeString()<<" ba=" << ifa->ifa_broadaddr <<" sc=" << sa.sin6_scope_id <<" fl=" << ifa->ifa_flags
|
||||
//<< " bn=" << Address(*((struct sockaddr_in6*)ifa->ifa_broadaddr)).serializeString()
|
||||
<<"\n"; */
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifaddr);
|
||||
#endif
|
||||
|
||||
if (scopes.empty())
|
||||
scopes.push_back(0);
|
||||
|
||||
struct addrinfo hints
|
||||
{
|
||||
};
|
||||
|
||||
hints.ai_family = AF_INET6;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
|
||||
struct addrinfo *result = nullptr;
|
||||
if (!getaddrinfo("ff02::1", nullptr, &hints, &result)) {
|
||||
for (auto info = result; info; info = info->ai_next) {
|
||||
try {
|
||||
sockaddr_in6 addr = *((struct sockaddr_in6 *)info->ai_addr);
|
||||
addr.sin6_port = htons(adv_port);
|
||||
UDPSocket socket_send(true);
|
||||
int set_option_on = 1;
|
||||
//setsockopt(socket_send.GetHandle(), SOL_SOCKET, IPV6_MULTICAST_HOPS,
|
||||
// (const char *)&set_option_on, sizeof(set_option_on));
|
||||
auto use_scopes = scopes;
|
||||
if (addr.sin6_scope_id) {
|
||||
use_scopes.clear();
|
||||
use_scopes.push_back(addr.sin6_scope_id);
|
||||
}
|
||||
for (auto &scope : use_scopes) {
|
||||
addr.sin6_scope_id = scope;
|
||||
socket_send.Send(Address(addr), str.c_str(), str.size());
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
verbosestream << "udp multicast send over ipv6 fail [" << e.what() << "]\n" << "Trying ipv4.\n";
|
||||
try {
|
||||
sockaddr_in addr = {};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(adv_port);
|
||||
UDPSocket socket_send(false);
|
||||
|
||||
inet_pton(AF_INET, adv_multicast_addr, &(addr.sin_addr));
|
||||
|
||||
struct ip_mreq mreq;
|
||||
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(adv_multicast_addr);
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
setsockopt(socket_send.GetHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
(const char *)&mreq, sizeof(mreq));
|
||||
|
||||
//int set_option_on = 2;
|
||||
//setsockopt(socket_send.GetHandle(), SOL_SOCKET, IP_MULTICAST_TTL,
|
||||
// (const char *)&set_option_on, sizeof(set_option_on));
|
||||
|
||||
socket_send.Send(Address(addr), str.c_str(), str.size());
|
||||
} catch (const std::exception &e) {
|
||||
verbosestream << "udp mulitcast send over ipv4 fail too. " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
sockaddr_in addr = {};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(adv_port);
|
||||
UDPSocket socket_send(false);
|
||||
|
||||
inet_pton(AF_INET, adv_multicast_addr, &(addr.sin_addr));
|
||||
|
||||
struct ip_mreq mreq;
|
||||
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(adv_multicast_addr);
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
setsockopt(socket_send.GetHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
(const char *)&mreq, sizeof(mreq));
|
||||
|
||||
//int set_option_on = 2;
|
||||
//setsockopt(socket_send.GetHandle(), SOL_SOCKET, IP_MULTICAST_TTL,
|
||||
// (const char *)&set_option_on, sizeof(set_option_on));
|
||||
|
||||
socket_send.Send(Address(addr), str.c_str(), str.size());
|
||||
} catch (const std::exception &e) {
|
||||
verbosestream << "udp mulitcast send over ipv4 fail " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lan_adv::serve(unsigned short port)
|
||||
{
|
||||
server_port = port;
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
|
||||
void *lan_adv::run()
|
||||
{
|
||||
BEGIN_DEBUG_EXCEPTION_HANDLER;
|
||||
|
||||
setName("lan_adv " + (server_port ? std::string("server") : std::string("client")));
|
||||
UDPSocket socket_recv(g_settings->getBool("ipv6_server"));
|
||||
|
||||
int set_option_off = 0, set_option_on = 1;
|
||||
setsockopt(socket_recv.GetHandle(), SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char *)&set_option_on, sizeof(set_option_on));
|
||||
#ifdef SO_REUSEPORT
|
||||
setsockopt(socket_recv.GetHandle(), SOL_SOCKET, SO_REUSEPORT,
|
||||
(const char *)&set_option_on, sizeof(set_option_on));
|
||||
#endif
|
||||
struct ip_mreq mreq;
|
||||
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(adv_multicast_addr);
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
setsockopt(socket_recv.GetHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
(const char *)&mreq, sizeof(mreq));
|
||||
setsockopt(socket_recv.GetHandle(), IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(const char *)&set_option_off, sizeof(set_option_off));
|
||||
socket_recv.setTimeoutMs(200);
|
||||
|
||||
if (g_settings->getBool("ipv6_server")) {
|
||||
try {
|
||||
socket_recv.Bind(Address(in6addr_any, adv_port));
|
||||
} catch (const std::exception &e) {
|
||||
warningstream << m_name << ": cant bind ipv6 address [" << e.what()
|
||||
<< "], trying ipv4. " << std::endl;
|
||||
try {
|
||||
socket_recv.Bind(Address((u32)INADDR_ANY, adv_port));
|
||||
} catch (const std::exception &e) {
|
||||
warningstream << m_name << ": cant bind ipv4 too [" << e.what() << "]"
|
||||
<< std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
socket_recv.Bind(Address((u32)INADDR_ANY, adv_port));
|
||||
} catch (const std::exception &e) {
|
||||
warningstream << m_name << ": cant bind ipv4 [" << e.what() << "]"
|
||||
<< std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
std::unordered_map<std::string, uint64_t> limiter;
|
||||
const unsigned int packet_maxsize = 16384;
|
||||
char buffer[packet_maxsize];
|
||||
Json::Reader reader;
|
||||
std::string answer_str;
|
||||
Json::Value server;
|
||||
if (server_port) {
|
||||
server["name"] = g_settings->get("server_name");
|
||||
server["description"] = g_settings->get("server_description");
|
||||
server["version"] = g_version_string;
|
||||
bool strict_checking = g_settings->getBool("strict_protocol_version_checking");
|
||||
server["proto_min"] =
|
||||
strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MIN;
|
||||
server["proto_max"] = LATEST_PROTOCOL_VERSION;
|
||||
server["url"] = g_settings->get("server_url");
|
||||
server["creative"] = g_settings->getBool("creative_mode");
|
||||
server["damage"] = g_settings->getBool("enable_damage");
|
||||
server["password"] = g_settings->getBool("disallow_empty_password");
|
||||
server["pvp"] = g_settings->getBool("enable_pvp");
|
||||
server["port"] = server_port;
|
||||
server["clients"] = clients_num.load();
|
||||
server["clients_max"] = g_settings->getU16("max_users");
|
||||
server["proto"] = proto;
|
||||
|
||||
send_string(fastWriteJson(server));
|
||||
}
|
||||
|
||||
while (isRunning() && !stopRequested()) {
|
||||
BEGIN_DEBUG_EXCEPTION_HANDLER;
|
||||
Address addr;
|
||||
int rlen = socket_recv.Receive(addr, buffer, packet_maxsize);
|
||||
if (rlen <= 0)
|
||||
continue;
|
||||
Json::Value p;
|
||||
if (!reader.parse(std::string(buffer, rlen), p)) {
|
||||
//errorstream << "cant parse "<< s << "\n";
|
||||
continue;
|
||||
}
|
||||
auto addr_str = addr.serializeString();
|
||||
auto now = porting::getTimeMs();
|
||||
//errorstream << " a=" << addr.serializeString() << " : " << addr.getPort() << " l=" << rlen << " b=" << p << " ; server=" << server_port << "\n";
|
||||
|
||||
if (server_port) {
|
||||
if (p["cmd"] == "ask" && limiter[addr_str] < now) {
|
||||
(clients_num.load() ? infostream : actionstream)
|
||||
<< "lan: want play " << addr_str << " " << p["proto"] << std::endl;
|
||||
|
||||
server["clients"] = clients_num.load();
|
||||
answer_str = fastWriteJson(server);
|
||||
limiter[addr_str] = now + 3000;
|
||||
send_string(answer_str);
|
||||
//UDPSocket socket_send(true);
|
||||
//addr.setPort(adv_port);
|
||||
//socket_send.Send(addr, answer_str.c_str(), answer_str.size());
|
||||
}
|
||||
} else {
|
||||
if (p["cmd"] == "ask") {
|
||||
actionstream << "lan: want play " << addr_str << " " << p["proto"] << std::endl;
|
||||
}
|
||||
if (p["port"].isInt()) {
|
||||
p["address"] = addr_str;
|
||||
auto key = addr_str + ":" + p["port"].asString();
|
||||
std::unique_lock lock(mutex);
|
||||
if (p["cmd"].asString() == "shutdown") {
|
||||
//infostream << "server shutdown " << key << "\n";
|
||||
collected.erase(key);
|
||||
fresh = true;
|
||||
} else if (p["proto"] == proto) {
|
||||
if (!collected.count(key))
|
||||
actionstream << "lan server start " << key << "\n";
|
||||
collected.insert_or_assign(key, p);
|
||||
fresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
//errorstream<<" current list: ";for (auto & i : collected) {errorstream<< i.first <<" ; ";}errorstream<<std::endl;
|
||||
}
|
||||
END_DEBUG_EXCEPTION_HANDLER;
|
||||
}
|
||||
|
||||
if (server_port) {
|
||||
Json::Value answer_json;
|
||||
answer_json["port"] = server_port;
|
||||
answer_json["cmd"] = "shutdown";
|
||||
send_string(fastWriteJson(answer_json));
|
||||
}
|
||||
|
||||
END_DEBUG_EXCEPTION_HANDLER;
|
||||
|
||||
return nullptr;
|
||||
}
|
49
src/network/lan.h
Normal file
49
src/network/lan.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Luanti
|
||||
Copyright (C) 2024 proller <proler@gmail.com> and contributors.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "json/json.h"
|
||||
#include <map>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include "threading/thread.h"
|
||||
|
||||
|
||||
class lan_adv : public Thread
|
||||
{
|
||||
public:
|
||||
void *run();
|
||||
|
||||
lan_adv();
|
||||
void ask();
|
||||
void send_string(const std::string &str);
|
||||
|
||||
void serve(unsigned short port);
|
||||
|
||||
std::map<std::string, Json::Value> collected;
|
||||
std::shared_mutex mutex;
|
||||
|
||||
std::atomic_bool fresh;
|
||||
std::atomic_int clients_num;
|
||||
|
||||
private:
|
||||
unsigned short server_port = 0;
|
||||
};
|
|
@ -17,6 +17,7 @@
|
|||
#include "convert_json.h"
|
||||
#include "content/content.h"
|
||||
#include "content/subgames.h"
|
||||
#include "server/serverlist.h"
|
||||
#include "mapgen/mapgen.h"
|
||||
#include "settings.h"
|
||||
#include "clientdynamicinfo.h"
|
||||
|
@ -27,6 +28,7 @@
|
|||
#include "content/mod_configuration.h"
|
||||
#include "threading/mutex_auto_lock.h"
|
||||
#include "common/c_converter.h"
|
||||
#include "json-forwards.h"
|
||||
#include "gui/guiOpenURL.h"
|
||||
#include "gettext.h"
|
||||
#include "log.h"
|
||||
|
@ -1038,6 +1040,44 @@ int ModApiMainMenu::l_do_async_callback(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int ModApiMainMenu::l_ask_lan_servers(lua_State *L)
|
||||
{
|
||||
ServerList::lan_get();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ModApiMainMenu::l_get_lan_servers(lua_State *L)
|
||||
{
|
||||
lua_newtable(L);
|
||||
int top = lua_gettop(L);
|
||||
unsigned int index = 1;
|
||||
|
||||
std::shared_lock lock(ServerList::lan_adv_client.mutex);
|
||||
for (const auto &server : ServerList::lan_adv_client.collected) {
|
||||
lua_pushnumber(L, index);
|
||||
|
||||
lua_newtable(L);
|
||||
int top_lvl2 = lua_gettop(L);
|
||||
|
||||
for (const auto &field_name : server.second.getMemberNames()) {
|
||||
lua_pushstring(L, field_name.c_str());
|
||||
if (server.second[field_name].isString())
|
||||
lua_pushstring(L, server.second[field_name].asCString());
|
||||
else if (server.second[field_name].isConvertibleTo(Json::realValue))
|
||||
lua_pushnumber(L, server.second[field_name].asDouble());
|
||||
else
|
||||
lua_pushnil(L);
|
||||
lua_settable(L, top_lvl2);
|
||||
}
|
||||
|
||||
lua_settable(L, top);
|
||||
++index;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void ModApiMainMenu::Initialize(lua_State *L, int top)
|
||||
{
|
||||
|
@ -1089,7 +1129,8 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
|
|||
API_FCT(open_dir);
|
||||
API_FCT(share_file);
|
||||
API_FCT(do_async_callback);
|
||||
|
||||
API_FCT(ask_lan_servers);
|
||||
API_FCT(get_lan_servers);
|
||||
lua_pushboolean(L, g_first_run);
|
||||
lua_setfield(L, top, "is_first_run");
|
||||
}
|
||||
|
@ -1120,4 +1161,6 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
|
|||
API_FCT(get_max_supp_proto);
|
||||
API_FCT(get_formspec_version);
|
||||
API_FCT(get_language);
|
||||
API_FCT(get_lan_servers);
|
||||
API_FCT(ask_lan_servers);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,20 @@ private:
|
|||
*/
|
||||
static int getBoolData(lua_State *L, const std::string &name ,bool& valid);
|
||||
|
||||
/**
|
||||
* Checks if a path may be modified. Paths in the temp directory or the user
|
||||
* games, mods, textures, or worlds directories may be modified.
|
||||
* @param path path to check
|
||||
* @return true if the path may be modified
|
||||
*/
|
||||
static bool mayModifyPath(std::string path);
|
||||
|
||||
//lan discovery
|
||||
|
||||
static int l_ask_lan_servers(lua_State *L);
|
||||
|
||||
static int l_get_lan_servers(lua_State *L);
|
||||
|
||||
//api calls
|
||||
|
||||
static int l_start(lua_State *L);
|
||||
|
|
|
@ -63,8 +63,10 @@
|
|||
#include "gameparams.h"
|
||||
#include "particles.h"
|
||||
#include "gettext.h"
|
||||
#include "network/lan.h"
|
||||
#include "util/tracy_wrapper.h"
|
||||
|
||||
|
||||
class ClientNotFoundException : public BaseException
|
||||
{
|
||||
public:
|
||||
|
@ -427,6 +429,17 @@ Server::~Server()
|
|||
delete m_unsent_map_edit_queue.front();
|
||||
m_unsent_map_edit_queue.pop();
|
||||
}
|
||||
|
||||
if (g_settings->getBool("serverlist_lan")) {
|
||||
lan_adv_server.stop();
|
||||
|
||||
while (lan_adv_server.isRunning()) {
|
||||
// Wait until the lan_adv_server thread has finished.
|
||||
// This is so that its thread destructor doesn't kill the thread
|
||||
// before it sends the 'shutdown' command to remove this server's
|
||||
// server info from the serverlist of local clients.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::init()
|
||||
|
@ -578,6 +591,10 @@ void Server::start()
|
|||
// Start thread
|
||||
m_thread->start();
|
||||
|
||||
if (!m_simple_singleplayer_mode && g_settings->getBool("serverlist_lan")) {
|
||||
lan_adv_server.serve(m_bind_addr.getPort());
|
||||
};
|
||||
|
||||
// ASCII art for the win!
|
||||
const char *art[] = {
|
||||
R"( _ _ _ )",
|
||||
|
@ -802,6 +819,10 @@ void Server::AsyncRunStep(float dtime, bool initial_step)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (!isSingleplayer() && g_settings->getBool("serverlist_lan")) {
|
||||
lan_adv_server.clients_num = m_clients.getPlayerNames().size();
|
||||
};
|
||||
|
||||
/*
|
||||
Check added and deleted active objects
|
||||
*/
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "network/lan.h"
|
||||
#include "irr_v3d.h"
|
||||
#include "map.h"
|
||||
#include "hud.h"
|
||||
|
@ -711,6 +712,9 @@ private:
|
|||
// The server mainly operates in this thread
|
||||
ServerThread *m_thread = nullptr;
|
||||
|
||||
// For local server discovery.
|
||||
lan_adv lan_adv_server;
|
||||
|
||||
/*
|
||||
Client interface
|
||||
*/
|
||||
|
|
|
@ -13,9 +13,27 @@
|
|||
#include "convert_json.h"
|
||||
#include "httpfetch.h"
|
||||
#include "server.h"
|
||||
#include "network/lan.h"
|
||||
#include "json/json.h"
|
||||
|
||||
namespace ServerList
|
||||
{
|
||||
|
||||
static std::string ask_str;
|
||||
|
||||
lan_adv lan_adv_client;
|
||||
|
||||
void lan_get() {
|
||||
if (!g_settings->getBool("serverlist_lan"))
|
||||
return;
|
||||
lan_adv_client.ask();
|
||||
}
|
||||
|
||||
bool lan_fresh() {
|
||||
auto result = lan_adv_client.fresh.load();
|
||||
lan_adv_client.fresh = false;
|
||||
return result;
|
||||
}
|
||||
#if USE_CURL
|
||||
void sendAnnounce(AnnounceAction action,
|
||||
const u16 port,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "content/mods.h"
|
||||
#include "json-forwards.h"
|
||||
#include <iostream>
|
||||
#include "network/lan.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -13,6 +14,10 @@
|
|||
|
||||
namespace ServerList
|
||||
{
|
||||
extern lan_adv lan_adv_client;
|
||||
void lan_get();
|
||||
bool lan_fresh();
|
||||
|
||||
#if USE_CURL
|
||||
enum AnnounceAction {AA_START, AA_UPDATE, AA_DELETE};
|
||||
void sendAnnounce(AnnounceAction, u16 port,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue