1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Merge remote-tracking branch 'upstream/master' into Visuals-Vol-2

This commit is contained in:
Gefüllte Taubenbrust 2024-09-25 20:53:09 +02:00
commit 71e648a776
647 changed files with 60434 additions and 37195 deletions

View file

@ -75,6 +75,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gameparams.h"
#include "particles.h"
#include "gettext.h"
#include "util/tracy_wrapper.h"
class ClientNotFoundException : public BaseException
{
@ -101,6 +102,8 @@ private:
void *ServerThread::run()
{
ZoneScoped;
BEGIN_DEBUG_EXCEPTION_HANDLER
/*
@ -110,17 +113,22 @@ void *ServerThread::run()
* server-step frequency. Receive() is used for waiting between the steps.
*/
auto framemarker = FrameMarker("ServerThread::run()-frame").started();
try {
m_server->AsyncRunStep(0.0f, true);
} catch (con::ConnectionBindFailed &e) {
m_server->setAsyncFatalError(e.what());
} catch (LuaError &e) {
m_server->setAsyncFatalError(e);
} catch (ModError &e) {
m_server->setAsyncFatalError(e.what());
}
framemarker.end();
float dtime = 0.0f;
while (!stopRequested()) {
framemarker.start();
ScopeProfiler spm(g_profiler, "Server::RunStep() (max)", SPT_MAX);
u64 t0 = porting::getTimeUs();
@ -142,9 +150,12 @@ void *ServerThread::run()
m_server->setAsyncFatalError(e.what());
} catch (LuaError &e) {
m_server->setAsyncFatalError(e);
} catch (ModError &e) {
m_server->setAsyncFatalError(e.what());
}
dtime = 1e-6f * (porting::getTimeUs() - t0);
framemarker.end();
}
END_DEBUG_EXCEPTION_HANDLER
@ -254,11 +265,7 @@ Server::Server(
m_simple_singleplayer_mode(simple_singleplayer_mode),
m_dedicated(dedicated),
m_async_fatal_error(""),
m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
512,
CONNECTION_TIMEOUT,
m_bind_addr.isIPv6(),
this)),
m_con(con::createMTP(CONNECTION_TIMEOUT, m_bind_addr.isIPv6(), this)),
m_itemdef(createItemDefManager()),
m_nodedef(createNodeDefManager()),
m_craftdef(createCraftDefManager()),
@ -329,27 +336,6 @@ Server::~Server()
SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
L"*** Server shutting down"));
if (m_env) {
MutexAutoLock envlock(m_env_mutex);
infostream << "Server: Saving players" << std::endl;
m_env->saveLoadedPlayers();
infostream << "Server: Kicking players" << std::endl;
std::string kick_msg;
bool reconnect = false;
if (isShutdownRequested()) {
reconnect = m_shutdown_state.should_reconnect;
kick_msg = m_shutdown_state.message;
}
if (kick_msg.empty()) {
kick_msg = g_settings->get("kick_msg_shutdown");
}
m_env->saveLoadedPlayers(true);
kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
kick_msg, reconnect);
}
actionstream << "Server: Shutting down" << std::endl;
// Stop server step from happening
@ -369,16 +355,33 @@ Server::~Server()
if (m_env) {
MutexAutoLock envlock(m_env_mutex);
infostream << "Server: Executing shutdown hooks" << std::endl;
try {
// Empty out the environment, this can also invoke callbacks.
m_env->deactivateBlocksAndObjects();
m_script->on_shutdown();
} catch (ModError &e) {
addShutdownError(e);
}
infostream << "Server: Executing shutdown hooks" << std::endl;
infostream << "Server: Saving players" << std::endl;
m_env->saveLoadedPlayers();
infostream << "Server: Kicking players" << std::endl;
std::string kick_msg;
bool reconnect = false;
if (isShutdownRequested()) {
reconnect = m_shutdown_state.should_reconnect;
kick_msg = m_shutdown_state.message;
}
if (kick_msg.empty()) {
kick_msg = g_settings->get("kick_msg_shutdown");
}
m_env->saveLoadedPlayers(true);
kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
kick_msg, reconnect);
try {
m_script->on_shutdown();
// Empty out the environment, this can also invoke callbacks.
m_env->deactivateBlocksAndObjects();
} catch (ModError &e) {
addShutdownError(e);
}
@ -555,7 +558,6 @@ void Server::start()
m_thread->stop();
// Initialize connection
m_con->SetTimeoutMs(30);
m_con->Serve(m_bind_addr);
// Start thread
@ -612,6 +614,9 @@ void Server::step()
void Server::AsyncRunStep(float dtime, bool initial_step)
{
ZoneScoped;
auto framemarker = FrameMarker("Server::AsyncRunStep()-frame").started();
{
// Send blocks to clients
SendBlocks(dtime);
@ -628,8 +633,6 @@ void Server::AsyncRunStep(float dtime, bool initial_step)
*/
m_uptime_counter->increment(dtime);
handlePeerChanges();
/*
Update time of day and overall game time
*/
@ -785,6 +788,12 @@ void Server::AsyncRunStep(float dtime, bool initial_step)
//infostream<<"Server: Checking added and deleted active objects"<<std::endl;
MutexAutoLock envlock(m_env_mutex);
// This guarantees that each object recomputes its cache only once per server step,
// unless get_effective_observers is called.
// If we were to update observer sets eagerly in set_observers instead,
// the total costs of calls to set_observers could theoretically be higher.
m_env->invalidateActiveObjectObserverCaches();
{
ClientInterface::AutoLock clientlock(m_clients);
const RemoteClientMap &clients = m_clients.getClientList();
@ -1056,6 +1065,9 @@ void Server::AsyncRunStep(float dtime, bool initial_step)
void Server::Receive(float timeout)
{
ZoneScoped;
auto framemarker = FrameMarker("Server::Receive()-frame").started();
const u64 t0 = porting::getTimeUs();
const float timeout_us = timeout * 1e6f;
auto remaining_time_us = [&]() -> float {
@ -1075,6 +1087,8 @@ void Server::Receive(float timeout)
// and a faster server-step is better than busy waiting.
if (remaining_time_us() < 1000.0f)
break;
else
continue;
}
peer_id = pkt.getPeerId();
@ -1145,10 +1159,6 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
// Send HP
SendPlayerHP(playersao, false);
// Send death screen
if (playersao->isDead())
SendDeathscreen(peer_id, false, v3f(0,0,0));
// Send Breath
SendPlayerBreath(playersao);
@ -1157,7 +1167,7 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
*/
{
NetworkPacket notice_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
notice_pkt << (u8) PLAYER_LIST_ADD << (u16) 1 << std::string(player->getName());
notice_pkt << (u8) PLAYER_LIST_ADD << (u16) 1 << player->getName();
m_clients.sendToAll(&notice_pkt);
}
{
@ -1252,21 +1262,20 @@ void Server::onMapEditEvent(const MapEditEvent &event)
m_unsent_map_edit_queue.push(new MapEditEvent(event));
}
void Server::peerAdded(con::Peer *peer)
void Server::peerAdded(con::IPeer *peer)
{
verbosestream<<"Server::peerAdded(): peer->id="
<<peer->id<<std::endl;
verbosestream << "Server::peerAdded(): id=" << peer->id << std::endl;
m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
m_clients.CreateClient(peer->id);
}
void Server::deletingPeer(con::Peer *peer, bool timeout)
void Server::deletingPeer(con::IPeer *peer, bool timeout)
{
verbosestream<<"Server::deletingPeer(): peer->id="
<<peer->id<<", timeout="<<timeout<<std::endl;
verbosestream << "Server::deletingPeer(): id=" << peer->id
<< ", timeout=" << timeout << std::endl;
m_clients.event(peer->id, CSE_Disconnect);
m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
DeleteClient(peer->id, timeout ? CDR_TIMEOUT : CDR_LEAVE);
}
bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
@ -1310,34 +1319,6 @@ const ClientDynamicInfo *Server::getClientDynamicInfo(session_t peer_id)
return &client->getDynamicInfo();
}
void Server::handlePeerChanges()
{
while(!m_peer_change_queue.empty())
{
con::PeerChange c = m_peer_change_queue.front();
m_peer_change_queue.pop();
verbosestream<<"Server: Handling peer change: "
<<"id="<<c.peer_id<<", timeout="<<c.timeout
<<std::endl;
switch(c.type)
{
case con::PEER_ADDED:
m_clients.CreateClient(c.peer_id);
break;
case con::PEER_REMOVED:
DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
break;
default:
FATAL_ERROR("Invalid peer change event received!");
break;
}
}
}
void Server::printToConsoleOnly(const std::string &text)
{
if (m_admin_chat) {
@ -1411,25 +1392,12 @@ void Server::SendBreath(session_t peer_id, u16 breath)
}
void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
const std::string &custom_reason, bool reconnect)
std::string_view custom_reason, bool reconnect)
{
assert(reason < SERVER_ACCESSDENIED_MAX);
NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
pkt << (u8)reason;
if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
pkt << custom_reason;
else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
reason == SERVER_ACCESSDENIED_CRASH)
pkt << custom_reason << (u8)reconnect;
Send(&pkt);
}
void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
v3f camera_point_target)
{
NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
pkt << set_camera_point_target << camera_point_target;
pkt << (u8)reason << custom_reason << (u8)reconnect;
Send(&pkt);
}
@ -1863,7 +1831,7 @@ void Server::SendCloudParams(session_t peer_id, const CloudParams &params)
{
NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
pkt << params.density << params.color_bright << params.color_ambient
<< params.height << params.thickness << params.speed;
<< params.height << params.thickness << params.speed << params.color_shadow;
Send(&pkt);
}
@ -1893,7 +1861,7 @@ void Server::SendSetLighting(session_t peer_id, const Lighting &lighting)
<< lighting.exposure.speed_bright_dark
<< lighting.exposure.center_weight_power;
pkt << lighting.volumetric_light_strength;
pkt << lighting.volumetric_light_strength << lighting.shadow_tint;
pkt << lighting.artificial_light_color;
@ -2060,19 +2028,10 @@ void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersa
// Removed objects
pkt << static_cast<u16>(removed_objects.size());
std::vector<u16> sounds_to_stop;
for (auto &it : removed_objects) {
const auto [gone, id] = it;
ServerActiveObject *obj = m_env->getActiveObject(id);
// Stop sounds if objects go out of range.
// This fixes https://github.com/minetest/minetest/issues/8094.
// We may not remove sounds if an entity was removed on the server.
// See https://github.com/minetest/minetest/issues/14422.
if (!gone) // just out of range for client, not gone on server?
sounds_to_stop.push_back(id);
pkt << id;
// Remove from known objects
@ -2081,8 +2040,10 @@ void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersa
obj->m_known_by_count--;
}
if (!sounds_to_stop.empty())
stopAttachedSounds(client->peer_id, sounds_to_stop);
// Note: Do yet NOT stop or remove object-attached sounds where the object goes out
// of range (client side). Such sounds would need to be re-sent when coming into range.
// Currently, the client will initiate m_playing_sounds clean ups indirectly by
// "Server::handleCommand_RemovedSounds".
// Added objects
pkt << static_cast<u16>(added_objects.size());
@ -2266,37 +2227,6 @@ void Server::fadeSound(s32 handle, float step, float gain)
m_playing_sounds.erase(it);
}
void Server::stopAttachedSounds(session_t peer_id,
const std::vector<u16> &object_ids)
{
assert(peer_id != PEER_ID_INEXISTENT);
assert(!object_ids.empty());
auto cb = [&] (const s32 id, ServerPlayingSound &sound) -> bool {
if (!CONTAINS(object_ids, sound.object))
return false;
auto clients_it = sound.clients.find(peer_id);
if (clients_it == sound.clients.end())
return false;
NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
pkt << id;
Send(peer_id, &pkt);
sound.clients.erase(clients_it);
// delete if client list empty
return sound.clients.empty();
};
for (auto it = m_playing_sounds.begin(); it != m_playing_sounds.end(); ) {
if (cb(it->first, it->second))
it = m_playing_sounds.erase(it);
else
++it;
}
}
void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
float far_d_nodes)
{
@ -2533,7 +2463,7 @@ bool Server::addMediaFile(const std::string &filename,
const char *supported_ext[] = {
".png", ".jpg", ".bmp", ".tga",
".ogg",
".x", ".b3d", ".obj",
".x", ".b3d", ".obj", ".gltf",
// Custom translation file format
".tr",
NULL
@ -2863,32 +2793,8 @@ void Server::HandlePlayerDeath(PlayerSAO *playersao, const PlayerHPChangeReason
// Trigger scripted stuff
m_script->on_dieplayer(playersao, reason);
SendDeathscreen(playersao->getPeerID(), false, v3f(0,0,0));
}
void Server::RespawnPlayer(session_t peer_id)
{
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
infostream << "Server::RespawnPlayer(): Player "
<< playersao->getPlayer()->getName()
<< " respawns" << std::endl;
const auto *prop = playersao->accessObjectProperties();
playersao->setHP(prop->hp_max,
PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
playersao->setBreath(prop->breath_max);
bool repositioned = m_script->on_respawnplayer(playersao);
if (!repositioned) {
// setPos will send the new position to client
playersao->setPos(findSpawnPos());
}
}
void Server::DenySudoAccess(session_t peer_id)
{
NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
@ -2897,7 +2803,7 @@ void Server::DenySudoAccess(session_t peer_id)
void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
const std::string &custom_reason, bool reconnect)
std::string_view custom_reason, bool reconnect)
{
SendAccessDenied(peer_id, reason, custom_reason, reconnect);
m_clients.event(peer_id, CSE_SetDenied);
@ -2970,9 +2876,6 @@ void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
PlayerSAO *playersao = player->getPlayerSAO();
assert(playersao);
playersao->clearChildAttachments();
playersao->clearParentAttachment();
// inform connected clients
const std::string &player_name = player->getName();
NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
@ -3218,14 +3121,11 @@ std::string Server::getStatusString()
bool first = true;
os << " | clients: ";
if (m_env) {
std::vector<session_t> clients = m_clients.getClientIDs();
for (session_t client_id : clients) {
RemotePlayer *player = m_env->getPlayer(client_id);
std::vector<std::string> player_names = m_clients.getPlayerNames();
// Get name of player
const char *name = player ? player->getName() : "<unknown>";
std::sort(player_names.begin(), player_names.end());
// Add name to information string
for (const std::string& name : player_names) {
if (!first)
os << ", ";
else